diff options
| author | Horus_Arch | 2015-03-02 15:31:39 +0100 |
|---|---|---|
| committer | Horus_Arch | 2015-03-02 15:31:39 +0100 |
| commit | e31b06b7b56aaf1cf5510d4bb0261f73bc0e8893 (patch) | |
| tree | 0651cdd688659b845f3605e09384161b3c0334db /app | |
| parent | cf66deeeba38263feef0ca4123a983cb78ce5cac (diff) | |
| download | webmon-e31b06b7b56aaf1cf5510d4bb0261f73bc0e8893.tar.gz | |
Diffstat (limited to 'app')
| -rw-r--r-- | app/controllers/app.go | 195 | ||||
| -rw-r--r-- | app/controllers/db.go | 119 | ||||
| -rw-r--r-- | app/controllers/mail.go | 45 | ||||
| -rw-r--r-- | app/db.go | 39 | ||||
| -rw-r--r-- | app/handler.go | 247 | ||||
| -rw-r--r-- | app/init.go | 43 | ||||
| -rw-r--r-- | app/main.go | 8 | ||||
| -rw-r--r-- | app/struct.go | 92 | ||||
| -rw-r--r-- | app/utilities.go (renamed from app/controllers/utilities.go) | 55 | ||||
| -rw-r--r-- | app/utilities_test.go | 106 | ||||
| -rw-r--r-- | app/views/App/Index.html | 23 | ||||
| -rw-r--r-- | app/views/Mailer/ConfirmRegistration.html | 5 | ||||
| -rw-r--r-- | app/views/Mailer/SendConfirmationKey.html | 4 | ||||
| -rw-r--r-- | app/views/debug.html | 64 | ||||
| -rw-r--r-- | app/views/errors/404.html | 20 | ||||
| -rw-r--r-- | app/views/errors/500.html | 16 | ||||
| -rw-r--r-- | app/views/flash.html | 18 | ||||
| -rw-r--r-- | app/views/footer.html | 5 | ||||
| -rw-r--r-- | app/views/header.html | 17 |
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> |
