Files
pnpm/network/auth-header/test/getAuthHeaderByURI.ts
Zoltan Kochan 45a6cb6b2a refactor(auth): unify auth/SSL into structured configByUri (#11201)
Replaces the dual `authConfig` (raw .npmrc) + `authInfos` (parsed auth) + `sslConfigs` (parsed SSL) pattern with a single structured `configByUri: Record<string, RegistryConfig>` field on Config.

### New types (`@pnpm/types`)
- **`RegistryConfig`** — per-registry config: `{ creds?: Creds, tls?: TlsConfig }`
- **`Creds`** — auth credentials: `{ authToken?, basicAuth?, tokenHelper? }`
- **`TlsConfig`** — TLS config: `{ cert?, key?, ca? }`

### Key changes
- Rewrite `createGetAuthHeaderByURI` to accept `Record<string, RegistryConfig>` instead of raw .npmrc key-value pairs
- Eliminate duplicate auth parsing between `getAuthHeadersFromConfig` and `getNetworkConfigs`
- Remove `authConfig` from the install pipeline (`StrictInstallOptions`, `HeadlessOptions`), replaced by `configByUri`
- Remove `sslConfigs` from Config — SSL fields now live in `configByUri[uri].tls`
- Remove `authConfig['registry']` mutation in `extendInstallOptions` (default registry now passed directly to `createGetAuthHeaderByURI`)
- `authConfig` remains on Config only for raw .npmrc access (config commands, error reporting, config inheritance)

### Security
- tokenHelper in project .npmrc now throws instead of being silently stripped
- tokenHelper execution uses `shell: false` to prevent shell metacharacter injection
- Basic auth uses `Buffer.from().toString('base64')` instead of `btoa()` for Unicode safety
- Dispatcher only creates custom agents when entries actually have TLS fields
2026-04-05 20:15:10 +02:00

86 lines
4.9 KiB
TypeScript

import { createGetAuthHeaderByURI } from '@pnpm/network.auth-header'
const configByUri = {
'//reg.com/': { creds: { authToken: 'abc123' } },
'//reg.co/tarballs/': { creds: { authToken: 'xxx' } },
'//reg.gg:8888/': { creds: { authToken: '0000' } },
'//custom.domain.com/artifactory/api/npm/npm-virtual/': { creds: { authToken: 'xyz' } },
}
test('getAuthHeaderByURI()', () => {
const getAuthHeaderByURI = createGetAuthHeaderByURI(configByUri)
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.com:8080/foo/-/foo-1.0.0.tgz')).toBe('Bearer abc123')
expect(getAuthHeaderByURI('https://reg.io/foo/-/foo-1.0.0.tgz')).toBeUndefined()
expect(getAuthHeaderByURI('https://reg.co/tarballs/foo/-/foo-1.0.0.tgz')).toBe('Bearer xxx')
expect(getAuthHeaderByURI('https://reg.gg:8888/foo/-/foo-1.0.0.tgz')).toBe('Bearer 0000')
expect(getAuthHeaderByURI('https://reg.gg:8888/foo/-/foo-1.0.0.tgz')).toBe('Bearer 0000')
})
test('getAuthHeaderByURI() basic auth without settings', () => {
const getAuthHeaderByURI = createGetAuthHeaderByURI({})
expect(getAuthHeaderByURI('https://user:secret@reg.io/')).toBe('Basic ' + btoa('user:secret'))
expect(getAuthHeaderByURI('https://user:@reg.io/')).toBe('Basic ' + btoa('user:'))
expect(getAuthHeaderByURI('https://:secret@reg.io/')).toBe('Basic ' + btoa(':secret'))
expect(getAuthHeaderByURI('https://user@reg.io/')).toBe('Basic ' + btoa('user:'))
})
test('getAuthHeaderByURI() basic auth with settings', () => {
const getAuthHeaderByURI = createGetAuthHeaderByURI(configByUri)
expect(getAuthHeaderByURI('https://user:secret@reg.com/')).toBe('Basic ' + btoa('user:secret'))
expect(getAuthHeaderByURI('https://user:secret@reg.com/foo/-/foo-1.0.0.tgz')).toBe('Basic ' + btoa('user:secret'))
expect(getAuthHeaderByURI('https://user:secret@reg.com:8080/foo/-/foo-1.0.0.tgz')).toBe('Basic ' + btoa('user:secret'))
expect(getAuthHeaderByURI('https://user:secret@reg.io/foo/-/foo-1.0.0.tgz')).toBe('Basic ' + btoa('user:secret'))
expect(getAuthHeaderByURI('https://user:secret@reg.co/tarballs/foo/-/foo-1.0.0.tgz')).toBe('Basic ' + btoa('user:secret'))
expect(getAuthHeaderByURI('https://user:secret@reg.gg:8888/foo/-/foo-1.0.0.tgz')).toBe('Basic ' + btoa('user:secret'))
expect(getAuthHeaderByURI('https://user:secret@reg.gg:8888/foo/-/foo-1.0.0.tgz')).toBe('Basic ' + btoa('user:secret'))
})
test('getAuthHeaderByURI() https port 443 checks', () => {
const getAuthHeaderByURI = createGetAuthHeaderByURI(configByUri)
expect(getAuthHeaderByURI('https://custom.domain.com:443/artifactory/api/npm/npm-virtual/')).toBe('Bearer xyz')
expect(getAuthHeaderByURI('https://custom.domain.com:443/artifactory/api/npm/')).toBeUndefined()
expect(getAuthHeaderByURI('https://custom.domain.com:443/artifactory/api/npm/-/@platform/device-utils-1.0.0.tgz')).toBeUndefined()
expect(getAuthHeaderByURI('https://custom.domain.com:443/artifactory/api/npm/npm-virtual/@platform/device-utils/-/@platform/device-utils-1.0.0.tgz')).toBe('Bearer xyz')
})
test('getAuthHeaderByURI() when default ports are specified', () => {
const getAuthHeaderByURI = createGetAuthHeaderByURI({
'//reg.com/': { creds: { authToken: 'abc123' } },
})
expect(getAuthHeaderByURI('https://reg.com:443/')).toBe('Bearer abc123')
expect(getAuthHeaderByURI('http://reg.com:80/')).toBe('Bearer abc123')
})
test('returns undefined when the auth header is not found', () => {
expect(createGetAuthHeaderByURI({})('http://reg.com')).toBeUndefined()
})
test('getAuthHeaderByURI() when the registry has pathnames', () => {
const getAuthHeaderByURI = createGetAuthHeaderByURI({
'//npm.pkg.github.com/pnpm/': { creds: { authToken: 'abc123' } },
})
expect(getAuthHeaderByURI('https://npm.pkg.github.com/pnpm')).toBe('Bearer abc123')
expect(getAuthHeaderByURI('https://npm.pkg.github.com/pnpm/')).toBe('Bearer abc123')
expect(getAuthHeaderByURI('https://npm.pkg.github.com/pnpm/foo')).toBe('Bearer abc123')
expect(getAuthHeaderByURI('https://npm.pkg.github.com/pnpm/foo/')).toBe('Bearer abc123')
expect(getAuthHeaderByURI('https://npm.pkg.github.com/pnpm/foo/-/foo-1.0.0.tgz')).toBe('Bearer abc123')
})
test('getAuthHeaderByURI() with default registry auth', () => {
const getAuthHeaderByURI = createGetAuthHeaderByURI(
{ '': { creds: { authToken: 'default-token' } } },
'https://registry.npmjs.org/'
)
expect(getAuthHeaderByURI('https://registry.npmjs.org/')).toBe('Bearer default-token')
expect(getAuthHeaderByURI('https://registry.npmjs.org/foo/-/foo-1.0.0.tgz')).toBe('Bearer default-token')
})
test('getAuthHeaderByURI() with basic auth via basicAuth', () => {
const getAuthHeaderByURI = createGetAuthHeaderByURI({
'//reg.com/': { creds: { basicAuth: { username: 'user', password: 'pass' } } },
})
expect(getAuthHeaderByURI('https://reg.com/')).toBe('Basic ' + btoa('user:pass'))
})