Files
vidconf/backend/core/rate_limit.py

37 lines
1.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Rate limit на основе Redis `INCR`+`EXPIRE` для публичных (без auth) эндпоинтов.
Используется резолвом конференций и гостевым входом (`api/conferences.py`) —
эндпоинтами без аутентификации, уязвимыми к перебору номера/ссылки конференции
(см. ADR-001, п.4 — оценка энтропии и рекомендуемый лимит 10 запросов/мин на IP).
"""
from fastapi import HTTPException, status
from core.redis import redis_client
RATE_LIMIT_MAX_REQUESTS = 10
RATE_LIMIT_WINDOW_SECONDS = 60
async def enforce_rate_limit(
key: str,
*,
max_requests: int = RATE_LIMIT_MAX_REQUESTS,
window_seconds: int = RATE_LIMIT_WINDOW_SECONDS,
) -> None:
"""Увеличить счётчик запросов по ключу; бросить 429, если лимит превышен.
`INCR` атомарно создаёт ключ со значением 1, если его ещё не было; TTL
выставляется только при первом инкременте в окне (когда счётчик стал
равен 1) — иначе окно продлевалось бы при каждом запросе и лимит
никогда бы не истекал.
"""
redis_key = f"rate_limit:{key}"
current = await redis_client.incr(redis_key)
if current == 1:
await redis_client.expire(redis_key, window_seconds)
if current > max_requests:
raise HTTPException(
status_code=status.HTTP_429_TOO_MANY_REQUESTS, detail="rate_limit_exceeded"
)