package web import ( "context" "net/http" "time" ) const sessionCookieName = "nidus_session" type ctxKey string const userCtxKey ctxKey = "web_username" // userFromContext returns the logged-in username for the current request, // or "" if unauthenticated. func userFromContext(ctx context.Context) string { u, _ := ctx.Value(userCtxKey).(string) return u } // requireLogin wraps a handler so that it redirects to /login when no // valid session cookie is present, otherwise it stores the username in // the request context for downstream handlers to use. func (s *Server) requireLogin(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie(sessionCookieName) if err != nil { http.Redirect(w, r, "/web/login", http.StatusSeeOther) return } username, err := s.dbase.SessionUser(cookie.Value) if err != nil { s.clearSessionCookie(w) http.Redirect(w, r, "/web/login", http.StatusSeeOther) return } ctx := context.WithValue(r.Context(), userCtxKey, username) next(w, r.WithContext(ctx)) } } func (s *Server) setSessionCookie(w http.ResponseWriter, token string) { http.SetCookie(w, &http.Cookie{ Name: sessionCookieName, Value: token, Path: "/", HttpOnly: true, Secure: true, SameSite: http.SameSiteLaxMode, Expires: time.Now().Add(7 * 24 * time.Hour), }) } func (s *Server) clearSessionCookie(w http.ResponseWriter) { http.SetCookie(w, &http.Cookie{ Name: sessionCookieName, Value: "", Path: "/", HttpOnly: true, Secure: true, SameSite: http.SameSiteLaxMode, MaxAge: -1, }) }