gophish/auth/auth.go

131 lines
3.6 KiB
Go

package auth
import (
"encoding/gob"
"errors"
"fmt"
"io"
"net/http"
"crypto/rand"
"github.com/gophish/gophish/models"
ctx "github.com/gorilla/context"
"github.com/gorilla/securecookie"
"github.com/gorilla/sessions"
"golang.org/x/crypto/bcrypt"
)
//init registers the necessary models to be saved in the session later
func init() {
gob.Register(&models.User{})
gob.Register(&models.Flash{})
}
// Store contains the session information for the request
var Store = sessions.NewCookieStore(
[]byte(securecookie.GenerateRandomKey(64)), //Signing key
[]byte(securecookie.GenerateRandomKey(32)))
// ErrInvalidPassword is thrown when a user provides an incorrect password.
var ErrInvalidPassword = errors.New("Invalid Password")
// ErrEmptyPassword is thrown when a user provides a blank password to the register
// or change password functions
var ErrEmptyPassword = errors.New("Password cannot be blank")
// ErrPasswordMismatch is thrown when a user provides passwords that do not match
var ErrPasswordMismatch = errors.New("Passwords must match")
// Login attempts to login the user given a request.
func Login(r *http.Request) (bool, error) {
username, password := r.FormValue("username"), r.FormValue("password")
session, _ := Store.Get(r, "gophish")
u, err := models.GetUserByUsername(username)
if err != nil && err != models.ErrUsernameTaken {
return false, err
}
//If we've made it here, we should have a valid user stored in u
//Let's check the password
err = bcrypt.CompareHashAndPassword([]byte(u.Hash), []byte(password))
if err != nil {
ctx.Set(r, "user", nil)
return false, ErrInvalidPassword
}
ctx.Set(r, "user", u)
session.Values["id"] = u.Id
return true, nil
}
// Register attempts to register the user given a request.
func Register(r *http.Request) (bool, error) {
username := r.FormValue("username")
password1 := r.FormValue("password")
password2 := r.FormValue("confirm_password")
u, err := models.GetUserByUsername(username)
// If we have an error which is not simply indicating that no user was found, report it
if err != nil {
fmt.Println(err)
return false, err
}
u = models.User{}
// If we've made it here, we should have a valid username given
// Check that the passsword isn't blank
if password1 == "" {
return false, ErrEmptyPassword
}
// Make sure passwords match
if password1 != password2 {
return false, ErrPasswordMismatch
}
// Let's create the password hash
h, err := bcrypt.GenerateFromPassword([]byte(password1), bcrypt.DefaultCost)
if err != nil {
return false, err
}
u.Username = username
u.Hash = string(h)
u.ApiKey = GenerateSecureKey()
err = models.PutUser(&u)
return true, nil
}
// GenerateSecureKey creates a secure key to use
// as an API key
func GenerateSecureKey() string {
// Inspired from gorilla/securecookie
k := make([]byte, 32)
io.ReadFull(rand.Reader, k)
return fmt.Sprintf("%x", k)
}
func ChangePassword(r *http.Request) error {
u := ctx.Get(r, "user").(models.User)
currentPw := r.FormValue("current_password")
pw1 := r.FormValue("new_password")
pw2 := r.FormValue("confirm_new_password")
// Check the current password
err := bcrypt.CompareHashAndPassword([]byte(u.Hash), []byte(currentPw))
if err != nil {
return ErrInvalidPassword
}
// Check that the new password isn't blank
if pw1 == "" {
return ErrEmptyPassword
}
// Check that new passwords match
if pw1 != pw2 {
return ErrPasswordMismatch
}
// Generate the new hash
h, err := bcrypt.GenerateFromPassword([]byte(pw1), bcrypt.DefaultCost)
if err != nil {
return err
}
u.Hash = string(h)
if err = models.PutUser(&u); err != nil {
return err
}
return nil
}