P0.5: Database Row-Level Security (RLS) - CRITICAL - Created Alembic migration for RLS policies on all client-scoped tables - Policies for: presentations, master_decks, brand_configs, slides, templates - Updated get_async_session to set PostgreSQL session variables - Multi-tenant isolation now enforced at database level (defense-in-depth) - Session variables: app.current_user_id, app.user_role P0.6: Safe Error Messages - Created safe_exception_handler to prevent info disclosure - Logs full errors internally with context (user_id, path, method) - Returns generic "internal error" message to clients - Preserves HTTPException details (intentional error messages) P0.7: Security Headers - Created SecurityHeadersMiddleware with comprehensive headers - Headers: X-Content-Type-Options, X-Frame-Options, X-XSS-Protection - CSP, Referrer-Policy, Permissions-Policy, HSTS - Updated nginx.conf with matching security headers P0.8: Database Connection Pool Optimization - Increased pool_size from 5 to 20 connections - Added max_overflow of 40 for burst traffic - Enabled pool_pre_ping for connection health checks - Pool recycle after 1 hour to prevent stale connections - Configurable via DB_POOL_SIZE, DB_MAX_OVERFLOW, DB_POOL_RECYCLE All critical pre-launch security tasks complete. System now has: ✅ CORS protection ✅ Rate limiting ✅ Request size limits ✅ Database-level tenant isolation (RLS) ✅ Safe error handling ✅ Security headers ✅ Optimized connection pooling Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
101 lines
4.2 KiB
Python
101 lines
4.2 KiB
Python
import os
|
|
|
|
from fastapi import APIRouter, FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.staticfiles import StaticFiles
|
|
from slowapi import _rate_limit_exceeded_handler
|
|
from slowapi.errors import RateLimitExceeded
|
|
from api.lifespan import app_lifespan
|
|
from api.middlewares import UserConfigEnvUpdateMiddleware
|
|
from api.middlewares.auth_middleware import AuthMiddleware
|
|
from api.middlewares.rate_limit_middleware import limiter
|
|
from utils.safe_error_handler import safe_exception_handler
|
|
from api.middlewares.request_size_middleware import RequestSizeLimitMiddleware
|
|
from api.middlewares.security_headers_middleware import SecurityHeadersMiddleware
|
|
from api.v1.ppt.router import API_V1_PPT_ROUTER
|
|
from api.v1.webhook.router import API_V1_WEBHOOK_ROUTER
|
|
from api.v1.mock.router import API_V1_MOCK_ROUTER
|
|
from api.v1.auth.router import AUTH_ROUTER
|
|
from api.v1.admin.users_router import USERS_ROUTER
|
|
from api.v1.admin.teams_router import TEAMS_ROUTER
|
|
from api.v1.admin.clients_router import CLIENTS_ROUTER
|
|
from api.v1.admin.audit_router import AUDIT_ROUTER
|
|
from api.v1.admin.brand_config_router import BRAND_CONFIG_ROUTER
|
|
from api.v1.admin.master_decks_router import MASTER_DECKS_ROUTER
|
|
from api.v1.admin.analytics_router import ANALYTICS_ROUTER
|
|
from api.v1.admin.storage_router import STORAGE_ROUTER
|
|
from api.v1.admin.settings_router import SETTINGS_ROUTER
|
|
from api.v1.ppt.endpoints.jobs import JOBS_ROUTER
|
|
from api.v1.ppt.endpoints.review import REVIEW_ROUTER
|
|
from api.v1.ppt.endpoints.export import EXPORT_ROUTER
|
|
from api.middlewares.audit_middleware import AuditMiddleware
|
|
|
|
|
|
app = FastAPI(lifespan=app_lifespan)
|
|
|
|
# Configure rate limiting
|
|
app.state.limiter = limiter
|
|
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
|
|
|
# Configure safe error handling (prevent info disclosure)
|
|
app.add_exception_handler(Exception, safe_exception_handler)
|
|
|
|
# Admin router aggregator
|
|
ADMIN_ROUTER = APIRouter(prefix="/api/v1/admin")
|
|
ADMIN_ROUTER.include_router(USERS_ROUTER)
|
|
ADMIN_ROUTER.include_router(TEAMS_ROUTER)
|
|
ADMIN_ROUTER.include_router(CLIENTS_ROUTER)
|
|
ADMIN_ROUTER.include_router(AUDIT_ROUTER)
|
|
ADMIN_ROUTER.include_router(BRAND_CONFIG_ROUTER)
|
|
ADMIN_ROUTER.include_router(MASTER_DECKS_ROUTER)
|
|
ADMIN_ROUTER.include_router(ANALYTICS_ROUTER)
|
|
ADMIN_ROUTER.include_router(STORAGE_ROUTER)
|
|
ADMIN_ROUTER.include_router(SETTINGS_ROUTER)
|
|
|
|
# Routers
|
|
app.include_router(AUTH_ROUTER)
|
|
app.include_router(ADMIN_ROUTER)
|
|
app.include_router(API_V1_PPT_ROUTER)
|
|
app.include_router(JOBS_ROUTER)
|
|
app.include_router(REVIEW_ROUTER)
|
|
app.include_router(EXPORT_ROUTER)
|
|
app.include_router(API_V1_WEBHOOK_ROUTER)
|
|
app.include_router(API_V1_MOCK_ROUTER)
|
|
|
|
# Serve static assets (placeholder images, etc.)
|
|
_static_dir = os.path.join(os.path.dirname(__file__), "..", "static")
|
|
if os.path.isdir(_static_dir):
|
|
app.mount("/static", StaticFiles(directory=_static_dir), name="static")
|
|
|
|
# Serve data directory (images, exports, uploads) for local dev
|
|
# In Docker, nginx serves these directly; this is a fallback for dev mode
|
|
_data_dir = os.environ.get("APP_DATA_DIRECTORY", os.path.join(os.path.dirname(__file__), "..", "data"))
|
|
os.makedirs(_data_dir, exist_ok=True)
|
|
app.mount("/app_data", StaticFiles(directory=_data_dir), name="app_data")
|
|
|
|
# Middlewares (executed in reverse order: last added = first executed)
|
|
# 1. CORS must run first (handles preflight OPTIONS)
|
|
origins = os.getenv("ALLOWED_ORIGINS", "http://localhost:3000").split(",")
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=origins,
|
|
allow_credentials=True,
|
|
allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
|
|
allow_headers=["Authorization", "Content-Type", "Accept"],
|
|
)
|
|
|
|
# 2. Security headers (add protective HTTP headers)
|
|
app.add_middleware(SecurityHeadersMiddleware)
|
|
|
|
# 3. Request size limit (reject large requests early)
|
|
max_request_size = int(os.getenv("MAX_REQUEST_SIZE", str(100 * 1024 * 1024))) # 100MB
|
|
app.add_middleware(RequestSizeLimitMiddleware, max_size=max_request_size)
|
|
|
|
# 4. Auth middleware (validates JWT, attaches user to request.state)
|
|
app.add_middleware(AuthMiddleware)
|
|
|
|
# 5. Audit middleware (fire-and-forget logging for mutations)
|
|
app.add_middleware(AuditMiddleware)
|
|
|
|
# 6. User config middleware
|
|
app.add_middleware(UserConfigEnvUpdateMiddleware)
|