lishwist/server/routing/login.go

123 lines
3.2 KiB
Go

package routing
import (
"lishwist/db"
sesh "lishwist/session"
"lishwist/templates"
"log"
"net/http"
"golang.org/x/crypto/bcrypt"
)
type LoginProps struct {
GeneralError string
SuccessfulRegistration bool
Username templates.InputProps
Password templates.InputProps
}
func NewLoginProps() LoginProps {
return LoginProps{
Username: templates.InputProps{
Name: "username",
Required: true,
},
Password: templates.InputProps{
Name: "password",
Type: "password",
Required: true,
},
}
}
func (ctx *Context) Login(w http.ResponseWriter, r *http.Request) {
session, _ := ctx.store.Get(r, "lishwist_user")
props := NewLoginProps()
flash, err := sesh.GetFirstFlash(w, r, session, "login_props")
if err != nil {
http.Error(w, "Something went wrong. Error code: Zuko", http.StatusInternalServerError)
return
}
flashProps, ok := flash.(*LoginProps)
if ok {
props.Username.Value = flashProps.Username.Value
props.GeneralError = flashProps.GeneralError
props.Username.Error = flashProps.Username.Error
props.Password.Error = flashProps.Password.Error
}
flash, err = sesh.GetFirstFlash(w, r, session, "successful_registration")
if err != nil {
http.Error(w, "Something went wrong. Error code: Zuko", http.StatusInternalServerError)
return
}
successfulReg, _ := flash.(bool)
if successfulReg {
props.SuccessfulRegistration = true
}
templates.Execute(w, "login.gotmpl", props)
}
func (ctx *Context) LoginPost(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, "Couldn't parse form", http.StatusBadRequest)
return
}
username := r.Form.Get("username")
password := r.Form.Get("password")
props := NewLoginProps()
props.Username.Value = username
user, err := db.GetUserByName(username)
if err != nil {
log.Printf("Failed to fetch user: %s\n", err)
props.GeneralError = "Username or password invalid"
ctx.RedirectWithFlash(w, r, "/", "login_props", &props)
return
}
if user == nil {
log.Printf("User not found by name: %q\n", username)
props.GeneralError = "Username or password invalid"
ctx.RedirectWithFlash(w, r, "/", "login_props", &props)
return
}
passHash, err := user.GetPassHash()
if err != nil {
log.Println("Failed to get password hash: " + err.Error())
props.GeneralError = "Something went wrong. Error code: Momo"
ctx.RedirectWithFlash(w, r, "/", "login_props", &props)
return
}
err = bcrypt.CompareHashAndPassword(passHash, []byte(password))
if err != nil {
log.Println("Username or password invalid: " + err.Error())
props.GeneralError = "Username or password invalid"
ctx.RedirectWithFlash(w, r, "/", "login_props", &props)
return
}
// NOTE: Overwriting any existing cookie or session here. So we don't care if there's an error
session, _ := ctx.store.Get(r, "lishwist_user")
session.ID = ""
session.Values["authorized"] = true
session.Values["username"] = username
if err := session.Save(r, w); err != nil {
log.Println("Couldn't save session:", err)
http.Error(w, "Something went wrong. Error code: Zuko", http.StatusInternalServerError)
return
}
http.Redirect(w, r, r.URL.Path, http.StatusSeeOther)
}