Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
lukekarrys committed Aug 30, 2023
1 parent b0849ab commit 7af81c7
Show file tree
Hide file tree
Showing 166 changed files with 25,836 additions and 15 deletions.
25 changes: 25 additions & 0 deletions node_modules/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
!/@npmcli/installed-package-contents
!/@npmcli/map-workspaces
!/@npmcli/metavuln-calculator
!/@npmcli/metavuln-calculator/node_modules/
/@npmcli/metavuln-calculator/node_modules/*
!/@npmcli/metavuln-calculator/node_modules/cacache
!/@npmcli/name-from-folder
!/@npmcli/node-gyp
!/@npmcli/package-json
Expand Down Expand Up @@ -71,6 +74,9 @@
!/buffer
!/builtins
!/cacache
!/cacache/node_modules/
/cacache/node_modules/*
!/cacache/node_modules/lru-cache
!/chalk
!/chownr
!/ci-info
Expand Down Expand Up @@ -146,6 +152,9 @@
!/just-diff
!/lru-cache
!/make-fetch-happen
!/make-fetch-happen/node_modules/
/make-fetch-happen/node_modules/*
!/make-fetch-happen/node_modules/cacache
!/minimatch
!/minipass-collect
!/minipass-collect/node_modules/
Expand Down Expand Up @@ -183,6 +192,13 @@
!/node-gyp/node_modules/abbrev
!/node-gyp/node_modules/are-we-there-yet
!/node-gyp/node_modules/brace-expansion
!/node-gyp/node_modules/cacache
!/node-gyp/node_modules/cacache/node_modules/
/node-gyp/node_modules/cacache/node_modules/*
!/node-gyp/node_modules/cacache/node_modules/brace-expansion
!/node-gyp/node_modules/cacache/node_modules/glob
!/node-gyp/node_modules/cacache/node_modules/minimatch
!/node-gyp/node_modules/cacache/node_modules/minipass
!/node-gyp/node_modules/gauge
!/node-gyp/node_modules/glob
!/node-gyp/node_modules/make-fetch-happen
Expand Down Expand Up @@ -214,6 +230,7 @@
!/pacote/node_modules/@npmcli/
/pacote/node_modules/@npmcli/*
!/pacote/node_modules/@npmcli/git
!/pacote/node_modules/cacache
!/parse-conflict-json
!/path-is-absolute
!/path-key
Expand Down Expand Up @@ -255,6 +272,10 @@
!/sigstore
!/sigstore/node_modules/
/sigstore/node_modules/*
!/sigstore/node_modules/cacache
!/sigstore/node_modules/cacache/node_modules/
/sigstore/node_modules/cacache/node_modules/*
!/sigstore/node_modules/cacache/node_modules/minipass
!/sigstore/node_modules/make-fetch-happen
!/sigstore/node_modules/minipass
!/smart-buffer
Expand Down Expand Up @@ -285,6 +306,10 @@
!/tuf-js
!/tuf-js/node_modules/
/tuf-js/node_modules/*
!/tuf-js/node_modules/cacache
!/tuf-js/node_modules/cacache/node_modules/
/tuf-js/node_modules/cacache/node_modules/*
!/tuf-js/node_modules/cacache/node_modules/minipass
!/tuf-js/node_modules/make-fetch-happen
!/tuf-js/node_modules/minipass
!/unique-filename
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
ISC License

Copyright (c) npm, Inc.

Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE COPYRIGHT HOLDER DISCLAIMS
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
USE OR PERFORMANCE OF THIS SOFTWARE.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict'

const contentVer = require('../../package.json')['cache-version'].content
const hashToSegments = require('../util/hash-to-segments')
const path = require('path')
const ssri = require('ssri')

// Current format of content file path:
//
// sha512-BaSE64Hex= ->
// ~/.my-cache/content-v2/sha512/ba/da/55deadbeefc0ffee
//
module.exports = contentPath

function contentPath (cache, integrity) {
const sri = ssri.parse(integrity, { single: true })
// contentPath is the *strongest* algo given
return path.join(
contentDir(cache),
sri.algorithm,
...hashToSegments(sri.hexDigest())
)
}

module.exports.contentDir = contentDir

function contentDir (cache) {
return path.join(cache, `content-v${contentVer}`)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
'use strict'

const fs = require('fs/promises')
const fsm = require('fs-minipass')
const ssri = require('ssri')
const contentPath = require('./path')
const Pipeline = require('minipass-pipeline')

module.exports = read

const MAX_SINGLE_READ_SIZE = 64 * 1024 * 1024
async function read (cache, integrity, opts = {}) {
const { size } = opts
const { stat, cpath, sri } = await withContentSri(cache, integrity, async (cpath, sri) => {
// get size
const stat = await fs.stat(cpath)
return { stat, cpath, sri }
})
if (typeof size === 'number' && stat.size !== size) {
throw sizeError(size, stat.size)
}

if (stat.size > MAX_SINGLE_READ_SIZE) {
return readPipeline(cpath, stat.size, sri, new Pipeline()).concat()
}

const data = await fs.readFile(cpath, { encoding: null })
if (!ssri.checkData(data, sri)) {
throw integrityError(sri, cpath)
}

return data
}

const readPipeline = (cpath, size, sri, stream) => {
stream.push(
new fsm.ReadStream(cpath, {
size,
readSize: MAX_SINGLE_READ_SIZE,
}),
ssri.integrityStream({
integrity: sri,
size,
})
)
return stream
}

module.exports.stream = readStream
module.exports.readStream = readStream

function readStream (cache, integrity, opts = {}) {
const { size } = opts
const stream = new Pipeline()
// Set all this up to run on the stream and then just return the stream
Promise.resolve().then(async () => {
const { stat, cpath, sri } = await withContentSri(cache, integrity, async (cpath, sri) => {
// just stat to ensure it exists
const stat = await fs.stat(cpath)
return { stat, cpath, sri }
})
if (typeof size === 'number' && size !== stat.size) {
return stream.emit('error', sizeError(size, stat.size))
}

return readPipeline(cpath, stat.size, sri, stream)
}).catch(err => stream.emit('error', err))

return stream
}

module.exports.copy = copy

function copy (cache, integrity, dest) {
return withContentSri(cache, integrity, (cpath, sri) => {
return fs.copyFile(cpath, dest)
})
}

module.exports.hasContent = hasContent

async function hasContent (cache, integrity) {
if (!integrity) {
return false
}

try {
return await withContentSri(cache, integrity, async (cpath, sri) => {
const stat = await fs.stat(cpath)
return { size: stat.size, sri, stat }
})
} catch (err) {
if (err.code === 'ENOENT') {
return false
}

if (err.code === 'EPERM') {
/* istanbul ignore else */
if (process.platform !== 'win32') {
throw err
} else {
return false
}
}
}
}

