// Copyright 2023 wanderer // SPDX-License-Identifier: AGPL-3.0-only package handlers import ( "context" "net/http" "strconv" "git.dotya.ml/mirre-mt/pcmt/ent" passwd "git.dotya.ml/mirre-mt/pcmt/modules/password" moduser "git.dotya.ml/mirre-mt/pcmt/modules/user" "github.com/gorilla/sessions" "github.com/labstack/echo-contrib/session" "github.com/labstack/echo/v4" ) func Signin() echo.HandlerFunc { return func(c echo.Context) error { addHeaders(c) if sess, _ := session.Get(setting.SessionCookieName(), c); sess != nil { username := sess.Values["username"] if username != nil { return c.Redirect(http.StatusFound, "/home") } } return c.Render( http.StatusOK, "signin.tmpl", page{ AppName: setting.AppName(), AppVer: appver, Title: "Sign in", DevelMode: setting.IsDevel(), Current: "signin", }, ) } } func SigninPost(client *ent.Client) echo.HandlerFunc { return func(c echo.Context) error { addHeaders(c) cu := new(userSignin) if err := c.Bind(cu); err != nil { return renderErrorPage( c, http.StatusBadRequest, http.StatusText(http.StatusBadRequest), err.Error(), ) } username := cu.Username password := cu.Password p := page{ AppName: setting.AppName(), AppVer: appver, Title: "Sign in", DevelMode: setting.IsDevel(), Current: "signin", } data := make(map[string]any) if username == "" || password == "" { c.Logger().Error("username or password not set, returning to /signin") data["flash"] = "you need to set both the username and the password" data["form"] = cu p.Data = data return c.Render( http.StatusBadRequest, "signin.tmpl", p, ) } ctx := context.WithValue(context.Background(), moduser.CtxKey{}, slogger) if usr, err := moduser.QueryUser(ctx, client, username); err == nil { log.Info("attempting login", "user", &usr.ID) if !passwd.Compare(usr.Password, password) { log.Warn("wrong credentials", "user", &usr.ID) data["flash"] = "wrong credentials" data["form"] = cu p.Data = data return c.Render( http.StatusBadRequest, "signin.tmpl", p, ) } } else { if ent.IsNotFound(err) { c.Logger().Error("user not found") } else { // just log the error instead of returning it to the user and // redirect back to /signin. c.Logger().Error( http.StatusText(http.StatusUnauthorized)+" "+err.Error(), strconv.Itoa(http.StatusUnauthorized)+" "+http.StatusText(http.StatusUnauthorized)+" "+err.Error(), ) } data["form"] = cu data["flash"] = "wrong credentials" p.Data = data return c.Render( http.StatusBadRequest, "signin.tmpl", p, ) } secure := c.Request().URL.Scheme == "https" //nolint:goconst sess, _ := session.Get(setting.SessionCookieName(), c) if sess != nil { sess.Options = &sessions.Options{ Path: "/", MaxAge: 3600, HttpOnly: true, Secure: secure, SameSite: http.SameSiteStrictMode, } sess.Values["foo"] = "bar" sess.Values["username"] = username err := sess.Save(c.Request(), c.Response()) if err != nil { c.Logger().Error("failed to save session") return renderErrorPage( c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)+" (make sure you've got cookies enabled)", err.Error(), ) } } return c.Redirect(http.StatusMovedPermanently, "/home") } }