middleware

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Feb 1, 2026 License: GPL-3.0 Imports: 18 Imported by: 0

Documentation

Overview

Package middleware provides HTTP middleware for authentication, authorization, and request context handling.

Package middleware provides HTTP middleware for authentication, authorization, and request context handling.

Package middleware provides HTTP middleware for the OCMS application.

Package middleware provides HTTP middleware for authentication, authorization, and request context handling.

Package middleware provides HTTP middleware for authentication, authorization, and request context handling.

Package middleware provides HTTP middleware for the OCMS application.

Index

Constants

View Source
const (
	SessionKeyUserID    = "user_id"
	SessionKeyAdminLang = "admin_lang"
)

Session keys for storing user data and preferences.

View Source
const (
	RoleAdmin  = "admin"
	RoleEditor = "editor"
)

User roles - must match handler.Role* constants.

View Source
const LanguageCookieName = "ocms_lang"

LanguageCookieName is the cookie name for language preference.

Variables

This section is empty.

Functions

func APIKeyAuth

func APIKeyAuth(db *sql.DB) func(http.Handler) http.Handler

APIKeyAuth creates middleware that validates API key authentication. It checks the Authorization header for a Bearer token.

func APIRateLimit

func APIRateLimit(rps float64, burst int) func(http.Handler) http.Handler

APIRateLimit creates middleware that rate limits requests per API key. rps is requests per second, burst is the maximum burst size.

func Auth

func Auth(sm *scs.SessionManager) func(http.Handler) http.Handler

Auth creates middleware that requires authentication. It checks for a valid user session and redirects to login if not authenticated.

func CSRF

func CSRF(cfg CSRFConfig) func(http.Handler) http.Handler

CSRF returns a middleware that provides CSRF protection. It uses filippo.io/csrf/gorilla under the hood, which uses Fetch metadata headers instead of cookies for CSRF protection.

func GetAPIKey

func GetAPIKey(r *http.Request) *store.ApiKey

GetAPIKey retrieves the API key from the request context. Returns nil if no API key is in context.

func GetAdminLang

func GetAdminLang(r *http.Request) string

GetAdminLang retrieves the admin UI language preference from the session. Falls back to Accept-Language header, then database default language.

func GetClientIP

func GetClientIP(r *http.Request) string

GetClientIP extracts the client IP from the request. It checks X-Forwarded-For and X-Real-IP headers for proxied requests, and falls back to RemoteAddr with port stripped.

func GetRequestPath

func GetRequestPath(ctx context.Context) string

GetRequestPath retrieves the request path from the context.

func GetRequestURL added in v0.2.0

func GetRequestURL(r *http.Request) string

GetRequestURL extracts the request URL path from the request. Returns the URL path without query string for cleaner logging.

func GetSiteName

func GetSiteName(r *http.Request) string

GetSiteName retrieves the site name from the request context. Returns "oCMS" as default if not found.

func GetUser

func GetUser(r *http.Request) *store.User

GetUser retrieves the current user from the request context. Returns nil if no user is in context.

func GetUserEmail

func GetUserEmail(r *http.Request) string

GetUserEmail returns the current user's email from context, or empty string if not found.

func GetUserID

func GetUserID(r *http.Request) int64

GetUserID returns the current user's ID from context, or 0 if not found. Safe to use in logging where a zero-value is acceptable.

func GetUserIDPtr

func GetUserIDPtr(r *http.Request) *int64

GetUserIDPtr returns a pointer to the current user's ID from context, or nil if not found. Useful for optional user ID parameters in event logging.

func InitLanguageCookies added in v0.1.0

func InitLanguageCookies(isDev bool)

InitLanguageCookies configures the Secure flag for language cookies. Call this during application startup with isDev=true for development mode.

func Language

func Language(db *sql.DB) func(http.Handler) http.Handler

Language creates middleware that detects and sets the current language. Priority order: 1. Query parameter ?lang=XX (explicit language switch, updates cookie) 2. URL parameter {lang} from chi router (e.g., /ru/page-slug) 3. For homepage only: Cookie preference, then Accept-Language header 4. Default language (for all non-prefixed content pages)

This ensures that /page-slug always shows in default language, while /ru/page-slug shows in Russian, and the homepage uses user preference.

func LoadSiteConfig

func LoadSiteConfig(db *sql.DB, cacheManager *cache.Manager) func(http.Handler) http.Handler

LoadSiteConfig creates middleware that loads site configuration (like site_name) into context. If cacheManager is provided, it will be used for faster config lookups.

func LoadUser

func LoadUser(sm *scs.SessionManager, db *sql.DB) func(http.Handler) http.Handler

LoadUser creates middleware that loads the current user into the request context. This should be used after Auth middleware.

func OptionalAPIKeyAuth

func OptionalAPIKeyAuth(db *sql.DB) func(http.Handler) http.Handler

OptionalAPIKeyAuth creates middleware that optionally validates API key authentication. Unlike APIKeyAuth, this middleware does not require authentication - it simply adds the API key to context if a valid one is provided.

