From 9b64ad24804f7e4a87c330efc078f0e9e21bbd66 Mon Sep 17 00:00:00 2001 From: Mike VanDenburgh Date: Wed, 20 Mar 2024 16:01:11 -0400 Subject: [PATCH] Rate limit assets list endpoint for logged out users --- dandiapi/api/views/asset.py | 6 ++++++ dandiapi/settings.py | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/dandiapi/api/views/asset.py b/dandiapi/api/views/asset.py index 34d35e8f1..ec719287a 100644 --- a/dandiapi/api/views/asset.py +++ b/dandiapi/api/views/asset.py @@ -36,6 +36,7 @@ from rest_framework.exceptions import NotAuthenticated, NotFound, PermissionDenied from rest_framework.generics import get_object_or_404 from rest_framework.response import Response +from rest_framework.throttling import AnonRateThrottle, BaseThrottle from rest_framework.viewsets import GenericViewSet, ReadOnlyModelViewSet from rest_framework_extensions.mixins import DetailSerializerMixin, NestedViewSetMixin @@ -82,6 +83,11 @@ class AssetViewSet(DetailSerializerMixin, GenericViewSet): filter_backends = [filters.DjangoFilterBackend] filterset_class = AssetFilter + def get_throttles(self) -> list[BaseThrottle]: + if self.action == 'list': + return [*self.throttle_classes, AnonRateThrottle()] + return super().get_throttles() + def raise_if_unauthorized(self): # We need to check the dandiset to see if it's embargoed, and if so whether or not the # user has ownership diff --git a/dandiapi/settings.py b/dandiapi/settings.py index 0ba65368f..1be4aab6a 100644 --- a/dandiapi/settings.py +++ b/dandiapi/settings.py @@ -2,6 +2,7 @@ import os from pathlib import Path +import sys from composed_configuration import ( ComposedConfiguration, @@ -79,6 +80,11 @@ def mutate_configuration(configuration: type[ComposedConfiguration]): 'dandiapi.drf_utils.rewrap_django_core_exceptions' ) + # By default, set request rate limit to a very high number, effectively disabling it. + configuration.REST_FRAMEWORK['DEFAULT_THROTTLE_RATES'] = { + 'anon': f'{sys.maxsize}/minute', + } + # If this environment variable is set, the pydantic model will allow URLs with localhost # in them. This is important for development and testing environments, where URLs will # frequently point to localhost. @@ -181,6 +187,11 @@ def mutate_configuration(configuration: type[ComposedConfiguration]): # We're configuring sentry by hand since we need to pass custom options (traces_sampler). configuration.INSTALLED_APPS.remove('composed_configuration.sentry.apps.SentryConfig') + # In production, enable rate limiting for unauthenticated users + configuration.REST_FRAMEWORK['DEFAULT_THROTTLE_RATES'] = { + 'anon': '60/minute', + } + ENABLE_GITHUB_OAUTH = True # All login attempts in production should go straight to GitHub