package app import ( "errors" md "farga/app/middleware" "farga/app/templating" db "farga/db" "farga/db/types" "farga/lib" "io" "net/http" "strings" ) type RegisterForm struct { Name string `form:"name" validate:"required,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"` } 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") 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 { io.WriteString(w, "Something went wrong while creating your session.") 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) { switch r.Method { case "GET": templating.Render(w, r, "base", "register", map[string]any{ "HandleRegex": lib.HandleRegex.String(), }) case "POST": form, _ := md.Form[RegisterForm](r) if !lib.ValidateHandle(form.Handle) { 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, }, } err = a.Store.NewUser(&user) if err != nil { 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 { io.WriteString(w, "Goddammit! Something went wrong while creating your session. Try logging in instead.") return } lib.SetCookie(w, "session", session.ID.String()) http.Redirect(w, r, "/?msg=AuthSuccess", http.StatusTemporaryRedirect) } } 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.RemoveSession(session) if err != nil { io.WriteString(w, "Something went wrong while deleting your session: "+err.Error()) return } lib.DeleteCookie(w, "session") http.Redirect(w, r, "/auth/login?msg=LogoutSuccess", http.StatusFound) } }