github.com/kvattikuti/drone@v0.2.1-0.20140603034306-d400229a327a/pkg/handler/app.go (about) 1 package handler 2 3 import ( 4 "crypto/rand" 5 "io" 6 "log" 7 "net/http" 8 "time" 9 10 "github.com/dchest/authcookie" 11 "github.com/dchest/passwordreset" 12 "github.com/drone/drone/pkg/database" 13 "github.com/drone/drone/pkg/mail" 14 . "github.com/drone/drone/pkg/model" 15 ) 16 17 var ( 18 // Secret key used to sign auth cookies, 19 // password reset tokens, etc. 20 secret = generateRandomKey(256) 21 ) 22 23 // GenerateRandomKey creates a random key of size length bytes 24 func generateRandomKey(strength int) []byte { 25 k := make([]byte, strength) 26 if _, err := io.ReadFull(rand.Reader, k); err != nil { 27 return nil 28 } 29 return k 30 } 31 32 // Returns an HTML index.html page if the user is 33 // not currently authenticated, otherwise redirects 34 // the user to their personal dashboard screen 35 func Index(w http.ResponseWriter, r *http.Request) error { 36 // is the user already authenticated then 37 // redirect to the dashboard page 38 if _, err := r.Cookie("_sess"); err == nil { 39 http.Redirect(w, r, "/dashboard", http.StatusSeeOther) 40 return nil 41 } 42 43 // otherwise redirect to the login page 44 http.Redirect(w, r, "/login", http.StatusSeeOther) 45 return nil 46 } 47 48 // Return an HTML form for the User to login. 49 func Login(w http.ResponseWriter, r *http.Request) error { 50 var settings, _ = database.GetSettings() 51 52 data := struct { 53 Settings *Settings 54 }{settings} 55 56 return RenderTemplate(w, "login.html", &data) 57 } 58 59 // Terminate the User session. 60 func Logout(w http.ResponseWriter, r *http.Request) error { 61 DelCookie(w, r, "_sess") 62 63 http.Redirect(w, r, "/login", http.StatusSeeOther) 64 return nil 65 } 66 67 // Return an HTML form for the User to request a password reset. 68 func Forgot(w http.ResponseWriter, r *http.Request) error { 69 return RenderTemplate(w, "forgot.html", nil) 70 } 71 72 // Return an HTML form for the User to perform a password reset. 73 // This page must be visited from a Password Reset email that 74 // contains a hash to verify the User's identity. 75 func Reset(w http.ResponseWriter, r *http.Request) error { 76 return RenderTemplate(w, "reset.html", &struct{ Error string }{""}) 77 } 78 79 // Return an HTML form for the User to signup. 80 func SignUp(w http.ResponseWriter, r *http.Request) error { 81 var settings, _ = database.GetSettings() 82 83 if settings == nil || !settings.OpenInvitations { 84 http.Redirect(w, r, "/login", http.StatusSeeOther) 85 return nil 86 } 87 88 return RenderTemplate(w, "signup.html", nil) 89 } 90 91 // Return an HTML form to register for a new account. This 92 // page must be visited from a Signup email that contains 93 // a hash to verify the Email address is correct. 94 func Register(w http.ResponseWriter, r *http.Request) error { 95 return RenderTemplate(w, "register.html", &struct{ Error string }{""}) 96 } 97 98 func ForgotPost(w http.ResponseWriter, r *http.Request) error { 99 email := r.FormValue("email") 100 101 // attempt to retrieve the user by email address 102 user, err := database.GetUserEmail(email) 103 if err != nil { 104 log.Printf("could not find user %s to reset password. %s", email, err) 105 // if we can't find the email, we still display 106 // the template to the user. This prevents someone 107 // from trying to guess passwords through trial & error 108 return RenderTemplate(w, "forgot_sent.html", nil) 109 } 110 111 // hostname from settings 112 hostname := database.SettingsMust().URL().String() 113 114 // generate the password reset token 115 token := passwordreset.NewToken(user.Email, 12*time.Hour, []byte(user.Password), secret) 116 data := struct { 117 Host string 118 User *User 119 Token string 120 }{hostname, user, token} 121 122 // send the email message async 123 go func() { 124 if err := mail.SendPassword(email, data); err != nil { 125 log.Printf("error sending password reset email to %s. %s", email, err) 126 } 127 }() 128 129 // render the template indicating a success 130 return RenderTemplate(w, "forgot_sent.html", nil) 131 } 132 133 func ResetPost(w http.ResponseWriter, r *http.Request) error { 134 // verify the token and extract the username 135 token := r.FormValue("token") 136 email, err := passwordreset.VerifyToken(token, database.GetPassEmail, secret) 137 if err != nil { 138 return RenderTemplate(w, "reset.html", &struct{ Error string }{"Your password reset request is expired."}) 139 } 140 141 // get the user from the database 142 user, err := database.GetUserEmail(email) 143 if err != nil { 144 return RenderTemplate(w, "reset.html", &struct{ Error string }{"Unable to locate user account."}) 145 } 146 147 // get the new password 148 password := r.FormValue("password") 149 if err := user.SetPassword(password); err != nil { 150 return RenderTemplate(w, "reset.html", &struct{ Error string }{err.Error()}) 151 } 152 153 // save to the database 154 if err := database.SaveUser(user); err != nil { 155 return RenderTemplate(w, "reset.html", &struct{ Error string }{"Unable to update password. Please try again"}) 156 } 157 158 // add the user to the session object 159 SetCookie(w, r, "_sess", user.Email) 160 161 http.Redirect(w, r, "/dashboard", http.StatusSeeOther) 162 return nil 163 } 164 165 func SignUpPost(w http.ResponseWriter, r *http.Request) error { 166 // if self-registration is disabled we should display an 167 // error message to the user. 168 if !database.SettingsMust().OpenInvitations { 169 http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden) 170 return nil 171 } 172 173 // generate the password reset token 174 email := r.FormValue("email") 175 token := authcookie.New(email, time.Now().Add(12*time.Hour), secret) 176 177 // get the hostname from the database for use in the email 178 hostname := database.SettingsMust().URL().String() 179 180 // data used to generate the email template 181 data := struct { 182 Host string 183 Email string 184 Token string 185 }{hostname, email, token} 186 187 // send the email message async 188 go mail.SendActivation(email, data) 189 190 return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) 191 } 192 193 func RegisterPost(w http.ResponseWriter, r *http.Request) error { 194 // verify the token and extract the username 195 token := r.FormValue("token") 196 email := authcookie.Login(token, secret) 197 if len(email) == 0 { 198 return RenderTemplate(w, "register.html", &struct{ Error string }{"Your registration email is expired."}) 199 } 200 201 // set the email and name 202 user := NewUser(r.FormValue("name"), email) 203 204 // set the new password 205 password := r.FormValue("password") 206 if err := user.SetPassword(password); err != nil { 207 return RenderTemplate(w, "register.html", &struct{ Error string }{err.Error()}) 208 } 209 210 // verify fields are correct 211 if err := user.Validate(); err != nil { 212 return RenderTemplate(w, "register.html", &struct{ Error string }{err.Error()}) 213 } 214 215 // save to the database 216 if err := database.SaveUser(user); err != nil { 217 return err 218 } 219 220 // add the user to the session object 221 SetCookie(w, r, "_sess", user.Email) 222 223 // redirect the user to their dashboard 224 http.Redirect(w, r, "/dashboard", http.StatusSeeOther) 225 return nil 226 }