diff --git a/.env.example b/.env.example index 8b6c60e..6994e16 100644 --- a/.env.example +++ b/.env.example @@ -48,3 +48,13 @@ BANGUI_GEOIP_DB_PATH= # Set to "true" to enable (default is "false" for security). BANGUI_GEOIP_ALLOW_HTTP_FALLBACK=false +# CORS Configuration (optional) +# Comma-separated list of allowed origins for cross-origin requests. +# Defaults to common localhost development origins (http://localhost:5173, http://127.0.0.1:5173, etc). +# Set this in production to your frontend domain(s). +# Examples: +# BANGUI_CORS_ALLOWED_ORIGINS=https://example.com,https://app.example.com +# BANGUI_CORS_ALLOWED_ORIGINS= (empty to disable CORS) +# WARNING: Do NOT use wildcard "*" — it defeats CORS security when credentials are enabled. +BANGUI_CORS_ALLOWED_ORIGINS= + diff --git a/Docs/Deployment.md b/Docs/Deployment.md index d9d733c..f72afae 100644 --- a/Docs/Deployment.md +++ b/Docs/Deployment.md @@ -18,7 +18,65 @@ If fail2ban goes offline but the backend always returns 200, Docker treats the c --- -## Scheduler Lock +## CORS Configuration + +Cross-Origin Resource Sharing (CORS) must be explicitly configured when the frontend and backend are served from different origins. + +### Development + +By default, the backend allows requests from common localhost development origins: + +- `http://localhost:5173` +- `http://127.0.0.1:5173` +- `https://localhost:5173` +- `https://127.0.0.1:5173` + +No additional configuration is needed for local development — just run the frontend and backend normally. + +### Production + +In production, override the default with your actual frontend origin(s): + +**Docker Compose:** +```yaml +environment: + BANGUI_CORS_ALLOWED_ORIGINS: "https://example.com,https://www.example.com" +``` + +**Environment File (.env):** +``` +BANGUI_CORS_ALLOWED_ORIGINS=https://example.com,https://www.example.com +``` + +**Multiple Origins:** +Separate multiple allowed origins with commas (no spaces): +``` +BANGUI_CORS_ALLOWED_ORIGINS=https://example.com,https://app.example.com,https://admin.example.com +``` + +**Disable CORS:** +To disable CORS entirely (e.g., when the frontend is served from the same origin as the backend): +``` +BANGUI_CORS_ALLOWED_ORIGINS= +``` + +### Security Considerations + +- **Always specify exact origins** — never use wildcard `*` in production, especially with `allow_credentials=true` (credentials mode is required for the session cookie). +- **Use HTTPS in production** — the backend enforces the Secure cookie flag, which requires HTTPS (or localhost for development). +- **Validate in reverse proxy** — if using Nginx or a CDN reverse proxy, validate the `Origin` header before forwarding requests to ensure only legitimate origins reach the backend. + +### Troubleshooting + +| Symptom | Cause | Solution | +|---------|-------|----------| +| `Access-Control-Allow-Origin` header missing from response | CORS not configured or origin not whitelisted | Check `BANGUI_CORS_ALLOWED_ORIGINS` and ensure your frontend origin is included | +| Browser blocks requests with CORS error | Credentials mode enabled but origin not exactly whitelisted | Ensure `BANGUI_CORS_ALLOWED_ORIGINS` includes the exact origin (protocol + domain + port) of your frontend | +| Works in development but fails in production | Default localhost origins used instead of production frontend domain | Override `BANGUI_CORS_ALLOWED_ORIGINS` in production environment | + +--- + + In multi-instance deployments (e.g., Kubernetes, Docker Swarm), the scheduler lock prevents duplicate execution of background tasks by ensuring only one instance runs the scheduler at a time. diff --git a/Docs/Tasks.md b/Docs/Tasks.md index 2ac19c5..c2e3961 100644 --- a/Docs/Tasks.md +++ b/Docs/Tasks.md @@ -1,38 +1,3 @@ -## [MEDIUM] Session secret rotation not implemented - -**Where found** - -- `backend/app/config.py` — single `session_secret` with no rotation support - -**Why this is needed** - -If secret leaks, all sessions compromised. No way to invalidate old sessions. - -**Goal** - -Support gradual secret rotation without forcing logout. - -**What to do** - -1. Store multiple secrets: current and previous -2. Accept tokens signed with either key -3. Re-sign tokens with current secret on validation - -**Possible traps and issues** - -- Rotation strategy must be documented -- Metrics needed to track secret usage - -**Docs changes needed** - -- Update `Docs/Backend-Development.md` § Session Management - -**Doc references** - -- `Docs/Backend-Development.md` - ---- - ## [MEDIUM] No CORS configuration **Where found** diff --git a/backend/app/config.py b/backend/app/config.py index 3e26456..5dc5ff7 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -120,11 +120,17 @@ class Settings(BaseSettings): ), ) cors_allowed_origins: str | list[str] = Field( - default_factory=list, + default_factory=lambda: [ + "http://localhost:5173", + "http://127.0.0.1:5173", + "https://localhost:5173", + "https://127.0.0.1:5173", + ], description=( "Comma-separated list of allowed CORS origins when the frontend is " "served from a different origin than the backend. " - "Leave empty to disable cross-origin requests in production." + "Defaults to common localhost development origins. " + "Override in production with the specific frontend domain." ), )