package web import ( "net/http" "inventree/internal/auth" "inventree/internal/models" ) // loadSession attaches the current user (if any) to the request context // based on the session cookie. It never blocks the request. func (a *App) loadSession(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie(auth.CookieName) if err != nil || cookie.Value == "" { next.ServeHTTP(w, r) return } u, err := a.Auth.UserForToken(r.Context(), cookie.Value) if err != nil { next.ServeHTTP(w, r) return } r = r.WithContext(auth.WithUser(r.Context(), u)) next.ServeHTTP(w, r) }) } // requireLogin redirects unauthenticated page requests to /login, and // returns 401 for AJAX/API requests instead. func (a *App) requireLogin(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, ok := auth.UserFromContext(r.Context()); !ok { if isAjax(r) { writeErr(w, http.StatusUnauthorized, "not authenticated") return } http.Redirect(w, r, "/login?next="+r.URL.Path, http.StatusSeeOther) return } next(w, r) } } // requireAdmin additionally requires the current user to hold the admin // role. func (a *App) requireAdmin(next http.HandlerFunc) http.HandlerFunc { return a.requireLogin(func(w http.ResponseWriter, r *http.Request) { u, _ := auth.UserFromContext(r.Context()) if !u.IsAdmin() { writeErr(w, http.StatusForbidden, "admin access required") return } next(w, r) }) } func isAjax(r *http.Request) bool { return r.Header.Get("X-Requested-With") == "XMLHttpRequest" || r.Header.Get("HX-Request") != "" } func currentUser(r *http.Request) *models.User { u, _ := auth.UserFromContext(r.Context()) return u }