summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorHorus_Arch2015-03-02 15:31:39 +0100
committerHorus_Arch2015-03-02 15:31:39 +0100
commite31b06b7b56aaf1cf5510d4bb0261f73bc0e8893 (patch)
tree0651cdd688659b845f3605e09384161b3c0334db /app
parentcf66deeeba38263feef0ca4123a983cb78ce5cac (diff)
downloadwebmon-e31b06b7b56aaf1cf5510d4bb0261f73bc0e8893.tar.gz
Migrating from revel.HEADmaster
Diffstat (limited to 'app')
-rw-r--r--app/controllers/app.go195
-rw-r--r--app/controllers/db.go119
-rw-r--r--app/controllers/mail.go45
-rw-r--r--app/db.go39
-rw-r--r--app/handler.go247
-rw-r--r--app/init.go43
-rw-r--r--app/main.go8
-rw-r--r--app/struct.go92
-rw-r--r--app/utilities.go (renamed from app/controllers/utilities.go)55
-rw-r--r--app/utilities_test.go106
-rw-r--r--app/views/App/Index.html23
-rw-r--r--app/views/Mailer/ConfirmRegistration.html5
-rw-r--r--app/views/Mailer/SendConfirmationKey.html4
-rw-r--r--app/views/debug.html64
-rw-r--r--app/views/errors/404.html20
-rw-r--r--app/views/errors/500.html16
-rw-r--r--app/views/flash.html18
-rw-r--r--app/views/footer.html5
-rw-r--r--app/views/header.html17
19 files changed, 530 insertions, 591 deletions
diff --git a/app/controllers/app.go b/app/controllers/app.go
deleted file mode 100644
index 9e5764f..0000000
--- a/app/controllers/app.go
+++ /dev/null
@@ -1,195 +0,0 @@
-package controllers
-
-import (
- "github.com/jinzhu/gorm"
- "github.com/revel/revel"
- "github.com/revel/revel/modules/jobs/app/jobs"
-)
-
-type App struct {
- *revel.Controller
-}
-
-func (c App) Index() revel.Result {
- return c.Render()
-}
-
-func (c App) PrintLogin(legacy bool) revel.Result {
- return c.Render(legacy)
-}
-
-func (c App) PrintRegister() revel.Result {
- return c.Render()
-}
-
-func (c App) Account() revel.Result {
- return c.Render()
-}
-
-func (c App) Login(email string, legacy bool, user string, password string, passwordConfirm string) revel.Result {
-
- if legacy {
- // Show login form with username and password
- c.Validation.Required(user).Message("Please enter a user name.")
- c.Validation.Required(password).Message("Please enter a password.")
- c.Validation.Required(passwordConfirm).Message("Please confirm your password.")
- c.Validation.Required(password == passwordConfirm).Message("The passwords do not match.")
- } else {
- // Show login form only with email
- c.Validation.Required(email).Message("Please provide a mail adress.")
- }
-
- if c.Validation.HasErrors() {
- c.Validation.Keep()
- c.FlashParams()
- return c.Redirect(App.PrintLogin)
- }
-
- u := User{}
- if legacy {
- // do database lookup and show if its matched
- db.Where("name = ?", user).First(&u)
- c.Validation.Required(u.Confirmed).Message("Your mail adress is not confirmed yet.")
- verify, _ := VerifyPassword(password, u.Password)
- c.Validation.Required(verify).Message("The user/password combination does not exists.")
-
- if c.Validation.HasErrors() {
- c.Validation.Keep()
- c.FlashParams()
- return c.Redirect(App.PrintLogin)
- }
-
- c.Session["login"] = "true"
- c.Session["uid"] = string(u.Id)
-
- return c.Redirect(App.Account)
- } else {
- if db.Where("email = ?", email).First(&u).Error == gorm.RecordNotFound {
- // Invalid Email
- c.Flash.Error("No valid mail adress.")
- return c.Redirect(App.PrintLogin)
- }
- // Get random string
- key := RandomKey()
- // Set key in redis
- conn := pool.Get()
- defer conn.Close()
- _, _ = conn.Do("SET", key, u.Email, 86400)
- // Send email with confirmation link
- //jobs.Now(Mailer{}.SendConfirmationKey(email, key))
- _ = Mailer{}.SendConfirmationKey(email, key)
-
- c.Flash.Success("A mail with a confirmation link was sent. Follow the instructions there.")
-
- return c.Redirect(App.PrintLogin)
- }
-}
-
-func (c App) Confirm(key, registration string) revel.Result {
-
- if registration == "" {
- // Processing login
-
- c.Validation.Required(key).Message("No key provided.")
-
- conn := pool.Get()
- confirmKey, err := conn.Do("GET", key)
- c.Validation.Required(err == nil).Message("Oops, there is currently an internal problem. Please check later again.")
- c.Validation.Required(confirmKey).Message("Key does not seem to be valid.")
-
- _, _ = conn.Do("DEL", key)
-
- if c.Validation.HasErrors() {
- c.Validation.Keep()
- c.FlashParams()
- return c.Redirect(App.PrintLogin)
- }
-
- u := User{}
- db.Where("email = ?", confirmKey).First(&u)
-
- if u.Confirmed == false {
- // E-Mail is now confirmed
- u.Confirmed = true
- u.ConfirmationKey = ""
- db.Save(&u)
- }
-
- c.Session["login"] = "true"
- c.Session["uid"] = string(u.Id)
-
- } else {
- // Processing registration confirmation
-
- c.Validation.Required(registration).Message("No confirmation key provided.")
-
- u := User{}
- db.Where("confirmationkey = ?").First(&u)
-
- c.Validation.Required(registration == u.ConfirmationKey).Message("Key does not seem to be valid.")
-
- if c.Validation.HasErrors() {
- c.Validation.Keep()
- c.FlashParams()
- return c.Redirect(App.PrintLogin)
- }
-
- u.Confirmed = true
- u.ConfirmationKey = ""
- db.Save(&u)
-
- c.Session["login"] = "true"
- c.Session["uid"] = string(u.Id)
-
- }
-
- return c.Redirect(App.Account)
-}
-
-func (c App) Register(email, confirmEmail, user, password, confirmPassword string) revel.Result {
-
- c.Validation.Required(email).Message("Please provide a mail adress.")
- c.Validation.Required(email == confirmEmail).Message("The mail adresses do not match.")
- c.Validation.Required(user).Message("Please provide a user name.")
-
- if password != "" {
- c.Validation.Required(password == confirmPassword).Message("Passwords do not match.")
- }
-
- if c.Validation.HasErrors() {
- c.Validation.Keep()
- c.FlashParams()
- return c.Redirect(App.PrintRegister)
- }
-
- p, _ := HashPassword(password)
- key := RandomKey() // Create key to confirm mail adress
- u := User{
- Name: user,
- Email: email,
- Password: p,
- Confirmed: false,
- ConfirmationKey: key,
- Alerts: []Alert{{Email: email}},
- }
-
- db.NewRecord(u)
- db.Create(&u)
- db.Save(&u)
-
- // Send email with confirmation link
- //jobs.Now(Mailer{}.ConfirmRegistration(email, key))
- //_ = Mailer{}.ConfirmRegistration(user, email, key)
- jobs.Now(JobRegistration{User: user, Email: email, Key: key})
- c.Flash.Success("A mail with a confirmation link was sent. Please confirm your mail adress now.")
-
- return c.Redirect(App.PrintRegister)
-}
-
-func (c App) Test(email, key string) revel.Result {
- // jobs.Now(JobRegistration{User: "foobar", Email: email, Key: key})
- Mailer{}.ConfirmRegistration("foobar", "raspi@dns.iamfabulous.de", "string")
- c.Flash.Success("A mail with a confirmation link was sent. Please confirm your mail adress now.")
-
- return c.Redirect(App.Index)
-}
diff --git a/app/controllers/db.go b/app/controllers/db.go
deleted file mode 100644
index baa772c..0000000
--- a/app/controllers/db.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package controllers
-
-import (
- "github.com/jinzhu/gorm"
- _ "github.com/mattn/go-sqlite3"
- "github.com/revel/revel"
- "time"
-)
-
-type User struct {
- Id int64
- Email string `sql:"unique"`
- Name string `sql:"unique"`
- Password string
- Confirmed bool
- ConfirmationKey string
- Alerts []Alert
- CreatedAt time.Time
- DeletedAt time.Time
- UpdatedAt time.Time
-}
-
-// Multiple accounts which are alerted
-type Alert struct {
- Id int64
- UserId int64
- Email string
- CreatedAt time.Time
- DeletedAt time.Time
- UpdatedAt time.Time
-}
-
-type Job struct {
- Id int64
- UserId int64
- Name string
- Url string
- Versions []Version
- Diff string
- DiffLen int64
- CreatedAt time.Time
- DeletedAt time.Time
- UpdatedAt time.Time
-}
-
-// Save history version of jobs
-type Version struct {
- Id int64
- JobId int64
- Content string
- Hash string
- CreatedAt time.Time
- DeletedAt time.Time
- UpdatedAt time.Time
-}
-
-var db = DBInit()
-
-func DBInit() gorm.DB {
- // Open database handler
- // !!! FIXME THIS THROWS A PANIC AT COMPILE TIME. WHY? !!!
-
- //db, err := gorm.Open(revel.Config.StringDefault("db.driver", "sqlite3"), revel.Config.StringDefault("db.spec", "webmon.db"))
-
- /* OR */
-
- /*
- var (
- d, s string
- )
- d = revel.Config.StringDefault("test.d", "sqlite3")
- s = revel.Config.StringDefault("test.s", "webmon.db")
- //db, err := gorm.Open(driver, spec)
-
- revel.WARN.Println(d)
- revel.WARN.Println(s)
- */
-
- // This works.
- db, err := gorm.Open("sqlite3", "webmon.db")
-
- // Set database logging to TRACE
- db.LogMode(true)
- db.SetLogger(gorm.Logger{revel.TRACE})
-
- // Ping database to check if up
- if err = db.DB().Ping(); err != nil {
- revel.ERROR.Panicf("Failed to init database. %s \n", err)
- }
- defer db.Close()
-
- // Set Pool connections
- db.DB().SetMaxIdleConns(10)
- db.DB().SetMaxOpenConns(100)
-
- // Create tables which are defined as struct
- db.Debug().CreateTable(&User{})
- db.Debug().CreateTable(&Alert{})
- db.Debug().CreateTable(&Job{})
- db.Debug().CreateTable(&Version{})
-
- // Automigration
- db.Debug().AutoMigrate(&User{}, &Job{}, &Version{}, &Alert{})
-
- // Add index on email and name to enforce uniqueness
- db.Debug().Model(&User{}).AddUniqueIndex("idx_user_email", "email")
- db.Debug().Model(&User{}).AddUniqueIndex("idx_user_name", "name")
-
- // Unique index on alert to ensure every user can specify not multiple equally alerts
- db.Debug().Model(&Alert{}).AddUniqueIndex("idx_alert_email_userid", "email", "user_id")
-
- // Unique index to ensure every user can have only one job with the same name
- db.Debug().Model(&Job{}).AddUniqueIndex("idx_job_name_userid", "name", "user_id")
-
- // Makes hash unique
- // db.Debug().Model(&Version{}).AddUniqueIndex("idx_version_hash", "hash")
-
- return db
-}
diff --git a/app/controllers/mail.go b/app/controllers/mail.go
deleted file mode 100644
index 3fd2e94..0000000
--- a/app/controllers/mail.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package controllers
-
-import (
- "github.com/tanema/revel_mailer"
-)
-
-type Mailer struct {
- revel_mailer.Mailer
-}
-
-type JobConfirmationKey struct {
- Email string
- Key string
-}
-
-func (j JobConfirmationKey) Run() {
- _ = Mailer{}.SendConfirmationKey(j.Email, j.Key)
-}
-
-func (u Mailer) SendConfirmationKey(email, key string) error {
- return u.Send(revel_mailer.H{
- "subject": "Confirmation Key",
- "to": []string{email},
- "key": key,
- })
-}
-
-type JobRegistration struct {
- User string
- Email string
- Key string
-}
-
-func (j JobRegistration) Run() {
- _ = Mailer{}.ConfirmRegistration(j.User, j.Email, j.Key)
-}
-
-func (u Mailer) ConfirmRegistration(user, email, key string) error {
- return u.Send(revel_mailer.H{
- "name": user,
- "subject": "Confirm registration",
- "to": []string{email},
- "key": key,
- })
-}
diff --git a/app/db.go b/app/db.go
new file mode 100644
index 0000000..16c6c98
--- /dev/null
+++ b/app/db.go
@@ -0,0 +1,39 @@
+package controllers
+
+import (
+ "github.com/jinzhu/gorm"
+ _ "github.com/mattn/go-sqlite3"
+ "log"
+ "time"
+)
+
+var Db, dberr = gorm.Open(os.Getenv("WEBMON_DB_DRIVER"), os.Getenv("WEBMON_DB_CREDENTIALS"))
+
+func InitDB() {
+ if dberr != nil {
+ log.Panic(dberr)
+ }
+ logMode := os.Getenv("WEBMON_DB_LOG")
+ if logMode == "true" {
+ Db.LogMode(true)
+ }
+ if err := Db.DB().Ping(); err != nil {
+ log.Panic(err)
+ }
+
+ db.Debug().CreateTable(&User{})
+ db.Debug().CreateTable(&Alert{})
+ db.Debug().CreateTable(&Job{})
+ db.Debug().CreateTable(&Version{})
+
+ db.Debug().AutoMigrate(&User{}, &Job{}, &Version{}, &Alert{})
+
+ db.Debug().Model(&User{}).AddUniqueIndex("idx_user_email", "email")
+ db.Debug().Model(&User{}).AddUniqueIndex("idx_user_name", "name")
+
+ // Unique index on alert to ensure every user can specify not multiple equally alerts
+ db.Debug().Model(&Alert{}).AddUniqueIndex("idx_alert_email_userid", "email", "user_id")
+
+ // Unique index to ensure every user can have only one job with the same name
+ db.Debug().Model(&Job{}).AddUniqueIndex("idx_job_name_userid", "name", "user_id")
+}
diff --git a/app/handler.go b/app/handler.go
new file mode 100644
index 0000000..c3093d6
--- /dev/null
+++ b/app/handler.go
@@ -0,0 +1,247 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+ "net/http"
+ "net/url"
+)
+
+func SetupHandler(w http.ResponseWriter, r *http.Request) {
+ log.Println("Get Setup")
+ u := User{}
+ if Db.Find(&u).RecordNotFound() {
+ PrintRegisterHandler(w, r)
+ } else {
+ http.Redirect(w, r, "/login", 302)
+ }
+}
+
+func RegisterHandler(w http.ResponseWriter, r *http.Request) {
+ log.Println("Processing registration!")
+ session, err := store.Get(r, "_SID")
+ if err != nil {
+ log.Println(err)
+ }
+ u := User{}
+ err = r.ParseForm()
+ if err != nil {
+ log.Println(err)
+ }
+ err = decoder.Decode(&u, r.PostForm)
+ if err != nil {
+ log.Println(err)
+ }
+ u.Password, _ = HashPassword(u.Password)
+ query := Db.Create(&u)
+ if query.Error != nil {
+ session.AddFlash("Registration failed.", "error")
+ session.Save(r, w)
+ http.Redirect(w, r, "/register", 302)
+ return
+ }
+ session.AddFlash("Registration completed!", "success")
+ session.Values["login"] = true
+ session.Save(r, w)
+ http.Redirect(w, r, "/admin", 302)
+}
+
+func PrintRegisterHandler(w http.ResponseWriter, r *http.Request) {
+ log.Println("Get Registration")
+ session, err := store.Get(r, "_SID")
+ if err != nil {
+ log.Println(err)
+ }
+ if session.Values["login"] == true {
+ http.Redirect(w, r, "/admin", 302)
+ log.Println("Schon erfolgreich eingeloggt!")
+ return
+ }
+ m := Messages{}
+ m.Success = session.Flashes("success")
+ m.Error = session.Flashes("error")
+ session.Save(r, w)
+ templ := mainTempl.Lookup("login.html")
+
+ err = templ.ExecuteTemplate(w, "register.html", m)
+ if err != nil {
+ log.Panic(err)
+ }
+
+}
+
+func AddNewJobHandler(w http.ResponseWriter, r *http.Request) {
+ log.Printf("Add new job")
+ session, err := store.Get(r, "_SID")
+ if err != nil {
+ log.Println(err)
+ }
+ if session.Values["login"] != true {
+ session.Values["history"] = "/new"
+ session.Save(r, w)
+ http.Redirect(w, r, "/login", 302)
+ return
+ }
+
+ err = r.ParseForm()
+ if err != nil {
+ log.Panic(err)
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ host := Host{}
+ err = decoder.Decode(&host, r.PostForm)
+ if err != nil {
+ log.Println(err)
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ u, err := url.Parse(host.Url)
+ if err != nil {
+ log.Println(err)
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ if u.Scheme != "http" && u.Scheme != "https" {
+ session.AddFlash("Unsurportted scheme. Only http:// and https:// is valid.", "error")
+ session.Save(r, w)
+ http.Redirect(w, r, "/admin", 302)
+ return
+ }
+
+ host.Monitored = true
+ host.Host = u.Host
+
+ query := Db.Save(&host)
+ if query.Error != nil {
+ log.Println(err)
+ //session.AddFlash("Befehl konnte auf Grund eines Problems nicht ausgeführt werden.", "error")
+ session.AddFlash("There was an error. :(", "error")
+ session.Save(r, w)
+ http.Redirect(w, r, "/admin", 302)
+ }
+
+ go func() {
+ h := []Host{}
+ Db.Find(&h)
+ h = CheckPages(h)
+ for k, _ := range h {
+ Db.Debug().Save(&h[k])
+ }
+ CacheHosts(cache_prefix+"database", h)
+ }()
+
+ session.AddFlash("Job added!", "success")
+ session.Save(r, w)
+
+ http.Redirect(w, r, "/admin", 302)
+
+}
+
+func LoginHandler(w http.ResponseWriter, r *http.Request) {
+ session, err := store.Get(r, "_SID")
+ if err != nil {
+ log.Println(err)
+ }
+ u := User{}
+ err = r.ParseForm()
+ if err != nil {
+ log.Println(err)
+ }
+ err = decoder.Decode(&u, r.PostForm)
+ if err != nil {
+ log.Println(err)
+ }
+ log.Println("Processing Login", u.Name)
+ login := login(u.Name, u.Password, session)
+ if !login {
+ session.AddFlash("Login failed.", "error")
+ session.Save(r, w)
+ log.Println("Login failed.")
+ http.Redirect(w, r, "/login", 302)
+ return
+ }
+ session.Values["login"] = true
+ session.Save(r, w)
+ var redirectTarget string
+ if session.Values["history"] != "" && session.Values["history"] != nil {
+ redirectTarget = fmt.Sprintf("%v", session.Values["history"])
+ session.Values["history"] = ""
+ session.Save(r, w)
+ http.Redirect(w, r, redirectTarget, 301)
+ }
+ http.Redirect(w, r, "/admin", 301)
+}
+
+func PrintLoginHandler(w http.ResponseWriter, r *http.Request) {
+ log.Println("Get Login")
+ session, err := store.Get(r, "_SID")
+ if err != nil {
+ log.Println(err)
+ }
+
+ m := Messages{}
+ m.Success = session.Flashes("success")
+ m.Error = session.Flashes("error")
+ session.Save(r, w)
+ templ := mainTempl.Lookup("login.html")
+
+ err = templ.ExecuteTemplate(w, "login.html", m)
+ if err != nil {
+ log.Panic(err)
+ }
+}
+
+func LogoutHandler(w http.ResponseWriter, r *http.Request) {
+ log.Println("Logout")
+ session, _ := store.Get(r, "_SID")
+ session.Values["login"] = false
+ session.Save(r, w)
+ http.Redirect(w, r, "/login", 301)
+}
+
+func DeleteHandler(w http.ResponseWriter, r *http.Request) {
+ log.Println("Get Delete")
+ session, err := store.Get(r, "_SID")
+ if err != nil {
+ log.Println(err)
+ }
+ if session.Values["login"] != true {
+ session.Values["history"] = "/admin"
+ session.Save(r, w)
+ http.Redirect(w, r, "/login", 302)
+ return
+ }
+ err = r.ParseForm()
+ if err != nil {
+ log.Println(err)
+ session.AddFlash("Error parsing form.", "error")
+ session.Save(r, w)
+ http.Redirect(w, r, "/admin", 302)
+ return
+ }
+ host := Host{}
+ err = decoder.Decode(&host, r.URL.Query())
+ if err != nil {
+ log.Println(err)
+ session.AddFlash("Error parsing form.", "error")
+ session.Save(r, w)
+ http.Redirect(w, r, "/admin", 302)
+ return
+ }
+ log.Println("Deleting host where id = ", host.Id)
+ query := Db.Where("id = ?", host.Id).Delete(&host)
+ if query.Error != nil {
+ session.AddFlash("Deleting failed.", "error")
+ log.Println("Deleting failed.", query.Error)
+ } else {
+ session.AddFlash("We removed the host.", "success")
+ }
+ session.Save(r, w)
+ http.Redirect(w, r, "/admin", 302)
+ go FillCache()
+}
diff --git a/app/init.go b/app/init.go
deleted file mode 100644
index b13043a..0000000
--- a/app/init.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package app
-
-import (
- "github.com/anonx/cachesession"
- "github.com/cbonello/revel-csrf"
- "github.com/revel/revel"
-)
-
-func init() {
- // Filters is the default set of global filters.
- revel.Filters = []revel.Filter{
- revel.PanicFilter, // Recover from panics and display an error page instead.
- revel.RouterFilter, // Use the routing table to select the right Action
- revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
- revel.ParamsFilter, // Parse parameters into Controller.Params.
- cachesession.Filter, // Restore and write the session cookie.
- revel.FlashFilter, // Restore and write the flash cookie.
- csrf.CSRFFilter, // CSRF protection
- revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
- revel.I18nFilter, // Resolve the requested language
- HeaderFilter, // Add some security based headers
- revel.InterceptorFilter, // Run interceptors around the action.
- revel.CompressFilter, // Compress the result.
- revel.ActionInvoker, // Invoke the action.
- }
-
- // register startup functions with OnAppStart
- // ( order dependent )
- // revel.OnAppStart(InitDB)
- // revel.OnAppStart(FillCache)
-}
-
-// TODO turn this into revel.HeaderFilter
-// should probably also have a filter for CSRF
-// not sure if it can go in the same filter or not
-var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) {
- // Add some common security headers
- c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN")
- c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block")
- c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff")
-
- fc[0](c, fc[1:]) // Execute the next filter stage.
-}
diff --git a/app/main.go b/app/main.go
new file mode 100644
index 0000000..00b7ba3
--- /dev/null
+++ b/app/main.go
@@ -0,0 +1,8 @@
+package main
+
+import (
+ "fmt"
+)
+
+func main() {
+}
diff --git a/app/struct.go b/app/struct.go
new file mode 100644
index 0000000..80d6bf2
--- /dev/null
+++ b/app/struct.go
@@ -0,0 +1,92 @@
+package main
+
+import (
+ "time"
+)
+
+type User struct {
+ Id int64
+ Email string `sql:"unique"`
+ Name string `sql:"unique"`
+ Password string
+ Confirmed bool
+ ConfirmationKey string
+ Alerts []Alert
+ CreatedAt time.Time
+ DeletedAt time.Time
+ UpdatedAt time.Time
+}
+
+// Multiple accounts which are alerted
+type Alert struct {
+ Id int64
+ UserId int64
+ Email string
+ CreatedAt time.Time
+ DeletedAt time.Time
+ UpdatedAt time.Time
+}
+
+type Job struct {
+ Id int64
+ UserId int64
+ Name string
+ Url string
+ Versions []Version
+ Diff string
+ DiffLen int64
+ CreatedAt time.Time
+ DeletedAt time.Time
+ UpdatedAt time.Time
+}
+
+// Save history version of jobs
+type Version struct {
+ Id int64
+ JobId int64
+ Content string
+ Hash string
+ CreatedAt time.Time
+ DeletedAt time.Time
+ UpdatedAt time.Time
+}
+
+/* Maybe worth saving uptime history? */
+
+/*
+type Host struct {
+ Id int64
+ Host string
+ Url string
+ // Protocoll string // e.g. http
+ Monitored bool // disable monitoring on error
+ Private bool
+ Status string
+ StatusCode int64
+ Success bool
+ Reason string // Connection failure
+ Description string
+ /*
+ Date time.Time
+ Include string // Website must include this string
+ Except string // Website must not include this string
+ Alert bool // True to send alert on failure
+ DeletedAt time.Time
+*/
+/*
+ CreatedAt time.Time
+ UpdatedAt time.Time
+ Class string
+}
+*/
+
+/*
+type Messages struct {
+ Success []interface{}
+ Error []interface{}
+ Hosts []Host
+ moreScripts []string
+ NextRun time.Time
+ Sticky string
+}
+*/
diff --git a/app/controllers/utilities.go b/app/utilities.go
index 1aa5d6d..65a6716 100644
--- a/app/controllers/utilities.go
+++ b/app/utilities.go
@@ -1,36 +1,41 @@
-package controllers
+package main
import (
+ "bytes"
"crypto/md5"
+ "encoding/gob"
+ "errors"
"fmt"
"github.com/garyburd/redigo/redis"
- "github.com/revel/revel"
"golang.org/x/crypto/bcrypt"
+ // "html/template"
"io"
"io/ioutil"
+ "log"
"math/rand"
"net/http"
+ "os"
"time"
)
-// Returns the content of a webpage as string
-func Get(url string) (string, error) {
- response, err := http.Get(url)
+// Returns the response from a GET request plus the headers as map and the content as string
+func HttpGet(url string) (*http.Response, string, error) {
+ r, err := http.Get(url)
if err != nil {
- return "Get request failed.", err
+ return r, "Get request failed.", err
}
- defer response.Body.Close()
- contents, err := ioutil.ReadAll(response.Body)
+ defer r.Body.Close()
+ contents, err := ioutil.ReadAll(r.Body)
if err != nil {
- return "Reading body failed.", err
+ return r, "Reading body failed.", err
}
- return string(contents), nil
+ return r, string(contents), nil
}
// Hashs and returns a string (md5)
-func Hash(content string) string {
+func Md5Hash(content string) string {
h := md5.New()
io.WriteString(h, content)
hash := fmt.Sprintf("%x", h.Sum(nil))
@@ -40,6 +45,7 @@ func Hash(content string) string {
// Creates a random string
func RandomKey() string {
+ rand.Seed(time.Now().UTC().UnixNano())
letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
key := make([]rune, 40)
for i := range key {
@@ -57,8 +63,9 @@ func newPool() *redis.Pool {
MaxIdle: 3,
IdleTimeout: 240 * time.Second,
Dial: func() (redis.Conn, error) {
- //c, err := redis.Dial("tcp", ":6379")
- c, err := redis.Dial("tcp", revel.Config.StringDefault("redis.server", "127.0.0.1")+":"+revel.Config.StringDefault("redis.port", "6379"))
+ redis_server := os.Getenv("STATUS_REDIS_SERVER")
+ redis_port := os.Getenv("STATUS_REDIS_PORT")
+ c, err := redis.Dial("tcp", redis_server+":"+redis_port)
if err != nil {
return nil, err
}
@@ -74,7 +81,7 @@ func newPool() *redis.Pool {
// Hashs password with bcrypt and returns the string
func HashPassword(password string) (string, error) {
if password == "" {
- return "", nil
+ return "", errors.New("Empty password.")
}
p := []byte(password)
hash, err := bcrypt.GenerateFromPassword(p, 10)
@@ -85,10 +92,24 @@ func HashPassword(password string) (string, error) {
}
// Verify password and hash
-func VerifyPassword(password, hash string) (bool, error) {
+func VerifyPassword(password, hash string) bool {
+ if hash == "" || password == "" {
+ return false
+ }
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
if err != nil {
- return false, err
+ log.Printf("%s \n", err)
+ return false
+ }
+ return true
+}
+
+func GetBytes(key interface{}) ([]byte, error) {
+ var buf bytes.Buffer
+ enc := gob.NewEncoder(&buf)
+ err := enc.Encode(key)
+ if err != nil {
+ return nil, err
}
- return true, nil
+ return buf.Bytes(), nil
}
diff --git a/app/utilities_test.go b/app/utilities_test.go
new file mode 100644
index 0000000..1865c61
--- /dev/null
+++ b/app/utilities_test.go
@@ -0,0 +1,106 @@
+// +build all general
+
+package main
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+)
+
+func TestHttpGet(t *testing.T) {
+ answer := "Fake webpage here."
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/html")
+ fmt.Fprintln(w, answer)
+ }))
+ defer ts.Close()
+
+ fakeUrl := ts.URL
+
+ resp, content, err := HttpGet(fakeUrl)
+ if err != nil {
+ t.Fatal("Error getting web page.")
+ }
+ if resp.StatusCode != 200 {
+ t.Fatal("Expecting 200 as status code.")
+ }
+ if strings.TrimSpace(content) != answer {
+ t.Log("We got this: ", content)
+ t.Log("We expected this: ", answer)
+ t.Fatal("Webpage returned wrong answer.")
+ }
+}
+
+func TestMd5Hash(t *testing.T) {
+ hash := "f9d08276bc85d30d578e8883f3c7e843"
+ testHash := Md5Hash("md5hash")
+
+ if hash != testHash {
+ t.Fatal("Expected %s as hash. Got %s.", hash, testHash)
+ }
+}
+
+func TestRandomKey(t *testing.T) {
+ m := map[string]bool{}
+ var key string
+ for i := 0; i < 100; i++ {
+ key = RandomKey()
+ t.Log(key) // Uncomment to see every generated key.
+ if m[key] {
+ t.Fatal("Key not random.")
+ } else {
+ m[key] = true
+ }
+ if len(key) != 40 {
+ t.Fatal("Expected a key with length of 40. Got %s.", key)
+ }
+ }
+}
+
+func TestPassword(t *testing.T) {
+
+ testHash, err := HashPassword("password")
+ if err != nil {
+ t.Fatal("Hashing password failed.")
+ }
+ verify := VerifyPassword("password", testHash)
+ if !verify {
+ t.Fatal("Verifying password failed.")
+ }
+
+ testHash, err = HashPassword("")
+ if err == nil {
+ t.Fatal("Accepting empty password.")
+ }
+ verify = VerifyPassword("", testHash)
+ if verify {
+ t.Fatal("Verifying empty password.")
+ }
+}
+
+func BenchmarkMd5Hash(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Md5Hash("md5hash")
+ }
+}
+
+func BenchmarkRandomKey(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ RandomKey()
+ }
+}
+
+func BenchmarkHashPassword(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ HashPassword("password")
+ }
+}
+
+func BenchmarkVerifyPassword(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ VerifyPassword("password", "$2a$10$OnsbG0Obaz2af3UkoQ9Jaeky3zfRi.0ZHCJC8DlWnbqbpaXEhWqYe")
+ }
+}
diff --git a/app/views/App/Index.html b/app/views/App/Index.html
deleted file mode 100644
index deb2304..0000000
--- a/app/views/App/Index.html
+++ /dev/null
@@ -1,23 +0,0 @@
-{{set . "title" "Home"}}
-{{template "header.html" .}}
-
-<header class="hero-unit" style="background-color:#A9F16C">
- <div class="container">
- <div class="row">
- <div class="hero-text">
- <h1>It works!</h1>
- <p></p>
- </div>
- </div>
- </div>
-</header>
-
-<div class="container">
- <div class="row">
- <div class="span6">
- {{template "flash.html" .}}
- </div>
- </div>
-</div>
-
-{{template "footer.html" .}}
diff --git a/app/views/Mailer/ConfirmRegistration.html b/app/views/Mailer/ConfirmRegistration.html
deleted file mode 100644
index a63fcba..0000000
--- a/app/views/Mailer/ConfirmRegistration.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<h1>{{.subject}}</h1>
-
-<p>Hello {{.user}},<br>
- to confirm your registration please follow this link: <a href="https://webmon.iamfabulous.de/confirm?registration={{.key}}" title="Confirmation Link">Link</a>
-</p>
diff --git a/app/views/Mailer/SendConfirmationKey.html b/app/views/Mailer/SendConfirmationKey.html
deleted file mode 100644
index 0fef96b..0000000
--- a/app/views/Mailer/SendConfirmationKey.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<h1>{{.subject}}</h1>
-
-<p>Hello,<br>
- please follow this link to confirm your action: <a href="https://webmon.iamfabulous.de/confirm?key={{.key}}">Link</a></p>
diff --git a/app/views/debug.html b/app/views/debug.html
deleted file mode 100644
index f3975b7..0000000
--- a/app/views/debug.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<style type="text/css">
- #sidebar {
- position: absolute;
- right: 0px;
- top:69px;
- max-width: 75%;
- z-index: 1000;
- background-color: #fee;
- border: thin solid grey;
- padding: 10px;
- }
- #toggleSidebar {
- position: absolute;
- right: 0px;
- top: 50px;
- background-color: #fee;
- }
-
-</style>
-<div id="sidebar" style="display:none;">
- <h4>Available pipelines</h4>
- <dl>
- {{ range $index, $value := .}}
- <dt>{{$index}}</dt>
- <dd>{{$value}}</dd>
- {{end}}
- </dl>
- <h4>Flash</h4>
- <dl>
- {{ range $index, $value := .flash}}
- <dt>{{$index}}</dt>
- <dd>{{$value}}</dd>
- {{end}}
- </dl>
-
- <h4>Errors</h4>
- <dl>
- {{ range $index, $value := .errors}}
- <dt>{{$index}}</dt>
- <dd>{{$value}}</dd>
- {{end}}
- </dl>
-</div>
-<a id="toggleSidebar" href="#" class="toggles"><i class="icon-chevron-left"></i></a>
-
-<script>
- $sidebar = 0;
- $('#toggleSidebar').click(function() {
- if ($sidebar === 1) {
- $('#sidebar').hide();
- $('#toggleSidebar i').addClass('icon-chevron-left');
- $('#toggleSidebar i').removeClass('icon-chevron-right');
- $sidebar = 0;
- }
- else {
- $('#sidebar').show();
- $('#toggleSidebar i').addClass('icon-chevron-right');
- $('#toggleSidebar i').removeClass('icon-chevron-left');
- $sidebar = 1;
- }
-
- return false;
- });
-</script>
diff --git a/app/views/errors/404.html b/app/views/errors/404.html
deleted file mode 100644
index ebdfe10..0000000
--- a/app/views/errors/404.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <title>Not found</title>
- </head>
- <body>
-{{if eq .RunMode "dev"}}
-{{template "errors/404-dev.html" .}}
-{{else}}
- {{with .Error}}
- <h1>
- {{.Title}}
- </h1>
- <p>
- {{.Description}}
- </p>
- {{end}}
-{{end}}
- </body>
-</html>
diff --git a/app/views/errors/500.html b/app/views/errors/500.html
deleted file mode 100644
index 0cef4de..0000000
--- a/app/views/errors/500.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>Application error</title>
- </head>
- <body>
- {{if eq .RunMode "dev"}}
- {{template "errors/500-dev.html" .}}
- {{else}}
- <h1>Oops, an error occured</h1>
- <p>
- This exception has been logged.
- </p>
- {{end}}
- </body>
-</html>
diff --git a/app/views/flash.html b/app/views/flash.html
deleted file mode 100644
index 9c9ade9..0000000
--- a/app/views/flash.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{{if .flash.success}}
-<div class="alert alert-success">
- {{.flash.success}}
-</div>
-{{end}}
-
-{{if or .errors .flash.error}}
-<div class="alert alert-error">
- {{if .flash.error}}
- {{.flash.error}}
- {{end}}
- <ul style="margin-top:10px;">
- {{range .errors}}
- <li>{{.}}</li>
- {{end}}
- </ul>
-</div>
-{{end}}
diff --git a/app/views/footer.html b/app/views/footer.html
deleted file mode 100644
index 8db95e5..0000000
--- a/app/views/footer.html
+++ /dev/null
@@ -1,5 +0,0 @@
- {{if eq .RunMode "dev"}}
- {{template "debug.html" .}}
- {{end}}
- </body>
-</html>
diff --git a/app/views/header.html b/app/views/header.html
deleted file mode 100644
index 01637f4..0000000
--- a/app/views/header.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-
-<html>
- <head>
- <title>{{.title}}</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <link rel="stylesheet" type="text/css" href="/public/css/bootstrap.css">
- <link rel="shortcut icon" type="image/png" href="/public/img/favicon.png">
- <script src="/public/js/jquery-1.9.1.min.js" type="text/javascript" charset="utf-8"></script>
- {{range .moreStyles}}
- <link rel="stylesheet" type="text/css" href="/public/{{.}}">
- {{end}}
- {{range .moreScripts}}
- <script src="/public/{{.}}" type="text/javascript" charset="utf-8"></script>
- {{end}}
- </head>
- <body>