2222# Visit https://github.com/nexB/vulnerablecode/ for support and download.
2323
2424import json
25- import re
26- import semantic_version
25+ from dephell_specifier import RangeSpecifier
2726from urllib .request import urlopen
27+ from urllib .error import HTTPError
28+
2829
2930NPM_URL = 'https://registry.npmjs.org{}'
3031PAGE = '/-/npm/v1/security/advisories?page=0'
3132
3233
33- def remove_spaces (x ):
34- """
35- Remove Multiple Space, spaces after relational operator
36- and remove v charecter in front of version string (ex v1.2.3)
37- """
38- x = re .sub (r' +' , ' ' , x )
39- x = re .sub (r'< +' , '<' , x )
40- x = re .sub (r'> +' , '>' , x )
41- x = re .sub (r'<= +' , '<=' , x )
42- x = re .sub (r'>= +' , '>=' , x )
43- x = re .sub (r'>=[vV]' , '>=' , x )
44- x = re .sub (r'<=[vV]' , '<=' , x )
45- x = re .sub (r'>[vV]' , '>' , x )
46- x = re .sub (r'<[vV]' , '<' , x )
47- return x
48-
49-
5034def get_all_versions (package_name ):
5135 """
5236 Returns all versions available for a module
5337 """
38+ package_name = package_name .strip ()
5439 package_url = NPM_URL .format (f'/{ package_name } ' )
55- with urlopen (package_url ) as response :
56- data = json .load (response )
40+ try :
41+ with urlopen (package_url ) as response :
42+ data = json .load (response )
43+ except HTTPError as e :
44+ if e .code == 404 :
45+ return []
46+ else :
47+ raise
48+ # NPM registry has no data regarding this package, we skip these
5749 return [v for v in data .get ('versions' , {})]
5850
5951
@@ -62,20 +54,21 @@ def extract_versions(package_name, aff_version_range, fixed_version_range):
6254 Seperate list of affected versions and unaffected versions from all versions
6355 using the ranges specified.
6456 """
65- aff_spec = semantic_version . NpmSpec ( remove_spaces ( aff_version_range ) )
66- fix_spec = semantic_version . NpmSpec ( remove_spaces ( fixed_version_range ) )
57+ aff_spec = RangeSpecifier ( aff_version_range )
58+ fix_spec = RangeSpecifier ( fixed_version_range )
6759 all_ver = get_all_versions (package_name )
60+ if not all_ver :
61+ # NPM registry has no data regarding this package, we skip these
62+ return ([], [])
6863 aff_ver = []
6964 fix_ver = []
7065 # Unaffected version is that version which is in the fixed_version_range
7166 # or which is absent in the aff_version_range
7267 for ver in all_ver :
73- cur_version = semantic_version .Version (ver )
74- if cur_version in fix_spec or cur_version not in aff_spec :
68+ if ver in fix_spec or ver not in aff_spec :
7569 fix_ver .append (ver )
7670 else :
7771 aff_ver .append (ver )
78-
7972 return (aff_ver , fix_ver )
8073
8174
@@ -96,6 +89,9 @@ def extract_data(JSON):
9689 obj .get ('vulnerable_versions' , '' ),
9790 obj .get ('patched_versions' , '' )
9891 )
92+ if not affected_versions and not fixed_versions :
93+ continue
94+ # NPM registry has no data regarding this package finally we skip these
9995
10096 package_vulnerabilities .append ({
10197 'package_name' : package_name ,
@@ -113,12 +109,19 @@ def scrape_vulnerabilities():
113109 """
114110 Extract JSON From NPM registry
115111 """
116- nextpage = PAGE
117112 package_vulnerabilities = []
113+ nextpage = PAGE
118114 while nextpage :
119- cururl = NPM_URL .format (nextpage )
120- response = json .load (urlopen (cururl ))
121- package_vulnerabilities .extend (extract_data (response ))
122- next_page = response .get ('urls' , {}).get ('next' )
115+ try :
116+ cururl = NPM_URL .format (nextpage )
117+ response = json .load (urlopen (cururl ))
118+ package_vulnerabilities .extend (extract_data (response ))
119+ nextpage = response .get ('urls' , {}).get ('next' )
120+
121+ except HTTPError as error :
122+ if error .code == 404 :
123+ break
124+ else :
125+ raise
123126
124127 return package_vulnerabilities
0 commit comments