package api import ( "context" "net/http" "strings" "markdownhub/internal/auth" ) type contextKey string const ( ctxUserID contextKey = "userID" ctxIsAdmin contextKey = "isAdmin" ) func (s *Server) requireAuth(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { tokenStr := extractToken(r) if tokenStr == "" { http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized) return } userID, isAdmin, err := auth.ValidateToken(tokenStr, s.secret) if err != nil || userID == "" { http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized) return } ctx := context.WithValue(r.Context(), ctxUserID, userID) ctx = context.WithValue(ctx, ctxIsAdmin, isAdmin) next(w, r.WithContext(ctx)) } } func (s *Server) requireAdmin(next http.HandlerFunc) http.HandlerFunc { return s.requireAuth(func(w http.ResponseWriter, r *http.Request) { isAdmin, _ := r.Context().Value(ctxIsAdmin).(bool) if !isAdmin { http.Error(w, `{"error":"forbidden"}`, http.StatusForbidden) return } next(w, r) }) } func extractToken(r *http.Request) string { // Cookie first if c, err := r.Cookie("authToken"); err == nil && c.Value != "" { return c.Value } // Bearer header h := r.Header.Get("Authorization") if strings.HasPrefix(h, "Bearer ") { return h[7:] } return "" } func getUserID(r *http.Request) string { v, _ := r.Context().Value(ctxUserID).(string) return v } func (s *Server) audit(userID, action, detail string) { s.db.Exec("INSERT INTO audit_log (user_id, action, detail) VALUES (?, ?, ?)", userID, action, detail) }