Skip to content

Commit

Permalink
fix(@angular/cli): handle unscoped authentication details in .npmrc f…
Browse files Browse the repository at this point in the history
  • Loading branch information
alan-agius4 authored and clydin committed Jun 17, 2021
1 parent 86db1c9 commit 911b5e4
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 40 deletions.
54 changes: 33 additions & 21 deletions packages/angular/cli/src/commands/update/schematic/npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ const lockfile = require('@yarnpkg/lockfile');
const ini = require('ini');
const pacote = require('pacote');

type PackageManagerOptions = Record<string, unknown>;
interface PackageManagerOptions extends Record<string, unknown> {
forceAuth?: Record<string, unknown>;
}

const npmPackageJsonCache = new Map<string, Promise<Partial<NpmRepositoryPackageJson>>>();
let npmrc: PackageManagerOptions;
Expand All @@ -41,8 +43,8 @@ function readOptions(
}

const defaultConfigLocations = [
path.join(globalPrefix, 'etc', baseFilename),
path.join(homedir(), dotFilename),
(!yarn && process.env.NPM_CONFIG_GLOBALCONFIG) || path.join(globalPrefix, 'etc', baseFilename),
(!yarn && process.env.NPM_CONFIG_USERCONFIG) || path.join(homedir(), dotFilename),
];

const projectConfigLocations: string[] = [path.join(cwd, dotFilename)];
Expand All @@ -67,47 +69,57 @@ function readOptions(
// See: https://github.com/npm/npm-registry-fetch/blob/ebddbe78a5f67118c1f7af2e02c8a22bcaf9e850/index.js#L99-L126
const rcConfig: PackageManagerOptions = yarn ? lockfile.parse(data) : ini.parse(data);
for (const [key, value] of Object.entries(rcConfig)) {
let substitutedValue = value;

// Substitute any environment variable references.
if (typeof value === 'string') {
substitutedValue = value.replace(/\$\{([^\}]+)\}/, (_, name) => process.env[name] || '');
}

switch (key) {
// Unless auth options are scope with the registry url it appears that npm-registry-fetch ignores them,
// even though they are documented.
// https://github.com/npm/npm-registry-fetch/blob/8954f61d8d703e5eb7f3d93c9b40488f8b1b62ac/README.md
// https://github.com/npm/npm-registry-fetch/blob/8954f61d8d703e5eb7f3d93c9b40488f8b1b62ac/auth.js#L45-L91
case '_authToken':
case 'token':
case 'username':
case 'password':
case '_auth':
case 'auth':
options['forceAuth'] ??= {};
options['forceAuth'][key] = substitutedValue;
break;
case 'noproxy':
case 'no-proxy':
options['noProxy'] = value;
options['noProxy'] = substitutedValue;
break;
case 'maxsockets':
options['maxSockets'] = value;
options['maxSockets'] = substitutedValue;
break;
case 'https-proxy':
case 'proxy':
options['proxy'] = value;
options['proxy'] = substitutedValue;
break;
case 'strict-ssl':
options['strictSSL'] = value;
options['strictSSL'] = substitutedValue;
break;
case 'local-address':
options['localAddress'] = value;
options['localAddress'] = substitutedValue;
break;
case 'cafile':
if (typeof value === 'string') {
const cafile = path.resolve(path.dirname(location), value);
if (typeof substitutedValue === 'string') {
const cafile = path.resolve(path.dirname(location), substitutedValue);
try {
options['ca'] = readFileSync(cafile, 'utf8').replace(/\r?\n/g, '\n');
} catch {}
}
break;
default:
options[key] = value;
options[key] = substitutedValue;
break;
}
}
} else if (showPotentials) {
logger.info(`Trying '${location}'...not found.`);
}
}

// Substitute any environment variable references
for (const key in options) {
const value = options[key];
if (typeof value === 'string') {
options[key] = value.replace(/\$\{([^\}]+)\}/, (_, name) => process.env[name] || '');
}
}

Expand Down
50 changes: 31 additions & 19 deletions packages/angular/cli/utilities/package-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ export interface PackageMetadata {
'dist-tags'?: unknown;
}

type PackageManagerOptions = Record<string, unknown>;
interface PackageManagerOptions extends Record<string, unknown> {
forceAuth?: Record<string, unknown>;
}

let npmrc: PackageManagerOptions;

Expand Down Expand Up @@ -122,47 +124,57 @@ function readOptions(
// See: https://github.com/npm/npm-registry-fetch/blob/ebddbe78a5f67118c1f7af2e02c8a22bcaf9e850/index.js#L99-L126
const rcConfig: PackageManagerOptions = yarn ? lockfile.parse(data) : ini.parse(data);
for (const [key, value] of Object.entries(rcConfig)) {
let substitutedValue = value;

// Substitute any environment variable references.
if (typeof value === 'string') {
substitutedValue = value.replace(/\$\{([^\}]+)\}/, (_, name) => process.env[name] || '');
}

switch (key) {
// Unless auth options are scope with the registry url it appears that npm-registry-fetch ignores them,
// even though they are documented.
// https://github.com/npm/npm-registry-fetch/blob/8954f61d8d703e5eb7f3d93c9b40488f8b1b62ac/README.md
// https://github.com/npm/npm-registry-fetch/blob/8954f61d8d703e5eb7f3d93c9b40488f8b1b62ac/auth.js#L45-L91
case '_authToken':
case 'token':
case 'username':
case 'password':
case '_auth':
case 'auth':
options['forceAuth'] ??= {};
options['forceAuth'][key] = substitutedValue;
break;
case 'noproxy':
case 'no-proxy':
options['noProxy'] = value;
options['noProxy'] = substitutedValue;
break;
case 'maxsockets':
options['maxSockets'] = value;
options['maxSockets'] = substitutedValue;
break;
case 'https-proxy':
case 'proxy':
options['proxy'] = value;
options['proxy'] = substitutedValue;
break;
case 'strict-ssl':
options['strictSSL'] = value;
options['strictSSL'] = substitutedValue;
break;
case 'local-address':
options['localAddress'] = value;
options['localAddress'] = substitutedValue;
break;
case 'cafile':
if (typeof value === 'string') {
const cafile = path.resolve(path.dirname(location), value);
if (typeof substitutedValue === 'string') {
const cafile = path.resolve(path.dirname(location), substitutedValue);
try {
options['ca'] = readFileSync(cafile, 'utf8').replace(/\r?\n/g, '\n');
} catch {}
}
break;
default:
options[key] = value;
options[key] = substitutedValue;
break;
}
}
} else if (showPotentials) {
logger.info(`Trying '${location}'...not found.`);
}
}

// Substitute any environment variable references
for (const key in options) {
const value = options[key];
if (typeof value === 'string') {
options[key] = value.replace(/\$\{([^\}]+)\}/, (_, name) => process.env[name] || '');
}
}

Expand Down

0 comments on commit 911b5e4

Please sign in to comment.