woodpecker/pkg/handler/app.go
Brad Rydzewski 4b412d3a26 added code to prevent panic if /login is reached but no settings exist
minor styling. added success and fail message to top of /signup screen
modified open_registration to boolean value in database
2014-02-15 18:56:48 -07:00

226 lines
6.5 KiB
Go

package handler
import (
"crypto/rand"
"io"
"log"
"net/http"
"time"
"github.com/dchest/authcookie"
"github.com/dchest/passwordreset"
"github.com/drone/drone/pkg/database"
"github.com/drone/drone/pkg/mail"
. "github.com/drone/drone/pkg/model"
)
var (
// Secret key used to sign auth cookies,
// password reset tokens, etc.
secret = generateRandomKey(256)
)
// GenerateRandomKey creates a random key of size length bytes
func generateRandomKey(strength int) []byte {
k := make([]byte, strength)
if _, err := io.ReadFull(rand.Reader, k); err != nil {
return nil
}
return k
}
// Returns an HTML index.html page if the user is
// not currently authenticated, otherwise redirects
// the user to their personal dashboard screen
func Index(w http.ResponseWriter, r *http.Request) error {
// is the user already authenticated then
// redirect to the dashboard page
if _, err := r.Cookie("_sess"); err == nil {
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
return nil
}
// otherwise redirect to the login page
http.Redirect(w, r, "/login", http.StatusSeeOther)
return nil
}
// Return an HTML form for the User to login.
func Login(w http.ResponseWriter, r *http.Request) error {
var settings, _ = database.GetSettings()
data := struct {
Settings *Settings
}{settings}
return RenderTemplate(w, "login.html", &data)
}
// Terminate the User session.
func Logout(w http.ResponseWriter, r *http.Request) error {
DelCookie(w, r, "_sess")
http.Redirect(w, r, "/login", http.StatusSeeOther)
return nil
}
// Return an HTML form for the User to request a password reset.
func Forgot(w http.ResponseWriter, r *http.Request) error {
return RenderTemplate(w, "forgot.html", nil)
}
// Return an HTML form for the User to perform a password reset.
// This page must be visited from a Password Reset email that
// contains a hash to verify the User's identity.
func Reset(w http.ResponseWriter, r *http.Request) error {
return RenderTemplate(w, "reset.html", &struct{ Error string }{""})
}
// Return an HTML form for the User to signup.
func SignUp(w http.ResponseWriter, r *http.Request) error {
var settings, _ = database.GetSettings()
if settings == nil || !settings.OpenInvitations {
http.Redirect(w, r, "/login", http.StatusSeeOther)
return nil
}
return RenderTemplate(w, "signup.html", nil)
}
// Return an HTML form to register for a new account. This
// page must be visited from a Signup email that contains
// a hash to verify the Email address is correct.
func Register(w http.ResponseWriter, r *http.Request) error {
return RenderTemplate(w, "register.html", &struct{ Error string }{""})
}
func ForgotPost(w http.ResponseWriter, r *http.Request) error {
email := r.FormValue("email")
// attempt to retrieve the user by email address
user, err := database.GetUserEmail(email)
if err != nil {
log.Printf("could not find user %s to reset password. %s", email, err)
// if we can't find the email, we still display
// the template to the user. This prevents someone
// from trying to guess passwords through trial & error
return RenderTemplate(w, "forgot_sent.html", nil)
}
// hostname from settings
hostname := database.SettingsMust().URL().String()
// generate the password reset token
token := passwordreset.NewToken(user.Email, 12*time.Hour, []byte(user.Password), secret)
data := struct {
Host string
User *User
Token string
}{hostname, user, token}
// send the email message async
go func() {
if err := mail.SendPassword(email, data); err != nil {
log.Printf("error sending password reset email to %s. %s", email, err)
}
}()
// render the template indicating a success
return RenderTemplate(w, "forgot_sent.html", nil)
}
func ResetPost(w http.ResponseWriter, r *http.Request) error {
// verify the token and extract the username
token := r.FormValue("token")
email, err := passwordreset.VerifyToken(token, database.GetPassEmail, secret)
if err != nil {
return RenderTemplate(w, "reset.html", &struct{ Error string }{"Your password reset request is expired."})
}
// get the user from the database
user, err := database.GetUserEmail(email)
if err != nil {
return RenderTemplate(w, "reset.html", &struct{ Error string }{"Unable to locate user account."})
}
// get the new password
password := r.FormValue("password")
if err := user.SetPassword(password); err != nil {
return RenderTemplate(w, "reset.html", &struct{ Error string }{err.Error()})
}
// save to the database
if err := database.SaveUser(user); err != nil {
return RenderTemplate(w, "reset.html", &struct{ Error string }{"Unable to update password. Please try again"})
}
// add the user to the session object
SetCookie(w, r, "_sess", user.Email)
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
return nil
}
func SignUpPost(w http.ResponseWriter, r *http.Request) error {
// if self-registration is disabled we should display an
// error message to the user.
if !database.SettingsMust().OpenInvitations {
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
return nil
}
// generate the password reset token
email := r.FormValue("email")
token := authcookie.New(email, time.Now().Add(12*time.Hour), secret)
// get the hostname from the database for use in the email
hostname := database.SettingsMust().URL().String()
// data used to generate the email template
data := struct {
Host string
Email string
Token string
}{hostname, email, token}
// send the email message async
go mail.SendActivation(email, data)
return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK)
}
func RegisterPost(w http.ResponseWriter, r *http.Request) error {
// verify the token and extract the username
token := r.FormValue("token")
email := authcookie.Login(token, secret)
if len(email) == 0 {
return RenderTemplate(w, "register.html", &struct{ Error string }{"Your registration email is expired."})
}
// set the email and name
user := NewUser(r.FormValue("name"), email)
// set the new password
password := r.FormValue("password")
if err := user.SetPassword(password); err != nil {
return RenderTemplate(w, "register.html", &struct{ Error string }{err.Error()})
}
// verify fields are correct
if err := user.Validate(); err != nil {
return RenderTemplate(w, "register.html", &struct{ Error string }{err.Error()})
}
// save to the database
if err := database.SaveUser(user); err != nil {
return err
}
// add the user to the session object
SetCookie(w, r, "_sess", user.Email)
// redirect the user to their dashboard
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
return nil
}