aboutsummaryrefslogtreecommitdiff
path: root/deps/node/deps/npm/lib/install/audit.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/node/deps/npm/lib/install/audit.js')
-rw-r--r--deps/node/deps/npm/lib/install/audit.js279
1 files changed, 279 insertions, 0 deletions
diff --git a/deps/node/deps/npm/lib/install/audit.js b/deps/node/deps/npm/lib/install/audit.js
new file mode 100644
index 00000000..f5bc5ae1
--- /dev/null
+++ b/deps/node/deps/npm/lib/install/audit.js
@@ -0,0 +1,279 @@
+'use strict'
+exports.generate = generate
+exports.generateFromInstall = generateFromInstall
+exports.submitForInstallReport = submitForInstallReport
+exports.submitForFullReport = submitForFullReport
+exports.printInstallReport = printInstallReport
+exports.printParseableReport = printParseableReport
+exports.printFullReport = printFullReport
+
+const auditReport = require('npm-audit-report')
+const npmConfig = require('../config/figgy-config.js')
+const figgyPudding = require('figgy-pudding')
+const treeToShrinkwrap = require('../shrinkwrap.js').treeToShrinkwrap
+const 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/specifiers
+const 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 = scrub
+function 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)
+}