middleware

package
v0.10.0 Latest Latest
Warning

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

Go to latest
Published: Oct 4, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Overview

Package middleware provides HTTP middleware for authentication and authorization.

Package middleware provides HTTP middleware for GoatFlow.

Package middleware provides HTTP middleware for authentication and authorization.

Index

Constants

View Source
const (
	// LanguageContextKey is the key for storing language in context.
	LanguageContextKey = "language"
	// DefaultLanguage is the default language.
	DefaultLanguage = "en"
)

Variables

This section is empty.

Functions

func APITokenAuthMiddleware

func APITokenAuthMiddleware() gin.HandlerFunc

APITokenAuthMiddleware authenticates requests using GoatKit API tokens (gf_*). Sets user context similar to JWT auth for compatibility with existing handlers.

func AuthenticateAPIToken

func AuthenticateAPIToken(c *gin.Context, token string)

AuthenticateAPIToken handles gf_* token authentication. Exported so that other auth middlewares (e.g. SessionOrJWTAuth) can delegate to it when they detect an API token.

func ClearLanguageCookie

func ClearLanguageCookie(c *gin.Context)

ClearLanguageCookie clears the language preference cookie.

func CustomerCaptiveRedirect

func CustomerCaptiveRedirect(jwtManager *auth.JWTManager) gin.HandlerFunc

CustomerCaptiveRedirect redirects customers whose org is captive to a plugin. Must run before CustomerPortalGate: that gate invokes OptionalAuth inline which writes the response body via c.Next(), after which a later redirect is silently dropped.

Capture only fires when the customer also has plugin access via gk_org_plugin_access — captive_plugin alone would lock a user out of the portal entirely.

func CustomerPortalGate

func CustomerPortalGate(jwtManager *auth.JWTManager) gin.HandlerFunc

CustomerPortalGate loads portal config, enforces enable/disable, and applies optional login rules. A signed-in customer gets their company's settings (per-company overrides on top of the global values); anonymous visitors get the global settings.

func DatabaseHealthCheck

func DatabaseHealthCheck() gin.HandlerFunc

and returns a friendly error page if the database is down.

func DemoGuard

func DemoGuard() gin.HandlerFunc

DemoGuard blocks non-admin users from modifying account security settings (password, MFA) when demo mode is active. Returns 403 with a friendly message.

func DemoMode

func DemoMode() gin.HandlerFunc

DemoMode sets is_demo=true on every request when app.demo_mode is enabled. This allows templates and handlers to check for demo mode globally.

func ExtractToken

func ExtractToken(c *gin.Context) string

ExtractToken extracts an auth token from the request. It checks the Authorization header first (Bearer JWT or raw API token), then falls back to cookies. On /customer paths customer-specific cookies are checked before agent cookies to avoid session conflicts in the same browser. The query parameter "token" is only accepted for browser transports that cannot reliably set headers: WebSocket upgrades and known same-origin SSE endpoints.

func GetCurrentUser

func GetCurrentUser(c *gin.Context) (uint, string, string, bool)

GetCurrentUser retrieves the current user from context.

func GetLanguage

func GetLanguage(c *gin.Context) string

GetLanguage gets the current language from context. Falls back to cookie detection if not set in context.

func IsAPIToken

func IsAPIToken(token string) bool

IsAPIToken checks if a token string is a GoatKit API token (gf_ prefix)

func IsCustomerPrincipal added in v0.10.0

func IsCustomerPrincipal(c *gin.Context) bool

IsCustomerPrincipal reports whether the authenticated caller is a customer: a customer JWT (role "Customer") or a customer API token. Customer ids live in customer_user, whose id space overlaps users.id, so a customer must never be treated as an agent with the same numeric id.

func MaintenanceNotification

func MaintenanceNotification(db *sql.DB) gin.HandlerFunc

MaintenanceNotification middleware checks for active/upcoming maintenance and adds notification data to the context for templates.

func OptionalAuth

func OptionalAuth(jwtManager *auth.JWTManager) gin.HandlerFunc

