diff --git a/config.json b/config.json index 1fd5a99b9..c122e9f36 100644 --- a/config.json +++ b/config.json @@ -160,5 +160,16 @@ } } } + }, + "keys": { + "npm": [ + { + "expires": null, + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==" + } + ] } -} +} \ No newline at end of file diff --git a/sources/corepackUtils.ts b/sources/corepackUtils.ts index bf14c3d17..2be5d9ac9 100644 --- a/sources/corepackUtils.ts +++ b/sources/corepackUtils.ts @@ -1,4 +1,4 @@ -import {createHash, createVerify, webcrypto} from 'crypto'; +import {createHash, createVerify} from 'crypto'; import {once} from 'events'; import {FileHandle} from 'fs/promises'; import fs from 'fs'; @@ -8,6 +8,8 @@ import path from 'path'; import semver from 'semver'; import {setTimeout as setTimeoutPromise} from 'timers/promises'; +import defaultConfig from '../config.json'; + import * as engine from './Engine'; import * as debugUtils from './debugUtils'; import * as folderUtils from './folderUtils'; @@ -23,8 +25,6 @@ export function getRegistryFromPackageManagerSpec(spec: PackageManagerSpec) { : spec.registry; } -type NpmSignatureKey = {"expires": null, "keyid": string, "keytype": string, "scheme": string, "key": string}; - export async function fetchLatestStableVersion(spec: RegistrySpec): Promise { switch (spec.type) { case `npm`: { @@ -244,8 +244,8 @@ export async function installVersion(installTarget: string, locator: Locator, {s if (registry.type === `npm` && !process.env.COREPACK_NPM_REGISTRY) { if (signatures! == null || integrity! == null) ({signatures, integrity} = (await npmRegistryUtils.fetchTarballURLAndSignature(registry.package, version))); - const {keys} = await httpUtils.fetchAsJson(new URL(`/-/npm/v1/keys`, process.env.COREPACK_NPM_REGISTRY || npmRegistryUtils.DEFAULT_NPM_REGISTRY_URL)); - const key: NpmSignatureKey | undefined = keys.find(({keyid}: NpmSignatureKey) => signatures.some(s => s.keyid === keyid)); + const {npm: keys} = defaultConfig.keys; + const key = keys.find(({keyid}) => signatures.some(s => s.keyid === keyid)); const signature = signatures.find(({keyid}) => keyid === key?.keyid); switch (key?.keytype) { case `ecdsa-sha2-nistp256`: { @@ -265,6 +265,7 @@ export async function installVersion(installTarget: string, locator: Locator, {s default: throw new Error(`Unsupported signature key`, {cause: key}); } + // @ts-expect-error ignore readonly build[1] = Buffer.from(integrity.slice(`sha512-`.length), `base64`).toString(`hex`); } } diff --git a/sources/types.ts b/sources/types.ts index 20d66233e..78808c89a 100644 --- a/sources/types.ts +++ b/sources/types.ts @@ -96,6 +96,10 @@ export interface Config { }; }; }; + + keys: { + [registry: string]: Array<{"expires": null, "keyid": string, "keytype": string, "scheme": string, "key": string}>; + }; } /** diff --git a/tests/config.test.ts b/tests/config.test.ts new file mode 100644 index 000000000..c6a512d04 --- /dev/null +++ b/tests/config.test.ts @@ -0,0 +1,14 @@ +import {jest, describe, it, expect} from '@jest/globals'; + +import defaultConfig from '../config.json'; +import {DEFAULT_NPM_REGISTRY_URL} from '../sources/npmRegistryUtils'; + +jest.mock(`../sources/httpUtils`); + +describe(`key store should be up-to-date`, () => { + it(`should contain up-to-date npm keys`, async () => { + const r = await globalThis.fetch(new URL(`/-/npm/v1/keys`, DEFAULT_NPM_REGISTRY_URL)); + expect(r.ok).toBe(true); + expect(r.json()).resolves.toMatchObject({keys: defaultConfig.keys.npm}); + }); +});