diff --git a/.changeset/breezy-owls-grin.md b/.changeset/breezy-owls-grin.md new file mode 100644 index 0000000000..2a716a4987 --- /dev/null +++ b/.changeset/breezy-owls-grin.md @@ -0,0 +1,9 @@ +--- +"@pnpm/audit": major +"@pnpm/default-resolver": major +"@pnpm/fetching-types": major +"@pnpm/npm-resolver": major +"@pnpm/tarball-fetcher": major +--- + +GetCredentials function replaced with GetAuthHeader. diff --git a/.changeset/modern-dodos-switch.md b/.changeset/modern-dodos-switch.md new file mode 100644 index 0000000000..6eee7c6990 --- /dev/null +++ b/.changeset/modern-dodos-switch.md @@ -0,0 +1,5 @@ +--- +"pnpm": patch +--- + +Ignore the always-auth setting. diff --git a/.changeset/olive-suns-hear.md b/.changeset/olive-suns-hear.md new file mode 100644 index 0000000000..44f49c308d --- /dev/null +++ b/.changeset/olive-suns-hear.md @@ -0,0 +1,5 @@ +--- +"@pnpm/network.auth-header": major +--- + +Initial release. diff --git a/packages/audit/src/index.ts b/packages/audit/src/index.ts index 10efbe4227..d5942d79e5 100644 --- a/packages/audit/src/index.ts +++ b/packages/audit/src/index.ts @@ -1,6 +1,6 @@ import { PnpmError } from '@pnpm/error' import { AgentOptions, fetchWithAgent, RetryTimeoutOptions } from '@pnpm/fetch' -import { GetCredentials } from '@pnpm/fetching-types' +import { GetAuthHeader } from '@pnpm/fetching-types' import { Lockfile } from '@pnpm/lockfile-types' import { DependenciesField } from '@pnpm/types' import { lockfileToAuditTree } from './lockfileToAuditTree' @@ -10,7 +10,7 @@ export * from './types' export async function audit ( lockfile: Lockfile, - getCredentials: GetCredentials, + getAuthHeader: GetAuthHeader, opts: { agentOptions?: AgentOptions include?: { [dependenciesField in DependenciesField]: boolean } @@ -22,14 +22,14 @@ export async function audit ( const auditTree = lockfileToAuditTree(lockfile, { include: opts.include }) const registry = opts.registry.endsWith('/') ? opts.registry : `${opts.registry}/` const auditUrl = `${registry}-/npm/v1/security/audits` - const credentials = getCredentials(registry) + const authHeaderValue = getAuthHeader(registry) const res = await fetchWithAgent(auditUrl, { agentOptions: opts.agentOptions ?? {}, body: JSON.stringify(auditTree), headers: { 'Content-Type': 'application/json', - ...getAuthHeaders(credentials), + ...getAuthHeaders(authHeaderValue), }, method: 'post', retry: opts.retry, @@ -46,15 +46,10 @@ export async function audit ( return res.json() as Promise } -function getAuthHeaders ( - credentials: { - authHeaderValue: string | undefined - alwaysAuth: boolean | undefined - } -) { +function getAuthHeaders (authHeaderValue: string | undefined) { const headers: { authorization?: string } = {} - if (credentials.alwaysAuth && credentials.authHeaderValue) { - headers['authorization'] = credentials.authHeaderValue + if (authHeaderValue) { + headers['authorization'] = authHeaderValue } return headers } diff --git a/packages/audit/test/index.ts b/packages/audit/test/index.ts index 47db88bfb3..82a65693f4 100644 --- a/packages/audit/test/index.ts +++ b/packages/audit/test/index.ts @@ -73,7 +73,7 @@ describe('audit', () => { test('an error is thrown if the audit endpoint responds with a non-OK code', async () => { const registry = 'http://registry.registry/' - const getCredentials = () => ({ authHeaderValue: undefined, alwaysAuth: undefined }) + const getAuthHeader = () => undefined nock(registry, { badheaders: ['authorization'], }) @@ -86,7 +86,7 @@ describe('audit', () => { importers: {}, lockfileVersion: 5, }, - getCredentials, + getAuthHeader, { registry, retry: { @@ -101,27 +101,4 @@ describe('audit', () => { expect(err.code).toEqual('ERR_PNPM_AUDIT_BAD_RESPONSE') expect(err.message).toEqual('The audit endpoint (at http://registry.registry/-/npm/v1/security/audits) responded with 500: {"message":"Something bad happened"}') }) - - test('authorization header is sent if alwaysAuth is true', async () => { - const registry = 'http://registry.registry/' - const getCredentials = () => ({ authHeaderValue: 'Bearer 123', alwaysAuth: true }) - - nock(registry, { - reqheaders: { authorization: 'Bearer 123' }, - }) - .post('/-/npm/v1/security/audits') - .reply(200, {}) - - await audit({ - importers: {}, - lockfileVersion: 5, - }, - getCredentials, - { - registry, - retry: { - retries: 0, - }, - }) - }) }) diff --git a/packages/client/package.json b/packages/client/package.json index 259dd16f9e..0354e0e07d 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -36,10 +36,9 @@ "@pnpm/fetch": "workspace:*", "@pnpm/fetching-types": "workspace:*", "@pnpm/git-fetcher": "workspace:*", + "@pnpm/network.auth-header": "workspace:*", "@pnpm/resolver-base": "workspace:*", - "@pnpm/tarball-fetcher": "workspace:*", - "credentials-by-uri": "^2.1.0", - "mem": "^8.1.1" + "@pnpm/tarball-fetcher": "workspace:*" }, "devDependencies": { "@pnpm/client": "workspace:*", diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index ff410fe682..0cdcaa9034 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -4,13 +4,12 @@ import { ResolverFactoryOptions, } from '@pnpm/default-resolver' import { AgentOptions, createFetchFromRegistry } from '@pnpm/fetch' -import { FetchFromRegistry, GetCredentials, RetryTimeoutOptions } from '@pnpm/fetching-types' +import { FetchFromRegistry, GetAuthHeader, RetryTimeoutOptions } from '@pnpm/fetching-types' import type { CustomFetchers, GitFetcher, DirectoryFetcher } from '@pnpm/fetcher-base' import { createDirectoryFetcher } from '@pnpm/directory-fetcher' import { createGitFetcher } from '@pnpm/git-fetcher' import { createTarballFetcher, TarballFetchers } from '@pnpm/tarball-fetcher' -import getCredentialsByURI from 'credentials-by-uri' -import mem from 'mem' +import { createGetAuthHeaderByURI } from '@pnpm/network.auth-header' export { ResolveFunction } @@ -31,17 +30,17 @@ export interface Client { export function createClient (opts: ClientOptions): Client { const fetchFromRegistry = createFetchFromRegistry(opts) - const getCredentials = mem((registry: string) => getCredentialsByURI(opts.authConfig, registry, opts.userConfig)) + const getAuthHeader = createGetAuthHeaderByURI({ allSettings: opts.authConfig, userSettings: opts.userConfig }) return { - fetchers: createFetchers(fetchFromRegistry, getCredentials, opts, opts.customFetchers), - resolve: _createResolver(fetchFromRegistry, getCredentials, opts), + fetchers: createFetchers(fetchFromRegistry, getAuthHeader, opts, opts.customFetchers), + resolve: _createResolver(fetchFromRegistry, getAuthHeader, opts), } } export function createResolver (opts: ClientOptions) { const fetchFromRegistry = createFetchFromRegistry(opts) - const getCredentials = mem((registry: string) => getCredentialsByURI(opts.authConfig, registry)) - return _createResolver(fetchFromRegistry, getCredentials, opts) + const getAuthHeader = createGetAuthHeaderByURI({ allSettings: opts.authConfig, userSettings: opts.userConfig }) + return _createResolver(fetchFromRegistry, getAuthHeader, opts) } type Fetchers = { @@ -51,12 +50,12 @@ type Fetchers = { function createFetchers ( fetchFromRegistry: FetchFromRegistry, - getCredentials: GetCredentials, + getAuthHeader: GetAuthHeader, opts: Pick, customFetchers?: CustomFetchers ): Fetchers { const defaultFetchers = { - ...createTarballFetcher(fetchFromRegistry, getCredentials, opts), + ...createTarballFetcher(fetchFromRegistry, getAuthHeader, opts), ...createGitFetcher(opts), ...createDirectoryFetcher(), } diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json index d1c1829d1c..0d35752795 100644 --- a/packages/client/tsconfig.json +++ b/packages/client/tsconfig.json @@ -27,6 +27,9 @@ { "path": "../git-fetcher" }, + { + "path": "../network.auth-header" + }, { "path": "../resolver-base" }, diff --git a/packages/config/src/Config.ts b/packages/config/src/Config.ts index ef4810d712..4fb6f3aa8d 100644 --- a/packages/config/src/Config.ts +++ b/packages/config/src/Config.ts @@ -103,8 +103,6 @@ export interface Config { tag?: string updateNotifier?: boolean - alwaysAuth?: boolean - // pnpm specific configs cacheDir: string configDir: string diff --git a/packages/core/test/install/auth.ts b/packages/core/test/install/auth.ts index 45f1e30054..d4a6588e5a 100644 --- a/packages/core/test/install/auth.ts +++ b/packages/core/test/install/auth.ts @@ -82,7 +82,6 @@ test('a package that need authentication, legacy way', async () => { const authConfig = { _auth: 'Zm9vOmJhcg==', // base64 encoded foo:bar - 'always-auth': true, registry: `http://localhost:${REGISTRY_MOCK_PORT}`, } await addDependenciesToPackage({}, ['@pnpm.e2e/needs-auth'], await testDefaults({}, { @@ -145,7 +144,6 @@ test('a scoped package that need legacy authentication specific to scope', async const authConfig = { [`//localhost:${REGISTRY_MOCK_PORT}/:_auth`]: 'Zm9vOmJhcg==', // base64 encoded foo:bar - [`//localhost:${REGISTRY_MOCK_PORT}/:always-auth`]: true, '@private:registry': `http://localhost:${REGISTRY_MOCK_PORT}/`, registry: 'https://registry.npmjs.org/', } @@ -186,7 +184,6 @@ skipOnNode17('a package that need authentication reuses authorization tokens for const authConfig = { [`//127.0.0.1:${REGISTRY_MOCK_PORT}/:_authToken`]: data.token, - [`//127.0.0.1:${REGISTRY_MOCK_PORT}/:always-auth`]: true, registry: `http://127.0.0.1:${REGISTRY_MOCK_PORT}`, } await addDependenciesToPackage({}, ['@pnpm.e2e/needs-auth'], await testDefaults({ @@ -214,7 +211,6 @@ skipOnNode17('a package that need authentication reuses authorization tokens for const authConfig = { [`//127.0.0.1:${REGISTRY_MOCK_PORT}/:_authToken`]: data.token, - [`//127.0.0.1:${REGISTRY_MOCK_PORT}/:always-auth`]: true, registry: `http://127.0.0.1:${REGISTRY_MOCK_PORT}`, } let opts = await testDefaults({ diff --git a/packages/default-reporter/src/reportError.ts b/packages/default-reporter/src/reportError.ts index 41e2de6e56..45105c8acc 100644 --- a/packages/default-reporter/src/reportError.ts +++ b/packages/default-reporter/src/reportError.ts @@ -365,8 +365,7 @@ function reportAuthError ( key.endsWith('_auth') || key.endsWith('_authToken') || key.endsWith('username') || - key.endsWith('_password') || - key.endsWith('always-auth') + key.endsWith('_password') ) { foundSettings.push(`${key}=${hideSecureInfo(key, value)}`) } diff --git a/packages/default-reporter/test/reportingErrors.ts b/packages/default-reporter/test/reportingErrors.ts index c635c71022..4e4783178b 100644 --- a/packages/default-reporter/test/reportingErrors.ts +++ b/packages/default-reporter/test/reportingErrors.ts @@ -482,7 +482,6 @@ test('prints authorization error with auth settings', (done) => { _auth: '0123456789', _authToken: '0123456789', _password: '0123456789', - 'always-auth': false, username: 'nagy.gabor', } const output$ = toOutput$({ @@ -512,7 +511,6 @@ ${ERROR_PAD}@foo:registry=https://foo.bar ${ERROR_PAD}_auth=0123[hidden] ${ERROR_PAD}_authToken=0123[hidden] ${ERROR_PAD}_password=[hidden] -${ERROR_PAD}always-auth=false ${ERROR_PAD}username=nagy.gabor`) }, }) diff --git a/packages/default-resolver/src/index.ts b/packages/default-resolver/src/index.ts index 7316a4183a..cf8903b0a9 100644 --- a/packages/default-resolver/src/index.ts +++ b/packages/default-resolver/src/index.ts @@ -1,5 +1,5 @@ import { PnpmError } from '@pnpm/error' -import { FetchFromRegistry, GetCredentials } from '@pnpm/fetching-types' +import { FetchFromRegistry, GetAuthHeader } from '@pnpm/fetching-types' import { createGitResolver } from '@pnpm/git-resolver' import { resolveFromLocal } from '@pnpm/local-resolver' import { @@ -21,10 +21,10 @@ export { export function createResolver ( fetchFromRegistry: FetchFromRegistry, - getCredentials: GetCredentials, + getAuthHeader: GetAuthHeader, pnpmOpts: ResolverFactoryOptions ): ResolveFunction { - const resolveFromNpm = createNpmResolver(fetchFromRegistry, getCredentials, pnpmOpts) + const resolveFromNpm = createNpmResolver(fetchFromRegistry, getAuthHeader, pnpmOpts) const resolveFromGit = createGitResolver(pnpmOpts) return async (wantedDependency, opts) => { const resolution = await resolveFromNpm(wantedDependency, opts as ResolveFromNpmOptions) ?? diff --git a/packages/default-resolver/test/index.ts b/packages/default-resolver/test/index.ts index 0f446f8e08..3b71591af2 100644 --- a/packages/default-resolver/test/index.ts +++ b/packages/default-resolver/test/index.ts @@ -3,8 +3,8 @@ import { createResolver } from '@pnpm/default-resolver' import { createFetchFromRegistry } from '@pnpm/fetch' test('createResolver()', () => { - const getCredentials = () => ({ authHeaderValue: '', alwaysAuth: false }) - const resolve = createResolver(createFetchFromRegistry({}), getCredentials, { + const getAuthHeader = () => undefined + const resolve = createResolver(createFetchFromRegistry({}), getAuthHeader, { cacheDir: '.cache', }) expect(typeof resolve).toEqual('function') diff --git a/packages/fetching-types/src/index.ts b/packages/fetching-types/src/index.ts index be6e469bb9..f09335b27f 100644 --- a/packages/fetching-types/src/index.ts +++ b/packages/fetching-types/src/index.ts @@ -13,7 +13,4 @@ export type FetchFromRegistry = ( } ) => Promise -export type GetCredentials = (registry: string) => { - authHeaderValue: string | undefined - alwaysAuth: boolean | undefined -} +export type GetAuthHeader = (uri: string) => string | undefined diff --git a/packages/network.auth-header/README.md b/packages/network.auth-header/README.md new file mode 100644 index 0000000000..0735ab3318 --- /dev/null +++ b/packages/network.auth-header/README.md @@ -0,0 +1,15 @@ +# @pnpm/network.auth-header + +> Gets the authorization header for the given URI + +[![npm version](https://img.shields.io/npm/v/@pnpm/network.auth-header.svg)](https://www.npmjs.com/package/@pnpm/network.auth-header) + +## Installation + +```sh +pnpm add @pnpm/network.auth-header +``` + +## License + +MIT diff --git a/packages/network.auth-header/jest.config.js b/packages/network.auth-header/jest.config.js new file mode 100644 index 0000000000..9b65513eba --- /dev/null +++ b/packages/network.auth-header/jest.config.js @@ -0,0 +1,3 @@ +const config = require('../../jest.config.js'); + +module.exports = Object.assign({}, config, {}); diff --git a/packages/network.auth-header/package.json b/packages/network.auth-header/package.json new file mode 100644 index 0000000000..eaf7cf79ad --- /dev/null +++ b/packages/network.auth-header/package.json @@ -0,0 +1,44 @@ +{ + "name": "@pnpm/network.auth-header", + "version": "0.0.0", + "description": "Gets the authorization header for the given URI", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "files": [ + "lib", + "!*.map" + ], + "engines": { + "node": ">=14.6" + }, + "scripts": { + "lint": "eslint src/**/*.ts test/**/*.ts", + "_test": "jest", + "test": "pnpm run compile && pnpm run _test", + "prepublishOnly": "pnpm run compile", + "compile": "tsc --build && pnpm run lint --fix" + }, + "repository": "https://github.com/pnpm/pnpm/blob/main/packages/network.auth-header", + "keywords": [ + "pnpm7", + "pnpm", + "auth" + ], + "license": "MIT", + "bugs": { + "url": "https://github.com/pnpm/pnpm/issues" + }, + "homepage": "https://github.com/pnpm/pnpm/blob/main/packages/network.auth-header#readme", + "devDependencies": { + "@pnpm/network.auth-header": "workspace:*", + "safe-buffer": "5.2.1" + }, + "dependencies": { + "@pnpm/error": "workspace:*", + "nerf-dart": "1.0.0" + }, + "funding": "https://opencollective.com/pnpm", + "exports": { + ".": "./lib/index.js" + } +} diff --git a/packages/network.auth-header/src/getAuthHeadersFromConfig.ts b/packages/network.auth-header/src/getAuthHeadersFromConfig.ts new file mode 100644 index 0000000000..ec2c7fddb9 --- /dev/null +++ b/packages/network.auth-header/src/getAuthHeadersFromConfig.ts @@ -0,0 +1,71 @@ +import { PnpmError } from '@pnpm/error' +import { spawnSync } from 'child_process' +import fs from 'fs' +import path from 'path' +import nerfDart from 'nerf-dart' + +export function getAuthHeadersFromConfig ( + { allSettings, userSettings }: { + allSettings: Record + userSettings: Record + } +) { + const authHeaderValueByURI = {} + for (const [key, value] of Object.entries(allSettings)) { + const [uri, authType] = splitKey(key) + switch (authType) { + case '_authToken': { + authHeaderValueByURI[uri] = `Bearer ${value}` + continue + } + case '_auth': { + authHeaderValueByURI[uri] = `Basic ${value}` + continue + } + case 'username': { + if (`${uri}:_password` in allSettings) { + const password = Buffer.from(allSettings[`${uri}:_password`], 'base64').toString('utf8') + authHeaderValueByURI[uri] = `Basic ${Buffer.from(`${value}:${password}`).toString('base64')}` + } + } + } + } + for (const [key, value] of Object.entries(userSettings)) { + const [uri, authType] = splitKey(key) + if (authType === 'tokenHelper') { + authHeaderValueByURI[uri] = loadToken(value, key) + } + } + const registry = allSettings['registry'] ? nerfDart(allSettings['registry']) : '//registry.npmjs.org/' + if (userSettings['tokenHelper']) { + authHeaderValueByURI[registry] = loadToken(userSettings['tokenHelper'], 'tokenHelper') + } else if (allSettings['_authToken']) { + authHeaderValueByURI[registry] = `Bearer ${allSettings['_authToken']}` + } else if (allSettings['_auth']) { + authHeaderValueByURI[registry] = `Basic ${allSettings['_auth']}` + } else if (allSettings['_password'] && allSettings['username']) { + authHeaderValueByURI[registry] = `Basic ${Buffer.from(`${allSettings['username']}:${allSettings['_password']}`).toString('base64')}` + } + return authHeaderValueByURI +} + +function splitKey (key: string) { + const index = key.lastIndexOf(':') + if (index === -1) { + return [key, ''] + } + return [key.slice(0, index), key.slice(index + 1)] +} + +function loadToken (helperPath: string, settingName: string) { + if (!path.isAbsolute(helperPath) || !fs.existsSync(helperPath)) { + throw new PnpmError('BAD_TOKEN_HELPER_PATH', `${settingName} must be an absolute path, without arguments`) + } + + const spawnResult = spawnSync(helperPath, { shell: true }) + + if (spawnResult.status !== 0) { + throw new PnpmError('TOKEN_HELPER_ERROR_STATUS', `Error running "${helperPath}" as a token helper, configured as ${settingName}. Exit code ${spawnResult.status?.toString() ?? ''}`) + } + return spawnResult.stdout.toString('utf8').trimEnd() +} diff --git a/packages/network.auth-header/src/index.ts b/packages/network.auth-header/src/index.ts new file mode 100644 index 0000000000..5ea73ea490 --- /dev/null +++ b/packages/network.auth-header/src/index.ts @@ -0,0 +1,33 @@ +import nerfDart from 'nerf-dart' +import { getAuthHeadersFromConfig } from './getAuthHeadersFromConfig' + +export function createGetAuthHeaderByURI ( + opts: { + allSettings: Record + userSettings?: Record + } +) { + const authHeaders = getAuthHeadersFromConfig({ + allSettings: opts.allSettings, + userSettings: opts.userSettings ?? {}, + }) + if (Object.keys(authHeaders).length === 0) return () => undefined + return getAuthHeaderByURI.bind(null, authHeaders, getMaxParts(Object.keys(authHeaders))) +} + +function getMaxParts (uris: string[]) { + return uris.reduce((max, uri) => { + const parts = uri.split('/').length + return parts > max ? parts : max + }, 0) +} + +function getAuthHeaderByURI (authHeaders: Record, maxParts: number, uri: string) { + const nerfed = nerfDart(uri) + const parts = nerfed.split('/') + for (let i = Math.min(parts.length, maxParts) - 1; i >= 3; i--) { + const key = `${parts.slice(0, i).join('/')}/` // eslint-disable-line + if (authHeaders[key]) return authHeaders[key] + } + return undefined +} diff --git a/packages/network.auth-header/test/getAuthHeaderByURI.ts b/packages/network.auth-header/test/getAuthHeaderByURI.ts new file mode 100644 index 0000000000..c656ef7bd9 --- /dev/null +++ b/packages/network.auth-header/test/getAuthHeaderByURI.ts @@ -0,0 +1,19 @@ +import { createGetAuthHeaderByURI } from '@pnpm/network.auth-header' + +test('getAuthHeaderByURI()', () => { + const getAuthHeaderByURI = createGetAuthHeaderByURI({ + allSettings: { + '//reg.com/:_authToken': 'abc123', + '//reg.co/tarballs/:_authToken': 'xxx', + }, + userSettings: {}, + }) + expect(getAuthHeaderByURI('https://reg.com/')).toBe('Bearer abc123') + expect(getAuthHeaderByURI('https://reg.com/foo/-/foo-1.0.0.tgz')).toBe('Bearer abc123') + expect(getAuthHeaderByURI('https://reg.io/foo/-/foo-1.0.0.tgz')).toBe(undefined) + expect(getAuthHeaderByURI('https://reg.co/tarballs/foo/-/foo-1.0.0.tgz')).toBe('Bearer xxx') +}) + +test('returns undefined when the auth header is not found', () => { + expect(createGetAuthHeaderByURI({ allSettings: {}, userSettings: {} })('http://reg.com')).toBe(undefined) +}) diff --git a/packages/network.auth-header/test/getAuthHeadersFromConfig.test.ts b/packages/network.auth-header/test/getAuthHeadersFromConfig.test.ts new file mode 100644 index 0000000000..c26664a419 --- /dev/null +++ b/packages/network.auth-header/test/getAuthHeadersFromConfig.test.ts @@ -0,0 +1,117 @@ +import path from 'path' +import os from 'os' +import { getAuthHeadersFromConfig } from '../src/getAuthHeadersFromConfig' +import { Buffer } from 'safe-buffer' + +const osTokenHelper = { + linux: path.join(__dirname, 'utils/test-exec.js'), + win32: path.join(__dirname, 'utils/test-exec.bat'), +} + +const osErrorTokenHelper = { + linux: path.join(__dirname, 'utils/test-exec-error.js'), + win32: path.join(__dirname, 'utils/test-exec-error.bat'), +} + +// Only exception is win32, all others behave like linux +const osFamily = os.platform() === 'win32' ? 'win32' : 'linux' + +describe('getAuthHeadersFromConfig()', () => { + it('should get settings', () => { + const allSettings = { + '//registry.npmjs.org/:_authToken': 'abc123', + '//registry.foobar.eu/:_password': encodeBase64('foobar'), + '//registry.foobar.eu/:username': 'foobar', + '//registry.hu/:_auth': 'foobar', + '//localhost:3000/:_auth': 'foobar', + } + const userSettings = {} + expect(getAuthHeadersFromConfig({ allSettings, userSettings })).toStrictEqual({ + '//registry.npmjs.org/': 'Bearer abc123', + '//registry.foobar.eu/': 'Basic Zm9vYmFyOmZvb2Jhcg==', + '//registry.hu/': 'Basic foobar', + '//localhost:3000/': 'Basic foobar', + }) + }) + describe('should get settings for the default registry', () => { + it('_auth', () => { + const allSettings = { + registry: 'https://reg.com/', + _auth: 'foobar', + } + expect(getAuthHeadersFromConfig({ allSettings, userSettings: {} })).toStrictEqual({ + '//reg.com/': 'Basic foobar', + }) + }) + it('username/_password', () => { + const allSettings = { + registry: 'https://reg.com/', + username: 'foo', + _password: 'bar', + } + expect(getAuthHeadersFromConfig({ allSettings, userSettings: {} })).toStrictEqual({ + '//reg.com/': `Basic ${encodeBase64('foo:bar')}`, + }) + }) + it('tokenHelper', () => { + const allSettings = { + registry: 'https://reg.com/', + } + const userSettings = { + tokenHelper: osTokenHelper[osFamily], + } + expect(getAuthHeadersFromConfig({ allSettings, userSettings })).toStrictEqual({ + '//reg.com/': 'Bearer token-from-spawn', + }) + }) + it('only read token helper from user config', () => { + const allSettings = { + registry: 'https://reg.com/', + tokenHelper: osTokenHelper[osFamily], + } + expect(getAuthHeadersFromConfig({ allSettings, userSettings: {} })).toStrictEqual({}) + }) + }) + it('should get tokenHelper', () => { + const userSettings = { + '//registry.foobar.eu/:tokenHelper': osTokenHelper[osFamily], + } + expect(getAuthHeadersFromConfig({ allSettings: {}, userSettings })).toStrictEqual({ + '//registry.foobar.eu/': 'Bearer token-from-spawn', + }) + }) + it('should throw an error if the token helper is not an absolute path', () => { + expect(() => getAuthHeadersFromConfig({ + allSettings: {}, + userSettings: { + '//reg.com:tokenHelper': './utils/text-exec.js', + }, + })).toThrowError('must be an absolute path, without arguments') + }) + it('should throw an error if the token helper is not an absolute path with args', () => { + expect(() => getAuthHeadersFromConfig({ + allSettings: {}, + userSettings: { + '//reg.com:tokenHelper': `${osTokenHelper[osFamily]} arg1`, + }, + })).toThrowError('must be an absolute path, without arguments') + }) + it('should throw an error if the token helper fails', () => { + expect(() => getAuthHeadersFromConfig({ + allSettings: {}, + userSettings: { + '//reg.com:tokenHelper': osErrorTokenHelper[osFamily], + }, + })).toThrowError('Exit code') + }) + it('only read token helper from user config', () => { + const allSettings = { + '//reg.com:tokenHelper': osTokenHelper[osFamily], + } + expect(getAuthHeadersFromConfig({ allSettings, userSettings: {} })).toStrictEqual({}) + }) +}) + +function encodeBase64 (s: string) { + return Buffer.from(s, 'utf8').toString('base64') +} diff --git a/packages/network.auth-header/test/utils/test-exec-error.bat b/packages/network.auth-header/test/utils/test-exec-error.bat new file mode 100644 index 0000000000..e6d16db878 --- /dev/null +++ b/packages/network.auth-header/test/utils/test-exec-error.bat @@ -0,0 +1,3 @@ +@echo off +echo Bearer token-from-spawn-errored +exit /b 1 \ No newline at end of file diff --git a/packages/network.auth-header/test/utils/test-exec-error.js b/packages/network.auth-header/test/utils/test-exec-error.js new file mode 100644 index 0000000000..614cca27b5 --- /dev/null +++ b/packages/network.auth-header/test/utils/test-exec-error.js @@ -0,0 +1 @@ +process.exit(1) diff --git a/packages/network.auth-header/test/utils/test-exec.bat b/packages/network.auth-header/test/utils/test-exec.bat new file mode 100644 index 0000000000..1304c25124 --- /dev/null +++ b/packages/network.auth-header/test/utils/test-exec.bat @@ -0,0 +1 @@ +@echo Bearer token-from-spawn \ No newline at end of file diff --git a/packages/network.auth-header/test/utils/test-exec.js b/packages/network.auth-header/test/utils/test-exec.js new file mode 100755 index 0000000000..12ccef0211 --- /dev/null +++ b/packages/network.auth-header/test/utils/test-exec.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +console.log('Bearer token-from-spawn') diff --git a/packages/network.auth-header/tsconfig.json b/packages/network.auth-header/tsconfig.json new file mode 100644 index 0000000000..b2232f7e30 --- /dev/null +++ b/packages/network.auth-header/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "@pnpm/tsconfig", + "compilerOptions": { + "outDir": "lib", + "rootDir": "src" + }, + "include": [ + "src/**/*.ts", + "../../typings/**/*.d.ts" + ], + "references": [ + { + "path": "../error" + } + ] +} diff --git a/packages/network.auth-header/tsconfig.lint.json b/packages/network.auth-header/tsconfig.lint.json new file mode 100644 index 0000000000..0dc5add6b7 --- /dev/null +++ b/packages/network.auth-header/tsconfig.lint.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "include": [ + "src/**/*.ts", + "test/**/*.ts", + "../../typings/**/*.d.ts" + ] +} diff --git a/packages/node.fetcher/src/index.ts b/packages/node.fetcher/src/index.ts index 532681440a..228211eccf 100644 --- a/packages/node.fetcher/src/index.ts +++ b/packages/node.fetcher/src/index.ts @@ -32,8 +32,8 @@ export async function fetchNode (fetch: FetchFromRegistry, version: string, targ await downloadAndUnpackZip(fetch, tarball, targetDir, pkgName) return } - const getCredentials = () => ({ authHeaderValue: undefined, alwaysAuth: undefined }) - const fetchers = createTarballFetcher(fetch, getCredentials, { + const getAuthHeader = () => undefined + const fetchers = createTarballFetcher(fetch, getAuthHeader, { retry: opts.retry, timeout: opts.fetchTimeout, }) diff --git a/packages/npm-resolver/src/index.ts b/packages/npm-resolver/src/index.ts index 257c0c6cb6..163bc48e8c 100644 --- a/packages/npm-resolver/src/index.ts +++ b/packages/npm-resolver/src/index.ts @@ -2,7 +2,7 @@ import path from 'path' import { PnpmError } from '@pnpm/error' import { FetchFromRegistry, - GetCredentials, + GetAuthHeader, RetryTimeoutOptions, } from '@pnpm/fetching-types' import { resolveWorkspaceRange } from '@pnpm/resolve-workspace-range' @@ -72,7 +72,7 @@ export interface ResolverFactoryOptions { export function createNpmResolver ( fetchFromRegistry: FetchFromRegistry, - getCredentials: GetCredentials, + getAuthHeader: GetAuthHeader, opts: ResolverFactoryOptions ) { if (typeof opts.cacheDir !== 'string') { @@ -86,13 +86,12 @@ export function createNpmResolver ( cacheKey: (...args) => JSON.stringify(args), maxAge: 1000 * 20, // 20 seconds }) - const getAuthHeaderValueByURI = (registry: string) => getCredentials(registry).authHeaderValue const metaCache = new LRU({ max: 10000, ttl: 120 * 1000, // 2 minutes }) return resolveNpm.bind(null, { - getAuthHeaderValueByURI, + getAuthHeaderValueByURI: getAuthHeader, pickPackage: pickPackage.bind(null, { fetch, filterMetadata: opts.filterMetadata, diff --git a/packages/npm-resolver/test/index.ts b/packages/npm-resolver/test/index.ts index a51381f4b2..672f1122a1 100644 --- a/packages/npm-resolver/test/index.ts +++ b/packages/npm-resolver/test/index.ts @@ -29,8 +29,8 @@ const registry = 'https://registry.npmjs.org/' const delay = async (time: number) => new Promise((resolve) => setTimeout(() => resolve(), time)) const fetch = createFetchFromRegistry({}) -const getCredentials = () => ({ authHeaderValue: undefined, alwaysAuth: undefined }) -const createResolveFromNpm = createNpmResolver.bind(null, fetch, getCredentials) +const getAuthHeader = () => undefined +const createResolveFromNpm = createNpmResolver.bind(null, fetch, getAuthHeader) async function retryLoadJsonFile (filePath: string) { let retry = 0 diff --git a/packages/npm-resolver/test/publishedBy.test.ts b/packages/npm-resolver/test/publishedBy.test.ts index 77110df1d5..4ec62db969 100644 --- a/packages/npm-resolver/test/publishedBy.test.ts +++ b/packages/npm-resolver/test/publishedBy.test.ts @@ -15,8 +15,8 @@ const badDatesMeta = loadJsonFile.sync(f.find('bad-dates.json')) /* eslint-enable @typescript-eslint/no-explicit-any */ const fetch = createFetchFromRegistry({}) -const getCredentials = () => ({ authHeaderValue: undefined, alwaysAuth: undefined }) -const createResolveFromNpm = createNpmResolver.bind(null, fetch, getCredentials) +const getAuthHeader = () => undefined +const createResolveFromNpm = createNpmResolver.bind(null, fetch, getAuthHeader) test('fall back to a newer version if there is no version published by the given date', async () => { nock(registry) diff --git a/packages/plugin-commands-audit/package.json b/packages/plugin-commands-audit/package.json index e92dd642c4..e2558d1c56 100644 --- a/packages/plugin-commands-audit/package.json +++ b/packages/plugin-commands-audit/package.json @@ -47,11 +47,11 @@ "@pnpm/constants": "workspace:*", "@pnpm/error": "workspace:*", "@pnpm/lockfile-file": "workspace:*", + "@pnpm/network.auth-header": "workspace:*", "@pnpm/read-project-manifest": "workspace:*", "@pnpm/types": "workspace:*", "@zkochan/table": "^1.0.0", "chalk": "^4.1.2", - "credentials-by-uri": "^2.1.0", "mem": "^8.1.1", "ramda": "npm:@pnpm/ramda@0.28.1", "render-help": "^1.0.2" diff --git a/packages/plugin-commands-audit/src/audit.ts b/packages/plugin-commands-audit/src/audit.ts index 89299013e1..dc00047125 100644 --- a/packages/plugin-commands-audit/src/audit.ts +++ b/packages/plugin-commands-audit/src/audit.ts @@ -1,4 +1,5 @@ import { audit, AuditReport, AuditVulnerabilityCounts } from '@pnpm/audit' +import { createGetAuthHeaderByURI } from '@pnpm/network.auth-header' import { docsUrl, TABLE_OPTIONS } from '@pnpm/cli-utils' import { Config, types as allTypes, UniversalOptions } from '@pnpm/config' import { WANTED_LOCKFILE } from '@pnpm/constants' @@ -9,7 +10,6 @@ import { table } from '@zkochan/table' import chalk from 'chalk' import pick from 'ramda/src/pick' import renderHelp from 'render-help' -import getCredentialsByURI from 'credentials-by-uri' import { fix } from './fix' // eslint-disable @@ -124,7 +124,6 @@ export async function handler ( | 'production' | 'dev' | 'optional' - | 'alwaysAuth' | 'userConfig' | 'rawConfig' > @@ -139,9 +138,9 @@ export async function handler ( optionalDependencies: opts.optional !== false, } let auditReport!: AuditReport - const getCredentials = (registry: string) => getCredentialsByURI(opts.rawConfig, registry, opts.userConfig) + const getAuthHeader = createGetAuthHeaderByURI({ allSettings: opts.rawConfig, userSettings: opts.userConfig }) try { - auditReport = await audit(lockfile, getCredentials, { + auditReport = await audit(lockfile, getAuthHeader, { agentOptions: { ca: opts.ca, cert: opts.cert, diff --git a/packages/plugin-commands-audit/test/index.ts b/packages/plugin-commands-audit/test/index.ts index 6e27ed1c4e..ee2223624f 100644 --- a/packages/plugin-commands-audit/test/index.ts +++ b/packages/plugin-commands-audit/test/index.ts @@ -134,7 +134,7 @@ test('audit does not exit with code 1 if the registry responds with a non-200 re expect(stripAnsi(output)).toBe(`The audit endpoint (at ${registries.default}-/npm/v1/security/audits) responded with 500: {"message":"Something bad happened"}`) }) -test('audit sends authToken if alwaysAuth is true', async () => { +test('audit sends authToken', async () => { nock(registries.default, { reqheaders: { authorization: 'Bearer 123' }, }) @@ -146,7 +146,6 @@ test('audit sends authToken if alwaysAuth is true', async () => { userConfig: {}, rawConfig: { registry: registries.default, - 'always-auth': true, [`${registries.default.replace(/^https?:/, '')}:_authToken`]: '123', }, registries, diff --git a/packages/plugin-commands-audit/tsconfig.json b/packages/plugin-commands-audit/tsconfig.json index c83b38b556..9b9168e173 100644 --- a/packages/plugin-commands-audit/tsconfig.json +++ b/packages/plugin-commands-audit/tsconfig.json @@ -30,6 +30,9 @@ { "path": "../lockfile-file" }, + { + "path": "../network.auth-header" + }, { "path": "../read-project-manifest" }, diff --git a/packages/plugin-commands-deploy/test/utils/index.ts b/packages/plugin-commands-deploy/test/utils/index.ts index adf5b5b5e2..b409fb15de 100644 --- a/packages/plugin-commands-deploy/test/utils/index.ts +++ b/packages/plugin-commands-deploy/test/utils/index.ts @@ -3,7 +3,6 @@ import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock' const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}` export const DEFAULT_OPTS = { - alwaysAuth: false, argv: { original: [], }, diff --git a/packages/plugin-commands-installation/test/import.ts b/packages/plugin-commands-installation/test/import.ts index 35dc83110c..c80ec897ba 100644 --- a/packages/plugin-commands-installation/test/import.ts +++ b/packages/plugin-commands-installation/test/import.ts @@ -14,7 +14,6 @@ const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}` const TMP = tempy.directory() const DEFAULT_OPTS = { - alwaysAuth: false, ca: undefined, cacheDir: path.join(TMP, 'cache'), cert: undefined, diff --git a/packages/plugin-commands-installation/test/importRecursive.ts b/packages/plugin-commands-installation/test/importRecursive.ts index a69ca577f9..c64320fb55 100644 --- a/packages/plugin-commands-installation/test/importRecursive.ts +++ b/packages/plugin-commands-installation/test/importRecursive.ts @@ -12,7 +12,6 @@ const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}` const TMP = tempy.directory() const DEFAULT_OPTS = { - alwaysAuth: false, ca: undefined, cacheDir: path.join(TMP, 'cache'), cert: undefined, diff --git a/packages/plugin-commands-installation/test/utils/index.ts b/packages/plugin-commands-installation/test/utils/index.ts index adf5b5b5e2..b409fb15de 100644 --- a/packages/plugin-commands-installation/test/utils/index.ts +++ b/packages/plugin-commands-installation/test/utils/index.ts @@ -3,7 +3,6 @@ import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock' const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}` export const DEFAULT_OPTS = { - alwaysAuth: false, argv: { original: [], }, diff --git a/packages/plugin-commands-listing/test/utils/index.ts b/packages/plugin-commands-listing/test/utils/index.ts index 47abcddf91..c24e6b1015 100644 --- a/packages/plugin-commands-listing/test/utils/index.ts +++ b/packages/plugin-commands-listing/test/utils/index.ts @@ -3,7 +3,6 @@ import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock' const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}` export const DEFAULT_OPTS = { - alwaysAuth: false, argv: { original: [], }, diff --git a/packages/plugin-commands-outdated/src/outdated.ts b/packages/plugin-commands-outdated/src/outdated.ts index 1ca05f9153..e55f510f1b 100644 --- a/packages/plugin-commands-outdated/src/outdated.ts +++ b/packages/plugin-commands-outdated/src/outdated.ts @@ -123,7 +123,6 @@ export type OutdatedCommandOptions = { table?: boolean } & Pick { - authHeaderValue: string | undefined - alwaysAuth: boolean | undefined - } + getAuthHeaderByURI: (registry: string) => string | undefined offline?: boolean }, cafs: Cafs, @@ -75,9 +72,8 @@ async function fetchFromTarball ( throw new PnpmError('NO_OFFLINE_TARBALL', `A package is missing from the store but cannot download it in offline mode. The missing package may be downloaded from ${resolution.tarball}.`) } - const auth = resolution.registry ? ctx.getCredentialsByURI(resolution.registry) : undefined return ctx.download(resolution.tarball, { - auth, + getAuthHeaderByURI: ctx.getAuthHeaderByURI, cafs, integrity: resolution.integrity, manifest: opts.manifest, diff --git a/packages/tarball-fetcher/src/remoteTarballFetcher.ts b/packages/tarball-fetcher/src/remoteTarballFetcher.ts index 434e52168e..6722caf631 100644 --- a/packages/tarball-fetcher/src/remoteTarballFetcher.ts +++ b/packages/tarball-fetcher/src/remoteTarballFetcher.ts @@ -1,5 +1,4 @@ import { IncomingMessage } from 'http' -import urlLib from 'url' import { requestRetryLogger } from '@pnpm/core-loggers' import { FetchError, PnpmError } from '@pnpm/error' import { FetchResult } from '@pnpm/fetcher-base' @@ -43,10 +42,7 @@ export interface HttpResponse { } export type DownloadFunction = (url: string, opts: { - auth?: { - authHeaderValue: string | undefined - alwaysAuth: boolean | undefined - } + getAuthHeaderByURI: (registry: string) => string | undefined cafs: Cafs manifest?: DeferredManifestPromise registry?: string @@ -83,10 +79,7 @@ export function createDownloader ( } return async function download (url: string, opts: { - auth?: { - authHeaderValue: string | undefined - alwaysAuth: boolean | undefined - } + getAuthHeaderByURI: (registry: string) => string | undefined cafs: Cafs manifest?: DeferredManifestPromise registry?: string @@ -94,13 +87,7 @@ export function createDownloader ( onProgress?: (downloaded: number) => void integrity?: string }): Promise { - // If a tarball is hosted on a different place than the manifest, only send - // credentials on `alwaysAuth` - const shouldAuth = (opts.auth != null) && ( - opts.auth.alwaysAuth === true || - !opts.registry || - new urlLib.URL(url).host === new urlLib.URL(opts.registry).host - ) + const authHeaderValue = opts.getAuthHeaderByURI(url) const op = retry.operation(retryOpts) @@ -136,7 +123,6 @@ export function createDownloader ( async function fetch (currentAttempt: number): Promise { try { - const authHeaderValue = shouldAuth ? opts.auth?.authHeaderValue : undefined const res = await fetchFromRegistry(url, { authHeaderValue, // The fetch library can retry requests on bad HTTP responses. diff --git a/packages/tarball-fetcher/test/fetch.ts b/packages/tarball-fetcher/test/fetch.ts index 069fac5db3..f405b0cc25 100644 --- a/packages/tarball-fetcher/test/fetch.ts +++ b/packages/tarball-fetcher/test/fetch.ts @@ -23,8 +23,8 @@ const tarballSize = 1279 const tarballIntegrity = 'sha1-HssnaJydJVE+rbyZFKc/VAi+enY=' const registry = 'http://example.com/' const fetchFromRegistry = createFetchFromRegistry({}) -const getCredentials = () => ({ authHeaderValue: undefined, alwaysAuth: undefined }) -const fetch = createTarballFetcher(fetchFromRegistry, getCredentials, { +const getAuthHeader = () => undefined +const fetch = createTarballFetcher(fetchFromRegistry, getAuthHeader, { retry: { maxTimeout: 100, minTimeout: 0, @@ -204,7 +204,7 @@ test("don't fail when fetching a local tarball in offline mode", async () => { tarball: `file:${tarballAbsoluteLocation}`, } - const fetch = createTarballFetcher(fetchFromRegistry, getCredentials, { + const fetch = createTarballFetcher(fetchFromRegistry, getAuthHeader, { offline: true, retry: { maxTimeout: 100, @@ -228,7 +228,7 @@ test('fail when trying to fetch a non-local tarball in offline mode', async () = tarball: `${registry}foo.tgz`, } - const fetch = createTarballFetcher(fetchFromRegistry, getCredentials, { + const fetch = createTarballFetcher(fetchFromRegistry, getAuthHeader, { offline: true, retry: { maxTimeout: 100, @@ -319,11 +319,8 @@ test('accessing private packages', async () => { process.chdir(tempy.directory()) - const getCredentials = () => ({ - alwaysAuth: undefined, - authHeaderValue: 'Bearer ofjergrg349gj3f2', - }) - const fetch = createTarballFetcher(fetchFromRegistry, getCredentials, { + const getAuthHeader = () => 'Bearer ofjergrg349gj3f2' + const fetch = createTarballFetcher(fetchFromRegistry, getAuthHeader, { retry: { maxTimeout: 100, minTimeout: 0, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 62aa53364a..6fcbf075a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -214,6 +214,22 @@ importers: specifier: 13.2.9 version: 13.2.9 + packages/network.auth-header: + dependencies: + '@pnpm/error': + specifier: workspace:* + version: link:../error + nerf-dart: + specifier: 1.0.0 + version: 1.0.0 + devDependencies: + '@pnpm/network.auth-header': + specifier: workspace:* + version: 'link:' + safe-buffer: + specifier: 5.2.1 + version: 5.2.1 + packages/build-modules: dependencies: '@pnpm/calc-dep-state': @@ -416,6 +432,9 @@ importers: packages/client: dependencies: + '@pnpm/network.auth-header': + specifier: workspace:* + version: link:../network.auth-header '@pnpm/default-resolver': specifier: workspace:* version: link:../default-resolver @@ -437,12 +456,6 @@ importers: '@pnpm/tarball-fetcher': specifier: workspace:* version: link:../tarball-fetcher - credentials-by-uri: - specifier: ^2.1.0 - version: 2.1.0 - mem: - specifier: ^8.1.1 - version: 8.1.1 devDependencies: '@pnpm/client': specifier: workspace:* @@ -2986,6 +2999,9 @@ importers: '@pnpm/audit': specifier: workspace:* version: link:../audit + '@pnpm/network.auth-header': + specifier: workspace:* + version: link:../network.auth-header '@pnpm/cli-utils': specifier: workspace:* version: link:../cli-utils @@ -3013,9 +3029,6 @@ importers: chalk: specifier: ^4.1.2 version: 4.1.2 - credentials-by-uri: - specifier: ^2.1.0 - version: 2.1.0 mem: specifier: ^8.1.1 version: 8.1.1 @@ -6392,14 +6405,14 @@ packages: '@jest/test-result': 29.1.2 '@jest/transform': 29.1.2_@babel+types@7.19.3 '@jest/types': 29.1.2 - '@types/node': 18.8.4 + '@types/node': 18.8.5 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.5.0 exit: 0.1.2 graceful-fs: 4.2.10 jest-changed-files: 29.0.0 - jest-config: 29.1.2_2bpsusnajtsxcfljrp4g4m4x6u + jest-config: 29.1.2_umh5qgof6v332qbluj233ooouq jest-haste-map: 29.1.2 jest-message-util: 29.1.2 jest-regex-util: 29.0.0 @@ -6602,7 +6615,7 @@ packages: '@jest/schemas': 29.0.0 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.8.4 + '@types/node': 18.8.5 '@types/yargs': 17.0.13 chalk: 4.1.2 dev: true @@ -6848,11 +6861,6 @@ packages: - typanion dev: true - /@pnpm/constants/5.0.0: - resolution: {integrity: sha512-VhUGKR5jvAtoBHgHAB3Kfc9g42ocVUws9iOafGAQ+xjR8uLokUCReXDpLXRRtrqw8N8yyh3gLNpCJs/AYadA1g==} - engines: {node: '>=12.17'} - dev: false - /@pnpm/constants/6.1.0: resolution: {integrity: sha512-L6AiU3OXv9kjKGTJN9j8n1TeJGDcLX9atQlZvAkthlvbXjvKc5SKNWESc/eXhr5nEfuMWhQhiKHDJCpYejmeCQ==} engines: {node: '>=14.19'} @@ -6983,13 +6991,6 @@ packages: ramda: /@pnpm/ramda/0.28.1 dev: true - /@pnpm/error/2.1.0: - resolution: {integrity: sha512-IxtPG61WgxsDNbtWW+128RiRo6WHhm7Dm2vm77xxC/zEi/uQ35Uf59olhVT3m2/ETDw/iz7Lv1RpvPYTsglX9g==} - engines: {node: '>=12.17'} - dependencies: - '@pnpm/constants': 5.0.0 - dev: false - /@pnpm/error/4.0.0: resolution: {integrity: sha512-NI4DFCMF6xb1SA0bZiiV5KrMCaJM2QmPJFC6p78FXujn7FpiRSWhT9r032wpuQumsl7DEmN4s3wl/P8TA+bL8w==} engines: {node: '>=14.6'} @@ -8023,7 +8024,7 @@ packages: resolution: {integrity: sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 14.18.32 + '@types/node': 18.8.5 dev: true /@types/graceful-fs/4.1.5: @@ -9899,14 +9900,6 @@ packages: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} dev: true - /credentials-by-uri/2.1.0: - resolution: {integrity: sha512-Ia57VrZYcs4YTPUB4Pirjf3MYsSdc7mAYGC99lUKii0KsohmZgpPvVOeqW1NWBCRg3HVrLOtSreLqkmFIUi8WQ==} - engines: {node: '>=10'} - dependencies: - '@pnpm/error': 2.1.0 - nerf-dart: 1.0.0 - dev: false - /cross-env/7.0.3: resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} @@ -12436,7 +12429,7 @@ packages: - ts-node dev: true - /jest-config/29.1.2_2bpsusnajtsxcfljrp4g4m4x6u: + /jest-config/29.1.2_62226uqvmdh4n5ozoaflu2xbzq: resolution: {integrity: sha512-EC3Zi86HJUOz+2YWQcJYQXlf0zuBhJoeyxLM6vb6qJsVmpP7KcCP1JnyF0iaqTaXdBP8Rlwsvs7hnKWQWWLwwA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -12451,7 +12444,7 @@ packages: '@babel/core': 7.19.3 '@jest/test-sequencer': 29.1.2 '@jest/types': 29.1.2 - '@types/node': 18.8.4 + '@types/node': 14.18.29 babel-jest: 29.1.2_rbxuy635u6cfvllmi4ba4h7ksu chalk: 4.1.2 ci-info: 3.5.0 @@ -12477,7 +12470,7 @@ packages: - supports-color dev: true - /jest-config/29.1.2_62226uqvmdh4n5ozoaflu2xbzq: + /jest-config/29.1.2_umh5qgof6v332qbluj233ooouq: resolution: {integrity: sha512-EC3Zi86HJUOz+2YWQcJYQXlf0zuBhJoeyxLM6vb6qJsVmpP7KcCP1JnyF0iaqTaXdBP8Rlwsvs7hnKWQWWLwwA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -12492,7 +12485,7 @@ packages: '@babel/core': 7.19.3 '@jest/test-sequencer': 29.1.2 '@jest/types': 29.1.2 - '@types/node': 14.18.29 + '@types/node': 18.8.5 babel-jest: 29.1.2_rbxuy635u6cfvllmi4ba4h7ksu chalk: 4.1.2 ci-info: 3.5.0 @@ -12764,7 +12757,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.1.2 - '@types/node': 18.8.4 + '@types/node': 18.8.5 chalk: 4.1.2 ci-info: 3.5.0 graceful-fs: 4.2.10 @@ -17212,7 +17205,6 @@ time: /cmd-extension/1.0.2: '2021-09-28T21:08:51.481Z' /comver-to-semver/1.0.0: '2021-04-04T23:59:39.895Z' /concat-stream/2.0.0: '2018-12-21T14:22:15.876Z' - /credentials-by-uri/2.1.0: '2021-12-25T22:13:49.239Z' /cross-env/7.0.3: '2020-12-01T20:25:26.541Z' /cross-spawn/7.0.3: '2020-05-25T15:35:07.209Z' /cross-var-no-babel/1.2.0: '2017-11-12T10:58:04.011Z' @@ -17266,6 +17258,7 @@ time: /mdast-util-to-string/2.0.0: '2020-11-11T09:15:26.835Z' /mem/8.1.1: '2021-04-20T15:49:07.407Z' /micromatch/4.0.5: '2022-03-24T19:31:47.722Z' + /nerf-dart/1.0.0: '2015-08-20T12:22:17.009Z' /nock/13.2.9: '2022-07-19T18:34:55.582Z' /node-fetch/3.0.0-beta.9: '2020-09-05T12:52:27.791Z' /node-gyp/9.2.0: '2022-10-04T10:40:24.552Z' @@ -17314,6 +17307,7 @@ time: /root-link-target/3.1.0: '2021-02-11T22:54:37.968Z' /run-groups/3.0.1: '2020-06-06T16:33:09.423Z' /rxjs/7.5.7: '2022-09-25T18:42:55.719Z' + /safe-buffer/5.2.1: '2020-05-10T16:37:30.776Z' /safe-execa/0.1.2: '2022-07-18T01:09:17.517Z' /safe-promise-defer/1.0.1: '2022-06-18T13:48:40.297Z' /sanitize-filename/1.6.3: '2019-08-26T02:10:56.988Z' diff --git a/typings/local.d.ts b/typings/local.d.ts index 5244509f6f..e9244757b1 100644 --- a/typings/local.d.ts +++ b/typings/local.d.ts @@ -137,6 +137,11 @@ declare module 'decompress-maybe' { export = anything } +declare module 'nerf-dart' { + const anything: any + export = anything +} + declare module 'patch-package/dist/applyPatches' { export function applyPatch (opts: any): boolean }