From a7efb693995c769c3aa1776701eb86b8f06de096 Mon Sep 17 00:00:00 2001 From: Wei Wei Date: Fri, 20 Jan 2017 03:05:29 +0800 Subject: [PATCH 1/4] Fix issue 2505 --- src/fetchers/base-fetcher.js | 1 + src/fetchers/tarball-fetcher.js | 2 +- src/registries/npm-registry.js | 71 +++++++++++++++--------- src/resolvers/registries/npm-resolver.js | 1 + src/types.js | 1 + 5 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/fetchers/base-fetcher.js b/src/fetchers/base-fetcher.js index 824844d628..22d0ecfcd9 100644 --- a/src/fetchers/base-fetcher.js +++ b/src/fetchers/base-fetcher.js @@ -13,6 +13,7 @@ const path = require('path'); export default class BaseFetcher { constructor(dest: string, remote: PackageRemote, config: Config) { this.reporter = config.reporter; + this.packageName = remote.packageName; this.reference = remote.reference; this.registry = remote.registry; this.hash = remote.hash; diff --git a/src/fetchers/tarball-fetcher.js b/src/fetchers/tarball-fetcher.js index 40084323bc..f3f200de8b 100644 --- a/src/fetchers/tarball-fetcher.js +++ b/src/fetchers/tarball-fetcher.js @@ -198,7 +198,7 @@ export default class TarballFetcher extends BaseFetcher { .on('error', reject); } }, - }); + }, this.packageName); } _fetch(): Promise { diff --git a/src/registries/npm-registry.js b/src/registries/npm-registry.js index 16c213c49b..6300b76d11 100644 --- a/src/registries/npm-registry.js +++ b/src/registries/npm-registry.js @@ -8,7 +8,7 @@ import * as fs from '../util/fs.js'; import NpmResolver from '../resolvers/registries/npm-resolver.js'; import envReplace from '../util/env-replace.js'; import Registry from './base-registry.js'; -import {addSuffix, removePrefix} from '../util/misc'; +import {addSuffix} from '../util/misc'; const defaults = require('defaults'); const userHome = require('user-home'); @@ -17,6 +17,8 @@ const url = require('url'); const ini = require('ini'); const DEFAULT_REGISTRY = 'https://registry.npmjs.org/'; +const REGEX_REGISTRY_PREFIX = /^https?:/; +const REGEX_REGISTRY_SUFFIX = /registry\/?$/; function getGlobalPrefix(): string { if (process.env.PREFIX) { @@ -50,16 +52,14 @@ export default class NpmRegistry extends Registry { return name.replace('/', '%2f'); } - request(pathname: string, opts?: RegistryRequestOptions = {}): Promise<*> { - const registry = addSuffix(this.getRegistry(pathname), '/'); + request(pathname: string, opts?: RegistryRequestOptions = {}, packageName?: string): Promise<*> { + const registry = addSuffix(this.getRegistry(packageName || pathname), '/'); const requestUrl = url.resolve(registry, pathname); - const alwaysAuth = this.getScopedOption(registry.replace(/^https?:/, ''), 'always-auth') - || this.getOption('always-auth') - || removePrefix(requestUrl, registry)[0] === '@'; + const alwaysAuth = this.getRegistryOrGlobalOption(registry, 'always-auth'); const headers = {}; - if (this.token || (alwaysAuth && requestUrl.startsWith(registry))) { - const authorization = this.getAuth(pathname); + if (this.token || alwaysAuth) { + const authorization = this.getAuth(packageName || pathname); if (authorization) { headers.authorization = authorization; } @@ -172,28 +172,26 @@ export default class NpmRegistry extends Registry { return this.token; } - for (let registry of [this.getRegistry(packageName), '', DEFAULT_REGISTRY]) { - registry = registry.replace(/^https?:/, ''); + const registry = this.getRegistry(packageName); - // Check for bearer token. - let auth = this.getScopedOption(registry.replace(/\/?$/, '/'), '_authToken'); - if (auth) { - return `Bearer ${String(auth)}`; - } + // Check for bearer token. + const authToken = this.getRegistryOrGlobalOption(registry, '_authToken'); + if (authToken) { + return `Bearer ${String(authToken)}`; + } - // Check for basic auth token. - auth = this.getScopedOption(registry, '_auth'); - if (auth) { - return `Basic ${String(auth)}`; - } + // Check for basic auth token. + const auth = this.getRegistryOrGlobalOption(registry, '_auth'); + if (auth) { + return `Basic ${String(auth)}`; + } - // Check for basic username/password auth. - const username = this.getScopedOption(registry, 'username'); - const password = this.getScopedOption(registry, '_password'); - if (username && password) { - const pw = new Buffer(String(password), 'base64').toString(); - return 'Basic ' + new Buffer(String(username) + ':' + pw).toString('base64'); - } + // Check for basic username/password auth. + const username = this.getRegistryOrGlobalOption(registry, 'username'); + const password = this.getRegistryOrGlobalOption(registry, '_password'); + if (username && password) { + const pw = new Buffer(String(password), 'base64').toString(); + return 'Basic ' + new Buffer(String(username) + ':' + pw).toString('base64'); } return ''; @@ -202,4 +200,23 @@ export default class NpmRegistry extends Registry { getScopedOption(scope: string, option: string): mixed { return this.getOption(scope + (scope ? ':' : '') + option); } + + getRegistryOption(registry: string, option: string): mixed { + const pre = REGEX_REGISTRY_PREFIX; + const suf = REGEX_REGISTRY_SUFFIX; + + // When registry is used config scope, the trailing '/' is required + const reg = addSuffix(registry, '/'); + + // 1st attempt, try to get option for the given registry URL + // 2nd attempt, remove the 'https?:' prefix of the registry URL + // 3nd attempt, remove the 'registry/?' suffix of the registry URL + return this.getScopedOption(reg, option) + || reg.match(pre) && this.getRegistryOption(reg.replace(pre, ''), option) + || reg.match(suf) && this.getRegistryOption(reg.replace(suf, ''), option); + } + + getRegistryOrGlobalOption(registry: string, option: string): mixed { + return this.getRegistryOption(registry, option) || this.getOption(option); + } } diff --git a/src/resolvers/registries/npm-resolver.js b/src/resolvers/registries/npm-resolver.js index 621c31c011..bcf76c83c8 100644 --- a/src/resolvers/registries/npm-resolver.js +++ b/src/resolvers/registries/npm-resolver.js @@ -189,6 +189,7 @@ export default class NpmResolver extends RegistryResolver { reference: this.cleanRegistry(dist.tarball), hash: dist.shasum, registry: 'npm', + packageName: info.name, }; } diff --git a/src/types.js b/src/types.js index 7e548b2621..86ecf517d2 100644 --- a/src/types.js +++ b/src/types.js @@ -42,6 +42,7 @@ export type PackageRemote = { reference: string, resolved?: ?string, hash: ?string, + packageName: ?string, }; // `dependencies` field in package info From c700b097c0437d17302c76e4e15ea7946862a7c9 Mon Sep 17 00:00:00 2001 From: Wei Wei Date: Fri, 20 Jan 2017 03:46:20 +0800 Subject: [PATCH 2/4] Fix flow check --- src/fetchers/base-fetcher.js | 1 + src/registries/npm-registry.js | 2 +- src/types.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/fetchers/base-fetcher.js b/src/fetchers/base-fetcher.js index 22d0ecfcd9..47f90a959d 100644 --- a/src/fetchers/base-fetcher.js +++ b/src/fetchers/base-fetcher.js @@ -25,6 +25,7 @@ export default class BaseFetcher { reporter: Reporter; remote: PackageRemote; registry: RegistryNames; + packageName: ?string; reference: string; config: Config; hash: ?string; diff --git a/src/registries/npm-registry.js b/src/registries/npm-registry.js index 6300b76d11..6f02b0827d 100644 --- a/src/registries/npm-registry.js +++ b/src/registries/npm-registry.js @@ -52,7 +52,7 @@ export default class NpmRegistry extends Registry { return name.replace('/', '%2f'); } - request(pathname: string, opts?: RegistryRequestOptions = {}, packageName?: string): Promise<*> { + request(pathname: string, opts?: RegistryRequestOptions = {}, packageName: ?string): Promise<*> { const registry = addSuffix(this.getRegistry(packageName || pathname), '/'); const requestUrl = url.resolve(registry, pathname); const alwaysAuth = this.getRegistryOrGlobalOption(registry, 'always-auth'); diff --git a/src/types.js b/src/types.js index 86ecf517d2..10010d634f 100644 --- a/src/types.js +++ b/src/types.js @@ -42,7 +42,7 @@ export type PackageRemote = { reference: string, resolved?: ?string, hash: ?string, - packageName: ?string, + packageName?: string, }; // `dependencies` field in package info From 8ca4cfa3f8b89767b47df22ec3150988a2d3477d Mon Sep 17 00:00:00 2001 From: "Wei Wei (BINGADS)" Date: Sat, 21 Jan 2017 22:47:35 -0800 Subject: [PATCH 3/4] Fix test errors --- .../install-from-authed-private-registry-no-slash/.npmrc | 1 + .../install/install-from-authed-private-registry/.npmrc | 1 + src/registries/npm-registry.js | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/__tests__/fixtures/install/install-from-authed-private-registry-no-slash/.npmrc b/__tests__/fixtures/install/install-from-authed-private-registry-no-slash/.npmrc index d64920ea68..729940e72b 100644 --- a/__tests__/fixtures/install/install-from-authed-private-registry-no-slash/.npmrc +++ b/__tests__/fixtures/install/install-from-authed-private-registry-no-slash/.npmrc @@ -1,2 +1,3 @@ //registry.yarnpkg.com/:_authToken=abc123 +//registry.yarnpkg.com/:always-auth=true @types:registry=https://registry.yarnpkg.com diff --git a/__tests__/fixtures/install/install-from-authed-private-registry/.npmrc b/__tests__/fixtures/install/install-from-authed-private-registry/.npmrc index c86299f566..e2d18acf7c 100644 --- a/__tests__/fixtures/install/install-from-authed-private-registry/.npmrc +++ b/__tests__/fixtures/install/install-from-authed-private-registry/.npmrc @@ -1,2 +1,3 @@ //registry.yarnpkg.com/:_authToken=abc123 +//registry.yarnpkg.com/:always-auth=true @types:registry=https://registry.yarnpkg.com/ diff --git a/src/registries/npm-registry.js b/src/registries/npm-registry.js index 6f02b0827d..6d09b4f8d4 100644 --- a/src/registries/npm-registry.js +++ b/src/registries/npm-registry.js @@ -53,7 +53,7 @@ export default class NpmRegistry extends Registry { } request(pathname: string, opts?: RegistryRequestOptions = {}, packageName: ?string): Promise<*> { - const registry = addSuffix(this.getRegistry(packageName || pathname), '/'); + const registry = this.getRegistry(packageName || pathname); const requestUrl = url.resolve(registry, pathname); const alwaysAuth = this.getRegistryOrGlobalOption(registry, 'always-auth'); @@ -152,7 +152,7 @@ export default class NpmRegistry extends Registry { const availableRegistries = this.getAvailableRegistries(); const registry = availableRegistries.find((registry) => packageName.startsWith(registry)); if (registry) { - return registry; + return addSuffix(registry, '/'); } } @@ -160,7 +160,7 @@ export default class NpmRegistry extends Registry { const registry = this.getScopedOption(scope, 'registry') || this.registries.yarn.getScopedOption(scope, 'registry'); if (registry) { - return String(registry); + return addSuffix(String(registry), '/'); } } From 50fee44571a868adef69cdb8ae05193f52e436c1 Mon Sep 17 00:00:00 2001 From: "Wei Wei (BINGADS)" Date: Wed, 1 Mar 2017 18:20:20 -0800 Subject: [PATCH 4/4] Fix test errors --- __tests__/package-resolver.js | 2 +- src/registries/is-request-to-registry.js | 13 ++++++++++--- src/registries/npm-registry.js | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/__tests__/package-resolver.js b/__tests__/package-resolver.js index b624bfd9b2..3e46b6d836 100644 --- a/__tests__/package-resolver.js +++ b/__tests__/package-resolver.js @@ -10,7 +10,7 @@ import * as fs from '../src/util/fs.js'; import * as constants from '../src/constants.js'; import inquirer from 'inquirer'; -jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000; +jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000; // automatically chose the first available version if cached does not fit inquirer.prompt = jest.fn((questions) => { diff --git a/src/registries/is-request-to-registry.js b/src/registries/is-request-to-registry.js index c6748bada4..b84650cc18 100644 --- a/src/registries/is-request-to-registry.js +++ b/src/registries/is-request-to-registry.js @@ -2,18 +2,25 @@ import url from 'url'; +const SUFFIX_VISUALSTUDIO = '.pkgs.visualstudio.com'; + export default function isRequestToRegistry(requestUrl: string, registry: string): boolean { const requestParsed = url.parse(requestUrl); const registryParsed = url.parse(registry); + const requestHost = requestParsed.hostname || ''; + const registryHost = registryParsed.hostname || ''; const requestPort = getPortOrDefaultPort(requestParsed.port, requestParsed.protocol); const registryPort = getPortOrDefaultPort(registryParsed.port, registryParsed.protocol); const requestPath = requestParsed.path || ''; const registryPath = registryParsed.path || ''; return (requestParsed.protocol === registryParsed.protocol) && - (requestParsed.hostname === registryParsed.hostname) && - (requestPort === registryPort) && - requestPath.startsWith(registryPath); + (requestHost === registryHost) && + (requestPort === registryPort) && ( + requestPath.startsWith(registryPath) || + // For pkgs.visualstudio.com, the package path does not prefix with the registry path + requestHost.endsWith(SUFFIX_VISUALSTUDIO) + ); } function getPortOrDefaultPort(port: ?string, protocol: ?string): ?string { diff --git a/src/registries/npm-registry.js b/src/registries/npm-registry.js index 623490203a..1069bcf346 100644 --- a/src/registries/npm-registry.js +++ b/src/registries/npm-registry.js @@ -8,7 +8,7 @@ import * as fs from '../util/fs.js'; import NpmResolver from '../resolvers/registries/npm-resolver.js'; import envReplace from '../util/env-replace.js'; import Registry from './base-registry.js'; -import {addSuffix, removePrefix} from '../util/misc'; +import {addSuffix} from '../util/misc'; import isRequestToRegistry from './is-request-to-registry.js'; const userHome = require('../util/user-home-dir').default;