Spaces:
Sleeping
Sleeping
| """Shared slowapi limiters and key functions. | |
| We run two parallel limiters: | |
| - per-IP (catches a single abuser even if they have the key) | |
| - per-app-key (catches mass abuse from a leaked extension key) | |
| """ | |
| from __future__ import annotations | |
| from fastapi import Request | |
| from slowapi import Limiter | |
| from slowapi.util import get_remote_address | |
| from app.config import settings | |
| def _key_from_header(request: Request) -> str: | |
| # Use the app API key as the limiter key. Falls back to client IP | |
| # so unauthenticated requests still bucket somewhere sane. | |
| key = request.headers.get("x-api-key", "") | |
| return key or get_remote_address(request) | |
| ip_limiter = Limiter(key_func=get_remote_address) | |
| key_limiter = Limiter(key_func=_key_from_header) | |
| def per_ip_limit() -> str: | |
| return settings.rate_limit_per_ip | |
| def per_key_limit() -> str: | |
| return settings.rate_limit_per_key | |