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
- func APIKeyAuth(db *sql.DB) func(http.Handler) http.Handler
- func APIRateLimit(rps float64, burst int) func(http.Handler) http.Handler
- func Auth(sm *scs.SessionManager) func(http.Handler) http.Handler
- func BlockDeleteInDemoMode(restriction DemoRestriction) func(http.Handler) http.Handler
- func BlockInDemoMode(restriction DemoRestriction) func(http.Handler) http.Handler
- func BlockWriteInDemoMode(restriction DemoRestriction) func(http.Handler) http.Handler
- func CSRF(cfg CSRFConfig) func(http.Handler) http.Handler
- func DemoModeMessageDetailed(restriction DemoRestriction) string
- func GetAPIKey(r *http.Request) *store.ApiKey
- func GetAdminLang(r *http.Request) string
- func GetClientIP(r *http.Request) string
- func GetDemoBlockedMessage(w http.ResponseWriter, r *http.Request) string
- func GetRequestPath(ctx context.Context) string
- func GetRequestURL(r *http.Request) string
- func GetSiteName(r *http.Request) string
- func GetUser(r *http.Request) *store.User
- func GetUserEmail(r *http.Request) string
- func GetUserID(r *http.Request) int64
- func GetUserIDPtr(r *http.Request) *int64
- func InitLanguageCookies(isDev bool)
- func IsDemoMode() bool
- func Language(db *sql.DB) func(http.Handler) http.Handler
- func LoadSiteConfig(db *sql.DB, cacheManager *cache.Manager) func(http.Handler) http.Handler
- func LoadUser(sm *scs.SessionManager, db *sql.DB) func(http.Handler) http.Handler
- func OptionalAPIKeyAuth(db *sql.DB) func(http.Handler) http.Handler
- func OptionalLoadUser(sm *scs.SessionManager, db *sql.DB) func(http.Handler) http.Handler
- func ParseAPIKeyPermissions(apiKey *store.ApiKey) []string
- func RequestPath(next http.Handler) http.Handler
- func RequireAdmin() func(http.Handler) http.Handler
- func RequireAdminWithEventLog(eventService *service.EventService) func(http.Handler) http.Handler
- func RequireAnyPermission(requiredPerms ...string) func(http.Handler) http.Handler
- func RequireEditor() func(http.Handler) http.Handler
- func RequireEditorWithEventLog(eventService *service.EventService) func(http.Handler) http.Handler
- func RequirePermission(permission string) func(http.Handler) http.Handler
- func RequireRole(minRole string) func(http.Handler) http.Handler
- func RequireRoleWithEventLog(minRole string, eventService *service.EventService) func(http.Handler) http.Handler
- func SecurityHeaders(cfg SecurityHeadersConfig) func(http.Handler) http.Handler
- func SetLanguageCookie(w http.ResponseWriter, langCode string)
- func SetSessionManager(sm *scs.SessionManager)
- func SkipCSRF(paths ...string) func(http.Handler) http.Handler
- func StaticCache(maxAge int) func(http.Handler) http.Handler
- func StripTrailingSlash(next http.Handler) http.Handler
- func Timeout(timeout time.Duration) func(http.Handler) http.Handler
- func ValidateTrustedOrigins(origins []string) error
- func WriteAPIError(w http.ResponseWriter, statusCode int, code, message string, ...)
- type APIError
- type CSRFConfig
- type ContextKey
- type DemoRestriction
- type GlobalRateLimiter
- type LanguageInfo
- type LoginProtection
- func (lp *LoginProtection) CheckIPRateLimit(ip string) bool
- func (lp *LoginProtection) GetRemainingAttempts(email string) int
- func (lp *LoginProtection) IsAccountLocked(email string) (bool, time.Duration)
- func (lp *LoginProtection) Middleware() func(http.Handler) http.Handler
- func (lp *LoginProtection) RecordFailedAttempt(email string) (bool, time.Duration)
- func (lp *LoginProtection) RecordSuccessfulLogin(email string)
- type LoginProtectionConfig
- type RedirectsMiddleware
- type SecurityHeadersConfig
Constants ¶
const ( SessionKeyUserID = "user_id" SessionKeyAdminLang = "admin_lang" )
Session keys for storing user data and preferences.
const ( RoleAdmin = "admin" RoleEditor = "editor" )
User roles - must match handler.Role* constants.
const DemoModeMessage = "This action is disabled in demo mode"
DemoModeMessage is the user-friendly message shown when an action is blocked.
const LanguageCookieName = "ocms_lang"
LanguageCookieName is the cookie name for language preference.
Variables ¶
This section is empty.
Functions ¶
func APIKeyAuth ¶
APIKeyAuth creates middleware that validates API key authentication. It checks the Authorization header for a Bearer token.
func APIRateLimit ¶
APIRateLimit creates middleware that rate limits requests per API key. rps is requests per second, burst is the maximum burst size.
func Auth ¶
Auth creates middleware that requires authentication. It checks for a valid user session and redirects to login if not authenticated.
func BlockDeleteInDemoMode ¶ added in v0.7.0
func BlockDeleteInDemoMode(restriction DemoRestriction) func(http.Handler) http.Handler
BlockDeleteInDemoMode creates middleware that blocks DELETE requests in demo mode. Allows GET, POST (for create/edit), but blocks DELETE operations.
func BlockInDemoMode ¶ added in v0.7.0
func BlockInDemoMode(restriction DemoRestriction) func(http.Handler) http.Handler
BlockInDemoMode creates middleware that blocks the request in demo mode. Use this to wrap entire routes that should be completely disabled.
func BlockWriteInDemoMode ¶ added in v0.7.0
func BlockWriteInDemoMode(restriction DemoRestriction) func(http.Handler) http.Handler
BlockWriteInDemoMode creates middleware that blocks POST/PUT/DELETE in demo mode. Use for routes where all modifications should be blocked.
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 DemoModeMessageDetailed ¶ added in v0.7.0
func DemoModeMessageDetailed(restriction DemoRestriction) string
DemoModeMessageDetailed returns a detailed message for a specific restriction.
func GetAPIKey ¶
GetAPIKey retrieves the API key from the request context. Returns nil if no API key is in context.
func GetAdminLang ¶
GetAdminLang retrieves the admin UI language preference from the session. Falls back to Accept-Language header, then database default language.
func GetClientIP ¶
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 GetDemoBlockedMessage ¶ added in v0.7.0
func GetDemoBlockedMessage(w http.ResponseWriter, r *http.Request) string
GetDemoBlockedMessage reads and clears the demo_blocked cookie, returning the restriction message if present.
func GetRequestPath ¶
GetRequestPath retrieves the request path from the context.
func GetRequestURL ¶ added in v0.2.0
GetRequestURL extracts the request URL path from the request. Returns the URL path without query string for cleaner logging.
func GetSiteName ¶
GetSiteName retrieves the site name from the request context. Returns "oCMS" as default if not found.
func GetUser ¶
GetUser retrieves the current user from the request context. Returns nil if no user is in context.
func GetUserEmail ¶
GetUserEmail returns the current user's email from context, or empty string if not found.
func GetUserID ¶
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 ¶
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 IsDemoMode ¶ added in v0.7.0
func IsDemoMode() bool
IsDemoMode returns true if the application is running in demo mode. Demo mode is enabled when OCMS_DEMO_MODE=true environment variable is set.
func Language ¶
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 ¶
LoadSiteConfig creates middleware that loads site configuration (like site_name) into context. If cacheManager is provided, it will be used for faster config lookups. If both cacheManager and db are nil, the default "oCMS" will be used.
func LoadUser ¶
LoadUser creates middleware that loads the current user into the request context. This should be used after Auth middleware.
func OptionalAPIKeyAuth ¶
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 OptionalLoadUser ¶ added in v0.3.0
OptionalLoadUser creates middleware that optionally loads the current user into context. Unlike LoadUser, this does NOT redirect to login if the user is not found. Use this for frontend routes where authentication is optional but user context is useful.
func ParseAPIKeyPermissions ¶
ParseAPIKeyPermissions parses the JSON permissions string from an API key. Returns an empty slice if the permissions string is empty or invalid.
func RequestPath ¶
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 ¶
RequireAdmin creates middleware that requires admin role. Shorthand for RequireRole(RoleAdmin).
func RequireAdminWithEventLog ¶ added in v0.4.0
RequireAdminWithEventLog creates middleware that requires admin role with event logging.
func RequireAnyPermission ¶
RequireAnyPermission creates middleware that requires any one of the specified permissions. This should be used after APIKeyAuth middleware.
func RequireEditor ¶
RequireEditor creates middleware that requires at least editor role. Allows both admin and editor users.
func RequireEditorWithEventLog ¶ added in v0.4.0
RequireEditorWithEventLog creates middleware that requires at least editor role with event logging.
func RequirePermission ¶
RequirePermission creates middleware that requires a specific API permission. This should be used after APIKeyAuth middleware.
func RequireRole ¶
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 RequireRoleWithEventLog ¶ added in v0.4.0
func RequireRoleWithEventLog(minRole string, eventService *service.EventService) func(http.Handler) http.Handler
RequireRoleWithEventLog creates middleware that requires a minimum user role and logs to event log. Roles are hierarchical: admin > editor. Public users have no admin access. If eventService is provided, 403 errors will be logged to the event log (visible in admin panel).
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 ¶
SkipCSRF returns a middleware that skips CSRF protection for specific paths. This is useful for API endpoints that use token-based authentication.
func StaticCache ¶
StaticCache adds Cache-Control headers for static files.
func StripTrailingSlash ¶ added in v0.5.0
StripTrailingSlash redirects URLs with trailing slashes to their non-trailing equivalents (HTTP 301). Excludes root path "/".
func Timeout ¶
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 ¶
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 DemoRestriction ¶ added in v0.7.0
type DemoRestriction string
DemoRestriction defines a type of restriction in demo mode.
const ( // Content restrictions (block all modifications) RestrictionContentReadOnly DemoRestriction = "content_read_only" RestrictionUnpublishContent DemoRestriction = "unpublish_content" RestrictionDeletePage DemoRestriction = "delete_page" RestrictionDeleteMedia DemoRestriction = "delete_media" RestrictionDeleteCategory DemoRestriction = "delete_category" RestrictionDeleteTag DemoRestriction = "delete_tag" RestrictionDeleteMenu DemoRestriction = "delete_menu" RestrictionDeleteMenuItem DemoRestriction = "delete_menu_item" RestrictionDeleteForm DemoRestriction = "delete_form" RestrictionDeleteWidget DemoRestriction = "delete_widget" // User management restrictions RestrictionCreateUser DemoRestriction = "create_user" RestrictionDeleteUser DemoRestriction = "delete_user" RestrictionEditUser DemoRestriction = "edit_user" RestrictionChangeRole DemoRestriction = "change_role" // System configuration restrictions RestrictionEditConfig DemoRestriction = "edit_config" RestrictionEditLanguages DemoRestriction = "edit_languages" // Security-sensitive restrictions RestrictionAPIKeys DemoRestriction = "api_keys" RestrictionWebhooks DemoRestriction = "webhooks" RestrictionExportData DemoRestriction = "export_data" RestrictionImportData DemoRestriction = "import_data" RestrictionModules DemoRestriction = "modules" RestrictionModuleSettings DemoRestriction = "module_settings" RestrictionThemeSettings DemoRestriction = "theme_settings" RestrictionClearCache DemoRestriction = "clear_cache" // Module-specific restrictions RestrictionSQLExecution DemoRestriction = "sql_execution" )
Demo mode restrictions - operations that are blocked in demo mode.
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 RedirectsMiddleware ¶ added in v0.5.0
type RedirectsMiddleware struct {
// contains filtered or unexported fields
}
RedirectsMiddleware handles URL redirects based on database rules.
func NewRedirectsMiddleware ¶ added in v0.5.0
func NewRedirectsMiddleware(db *sql.DB) *RedirectsMiddleware
NewRedirectsMiddleware creates a new redirects middleware.
func (*RedirectsMiddleware) Handler ¶ added in v0.5.0
func (rm *RedirectsMiddleware) Handler(next http.Handler) http.Handler
Handler returns the middleware handler function.
func (*RedirectsMiddleware) InvalidateCache ¶ added in v0.5.0
func (rm *RedirectsMiddleware) InvalidateCache()
InvalidateCache forces a reload of redirects on next request.
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.