diff --git a/zddc/internal/handler/profilehandler.go b/zddc/internal/handler/profilehandler.go index 684ff3c..c1e6013 100644 --- a/zddc/internal/handler/profilehandler.go +++ b/zddc/internal/handler/profilehandler.go @@ -49,6 +49,21 @@ func ServeProfile(cfg config.Config, ring *LogRing, idx *archive.Index, w http.R email := EmailFromContext(r) + // adminOnly wraps an admin-gated sub-handler. Routes that need root- + // admin authority (sudo-style, elevation-gated) deny with 404 (not + // 403) so a non-admin probing the namespace can't enumerate which + // admin-only resources exist. Single helper instead of five copy- + // pasted gates. + adminOnly := func(fn http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if !zddc.IsAdmin(cfg.Root, PrincipalFromContext(r)) { + http.NotFound(w, r) + return + } + fn(w, r) + } + } + switch sub { case "/", "": serveProfilePage(cfg, w, r) @@ -57,35 +72,25 @@ func ServeProfile(cfg config.Config, ring *LogRing, idx *archive.Index, w http.R case "/projects": serveProfileProjectsCreate(cfg, w, r) case "/whoami": - if !zddc.IsAdmin(cfg.Root, PrincipalFromContext(r)) { - http.NotFound(w, r) - return - } - serveProfileWhoami(cfg, email, w, r) + adminOnly(func(w http.ResponseWriter, r *http.Request) { + serveProfileWhoami(cfg, email, w, r) + })(w, r) case "/config": - if !zddc.IsAdmin(cfg.Root, PrincipalFromContext(r)) { - http.NotFound(w, r) - return - } - serveProfileConfig(cfg, w, r) + adminOnly(func(w http.ResponseWriter, r *http.Request) { + serveProfileConfig(cfg, w, r) + })(w, r) case "/logs": - if !zddc.IsAdmin(cfg.Root, PrincipalFromContext(r)) { - http.NotFound(w, r) - return - } - serveProfileLogs(ring, w, r) + adminOnly(func(w http.ResponseWriter, r *http.Request) { + serveProfileLogs(ring, w, r) + })(w, r) case "/effective-policy": - if !zddc.IsAdmin(cfg.Root, PrincipalFromContext(r)) { - http.NotFound(w, r) - return - } - serveProfileEffectivePolicy(cfg, w, r) + adminOnly(func(w http.ResponseWriter, r *http.Request) { + serveProfileEffectivePolicy(cfg, w, r) + })(w, r) case "/reindex": - if !zddc.IsAdmin(cfg.Root, PrincipalFromContext(r)) { - http.NotFound(w, r) - return - } - serveProfileReindex(cfg, idx, email, w, r) + adminOnly(func(w http.ResponseWriter, r *http.Request) { + serveProfileReindex(cfg, idx, email, w, r) + })(w, r) default: http.NotFound(w, r) }