dusty/scanners/sast/retirejs/legacy.py (94 lines of code) (raw):
#!/usr/bin/python3
# coding=utf-8
# pylint: skip-file
# Copyright 2019 getcarrier.io
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Code from Dusty 1.0
"""
import json
import os
import re
import requests
from bs4 import BeautifulSoup
from distutils.version import LooseVersion
from dusty.tools import markdown
__author__ = 'KarynaTaranova'
NVD_URL = 'https://nvd.nist.gov/vuln/detail/'
SEVERITIES = {
'Info': 4,
'Low': 3,
'Medium': 2,
'High': 1,
'Critical': 0
}
def get_dependencies(file_path, add_devdep=False):
package_json = json.load(open(f'{file_path}/package.json'))
deps = list(package_json.get('dependencies', {}).keys())
if add_devdep:
deps.extend(list(package_json.get('devDependencies', {}).keys()))
return deps
class RetireScanParser(object):
def __init__(self, filename, deps):
dupes = dict()
find_date = None
self.items = []
if not os.path.exists(filename):
return
data = json.load(open(filename))['data']
components_data = {}
for file_results in data:
file_path = file_results.get('file')
for version_results in file_results.get('results'):
component = version_results.get('component')
if component in deps:
if component not in components_data:
components_data[component] = \
{'versions': set(), 'descriptions': {}, 'references': {},
'file_paths': {}, 'version_to_update': '0', 'severity': 'Info'}
components_data[component]['versions'].add(version_results.get('version'))
for vulnerability in version_results.get('vulnerabilities', []):
summary = vulnerability.get('identifiers').get('summary')
if summary not in components_data[component]['file_paths']:
components_data[component]['file_paths'][summary] = set()
components_data[component]['references'][summary] = set()
components_data[component]['file_paths'][summary].add(file_path)
for reference in vulnerability.get('info'):
if reference not in components_data[component]['references']:
components_data[component]['references'][summary].add(reference)
if NVD_URL in reference:
url_text = requests.get(reference).text
soup = BeautifulSoup(url_text, 'html.parser')
recomendation = soup.find_all('a', {'id': 'showCPERanges'})
if recomendation:
ver_res = re.findall('versions up to \(excluding\)(.*)',
recomendation[0].attrs['data-range-description'])
if ver_res:
ver = ver_res[0].strip()
if (LooseVersion(components_data[component]['version_to_update'])
< LooseVersion(ver)):
components_data[component]['version_to_update'] = ver
description = soup.find_all('p', {'data-testid': 'vuln-description'})
if description:
components_data[component]['descriptions'][summary] = description[0].text
cur_severity = vulnerability.get('severity').title()
if SEVERITIES.get(components_data[component]['severity']) \
> SEVERITIES.get(cur_severity):
components_data[component]['severity'] = cur_severity
format_str = ' \n**{}**: {}\n \n'
for key, value in components_data.items():
title = 'Update {}'.format(key)
if value.get('version_to_update') != '0':
title += ' to version {}'.format(value.get('version_to_update'))
severity = value.get('severity')
description = ' \n'.join([format_str.format(markdown.markdown_escape(key), markdown.markdown_escape(val))
for key, val in value.get('descriptions').items()])
references = ''
for ref_key, ref_val in value.get('references').items():
_references = ','.join([' \n- {}'.format(x) for x in ref_val]) + ' \n'
references += format_str.format(markdown.markdown_escape(ref_key), markdown.markdown_escape(_references))
file_path = ''
for path_key, path_val in value.get('file_paths').items():
_paths = ','.join([' \n- {}'.format(x) for x in path_val]) + ' \n'
file_path += format_str.format(markdown.markdown_escape(path_key), markdown.markdown_escape(_paths))
dupes[title] = {
"title": title,
"description": description,
"severity": severity,
"file_path": file_path,
"date": find_date,
"references": references
}
self.items = dupes.values()