Skip to content

Commit

Permalink
Fix scoped pkg auth when using npm private pkgs via npm login --scope
Browse files Browse the repository at this point in the history
  • Loading branch information
KidkArolis committed Jan 6, 2018
1 parent 3e1c3a7 commit a05fc91
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 70 deletions.
54 changes: 8 additions & 46 deletions __tests__/registries/npm-registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,69 +197,31 @@ describe('request', () => {

npmRegistry.config = {
'//some.other.registry/:_authToken': 'testScopedAuthToken',
'@testScope:registry': '//some.other.registry/',
'@testScope:registry': 'https://some.other.registry/',
};
npmRegistry.request(url);

const requestParams = mockRequestManager.request.mock.calls[0][0];

expect(requestParams.headers.authorization).toBe('Bearer testScopedAuthToken');
});
});

describe('isRequestToRegistry functional test', () => {
test('request to registry url matching', () => {
test('should add authorization header with token for default registry when using npm login --scope=@foo', () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);

const validRegistryUrls = [
['http://foo.bar:80/foo/bar/baz', 'http://foo.bar/foo/'],
['http://foo.bar:80/foo/bar/baz', 'https://foo.bar/foo/'],
['http://foo.bar/foo/bar/baz', 'http://foo.bar/foo/'],
['http://foo.bar/foo/00000000-1111-4444-8888-000000000000/baz', 'http://foo.bar/foo/'],
['https://foo.bar:443/foo/bar/baz', 'https://foo.bar/foo/'],
['http://foo.bar/foo/bar/baz', 'https://foo.bar:443/foo/'],
['https://foo.bar/foo/bar/baz', 'https://foo.bar:443/foo/'],
['HTTP://xn--xample-hva.com:80/foo/bar/baz', 'http://êxample.com/foo/bar/baz'],
];

const invalidRegistryUrls = [
['https://wrong.thing/foo/bar/baz', 'https://foo.bar/foo/'],
['https://foo.bar:1337/foo/bar/baz', 'https://foo.bar/foo/'],
];

validRegistryUrls.forEach(([requestUrl, registryUrl]) =>
expect(npmRegistry.isRequestToRegistry(requestUrl, registryUrl)).toBe(true),
);
invalidRegistryUrls.forEach(([requestUrl, registryUrl]) =>
expect(npmRegistry.isRequestToRegistry(requestUrl, registryUrl)).toBe(false),
);
});

test('isRequestToRegistry with custom host prefix', () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const url = 'https://npmjs.registry.org/@foo%2fyarn.tgz';

npmRegistry.config = {
'custom-host-suffix': 'some.host.org',
'//npmjs.registry.org/:_authToken': 'testScopedAuthToken',
'@foo:registry': 'https://npmjs.registry.org/',
};
npmRegistry.request(url);

expect(npmRegistry.isRequestToRegistry('http://pkgs.host.com:80/foo/bar/baz', 'http://pkgs.host.com/bar/baz')).toBe(
false,
);

npmRegistry.config = {
'custom-host-suffix': 'pkgs.host.com',
};
const requestParams = mockRequestManager.request.mock.calls[0][0];

expect(npmRegistry.isRequestToRegistry('http://pkgs.host.com:80/foo/bar/baz', 'http://pkgs.host.com/bar/baz')).toBe(
true,
);
expect(npmRegistry.isRequestToRegistry('http://pkgs.host.com:80/foo/bar/baz', '//pkgs.host.com/bar/baz')).toBe(
true,
);
expect(requestParams.headers.authorization).toBe('Bearer testScopedAuthToken');
});
});

Expand Down
43 changes: 19 additions & 24 deletions src/registries/npm-registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import envReplace from '../util/env-replace.js';
import Registry from './base-registry.js';
import {addSuffix} from '../util/misc';
import {getPosixPath, resolveWithHome} from '../util/path';
import normalizeUrl from 'normalize-url';
import {default as userHome, home} from '../util/user-home-dir';
import path from 'path';
import url from 'url';
Expand Down Expand Up @@ -99,32 +98,13 @@ export default class NpmRegistry extends Registry {
}
}

isRequestToRegistry(requestUrl: string, registryUrl: string): boolean {
const normalizedRequestUrl = normalizeUrl(requestUrl);
const normalizedRegistryUrl = normalizeUrl(registryUrl);
const requestParsed = url.parse(normalizedRequestUrl);
const registryParsed = url.parse(normalizedRegistryUrl);
const requestHost = requestParsed.host || '';
const registryHost = registryParsed.host || '';
const requestPath = requestParsed.path || '';
const registryPath = registryParsed.path || '';
const customHostSuffix = this.getRegistryOrGlobalOption(registryUrl, 'custom-host-suffix');

return (
requestHost === registryHost &&
(requestPath.startsWith(registryPath) ||
// For some registries, the package path does not prefix with the registry path
(typeof customHostSuffix === 'string' && requestHost.endsWith(customHostSuffix)))
);
}

request(pathname: string, opts?: RegistryRequestOptions = {}, packageName: ?string): Promise<*> {
// packageName needs to be escaped when if it is passed
const packageIdent = (packageName && NpmRegistry.escapeName(packageName)) || pathname;
const registry = this.getRegistry(packageIdent);
const requestUrl = this.getRequestUrl(registry, pathname);

const alwaysAuth = this.getRegistryOrGlobalOption(registry, 'always-auth');
const alwaysAuth = registry && this.getRegistryOrGlobalOption(registry, 'always-auth');

const headers = Object.assign(
{
Expand All @@ -133,10 +113,8 @@ export default class NpmRegistry extends Registry {
opts.headers,
);

const isToRegistry = this.isRequestToRegistry(requestUrl, registry);

// this.token must be checked to account for publish requests on non-scopped packages
if (this.token || (isToRegistry && (alwaysAuth || this.isScopedPackage(packageIdent)))) {
if (this.token || alwaysAuth || this.isScopedPackage(packageIdent)) {
const authorization = this.getAuth(packageIdent);
if (authorization) {
headers.authorization = authorization;
Expand Down Expand Up @@ -271,6 +249,7 @@ export default class NpmRegistry extends Registry {
if (registry) {
return String(registry);
}
return '';
}

for (const scope of [this.getScope(packageIdent), '']) {
Expand All @@ -290,6 +269,11 @@ export default class NpmRegistry extends Registry {
}

const baseRegistry = this.getRegistry(packageIdent);

if (!baseRegistry) {
return '';
}

const registries = [baseRegistry];

// If sending a request to the Yarn registry, we must also send it the auth token for the npm registry
Expand Down Expand Up @@ -346,4 +330,15 @@ export default class NpmRegistry extends Registry {
getRegistryOrGlobalOption(registry: string, option: string): mixed {
return this.getRegistryOption(registry, option) || this.getOption(option);
}

getAvailableRegistries(): Array<string> {
const availableRegistries = super.getAvailableRegistries();
if (availableRegistries.indexOf(YARN_REGISTRY) === -1) {
availableRegistries.push(YARN_REGISTRY);
}
if (availableRegistries.indexOf(DEFAULT_REGISTRY) === -1) {
availableRegistries.push(DEFAULT_REGISTRY);
}
return availableRegistries;
}
}

0 comments on commit a05fc91

Please sign in to comment.