Browse Source

fix: add rate limit for project transfer endpoint (#73576)

Alexander Tarasov 8 months ago
parent
commit
40f460299d

+ 10 - 0
src/sentry/api/endpoints/project_transfer.py

@@ -14,6 +14,7 @@ from sentry.api.bases.project import ProjectEndpoint, ProjectPermission
 from sentry.api.decorators import sudo_required
 from sentry.models.options.project_option import ProjectOption
 from sentry.models.organizationmember import OrganizationMember
+from sentry.types.ratelimit import RateLimit, RateLimitCategory
 from sentry.utils.email import MessageBuilder
 from sentry.utils.http import absolute_uri
 from sentry.utils.signing import sign
@@ -32,6 +33,15 @@ class ProjectTransferEndpoint(ProjectEndpoint):
     }
     permission_classes = (RelaxedProjectPermission,)
 
+    enforce_rate_limit = True
+    rate_limits = {
+        "POST": {
+            RateLimitCategory.USER: RateLimit(
+                limit=3, window=60 * 60
+            ),  # 3 POST requests per hour per user
+        }
+    }
+
     @sudo_required
     def post(self, request: Request, project) -> Response:
         """

+ 26 - 0
tests/sentry/api/endpoints/test_project_transfer.py

@@ -1,8 +1,10 @@
 from django.core import mail
+from django.test import override_settings
 from django.urls import reverse
 
 from sentry.models.options.project_option import ProjectOption
 from sentry.testutils.cases import APITestCase
+from sentry.testutils.helpers.datetime import freeze_time
 
 
 class ProjectTransferTest(APITestCase):
@@ -73,3 +75,27 @@ class ProjectTransferTest(APITestCase):
 
                 assert response.status_code == 404
                 assert not mail.outbox
+
+    @override_settings(SENTRY_SELF_HOSTED=False)
+    def test_rate_limit(self):
+        project = self.create_project()
+        # new user is not an owner of anything
+        new_user = self.create_user("b@example.com")
+        self.login_as(user=self.user)
+
+        url = reverse(
+            "sentry-api-0-project-transfer",
+            kwargs={
+                "organization_id_or_slug": project.organization.slug,
+                "project_id_or_slug": project.slug,
+            },
+        )
+
+        with freeze_time("2024-07-01"):
+            for _ in range(3 + 1):
+                response = self.client.post(url, {"email": new_user.email})
+        assert response.status_code == 429
+        assert (
+            response.content
+            == b'"You are attempting to use this endpoint too frequently. Limit is 3 requests in 3600 seconds"'
+        )