refactor and documentation

This commit is contained in:
2026-01-03 15:41:21 +02:00
parent 1468937589
commit ca569d25bc
5 changed files with 159 additions and 312 deletions

View File

@@ -3,24 +3,19 @@
package api_auth
import (
"encoding/json"
"fmt"
"log/slog"
"net/http"
"time"
"git.oblat.lv/alex/triggerssmith/internal/auth"
"git.oblat.lv/alex/triggerssmith/internal/config"
"git.oblat.lv/alex/triggerssmith/internal/server"
"github.com/go-chi/chi/v5"
"github.com/golang-jwt/jwt/v5"
)
func setRefreshCookie(w http.ResponseWriter, token string, ttl time.Duration, secure bool) {
http.SetCookie(w, &http.Cookie{
Name: "refresh_token",
Value: token,
Path: "/api/auth/refresh",
Path: "/api/auth/",
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
MaxAge: int(ttl.Seconds()),
@@ -58,165 +53,3 @@ func MustRoute(config *config.Config, authService *auth.Service) func(chi.Router
r.Post("/revoke", h.handleRevoke) // not implemented
}
}
type registerRequest struct {
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
}
type registerResponse struct {
UserID uint `json:"id"`
Username string `json:"username"`
}
func (h *authHandler) handleRegister(w http.ResponseWriter, r *http.Request) {
var req registerRequest
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
http.Error(w, "Invalid request payload", http.StatusBadRequest)
return
}
user, err := h.a.Register(req.Username, req.Email, req.Password)
if err != nil {
slog.Error("Failed to register user", "error", err)
http.Error(w, "Registration failed", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(registerResponse{
UserID: user.ID,
Username: user.Username,
})
if err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
}
type loginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
type loginResponse struct {
Token string `json:"accessToken"`
}
func (h *authHandler) handleLogin(w http.ResponseWriter, r *http.Request) {
var req loginRequest
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
http.Error(w, "Invalid request payload", http.StatusBadRequest)
return
}
tokens, err := h.a.Login(req.Username, req.Password)
if err != nil {
http.Error(w, "Authentication failed", http.StatusUnauthorized)
return
}
setRefreshCookie(w, tokens.Refresh, h.cfg.Auth.RefreshTokenTTL, false)
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(loginResponse{Token: tokens.Access})
if err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
return
}
}
func (h *authHandler) handleLogout(w http.ResponseWriter, r *http.Request) {
claims, err := h.a.AuthenticateRequest(r)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
rjti := claims.(jwt.MapClaims)["rjti"].(string)
err = h.a.Logout(rjti)
if err != nil {
http.Error(w, "Failed to logout, taking cookie anyways", http.StatusInternalServerError)
}
http.SetCookie(w, &http.Cookie{
Name: "refresh_token",
Value: "",
MaxAge: -1,
Path: "/api/users/refresh",
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
})
if err == nil {
w.WriteHeader(http.StatusOK)
}
}
type meResponse struct {
UserID uint `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
}
func (h *authHandler) handleMe(w http.ResponseWriter, r *http.Request) {
refresh_token_cookie, err := r.Cookie("refresh_token")
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
userID, err := h.a.ValidateRefreshToken(refresh_token_cookie.Value)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
user, err := h.a.Get("id", fmt.Sprint(userID))
if err != nil {
http.Error(w, "Failed to get user", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(meResponse{
UserID: user.ID,
Username: user.Username,
Email: user.Email,
})
if err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
return
}
}
type GetUserDataResponse meResponse
func (h *authHandler) handleGetUserData(w http.ResponseWriter, r *http.Request) {
by := r.URL.Query().Get("by")
value := r.URL.Query().Get("value")
if value == "" {
value = r.URL.Query().Get(by)
}
user, err := h.a.Get(by, value)
if err != nil {
http.Error(w, "Failed to get user", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(meResponse{
UserID: user.ID,
Username: user.Username,
Email: user.Email,
})
if err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
return
}
}
func (h *authHandler) handleRevoke(w http.ResponseWriter, r *http.Request) {
server.NotImplemented(w)
}
func (h *authHandler) handleRefresh(w http.ResponseWriter, r *http.Request) {
server.NotImplemented(w)
}