func ParseAPIKeyPermissions

func ParseAPIKeyPermissions(apiKey *store.ApiKey) []string

ParseAPIKeyPermissions parses the JSON permissions string from an API key. Returns an empty slice if the permissions string is empty or invalid.

func RequestPath

func RequestPath(next http.Handler) http.Handler

RequestPath creates middleware that stores the request path in the context. This is used by the logging handler to include the URL in error logs.

func RequireAdmin

func RequireAdmin() func(http.Handler) http.Handler

RequireAdmin creates middleware that requires admin role. Shorthand for RequireRole(RoleAdmin).

func RequireAnyPermission

func RequireAnyPermission(requiredPerms ...string) func(http.Handler) http.Handler

RequireAnyPermission creates middleware that requires any one of the specified permissions. This should be used after APIKeyAuth middleware.

func RequireEditor

func RequireEditor() func(http.Handler) http.Handler

RequireEditor creates middleware that requires at least editor role. Allows both admin and editor users.

func RequirePermission

func RequirePermission(permission string) func(http.Handler) http.Handler

RequirePermission creates middleware that requires a specific API permission. This should be used after APIKeyAuth middleware.

func RequireRole

func RequireRole(minRole string) func(http.Handler) http.Handler

RequireRole creates middleware that requires a minimum user role. Roles are hierarchical: admin > editor. Public users have no admin access. For example, RequireRole("editor") allows both admin and editor users.

func SecurityHeaders

func SecurityHeaders(cfg SecurityHeadersConfig) func(http.Handler) http.Handler

SecurityHeaders returns a middleware that adds security headers to responses.

func SetLanguageCookie

func SetLanguageCookie(w http.ResponseWriter, langCode string)

SetLanguageCookie sets the language preference cookie. The Secure flag is set based on the configuration from InitLanguageCookies.

func SetSessionManager

func SetSessionManager(sm *scs.SessionManager)

SetSessionManager sets the global session manager for admin language retrieval. This should be called during application initialization.

func SkipCSRF

func SkipCSRF(paths ...string) func(http.Handler) http.Handler

SkipCSRF returns a middleware that skips CSRF protection for specific paths. This is useful for API endpoints that use token-based authentication.

func StaticCache

func StaticCache(maxAge int) func(http.Handler) http.Handler

StaticCache adds Cache-Control headers for static files.

func Timeout

func Timeout(timeout time.Duration) func(http.Handler) http.Handler

Timeout wraps an http.Handler and applies a request timeout. If the handler doesn't complete within the timeout duration, a 503 Service Unavailable response is sent.

func ValidateTrustedOrigins

func ValidateTrustedOrigins(origins []string) error

ValidateTrustedOrigins checks that origins are in the correct format. The filippo.io/csrf library expects host:port format, not full URLs.

func WriteAPIError

func WriteAPIError(w http.ResponseWriter, statusCode int, code, message string, details map[string]string)

WriteAPIError writes a JSON error response.

Types

type APIError

type APIError struct {
	Error struct {
		Code    string            `json:"code"`
		Message string            `json:"message"`
		Details map[string]string `json:"details,omitempty"`
	} `json:"error"`
}

APIError represents a JSON error response for the API.

type CSRFConfig

type CSRFConfig struct {
	// AuthKey is a 32-byte key used to authenticate the CSRF token.
	// This should be the same as the session secret for simplicity.
	AuthKey []byte

	// ErrorHandler is called when CSRF validation fails.
	ErrorHandler http.Handler

	// TrustedOrigins is a list of origins that are allowed to make
	// cross-origin requests. This is useful for AJAX requests.
	TrustedOrigins []string
}

CSRFConfig holds configuration for CSRF protection. Note: filippo.io/csrf/gorilla uses Fetch metadata headers instead of cookies, so cookie-related options (Secure, Domain, Path, MaxAge, SameSite) are no longer used.

func DefaultCSRFConfig

func DefaultCSRFConfig(authKey []byte, isDev bool) CSRFConfig

DefaultCSRFConfig returns a CSRFConfig with sensible defaults.

type ContextKey

type ContextKey string

ContextKey is a type for context keys to avoid collisions.

const (
	ContextKeyUser        ContextKey = "user"
	ContextKeySiteName    ContextKey = "site_name"
	ContextKeyRequestPath ContextKey = "request_path"
)

Context keys for user data.

const (
	ContextKeyLanguage     ContextKey = "language"
	ContextKeyLanguageCode ContextKey = "language_code"
)

Context keys for language data.

const ContextKeyAPIKey ContextKey = "api_key"

ContextKeyAPIKey is the context key for API key data.

type GlobalRateLimiter

type GlobalRateLimiter struct {
	// contains filtered or unexported fields
}

GlobalRateLimiter provides a global rate limiter for unauthenticated requests.

func NewGlobalRateLimiter

func NewGlobalRateLimiter(rps float64, burst int) *GlobalRateLimiter

