| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 | 'use strict'exports.generate = generateexports.generateFromInstall = generateFromInstallexports.submitForInstallReport = submitForInstallReportexports.submitForFullReport = submitForFullReportexports.printInstallReport = printInstallReportexports.printParseableReport = printParseableReportexports.printFullReport = printFullReportconst auditReport = require('npm-audit-report')const npmConfig = require('../config/figgy-config.js')const figgyPudding = require('figgy-pudding')const treeToShrinkwrap = require('../shrinkwrap.js').treeToShrinkwrapconst packageId = require('../utils/package-id.js')const output = require('../utils/output.js')const npm = require('../npm.js')const qw = require('qw')const regFetch = require('npm-registry-fetch')const perf = require('../utils/perf.js')const npa = require('npm-package-arg')const uuid = require('uuid')const ssri = require('ssri')const cloneDeep = require('lodash.clonedeep')// used when scrubbing module names/specifiersconst runId = uuid.v4()const InstallAuditConfig = figgyPudding({  color: {},  json: {},  unicode: {}}, {  other (key) {    return /:registry$/.test(key)  }})function submitForInstallReport (auditData) {  const opts = InstallAuditConfig(npmConfig())  const scopedRegistries = [...opts.keys()].filter(    k => /:registry$/.test(k)  ).map(k => opts[k])  scopedRegistries.forEach(registry => {    // we don't care about the response so destroy the stream if we can, or leave it flowing    // so it can eventually finish and clean up after itself    regFetch('/-/npm/v1/security/audits/quick', opts.concat({      method: 'POST',      registry,      gzip: true,      body: auditData    })).then(_ => {      _.body.on('error', () => {})      if (_.body.destroy) {        _.body.destroy()      } else {        _.body.resume()      }    }, _ => {})  })  perf.emit('time', 'audit submit')  return regFetch('/-/npm/v1/security/audits/quick', opts.concat({    method: 'POST',    gzip: true,    body: auditData  })).then(response => {    perf.emit('timeEnd', 'audit submit')    perf.emit('time', 'audit body')    return response.json()  }).then(result => {    perf.emit('timeEnd', 'audit body')    return result  })}function submitForFullReport (auditData) {  perf.emit('time', 'audit submit')  const opts = InstallAuditConfig(npmConfig())  return regFetch('/-/npm/v1/security/audits', opts.concat({    method: 'POST',    gzip: true,    body: auditData  })).then(response => {    perf.emit('timeEnd', 'audit submit')    perf.emit('time', 'audit body')    return response.json()  }).then(result => {    perf.emit('timeEnd', 'audit body')    result.runId = runId    return result  })}function printInstallReport (auditResult) {  const opts = InstallAuditConfig(npmConfig())  return auditReport(auditResult, {    reporter: 'install',    withColor: opts.color,    withUnicode: opts.unicode  }).then(result => output(result.report))}function printFullReport (auditResult) {  const opts = InstallAuditConfig(npmConfig())  return auditReport(auditResult, {    log: output,    reporter: opts.json ? 'json' : 'detail',    withColor: opts.color,    withUnicode: opts.unicode  }).then(result => output(result.report))}function printParseableReport (auditResult) {  const opts = InstallAuditConfig(npmConfig())  return auditReport(auditResult, {    log: output,    reporter: 'parseable',    withColor: opts.color,    withUnicode: opts.unicode  }).then(result => output(result.report))}function generate (shrinkwrap, requires, diffs, install, remove) {  const sw = cloneDeep(shrinkwrap)  delete sw.lockfileVersion  sw.requires = scrubRequires(requires)  scrubDeps(sw.dependencies)  // sw.diffs = diffs || {}  sw.install = (install || []).map(scrubArg)  sw.remove = (remove || []).map(scrubArg)  return generateMetadata().then((md) => {    sw.metadata = md    return sw  })}const scrubKeys = qw`version`const deleteKeys = qw`from resolved`function scrubDeps (deps) {  if (!deps) return  Object.keys(deps).forEach(name => {    if (!shouldScrubName(name) && !shouldScrubSpec(name, deps[name].version)) return    const value = deps[name]    delete deps[name]    deps[scrub(name)] = value  })  Object.keys(deps).forEach(name => {    for (let toScrub of scrubKeys) {      if (!deps[name][toScrub]) continue      deps[name][toScrub] = scrubSpec(name, deps[name][toScrub])    }    for (let toDelete of deleteKeys) delete deps[name][toDelete]    scrubRequires(deps[name].requires)    scrubDeps(deps[name].dependencies)  })}function scrubRequires (reqs) {  if (!reqs) return reqs  Object.keys(reqs).forEach(name => {    const spec = reqs[name]    if (shouldScrubName(name) || shouldScrubSpec(name, spec)) {      delete reqs[name]      reqs[scrub(name)] = scrubSpec(name, spec)    } else {      reqs[name] = scrubSpec(name, spec)    }  })  return reqs}function getScope (name) {  if (name[0] === '@') return name.slice(0, name.indexOf('/'))}function shouldScrubName (name) {  const scope = getScope(name)  const cfg = npm.config // avoid the no-dynamic-lookups test  return Boolean(scope && cfg.get(scope + ':registry'))}function shouldScrubSpec (name, spec) {  const req = npa.resolve(name, spec)  return !req.registry}function scrubArg (arg) {  const req = npa(arg)  let name = req.name  if (shouldScrubName(name) || shouldScrubSpec(name, req.rawSpec)) {    name = scrubName(name)  }  const spec = scrubSpec(req.name, req.rawSpec)  return name + '@' + spec}function scrubName (name) {  return shouldScrubName(name) ? scrub(name) : name}function scrubSpec (name, spec) {  const req = npa.resolve(name, spec)  if (req.registry) return spec  if (req.type === 'git') {    return 'git+ssh://' + scrub(spec)  } else if (req.type === 'remote') {    return 'https://' + scrub(spec)  } else if (req.type === 'directory') {    return 'file:' + scrub(spec)  } else if (req.type === 'file') {    return 'file:' + scrub(spec) + '.tar'  } else {    return scrub(spec)  }}module.exports.scrub = scrubfunction scrub (value, rid) {  return ssri.fromData((rid || runId) + ' ' + value, {algorithms: ['sha256']}).hexDigest()}function generateMetadata () {  const meta = {}  meta.npm_version = npm.version  meta.node_version = process.version  meta.platform = process.platform  meta.node_env = process.env.NODE_ENV  return Promise.resolve(meta)}/*  const head = path.resolve(npm.prefix, '.git/HEAD')  return readFile(head, 'utf8').then((head) => {    if (!head.match(/^ref: /)) {      meta.commit_hash = head.trim()      return    }    const headFile = head.replace(/^ref: /, '').trim()    meta.branch = headFile.replace(/^refs[/]heads[/]/, '')    return readFile(path.resolve(npm.prefix, '.git', headFile), 'utf8')  }).then((commitHash) => {    meta.commit_hash = commitHash.trim()    const proc = spawn('git', qw`diff --quiet --exit-code package.json package-lock.json`, {cwd: npm.prefix, stdio: 'ignore'})    return new Promise((resolve, reject) => {      proc.once('error', reject)      proc.on('exit', (code, signal) => {        if (signal == null) meta.state = code === 0 ? 'clean' : 'dirty'        resolve()      })    })  }).then(() => meta, () => meta)*/function generateFromInstall (tree, diffs, install, remove) {  const requires = {}  tree.requires.forEach((pkg) => {    requires[pkg.package.name] = tree.package.dependencies[pkg.package.name] || tree.package.devDependencies[pkg.package.name] || pkg.package.version  })  const auditInstall = (install || []).filter((a) => a.name).map(packageId)  const auditRemove = (remove || []).filter((a) => a.name).map(packageId)  const auditDiffs = {}  diffs.forEach((action) => {    const mutation = action[0]    const child = action[1]    if (mutation !== 'add' && mutation !== 'update' && mutation !== 'remove') return    if (!auditDiffs[mutation]) auditDiffs[mutation] = []    if (mutation === 'add') {      auditDiffs[mutation].push({location: child.location})    } else if (mutation === 'update') {      auditDiffs[mutation].push({location: child.location, previous: packageId(child.oldPkg)})    } else if (mutation === 'remove') {      auditDiffs[mutation].push({previous: packageId(child)})    }  })  return generate(treeToShrinkwrap(tree), requires, auditDiffs, auditInstall, auditRemove)}
 |