OptionalAuth is middleware that validates tokens if present but doesn't require them.

func RequestID

func RequestID() gin.HandlerFunc

RequestID adds a unique request ID to each request.

func RequireAdminAccess

func RequireAdminAccess(rbac *auth.RBAC) gin.HandlerFunc

RequireAdminAccess is a convenience function for admin-only routes.

func RequireAdminGroup

func RequireAdminGroup() gin.HandlerFunc

RequireAdminGroup checks if the user is in the admin group.

func RequireAgent added in v0.10.0

func RequireAgent() gin.HandlerFunc

RequireAgent admits authenticated agents (agent JWTs and agent API tokens) and refuses customers and anonymous callers.

func RequireAgentAccess

func RequireAgentAccess(rbac *auth.RBAC) gin.HandlerFunc

RequireAgentAccess allows both admins and agents.

func RequireAnyPermission

func RequireAnyPermission(rbac *auth.RBAC, permissions ...auth.Permission) gin.HandlerFunc

RequireAnyPermission checks if the user has any of the required permissions.

func RequireAnyQueueAccess

func RequireAnyQueueAccess(permType string) gin.HandlerFunc

RequireAnyQueueAccess checks if the user has the specified permission for at least one queue. This is useful for routes where access to any queue is sufficient (like ticket list pages).

func RequireCustomer added in v0.10.0

func RequireCustomer() gin.HandlerFunc

RequireCustomer admits authenticated customers (customer JWTs and customer API tokens) and refuses agents and anonymous callers.

func RequireCustomerOrAnyQueueAccess added in v0.10.0

func RequireCustomerOrAnyQueueAccess(permType string) gin.HandlerFunc

RequireCustomerOrAnyQueueAccess is RequireAnyQueueAccess for routes that customers may also call: customers pass through and the handler must limit them to their own tickets; agents need permType on at least one queue.

func RequirePermission

func RequirePermission(rbac *auth.RBAC, permission auth.Permission) gin.HandlerFunc

RequirePermission checks if the user has the required permission.

func RequireQueueAccess

func RequireQueueAccess(permType string) gin.HandlerFunc

RequireQueueAccess checks if the user has the specified permission for the queue. The queue ID is extracted from the URL parameter "queue_id" or query parameter "queue_id". Permission types: ro, rw, create, move_into, note, owner, priority

func RequireQueueAccessFromTicket

func RequireQueueAccessFromTicket(permType string) gin.HandlerFunc

RequireQueueAccessFromTicket checks if the user has the specified permission for the queue that the ticket belongs to. The ticket ID is extracted from the URL parameter "ticket_id" or "id".

func RequireRole

func RequireRole(roles ...string) gin.HandlerFunc

RequireRole checks if the user has the required role.

func RequireScope

func RequireScope(scope string) gin.HandlerFunc

RequireScope middleware checks that the API token has the required scope. It also enforces AgentOnly and RequireRole restrictions from the scope definition.

func RequireTicketAccess

func RequireTicketAccess(rbac *auth.RBAC) gin.HandlerFunc

RequireTicketAccess checks if the user can access a specific ticket.

func RequireTicketReadOrCustomerOwner added in v0.10.0

func RequireTicketReadOrCustomerOwner() gin.HandlerFunc

RequireTicketReadOrCustomerOwner admits agents with "ro" on the queue of the ticket in the path (as RequireQueueAccessFromTicket("ro")) and customers whose login is the ticket's customer_user_id. Other customers get 404, so the existence of foreign tickets is not revealed. The handler must still hide agent-only content (internal articles) from customers.

func ResolveTenantFromHost

func ResolveTenantFromHost(host string) uint

ResolveTenantFromHost maps the request host to a tenant ID using GOATFLOW_CUSTOMER_HOSTMAP. Format: "host1=1,host2=2". Unknown hosts return 0.

func SecurityHeaders

func SecurityHeaders() gin.HandlerFunc

SecurityHeaders adds HTTP security headers to all responses.

