middleware

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Feb 8, 2026 License: GPL-3.0 Imports: 21 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 DemoModeMessage = "This action is disabled in demo mode"

DemoModeMessage is the user-friendly message shown when an action is blocked.

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 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

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 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

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 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

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. If both cacheManager and db are nil, the default "oCMS" will be used.

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 OptionalLoadUser added in v0.3.0

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

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

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 RequireAdminWithEventLog added in v0.4.0

func RequireAdminWithEventLog(eventService *service.EventService) func(http.Handler) http.Handler

RequireAdminWithEventLog creates middleware that requires admin role with event logging.

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 RequireEditorWithEventLog added in v0.4.0

func RequireEditorWithEventLog(eventService *service.EventService) func(http.Handler) http.Handler

RequireEditorWithEventLog creates middleware that requires at least editor role with event logging.

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 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

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 StripTrailingSlash added in v0.5.0

func StripTrailingSlash(next http.Handler) http.Handler

StripTrailingSlash redirects URLs with trailing slashes to their non-trailing equivalents (HTTP 301). Excludes root path "/".

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 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.

Jump to

Keyboard shortcuts

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