Personal Git forge.

Code git clone ssh://git.poy.ooo:6969/~poyo/farga ZIP
app/auth.go / 4KiB #40ac665d
Raw
package appimport (	"errors"	md "farga/app/middleware"	db "farga/db"	"farga/db/types"	"farga/lib"	"farga/templating"	"net/http"	"strings"	"github.com/google/uuid"	"github.com/gorilla/mux")type RegisterForm struct {	Name        string `form:"name"     validate:"required,min=2,max=40"`	Handle      string `form:"handle"   validate:"required,min=3,max=30"`	Email       string `form:"email"    validate:"required,email"`	Password    string `form:"password" validate:"required,min=8"`	InviteToken string `form:"invite-token"`}type LoginForm struct {	Email    string `form:"email"    validate:"required,email"`	Password string `form:"password" validate:"required,min=8"`}func (a *App) Login(w http.ResponseWriter, r *http.Request) {	switch r.Method {	case "GET":		templating.Render(w, r, "base", "login", map[string]any{			"AllowSignups": a.Config.AllowSignups,		})	case "POST":		form, _ := md.Form[LoginForm](r)		user, err := a.Store.LoginUser(form.Email, form.Password)		if err != nil && (errors.Is(err, db.UserNotFound) || errors.Is(err, db.IncorrectPassword)) { // user not found or incorrect password			http.Redirect(w, r, "/auth/login?err=InvalidCredentials", http.StatusSeeOther)			return		}		session, err := a.Store.NewSession(&user.ID)		if err != nil {			http.Error(w, "Something went wrong while creating your session.", http.StatusInternalServerError)			return		}		lib.SetCookie(w, "session", session.ID.String())		http.Redirect(w, r, "/?msg=AuthSuccess", http.StatusSeeOther)	}}func (a *App) Register(w http.ResponseWriter, r *http.Request) {	vars := mux.Vars(r)	switch r.Method {	case "GET":		inviteToken := vars["token"]		// if signups are disallowed, but the user has an inviteToken		if inviteToken != "" {			invite, ok := a.Store.ValidateInviteToken(inviteToken)			if ok {				// allow user to register				templating.Render(w, r, "base", "register", map[string]any{					"HandleRegex": lib.HandleRegex.String(),					"Invite":      invite,				})			} else {				// token is invvalid/expired				templating.Render(w, r, "base", "invite/invalid_token")			}		} else if a.Config.AllowSignups { // if signups are allowed			templating.Render(w, r, "base", "register", map[string]any{				"HandleRegex": lib.HandleRegex.String(),			})		} else { // if neither, just reject them.			templating.Render(w, r, "base", "invite_only")		}	case "POST":		form, ok := md.Form[RegisterForm](r)		if !ok {			http.Error(w, "Internal error.", http.StatusInternalServerError)			return		}		if !a.Config.AllowSignups && form.InviteToken == "" {			http.Redirect(w, r, "/auth/register?err=Forbidden", http.StatusSeeOther)			return		}		var invite types.Invite		if form.InviteToken != "" {			invite, ok = a.Store.ValidateInviteToken(form.InviteToken)			if !ok {				templating.Render(w, r, "base", "invite/invalid_token")				return			}		}		if !lib.ValidateHandle(form.Handle) {			http.Redirect(w, r, "?err=UserInvalidHandle", http.StatusSeeOther)			return		}		if !lib.ValidateUsername(form.Name) {			http.Redirect(w, r, "?err=UserInvalidHandle", http.StatusSeeOther)			return		}		password, err := lib.GenerateHash(form.Password)		if err != nil {			http.Error(w, "Something went wrong while generating your password's hash. Please try again!", 500)			return		}		user := types.User{			Name:         strings.TrimSpace(form.Name),			Handle:       strings.TrimSpace(form.Handle),			Email:        strings.TrimSpace(form.Email),			PasswordHash: password,			Config: types.UserConfig{				GitDefaultBranch: lib.GitDefaultBranch,			},		}		// set to admin if invite token says so.		if invite.ID != uuid.Nil && invite.Role == uint(types.RoleAdmin) {			user.Role = types.RoleAdmin		} else {			user.Role = types.RoleUser		}		if form.InviteToken != "" {			err = a.Store.NewUserWithInvite(&user, form.InviteToken)		} else {			err = a.Store.NewUser(&user)		}		if err != nil {			if errors.Is(err, db.ErrInvalidInvite) {				templating.Render(w, r, "base", "invite/invalid_token")				return			}			constrainedField := strings.Replace(err.Error(), "UNIQUE constraint failed: users.", "That ", 1) + " has already been claimed."			http.Error(w, constrainedField, 500)			return		}		session, err := a.Store.NewSession(&user.ID)		if err != nil {			http.Error(w, "Something went wrong while creating your session.", http.StatusInternalServerError)			return		}		lib.SetCookie(w, "session", session.ID.String())		http.Redirect(w, r, "/?msg=AuthSuccess", http.StatusSeeOther)	}}func (a *App) Logout(w http.ResponseWriter, r *http.Request) {	switch r.Method {	case "GET":		templating.Render(w, r, "base", "logout")	case "POST":		session := r.Context().Value(lib.SessionKey).(string)		err := a.Store.DeleteSession(session)		if err != nil {			http.Error(w, "Something went wrong while creating your session.", http.StatusInternalServerError)			return		}		lib.DeleteCookie(w, "session")		http.Redirect(w, r, "/auth/login?msg=LogoutSuccess", http.StatusFound)	}}