mirror of
https://github.com/suitenumerique/meet.git
synced 2026-10-13 16:42:18 +00:00
059e5f1ec4
The per-minute room creation throttle absorbs bursts but does not stop a compromised account from steadily creating rooms over hours or days. Add RoomCreationDailyUserRateThrottle, a per-user throttle with its own "room_creation_daily" scope, applied to room creation only alongside the existing short-term throttle. It defaults to 1000 rooms per day and is configurable via ROOM_CREATION_DAILY_THROTTLE_RATES. Tests use a controllable clock and patch rates with monkeypatch so they are restored after each test.
127 lines
4.2 KiB
Python
127 lines
4.2 KiB
Python
"""Throttling modules for the API."""
|
|
|
|
from django.conf import settings
|
|
|
|
from lasuite.drf.throttling import MonitoredThrottleMixin
|
|
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
|
|
from sentry_sdk import capture_message
|
|
|
|
|
|
def sentry_monitoring_throttle_failure(message):
|
|
"""Log when a failure occurs to detect rate limiting issues."""
|
|
capture_message(message, "warning")
|
|
|
|
|
|
class MonitoredAnonRateThrottle(MonitoredThrottleMixin, AnonRateThrottle):
|
|
"""Throttle for the monitored scoped rate throttle."""
|
|
|
|
|
|
class MonitoredUserRateThrottle(MonitoredThrottleMixin, UserRateThrottle):
|
|
"""Throttle for the monitored scoped rate throttle."""
|
|
|
|
|
|
class RoomCreationUserRateThrottle(MonitoredUserRateThrottle):
|
|
"""Throttle room creation per authenticated user.
|
|
|
|
Can be declared at the viewset level: every action other than "create"
|
|
is left unthrottled, so the same class can be reused on any viewset
|
|
exposing a room creation endpoint.
|
|
"""
|
|
|
|
scope = "room_creation"
|
|
|
|
def get_cache_key(self, request, view):
|
|
"""Throttle only room creations."""
|
|
if getattr(view, "action", None) != "create":
|
|
return None
|
|
return super().get_cache_key(request, view)
|
|
|
|
|
|
class RoomCreationDailyUserRateThrottle(RoomCreationUserRateThrottle):
|
|
"""Cap room creation per authenticated user over a day.
|
|
|
|
Complements the short-term RoomCreationUserRateThrottle, which absorbs
|
|
bursts but lets a user steadily create rooms over hours or days.
|
|
"""
|
|
|
|
scope = "room_creation_daily"
|
|
|
|
|
|
class RequestEntryAuthenticatedUserRateThrottle(MonitoredUserRateThrottle):
|
|
"""Throttle authenticated user requesting room entry"""
|
|
|
|
scope = "request_entry"
|
|
|
|
def get_cache_key(self, request, view):
|
|
"""Use the authenticated user ID as the throttle cache key."""
|
|
|
|
if request.user and not request.user.is_authenticated:
|
|
return None # Defer to RequestEntryAnonRateThrottle for anonymous users.
|
|
|
|
return super().get_cache_key(request, view)
|
|
|
|
|
|
class RequestEntryAnonRateThrottle(MonitoredAnonRateThrottle):
|
|
"""Throttle Anonymous user requesting room entry"""
|
|
|
|
scope = "request_entry"
|
|
|
|
def get_cache_key(self, request, view):
|
|
"""Use the lobby participant cookie ID as the throttle cache key.
|
|
|
|
Only throttle if a cookie is already set. If no cookie exists yet,
|
|
return None to skip throttling — the cookie will be set on the first
|
|
response, and throttling will apply from the second request onward.
|
|
|
|
Keying on the cookie rather than the IP address prevents penalising
|
|
multiple users behind the same NAT/proxy, and is consistent with how
|
|
LobbyService identifies participants.
|
|
|
|
Note: as per DRF documentation, application-level throttling is not a
|
|
security measure against brute-force or DoS attacks. This throttle exists
|
|
solely to guard against accidental hammering from buggy clients.
|
|
"""
|
|
|
|
if request.user and request.user.is_authenticated:
|
|
return None # Only throttle unauthenticated requests.
|
|
|
|
participant_id = request.COOKIES.get(settings.LOBBY_COOKIE_NAME)
|
|
|
|
if participant_id is None:
|
|
return None # No throttling for cookieless requests
|
|
|
|
return self.cache_format % {
|
|
"scope": self.scope,
|
|
"ident": participant_id,
|
|
}
|
|
|
|
|
|
class CreationCallbackAnonRateThrottle(MonitoredAnonRateThrottle):
|
|
"""Throttle Anonymous user requesting room generation callback"""
|
|
|
|
scope = "creation_callback"
|
|
|
|
|
|
class RoomKitJoinRateThrottle(MonitoredUserRateThrottle):
|
|
"""Throttle the LiveKit SIP module requesting roomkit joins.
|
|
|
|
The roomkit endpoints are authenticated as a machine user, so all requests
|
|
share a single throttle bucket. This is not a security measure against
|
|
brute-force attacks but a guard against accidental hammering from a buggy
|
|
SIP module.
|
|
"""
|
|
|
|
scope = "roomkit_join"
|
|
|
|
|
|
class ConnectionTestUserRateThrottle(MonitoredUserRateThrottle):
|
|
"""Throttle authenticated users requesting connection test tokens."""
|
|
|
|
scope = "connection_test"
|
|
|
|
|
|
class ConnectionTestAnonRateThrottle(MonitoredAnonRateThrottle):
|
|
"""Throttle anonymous users requesting connection test tokens."""
|
|
|
|
scope = "connection_test"
|