From bba53e59d4feb315fce96ae941ce957c8551ca1f Mon Sep 17 00:00:00 2001 From: Iam54r1n4 Date: Thu, 6 Feb 2025 01:50:37 +0000 Subject: [PATCH] Document that APIs need API key --- core/scripts/webpanel/app.py | 8 +++-- core/scripts/webpanel/openapi/__init__.py | 1 + core/scripts/webpanel/openapi/openapi.py | 39 +++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 core/scripts/webpanel/openapi/__init__.py create mode 100644 core/scripts/webpanel/openapi/openapi.py diff --git a/core/scripts/webpanel/app.py b/core/scripts/webpanel/app.py index 841dfc8..08f44b4 100644 --- a/core/scripts/webpanel/app.py +++ b/core/scripts/webpanel/app.py @@ -5,11 +5,11 @@ import asyncio from fastapi import FastAPI from starlette.staticfiles import StaticFiles - from config import CONFIGS # Loads the configuration from .env from middleware import AuthMiddleware # Defines authentication middleware from middleware import AfterRequestMiddleware # Defines after request middleware from dependency import get_session_manager # Defines dependencies across routers +from openapi import setup_openapi_schema # Adds authorization header to openapi schema from exception_handler import setup_exception_handler # Defines exception handlers # Append directory of cli_api.py to be able to import it @@ -43,6 +43,7 @@ def create_app() -> FastAPI: setup_exception_handler(app) # Set up authentication middleware + app.add_middleware(AuthMiddleware, session_manager=get_session_manager(), api_token=CONFIGS.API_TOKEN) # Set up after request middleware app.add_middleware(AfterRequestMiddleware) @@ -51,7 +52,10 @@ def create_app() -> FastAPI: app.include_router(routers.basic.router, prefix='', tags=['Basic Routes[Web]']) # Add basic router app.include_router(routers.login.router, prefix='', tags=['Authentication[Web]']) # Add authentication router app.include_router(routers.user.router, prefix='/users', tags=['User Management[Web]']) # Add user router - app.include_router(routers.api.v1.api_v1_router, prefix='/api/v1', tags=['API Version 1']) # Add API version 1 router + app.include_router(routers.api.v1.api_v1_router, prefix='/api/v1', tags=['API Version 1']) # Add API version 1 router # type: ignore + + # Document that the API requires an API key + setup_openapi_schema(app) return app diff --git a/core/scripts/webpanel/openapi/__init__.py b/core/scripts/webpanel/openapi/__init__.py new file mode 100644 index 0000000..c9aeec1 --- /dev/null +++ b/core/scripts/webpanel/openapi/__init__.py @@ -0,0 +1 @@ +from .openapi import setup_openapi_schema diff --git a/core/scripts/webpanel/openapi/openapi.py b/core/scripts/webpanel/openapi/openapi.py new file mode 100644 index 0000000..23c2987 --- /dev/null +++ b/core/scripts/webpanel/openapi/openapi.py @@ -0,0 +1,39 @@ +from fastapi import FastAPI + +from config import CONFIGS + + +def setup_openapi_schema(app: FastAPI): + """Set up the OpenAPI schema for the API. + + The OpenAPI schema is modified to include the API key in the + "Authorization" header. All routes under /api/v1/ are modified to + require the API key. + """ + + app.openapi_schema = app.openapi() + + app.openapi_schema["servers"] = [ + { + "url": f"/{CONFIGS.ROOT_PATH}", + "description": "Root path of the API" + } + ] + + # Define API key in the OpenAPI schema + # It's a header with the name "Authorization" + app.openapi_schema["components"]["securitySchemes"] = { + "ApiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "Authorization" + } + } + + # Apply the API key requirement to all paths under /api/v1/ dynamically + for path, operations in app.openapi_schema["paths"].items(): + if path.startswith("/api/v1/"): # Apply security to routes starting with /api/v1/ + for operation in operations.values(): + if "security" not in operation: + operation["security"] = [] + operation["security"].append({"ApiKeyAuth": []})