From b70dfdb80d897abf77b74a78eb59b984dfba64d4 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Wed, 20 May 2026 14:08:43 +0300 Subject: Block bootstrap.html access after first user created (o9) serveBootstrap now calls CountUsers() and redirects to /login.html when the user count is non-zero, preventing the bootstrap form from being reachable on an already-configured instance. Co-Authored-By: Claude Opus 4.7 --- player-server/internal/api/handlers.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'player-server/internal/api/handlers.go') diff --git a/player-server/internal/api/handlers.go b/player-server/internal/api/handlers.go index 9cffa50..7f05435 100644 --- a/player-server/internal/api/handlers.go +++ b/player-server/internal/api/handlers.go @@ -169,7 +169,23 @@ func (s *Server) serveLogin(w http.ResponseWriter, r *http.Request) { s.serveFile(w, r, "login.html") } +// serveBootstrap serves bootstrap.html only when no users exist yet. +// Once the first admin account has been created the bootstrap page must no +// longer be reachable — redirecting to /login.html prevents an attacker +// from reaching the form on an already-configured instance. func (s *Server) serveBootstrap(w http.ResponseWriter, r *http.Request) { + if s.authSvc != nil { + count, err := s.authSvc.CountUsers(r.Context()) + if err != nil { + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + if count > 0 { + // Bootstrap is complete; send browsers to the login page. + http.Redirect(w, r, "/login.html", http.StatusTemporaryRedirect) + return + } + } s.serveFile(w, r, "bootstrap.html") } -- cgit v1.2.3