diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-17 15:25:52 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-17 15:25:52 +0300 |
| commit | 914bd7cd6aa14e839332a98d91c30b19865b0cf2 (patch) | |
| tree | 02b11537237a204048589e14ed24938b805e42f7 /internal/api/middleware.go | |
| parent | 3b24f0e1be832584d6550e8cc3e5d24329f66f90 (diff) | |
Restructure repo: move Go server into player-server/
Diffstat (limited to 'internal/api/middleware.go')
| -rw-r--r-- | internal/api/middleware.go | 116 |
1 files changed, 0 insertions, 116 deletions
diff --git a/internal/api/middleware.go b/internal/api/middleware.go deleted file mode 100644 index 8fcf1e3..0000000 --- a/internal/api/middleware.go +++ /dev/null @@ -1,116 +0,0 @@ -package api - -import ( - "context" - "net/http" - "strings" - - "codeberg.org/snonux/player/internal/auth" - "codeberg.org/snonux/player/internal/model" - "codeberg.org/snonux/player/internal/service" -) - -type ctxKey int - -const ( - sessionCtxKey ctxKey = iota - userCtxKey -) - -// Middleware holds dependencies for middleware constructors. -type Middleware struct { - authSvc service.AuthService - sm auth.SessionManager -} - -// NewMiddleware creates middleware handlers. -func NewMiddleware(authSvc service.AuthService, sm auth.SessionManager) *Middleware { - return &Middleware{authSvc: authSvc, sm: sm} -} - -// RequireSession validates the session cookie and injects the session into request context. -// For HTML page requests (Accept: text/html), redirects to /login.html instead of returning 401. -func (mw *Middleware) RequireSession(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - cookie, err := r.Cookie("session") - if err != nil { - if wantsHTML(r) { - http.Redirect(w, r, "/login.html", http.StatusTemporaryRedirect) - return - } - http.Error(w, "unauthorized", http.StatusUnauthorized) - return - } - sess, err := mw.sm.ValidateSession(r.Context(), cookie.Value) - if err != nil || sess == nil { - if wantsHTML(r) { - http.Redirect(w, r, "/login.html", http.StatusTemporaryRedirect) - return - } - http.Error(w, "unauthorized", http.StatusUnauthorized) - return - } - ctx := context.WithValue(r.Context(), sessionCtxKey, sess) - next.ServeHTTP(w, r.WithContext(ctx)) - }) -} - -// wantsHTML returns true if the request appears to be from a browser expecting an HTML page. -func wantsHTML(r *http.Request) bool { - accept := r.Header.Get("Accept") - return strings.Contains(accept, "text/html") -} - -// RequireAdmin ensures the authenticated user is an admin. -func (mw *Middleware) RequireAdmin(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - sess, ok := r.Context().Value(sessionCtxKey).(*model.Session) - if !ok || sess == nil { - http.Error(w, "unauthorized", http.StatusUnauthorized) - return - } - user, err := mw.authSvc.GetUserByID(r.Context(), sess.UserID) - if err != nil || user == nil || !user.IsAdmin { - http.Error(w, "forbidden", http.StatusForbidden) - return - } - ctx := context.WithValue(r.Context(), userCtxKey, user) - next.ServeHTTP(w, r.WithContext(ctx)) - }) -} - -// BootstrapRedirect redirects all requests to /bootstrap.html when no users exist. -func (mw *Middleware) BootstrapRedirect(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if isBootstrapPublic(r.URL.Path) { - next.ServeHTTP(w, r) - return - } - if mw.authSvc == nil { - http.Error(w, "internal server error", http.StatusInternalServerError) - return - } - count, err := mw.authSvc.CountUsers(r.Context()) - if err != nil { - http.Error(w, "internal server error", http.StatusInternalServerError) - return - } - if count == 0 { - http.Redirect(w, r, "/bootstrap.html", http.StatusTemporaryRedirect) - return - } - next.ServeHTTP(w, r) - }) -} - -func isBootstrapPublic(path string) bool { - switch path { - case "/bootstrap.html", "/api/bootstrap", "/login.html", "/api/login", "/healthz", "/readyz", - "/favicon.svg", "/favicon.ico", "/logo.svg", "/logo.png", "/manifest.json", "/sw.js": - return true - } - if strings.HasPrefix(path, "/css/") || strings.HasPrefix(path, "/js/") || strings.HasPrefix(path, "/images/") { - return true - } - return false -} |
