111 lines
3.9 KiB
Python
111 lines
3.9 KiB
Python
|
from collections import namedtuple
|
||
|
from datetime import datetime
|
||
|
from typing import NamedTuple
|
||
|
|
||
|
|
||
|
class DictConverter(object):
|
||
|
|
||
|
def to_dict(self, **kwargs):
|
||
|
pass
|
||
|
|
||
|
|
||
|
announcement_nmt = namedtuple('Announcement', ['type', 'message'])
|
||
|
remediation_nmt = namedtuple('Remediation', ['Package', 'closest_secure_version', 'secure_versions',
|
||
|
'latest_package_version'])
|
||
|
cve_nmt = namedtuple('Cve', ['name', 'cvssv2', 'cvssv3'])
|
||
|
severity_nmt = namedtuple('Severity', ['source', 'cvssv2', 'cvssv3'])
|
||
|
vulnerability_nmt = namedtuple('Vulnerability',
|
||
|
['vulnerability_id', 'package_name', 'pkg', 'ignored', 'ignored_reason', 'ignored_expires',
|
||
|
'vulnerable_spec', 'all_vulnerable_specs', 'analyzed_version', 'advisory',
|
||
|
'is_transitive', 'published_date', 'fixed_versions',
|
||
|
'closest_versions_without_known_vulnerabilities', 'resources', 'CVE', 'severity',
|
||
|
'affected_versions', 'more_info_url'])
|
||
|
package_nmt = namedtuple('Package', ['name', 'version', 'found', 'insecure_versions', 'secure_versions',
|
||
|
'latest_version_without_known_vulnerabilities', 'latest_version', 'more_info_url'])
|
||
|
package_nmt.__new__.__defaults__ = (None,) * len(package_nmt._fields) # Ugly hack for now
|
||
|
RequirementFile = namedtuple('RequirementFile', ['path'])
|
||
|
|
||
|
|
||
|
class Package(package_nmt, DictConverter):
|
||
|
|
||
|
def to_dict(self, **kwargs):
|
||
|
if kwargs.get('short_version', False):
|
||
|
return {
|
||
|
'name': self.name,
|
||
|
'version': self.version,
|
||
|
}
|
||
|
|
||
|
return {'name': self.name,
|
||
|
'version': self.version,
|
||
|
'found': self.found,
|
||
|
'insecure_versions': self.insecure_versions,
|
||
|
'secure_versions': self.secure_versions,
|
||
|
'latest_version_without_known_vulnerabilities': self.latest_version_without_known_vulnerabilities,
|
||
|
'latest_version': self.latest_version,
|
||
|
'more_info_url': self.more_info_url
|
||
|
}
|
||
|
|
||
|
|
||
|
class Announcement(announcement_nmt):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class Remediation(remediation_nmt, DictConverter):
|
||
|
|
||
|
def to_dict(self):
|
||
|
return {'package': self.Package.name,
|
||
|
'closest_secure_version': self.closest_secure_version,
|
||
|
'secure_versions': self.secure_versions,
|
||
|
'latest_package_version': self.latest_package_version
|
||
|
}
|
||
|
|
||
|
|
||
|
class CVE(cve_nmt, DictConverter):
|
||
|
|
||
|
def to_dict(self):
|
||
|
return {'name': self.name, 'cvssv2': self.cvssv2, 'cvssv3': self.cvssv3}
|
||
|
|
||
|
|
||
|
class Severity(severity_nmt, DictConverter):
|
||
|
def to_dict(self):
|
||
|
result = {'severity': {'source': self.source}}
|
||
|
|
||
|
result['severity']['cvssv2'] = self.cvssv2
|
||
|
result['severity']['cvssv3'] = self.cvssv3
|
||
|
|
||
|
return result
|
||
|
|
||
|
|
||
|
class Vulnerability(vulnerability_nmt):
|
||
|
|
||
|
def to_dict(self):
|
||
|
empty_list_if_none = ['fixed_versions', 'closest_versions_without_known_vulnerabilities', 'resources']
|
||
|
result = {
|
||
|
}
|
||
|
|
||
|
ignore = ['pkg']
|
||
|
|
||
|
for field, value in zip(self._fields, self):
|
||
|
if field in ignore:
|
||
|
continue
|
||
|
|
||
|
if value is None and field in empty_list_if_none:
|
||
|
value = []
|
||
|
|
||
|
if isinstance(value, CVE):
|
||
|
val = None
|
||
|
if value.name.startswith("CVE"):
|
||
|
val = value.name
|
||
|
result[field] = val
|
||
|
elif isinstance(value, DictConverter):
|
||
|
result.update(value.to_dict())
|
||
|
elif isinstance(value, datetime):
|
||
|
result[field] = str(value)
|
||
|
else:
|
||
|
result[field] = value
|
||
|
|
||
|
return result
|
||
|
|
||
|
def get_advisory(self):
|
||
|
return self.advisory.replace('\r', '') if self.advisory else "No advisory found for this vulnerability."
|