package handler import ( "context" "net/http" "time" "projectreshoot/internal/models" "projectreshoot/internal/view/component/form" "projectreshoot/internal/view/page" "git.haelnorr.com/h/golib/cookies" "git.haelnorr.com/h/golib/hws" "git.haelnorr.com/h/golib/hwsauth" "github.com/pkg/errors" "github.com/uptrace/bun" ) func validateRegistration( ctx context.Context, tx bun.Tx, r *http.Request, ) (*models.UserBun, error) { formUsername := r.FormValue("username") formPassword := r.FormValue("password") formConfirmPassword := r.FormValue("confirm-password") unique, err := models.IsUsernameUnique(ctx, tx, formUsername) if err != nil { return nil, errors.Wrap(err, "models.CheckUsernameUnique") } if !unique { return nil, errors.New("Username is taken") } if formPassword != formConfirmPassword { return nil, errors.New("Passwords do not match") } if len(formPassword) > 72 { return nil, errors.New("Password exceeds maximum length of 72 bytes") } user, err := models.CreateUser(ctx, tx, formUsername, formPassword) if err != nil { return nil, errors.Wrap(err, "models.CreateNewUser") } return user, nil } func RegisterRequest( server *hws.Server, auth *hwsauth.Authenticator[*models.UserBun, bun.Tx], db *bun.DB, ) http.Handler { return http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(r.Context(), 15*time.Second) defer cancel() // Start the transaction tx, err := db.BeginTx(ctx, nil) if err != nil { err := server.ThrowError(w, r, hws.HWSError{ StatusCode: http.StatusServiceUnavailable, Message: "Failed to start transaction", Error: err, }) if err != nil { server.ThrowFatal(w, err) } return } r.ParseForm() user, err := validateRegistration(ctx, tx, r) if err != nil { tx.Rollback() if err.Error() != "Username is taken" && err.Error() != "Passwords do not match" && err.Error() != "Password exceeds maximum length of 72 bytes" { err := server.ThrowError(w, r, hws.HWSError{ StatusCode: http.StatusInternalServerError, Message: "Registration failed", Error: err, }) if err != nil { server.ThrowFatal(w, err) } } else { form.RegisterForm(err.Error()).Render(r.Context(), w) } return } rememberMe := checkRememberMe(r) err = auth.Login(w, r, user, rememberMe) if err != nil { tx.Rollback() err := server.ThrowError(w, r, hws.HWSError{ StatusCode: http.StatusInternalServerError, Message: "Login failed", Error: err, }) if err != nil { server.ThrowFatal(w, err) } return } tx.Commit() pageFrom := cookies.CheckPageFrom(w, r) w.Header().Set("HX-Redirect", pageFrom) }, ) } // Handles a request to view the login page. Will attempt to set "pagefrom" // cookie so a successful login can redirect the user to the page they came func RegisterPage(trustedHost string) http.Handler { return http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { cookies.SetPageFrom(w, r, trustedHost) page.Register().Render(r.Context(), w) }, ) }