mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-17 14:07:49 +00:00
116 lines
3.9 KiB
Python
116 lines
3.9 KiB
Python
"""Throttling modules for the API."""
|
|
|
|
from lasuite.drf.throttling import MonitoredThrottleMixin
|
|
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
|
|
from sentry_sdk import capture_message
|
|
|
|
from . import serializers
|
|
|
|
|
|
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 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 requests carrying a participant identifier. The
|
|
identifier is returned by the first request-entry response and
|
|
echoed back by the client from the second request onward, which is
|
|
when throttling starts applying.
|
|
|
|
Keying on the identifier rather than the IP address prevents
|
|
penalising multiple users behind the same NAT/proxy, and is
|
|
consistent with how the lobby 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.
|
|
|
|
serializer = serializers.RequestEntrySerializer(data=request.data)
|
|
if not serializer.is_valid():
|
|
return None
|
|
|
|
participant_id = serializer.validated_data.get("participant_id")
|
|
|
|
if not participant_id:
|
|
return None # No throttling for unidentified 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"
|
|
|
|
|
|
class ExchangeAccessTokenAnonRateThrottle(MonitoredAnonRateThrottle):
|
|
"""Throttle anonymous transit code exchange attempts.
|
|
|
|
Abuse mitigation only, not a security boundary: DRF throttling is
|
|
best-effort. The security of the exchange rests on the codes'
|
|
entropy and single use.
|
|
"""
|
|
|
|
scope = "exchange_access_token"
|