2026-10-03 10:30:07 -04:00
|
|
|
package server
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"log/slog"
|
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
|
|
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/auth"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// SessionLookup finds the live session a request carries; it returns
|
|
|
|
|
// auth.ErrNoSession when there is none. *auth.SessionManager implements it.
|
|
|
|
|
type SessionLookup interface {
|
|
|
|
|
SessionFor(r *http.Request) (auth.Session, error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// requireSession is the RequireSession middleware. It passes requests with a
|
2026-10-03 10:51:26 -04:00
|
|
|
// live session to next with the session in the context (read it with
|
|
|
|
|
// auth.SessionFrom or auth.ActorFrom); others get 401 unauthenticated.
|
2026-10-03 10:30:07 -04:00
|
|
|
func requireSession(logger *slog.Logger, sessions SessionLookup) func(http.Handler) http.Handler {
|
|
|
|
|
unauthenticated := apiErrorHandler(logger, http.StatusUnauthorized, "unauthenticated", "sign in required")
|
|
|
|
|
internal := apiErrorHandler(logger, http.StatusInternalServerError, "internal", "internal error")
|
|
|
|
|
return func(next http.Handler) http.Handler {
|
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
s, err := sessions.SessionFor(r)
|
|
|
|
|
switch {
|
|
|
|
|
case errors.Is(err, auth.ErrNoSession):
|
|
|
|
|
unauthenticated(w, r)
|
|
|
|
|
case err != nil:
|
|
|
|
|
logger.ErrorContext(r.Context(), "look up session", "error", err)
|
|
|
|
|
internal(w, r)
|
|
|
|
|
default:
|
2026-10-03 10:51:26 -04:00
|
|
|
next.ServeHTTP(w, r.WithContext(auth.WithSession(r.Context(), s)))
|
2026-10-03 10:30:07 -04:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|