-
Notifications
You must be signed in to change notification settings - Fork 198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use packageurl version 0.9.3 and Add nginx importer #264
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
# Copyright (c) nexB Inc. and others. All rights reserved. | ||
# http://nexb.com and https://github.com/nexB/vulnerablecode/ | ||
# The VulnerableCode software is licensed under the Apache License version | ||
# Data generated with VulnerableCode require an acknowledgment. | ||
# | ||
# You may not use this software except in compliance with the License. | ||
# You may obtain a copy of the License at: http://apache.org/licenses/LICE | ||
# Unless required by applicable law or agreed to in writing, software dist | ||
# under the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES | ||
# CONDITIONS OF ANY KIND, either express or implied. See the License for t | ||
# specific language governing permissions and limitations under the Licens | ||
# | ||
# When you publish or redistribute any data created with VulnerableCode or | ||
# derivative work, you must accompany this data with the following acknowl | ||
# | ||
# Generated with VulnerableCode and provided on an 'AS IS' BASIS, WITHOUT | ||
# OR CONDITIONS OF ANY KIND, either express or implied. No content create | ||
# VulnerableCode should be considered or used as legal advice. Consult an | ||
# for any legal advice. | ||
# VulnerableCode is a free software from nexB Inc. and others. | ||
# Visit https://github.com/nexB/vulnerablecode/ for support and download. | ||
|
||
import asyncio | ||
import dataclasses | ||
import json | ||
|
||
import requests | ||
from packageurl import PackageURL | ||
from bs4 import BeautifulSoup | ||
from dephell_specifier import RangeSpecifier | ||
|
||
from vulnerabilities.data_source import Advisory | ||
from vulnerabilities.data_source import DataSource | ||
from vulnerabilities.data_source import DataSourceConfiguration | ||
from vulnerabilities.data_source import Reference | ||
from vulnerabilities.package_managers import GitHubTagsAPI | ||
|
||
|
||
@dataclasses.dataclass | ||
class NginxDataSourceConfiguration(DataSourceConfiguration): | ||
etag: dict | ||
|
||
|
||
class NginxDataSource(DataSource): | ||
CONFIG_CLASS = NginxDataSourceConfiguration | ||
|
||
url = "http://nginx.org/en/security_advisories.html" | ||
|
||
def set_api(self): | ||
self.version_api = GitHubTagsAPI() | ||
asyncio.run(self.version_api.load_api(["nginx/nginx"])) | ||
|
||
# For some reason nginx tags it's releases in the form of `release-1.2.3` | ||
# Chop off the `release-` part here. | ||
for index, version in enumerate(self.version_api.cache["nginx/nginx"]): | ||
self.version_api.cache["nginx/nginx"][index] = version.replace("release-", "") | ||
|
||
def updated_advisories(self): | ||
advisories = [] | ||
if self.create_etag(): | ||
self.set_api() | ||
data = requests.get(self.url).content | ||
advisories.extend(self.to_advisories(data)) | ||
return self.batch_advisories(advisories) | ||
|
||
def create_etag(self): | ||
etag = requests.head(self.url).headers.get("ETag") | ||
if not etag: | ||
return True | ||
|
||
elif self.url in self.config.etag: | ||
if self.config.etag[self.url] == etag: | ||
return False | ||
|
||
self.config.etag[self.url] = etag | ||
return True | ||
|
||
def to_advisories(self, data): | ||
advisories = [] | ||
soup = BeautifulSoup(data) | ||
vuln_list = soup.select("li p") | ||
|
||
# Example value of `vuln_list` : | ||
# ['Excessive CPU usage in HTTP/2 with small window updates', | ||
# <br/>, | ||
# 'Severity: medium', | ||
# <br/>, | ||
# <a href="http://mailman.nginx.org/pipermail/nginx-announce/2019/000249.html">Advisory</a>, # nopep8 | ||
# <br/>, | ||
# <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9511">CVE-2019-9511</a>, | ||
# <br/>, | ||
# 'Not vulnerable: 1.17.3+, 1.16.1+', | ||
# <br/>, | ||
# 'Vulnerable: 1.9.5-1.17.2'] | ||
|
||
for vuln_info in vuln_list: | ||
references = [] | ||
for index, child in enumerate(vuln_info.children): | ||
if index == 0: | ||
# type of this child is bs4.element.NavigableString. | ||
# Hence cast it into standard string | ||
summary = str(child) | ||
continue | ||
|
||
# hasattr(child, "attrs") == False for bs4.element.NavigableString | ||
if hasattr(child, "attrs") and child.attrs.get("href"): | ||
link = child.attrs["href"] | ||
references.append(Reference(url=link)) | ||
if "cve.mitre.org" in link: | ||
cve_id = child.text | ||
continue | ||
|
||
if "Not vulnerable" in child: | ||
fixed_packages = self.extract_fixed_pkgs(child) | ||
continue | ||
|
||
if "Vulnerable" in child: | ||
vulnerable_packages = self.extract_vuln_pkgs(child) | ||
continue | ||
|
||
advisories.append( | ||
Advisory( | ||
cve_id=cve_id, | ||
summary=summary, | ||
impacted_package_urls=vulnerable_packages, | ||
resolved_package_urls=fixed_packages, | ||
) | ||
) | ||
|
||
return advisories | ||
|
||
def extract_fixed_pkgs(self, vuln_info): | ||
vuln_status, version_info = vuln_info.split(": ") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using a |
||
if "none" in version_info: | ||
return {} | ||
|
||
raw_ranges = version_info.split(",") | ||
version_ranges = [] | ||
for rng in raw_ranges: | ||
# Eg. "1.7.3+" gets converted to RangeSpecifier("^1.7.3") | ||
# The advisory in this case uses `+` in the sense that any version | ||
# with greater or equal `minor` version satisfies the range. | ||
# "1.7.4" satisifes "1.7.3+", but "1.8.4" does not. "1.7.3+" has same | ||
# semantics as that of "^1.7.3" | ||
|
||
version_ranges.append(RangeSpecifier("^" + rng[:-1])) | ||
|
||
valid_versions = find_valid_versions(self.version_api.get("nginx/nginx"), version_ranges) | ||
|
||
return { | ||
PackageURL(type="generic", name="nginx", version=version) for version in valid_versions | ||
} | ||
|
||
def extract_vuln_pkgs(self, vuln_info): | ||
vuln_status, version_infos = vuln_info.split(": ") | ||
if "none" in version_infos: | ||
return {} | ||
|
||
version_ranges = [] | ||
windows_only = False | ||
for version_info in version_infos.split(", "): | ||
if "-" not in version_info: | ||
# These are discrete versions | ||
version_ranges.append(RangeSpecifier(version_info[0])) | ||
continue | ||
|
||
windows_only = "nginx/Windows" in version_info | ||
version_info = version_info.replace("nginx/Windows", "") | ||
lower_bound, upper_bound = version_info.split("-") | ||
|
||
version_ranges.append(RangeSpecifier(f">={lower_bound},<={upper_bound}")) | ||
|
||
valid_versions = find_valid_versions(self.version_api.get("nginx/nginx"), version_ranges) | ||
qualifiers = {} | ||
if windows_only: | ||
qualifiers["os"] = "windows" | ||
|
||
return { | ||
PackageURL(type="generic", name="nginx", version=version, qualifiers=qualifiers) | ||
for version in valid_versions | ||
} | ||
|
||
|
||
def find_valid_versions(versions, version_ranges): | ||
valid_versions = set() | ||
for version in versions: | ||
if any([version in ver_range for ver_range in version_ranges]): | ||
valid_versions.add(version) | ||
|
||
return valid_versions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: we should sort imports. But we should also switch to using black and isort, so we can do it all at once!