CSP Note: GoatFlow uses Alpine.js (requires unsafe-eval for x-data/x-bind expression evaluation) and HTMX (injects inline scripts from AJAX responses). These frameworks are fundamentally incompatible with strict script-src CSP. XSS protection is provided by server-side HTML sanitisation (bluemonday), not by CSP script restrictions. CSP still protects against clickjacking, content sniffing, form hijacking, and framing attacks.

func SetAPITokenVerifier

func SetAPITokenVerifier(v APITokenVerifier)

SetAPITokenVerifier sets the global token verifier

func SetCaptivePluginLandingResolver

func SetCaptivePluginLandingResolver(r CaptivePluginLandingResolver)

SetCaptivePluginLandingResolver installs the landing-path lookup used by the captive redirect inside CustomerPortalGate.

func SetLanguageCookie

func SetLanguageCookie(c *gin.Context, lang string)

SetLanguageCookie sets the language preference cookie.

func SetMaintenanceCheckerFactory

func SetMaintenanceCheckerFactory(f func(*sql.DB) MaintenanceChecker)

SetMaintenanceCheckerFactory injects a maintenance checker factory from product code.

func SetQueueAccessCheckerFactory

func SetQueueAccessCheckerFactory(f func(*sql.DB) QueueAccessChecker)

SetQueueAccessCheckerFactory injects a queue access checker factory from product code.

func SetSessionServiceFactory

func SetSessionServiceFactory(f func(*sql.DB) SessionChecker)

func SetTicketQueueResolverFactory

func SetTicketQueueResolverFactory(f func() TicketQueueResolver)

SetTicketQueueResolverFactory injects a ticket queue resolver factory from product code.

func T

func T(c *gin.Context, key string, args ...interface{}) string

T translates a key in the current language.

func TranslateError

func TranslateError(c *gin.Context, key string, args ...interface{}) string

TranslateError translates an error message.

func TranslateSuccess

func TranslateSuccess(c *gin.Context, key string, args ...interface{}) string

TranslateSuccess translates a success message.

func TranslateValidation

func TranslateValidation(c *gin.Context, key string, args ...interface{}) string

TranslateValidation translates a validation message.

func UnifiedAuthMiddleware

func UnifiedAuthMiddleware(jwtManager interface {
	ValidateToken(string) (*auth.Claims, error)
}) gin.HandlerFunc

UnifiedAuthMiddleware handles both JWT tokens and API tokens (gf_*).

func VerifySession added in v0.10.0

func VerifySession(c *gin.Context, claims *auth.Claims) bool

VerifySession reports whether the session an access token names still exists, touching its last-request time when it does. Every auth middleware that accepts a JWT must call it: a killed session revokes the token regardless of which cookies or headers the client sends. Without a session checker nothing can vouch for the token, so the answer is no.

Types

type APITokenVerifier

type APITokenVerifier interface {
	VerifyToken(ctx context.Context, rawToken string) (*platformmodels.APIToken, error)
	UpdateLastUsed(ctx context.Context, tokenID int64, ip string) error
}

APITokenVerifier is the interface for verifying API tokens. This breaks the import cycle between api and middleware packages.

type AuthMiddleware

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

func NewAuthMiddleware

func NewAuthMiddleware(jwtManager *auth.JWTManager) *AuthMiddleware

func (*AuthMiddleware) CanAccessTicket

func (m *AuthMiddleware) CanAccessTicket(c *gin.Context, ticketOwnerID uint) bool

func (*AuthMiddleware) GetUserID

func (m *AuthMiddleware) GetUserID(c *gin.Context) (uint, bool)

func (*AuthMiddleware) GetUserRole

func (m *AuthMiddleware) GetUserRole(c *gin.Context) (string, bool)

func (*AuthMiddleware) IsAuthenticated

func (m *AuthMiddleware) IsAuthenticated(c *gin.Context) bool

func (*AuthMiddleware) OptionalAuth

func (m *AuthMiddleware) OptionalAuth() gin.HandlerFunc

func (*AuthMiddleware) RequireAuth

