feat(V2): X-Bot-Tag header obbligatorio + endpoint /admin/audit con filtri
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+43
-4
@@ -1,4 +1,8 @@
|
||||
"""Bearer auth middleware: bearer token → request.state.environment."""
|
||||
"""Bearer auth middleware: bearer token → request.state.environment.
|
||||
|
||||
Inoltre richiede header `X-Bot-Tag` su tutte le chiamate non whitelisted,
|
||||
così che l'audit log identifichi il bot chiamante.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import secrets
|
||||
@@ -9,7 +13,17 @@ from fastapi.responses import JSONResponse
|
||||
|
||||
Environment = Literal["testnet", "mainnet"]
|
||||
|
||||
WHITELIST_PATHS = frozenset({"/health", "/apidocs", "/openapi.json", "/docs", "/redoc"})
|
||||
# Path che bypassano sia bearer auth sia bot_tag check.
|
||||
PATH_WHITELIST_FULL = frozenset(
|
||||
{"/health", "/apidocs", "/openapi.json", "/docs", "/redoc"}
|
||||
)
|
||||
# Path che richiedono bearer ma NON il bot_tag (admin endpoint).
|
||||
PATH_WHITELIST_BOT_TAG_ONLY = frozenset({"/admin/audit"})
|
||||
|
||||
# Backward-compat alias (vecchi import).
|
||||
WHITELIST_PATHS = PATH_WHITELIST_FULL
|
||||
|
||||
MAX_BOT_TAG_LEN = 64
|
||||
|
||||
|
||||
def _extract_bearer(auth_header: str) -> str | None:
|
||||
@@ -35,13 +49,17 @@ def install_auth_middleware(
|
||||
testnet_token: str,
|
||||
mainnet_token: str,
|
||||
) -> None:
|
||||
"""Registra middleware di auth bearer sull'app FastAPI."""
|
||||
"""Registra middleware di auth bearer + bot_tag sull'app FastAPI."""
|
||||
|
||||
@app.middleware("http")
|
||||
async def auth_middleware(request: Request, call_next):
|
||||
if request.url.path in WHITELIST_PATHS:
|
||||
path = request.url.path
|
||||
|
||||
# 1. Whitelist totale: nessun check.
|
||||
if path in PATH_WHITELIST_FULL:
|
||||
return await call_next(request)
|
||||
|
||||
# 2. Bearer auth (sempre richiesto).
|
||||
token = _extract_bearer(request.headers.get("Authorization", ""))
|
||||
if token is None:
|
||||
return JSONResponse(
|
||||
@@ -57,4 +75,25 @@ def install_auth_middleware(
|
||||
"message": "invalid token"}},
|
||||
)
|
||||
request.state.environment = env
|
||||
|
||||
# 3. Whitelist parziale (admin): bearer ok, no bot_tag check.
|
||||
if path in PATH_WHITELIST_BOT_TAG_ONLY:
|
||||
return await call_next(request)
|
||||
|
||||
# 4. X-Bot-Tag obbligatorio.
|
||||
raw_tag = request.headers.get("X-Bot-Tag", "")
|
||||
tag = raw_tag.strip() if raw_tag else ""
|
||||
if not tag:
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
content={"error": {"code": "BAD_REQUEST",
|
||||
"message": "missing X-Bot-Tag header"}},
|
||||
)
|
||||
if len(tag) > MAX_BOT_TAG_LEN:
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
content={"error": {"code": "BAD_REQUEST",
|
||||
"message": "X-Bot-Tag too long"}},
|
||||
)
|
||||
request.state.bot_tag = tag
|
||||
return await call_next(request)
|
||||
|
||||
Reference in New Issue
Block a user