From 42d8ed4ccada1b9b3f063ca4ef68dff2844009eb Mon Sep 17 00:00:00 2001 From: xengineering Date: Sun, 24 May 2026 12:35:46 +0200 Subject: Add authentication middleware This protects all parts of /api/* except the /api/register URL. This one must stay accessible to allow new users. --- handlers.go | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'handlers.go') diff --git a/handlers.go b/handlers.go index f23171f..99b4eaf 100644 --- a/handlers.go +++ b/handlers.go @@ -6,15 +6,24 @@ import ( "io/fs" "log" "net/http" + "strings" +) + +const ( + COOKIE_NAME_TOKEN = `token` ) //go:embed build/frontend/public var frontendEmbed embed.FS func init() { - router.HandleFunc("/api/version", version) + // /api/registration must always be accessible without authentication router.HandleFunc("/api/registration", registration).Methods("POST") + protected := router.PathPrefix("/api").Subrouter() + protected.Use(authentication) + protected.HandleFunc("/version", version) + // frontend must come last to make sure /api takes precedence frontend, err := fs.Sub(frontendEmbed, "build/frontend/public") if err != nil { @@ -35,7 +44,7 @@ func registration(w http.ResponseWriter, r *http.Request) { } cookie := http.Cookie{ - Name: "token", + Name: COOKIE_NAME_TOKEN, Value: token.Private(), HttpOnly: true, Secure: true, @@ -46,3 +55,28 @@ func registration(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "%s\n", token.Public()) } + +func authentication(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + cookie, err := r.Cookie(COOKIE_NAME_TOKEN) + if err != nil { + http.Error(w, "No authentication cookie present.", http.StatusForbidden) + return + } + + candidate, found := strings.CutPrefix(cookie.String(), COOKIE_NAME_TOKEN + "=") + if !found { + http.Error(w, "Unexpected cookie prefix.", http.StatusForbidden) + return + } + + user := authenticate(candidate) + if user == nil { + http.Error(w, "Unknown authentication token.", http.StatusForbidden) + return + } + + log.Printf("Authenticated user number %d\n", *user) + next.ServeHTTP(w, r) + }) +} -- cgit v1.3