package middlewares import ( "net/http" "strings" "time" "git.aiterp.net/lucifer/lucifer/internal/httperr" "git.aiterp.net/lucifer/lucifer/models" "github.com/gorilla/mux" ) // Session is a middleware that adds a Session to the request context if there // is one. func Session(sessions models.SessionRepository, users models.UserRepository) mux.MiddlewareFunc { clearCookie := &http.Cookie{ Name: "lucifer_session", Value: "", Path: "/", Expires: time.Unix(0, 0), HttpOnly: true, } redirectFailure := func(next http.Handler, w http.ResponseWriter, r *http.Request) { if !strings.HasPrefix(r.URL.Path, "/api/") || strings.HasPrefix(r.URL.Path, "/api/user/") { next.ServeHTTP(w, r) } else { httperr.Respond(w, httperr.ErrLoginRequired) } } return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() // Find cookie cookie, err := r.Cookie("lucifer_session") if err != nil || cookie == nil { redirectFailure(next, w, r) return } // Check session existence session, err := sessions.FindByID(r.Context(), cookie.Value) if err != nil { http.SetCookie(w, clearCookie) redirectFailure(next, w, r) return } ctx = session.InContext(ctx) user, err := users.FindByID(r.Context(), session.UserID) if err != nil { http.SetCookie(w, clearCookie) redirectFailure(next, w, r) return } ctx = user.InContext(ctx) // Check if session has expired if session.Expired() { http.SetCookie(w, clearCookie) redirectFailure(next, w, r) return } // Proceed. next.ServeHTTP(w, r.WithContext(ctx)) }) } }