async function withContentSri (cache, integrity, fn) {
const sri = ssri.parse(integrity)
// If `integrity` has multiple entries, pick the first digest
// with available local data.
const algo = sri.pickAlgorithm()
const digests = sri[algo]

if (digests.length <= 1) {
const cpath = contentPath(cache, digests[0])
return fn(cpath, digests[0])
} else {
// Can't use race here because a generic error can happen before
// a ENOENT error, and can happen before a valid result
const results = await Promise.all(digests.map(async (meta) => {
try {
return await withContentSri(cache, meta, fn)
} catch (err) {
if (err.code === 'ENOENT') {
return Object.assign(
new Error('No matching content found for ' + sri.toString()),
{ code: 'ENOENT' }
)
}
return err
}
}))
// Return the first non error if it is found
const result = results.find((r) => !(r instanceof Error))
if (result) {
return result
}

// Throw the No matching content found error
const enoentError = results.find((r) => r.code === 'ENOENT')
if (enoentError) {
throw enoentError
}

// Throw generic error
throw results.find((r) => r instanceof Error)
}
}

function sizeError (expected, found) {
/* eslint-disable-next-line max-len */
const err = new Error(`Bad data size: expected inserted data to be ${expected} bytes, but got ${found} instead`)
err.expected = expected
err.found = found
err.code = 'EBADSIZE'
return err
}

function integrityError (sri, path) {
const err = new Error(`Integrity verification failed for ${sri} (${path})`)
err.code = 'EINTEGRITY'
err.sri = sri
err.path = path
return err
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict'

const fs = require('fs/promises')
const contentPath = require('./path')
const { hasContent } = require('./read')

module.exports = rm

async function rm (cache, integrity) {
const content = await hasContent(cache, integrity)
// ~pretty~ sure we can't end up with a content lacking sri, but be safe
if (content && content.sri) {
await fs.rm(contentPath(cache, content.sri), { recursive: true, force: true })
return true
} else {
return false
}
}
Loading

0 comments on commit 7af81c7

Please sign in to comment.