Documentation
¶
Index ¶
- Constants
- Variables
- func Auth(jwtSecret string) func(http.Handler) http.Handler
- func AuthCookie(name, value string, maxAge int) *http.Cookie
- func ClientIP(r *http.Request, trustForwardedIP bool) string
- func EnsureUser(jwtSecret string, queries *store.Queries, provisionGuest GuestProvisioner, ...) func(http.Handler) http.Handler
- func ErrorLog(queries *store.Queries) func(http.Handler) http.Handler
- func OptionalUser(jwtSecret string) func(http.Handler) http.Handler
- func ParseSessionCookie(r *http.Request, jwtSecret string) (id, email string, ok bool)
- func SetCookieSecure(secure bool)
- func SetSessionCookie(w http.ResponseWriter, jwtSecret string, userID uuid.UUID, email string) error
- func UserFromContext(ctx context.Context) (id, email string, ok bool)
- func UserIDFromContext(ctx context.Context) (string, bool)
- type GuestGate
- type GuestProvisioner
- type IPLimiter
- type Limits
- type RateLimiter
Constants ¶
const GuestEmailSuffix = "@guest.local"
GuestEmailSuffix must match the suffix ProvisionGuestUser writes: the limiter tiers on it instead of reading the DB.
Variables ¶
var SessionExpiryDays = 30
SessionExpiryDays is the lifetime of a signed session cookie. Wrappers may override it at startup.
Functions ¶
func Auth ¶
Auth requires a valid session cookie, returning 401 if missing or invalid. Use for routes that must not auto-provision.
func AuthCookie ¶
AuthCookie builds a cookie with the standard auth attributes so the Secure flag is consistent across session, anon-id and oauth-state.
func ClientIP ¶
ClientIP extracts the requester's IP. With trustForwardedIP set it reads the RIGHT-most X-Forwarded-For entry — the IP a single trusted proxy (Caddy) appends as the real peer, which a client cannot forge (any injected value lands to the left of the append).
func EnsureUser ¶
func EnsureUser( jwtSecret string, queries *store.Queries, provisionGuest GuestProvisioner, gate GuestGate, onProvision func(outcome string), ) func(http.Handler) http.Handler
EnsureUser attaches a user to the request context. If the cookie is missing or invalid, gate (if any) runs first, then a guest user is provisioned and its session cookie set. onProvision (nil-safe) reports the "created" outcome for metrics. Use for routes that allow anonymous access.
func OptionalUser ¶
OptionalUser attaches a user to the request context iff the session cookie is valid. Never provisions. Use for read endpoints that serve a useful response to an unauthenticated client (e.g. /api/me returning anon).
func ParseSessionCookie ¶
ParseSessionCookie reads and verifies the session cookie. Returns (id, email, true) on success. Used outside middleware (e.g. OAuth callback) to read the current user without forcing auto-provision.
func SetCookieSecure ¶
func SetCookieSecure(secure bool)
SetCookieSecure configures the Secure attribute for all auth cookies.
func SetSessionCookie ¶
func SetSessionCookie(w http.ResponseWriter, jwtSecret string, userID uuid.UUID, email string) error
SetSessionCookie writes the signed session cookie. Shared by EnsureUser auto-provisioning and the wrapper login flows.
func UserFromContext ¶
UserFromContext returns the request's user id and email, if any.
Types ¶
type GuestGate ¶
type GuestGate func(w http.ResponseWriter, r *http.Request) bool
GuestGate is an optional pre-provision policy check (captcha, per-IP caps, global capacity). It returns true to allow provisioning; on rejection it writes the HTTP response itself and returns false. A nil gate always allows — the self-host default.
type GuestProvisioner ¶
GuestProvisioner creates a guest user (with thread and default flow) and returns its ID + synthetic email. Injected so middleware need not import the handler package.
type IPLimiter ¶
type IPLimiter struct {
// contains filtered or unexported fields
}
IPLimiter gates guest provisioning. Each browser (identified by a signed ofc_anon cookie, minted on first contact) gets its own per-window budget so users behind one proxy IP don't starve each other; a higher per-IP ceiling backstops cookie-rotation floods.
func NewIPLimiter ¶
func NewIPLimiter( window time.Duration, perBrowser, perIP int, trustForwardedIP bool, secret string, ) *IPLimiter
NewIPLimiter builds a guest-provisioning limiter over the given window.
type Limits ¶
Limits carries every tunable per-minute cap. Signed-in users and guests are tiered read-vs-write by user_id; anonymous reads get a single coarse per-IP ceiling as a flood backstop.
type RateLimiter ¶
type RateLimiter struct {
// contains filtered or unexported fields
}
RateLimiter enforces per-minute request caps, tiered anon/guest/user.
func NewRateLimiter ¶
func NewRateLimiter(trustForwardedIP bool, onReject func(tier, kind string)) *RateLimiter
NewRateLimiter builds a limiter. onReject (nil-safe) is called with the tier and kind ("read"/"write") labels whenever a request is throttled, letting a wrapper record metrics without coupling core to a metrics backend.
func (*RateLimiter) Middleware ¶
func (rl *RateLimiter) Middleware(next http.Handler) http.Handler
Middleware throttles requests by tier. With all caps at zero (the self-host default) every request is allowed.
func (*RateLimiter) SetLimits ¶
func (rl *RateLimiter) SetLimits(l Limits)
SetLimits updates the caps at runtime.