mirror of
https://github.com/pnpm/pnpm.git
synced 2026-02-02 19:22:52 -05:00
fix: ignore always auth
This commit is contained in:
9
.changeset/breezy-owls-grin.md
Normal file
9
.changeset/breezy-owls-grin.md
Normal file
@@ -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.
|
||||
5
.changeset/modern-dodos-switch.md
Normal file
5
.changeset/modern-dodos-switch.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Ignore the always-auth setting.
|
||||
5
.changeset/olive-suns-hear.md
Normal file
5
.changeset/olive-suns-hear.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/network.auth-header": major
|
||||
---
|
||||
|
||||
Initial release.
|
||||
@@ -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<AuditReport>
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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:*",
|
||||
|
||||
@@ -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<ClientOptions, 'retry' | 'gitShallowHosts'>,
|
||||
customFetchers?: CustomFetchers
|
||||
): Fetchers {
|
||||
const defaultFetchers = {
|
||||
...createTarballFetcher(fetchFromRegistry, getCredentials, opts),
|
||||
...createTarballFetcher(fetchFromRegistry, getAuthHeader, opts),
|
||||
...createGitFetcher(opts),
|
||||
...createDirectoryFetcher(),
|
||||
}
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
{
|
||||
"path": "../git-fetcher"
|
||||
},
|
||||
{
|
||||
"path": "../network.auth-header"
|
||||
},
|
||||
{
|
||||
"path": "../resolver-base"
|
||||
},
|
||||
|
||||
@@ -103,8 +103,6 @@ export interface Config {
|
||||
tag?: string
|
||||
updateNotifier?: boolean
|
||||
|
||||
alwaysAuth?: boolean
|
||||
|
||||
// pnpm specific configs
|
||||
cacheDir: string
|
||||
configDir: string
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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)}`)
|
||||
}
|
||||
|
||||
@@ -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`)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -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) ??
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -13,7 +13,4 @@ export type FetchFromRegistry = (
|
||||
}
|
||||
) => Promise<Response>
|
||||
|
||||
export type GetCredentials = (registry: string) => {
|
||||
authHeaderValue: string | undefined
|
||||
alwaysAuth: boolean | undefined
|
||||
}
|
||||
export type GetAuthHeader = (uri: string) => string | undefined
|
||||
|
||||
15
packages/network.auth-header/README.md
Normal file
15
packages/network.auth-header/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# @pnpm/network.auth-header
|
||||
|
||||
> Gets the authorization header for the given URI
|
||||
|
||||
[](https://www.npmjs.com/package/@pnpm/network.auth-header)
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
pnpm add @pnpm/network.auth-header
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
3
packages/network.auth-header/jest.config.js
Normal file
3
packages/network.auth-header/jest.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
const config = require('../../jest.config.js');
|
||||
|
||||
module.exports = Object.assign({}, config, {});
|
||||
44
packages/network.auth-header/package.json
Normal file
44
packages/network.auth-header/package.json
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
71
packages/network.auth-header/src/getAuthHeadersFromConfig.ts
Normal file
71
packages/network.auth-header/src/getAuthHeadersFromConfig.ts
Normal file
@@ -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<string, string>
|
||||
userSettings: Record<string, string>
|
||||
}
|
||||
) {
|
||||
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()
|
||||
}
|
||||
33
packages/network.auth-header/src/index.ts
Normal file
33
packages/network.auth-header/src/index.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import nerfDart from 'nerf-dart'
|
||||
import { getAuthHeadersFromConfig } from './getAuthHeadersFromConfig'
|
||||
|
||||
export function createGetAuthHeaderByURI (
|
||||
opts: {
|
||||
allSettings: Record<string, string>
|
||||
userSettings?: Record<string, string>
|
||||
}
|
||||
) {
|
||||
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<string, string>, 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
|
||||
}
|
||||
19
packages/network.auth-header/test/getAuthHeaderByURI.ts
Normal file
19
packages/network.auth-header/test/getAuthHeaderByURI.ts
Normal file
@@ -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)
|
||||
})
|
||||
@@ -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')
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
echo Bearer token-from-spawn-errored
|
||||
exit /b 1
|
||||
@@ -0,0 +1 @@
|
||||
process.exit(1)
|
||||
1
packages/network.auth-header/test/utils/test-exec.bat
Normal file
1
packages/network.auth-header/test/utils/test-exec.bat
Normal file
@@ -0,0 +1 @@
|
||||
@echo Bearer token-from-spawn
|
||||
3
packages/network.auth-header/test/utils/test-exec.js
Executable file
3
packages/network.auth-header/test/utils/test-exec.js
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
console.log('Bearer token-from-spawn')
|
||||
16
packages/network.auth-header/tsconfig.json
Normal file
16
packages/network.auth-header/tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "@pnpm/tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"../../typings/**/*.d.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../error"
|
||||
}
|
||||
]
|
||||
}
|
||||
8
packages/network.auth-header/tsconfig.lint.json
Normal file
8
packages/network.auth-header/tsconfig.lint.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"test/**/*.ts",
|
||||
"../../typings/**/*.d.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,
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -29,8 +29,8 @@ const registry = 'https://registry.npmjs.org/'
|
||||
const delay = async (time: number) => new Promise<void>((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<T> (filePath: string) {
|
||||
let retry = 0
|
||||
|
||||
@@ -15,8 +15,8 @@ const badDatesMeta = loadJsonFile.sync<any>(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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
{
|
||||
"path": "../lockfile-file"
|
||||
},
|
||||
{
|
||||
"path": "../network.auth-header"
|
||||
},
|
||||
{
|
||||
"path": "../read-project-manifest"
|
||||
},
|
||||
|
||||
@@ -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: [],
|
||||
},
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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: [],
|
||||
},
|
||||
|
||||
@@ -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: [],
|
||||
},
|
||||
|
||||
@@ -123,7 +123,6 @@ export type OutdatedCommandOptions = {
|
||||
table?: boolean
|
||||
} & Pick<Config,
|
||||
| 'allProjects'
|
||||
| 'alwaysAuth'
|
||||
| 'ca'
|
||||
| 'cacheDir'
|
||||
| 'cert'
|
||||
|
||||
@@ -20,7 +20,6 @@ const withPnpmUpdateIgnore = path.join(fixtures, 'with-pnpm-update-ignore')
|
||||
const REGISTRY_URL = `http://localhost:${REGISTRY_MOCK_PORT}`
|
||||
|
||||
const OUTDATED_OPTIONS = {
|
||||
alwaysAuth: false,
|
||||
cacheDir: 'cache',
|
||||
fetchRetries: 1,
|
||||
fetchRetryFactor: 1,
|
||||
|
||||
@@ -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: [],
|
||||
},
|
||||
|
||||
@@ -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: [],
|
||||
},
|
||||
|
||||
@@ -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: [],
|
||||
},
|
||||
|
||||
@@ -3,7 +3,6 @@ import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
|
||||
export const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}`
|
||||
|
||||
export const DEFAULT_OPTS = {
|
||||
alwaysAuth: false,
|
||||
argv: {
|
||||
original: [],
|
||||
},
|
||||
|
||||
@@ -6,7 +6,6 @@ export const REGISTRY_URL = `http://localhost:${REGISTRY_MOCK_PORT}`
|
||||
const tmp = tempDir()
|
||||
|
||||
export const DEFAULT_OPTS = {
|
||||
alwaysAuth: false,
|
||||
argv: {
|
||||
original: [],
|
||||
},
|
||||
|
||||
@@ -17,7 +17,6 @@ async function main() {
|
||||
store,
|
||||
})
|
||||
const fetchers = createFetcher({
|
||||
alwaysAuth: true,
|
||||
registry,
|
||||
strictSsl: true,
|
||||
rawConfig,
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
import type { Cafs } from '@pnpm/cafs-types'
|
||||
import {
|
||||
FetchFromRegistry,
|
||||
GetCredentials,
|
||||
GetAuthHeader,
|
||||
RetryTimeoutOptions,
|
||||
} from '@pnpm/fetching-types'
|
||||
import {
|
||||
@@ -29,7 +29,7 @@ export interface TarballFetchers {
|
||||
|
||||
export function createTarballFetcher (
|
||||
fetchFromRegistry: FetchFromRegistry,
|
||||
getCredentials: GetCredentials,
|
||||
getAuthHeader: GetAuthHeader,
|
||||
opts: {
|
||||
timeout?: number
|
||||
retry?: RetryTimeoutOptions
|
||||
@@ -43,7 +43,7 @@ export function createTarballFetcher (
|
||||
|
||||
const remoteTarballFetcher = fetchFromTarball.bind(null, {
|
||||
download,
|
||||
getCredentialsByURI: getCredentials,
|
||||
getAuthHeaderByURI: getAuthHeader,
|
||||
offline: opts.offline,
|
||||
}) as FetchFunction
|
||||
|
||||
@@ -57,10 +57,7 @@ export function createTarballFetcher (
|
||||
async function fetchFromTarball (
|
||||
ctx: {
|
||||
download: DownloadFunction
|
||||
getCredentialsByURI: (registry: string) => {
|
||||
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,
|
||||
|
||||
@@ -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<FetchResult> {
|
||||
// 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<FetchResult> {
|
||||
try {
|
||||
const authHeaderValue = shouldAuth ? opts.auth?.authHeaderValue : undefined
|
||||
const res = await fetchFromRegistry(url, {
|
||||
authHeaderValue,
|
||||
// The fetch library can retry requests on bad HTTP responses.
|
||||
|
||||
@@ -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,
|
||||
|
||||
72
pnpm-lock.yaml
generated
72
pnpm-lock.yaml
generated
@@ -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'
|
||||
|
||||
5
typings/local.d.ts
vendored
5
typings/local.d.ts
vendored
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user