package http import ( "encoding/json" "net/http" "github.com/example/storage-appliance/internal/auth" ) // LoginHandler handles user login func (a *App) LoginHandler(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { // Show login page data := map[string]interface{}{ "Title": "Login", } if err := templates.ExecuteTemplate(w, "login", data); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } return } // Handle POST login var req struct { Username string `json:"username"` Password string `json:"password"` } if r.Header.Get("Content-Type") == "application/json" { if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "invalid request", http.StatusBadRequest) return } } else { req.Username = r.FormValue("username") req.Password = r.FormValue("password") } // Authenticate user userStore := auth.NewUserStore(a.DB) user, err := userStore.Authenticate(r.Context(), req.Username, req.Password) if err != nil { if r.Header.Get("HX-Request") == "true" { w.Header().Set("Content-Type", "text/html") w.WriteHeader(http.StatusUnauthorized) w.Write([]byte(`
Invalid username or password
`)) } else { http.Error(w, "invalid credentials", http.StatusUnauthorized) } return } // Create session sessionStore := auth.NewSessionStore(a.DB) session, err := sessionStore.CreateSession(r.Context(), user.ID) if err != nil { http.Error(w, "failed to create session", http.StatusInternalServerError) return } // Set session cookie http.SetCookie(w, &http.Cookie{ Name: auth.SessionCookieName, Value: session.Token, Path: "/", HttpOnly: true, Secure: false, // Set to true in production with HTTPS SameSite: http.SameSiteStrictMode, MaxAge: int(auth.SessionDuration.Seconds()), }) // Set CSRF token cookie csrfToken := generateCSRFToken() http.SetCookie(w, &http.Cookie{ Name: "csrf_token", Value: csrfToken, Path: "/", HttpOnly: false, // Needed for HTMX to read it Secure: false, SameSite: http.SameSiteStrictMode, MaxAge: int(auth.SessionDuration.Seconds()), }) // Redirect or return success if r.Header.Get("HX-Request") == "true" { w.Header().Set("HX-Redirect", "/dashboard") w.WriteHeader(http.StatusOK) } else { http.Redirect(w, r, "/dashboard", http.StatusFound) } } // LogoutHandler handles user logout func (a *App) LogoutHandler(w http.ResponseWriter, r *http.Request) { // Get session token from cookie cookie, err := r.Cookie(auth.SessionCookieName) if err == nil { // Delete session sessionStore := auth.NewSessionStore(a.DB) sessionStore.DeleteSession(r.Context(), cookie.Value) } // Clear cookies http.SetCookie(w, &http.Cookie{ Name: auth.SessionCookieName, Value: "", Path: "/", HttpOnly: true, MaxAge: -1, }) http.SetCookie(w, &http.Cookie{ Name: "csrf_token", Value: "", Path: "/", HttpOnly: false, MaxAge: -1, }) if r.Header.Get("HX-Request") == "true" { w.Header().Set("HX-Redirect", "/login") w.WriteHeader(http.StatusOK) } else { http.Redirect(w, r, "/login", http.StatusFound) } }