151 lines
3.1 KiB
Go
151 lines
3.1 KiB
Go
package routes
|
|
|
|
import (
|
|
"errors"
|
|
"html/template"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"git.soup.land/soup/shelves/internal/auth"
|
|
"git.soup.land/soup/shelves/internal/errorsx"
|
|
"git.soup.land/soup/shelves/internal/forms"
|
|
"git.soup.land/soup/shelves/internal/httpx"
|
|
"git.soup.land/soup/shelves/internal/templates/components"
|
|
)
|
|
|
|
type loginForm struct {
|
|
password string
|
|
redirectTo string
|
|
}
|
|
|
|
type loginFormErrors struct {
|
|
password error
|
|
}
|
|
|
|
func loginRenderView(f loginForm, e loginFormErrors, ctx Ctx) template.HTML {
|
|
formHtml := components.Form{
|
|
Action: "/login",
|
|
Fields: []components.Field{
|
|
components.Field{
|
|
Label: "Password",
|
|
Type: "password",
|
|
Placeholder: "Password",
|
|
Name: "password",
|
|
Error: errorsx.String(e.password),
|
|
},
|
|
components.Field{
|
|
Type: "hidden",
|
|
Name: "redirectTo",
|
|
Value: f.redirectTo,
|
|
},
|
|
},
|
|
}.HTML()
|
|
|
|
page := components.Page{
|
|
Title: "Login",
|
|
SessionInfo: ctx.SessionInfo,
|
|
Body: formHtml,
|
|
}
|
|
|
|
return page.HTML()
|
|
}
|
|
|
|
func getRedirectTo(r *http.Request) string {
|
|
redirectTo := r.URL.Query().Get("redirectTo")
|
|
if redirectTo == "" {
|
|
redirectTo = "/"
|
|
}
|
|
|
|
redirectTo, err := url.QueryUnescape(redirectTo)
|
|
if err != nil {
|
|
redirectTo = ""
|
|
}
|
|
|
|
return redirectTo
|
|
}
|
|
|
|
func loginGet(w http.ResponseWriter, r *http.Request) {
|
|
ctx := getCtx(r)
|
|
redirectTo := getRedirectTo(r)
|
|
|
|
if ctx.SessionInfo.IsAdmin {
|
|
httpx.SeeOther(w, redirectTo)
|
|
return
|
|
}
|
|
|
|
html(w, loginRenderView(loginForm{redirectTo: redirectTo}, loginFormErrors{}, ctx))
|
|
}
|
|
|
|
func loginParseForm(f *loginForm, e *loginFormErrors, vs url.Values, v *forms.Validator) {
|
|
f.password = vs.Get("password")
|
|
f.redirectTo = vs.Get("redirectTo")
|
|
}
|
|
|
|
func loginPost(w http.ResponseWriter, r *http.Request) {
|
|
ctx := getCtx(r)
|
|
|
|
form := loginForm{}
|
|
errs := loginFormErrors{}
|
|
failed := forms.ParseFormData(r, func(vs url.Values, v *forms.Validator) {
|
|
loginParseForm(&form, &errs, vs, v)
|
|
})
|
|
if failed {
|
|
httpx.BadRequest(w)
|
|
html(w, loginRenderView(form, errs, ctx))
|
|
return
|
|
}
|
|
|
|
if ctx.SessionInfo.IsAdmin {
|
|
httpx.SeeOther(w, form.redirectTo)
|
|
return
|
|
}
|
|
|
|
success, sessionId, err := auth.Login(ctx.DB, form.password)
|
|
if err != nil {
|
|
httpx.InternalServerError(w, err)
|
|
return
|
|
}
|
|
if !success {
|
|
httpx.BadRequest(w)
|
|
|
|
errs.password = errors.New("Incorrect password")
|
|
html(w, loginRenderView(form, errs, ctx))
|
|
return
|
|
}
|
|
|
|
cookie := http.Cookie{Name: "SHELVES_OWNER_SESSION_ID", Value: sessionId}
|
|
cookie.Secure = true
|
|
cookie.HttpOnly = true
|
|
cookie.SameSite = http.SameSiteStrictMode
|
|
cookie.MaxAge = 60 * 60 * 24 * 7 // 7 days
|
|
|
|
http.SetCookie(w, &cookie)
|
|
httpx.SeeOther(w, form.redirectTo)
|
|
}
|
|
|
|
func loginDelete(w http.ResponseWriter, r *http.Request) {
|
|
ctx := getCtx(r)
|
|
httpx.HxRefresh(w)
|
|
|
|
if !ctx.SessionInfo.IsAdmin {
|
|
httpx.OK(w)
|
|
return
|
|
}
|
|
|
|
sessionId := ctx.SessionInfo.SessionId
|
|
err := auth.SessionDelete(ctx.DB, sessionId)
|
|
if err != nil {
|
|
httpx.InternalServerError(w, err)
|
|
return
|
|
}
|
|
|
|
cookie := http.Cookie{Name: "SHELVES_OWNER_SESSION_ID", Value: ""}
|
|
cookie.Secure = true
|
|
cookie.HttpOnly = true
|
|
cookie.SameSite = http.SameSiteStrictMode
|
|
cookie.MaxAge = -1
|
|
|
|
http.SetCookie(w, &cookie)
|
|
httpx.OK(w)
|
|
}
|