centralize admin auth in hooks + rate limit uploads
Created by: jedmund
Summary
Architecture audit phase 3 — structural auth enforcement and defense-in-depth rate limits.
-
A-4 · Move admin auth from per-route
checkAdminAuth()calls to a single/api/admin/*prefix check inhooks.server.ts. New admin endpoints can't accidentally ship unauthenticated — forgetting the guard is no longer possible. Dropped 21 redundant guards across admin routes;checkAdminAuth()stays available for routes that mix public reads with admin writes (/api/projects,/api/posts,/api/albums,/api/media,/api/tags) until A-10 relocates those. -
A-9 (scaled) · Refactored the rate limiter to support per-prefix configs. Added a 30/min bucket for
/api/media/uploadand/api/media/bulk-uploadas defense in depth — these are session-gated, so rate-limiting is self-DoS protection rather than a brute-force defense. Existing login (5/min) and project unlock (5/min) limits unchanged. - Also removed two unused Apple Music test fixtures (
debug/test-find-album,debug/test-simple-search) that were noise.
Net: −233 lines across 24 files.
Test plan
-
pnpm check— baseline 116 errors / 9 warnings, no new ones introduced -
Unauthenticated GET /api/admin/media-stats→ 401{error:"Unauthorized"} -
Authenticated GET /api/admin/media-stats→ 200 with stats -
curl -X POST /api/media/upload31 times → 429 on request 31 (verify the 30/min bucket) -
curl -X POST /admin/login6 times → 429 on request 6 (verify login bucket still works, independent of upload bucket) -
Admin UI still loads and can perform uploads/edits without "Unauthorized" flashes