UNPKG

hhurley

Version:

Tool to find lost security patches for Linux distributions.

167 lines (135 loc) 4.88 kB
/* Copyright IBM Research Emergent Solutions Jesús Pérez <jesusprubio@gmail.com> This code may only be used under the MIT license found at https://opensource.org/licenses/MIT. */ 'use strict'; const path = require('path'); const fs = require('fs'); const util = require('util'); const EventEmitter = require('events').EventEmitter; const pkgInfo = require('./package'); const cfg = require('./cfg'); const utils = require('./lib/utils'); // const parser = require('./lib/parsers'); const providers = utils.requireDir(module, './lib/providers'); const dbg = utils.dbg(__filename); const baseFilePath = path.resolve(__dirname, cfg.baseFile.path); // function parse(opts) { // return { // concurrency: parser.natural(opts.concurrency), // timeout: parser.natural(opts.timeout) // }; // } class Cli { constructor(opts = {}) { this.version = pkgInfo.version; this.forceDown = opts.forceDown || false; this.fileExists = false; this.interval = null; dbg(`Checking if the base file exists ... (${baseFilePath})`); try { fs.statSync(baseFilePath); dbg('File already exists'); this.fileExists = true; } catch (err) { if (err.code !== 'ENOENT') { // Not expected error. throw err; } dbg('File doesn\'t exist'); } dbg(`Version: ${this.version}`); } stop() { clearInterval(this.interval); } // TODO: Allow to pass the options here. search() { dbg('Starting ...'); // Conditional promise. const downloadC = () => new Promise((resD, rejD) => { if (this.forceDown || !this.fileExists) { dbg('Downloading base file ...'); // TODO: Add progress support: // https://www.npmjs.com/package/progress-stream this.emit('file:downloading'); utils.downBase(cfg.baseFile.url, baseFilePath) .then(() => { this.emit('file:downloaded'); resD(); }) .catch(err => rejD(err)); } else { dbg('File already exists'); resD(); } }); downloadC() .then(() => { dbg('Download finished, reading the file now ...'); // TODO: Ue an iterator. In case a huge file the memory print could be too much. utils.readFile(baseFilePath, { encoding: 'utf8' }) .then((baseFile) => { let lastCve; dbg('Base file correctly readed'); const split = baseFile.split('\n'); dbg('Base file splitted:', split); utils.each(split, (line) => { dbg(`New line to inspect: ${line}`); if (line[0] === 'C' && line[1] === 'V' && line[2] === 'E' && line[3] === '-') { lastCve = line.substring(0, 12).trim(); dbg(`New CVE ID: ${lastCve}`); } if (line[0] === '\t' && line[1] === 'N' && line[2] === 'O' && line[3] === 'T' && line[4] === 'E') { let link = line.substring(7).trim(); dbg(`New note line found: ${link}`); // TODO: Trim this (if possible): // https://github.com/chriso/validator.js/#validators if (utils.validator.isURL(link, { protocols: ['http', 'https'], require_protocol: true, require_valid_protocol: true, require_host: true, })) { dbg(`New URL found: ${link}`); // Sometimes the url includes a "/" at the end and we don't // want it because sometimes we need to add stuff to the end. // ie: Github url -> url.patch if (link.slice(-1) === '/') { link = link.slice(0, -1); } const patchInfo = { cve: lastCve }; utils.each(Object.keys(providers), (name) => { // Until one is found. if (!patchInfo.patchUrl) { // We need to found all the included ones. if (providers[name].match(link)) { // TODO: Add a check to confirm the methods exist. const hash = providers[name].getHash(link); const patchUrl = providers[name].massage(link); if (patchUrl) { patchInfo.provider = name; patchInfo.id = `${name}:${patchInfo.cve}:${hash}`; patchInfo.link = link; patchInfo.patchUrl = patchUrl; } } } }); if (patchInfo.patchUrl) { this.emit('new', patchInfo); } } } }); dbg('Done'); this.emit('end'); }) .catch(err => this.emit('error', err)); }) .catch(err => this.emit('error', err)); } } util.inherits(Cli, EventEmitter); module.exports = Cli;