func (m *AuthMiddleware) RequireAuth() gin.HandlerFunc

func (*AuthMiddleware) RequirePermission

func (m *AuthMiddleware) RequirePermission(permission auth.Permission) gin.HandlerFunc

func (*AuthMiddleware) RequireRole

func (m *AuthMiddleware) RequireRole(roles ...string) gin.HandlerFunc

type CaptivePluginLandingResolver

type CaptivePluginLandingResolver func(pluginName string) string

CaptivePluginLandingResolver maps a plugin name to its declared landing path. Supplied by the api package at startup to avoid an import cycle (middleware → api → middleware). When nil, captive redirects degrade to no-op — the customer sees the normal portal rather than getting stuck at a blank page.

type I18nMiddleware

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

I18nMiddleware handles language detection and sets it in context.

func NewI18nMiddleware

func NewI18nMiddleware() *I18nMiddleware

NewI18nMiddleware creates a new i18n middleware.

func (*I18nMiddleware) Handle

func (m *I18nMiddleware) Handle() gin.HandlerFunc

Handle returns the middleware handler function.

type MaintenanceChecker

type MaintenanceChecker interface {
	IsActive() (*platformmodels.SystemMaintenance, error)
	IsComing(withinMinutes int) (*platformmodels.SystemMaintenance, error)
}

MaintenanceChecker checks for active system maintenance.

func NewMaintenanceChecker

func NewMaintenanceChecker(db *sql.DB) MaintenanceChecker

NewMaintenanceChecker creates a MaintenanceChecker from the injected factory. Returns nil if no factory is set.

type QueueAccessChecker

type QueueAccessChecker interface {
	IsAdmin(ctx context.Context, userID uint) (bool, error)
	HasQueueAccess(ctx context.Context, userID uint, queueID uint, permType string) (bool, error)
	GetAccessibleQueueIDs(ctx context.Context, userID uint, permType string) ([]uint, error)
}

QueueAccessChecker checks queue permissions (subset of service.QueueAccessService).

func NewQueueAccessChecker added in v0.10.0

func NewQueueAccessChecker(db *sql.DB) QueueAccessChecker

NewQueueAccessChecker creates a QueueAccessChecker from the injected factory. Returns nil if no factory is set.

type RateLimiter

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

RateLimiter implements a token bucket rate limiter

func GlobalRateLimiter

func GlobalRateLimiter() *RateLimiter

GlobalRateLimiter returns the shared rate limiter instance.

func NewRateLimiter

func NewRateLimiter() *RateLimiter

NewRateLimiter creates a new rate limiter

func (*RateLimiter) Allow

func (rl *RateLimiter) Allow(key string, limit int) bool

Allow checks if a request is allowed and consumes a token from a bucket of limit requests per hour.

func (*RateLimiter) AllowPer added in v0.10.0

func (rl *RateLimiter) AllowPer(key string, limit int, window time.Duration) bool

AllowPer checks if a request is allowed and consumes a token from a bucket of limit requests per window. A bucket whose limit or window changed (e.g. a reconfigured plugin UI) adopts the new values.

func (*RateLimiter) Remaining

func (rl *RateLimiter) Remaining(key string) int

Remaining returns remaining tokens for a key

type ResolvedTicket added in v0.10.0

type ResolvedTicket struct {
	ID      uint64
	QueueID uint
}

ResolvedTicket is a ticket a path identifier names, with its queue.

type SessionChecker

type SessionChecker interface {
	GetSession(sessionID string) (*platformmodels.Session, error)
	TouchSession(sessionID string) error
}

SessionChecker checks session validity (subset of service.SessionService).

type TicketQueueResolver

type TicketQueueResolver interface {
	ResolveTickets(db *sql.DB, ticketIDStr string) ([]ResolvedTicket, error)
}

TicketQueueResolver resolves a ticket identifier (tn or id) to the tickets it can name. Product code injects a concrete implementation via SetTicketQueueResolverFactory. It returns sql.ErrNoRows when none exists.

Jump to

Keyboard shortcuts

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