wrongmove/api/origin_validator.py

35 lines
1.2 KiB
Python
Raw Normal View History

"""Origin validation middleware for state-changing requests."""
import logging
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import JSONResponse, Response
logger = logging.getLogger("uvicorn")
STATE_CHANGING_METHODS = {"POST", "PUT", "DELETE", "PATCH"}
class OriginValidatorMiddleware(BaseHTTPMiddleware):
"""Reject state-changing requests with mismatched Origin header."""
def __init__(self, app, allowed_origins: list[str] | None = None) -> None:
super().__init__(app)
self._allowed = {o.rstrip("/") for o in (allowed_origins or [])}
async def dispatch(self, request: Request, call_next) -> Response:
if request.method not in STATE_CHANGING_METHODS:
return await call_next(request)
origin = request.headers.get("origin")
if origin is None:
return await call_next(request)
if origin.rstrip("/") not in self._allowed:
logger.warning(f"Rejected request from origin: {origin}")
return JSONResponse(
status_code=403,
content={"detail": "Origin not allowed"},
)
return await call_next(request)