fix: address multiple code audit findings

- CORS: replace wildcard with explicit origin list from CORS_ORIGINS env
- Auth: enforce strong defaults, JWT blacklist (RevokedToken model), login rate limiting
- Auth: validate password length before bcrypt (72-byte limit)
- Scheduler: single-threaded worker to mitigate SQLite write contention
- Scheduler: graceful shutdown (wait=True)
- Snapshots: add prune_snapshots() with configurable retention count
- Storage: isolate localStorage keys via VITE_APP_KEY prefix
- Config: add cors_origins, login_rate_limit, snapshot_retention_count settings
This commit is contained in:
SmartUp Developer
2026-05-17 10:52:18 +08:00
parent a42ecf7bcc
commit ad16618406
25 changed files with 792 additions and 165 deletions
+5 -3
View File
@@ -5,6 +5,7 @@ import json
import logging
from datetime import datetime, timezone
from apscheduler.executors.pool import ThreadPoolExecutor
from apscheduler.schedulers.background import BackgroundScheduler
from sqlalchemy.orm import Session
@@ -12,14 +13,14 @@ from app.database import SessionLocal
from app.models.upstream import Upstream
from app.models.snapshot import UpstreamRateSnapshot
from app.services.upstream_client import UpstreamClient, UpstreamError, build_snapshot
from app.services.snapshot_service import diff_snapshots
from app.services.snapshot_service import diff_snapshots, prune_snapshots
from app.services import webhook_service
from app.services import website_sync
from app.config import get_settings
logger = logging.getLogger(__name__)
_scheduler = BackgroundScheduler(timezone="UTC")
_scheduler = BackgroundScheduler(timezone="UTC", executors={"default": ThreadPoolExecutor(max_workers=1)})
def get_scheduler() -> BackgroundScheduler:
@@ -95,6 +96,7 @@ def _check_upstream(upstream_id: int) -> None:
upstream.last_checked_at = datetime.now(timezone.utc)
upstream.last_error = None
upstream.consecutive_failures = 0
prune_snapshots(db, upstream_id, settings.snapshot_retention_count)
db.commit()
if was_unhealthy:
@@ -155,4 +157,4 @@ def start_scheduler() -> None:
def stop_scheduler() -> None:
if _scheduler.running:
_scheduler.shutdown(wait=False)
_scheduler.shutdown(wait=True)