UNPKG

node-version-audit

Version:

Audit your Node version for known CVEs and patches

82 lines (75 loc) 2.89 kB
const { CachedDownload } = require('./CachedDownload'); const { CveId } = require('./CveId'); const { NodeVersion } = require('./NodeVersion'); const { NodeRelease } = require('./NodeRelease'); const { Logger } = require('./Logger'); const CHANGELOGS_URL = 'https://api.github.com/repos/nodejs/node/contents/doc/changelogs'; const Changelogs = {}; /** * * @return {Promise<{string: NodeRelease}>} */ Changelogs.parse = async function () { const changelogUrls = await Changelogs.getChangelogUrls(); const fullChangelog = (await Promise.all(changelogUrls.map(CachedDownload.download))).join('\n'); return Changelogs.parseChangelog(fullChangelog); }; /** * @return {Promise<string[]>} */ Changelogs.getChangelogUrls = async function () { const folderContent = await CachedDownload.json(CHANGELOGS_URL); // Accept only file names matching CHANGELOG_VXX or CHANGELOG_IOJS.md const filenamePattern = new RegExp(/^CHANGELOG_(V\d+|IOJS)\.md$/); return folderContent.reduce((urls, fileOrFolder) => { if (fileOrFolder.type === 'file' && filenamePattern.test(fileOrFolder.name)) { Logger.debug('Changelog URL found', fileOrFolder.name); urls.push(fileOrFolder.download_url); } else { Logger.debug('Excluding changelog', fileOrFolder.type, fileOrFolder.name); } return urls; }, []); }; /** * @param {string} changelog * @return {{string: NodeRelease}} */ Changelogs.parseChangelog = function (changelog) { let releases = []; let currentRelease = null; const versionBlockMatch = new RegExp(/<a id="(\d+.\d+.\d+)"><\/a>$/); for (const line of changelog.split('\n')) { const matches = versionBlockMatch.exec(line); if (matches && matches.length === 2) { const foundVersion = NodeVersion.fromString(matches[1]); currentRelease = new NodeRelease(foundVersion); releases.push(currentRelease); continue; } if (!currentRelease) { continue; } if (!currentRelease.releaseDate) { const releaseDateMatch = line.match(/## (\d{4}-\d{1,2}-\d{1,2}),.+Version.+/i); if (releaseDateMatch && releaseDateMatch.length === 2) { currentRelease.releaseDate = new Date(releaseDateMatch[1]); continue; } } const cveMatches = line.matchAll(/(CVE-\d{4}-\d+)/gi); for (const cveMatch of cveMatches) { currentRelease.addPatchedCveId(CveId.fromString(cveMatch[1])); } } releases = releases.sort((a, b) => { return NodeVersion.compare(a.version, b.version); }); return releases.reduce((releasesByKey, release) => { releasesByKey[release.version.toString()] = release; return releasesByKey; }, {}); }; module.exports = { Changelogs, };