import os from app.api.router import api_router, health_router from app.config import settings from app.middleware.exceptions import ( APIException, api_exception_handler, general_exception_handler, http_exception_handler, validation_exception_handler, ) from app.middleware.logging import RequestLoggingMiddleware from fastapi import FastAPI from fastapi.exceptions import RequestValidationError from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.gzip import GZipMiddleware from starlette.exceptions import HTTPException as StarletteHTTPException from starlette.staticfiles import StaticFiles app = FastAPI( title="小虾 SaaS API", description="自动化剪辑 SaaS 平台 API", version=settings.APP_VERSION, docs_url="/docs", redoc_url="/redoc", ) app.add_exception_handler(APIException, api_exception_handler) app.add_exception_handler(StarletteHTTPException, http_exception_handler) app.add_exception_handler(RequestValidationError, validation_exception_handler) app.add_exception_handler(Exception, general_exception_handler) # P1-1: Fix CORS configuration security issue # - allow_credentials=True is incompatible with allow_origins=["*"] # - In production, only allow configured domains, not "*" if settings.DEBUG: allow_origins = settings.CORS_ORIGINS # Allow localhost in debug mode else: # In production, filter out any wildcard "*" origins allow_origins = [origin for origin in settings.CORS_ORIGINS if origin != "*"] if not allow_origins: # Default to production domain if no valid origins configured allow_origins = ["https://xiaoxiajianji.com"] app.add_middleware( CORSMiddleware, allow_origins=allow_origins, allow_credentials=True, allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], allow_headers=["Authorization", "Content-Type"], ) app.add_middleware(GZipMiddleware, minimum_size=1000) app.add_middleware(RequestLoggingMiddleware) app.include_router(health_router) app.include_router(api_router) _generated_files_dir = os.getenv("GENERATED_FILES_DIR", "/app/generated") os.makedirs(_generated_files_dir, exist_ok=True) app.mount( os.getenv("GENERATED_FILES_URL_PREFIX", "/generated-files"), StaticFiles(directory=_generated_files_dir), name="generated-files", ) def create_app() -> FastAPI: return app @app.get("/") async def root(): return { "service": settings.APP_NAME, "status": "running", "version": settings.APP_VERSION, } if __name__ == "__main__": import uvicorn uvicorn.run(app, host=settings.API_HOST, port=settings.API_PORT)