Go-Backend (chi, pgx, golang-migrate) + React/TS-Frontend als PWA. Enthalten: Auth inkl. OIDC, Dateien mit Versionen und Papierkorb, Freigaben (Links + intern), WebDAV, Gruppenordner, Admin/Theming, Volltextsuche mit OCR, eigener PDF-Betrachter und WOPI-Office (Collabora/OnlyOffice). Nicht im Repo: deploy/.env (Sitzungsschlüssel, DB- und Admin-Passwort) sowie alle Daten- und Build-Verzeichnisse – siehe .gitignore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
68 lines
1.8 KiB
Go
68 lines
1.8 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"aether/pkg/response"
|
|
)
|
|
|
|
type contextKey int
|
|
|
|
const keyUser contextKey = iota
|
|
|
|
// RequireAuth loads the session user and injects it into context.
|
|
// Returns 401 if not authenticated.
|
|
func RequireAuth(ss *SessionStore, store *Store) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
id, ok := ss.GetUserID(r)
|
|
if !ok {
|
|
response.Error(w, http.StatusUnauthorized, "authentication required")
|
|
return
|
|
}
|
|
user, err := store.GetByID(r.Context(), id)
|
|
if err != nil {
|
|
response.Error(w, http.StatusUnauthorized, "authentication required")
|
|
return
|
|
}
|
|
ctx := context.WithValue(r.Context(), keyUser, user)
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|
|
}
|
|
|
|
// RequireAdmin additionally checks that the user is an admin.
|
|
func RequireAdmin(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
user := UserFromContext(r.Context())
|
|
if user == nil || !user.IsAdmin {
|
|
response.Error(w, http.StatusForbidden, "admin access required")
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// CSRF validates the double-submit CSRF token for state-changing requests.
|
|
func CSRF(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch r.Method {
|
|
case http.MethodGet, http.MethodHead, http.MethodOptions:
|
|
next.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
if !ValidateCSRF(r) {
|
|
response.Error(w, http.StatusForbidden, "invalid CSRF token")
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// UserFromContext retrieves the authenticated user from context (may be nil).
|
|
func UserFromContext(ctx context.Context) *User {
|
|
u, _ := ctx.Value(keyUser).(*User)
|
|
return u
|
|
}
|