nsp-audit-package
Version:
offers a simple library to audit your package.json or a stream of package.json
100 lines (80 loc) • 2.48 kB
JavaScript
var fs = require('fs');
var async = require('async');
var npmconf = require('npmconf');
var RegClient = require('silent-npm-registry-client');
var validateModule = require('nsp-api').validateModule;
var traverse = require('./traverse');
var MAX_ASYNC_THROTTLING = 20;
module.exports = auditPackage;
function auditPackage(pkgPath, cb) {
async.waterfall([
async.parallel.bind(async, [
loadPkg.bind(null, pkgPath),
buildRegClient,
]),
function(res, cb) {
var pkg = res[0];
var reg = res[1];
traverse(reg, pkg, then);
function then(err, pkgs) {
if (err) {
return cb(err);
}
async.mapLimit(pkgs, MAX_ASYNC_THROTTLING, verifyModule, cb);
}
},
function(all, cb) { cb(null, all.filter(function(x) { return x; })); }
], cb);
}
function loadPkg(pkgPath, cb) {
async.waterfall([
assertPkgFileExists,
fs.readFile.bind(fs, pkgPath, {encoding: 'utf8'}),
function(pkgText, cb) { cb(null, JSON.parse(pkgText)); }
], cb);
function assertPkgFileExists(cb) {
fs.exists(pkgPath, then);
function then(exists) {
cb(exists ? null :
new Error('Can\'t load ' + pkgPath +
'\nMake sure you have a package.json available'));
}
}
}
function buildRegClient(cb) {
async.waterfall([
npmconf.load.bind(npmconf),
function build(config, cb) { cb(null, new RegClient(config)); }
], cb);
}
function getAncestry(module, list) {
list = list || [];
if (!module) {
return list;
}
list.push(module);
return getAncestry(module.parent, list);
}
function verifyModule(module, cb) {
validateModule(module.name, module.version, validated);
function validated(err, result) {
if (err) {
return cb(err);
}
if (!Array.isArray(result)) {
return cb(new TypeError('Unexpected API response format.'));
}
if (!result.length) {
return cb();
}
cb(null, {
module: module.name,
version: module.version,
advisory: result[0],
advisories: result,
dependencyOf: getAncestry(module)
.map(function(d) { return d.name + '@' + d.version; })
.reverse()
});
}
}