diff --git a/node_modules/pacote/lib/fetcher.js b/node_modules/pacote/lib/fetcher.js index c9a3201f0ae4a..d488e88ff7236 100644 --- a/node_modules/pacote/lib/fetcher.js +++ b/node_modules/pacote/lib/fetcher.js @@ -40,6 +40,7 @@ const _istream = Symbol('_istream') const _assertType = Symbol('_assertType') const _tarballFromCache = Symbol('_tarballFromCache') const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved') +const _cacheFetches = Symbol.for('pacote.Fetcher._cacheFetches') class FetcherBase { constructor (spec, opts) { @@ -166,25 +167,19 @@ class FetcherBase { } // private, should be overridden. - // Note that they should *not* calculate or check integrity, but *just* - // return the raw tarball data stream. + // Note that they should *not* calculate or check integrity or cache, + // but *just* return the raw tarball data stream. [_tarballFromResolved] () { throw this.notImplementedError } // public, should not be overridden tarball () { - return this.tarballStream(stream => new Promise((res, rej) => { - const buf = [] - stream.on('error', er => rej(er)) - stream.on('end', () => { - const data = Buffer.concat(buf) - data.integrity = this.integrity && String(this.integrity) - data.resolved = this.resolved - data.from = this.from - return res(data) - }) - stream.on('data', d => buf.push(d)) + return this.tarballStream(stream => stream.concat().then(data => { + data.integrity = this.integrity && String(this.integrity) + data.resolved = this.resolved + data.from = this.from + return data })) } @@ -194,6 +189,10 @@ class FetcherBase { return cacache.get.stream.byDigest(this.cache, this.integrity, this.opts) } + get [_cacheFetches] () { + return true + } + [_istream] (stream) { // everyone will need one of these, either for verifying or calculating // We always set it, because we have might only have a weak legacy hex @@ -203,7 +202,31 @@ class FetcherBase { // gets to the point of re-setting the integrity. const istream = ssri.integrityStream(this.opts) istream.on('integrity', i => this.integrity = i) - return stream.on('error', er => istream.emit('error', er)).pipe(istream) + stream.on('error', er => istream.emit('error', er)) + + // if not caching this, just pipe through to the istream and return it + if (!this.opts.cache || !this[_cacheFetches]) + return stream.pipe(istream) + + // we have to return a stream that gets ALL the data, and proxies errors, + // but then pipe from the original tarball stream into the cache as well. + // To do this without losing any data, and since the cacache put stream + // is not a passthrough, we have to pipe from the original stream into + // the cache AFTER we pipe into the istream. Since the cache stream + // has an asynchronous flush to write its contents to disk, we need to + // defer the istream end until the cache stream ends. + stream.pipe(istream, { end: false }) + const cstream = cacache.put.stream( + this.opts.cache, + `pacote:tarball:${this.from}`, + this.opts + ) + stream.pipe(cstream) + // defer istream end until after cstream + // cache write errors should not crash the fetch, this is best-effort. + cstream.promise().catch(() => {}).then(() => istream.end()) + + return istream } pickIntegrityAlgorithm () { @@ -232,7 +255,9 @@ class FetcherBase { // An ENOENT trying to read a tgz file, for example, is Right Out. isRetriableError (er) { // TODO: check error class, once those are rolled out to our deps - return this.isDataCorruptionError(er) || er.code === 'ENOENT' + return this.isDataCorruptionError(er) || + er.code === 'ENOENT' || + er.code === 'EISDIR' } // Mostly internal, but has some uses diff --git a/node_modules/pacote/lib/remote.js b/node_modules/pacote/lib/remote.js index 91f6eb59daa6f..727a8bfc8e608 100644 --- a/node_modules/pacote/lib/remote.js +++ b/node_modules/pacote/lib/remote.js @@ -8,6 +8,7 @@ const Minipass = require('minipass') // The default registry URL is a string of great magic. const magic = /^https?:\/\/registry\.npmjs\.org\// +const _cacheFetches = Symbol.for('pacote.Fetcher._cacheFetches') const _headers = Symbol('_headers') class RemoteFetcher extends Fetcher { constructor (spec, opts) { @@ -21,6 +22,12 @@ class RemoteFetcher extends Fetcher { this.pkgid = opts.pkgid ? opts.pkgid : `remote:${nameat}${this.resolved}` } + // Don't need to cache tarball fetches in pacote, because make-fetch-happen + // will write into cacache anyway. + get [_cacheFetches] () { + return false + } + [_tarballFromResolved] () { const stream = new Minipass() const fetchOpts = { diff --git a/node_modules/pacote/node_modules/npm-registry-fetch/CHANGELOG.md b/node_modules/pacote/node_modules/npm-registry-fetch/CHANGELOG.md new file mode 100644 index 0000000000000..fc26ee1bda4ba --- /dev/null +++ b/node_modules/pacote/node_modules/npm-registry-fetch/CHANGELOG.md @@ -0,0 +1,384 @@ +# Changelog + +All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +### [8.1.5](https://github.com/npm/registry-fetch/compare/v8.1.4...v8.1.5) (2020-10-12) + + +### Bug Fixes + +* respect publishConfig.registry when specified ([32e36ef](https://github.com/npm/registry-fetch/commit/32e36efe86302ed319973cd5b1e6ccc3f62e557e)), closes [#35](https://github.com/npm/registry-fetch/issues/35) + +### [8.1.4](https://github.com/npm/registry-fetch/compare/v8.1.3...v8.1.4) (2020-08-17) + + +### Bug Fixes + +* redact passwords from http logs ([3c294eb](https://github.com/npm/registry-fetch/commit/3c294ebbd7821725db4ff1bc5fe368c49613efcc)) + +### [8.1.3](https://github.com/npm/registry-fetch/compare/v8.1.2...v8.1.3) (2020-07-21) + +### [8.1.2](https://github.com/npm/registry-fetch/compare/v8.1.1...v8.1.2) (2020-07-11) + +### [8.1.1](https://github.com/npm/registry-fetch/compare/v8.1.0...v8.1.1) (2020-06-30) + +## [8.1.0](https://github.com/npm/registry-fetch/compare/v8.0.3...v8.1.0) (2020-05-20) + + +### Features + +* add npm-command HTTP header ([1bb4eb2](https://github.com/npm/registry-fetch/commit/1bb4eb2c66ee8a0dc62558bdcff1b548e2bb9820)) + +### [8.0.3](https://github.com/npm/registry-fetch/compare/v8.0.2...v8.0.3) (2020-05-13) + + +### Bug Fixes + +* update minipass and make-fetch-happen to latest ([3b6c5d0](https://github.com/npm/registry-fetch/commit/3b6c5d0d8ccd4c4a97862a65acef956f19aec127)), closes [#23](https://github.com/npm/registry-fetch/issues/23) + +### [8.0.2](https://github.com/npm/registry-fetch/compare/v8.0.1...v8.0.2) (2020-05-04) + + +### Bug Fixes + +* update make-fetch-happen to 8.0.6 ([226df2c](https://github.com/npm/registry-fetch/commit/226df2c32e3f9ed8ceefcfdbd11efb178181b442)) + +## [8.0.0](https://github.com/npm/registry-fetch/compare/v7.0.1...v8.0.0) (2020-02-24) + + +### ⚠ BREAKING CHANGES + +* Removes the 'opts.refer' option and the HTTP Referer +header (unless explicitly added to the 'headers' option, of course). + +PR-URL: https://github.com/npm/npm-registry-fetch/pull/25 +Credit: @isaacs + +### Bug Fixes + +* remove referer header and opts.refer ([eb8f7af](https://github.com/npm/registry-fetch/commit/eb8f7af3c102834856604c1be664b00ca0fe8ef2)), closes [#25](https://github.com/npm/registry-fetch/issues/25) + +### [7.0.1](https://github.com/npm/registry-fetch/compare/v7.0.0...v7.0.1) (2020-02-24) + +## [7.0.0](https://github.com/npm/registry-fetch/compare/v6.0.2...v7.0.0) (2020-02-18) + + +### ⚠ BREAKING CHANGES + +* figgy pudding is now nowhere to be found. +* this removes figgy-pudding, and drops several option +aliases. + +Defaults and behavior are all the same, and this module is now using the +canonical camelCase option names that npm v7 will provide to all its +deps. + +Related to: https://github.com/npm/rfcs/pull/102 + +PR-URL: https://github.com/npm/npm-registry-fetch/pull/22 +Credit: @isaacs + +### Bug Fixes + +* Remove figgy-pudding, use canonical option names ([ede3c08](https://github.com/npm/registry-fetch/commit/ede3c087007fd1808e02b1af70562220d03b18a9)), closes [#22](https://github.com/npm/registry-fetch/issues/22) + + +* update cacache, ssri, make-fetch-happen ([57fcc88](https://github.com/npm/registry-fetch/commit/57fcc889bee03edcc0a2025d96a171039108c231)) + +### [6.0.2](https://github.com/npm/registry-fetch/compare/v6.0.1...v6.0.2) (2020-02-14) + + +### Bug Fixes + +* always bypass cache when ?write=true ([83f89f3](https://github.com/npm/registry-fetch/commit/83f89f35abd2ed0507c869e37f90ed746375772c)) + +### [6.0.1](https://github.com/npm/registry-fetch/compare/v6.0.0...v6.0.1) (2020-02-14) + + +### Bug Fixes + +* use 30s default for timeout as per README ([50e8afc](https://github.com/npm/registry-fetch/commit/50e8afc6ff850542feb588f9f9c64ebae59e72a0)), closes [#20](https://github.com/npm/registry-fetch/issues/20) + +## [6.0.0](https://github.com/npm/registry-fetch/compare/v5.0.1...v6.0.0) (2019-12-17) + + +### ⚠ BREAKING CHANGES + +* This drops support for node < 10. + +There are some lint failures due to standard pushing for using WhatWG URL +objects instead of url.parse/url.resolve. However, the code in this lib +does some fancy things with the query/search portions of the parsed url +object, so it'll take a bit of care to make it work properly. + +### Bug Fixes + +* detect CI so our tests don't fail in CI ([5813da6](https://github.com/npm/registry-fetch/commit/5813da634cef73b12e40373972d7937e6934fce0)) +* Use WhatWG URLs instead of url.parse ([8ccfa8a](https://github.com/npm/registry-fetch/commit/8ccfa8a72c38cfedb0f525b7f453644fd4444f99)) + + +* normalize settings, drop old nodes, update deps ([510b125](https://github.com/npm/registry-fetch/commit/510b1255cc7ed4bb397a34e0007757dae33e2275)) + + +## [5.0.1](https://github.com/npm/registry-fetch/compare/v5.0.0...v5.0.1) (2019-11-11) + + + + +# [5.0.0](https://github.com/npm/registry-fetch/compare/v4.0.2...v5.0.0) (2019-10-04) + + +### Bug Fixes + +* prefer const in getAuth function ([90ac7b1](https://github.com/npm/registry-fetch/commit/90ac7b1)) +* use minizlib instead of core zlib ([e64702e](https://github.com/npm/registry-fetch/commit/e64702e)) + + +### Features + +* refactor to use Minipass streams ([bb37f20](https://github.com/npm/registry-fetch/commit/bb37f20)) + + +### BREAKING CHANGES + +* this replaces all core streams (except for some +PassThrough streams in a few tests) with Minipass streams, and updates +all deps to the latest and greatest Minipass versions of things. + + + + +## [4.0.2](https://github.com/npm/registry-fetch/compare/v4.0.0...v4.0.2) (2019-10-04) + + +### Bug Fixes + +* Add null check on body on 401 errors ([e3a0186](https://github.com/npm/registry-fetch/commit/e3a0186)), closes [#9](https://github.com/npm/registry-fetch/issues/9) +* **deps:** Add explicit dependency on safe-buffer ([8eae5f0](https://github.com/npm/registry-fetch/commit/8eae5f0)), closes [npm/libnpmaccess#2](https://github.com/npm/libnpmaccess/issues/2) [#3](https://github.com/npm/registry-fetch/issues/3) + + + + +# [4.0.0](https://github.com/npm/registry-fetch/compare/v3.9.1...v4.0.0) (2019-07-15) + + +* cacache@12.0.0, infer uid from cache folder ([0c4f060](https://github.com/npm/registry-fetch/commit/0c4f060)) + + +### BREAKING CHANGES + +* uid and gid are inferred from cache folder, rather than +being passed in as options. + + + + +## [3.9.1](https://github.com/npm/registry-fetch/compare/v3.9.0...v3.9.1) (2019-07-02) + + + + +# [3.9.0](https://github.com/npm/registry-fetch/compare/v3.8.0...v3.9.0) (2019-01-24) + + +### Features + +* **auth:** support username:password encoded legacy _auth ([a91f90c](https://github.com/npm/registry-fetch/commit/a91f90c)) + + + + +# [3.8.0](https://github.com/npm/registry-fetch/compare/v3.7.0...v3.8.0) (2018-08-23) + + +### Features + +* **mapJson:** add support for passing in json stream mapper ([0600986](https://github.com/npm/registry-fetch/commit/0600986)) + + + + +# [3.7.0](https://github.com/npm/registry-fetch/compare/v3.6.0...v3.7.0) (2018-08-23) + + +### Features + +* **json.stream:** add utility function for streamed JSON parsing ([051d969](https://github.com/npm/registry-fetch/commit/051d969)) + + + + +# [3.6.0](https://github.com/npm/registry-fetch/compare/v3.5.0...v3.6.0) (2018-08-22) + + +### Bug Fixes + +* **docs:** document opts.forceAuth ([40bcd65](https://github.com/npm/registry-fetch/commit/40bcd65)) + + +### Features + +* **opts.ignoreBody:** add a boolean to throw away response bodies ([6923702](https://github.com/npm/registry-fetch/commit/6923702)) + + + + +# [3.5.0](https://github.com/npm/registry-fetch/compare/v3.4.0...v3.5.0) (2018-08-22) + + +### Features + +* **pkgid:** heuristic pkgid calculation for errors ([2e789a5](https://github.com/npm/registry-fetch/commit/2e789a5)) + + + + +# [3.4.0](https://github.com/npm/registry-fetch/compare/v3.3.0...v3.4.0) (2018-08-22) + + +### Bug Fixes + +* **deps:** use new figgy-pudding with aliases fix ([0308f54](https://github.com/npm/registry-fetch/commit/0308f54)) + + +### Features + +* **auth:** add forceAuth option to force a specific auth mechanism ([4524d17](https://github.com/npm/registry-fetch/commit/4524d17)) + + + + +# [3.3.0](https://github.com/npm/registry-fetch/compare/v3.2.1...v3.3.0) (2018-08-21) + + +### Bug Fixes + +* **query:** stop including undefined keys ([4718b1b](https://github.com/npm/registry-fetch/commit/4718b1b)) + + +### Features + +* **otp:** use heuristic detection for malformed EOTP responses ([f035194](https://github.com/npm/registry-fetch/commit/f035194)) + + + + +## [3.2.1](https://github.com/npm/registry-fetch/compare/v3.2.0...v3.2.1) (2018-08-16) + + +### Bug Fixes + +* **opts:** pass through non-null opts.retry ([beba040](https://github.com/npm/registry-fetch/commit/beba040)) + + + + +# [3.2.0](https://github.com/npm/registry-fetch/compare/v3.1.1...v3.2.0) (2018-07-27) + + +### Features + +* **gzip:** add opts.gzip convenience opt ([340abe0](https://github.com/npm/registry-fetch/commit/340abe0)) + + + + +## [3.1.1](https://github.com/npm/registry-fetch/compare/v3.1.0...v3.1.1) (2018-04-09) + + + + +# [3.1.0](https://github.com/npm/registry-fetch/compare/v3.0.0...v3.1.0) (2018-04-09) + + +### Features + +* **config:** support no-proxy and https-proxy options ([9aa906b](https://github.com/npm/registry-fetch/commit/9aa906b)) + + + + +# [3.0.0](https://github.com/npm/registry-fetch/compare/v2.1.0...v3.0.0) (2018-04-09) + + +### Bug Fixes + +* **api:** pacote integration-related fixes ([a29de4f](https://github.com/npm/registry-fetch/commit/a29de4f)) +* **config:** stop caring about opts.config ([5856a6f](https://github.com/npm/registry-fetch/commit/5856a6f)) + + +### BREAKING CHANGES + +* **config:** opts.config is no longer supported. Pass the options down in opts itself. + + + + +# [2.1.0](https://github.com/npm/registry-fetch/compare/v2.0.0...v2.1.0) (2018-04-08) + + +### Features + +* **token:** accept opts.token for opts._authToken ([108c9f0](https://github.com/npm/registry-fetch/commit/108c9f0)) + + + + +# [2.0.0](https://github.com/npm/registry-fetch/compare/v1.1.1...v2.0.0) (2018-04-08) + + +### meta + +* drop support for node@4 ([758536e](https://github.com/npm/registry-fetch/commit/758536e)) + + +### BREAKING CHANGES + +* node@4 is no longer supported + + + + +## [1.1.1](https://github.com/npm/registry-fetch/compare/v1.1.0...v1.1.1) (2018-04-06) + + + + +# [1.1.0](https://github.com/npm/registry-fetch/compare/v1.0.1...v1.1.0) (2018-03-16) + + +### Features + +* **specs:** can use opts.spec to trigger pickManifest ([85c4ac9](https://github.com/npm/registry-fetch/commit/85c4ac9)) + + + + +## [1.0.1](https://github.com/npm/registry-fetch/compare/v1.0.0...v1.0.1) (2018-03-16) + + +### Bug Fixes + +* **query:** oops console.log ([870e4f5](https://github.com/npm/registry-fetch/commit/870e4f5)) + + + + +# 1.0.0 (2018-03-16) + + +### Bug Fixes + +* **auth:** get auth working with all the little details ([84b94ba](https://github.com/npm/registry-fetch/commit/84b94ba)) +* **deps:** add bluebird as an actual dep ([1286e31](https://github.com/npm/registry-fetch/commit/1286e31)) +* **errors:** Unknown auth errors use default code ([#1](https://github.com/npm/registry-fetch/issues/1)) ([3d91b93](https://github.com/npm/registry-fetch/commit/3d91b93)) +* **standard:** remove args from invocation ([9620a0a](https://github.com/npm/registry-fetch/commit/9620a0a)) + + +### Features + +* **api:** baseline kinda-working API impl ([bf91f9f](https://github.com/npm/registry-fetch/commit/bf91f9f)) +* **body:** automatic handling of different opts.body values ([f3b97db](https://github.com/npm/registry-fetch/commit/f3b97db)) +* **config:** nicer input config input handling ([b9ce21d](https://github.com/npm/registry-fetch/commit/b9ce21d)) +* **opts:** use figgy-pudding for opts handling ([0abd527](https://github.com/npm/registry-fetch/commit/0abd527)) +* **query:** add query utility support ([65ea8b1](https://github.com/npm/registry-fetch/commit/65ea8b1)) diff --git a/node_modules/pacote/node_modules/npm-registry-fetch/LICENSE.md b/node_modules/pacote/node_modules/npm-registry-fetch/LICENSE.md new file mode 100644 index 0000000000000..8d28acf866d93 --- /dev/null +++ b/node_modules/pacote/node_modules/npm-registry-fetch/LICENSE.md @@ -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. diff --git a/node_modules/pacote/node_modules/npm-registry-fetch/README.md b/node_modules/pacote/node_modules/npm-registry-fetch/README.md new file mode 100644 index 0000000000000..5ce9770c604cf --- /dev/null +++ b/node_modules/pacote/node_modules/npm-registry-fetch/README.md @@ -0,0 +1,635 @@ +# npm-registry-fetch + +[`npm-registry-fetch`](https://github.com/npm/npm-registry-fetch) is a Node.js +library that implements a `fetch`-like API for accessing npm registry APIs +consistently. It's able to consume npm-style configuration values and has all +the necessary logic for picking registries, handling scopes, and dealing with +authentication details built-in. + +This package is meant to replace the older +[`npm-registry-client`](https://npm.im/npm-registry-client). + +## Example + +```javascript +const npmFetch = require('npm-registry-fetch') + +console.log( + await npmFetch.json('/-/ping') +) +``` + +## Table of Contents + +* [Installing](#install) +* [Example](#example) +* [Contributing](#contributing) +* [API](#api) + * [`fetch`](#fetch) + * [`fetch.json`](#fetch-json) + * [`fetch` options](#fetch-opts) + +### Install + +`$ npm install npm-registry-fetch` + +### Contributing + +The npm team enthusiastically welcomes contributions and project participation! +There's a bunch of things you can do if you want to contribute! The [Contributor +Guide](CONTRIBUTING.md) has all the information you need for everything from +reporting bugs to contributing entire new features. Please don't hesitate to +jump in if you'd like to, or even ask us questions if something isn't clear. + +All participants and maintainers in this project are expected to follow [Code of +Conduct](CODE_OF_CONDUCT.md), and just generally be excellent to each other. + +Please refer to the [Changelog](CHANGELOG.md) for project history details, too. + +Happy hacking! + +### API + +#### Caching and `write=true` query strings + +Before performing any PUT or DELETE operation, npm clients first make a +GET request to the registry resource being updated, which includes +the query string `?write=true`. + +The semantics of this are, effectively, "I intend to write to this thing, +and need to know the latest current value, so that my write can land +cleanly". + +The public npm registry handles these `?write=true` requests by ensuring +that the cache is re-validated before sending a response. In order to +maintain the same behavior on the client, and not get tripped up by an +overeager local cache when we intend to write data to the registry, any +request that comes through `npm-registry-fetch` that contains `write=true` +in the query string will forcibly set the `prefer-online` option to `true`, +and set both `prefer-offline` and `offline` to false, so that any local +cached value will be revalidated. + +#### `> fetch(url, [opts]) -> Promise` + +Performs a request to a given URL. + +The URL can be either a full URL, or a path to one. The appropriate registry +will be automatically picked if only a URL path is given. + +For available options, please see the section on [`fetch` options](#fetch-opts). + +##### Example + +```javascript +const res = await fetch('/-/ping') +console.log(res.headers) +res.on('data', d => console.log(d.toString('utf8'))) +``` + +#### `> fetch.json(url, [opts]) -> Promise` + +Performs a request to a given registry URL, parses the body of the response as +JSON, and returns it as its final value. This is a utility shorthand for +`fetch(url).then(res => res.json())`. + +For available options, please see the section on [`fetch` options](#fetch-opts). + +##### Example + +```javascript +const res = await fetch.json('/-/ping') +console.log(res) // Body parsed as JSON +``` + +#### `> fetch.json.stream(url, jsonPath, [opts]) -> Stream` + +Performs a request to a given registry URL and parses the body of the response +as JSON, with each entry being emitted through the stream. + +The `jsonPath` argument is a [`JSONStream.parse()` +path](https://github.com/dominictarr/JSONStream#jsonstreamparsepath), and the +returned stream (unlike default `JSONStream`s), has a valid +`Symbol.asyncIterator` implementation. + +For available options, please see the section on [`fetch` options](#fetch-opts). + +##### Example + +```javascript +console.log('https://npm.im/~zkat has access to the following packages:') +for await (let {key, value} of fetch.json.stream('/-/user/zkat/package', '$*')) { + console.log(`https://npm.im/${key} (perms: ${value})`) +} +``` + +#### `fetch` Options + +Fetch options are optional, and can be passed in as either a Map-like object +(one with a `.get()` method), a plain javascript object, or a +[`figgy-pudding`](https://npm.im/figgy-pudding) instance. + +##### `opts.agent` + +* Type: http.Agent +* Default: an appropriate agent based on URL protocol and proxy settings + +An [`Agent`](https://nodejs.org/api/http.html#http_class_http_agent) instance to +be shared across requests. This allows multiple concurrent `fetch` requests to +happen on the same socket. + +You do _not_ need to provide this option unless you want something particularly +specialized, since proxy configurations and http/https agents are already +automatically managed internally when this option is not passed through. + +##### `opts.body` + +* Type: Buffer | Stream | Object +* Default: null + +Request body to send through the outgoing request. Buffers and Streams will be +passed through as-is, with a default `content-type` of +`application/octet-stream`. Plain JavaScript objects will be `JSON.stringify`ed +and the `content-type` will default to `application/json`. + +Use [`opts.headers`](#opts-headers) to set the content-type to something else. + +##### `opts.ca` + +* Type: String, Array, or null +* Default: null + +The Certificate Authority signing certificate that is trusted for SSL +connections to the registry. Values should be in PEM format (Windows calls it +"Base-64 encoded X.509 (.CER)") with newlines replaced by the string `'\n'`. For +example: + +``` +{ + ca: '-----BEGIN CERTIFICATE-----\nXXXX\nXXXX\n-----END CERTIFICATE-----' +} +``` + +Set to `null` to only allow "known" registrars, or to a specific CA cert +to trust only that specific signing authority. + +Multiple CAs can be trusted by specifying an array of certificates instead of a +single string. + +See also [`opts.strictSSL`](#opts-strictSSL), [`opts.ca`](#opts-ca) and +[`opts.key`](#opts-key) + +##### `opts.cache` + +* Type: path +* Default: null + +The location of the http cache directory. If provided, certain cachable requests +will be cached according to [IETF RFC 7234](https://tools.ietf.org/html/rfc7234) +rules. This will speed up future requests, as well as make the cached data +available offline if necessary/requested. + +See also [`offline`](#opts-offline), [`preferOffline`](#opts-preferOffline), +and [`preferOnline`](#opts-preferOnline). + +##### `opts.cert` + +* Type: String +* Default: null + +A client certificate to pass when accessing the registry. Values should be in +PEM format (Windows calls it "Base-64 encoded X.509 (.CER)") with newlines +replaced by the string `'\n'`. For example: + +``` +{ + cert: '-----BEGIN CERTIFICATE-----\nXXXX\nXXXX\n-----END CERTIFICATE-----' +} +``` + +It is _not_ the path to a certificate file (and there is no "certfile" option). + +See also: [`opts.ca`](#opts-ca) and [`opts.key`](#opts-key) + +##### `opts.fetchRetries` + +* Type: Number +* Default: 2 + +The "retries" config for [`retry`](https://npm.im/retry) to use when fetching +packages from the registry. + +See also [`opts.retry`](#opts-retry) to provide all retry options as a single +object. + +##### `opts.fetchRetryFactor` + +* Type: Number +* Default: 10 + +The "factor" config for [`retry`](https://npm.im/retry) to use when fetching +packages. + +See also [`opts.retry`](#opts-retry) to provide all retry options as a single +object. + +##### `opts.fetchRetryMintimeout` + +* Type: Number +* Default: 10000 (10 seconds) + +The "minTimeout" config for [`retry`](https://npm.im/retry) to use when fetching +packages. + +See also [`opts.retry`](#opts-retry) to provide all retry options as a single +object. + +##### `opts.fetchRetryMaxtimeout` + +* Type: Number +* Default: 60000 (1 minute) + +The "maxTimeout" config for [`retry`](https://npm.im/retry) to use when fetching +packages. + +See also [`opts.retry`](#opts-retry) to provide all retry options as a single +object. + +##### `opts.forceAuth` + +* Type: Object +* Default: null + +If present, other auth-related values in `opts` will be completely ignored, +including `alwaysAuth`, `email`, and `otp`, when calculating auth for a request, +and the auth details in `opts.forceAuth` will be used instead. + +##### `opts.gzip` + +* Type: Boolean +* Default: false + +If true, `npm-registry-fetch` will set the `Content-Encoding` header to `gzip` +and use `zlib.gzip()` or `zlib.createGzip()` to gzip-encode +[`opts.body`](#opts-body). + +##### `opts.headers` + +* Type: Object +* Default: null + +Additional headers for the outgoing request. This option can also be used to +override headers automatically generated by `npm-registry-fetch`, such as +`Content-Type`. + +##### `opts.ignoreBody` + +* Type: Boolean +* Default: false + +If true, the **response body** will be thrown away and `res.body` set to `null`. +This will prevent dangling response sockets for requests where you don't usually +care what the response body is. + +##### `opts.integrity` + +* Type: String | [SRI object](https://npm.im/ssri) +* Default: null + +If provided, the response body's will be verified against this integrity string, +using [`ssri`](https://npm.im/ssri). If verification succeeds, the response will +complete as normal. If verification fails, the response body will error with an +`EINTEGRITY` error. + +Body integrity is only verified if the body is actually consumed to completion -- +that is, if you use `res.json()`/`res.buffer()`, or if you consume the default +`res` stream data to its end. + +Cached data will have its integrity automatically verified using the +previously-generated integrity hash for the saved request information, so +`EINTEGRITY` errors can happen if [`opts.cache`](#opts-cache) is used, even if +`opts.integrity` is not passed in. + +##### `opts.key` + +* Type: String +* Default: null + +A client key to pass when accessing the registry. Values should be in PEM +format with newlines replaced by the string `'\n'`. For example: + +``` +{ + key: '-----BEGIN PRIVATE KEY-----\nXXXX\nXXXX\n-----END PRIVATE KEY-----' +} +``` + +It is _not_ the path to a key file (and there is no "keyfile" option). + +See also: [`opts.ca`](#opts-ca) and [`opts.cert`](#opts-cert) + +##### `opts.localAddress` + +* Type: IP Address String +* Default: null + +The IP address of the local interface to use when making connections +to the registry. + +See also [`opts.proxy`](#opts-proxy) + +##### `opts.log` + +* Type: [`npmlog`](https://npm.im/npmlog)-like +* Default: null + +Logger object to use for logging operation details. Must have the same methods +as `npmlog`. + +##### `opts.mapJSON` + +* Type: Function +* Default: undefined + +When using `fetch.json.stream()` (NOT `fetch.json()`), this will be passed down +to [`JSONStream`](https://npm.im/JSONStream) as the second argument to +`JSONStream.parse`, and can be used to transform stream data before output. + +##### `opts.maxSockets` + +* Type: Integer +* Default: 12 + +Maximum number of sockets to keep open during requests. Has no effect if +[`opts.agent`](#opts-agent) is used. + +##### `opts.method` + +* Type: String +* Default: 'GET' + +HTTP method to use for the outgoing request. Case-insensitive. + +##### `opts.noproxy` + +* Type: Boolean +* Default: process.env.NOPROXY + +If true, proxying will be disabled even if [`opts.proxy`](#opts-proxy) is used. + +##### `opts.npmSession` + +* Type: String +* Default: null + +If provided, will be sent in the `npm-session` header. This header is used by +the npm registry to identify individual user sessions (usually individual +invocations of the CLI). + +##### `opts.npmCommand` + +* Type: String +* Default: null + +If provided, it will be sent in the `npm-command` header. This yeader is +used by the npm registry to identify the npm command that caused this +request to be made. + +##### `opts.offline` + +* Type: Boolean +* Default: false + +Force offline mode: no network requests will be done during install. To allow +`npm-registry-fetch` to fill in missing cache data, see +[`opts.preferOffline`](#opts-preferOffline). + +This option is only really useful if you're also using +[`opts.cache`](#opts-cache). + +This option is set to `true` when the request includes `write=true` in the +query string. + +##### `opts.otp` + +* Type: Number | String +* Default: null + +This is a one-time password from a two-factor authenticator. It is required for +certain registry interactions when two-factor auth is enabled for a user +account. + +##### `opts.otpPrompt` + +* Type: Function +* Default: null + +This is a method which will be called to provide an OTP if the server +responds with a 401 response indicating that a one-time-password is +required. + +It may return a promise, which must resolve to the OTP value to be used. +If the method fails to provide an OTP value, then the fetch will fail with +the auth error that indicated an OTP was needed. + +##### `opts.password` + +* Alias: `_password` +* Type: String +* Default: null + +Password used for basic authentication. For the more modern authentication +method, please use the (more secure) [`opts.token`](#opts-token) + +Can optionally be scoped to a registry by using a "nerf dart" for that registry. +That is: + +``` +{ + '//registry.npmjs.org/:password': 't0k3nH34r' +} +``` + +See also [`opts.username`](#opts-username) + +##### `opts.preferOffline` + +* Type: Boolean +* Default: false + +If true, staleness checks for cached data will be bypassed, but missing data +will be requested from the server. To force full offline mode, use +[`opts.offline`](#opts-offline). + +This option is generally only useful if you're also using +[`opts.cache`](#opts-cache). + +This option is set to `false` when the request includes `write=true` in the +query string. + +##### `opts.preferOnline` + +* Type: Boolean +* Default: false + +If true, staleness checks for cached data will be forced, making the CLI look +for updates immediately even for fresh package data. + +This option is generally only useful if you're also using +[`opts.cache`](#opts-cache). + +This option is set to `true` when the request includes `write=true` in the +query string. + +##### `opts.projectScope` + +* Type: String +* Default: null + +If provided, will be sent in the `npm-scope` header. This header is used by the +npm registry to identify the toplevel package scope that a particular project +installation is using. + +##### `opts.proxy` + +* Type: url +* Default: null + +A proxy to use for outgoing http requests. If not passed in, the `HTTP(S)_PROXY` +environment variable will be used. + +##### `opts.query` + +* Type: String | Object +* Default: null + +If provided, the request URI will have a query string appended to it using this +query. If `opts.query` is an object, it will be converted to a query string +using +[`querystring.stringify()`](https://nodejs.org/api/querystring.html#querystring_querystring_stringify_obj_sep_eq_options). + +If the request URI already has a query string, it will be merged with +`opts.query`, preferring `opts.query` values. + +##### `opts.registry` + +* Type: URL +* Default: `'https://registry.npmjs.org'` + +Registry configuration for a request. If a request URL only includes the URL +path, this registry setting will be prepended. This configuration is also used +to determine authentication details, so even if the request URL references a +completely different host, `opts.registry` will be used to find the auth details +for that request. + +See also [`opts.scope`](#opts-scope), [`opts.spec`](#opts-spec), and +[`opts.:registry`](#opts-scope-registry) which can all affect the actual +registry URL used by the outgoing request. + +##### `opts.retry` + +* Type: Object +* Default: null + +Single-object configuration for request retry settings. If passed in, will +override individually-passed `fetch-retry-*` settings. + +##### `opts.scope` + +* Type: String +* Default: null + +Associate an operation with a scope for a scoped registry. This option can force +lookup of scope-specific registries and authentication. + +See also [`opts.:registry`](#opts-scope-registry) and +[`opts.spec`](#opts-spec) for interactions with this option. + +##### `opts.:registry` + +* Type: String +* Default: null + +This option type can be used to configure the registry used for requests +involving a particular scope. For example, `opts['@myscope:registry'] = +'https://scope-specific.registry/'` will make it so requests go out to this +registry instead of [`opts.registry`](#opts-registry) when +[`opts.scope`](#opts-scope) is used, or when [`opts.spec`](#opts-spec) is a +scoped package spec. + +The `@` before the scope name is optional, but recommended. + +##### `opts.spec` + +* Type: String | [`npm-registry-arg`](https://npm.im/npm-registry-arg) object. +* Default: null + +If provided, can be used to automatically configure [`opts.scope`](#opts-scope) +based on a specific package name. Non-registry package specs will throw an +error. + +##### `opts.strictSSL` + +* Type: Boolean +* Default: true + +Whether or not to do SSL key validation when making requests to the +registry via https. + +See also [`opts.ca`](#opts-ca). + +##### `opts.timeout` + +* Type: Milliseconds +* Default: 300000 (5 minutes) + +Time before a hanging request times out. + +##### `opts.token` + +* Alias: `opts._authToken` +* Type: String +* Default: null + +Authentication token string. + +Can be scoped to a registry by using a "nerf dart" for that registry. That is: + +``` +{ + '//registry.npmjs.org/:token': 't0k3nH34r' +} +``` + +##### `opts.userAgent` + +* Type: String +* Default: `'npm-registry-fetch@/node@+ ()'` + +User agent string to send in the `User-Agent` header. + +##### `opts.username` + +* Type: String +* Default: null + +Username used for basic authentication. For the more modern authentication +method, please use the (more secure) [`opts.token`](#opts-token) + +Can optionally be scoped to a registry by using a "nerf dart" for that registry. +That is: + +``` +{ + '//registry.npmjs.org/:username': 't0k3nH34r' +} +``` + +See also [`opts.password`](#opts-password) + +##### `opts._auth` + +* Type: String +* Default: null + +** DEPRECATED ** This is a legacy authentication token supported only for +compatibility. Please use [`opts.token`](#opts-token) instead. diff --git a/node_modules/pacote/node_modules/npm-registry-fetch/auth.js b/node_modules/pacote/node_modules/npm-registry-fetch/auth.js new file mode 100644 index 0000000000000..cf76fdb6beb4d --- /dev/null +++ b/node_modules/pacote/node_modules/npm-registry-fetch/auth.js @@ -0,0 +1,94 @@ +'use strict' +const npa = require('npm-package-arg') + +// Find the longest registry key that is used for some kind of auth +// in the options. +const regKeyFromURI = (uri, opts) => { + const parsed = new URL(uri) + // try to find a config key indicating we have auth for this registry + // can be one of :_authToken, :_auth, or :_password and :username + // We walk up the "path" until we're left with just //[:], + // stopping when we reach '//'. + let regKey = `//${parsed.host}${parsed.pathname}` + while (regKey.length > '//'.length) { + // got some auth for this URI + if (hasAuth(regKey, opts)) + return regKey + + // can be either //host/some/path/:_auth or //host/some/path:_auth + // walk up by removing EITHER what's after the slash OR the slash itself + regKey = regKey.replace(/([^/]+|\/)$/, '') + } +} + +const hasAuth = (regKey, opts) => ( + opts[`${regKey}:_authToken`] || + opts[`${regKey}:_auth`] || + opts[`${regKey}:username`] && opts[`${regKey}:_password`] +) + +const getAuth = (uri, opts = {}) => { + const { forceAuth } = opts + if (!uri) + throw new Error('URI is required') + const regKey = regKeyFromURI(uri, forceAuth || opts) + + // we are only allowed to use what's in forceAuth if specified + if (forceAuth && !regKey) { + return new Auth({ + scopeAuthKey: null, + token: forceAuth._authToken, + username: forceAuth.username, + password: forceAuth._password || forceAuth.password, + auth: forceAuth._auth || forceAuth.auth, + }) + } + + // no auth for this URI + if (!regKey && opts.spec) { + // If making a tarball request to a different base URI than the + // registry where we logged in, but the same auth SHOULD be sent + // to that artifact host, then we track where it was coming in from, + // and warn the user if we get a 4xx error on it. + const { spec } = opts + const { scope: specScope, subSpec } = npa(spec) + const subSpecScope = subSpec && subSpec.scope + const scope = subSpec ? subSpecScope : specScope + const scopeReg = scope && opts[`${scope}:registry`] + const scopeAuthKey = scopeReg && regKeyFromURI(scopeReg, opts) + return new Auth({ scopeAuthKey }) + } + + const { + [`${regKey}:_authToken`]: token, + [`${regKey}:username`]: username, + [`${regKey}:_password`]: password, + [`${regKey}:_auth`]: auth, + } = opts + + return new Auth({ + scopeAuthKey: null, + token, + auth, + username, + password, + }) +} + +class Auth { + constructor ({ token, auth, username, password, scopeAuthKey }) { + this.scopeAuthKey = scopeAuthKey + this.token = null + this.auth = null + if (token) + this.token = token + else if (auth) + this.auth = auth + else if (username && password) { + const p = Buffer.from(password, 'base64').toString('utf8') + this.auth = Buffer.from(`${username}:${p}`, 'utf8').toString('base64') + } + } +} + +module.exports = getAuth diff --git a/node_modules/pacote/node_modules/npm-registry-fetch/check-response.js b/node_modules/pacote/node_modules/npm-registry-fetch/check-response.js new file mode 100644 index 0000000000000..7610e0d7a7ad2 --- /dev/null +++ b/node_modules/pacote/node_modules/npm-registry-fetch/check-response.js @@ -0,0 +1,139 @@ +'use strict' + +const errors = require('./errors.js') +const LRU = require('lru-cache') +const { Response } = require('minipass-fetch') +const defaultOpts = require('./default-opts.js') + +const checkResponse = async ({ method, uri, res, registry, startTime, auth, opts }) => { + opts = { ...defaultOpts, ...opts } + if (res.headers.has('npm-notice') && !res.headers.has('x-local-cache')) + opts.log.notice('', res.headers.get('npm-notice')) + + checkWarnings(res, registry, opts) + if (res.status >= 400) { + logRequest(method, res, startTime, opts) + if (auth && auth.scopeAuthKey && !auth.token && !auth.auth) { + // we didn't have auth for THIS request, but we do have auth for + // requests to the registry indicated by the spec's scope value. + // Warn the user. + opts.log.warn('registry', `No auth for URI, but auth present for scoped registry. + +URI: ${uri} +Scoped Registry Key: ${auth.scopeAuthKey} + +More info here: https://github.com/npm/cli/wiki/No-auth-for-URI,-but-auth-present-for-scoped-registry`) + } + return checkErrors(method, res, startTime, opts) + } else { + res.body.on('end', () => logRequest(method, res, startTime, opts)) + if (opts.ignoreBody) { + res.body.resume() + return new Response(null, res) + } + return res + } +} +module.exports = checkResponse + +function logRequest (method, res, startTime, opts) { + const elapsedTime = Date.now() - startTime + const attempt = res.headers.get('x-fetch-attempts') + const attemptStr = attempt && attempt > 1 ? ` attempt #${attempt}` : '' + const cacheStr = res.headers.get('x-local-cache') ? ' (from cache)' : '' + + let urlStr + try { + const { URL } = require('url') + const url = new URL(res.url) + if (url.password) + url.password = '***' + + urlStr = url.toString() + } catch (er) { + urlStr = res.url + } + + opts.log.http( + 'fetch', + `${method.toUpperCase()} ${res.status} ${urlStr} ${elapsedTime}ms${attemptStr}${cacheStr}` + ) +} + +const WARNING_REGEXP = /^\s*(\d{3})\s+(\S+)\s+"(.*)"\s+"([^"]+)"/ +const BAD_HOSTS = new LRU({ max: 50 }) + +function checkWarnings (res, registry, opts) { + if (res.headers.has('warning') && !BAD_HOSTS.has(registry)) { + const warnings = {} + // note: headers.raw() will preserve case, so we might have a + // key on the object like 'WaRnInG' if that was used first + for (const [key, value] of Object.entries(res.headers.raw())) { + if (key.toLowerCase() !== 'warning') + continue + value.forEach(w => { + const match = w.match(WARNING_REGEXP) + if (match) { + warnings[match[1]] = { + code: match[1], + host: match[2], + message: match[3], + date: new Date(match[4]), + } + } + }) + } + BAD_HOSTS.set(registry, true) + if (warnings['199']) { + if (warnings['199'].message.match(/ENOTFOUND/)) + opts.log.warn('registry', `Using stale data from ${registry} because the host is inaccessible -- are you offline?`) + else + opts.log.warn('registry', `Unexpected warning for ${registry}: ${warnings['199'].message}`) + } + if (warnings['111']) { + // 111 Revalidation failed -- we're using stale data + opts.log.warn( + 'registry', + `Using stale data from ${registry} due to a request error during revalidation.` + ) + } + } +} + +function checkErrors (method, res, startTime, opts) { + return res.buffer() + .catch(() => null) + .then(body => { + let parsed = body + try { + parsed = JSON.parse(body.toString('utf8')) + } catch (e) {} + if (res.status === 401 && res.headers.get('www-authenticate')) { + const auth = res.headers.get('www-authenticate') + .split(/,\s*/) + .map(s => s.toLowerCase()) + if (auth.indexOf('ipaddress') !== -1) { + throw new errors.HttpErrorAuthIPAddress( + method, res, parsed, opts.spec + ) + } else if (auth.indexOf('otp') !== -1) { + throw new errors.HttpErrorAuthOTP( + method, res, parsed, opts.spec + ) + } else { + throw new errors.HttpErrorAuthUnknown( + method, res, parsed, opts.spec + ) + } + } else if (res.status === 401 && body != null && /one-time pass/.test(body.toString('utf8'))) { + // Heuristic for malformed OTP responses that don't include the www-authenticate header. + throw new errors.HttpErrorAuthOTP( + method, res, parsed, opts.spec + ) + } else { + throw new errors.HttpErrorGeneral( + method, res, parsed, opts.spec + ) + } + }) +} diff --git a/node_modules/pacote/node_modules/npm-registry-fetch/default-opts.js b/node_modules/pacote/node_modules/npm-registry-fetch/default-opts.js new file mode 100644 index 0000000000000..9ca3f97d0352e --- /dev/null +++ b/node_modules/pacote/node_modules/npm-registry-fetch/default-opts.js @@ -0,0 +1,20 @@ +const pkg = require('./package.json') +module.exports = { + log: require('./silentlog.js'), + maxSockets: 12, + method: 'GET', + registry: 'https://registry.npmjs.org/', + timeout: 5 * 60 * 1000, // 5 minutes + strictSSL: true, + noProxy: process.env.NOPROXY, + userAgent: `${pkg.name + }@${ + pkg.version + }/node@${ + process.version + }+${ + process.arch + } (${ + process.platform + })`, +} diff --git a/node_modules/pacote/node_modules/npm-registry-fetch/errors.js b/node_modules/pacote/node_modules/npm-registry-fetch/errors.js new file mode 100644 index 0000000000000..e65e5fbd80dda --- /dev/null +++ b/node_modules/pacote/node_modules/npm-registry-fetch/errors.js @@ -0,0 +1,79 @@ +'use strict' + +const url = require('url') + +function packageName (href) { + try { + let basePath = new url.URL(href).pathname.substr(1) + if (!basePath.match(/^-/)) { + basePath = basePath.split('/') + var index = basePath.indexOf('_rewrite') + if (index === -1) + index = basePath.length - 1 + else + index++ + return decodeURIComponent(basePath[index]) + } + } catch (_) { + // this is ok + } +} + +class HttpErrorBase extends Error { + constructor (method, res, body, spec) { + super() + this.name = this.constructor.name + this.headers = res.headers.raw() + this.statusCode = res.status + this.code = `E${res.status}` + this.method = method + this.uri = res.url + this.body = body + this.pkgid = spec ? spec.toString() : packageName(res.url) + } +} +module.exports.HttpErrorBase = HttpErrorBase + +class HttpErrorGeneral extends HttpErrorBase { + constructor (method, res, body, spec) { + super(method, res, body, spec) + this.message = `${res.status} ${res.statusText} - ${ + this.method.toUpperCase() + } ${ + this.spec || this.uri + }${ + (body && body.error) ? ' - ' + body.error : '' + }` + Error.captureStackTrace(this, HttpErrorGeneral) + } +} +module.exports.HttpErrorGeneral = HttpErrorGeneral + +class HttpErrorAuthOTP extends HttpErrorBase { + constructor (method, res, body, spec) { + super(method, res, body, spec) + this.message = 'OTP required for authentication' + this.code = 'EOTP' + Error.captureStackTrace(this, HttpErrorAuthOTP) + } +} +module.exports.HttpErrorAuthOTP = HttpErrorAuthOTP + +class HttpErrorAuthIPAddress extends HttpErrorBase { + constructor (method, res, body, spec) { + super(method, res, body, spec) + this.message = 'Login is not allowed from your IP address' + this.code = 'EAUTHIP' + Error.captureStackTrace(this, HttpErrorAuthIPAddress) + } +} +module.exports.HttpErrorAuthIPAddress = HttpErrorAuthIPAddress + +class HttpErrorAuthUnknown extends HttpErrorBase { + constructor (method, res, body, spec) { + super(method, res, body, spec) + this.message = 'Unable to authenticate, need: ' + res.headers.get('www-authenticate') + Error.captureStackTrace(this, HttpErrorAuthUnknown) + } +} +module.exports.HttpErrorAuthUnknown = HttpErrorAuthUnknown diff --git a/node_modules/pacote/node_modules/npm-registry-fetch/index.js b/node_modules/pacote/node_modules/npm-registry-fetch/index.js new file mode 100644 index 0000000000000..5411b51e58abc --- /dev/null +++ b/node_modules/pacote/node_modules/npm-registry-fetch/index.js @@ -0,0 +1,221 @@ +'use strict' + +const { HttpErrorAuthOTP } = require('./errors.js') +const checkResponse = require('./check-response.js') +const getAuth = require('./auth.js') +const fetch = require('make-fetch-happen') +const JSONStream = require('minipass-json-stream') +const npa = require('npm-package-arg') +const qs = require('querystring') +const url = require('url') +const zlib = require('minizlib') +const Minipass = require('minipass') + +const defaultOpts = require('./default-opts.js') + +// WhatWG URL throws if it's not fully resolved +const urlIsValid = u => { + try { + return !!new url.URL(u) + } catch (_) { + return false + } +} + +module.exports = regFetch +function regFetch (uri, /* istanbul ignore next */ opts_ = {}) { + const opts = { + ...defaultOpts, + ...opts_, + } + + // if we did not get a fully qualified URI, then we look at the registry + // config or relevant scope to resolve it. + const uriValid = urlIsValid(uri) + let registry = opts.registry || defaultOpts.registry + if (!uriValid) { + registry = opts.registry = ( + (opts.spec && pickRegistry(opts.spec, opts)) || + opts.registry || + registry + ) + uri = `${ + registry.trim().replace(/\/?$/g, '') + }/${ + uri.trim().replace(/^\//, '') + }` + // asserts that this is now valid + new url.URL(uri) + } + + const method = opts.method || 'GET' + + // through that takes into account the scope, the prefix of `uri`, etc + const startTime = Date.now() + const auth = getAuth(uri, opts) + const headers = getHeaders(uri, auth, opts) + let body = opts.body + const bodyIsStream = Minipass.isStream(body) + const bodyIsPromise = body && + typeof body === 'object' && + typeof body.then === 'function' + + if (body && !bodyIsStream && !bodyIsPromise && typeof body !== 'string' && !Buffer.isBuffer(body)) { + headers['content-type'] = headers['content-type'] || 'application/json' + body = JSON.stringify(body) + } else if (body && !headers['content-type']) + headers['content-type'] = 'application/octet-stream' + + if (opts.gzip) { + headers['content-encoding'] = 'gzip' + if (bodyIsStream) { + const gz = new zlib.Gzip() + body.on('error', /* istanbul ignore next: unlikely and hard to test */ + err => gz.emit('error', err)) + body = body.pipe(gz) + } else if (!bodyIsPromise) + body = new zlib.Gzip().end(body).concat() + } + + const parsed = new url.URL(uri) + + if (opts.query) { + const q = typeof opts.query === 'string' ? qs.parse(opts.query) + : opts.query + + Object.keys(q).forEach(key => { + if (q[key] !== undefined) + parsed.searchParams.set(key, q[key]) + }) + uri = url.format(parsed) + } + + if (parsed.searchParams.get('write') === 'true' && method === 'GET') { + // do not cache, because this GET is fetching a rev that will be + // used for a subsequent PUT or DELETE, so we need to conditionally + // update cache. + opts.offline = false + opts.preferOffline = false + opts.preferOnline = true + } + + const doFetch = async body => { + const p = fetch(uri, { + agent: opts.agent, + algorithms: opts.algorithms, + body, + cache: getCacheMode(opts), + cacheManager: opts.cache, + ca: opts.ca, + cert: opts.cert, + headers, + integrity: opts.integrity, + key: opts.key, + localAddress: opts.localAddress, + maxSockets: opts.maxSockets, + memoize: opts.memoize, + method: method, + noProxy: opts.noProxy, + proxy: opts.httpsProxy || opts.proxy, + retry: opts.retry ? opts.retry : { + retries: opts.fetchRetries, + factor: opts.fetchRetryFactor, + minTimeout: opts.fetchRetryMintimeout, + maxTimeout: opts.fetchRetryMaxtimeout, + }, + strictSSL: opts.strictSSL, + timeout: opts.timeout || 30 * 1000, + }).then(res => checkResponse({ + method, + uri, + res, + registry, + startTime, + auth, + opts, + })) + + if (typeof opts.otpPrompt === 'function') { + return p.catch(async er => { + if (er instanceof HttpErrorAuthOTP) { + // if otp fails to complete, we fail with that failure + const otp = await opts.otpPrompt() + // if no otp provided, throw the original HTTP error + if (!otp) + throw er + return regFetch(uri, { ...opts, otp }) + } + throw er + }) + } else + return p + } + + return Promise.resolve(body).then(doFetch) +} + +module.exports.json = fetchJSON +function fetchJSON (uri, opts) { + return regFetch(uri, opts).then(res => res.json()) +} + +module.exports.json.stream = fetchJSONStream +function fetchJSONStream (uri, jsonPath, /* istanbul ignore next */ opts_ = {}) { + const opts = { ...defaultOpts, ...opts_ } + const parser = JSONStream.parse(jsonPath, opts.mapJSON) + regFetch(uri, opts).then(res => + res.body.on('error', + /* istanbul ignore next: unlikely and difficult to test */ + er => parser.emit('error', er)).pipe(parser) + ).catch(er => parser.emit('error', er)) + return parser +} + +module.exports.pickRegistry = pickRegistry +function pickRegistry (spec, opts = {}) { + spec = npa(spec) + let registry = spec.scope && + opts[spec.scope.replace(/^@?/, '@') + ':registry'] + + if (!registry && opts.scope) + registry = opts[opts.scope.replace(/^@?/, '@') + ':registry'] + + if (!registry) + registry = opts.registry || defaultOpts.registry + + return registry +} + +function getCacheMode (opts) { + return opts.offline ? 'only-if-cached' + : opts.preferOffline ? 'force-cache' + : opts.preferOnline ? 'no-cache' + : 'default' +} + +function getHeaders (uri, auth, opts) { + const headers = Object.assign({ + 'user-agent': opts.userAgent, + }, opts.headers || {}) + + if (opts.projectScope) + headers['npm-scope'] = opts.projectScope + + if (opts.npmSession) + headers['npm-session'] = opts.npmSession + + if (opts.npmCommand) + headers['npm-command'] = opts.npmCommand + + // If a tarball is hosted on a different place than the manifest, only send + // credentials on `alwaysAuth` + if (auth.token) + headers.authorization = `Bearer ${auth.token}` + else if (auth.auth) + headers.authorization = `Basic ${auth.auth}` + + if (opts.otp) + headers['npm-otp'] = opts.otp + + return headers +} diff --git a/node_modules/pacote/node_modules/npm-registry-fetch/package.json b/node_modules/pacote/node_modules/npm-registry-fetch/package.json new file mode 100644 index 0000000000000..614d664c463cc --- /dev/null +++ b/node_modules/pacote/node_modules/npm-registry-fetch/package.json @@ -0,0 +1,62 @@ +{ + "name": "npm-registry-fetch", + "version": "10.0.0", + "description": "Fetch-based http client for use with npm registry APIs", + "main": "index.js", + "files": [ + "*.js" + ], + "scripts": { + "eslint": "eslint", + "lint": "npm run eslint -- *.js test/*.js", + "lintfix": "npm run lint -- --fix", + "prepublishOnly": "git push origin --follow-tags", + "preversion": "npm test", + "postversion": "npm publish", + "test": "tap", + "posttest": "npm run lint" + }, + "repository": "https://github.com/npm/npm-registry-fetch", + "keywords": [ + "npm", + "registry", + "fetch" + ], + "author": { + "name": "Kat Marchán", + "email": "kzm@sykosomatic.org", + "twitter": "maybekatz" + }, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0", + "make-fetch-happen": "^8.0.9", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + }, + "devDependencies": { + "cacache": "^15.0.0", + "eslint": "^6.8.0", + "eslint-plugin-import": "^2.18.2", + "eslint-plugin-node": "^10.0.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.1", + "mkdirp": "^0.5.1", + "nock": "^11.7.0", + "npmlog": "^4.1.2", + "require-inject": "^1.4.4", + "rimraf": "^2.6.2", + "ssri": "^8.0.0", + "tap": "^14.10.7" + }, + "tap": { + "check-coverage": true, + "test-ignore": "test[\\\\/](util|cache)[\\\\/]" + }, + "engines": { + "node": ">=10" + } +} diff --git a/node_modules/pacote/node_modules/npm-registry-fetch/silentlog.js b/node_modules/pacote/node_modules/npm-registry-fetch/silentlog.js new file mode 100644 index 0000000000000..483bd44c7086a --- /dev/null +++ b/node_modules/pacote/node_modules/npm-registry-fetch/silentlog.js @@ -0,0 +1,14 @@ +'use strict' + +const noop = Function.prototype +module.exports = { + error: noop, + warn: noop, + notice: noop, + info: noop, + verbose: noop, + silly: noop, + http: noop, + pause: noop, + resume: noop, +} diff --git a/node_modules/pacote/package.json b/node_modules/pacote/package.json index dd6bf9400c6ea..aee117b016e46 100644 --- a/node_modules/pacote/package.json +++ b/node_modules/pacote/package.json @@ -1,6 +1,6 @@ { "name": "pacote", - "version": "11.3.1", + "version": "11.3.2", "description": "JavaScript package downloader", "author": "Isaac Z. Schlueter (https://izs.me)", "bin": { @@ -17,15 +17,12 @@ }, "tap": { "timeout": 300, - "check-coverage": true, - "coverage-map": "map.js", - "esm": false + "coverage-map": "map.js" }, "devDependencies": { "mutate-fs": "^2.1.1", "npm-registry-mock": "^1.3.1", - "require-inject": "^1.4.4", - "tap": "^14.11.0" + "tap": "^15.0.4" }, "files": [ "lib/**/*.js" @@ -49,7 +46,7 @@ "npm-package-arg": "^8.0.1", "npm-packlist": "^2.1.4", "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^9.0.0", + "npm-registry-fetch": "^10.0.0", "promise-retry": "^2.0.1", "read-package-json-fast": "^2.0.1", "rimraf": "^3.0.2", diff --git a/package-lock.json b/package-lock.json index 704fd1571d0a0..af537c677cc22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -303,7 +303,7 @@ "npm-user-validate": "^1.0.1", "npmlog": "~4.1.2", "opener": "^1.5.2", - "pacote": "^11.3.1", + "pacote": "^11.3.2", "parse-conflict-json": "^1.1.1", "qrcode-terminal": "^0.12.0", "read": "~1.0.7", @@ -6037,9 +6037,9 @@ } }, "node_modules/pacote": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.1.tgz", - "integrity": "sha512-TymtwoAG12cczsJIrwI/euOQKtjrQHlD0k0oyt9QSmZGpqa+KdlxKdWR/YUjYizkixaVyztxt/Wsfo8bL3A6Fg==", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.2.tgz", + "integrity": "sha512-lMO7V9aMhyE5gfaSFxKfW3OTdXuFBNQJfuNuet3NPzWWhOYIW90t85vHcHLDjdhgmfAdAHyh9q1HAap96ea0XA==", "inBundle": true, "dependencies": { "@npmcli/git": "^2.0.1", @@ -6055,7 +6055,7 @@ "npm-package-arg": "^8.0.1", "npm-packlist": "^2.1.4", "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^9.0.0", + "npm-registry-fetch": "^10.0.0", "promise-retry": "^2.0.1", "read-package-json-fast": "^2.0.1", "rimraf": "^3.0.2", @@ -6069,6 +6069,24 @@ "node": ">=10" } }, + "node_modules/pacote/node_modules/npm-registry-fetch": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-10.0.0.tgz", + "integrity": "sha512-/uLlH8Toc2ZwxwcKpxciEr8WaJM9eW5OeznBphtob8T0fWRT8IDCRYvXfKvmGVYdRdA9ZPDEwE8AF8C0RMTyew==", + "inBundle": true, + "dependencies": { + "lru-cache": "^6.0.0", + "make-fetch-happen": "^8.0.9", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -14921,9 +14939,9 @@ } }, "pacote": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.1.tgz", - "integrity": "sha512-TymtwoAG12cczsJIrwI/euOQKtjrQHlD0k0oyt9QSmZGpqa+KdlxKdWR/YUjYizkixaVyztxt/Wsfo8bL3A6Fg==", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.2.tgz", + "integrity": "sha512-lMO7V9aMhyE5gfaSFxKfW3OTdXuFBNQJfuNuet3NPzWWhOYIW90t85vHcHLDjdhgmfAdAHyh9q1HAap96ea0XA==", "requires": { "@npmcli/git": "^2.0.1", "@npmcli/installed-package-contents": "^1.0.6", @@ -14938,12 +14956,28 @@ "npm-package-arg": "^8.0.1", "npm-packlist": "^2.1.4", "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^9.0.0", + "npm-registry-fetch": "^10.0.0", "promise-retry": "^2.0.1", "read-package-json-fast": "^2.0.1", "rimraf": "^3.0.2", "ssri": "^8.0.1", "tar": "^6.1.0" + }, + "dependencies": { + "npm-registry-fetch": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-10.0.0.tgz", + "integrity": "sha512-/uLlH8Toc2ZwxwcKpxciEr8WaJM9eW5OeznBphtob8T0fWRT8IDCRYvXfKvmGVYdRdA9ZPDEwE8AF8C0RMTyew==", + "requires": { + "lru-cache": "^6.0.0", + "make-fetch-happen": "^8.0.9", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + } + } } }, "parent-module": { diff --git a/package.json b/package.json index a10d5377a7d85..0db985b8ae29c 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "npm-user-validate": "^1.0.1", "npmlog": "~4.1.2", "opener": "^1.5.2", - "pacote": "^11.3.1", + "pacote": "^11.3.2", "parse-conflict-json": "^1.1.1", "qrcode-terminal": "^0.12.0", "read": "~1.0.7",