/// import path from 'path' import { createFetchFromRegistry } from '@pnpm/fetch' import nock from 'nock' import { ProxyServer } from 'https-proxy-server-express' import fs from 'fs' const CERTS_DIR = path.join(import.meta.dirname, '__certs__') afterEach(() => { nock.cleanAll() }) test('fetchFromRegistry', async () => { const fetchFromRegistry = createFetchFromRegistry({}) const res = await fetchFromRegistry('https://registry.npmjs.org/is-positive') const metadata = await res.json() as any // eslint-disable-line expect(metadata.name).toBe('is-positive') expect(metadata.versions['1.0.0'].scripts).not.toBeTruthy() }) test('fetchFromRegistry fullMetadata', async () => { const fetchFromRegistry = createFetchFromRegistry({}) const res = await fetchFromRegistry('https://registry.npmjs.org/is-positive', { fullMetadata: true }) const metadata = await res.json() as any // eslint-disable-line expect(metadata.name).toBe('is-positive') expect(metadata.versions['1.0.0'].scripts).toBeTruthy() }) test('authorization headers are removed before redirection if the target is on a different host', async () => { nock('http://registry.pnpm.io/', { reqheaders: { authorization: 'Bearer 123' }, }) .get('/is-positive') .reply(302, '', { location: 'http://registry.other.org/is-positive' }) nock('http://registry.other.org/', { badheaders: ['authorization'] }) .get('/is-positive') .reply(200, { ok: true }) const fetchFromRegistry = createFetchFromRegistry({}) const res = await fetchFromRegistry( 'http://registry.pnpm.io/is-positive', { authHeaderValue: 'Bearer 123' } ) expect(await res.json()).toStrictEqual({ ok: true }) expect(nock.isDone()).toBeTruthy() }) test('authorization headers are not removed before redirection if the target is on the same host', async () => { nock('http://registry.pnpm.io/', { reqheaders: { authorization: 'Bearer 123' }, }) .get('/is-positive') .reply(302, '', { location: 'http://registry.pnpm.io/is-positive-new' }) nock('http://registry.pnpm.io/', { reqheaders: { authorization: 'Bearer 123' }, }) .get('/is-positive-new') .reply(200, { ok: true }) const fetchFromRegistry = createFetchFromRegistry({}) const res = await fetchFromRegistry( 'http://registry.pnpm.io/is-positive', { authHeaderValue: 'Bearer 123' } ) expect(await res.json()).toStrictEqual({ ok: true }) expect(nock.isDone()).toBeTruthy() }) test('switch to the correct agent for requests on redirect from http: to https:', async () => { const fetchFromRegistry = createFetchFromRegistry({}) // We can test this on any endpoint that redirects from http: to https: const { status } = await fetchFromRegistry('http://pnpm.io/pnpm.js') expect(status).toBe(200) }) test('fetch from registry with client certificate authentication', async () => { const randomPort = Math.floor(Math.random() * 10000 + 10000) const proxyServer = new ProxyServer(randomPort, { key: fs.readFileSync(path.join(CERTS_DIR, 'server-key.pem')), cert: fs.readFileSync(path.join(CERTS_DIR, 'server-crt.pem')), ca: fs.readFileSync(path.join(CERTS_DIR, 'ca-crt.pem')), rejectUnauthorized: true, requestCert: true, }, 'https://registry.npmjs.org/') await proxyServer.start() const sslConfigs = { [`//localhost:${randomPort}/`]: { ca: fs.readFileSync(path.join(CERTS_DIR, 'ca-crt.pem'), 'utf8'), cert: fs.readFileSync(path.join(CERTS_DIR, 'client-crt.pem'), 'utf8'), key: fs.readFileSync(path.join(CERTS_DIR, 'client-key.pem'), 'utf8'), }, } const fetchFromRegistry = createFetchFromRegistry({ sslConfigs, strictSsl: false, }) try { const res = await fetchFromRegistry(`https://localhost:${randomPort}/is-positive`) const metadata = await res.json() as any // eslint-disable-line expect(metadata.name).toBe('is-positive') } finally { await proxyServer.stop() } }) test('fail if the client certificate is not provided', async () => { const randomPort = Math.floor(Math.random() * 10000 + 10000) const proxyServer = new ProxyServer(randomPort, { key: fs.readFileSync(path.join(CERTS_DIR, 'server-key.pem')), cert: fs.readFileSync(path.join(CERTS_DIR, 'server-crt.pem')), ca: fs.readFileSync(path.join(CERTS_DIR, 'ca-crt.pem')), rejectUnauthorized: true, requestCert: true, }, 'https://registry.npmjs.org/') await proxyServer.start() const fetchFromRegistry = createFetchFromRegistry({ strictSsl: false, }) let err!: Error & { code: string } try { await fetchFromRegistry(`https://localhost:${randomPort}/is-positive`, { retry: { retries: 0, }, }) } catch (_err: any) { // eslint-disable-line err = _err } finally { await proxyServer.stop() } expect(err?.code).toMatch(/ECONNRESET|ERR_SSL_TLSV13_ALERT_CERTIFICATE_REQUIRED/) }) test('redirect to protocol-relative URL', async () => { nock('http://registry.pnpm.io/') .get('/foo') .reply(302, '', { location: '//registry.other.org/foo' }) nock('http://registry.other.org/') .get('/foo') .reply(200, { ok: true }) const fetchFromRegistry = createFetchFromRegistry({}) const res = await fetchFromRegistry( 'http://registry.pnpm.io/foo' ) expect(await res.json()).toStrictEqual({ ok: true }) expect(nock.isDone()).toBeTruthy() }) test('redirect to relative URL', async () => { nock('http://registry.pnpm.io/') .get('/bar/baz') .reply(302, '', { location: '../foo' }) nock('http://registry.pnpm.io/') .get('/foo') .reply(200, { ok: true }) const fetchFromRegistry = createFetchFromRegistry({}) const res = await fetchFromRegistry( 'http://registry.pnpm.io/bar/baz' ) expect(await res.json()).toStrictEqual({ ok: true }) expect(nock.isDone()).toBeTruthy() }) test('redirect to relative URL when request pkg.pr.new link', async () => { nock('https://pkg.pr.new/') .get('/vue@14175') .reply(302, '', { location: '/vuejs/core/vue@14182' }) nock('https://pkg.pr.new/') .get('/vuejs/core/vue@14182') .reply(302, '', { location: '/vuejs/core/vue@82a13bb6faaa9f77a06b57e69e0934b9f620f333' }) nock('https://pkg.pr.new/') .get('/vuejs/core/vue@82a13bb6faaa9f77a06b57e69e0934b9f620f333') .reply(200, { ok: true }) const fetchFromRegistry = createFetchFromRegistry({}) const res = await fetchFromRegistry( 'https://pkg.pr.new/vue@14175' ) expect(await res.json()).toStrictEqual({ ok: true }) expect(nock.isDone()).toBeTruthy() }) test('redirect without location header throws error', async () => { nock('http://registry.pnpm.io/') .get('/missing-location') .reply(302, 'found') const fetchFromRegistry = createFetchFromRegistry({}) await expect(fetchFromRegistry( 'http://registry.pnpm.io/missing-location' )).rejects.toThrow(/Redirect location header missing/) })