UNPKG

node-version-audit

Version:

Audit your Node version for known CVEs and patches

113 lines (103 loc) 3.57 kB
const { CachedDownload } = require('./CachedDownload'); const { ParseException } = require('./Exceptions'); const { CveId } = require('./CveId'); const { CveDetails } = require('./CveDetails'); const { Logger } = require('./Logger'); const CVE_START_YEAR = 2013; const CveFeed = {}; /** * @param {CveId[]} cveIds * @return {Promise<{string: CveDetails}>} */ CveFeed.parse = async (cveIds) => { const feedNames = ['modified', 'recent']; const currentYear = new Date().getFullYear(); for (let year = CVE_START_YEAR; year <= currentYear; year++) { feedNames.push(year.toString()); } let cveDetails = []; for (let feedName of feedNames) { let cveFeed = await CveFeed._downloadFeed(feedName); Logger.info('Beginning NVD feed parse: ', feedName); cveDetails = cveDetails.concat(CveFeed._parseFeed(cveIds, cveFeed)); } cveDetails.sort(CveDetails.compare); return cveDetails.reduce((sortedCveDetails, cveDetail) => { if (!sortedCveDetails[cveDetail.id.toString()]) { sortedCveDetails[cveDetail.id.toString()] = cveDetail; } return sortedCveDetails; }, {}); }; /** * @param {CveId[]} cveIds * @param {*} cveFeed * @return {CveDetails[]} * @private */ CveFeed._parseFeed = function (cveIds, cveFeed) { const cveDetails = []; const cvesSet = new Set(cveIds.map((cve) => cve.toString())); for (let cveItem of cveFeed.CVE_Items) { const cve = CveFeed._parseCveItem(cveItem); if (cve && cvesSet.has(cve.id.toString())) { cveDetails.push(cve); cvesSet.delete(cve.id.toString()); } } return cveDetails; }; /** * @param {string} feedName * @throws {ParseException} * @return {*} */ CveFeed._downloadFeed = async function (feedName) { try { return await CachedDownload.json(`https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-${feedName}.json.gz`); } catch (ex) { const currentYear = new Date().getFullYear(); const currentMonth = new Date().getMonth(); if (feedName === currentYear.toString() && currentMonth === 0) { Logger.warn(`Unable to download feed ${feedName}. Skipping due to beginning of the year.`); return { CVE_Items: [], }; } else { throw ParseException.fromException(ex); } } }; /** * @param cveItem * @return {null|CveDetails} */ CveFeed._parseCveItem = function (cveItem) { let id = null; try { id = CveId.fromString(cveItem.cve.CVE_data_meta.ID); } catch (e) { return null; } const publishedDate = new Date(cveItem.publishedDate).toISOString(); const lastModifiedDate = new Date(cveItem.lastModifiedDate).toISOString(); let description = null; let baseScore = null; if (cveItem.cve.description.description_data) { for (let descriptionLang of cveItem.cve.description.description_data) { if (descriptionLang.lang === 'en') { description = descriptionLang.value; break; } } } if (cveItem.impact.baseMetricV3 && cveItem.impact.baseMetricV3.cvssV3.baseScore) { baseScore = cveItem.impact.baseMetricV3.cvssV3.baseScore; } else if (cveItem.impact.baseMetricV2 && cveItem.impact.baseMetricV2.cvssV2.baseScore) { baseScore = cveItem.impact.baseMetricV2.cvssV2.baseScore; } return new CveDetails(id, baseScore, publishedDate, lastModifiedDate, description); }; module.exports = { CveFeed, };