woodpecker/pkg/handler/app.go
2014-02-08 14:07:02 -07:00

180 lines
5.3 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 {
return RenderTemplate(w, "login.html", nil)
}
// 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 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 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
}