NewGlobalRateLimiter creates a new global rate limiter.

func (*GlobalRateLimiter) HTMLMiddleware

func (rl *GlobalRateLimiter) HTMLMiddleware() func(http.Handler) http.Handler

HTMLMiddleware returns the rate limiting middleware for public routes (returns plain text errors). This is suitable for login and other public HTML form endpoints.

func (*GlobalRateLimiter) Middleware

func (rl *GlobalRateLimiter) Middleware() func(http.Handler) http.Handler

Middleware returns the rate limiting middleware for API routes (returns JSON errors).

type LanguageInfo

type LanguageInfo struct {
	ID         int64
	Code       string
	Name       string
	NativeName string
	Direction  string
	IsDefault  bool
}

LanguageInfo holds language data for the request context.

func GetLanguage

func GetLanguage(r *http.Request) *LanguageInfo

GetLanguage retrieves the current language from the request context. Returns nil if no language is in context.

type LoginProtection

type LoginProtection struct {
	// contains filtered or unexported fields
}

LoginProtection provides combined IP rate limiting and account lockout protection.

func NewLoginProtection

func NewLoginProtection(cfg LoginProtectionConfig) *LoginProtection

NewLoginProtection creates a new login protection instance.

func (*LoginProtection) CheckIPRateLimit

func (lp *LoginProtection) CheckIPRateLimit(ip string) bool

CheckIPRateLimit checks if the IP is rate limited. Returns true if the request should be allowed.

func (*LoginProtection) GetRemainingAttempts

func (lp *LoginProtection) GetRemainingAttempts(email string) int

GetRemainingAttempts returns the number of remaining attempts before lockout.

func (*LoginProtection) IsAccountLocked

func (lp *LoginProtection) IsAccountLocked(email string) (bool, time.Duration)

IsAccountLocked checks if an account is currently locked. Returns (locked, remainingTime).

func (*LoginProtection) Middleware

func (lp *LoginProtection) Middleware() func(http.Handler) http.Handler

Middleware returns HTTP middleware for IP rate limiting on login. This should be applied to the login POST route.

func (*LoginProtection) RecordFailedAttempt

func (lp *LoginProtection) RecordFailedAttempt(email string) (bool, time.Duration)

RecordFailedAttempt records a failed login attempt. Returns (locked, lockDuration) if the account is now locked.

func (*LoginProtection) RecordSuccessfulLogin

func (lp *LoginProtection) RecordSuccessfulLogin(email string)

RecordSuccessfulLogin clears failed attempt tracking for an account.

type LoginProtectionConfig

type LoginProtectionConfig struct {
	// IPRateLimit is requests per second per IP (default: 0.5 = 1 request per 2 seconds)
	IPRateLimit float64
	// IPBurst is the maximum burst size for IP rate limiting (default: 5)
	IPBurst int
	// MaxFailedAttempts before account lockout (default: 5)
	MaxFailedAttempts int
	// LockoutDuration is base lockout time, doubles with each lockout (default: 15 minutes)
	LockoutDuration time.Duration
	// AttemptWindow is the time window for counting failed attempts (default: 15 minutes)
	AttemptWindow time.Duration
}

LoginProtectionConfig holds configuration for login protection.

func DefaultLoginProtectionConfig

func DefaultLoginProtectionConfig() LoginProtectionConfig

DefaultLoginProtectionConfig returns sensible defaults.

type SecurityHeadersConfig

type SecurityHeadersConfig struct {
	// IsDevelopment indicates if the application is running in development mode.
	// When true, HSTS is disabled and CSP is more permissive.
	IsDevelopment bool

	// ContentSecurityPolicy is the CSP header value.
	// If empty, a default policy is used.
	ContentSecurityPolicy string

	// HSTSMaxAge is the max-age for Strict-Transport-Security header in seconds.
	// Default is 31536000 (1 year). Set to 0 to disable HSTS.
	HSTSMaxAge int

	// HSTSIncludeSubDomains includes subdomains in HSTS policy.
	HSTSIncludeSubDomains bool

	// HSTSPreload enables HSTS preload list eligibility.
	HSTSPreload bool

	// FrameOptions controls the X-Frame-Options header.
	// Valid values: "DENY", "SAMEORIGIN", or empty to disable.
	FrameOptions string

	// ReferrerPolicy controls the Referrer-Policy header.
	// Default is "strict-origin-when-cross-origin".
	ReferrerPolicy string

	// PermissionsPolicy controls the Permissions-Policy header.
	// If empty, a restrictive default policy is used.
	PermissionsPolicy string

	// ExcludePaths are paths that should skip security headers.
	// Useful for API endpoints that need different policies.
	ExcludePaths []string
}

SecurityHeadersConfig holds configuration for security headers.

func DefaultSecurityHeadersConfig

func DefaultSecurityHeadersConfig(isDev bool) SecurityHeadersConfig

DefaultSecurityHeadersConfig returns a SecurityHeadersConfig with sensible defaults.

Jump to

Keyboard shortcuts

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