diff --git a/CHANGELOG.md b/CHANGELOG.md index c45b7398fa..32f46dfc15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Please add one entry in this file for each change in Yarn's behavior. Use the sa ## Master +- Enforces https for the Yarn and npm registries. + + [#7393](https://github.com/yarnpkg/yarn/pull/7393) - [**Maël Nison**](https://twitter.com/arcanis) + - Adds support for reading `yarnPath` from v2-produced `.yarnrc.yml` files. [#7350](https://github.com/yarnpkg/yarn/pull/7350) - [**Maël Nison**](https://twitter.com/arcanis) diff --git a/__tests__/registries/npm-registry.js b/__tests__/registries/npm-registry.js index b5177b7719..54ade142a0 100644 --- a/__tests__/registries/npm-registry.js +++ b/__tests__/registries/npm-registry.js @@ -781,6 +781,30 @@ describe('getRequestUrl functional test', () => { expect(npmRegistry.getRequestUrl(registry, pathname)).toEqual('https://my.registry.co/registry/foo/bar/baz'); }); + + for (const host of [`registry.yarnpkg.com`, `registry.npmjs.org`, `registry.npmjs.com`]) { + test(`enforces loading packages through https when they come from ${host}`, () => { + const testCwd = '.'; + const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); + const registry = `http://${host}/registry`; + const pathname = 'foo/bar/baz'; + + expect(npmRegistry.getRequestUrl(registry, pathname)).toEqual(`https://${host}/registry/foo/bar/baz`); + }); + } + + test("doesn't change the protocol for packages from other registries", () => { + const testCwd = '.'; + const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); + const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []); + const registry = 'http://registry.mylittlepony.org/registry'; + const pathname = 'foo/bar/baz'; + + expect(npmRegistry.getRequestUrl(registry, pathname)).toEqual( + 'http://registry.mylittlepony.org/registry/foo/bar/baz', + ); + }); }); describe('getScope functional test', () => { diff --git a/src/registries/npm-registry.js b/src/registries/npm-registry.js index f1fb3786b7..083b8c1bab 100644 --- a/src/registries/npm-registry.js +++ b/src/registries/npm-registry.js @@ -22,6 +22,7 @@ import url from 'url'; import ini from 'ini'; const DEFAULT_REGISTRY = 'https://registry.npmjs.org/'; +const REGEX_REGISTRY_ENFORCED_HTTPS = /^https?:\/\/([^\/]+\.)?(yarnpkg\.com|npmjs\.(org|com))(\/|$)/; const REGEX_REGISTRY_HTTP_PROTOCOL = /^https?:/i; const REGEX_REGISTRY_PREFIX = /^(https?:)?\/\//i; const REGEX_REGISTRY_SUFFIX = /registry\/?$/; @@ -112,13 +113,17 @@ export default class NpmRegistry extends Registry { } getRequestUrl(registry: string, pathname: string): string { - const isUrl = REGEX_REGISTRY_PREFIX.test(pathname); + let resolved = pathname; - if (isUrl) { - return pathname; - } else { - return url.resolve(addSuffix(registry, '/'), pathname); + if (!REGEX_REGISTRY_PREFIX.test(pathname)) { + resolved = url.resolve(addSuffix(registry, '/'), pathname); } + + if (REGEX_REGISTRY_ENFORCED_HTTPS.test(resolved)) { + resolved = resolved.replace(/^http:\/\//, 'https://'); + } + + return resolved; } isRequestToRegistry(requestUrl: string, registryUrl: string): boolean {