- Embedded NATS server with JetStream (sync_interval=always per Jepsen 2025) - AUDIT and STATE JetStream streams for tournament event durability - NATS publisher with UUID validation to prevent subject injection - WebSocket hub with JWT auth (query param), tournament-scoped broadcasting - Origin validation and slow-consumer message dropping - chi HTTP router with middleware (logger, recoverer, request ID, CORS, body limits) - Server timeouts: ReadHeader 10s, Read 30s, Write 60s, Idle 120s, MaxHeader 1MB - MaxBytesReader middleware for request body limits (1MB default) - JWT auth middleware with HMAC-SHA256 validation - Role-based access control (admin > floor > viewer) - Health endpoint reporting all subsystem status (DB, NATS, WebSocket) - SvelteKit SPA served via go:embed with fallback routing - Signal-driven graceful shutdown in reverse startup order - 9 integration tests covering all verification criteria Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
40 lines
918 B
Go
40 lines
918 B
Go
package middleware
|
|
|
|
import (
|
|
"net/http"
|
|
)
|
|
|
|
// Role constants for operator access levels.
|
|
const (
|
|
RoleAdmin = "admin"
|
|
RoleFloor = "floor"
|
|
RoleViewer = "viewer"
|
|
)
|
|
|
|
// roleHierarchy defines the permission level for each role.
|
|
// Higher numbers have more permissions.
|
|
var roleHierarchy = map[string]int{
|
|
RoleViewer: 1,
|
|
RoleFloor: 2,
|
|
RoleAdmin: 3,
|
|
}
|
|
|
|
// RequireRole returns middleware that checks the operator has at least the
|
|
// given role level. Admin > Floor > Viewer.
|
|
func RequireRole(minRole string) func(http.Handler) http.Handler {
|
|
minLevel := roleHierarchy[minRole]
|
|
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
role := OperatorRole(r)
|
|
level := roleHierarchy[role]
|
|
|
|
if level < minLevel {
|
|
http.Error(w, `{"error":"insufficient permissions"}`, http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|