// Copyright 2023 wanderer // SPDX-License-Identifier: AGPL-3.0-only package handlers import ( "context" "errors" "net/http" "git.dotya.ml/mirre-mt/pcmt/ent" 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 Signup() echo.HandlerFunc { return func(c echo.Context) error { addHeaders(c) sess, _ := session.Get(setting.SessionCookieName(), c) if sess != nil { log.Info("gorilla session", "endpoint", "signup") username := sess.Values["username"] if username != nil { return c.Redirect(http.StatusFound, "/home") } } // tpl := getTmpl("signup.tmpl") csrf := c.Get("csrf").(string) // secure := c.Request().URL.Scheme == "https" // cookieCSRF := &http.Cookie{ // Name: "_csrf", // Value: csrf, // // SameSite: http.SameSiteStrictMode, // SameSite: http.SameSiteLaxMode, // MaxAge: 3600, // Secure: secure, // HttpOnly: true, // } // c.SetCookie(cookieCSRF) err := c.Render( http.StatusOK, "signup.tmpl", page{ AppName: setting.AppName(), AppVer: appver, Title: "Sign up", CSRF: csrf, DevelMode: setting.IsDevel(), Current: "signup", }, ) if err != nil { log.Warnf("error: %q", err) return renderErrorPage( c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), err.Error(), ) } return nil } } func SignupPost(client *ent.Client) echo.HandlerFunc { return func(c echo.Context) error { addHeaders(c) cu := new(userSignup) if err := c.Bind(cu); err != nil { return renderErrorPage( c, http.StatusBadRequest, http.StatusText(http.StatusBadRequest), err.Error(), ) } if cu.Username == "" || cu.Email == "" || cu.Password == "" { c.Logger().Error("username or email or password not set, returning to /singup") return c.Redirect(http.StatusFound, "/singup") } username := cu.Username email := cu.Email passwd := cu.Password ctx := context.WithValue(context.Background(), moduser.CtxKey{}, slogger) exists, err := moduser.Exists(ctx, client, username, email) if err != nil { c.Logger().Error("error checking whether user exists", err) return renderErrorPage( c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), err.Error(), ) } if exists { c.Logger().Error("username/email already taken") return c.Redirect(http.StatusSeeOther, "/signup") } u, err := moduser.CreateUser( ctx, client, email, username, passwd, ) if err != nil { if errors.Is(err, errors.New("username is not unique")) { c.Logger().Error("username already taken") // TODO: re-render signup page with a flash message // stating what went wrong. return c.Redirect(http.StatusSeeOther, "/signup") } return renderErrorPage( c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)+" - failed to create schema resources", err.Error(), ) } log.Infof("successfully registered user '%s'", u.Username) log.Debug("user details", "id", u.ID, "email", u.Email, "isAdmin", u.IsAdmin) secure := c.Request().URL.Scheme == "https" //nolint:goconst sess, _ := session.Get(setting.SessionCookieName(), c) 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") } }