File tree Expand file tree Collapse file tree 4 files changed +83
-4
lines changed Expand file tree Collapse file tree 4 files changed +83
-4
lines changed Original file line number Diff line number Diff line change 14
14
15
15
16
16
class PackageSearchForm (forms .Form ):
17
-
18
17
search = forms .CharField (
19
18
required = True ,
20
19
widget = forms .TextInput (
21
- attrs = {"placeholder" : "Package name, purl or purl fragment" },
20
+ attrs = {
21
+ "placeholder" : "Package name, purl or purl fragment" ,
22
+ },
23
+ ),
24
+ )
25
+ type = forms .CharField (required = False , max_length = 50 )
26
+ vulnerable_only = forms .ChoiceField (
27
+ required = False ,
28
+ choices = (
29
+ ("" , "All Packages" ),
30
+ ("true" , "Vulnerable Only" ),
31
+ ("false" , "Non-Vulnerable Only" ),
22
32
),
23
33
)
24
34
35
+ def clean_search (self ):
36
+ """Sanitize the search input which provide extra layer of protection from XSS attacks"""
37
+ search = self .cleaned_data ["search" ].strip ()
38
+ if not search :
39
+ raise forms .ValidationError ("Search field cannot be empty" )
40
+ return search
41
+
42
+ def clean_type (self ):
43
+ """Sanitize the type input which provide extra layer of protection from XSS attacks"""
44
+ pkg_type = self .cleaned_data ["type" ].strip ()
45
+ return pkg_type
46
+
25
47
26
48
class VulnerabilitySearchForm (forms .Form ):
27
49
Original file line number Diff line number Diff line change 18
18
< div >
19
19
{{ page_obj.paginator.count|intcomma }} results
20
20
</ div >
21
+ < select name ="vulnerable_only " class ="select " id ="vulnerable-select ">
22
+ < option value =""> All Packages</ option >
23
+ < option value ="true " {% if request.GET.vulnerable_only == 'true ' %}selected{% endif %} > Vulnerable Only</ option >
24
+ < option value ="false " {% if request.GET.vulnerable_only == 'false ' %}selected{% endif %} > Non-Vulnerable Only</ option >
25
+ </ select >
26
+
21
27
{% if is_paginated %}
22
28
{% include 'includes/pagination.html' with page_obj=page_obj %}
23
29
{% endif %}
81
87
82
88
</ section >
83
89
{% endif %}
84
- {% endblock %}
90
+ < script >
91
+ // This script is used to update the URL when the user selects a value from the vulnerable_only dropdown menu.
92
+ // It also sanitize the URL to prevent XSS attacks.
93
+ document . getElementById ( 'vulnerable-select' ) . addEventListener ( 'change' , function ( ) {
94
+ let searchParams = new URLSearchParams ( window . location . search ) ;
95
+ let selectedValue = this . value . replace ( / [ ^ a - z A - Z 0 - 9 ] / g, '' ) ;
96
+ let searchTerm = searchParams . get ( 'search' ) ;
97
+ if ( searchTerm ) {
98
+ searchTerm = encodeURIComponent ( searchTerm ) ;
99
+ }
100
+ if ( selectedValue ) {
101
+ searchParams . set ( 'vulnerable_only' , selectedValue ) ;
102
+ } else {
103
+ searchParams . delete ( 'vulnerable_only' ) ;
104
+ }
105
+ if ( searchTerm ) {
106
+ searchParams . set ( 'search' , searchTerm ) ;
107
+ }
108
+ let newUrl = window . location . pathname + '?' + searchParams . toString ( ) ;
109
+ if ( newUrl . match ( / ^ [ ^ < > ' " ] * $ / ) ) {
110
+ window . location . href = newUrl ;
111
+ }
112
+ } ) ;
113
+ </ script >
114
+ {% endblock %}
Original file line number Diff line number Diff line change @@ -127,6 +127,26 @@ def test_package_view_with_valid_purl_without_version(self):
127
127
128
128
]
129
129
130
+ def test_package_search_vulnerable_only_filter (self ):
131
+ vulnerable_pkg = Package .objects .create (type = "npm" , name = "vulnerable-pkg" , version = "1.0.0" )
132
+ non_vulnerable_pkg = Package .objects .create (
133
+ type = "npm" , name = "non-vulnerable-pkg" , version = "2.0.0"
134
+ )
135
+ vuln = Vulnerability .objects .create (
136
+ vulnerability_id = "VCID-123" , summary = "test vulnerability"
137
+ )
138
+ AffectedByPackageRelatedVulnerability .objects .create (
139
+ package = vulnerable_pkg , vulnerability = vuln
140
+ )
141
+ self .assertTrue (
142
+ AffectedByPackageRelatedVulnerability .objects .filter (package = vulnerable_pkg ).exists ()
143
+ )
144
+ self .assertFalse (
145
+ AffectedByPackageRelatedVulnerability .objects .filter (
146
+ package = non_vulnerable_pkg
147
+ ).exists ()
148
+ )
149
+
130
150
def test_package_view_with_valid_purl_and_incomplete_version (self ):
131
151
qs = PackageSearch ().get_queryset (query = "pkg:nginx/nginx@1" )
132
152
pkgs = list (qs )
Original file line number Diff line number Diff line change @@ -58,12 +58,19 @@ def get_queryset(self, query=None):
58
58
on exact purl, partial purl or just name and namespace.
59
59
"""
60
60
query = query or self .request .GET .get ("search" ) or ""
61
- return (
61
+ queryset = (
62
62
self .model .objects .search (query )
63
63
.with_vulnerability_counts ()
64
64
.prefetch_related ()
65
65
.order_by ("package_url" )
66
66
)
67
+ if hasattr (self , "request" ):
68
+ vulnerable_only = self .request .GET .get ("vulnerable_only" , "" ).lower ()
69
+ if vulnerable_only in ["true" , "false" ]:
70
+ queryset = queryset .with_is_vulnerable ()
71
+ queryset = queryset .filter (is_vulnerable = vulnerable_only == "true" )
72
+
73
+ return queryset
67
74
68
75
69
76
class VulnerabilitySearch (ListView ):
You can’t perform that action at this time.
0 commit comments