package handlers import ( "errors" "net/http" "strings" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" "github.com/jackc/pgx/v5/pgtype" "wherewoof/frontend/internal/auth" "wherewoof/frontend/internal/db" ) func (a *App) RegisterPage(w http.ResponseWriter, r *http.Request) { a.render(w, r, "register", "Create account", nil, "") } func (a *App) Register(w http.ResponseWriter, r *http.Request) { email := strings.ToLower(strings.TrimSpace(r.FormValue("email"))) password := r.FormValue("password") name := strings.TrimSpace(r.FormValue("name")) if email == "" || password == "" { a.render(w, r, "register", "Create account", nil, "Email and password are required.") return } if confirm := strings.ToLower(strings.TrimSpace(r.FormValue("confirm_email"))); confirm != "" && confirm != email { a.render(w, r, "register", "Create account", nil, "Emails do not match.") return } if len(password) < 8 { a.render(w, r, "register", "Create account", nil, "Password must be at least 8 characters.") return } if len([]byte(password)) > 72 { a.render(w, r, "register", "Create account", nil, "Password must be 72 bytes or fewer.") return } hash, err := auth.HashPassword(password) if err != nil { http.Error(w, "internal error", http.StatusInternalServerError) return } user, err := a.Queries.CreateUser(r.Context(), db.CreateUserParams{ Email: email, PasswordHash: hash, Name: pgtype.Text{String: name, Valid: name != ""}, }) if err != nil { var pgErr *pgconn.PgError if errors.As(err, &pgErr) && pgErr.Code == "23505" { a.render(w, r, "register", "Create account", nil, "That email is already registered.") return } http.Error(w, "internal error", http.StatusInternalServerError) return } if err := auth.SetUserID(w, r, user.ID); err != nil { http.Error(w, "internal error", http.StatusInternalServerError) return } http.Redirect(w, r, "/account", http.StatusSeeOther) } func (a *App) LoginPage(w http.ResponseWriter, r *http.Request) { a.render(w, r, "login", "Log in", nil, "") } func (a *App) Login(w http.ResponseWriter, r *http.Request) { email := strings.ToLower(strings.TrimSpace(r.FormValue("email"))) password := r.FormValue("password") user, err := a.Queries.GetUserByEmail(r.Context(), email) if err != nil { if !errors.Is(err, pgx.ErrNoRows) { http.Error(w, "internal error", http.StatusInternalServerError) return } a.render(w, r, "login", "Log in", nil, "Invalid email or password.") return } if !auth.CheckPassword(user.PasswordHash, password) { a.render(w, r, "login", "Log in", nil, "Invalid email or password.") return } if err := auth.SetUserID(w, r, user.ID); err != nil { http.Error(w, "internal error", http.StatusInternalServerError) return } http.Redirect(w, r, "/account", http.StatusSeeOther) } func (a *App) Logout(w http.ResponseWriter, r *http.Request) { _ = auth.Clear(w, r) http.Redirect(w, r, "/", http.StatusSeeOther) }