Skip to content

Commit fcc6acf

Browse files
wraithgarnlf
authored andcommitted
deps: @npmcli/metavuln-calculator@3.0.1
1 parent 48d5cb5 commit fcc6acf

File tree

21 files changed

+2160
-18
lines changed

21 files changed

+2160
-18
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
ISC License
2+
3+
Copyright (c) npm, Inc.
4+
5+
Permission to use, copy, modify, and/or distribute this software for
6+
any purpose with or without fee is hereby granted, provided that the
7+
above copyright notice and this permission notice appear in all copies.
8+
9+
THE SOFTWARE IS PROVIDED "AS IS" AND THE COPYRIGHT HOLDER DISCLAIMS
10+
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11+
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12+
COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13+
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
14+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15+
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
16+
USE OR PERFORMANCE OF THIS SOFTWARE.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use strict'
2+
3+
const contentVer = require('../../package.json')['cache-version'].content
4+
const hashToSegments = require('../util/hash-to-segments')
5+
const path = require('path')
6+
const ssri = require('ssri')
7+
8+
// Current format of content file path:
9+
//
10+
// sha512-BaSE64Hex= ->
11+
// ~/.my-cache/content-v2/sha512/ba/da/55deadbeefc0ffee
12+
//
13+
module.exports = contentPath
14+
15+
function contentPath (cache, integrity) {
16+
const sri = ssri.parse(integrity, { single: true })
17+
// contentPath is the *strongest* algo given
18+
return path.join(
19+
contentDir(cache),
20+
sri.algorithm,
21+
...hashToSegments(sri.hexDigest())
22+
)
23+
}
24+
25+
module.exports.contentDir = contentDir
26+
27+
function contentDir (cache) {
28+
return path.join(cache, `content-v${contentVer}`)
29+
}
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
'use strict'
2+
3+
const util = require('util')
4+
5+
const fs = require('fs')
6+
const fsm = require('fs-minipass')
7+
const ssri = require('ssri')
8+
const contentPath = require('./path')
9+
const Pipeline = require('minipass-pipeline')
10+
11+
const lstat = util.promisify(fs.lstat)
12+
const readFile = util.promisify(fs.readFile)
13+
14+
module.exports = read
15+
16+
const MAX_SINGLE_READ_SIZE = 64 * 1024 * 1024
17+
function read (cache, integrity, opts = {}) {
18+
const { size } = opts
19+
return withContentSri(cache, integrity, (cpath, sri) => {
20+
// get size
21+
return lstat(cpath).then(stat => ({ stat, cpath, sri }))
22+
}).then(({ stat, cpath, sri }) => {
23+
if (typeof size === 'number' && stat.size !== size) {
24+
throw sizeError(size, stat.size)
25+
}
26+
27+
if (stat.size > MAX_SINGLE_READ_SIZE) {
28+
return readPipeline(cpath, stat.size, sri, new Pipeline()).concat()
29+
}
30+
31+
return readFile(cpath, null).then((data) => {
32+
if (!ssri.checkData(data, sri)) {
33+
throw integrityError(sri, cpath)
34+
}
35+
36+
return data
37+
})
38+
})
39+
}
40+
41+
const readPipeline = (cpath, size, sri, stream) => {
42+
stream.push(
43+
new fsm.ReadStream(cpath, {
44+
size,
45+
readSize: MAX_SINGLE_READ_SIZE,
46+
}),
47+
ssri.integrityStream({
48+
integrity: sri,
49+
size,
50+
})
51+
)
52+
return stream
53+
}
54+
55+
module.exports.sync = readSync
56+
57+
function readSync (cache, integrity, opts = {}) {
58+
const { size } = opts
59+
return withContentSriSync(cache, integrity, (cpath, sri) => {
60+
const data = fs.readFileSync(cpath)
61+
if (typeof size === 'number' && size !== data.length) {
62+
throw sizeError(size, data.length)
63+
}
64+
65+
if (ssri.checkData(data, sri)) {
66+
return data
67+
}
68+
69+
throw integrityError(sri, cpath)
70+
})
71+
}
72+
73+
module.exports.stream = readStream
74+
module.exports.readStream = readStream
75+
76+
function readStream (cache, integrity, opts = {}) {
77+
const { size } = opts
78+
const stream = new Pipeline()
79+
withContentSri(cache, integrity, (cpath, sri) => {
80+
// just lstat to ensure it exists
81+
return lstat(cpath).then((stat) => ({ stat, cpath, sri }))
82+
}).then(({ stat, cpath, sri }) => {
83+
if (typeof size === 'number' && size !== stat.size) {
84+
return stream.emit('error', sizeError(size, stat.size))
85+
}
86+
87+
readPipeline(cpath, stat.size, sri, stream)
88+
}, er => stream.emit('error', er))
89+
90+
return stream
91+
}
92+
93+
let copyFile
94+
if (fs.copyFile) {
95+
module.exports.copy = copy
96+
module.exports.copy.sync = copySync
97+
copyFile = util.promisify(fs.copyFile)
98+
}
99+
100+
function copy (cache, integrity, dest) {
101+
return withContentSri(cache, integrity, (cpath, sri) => {
102+
return copyFile(cpath, dest)
103+
})
104+
}
105+
106+
function copySync (cache, integrity, dest) {
107+
return withContentSriSync(cache, integrity, (cpath, sri) => {
108+
return fs.copyFileSync(cpath, dest)
109+
})
110+
}
111+
112+
module.exports.hasContent = hasContent
113+
114+
function hasContent (cache, integrity) {
115+
if (!integrity) {
116+
return Promise.resolve(false)
117+
}
118+
119+
return withContentSri(cache, integrity, (cpath, sri) => {
120+
return lstat(cpath).then((stat) => ({ size: stat.size, sri, stat }))
121+
}).catch((err) => {
122+
if (err.code === 'ENOENT') {
123+
return false
124+
}
125+
126+
if (err.code === 'EPERM') {
127+
/* istanbul ignore else */
128+
if (process.platform !== 'win32') {
129+
throw err
130+
} else {
131+
return false
132+
}
133+
}
134+
})
135+
}
136+
137+
module.exports.hasContent.sync = hasContentSync
138+
139+
function hasContentSync (cache, integrity) {
140+
if (!integrity) {
141+
return false
142+
}
143+
144+
return withContentSriSync(cache, integrity, (cpath, sri) => {
145+
try {
146+
const stat = fs.lstatSync(cpath)
147+
return { size: stat.size, sri, stat }
148+
} catch (err) {
149+
if (err.code === 'ENOENT') {
150+
return false
151+
}
152+
153+
if (err.code === 'EPERM') {
154+
/* istanbul ignore else */
155+
if (process.platform !== 'win32') {
156+
throw err
157+
} else {
158+
return false
159+
}
160+
}
161+
}
162+
})
163+
}
164+
165+
function withContentSri (cache, integrity, fn) {
166+
const tryFn = () => {
167+
const sri = ssri.parse(integrity)
168+
// If `integrity` has multiple entries, pick the first digest
169+
// with available local data.
170+
const algo = sri.pickAlgorithm()
171+
const digests = sri[algo]
172+
173+
if (digests.length <= 1) {
174+
const cpath = contentPath(cache, digests[0])
175+
return fn(cpath, digests[0])
176+
} else {
177+
// Can't use race here because a generic error can happen before
178+
// a ENOENT error, and can happen before a valid result
179+
return Promise
180+
.all(digests.map((meta) => {
181+
return withContentSri(cache, meta, fn)
182+
.catch((err) => {
183+
if (err.code === 'ENOENT') {
184+
return Object.assign(
185+
new Error('No matching content found for ' + sri.toString()),
186+
{ code: 'ENOENT' }
187+
)
188+
}
189+
return err
190+
})
191+
}))
192+
.then((results) => {
193+
// Return the first non error if it is found
194+
const result = results.find((r) => !(r instanceof Error))
195+
if (result) {
196+
return result
197+
}
198+
199+
// Throw the No matching content found error
200+
const enoentError = results.find((r) => r.code === 'ENOENT')
201+
if (enoentError) {
202+
throw enoentError
203+
}
204+
205+
// Throw generic error
206+
throw results.find((r) => r instanceof Error)
207+
})
208+
}
209+
}
210+
211+
return new Promise((resolve, reject) => {
212+
try {
213+
tryFn()
214+
.then(resolve)
215+
.catch(reject)
216+
} catch (err) {
217+
reject(err)
218+
}
219+
})
220+
}
221+
222+
function withContentSriSync (cache, integrity, fn) {
223+
const sri = ssri.parse(integrity)
224+
// If `integrity` has multiple entries, pick the first digest
225+
// with available local data.
226+
const algo = sri.pickAlgorithm()
227+
const digests = sri[algo]
228+
if (digests.length <= 1) {
229+
const cpath = contentPath(cache, digests[0])
230+
return fn(cpath, digests[0])
231+
} else {
232+
let lastErr = null
233+
for (const meta of digests) {
234+
try {
235+
return withContentSriSync(cache, meta, fn)
236+
} catch (err) {
237+
lastErr = err
238+
}
239+
}
240+
throw lastErr
241+
}
242+
}
243+
244+
function sizeError (expected, found) {
245+
/* eslint-disable-next-line max-len */
246+
const err = new Error(`Bad data size: expected inserted data to be ${expected} bytes, but got ${found} instead`)
247+
err.expected = expected
248+
err.found = found
249+
err.code = 'EBADSIZE'
250+
return err
251+
}
252+
253+
function integrityError (sri, path) {
254+
const err = new Error(`Integrity verification failed for ${sri} (${path})`)
255+
err.code = 'EINTEGRITY'
256+
err.sri = sri
257+
err.path = path
258+
return err
259+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict'
2+
3+
const util = require('util')
4+
5+
const contentPath = require('./path')
6+
const { hasContent } = require('./read')
7+
const rimraf = util.promisify(require('rimraf'))
8+
9+
module.exports = rm
10+
11+
function rm (cache, integrity) {
12+
return hasContent(cache, integrity).then((content) => {
13+
// ~pretty~ sure we can't end up with a content lacking sri, but be safe
14+
if (content && content.sri) {
15+
return rimraf(contentPath(cache, content.sri)).then(() => true)
16+
} else {
17+
return false
18+
}
19+
})
20+
}

0 commit comments

Comments
 (0)