From 8f583e38542f7c224d834c8969c78e86f00281e2 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Mon, 9 Dec 2024 17:59:37 -0500 Subject: [PATCH] API v2: disallow empty strings as filters (#11832) --- readthedocs/api/v2/views/model_views.py | 14 ++++++++------ readthedocs/rtd_tests/tests/test_api.py | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/readthedocs/api/v2/views/model_views.py b/readthedocs/api/v2/views/model_views.py index 8498cd26af2..27d33cdaa1d 100644 --- a/readthedocs/api/v2/views/model_views.py +++ b/readthedocs/api/v2/views/model_views.py @@ -95,15 +95,17 @@ def list(self, *args, **kwargs): disabled = True + # DRF strips whitespaces from query params, and if the final string is empty + # the filter is ignored. So we do the same to check if the filter is going to be used or not. + project_slug = self.request.GET.get("project__slug", "").strip() + commit = self.request.GET.get("commit", "").strip() + slug = self.request.GET.get("slug", "").strip() # NOTE: keep list endpoint that specifies a resource if any( [ - self.basename == "version" and "project__slug" in self.request.GET, - self.basename == "build" - and ( - "commit" in self.request.GET or "project__slug" in self.request.GET - ), - self.basename == "project" and "slug" in self.request.GET, + self.basename == "version" and project_slug, + self.basename == "build" and (commit or project_slug), + self.basename == "project" and slug, ] ): disabled = False diff --git a/readthedocs/rtd_tests/tests/test_api.py b/readthedocs/rtd_tests/tests/test_api.py index 83932f32add..725d57c3896 100644 --- a/readthedocs/rtd_tests/tests/test_api.py +++ b/readthedocs/rtd_tests/tests/test_api.py @@ -3333,6 +3333,25 @@ def test_get_active_versions(self): self.assertEqual(resp.status_code, 200) self.assertEqual(resp.data["count"], pip.versions.filter(active=False).count()) + def test_listing_of_versions_without_filtering_by_a_project(self): + url = reverse("version-list") + resp = self.client.get(url) + self.assertEqual(resp.status_code, 410) + + data = { + "active": "true", + } + resp = self.client.get(url, data) + self.assertEqual(resp.status_code, 410) + + data["project__slug"] = "" + resp = self.client.get(url, data) + self.assertEqual(resp.status_code, 410) + + data["project__slug"] = " \n" + resp = self.client.get(url, data) + self.assertEqual(resp.status_code, 410) + def test_project_get_active_versions(self): pip = Project.objects.get(slug="pip") url = reverse("project-active-versions", args=[pip.pk])