2020from django .db .models import Exists
2121from django .db .models import OuterRef
2222from django .db .models import Prefetch
23+ from django .http import HttpResponse
2324from django .http .response import Http404
2425from django .shortcuts import get_object_or_404
2526from django .shortcuts import redirect
4748from vulnerabilities .pipelines .v2_importers .epss_importer_v2 import EPSSImporterPipeline
4849from vulnerabilities .severity_systems import EPSS
4950from vulnerabilities .severity_systems import SCORING_SYSTEMS
51+ from vulnerabilities .throttling import AnonUserUIThrottle
5052from vulnerabilities .utils import TYPES_WITH_MULTIPLE_IMPORTERS
5153from vulnerabilities .utils import get_advisories_from_groups
5254from vulnerabilities .utils import merge_and_save_grouped_advisories
5658PAGE_SIZE = 10
5759
5860
59- class PackageSearch (ListView ):
61+ class VulnerableCodeView (View ):
62+ """
63+ Base ListView for VulnerableCode views that includes throttling.
64+ """
65+
66+ throttle_classes = [AnonUserUIThrottle ]
67+
68+ def dispatch (self , request , * args , ** kwargs ):
69+ throttle = AnonUserUIThrottle ()
70+
71+ if not throttle .allow_request (request , self ):
72+ return HttpResponse ("Rate limit exceeded" , status = 429 )
73+
74+ return super ().dispatch (request , * args , ** kwargs )
75+
76+
77+ class VulnerableCodeDetailView (DetailView , VulnerableCodeView ):
78+ """
79+ Base DetailView for VulnerableCode views that includes throttling.
80+ """
81+
82+ pass
83+
84+
85+ class VulnerableCodeListView (ListView , VulnerableCodeView ):
86+ """
87+ Base ListView for VulnerableCode views that includes throttling.
88+ """
89+
90+ pass
91+
92+
93+ class VulnerableCodeCreateView (generic .CreateView , VulnerableCodeView ):
94+ """
95+ Base CreateView for VulnerableCode views that includes throttling.
96+ """
97+
98+ pass
99+
100+
101+ class PackageSearch (VulnerableCodeListView ):
60102 model = models .Package
61103 template_name = "packages.html"
62104 ordering = ["type" , "namespace" , "name" , "version" ]
@@ -84,7 +126,7 @@ def get_queryset(self, query=None):
84126 )
85127
86128
87- class VulnerabilitySearch (ListView ):
129+ class VulnerabilitySearch (VulnerableCodeListView ):
88130 model = models .Vulnerability
89131 template_name = "vulnerabilities.html"
90132 ordering = ["vulnerability_id" ]
@@ -102,7 +144,7 @@ def get_queryset(self, query=None):
102144 return self .model .objects .search (query = query ).with_package_counts ()
103145
104146
105- class PackageDetails (DetailView ):
147+ class PackageDetails (VulnerableCodeDetailView ):
106148 model = models .Package
107149 template_name = "package_details.html"
108150 slug_url_kwarg = "purl"
@@ -143,7 +185,7 @@ def get_object(self, queryset=None):
143185 return package
144186
145187
146- class PackageSearchV2 (ListView ):
188+ class PackageSearchV2 (VulnerableCodeListView ):
147189 model = models .PackageV2
148190 template_name = "packages_v2.html"
149191 ordering = ["type" , "namespace" , "name" , "version" ]
@@ -166,7 +208,7 @@ def get_queryset(self, query=None):
166208 return self .model .objects .search (query ).prefetch_related ().with_is_vulnerable ()
167209
168210
169- class AffectedByAdvisoriesListView (ListView ):
211+ class AffectedByAdvisoriesListView (VulnerableCodeListView ):
170212 model = models .AdvisoryV2
171213 template_name = "affected_by_advisories.html"
172214 paginate_by = PAGE_SIZE
@@ -187,7 +229,7 @@ def get_queryset(self):
187229 )
188230
189231
190- class FixingAdvisoriesListView (ListView ):
232+ class FixingAdvisoriesListView (VulnerableCodeListView ):
191233 model = models .AdvisoryV2
192234 template_name = "fixing_advisories.html"
193235 paginate_by = PAGE_SIZE
@@ -201,7 +243,7 @@ def get_queryset(self):
201243 )
202244
203245
204- class PackageV2Details (DetailView ):
246+ class PackageV2Details (VulnerableCodeDetailView ):
205247 model = models .PackageV2
206248 template_name = "package_details_v2.html"
207249 slug_url_kwarg = "purl"
@@ -439,7 +481,7 @@ def get_fixed_package_details(package):
439481 return fixed_pkg_details
440482
441483
442- class VulnerabilityDetails (DetailView ):
484+ class VulnerabilityDetails (VulnerableCodeDetailView ):
443485 model = models .Vulnerability
444486 template_name = "vulnerability_details.html"
445487 slug_url_kwarg = "vulnerability_id"
@@ -543,7 +585,7 @@ def get_context_data(self, **kwargs):
543585 return context
544586
545587
546- class AdvisoryDetails (DetailView ):
588+ class AdvisoryDetails (VulnerableCodeDetailView ):
547589 model = models .AdvisoryV2
548590 template_name = "advisory_detail.html"
549591 slug_url_kwarg = "avid"
@@ -717,7 +759,7 @@ def add_ssvc(ssvc):
717759 return context
718760
719761
720- class HomePage (View ):
762+ class HomePage (VulnerableCodeView ):
721763 template_name = "index.html"
722764
723765 def get (self , request ):
@@ -730,7 +772,7 @@ def get(self, request):
730772 return render (request = request , template_name = self .template_name , context = context )
731773
732774
733- class HomePageV2 (View ):
775+ class HomePageV2 (VulnerableCodeView ):
734776 template_name = "index_v2.html"
735777
736778 def get (self , request ):
@@ -770,7 +812,7 @@ def get(self, request):
770812"""
771813
772814
773- class ApiUserCreateView (generic . CreateView ):
815+ class ApiUserCreateView (VulnerableCodeCreateView ):
774816 model = models .ApiUser
775817 form_class = ApiUserCreationForm
776818 template_name = "api_user_creation_form.html"
@@ -800,7 +842,7 @@ def get_success_url(self):
800842 return reverse_lazy ("api_user_request" )
801843
802844
803- class VulnerabilityPackagesDetails (DetailView ):
845+ class VulnerabilityPackagesDetails (VulnerableCodeDetailView ):
804846 """
805847 View to display all packages affected by or fixing a specific vulnerability.
806848 URL: /vulnerabilities/{vulnerability_id}/packages
@@ -851,7 +893,7 @@ def get_context_data(self, **kwargs):
851893 return context
852894
853895
854- class AdvisoryPackagesDetails (DetailView ):
896+ class AdvisoryPackagesDetails (VulnerableCodeDetailView ):
855897 """
856898 View to display all packages affected by or fixing a specific vulnerability.
857899 URL: /advisories/{id}/packages
@@ -902,7 +944,7 @@ def get_queryset(self):
902944 )
903945
904946
905- class PipelineScheduleListView (ListView , FormMixin ):
947+ class PipelineScheduleListView (VulnerableCodeListView , FormMixin ):
906948 model = PipelineSchedule
907949 context_object_name = "schedule_list"
908950 template_name = "pipeline_dashboard.html"
@@ -926,7 +968,7 @@ def get_context_data(self, **kwargs):
926968 return context
927969
928970
929- class PipelineRunListView (ListView ):
971+ class PipelineRunListView (VulnerableCodeListView ):
930972 model = PipelineRun
931973 context_object_name = "run_list"
932974 template_name = "pipeline_run_list.html"
@@ -952,7 +994,7 @@ def get_context_data(self, **kwargs):
952994 return context
953995
954996
955- class PipelineRunDetailView (DetailView ):
997+ class PipelineRunDetailView (VulnerableCodeDetailView ):
956998 model = PipelineRun
957999 template_name = "pipeline_run_details.html"
9581000 context_object_name = "run"
0 commit comments