Help us shape the future of Go! Take the 2026 Go Developer Survey

middleware

package
v0.2.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2026 License: AGPL-3.0 Imports: 20 Imported by: 0

Documentation

Index

Constants

View Source
const GuestEmailSuffix = "@guest.local"

GuestEmailSuffix must match the suffix ProvisionGuestUser writes: the limiter tiers on it instead of reading the DB.

Variables

View Source
var SessionExpiryDays = 30

SessionExpiryDays is the lifetime of a signed session cookie. Wrappers may override it at startup.

Functions

func Auth

func Auth(jwtSecret string) func(http.Handler) http.Handler

Auth requires a valid session cookie, returning 401 if missing or invalid. Use for routes that must not auto-provision.

func AuthCookie

func AuthCookie(name, value string, maxAge int) *http.Cookie

AuthCookie builds a cookie with the standard auth attributes so the Secure flag is consistent across session, anon-id and oauth-state.

func ClientIP

func ClientIP(r *http.Request, trustForwardedIP bool) string

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 ErrorLog

func ErrorLog(queries *store.Queries) func(http.Handler) http.Handler

ErrorLog records 4xx/5xx responses to error_events for later triage.

func OptionalUser

func OptionalUser(jwtSecret string) func(http.Handler) http.Handler

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

func ParseSessionCookie(r *http.Request, jwtSecret string) (id, email string, ok bool)

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

func UserFromContext(ctx context.Context) (id, email string, ok bool)

UserFromContext returns the request's user id and email, if any.

func UserIDFromContext

func UserIDFromContext(ctx context.Context) (string, bool)

UserIDFromContext returns the request's user id, 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

type GuestProvisioner func(ctx context.Context, queries *store.Queries) (uuid.UUID, string, error)

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.

func (*IPLimiter) Allow

func (l *IPLimiter) Allow(w http.ResponseWriter, r *http.Request) (ok bool, reason string)

Allow reports whether a new guest may be provisioned for this request, minting the browser cookie when absent. Both the per-browser and per-IP windows must have headroom; the returned reason ("browser"/"ip") names the exhausted one when denied.

func (*IPLimiter) SetLimits

func (l *IPLimiter) SetLimits(perBrowser, perIP int)

SetLimits updates the per-browser and per-IP caps at runtime. Non-positive values are ignored (they'd deny every request).

type Limits

type Limits struct {
	ReadGuest, WriteGuest int32
	ReadUser, WriteUser   int32
	AnonIPCeiling         int32
}

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL