feat: add CORS configuration options to enhance API security

This commit is contained in:
2025-12-19 02:33:00 +09:00
parent ea5a0004da
commit 1806e0823f
3 changed files with 75 additions and 8 deletions
+15 -1
View File
@@ -14,4 +14,18 @@ PLEXPLAYLISTSYNC_AUTH_PASSWORD=CHANGE_PASSWORD
PLEXPLAYLISTSYNC_AUTH_TOKEN_SECRET=REPLACE_WITH_A_RANDOM_STRING PLEXPLAYLISTSYNC_AUTH_TOKEN_SECRET=REPLACE_WITH_A_RANDOM_STRING
# Token TTL seconds (optional) # Token TTL seconds (optional)
PLEXPLAYLISTSYNC_AUTH_TOKEN_TTL_SECONDS=86400 PLEXPLAYLISTSYNC_AUTH_TOKEN_TTL_SECONDS=86400
# CORS allowlist (optional)
# Default is empty (CORS disabled; same-origin only).
# Accepts comma-separated list or a JSON array.
# Example:
# PLEXPLAYLISTSYNC_CORS_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
# or
# PLEXPLAYLISTSYNC_CORS_ALLOWED_ORIGINS=["https://your.domain"]
PLEXPLAYLISTSYNC_CORS_ALLOWED_ORIGINS=
# Allow cookies/credentials for allowlisted origins (optional)
# 1 = enabled, 0 = disabled
# Note: if origins contains '*', credentials will be forced off.
PLEXPLAYLISTSYNC_CORS_ALLOW_CREDENTIALS=0
+47 -2
View File
@@ -1,4 +1,5 @@
import os import os
import json
from datetime import datetime from datetime import datetime
from typing import Sequence from typing import Sequence
@@ -21,6 +22,50 @@ from app.utils.auth import load_auth_config, issue_token, verify_token
app = FastAPI() app = FastAPI()
def _parse_cors_allowed_origins(raw: str | None) -> list[str]:
if not raw:
return []
value = raw.strip()
if not value:
return []
if value == "*":
return ["*"]
try:
if value.startswith("["):
parsed = json.loads(value)
if isinstance(parsed, list):
origins = [str(item).strip() for item in parsed]
else:
origins = [str(parsed).strip()]
else:
origins = [part.strip() for part in value.split(",")]
except Exception:
logger.warning(
"Invalid PLEXPLAYLISTSYNC_CORS_ALLOWED_ORIGINS; CORS will be disabled."
)
return []
return [origin for origin in origins if origin]
def _env_truthy(name: str, default: str = "0") -> bool:
value = os.getenv(name, default)
return str(value).strip().lower() in {"1", "true", "yes", "y", "on"}
_CORS_ALLOWED_ORIGINS = _parse_cors_allowed_origins(
os.getenv("PLEXPLAYLISTSYNC_CORS_ALLOWED_ORIGINS", "")
)
_CORS_ALLOW_CREDENTIALS = (
False
if "*" in _CORS_ALLOWED_ORIGINS
else _env_truthy("PLEXPLAYLISTSYNC_CORS_ALLOW_CREDENTIALS", "0")
)
# --- Optional API Authentication (username/password) --- # --- Optional API Authentication (username/password) ---
AUTH_CONFIG = load_auth_config() AUTH_CONFIG = load_auth_config()
@@ -107,8 +152,8 @@ async def startup_event():
app.add_middleware( app.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=["*"], allow_origins=_CORS_ALLOWED_ORIGINS,
allow_credentials=True, allow_credentials=_CORS_ALLOW_CREDENTIALS,
allow_methods=["*"], allow_methods=["*"],
allow_headers=["*"], allow_headers=["*"],
) )
+13 -5
View File
@@ -3,12 +3,12 @@ services:
build: . build: .
command: uvicorn app.main:app --host 0.0.0.0 --port 8080 --reload command: uvicorn app.main:app --host 0.0.0.0 --port 8080 --reload
ports: ports:
- "8888:8080" - "8000:8080"
volumes: volumes:
- PATH_TO_YOUR_PLAYLISTS:/app/playlists - ./playlists:/app/playlists
- PATH_TO_DATA/backup:/app/data/backup - ./data/backup:/app/data/backup
- PATH_TO_DATA/config:/app/data/config - ./data/config:/app/data/config
- PATH_TO_DATA/sync_artifacts:/app/data/sync_artifacts - ./data/sync_artifacts:/app/data/sync_artifacts
environment: environment:
- PYTHONUNBUFFERED=1 - PYTHONUNBUFFERED=1
- PYTHONDONTWRITEBYTECODE=1 - PYTHONDONTWRITEBYTECODE=1
@@ -16,6 +16,14 @@ services:
- PLEXPLAYLISTSYNC_BACKUP_DIR=/app/data/backup - PLEXPLAYLISTSYNC_BACKUP_DIR=/app/data/backup
- TZ=${TZ:-UTC} - TZ=${TZ:-UTC}
- LOG_LEVEL=${LOG_LEVEL:-INFO} - LOG_LEVEL=${LOG_LEVEL:-INFO}
# CORS (default: disabled / same-origin only)
# Comma-separated list or JSON array. Example:
# - PLEXPLAYLISTSYNC_CORS_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
# - PLEXPLAYLISTSYNC_CORS_ALLOWED_ORIGINS=["https://your.domain"]
# Use '*' only if you understand the risk (credentials will be forced off).
- PLEXPLAYLISTSYNC_CORS_ALLOWED_ORIGINS=${PLEXPLAYLISTSYNC_CORS_ALLOWED_ORIGINS:-}
# Optional: allow cookies/credentials for allowed origins (ignored when origins contains '*')
- PLEXPLAYLISTSYNC_CORS_ALLOW_CREDENTIALS=${PLEXPLAYLISTSYNC_CORS_ALLOW_CREDENTIALS:-0}
# Optional API auth (protects /api/*). # Optional API auth (protects /api/*).
# Set PLEXPLAYLISTSYNC_AUTH_ENABLED=1 to enable. # Set PLEXPLAYLISTSYNC_AUTH_ENABLED=1 to enable.
- PLEXPLAYLISTSYNC_AUTH_ENABLED=${PLEXPLAYLISTSYNC_AUTH_ENABLED:-0} - PLEXPLAYLISTSYNC_AUTH_ENABLED=${PLEXPLAYLISTSYNC_AUTH_ENABLED:-0}