Skip to content

Commit

Permalink
deps: @npmcli/[email protected]
Browse files Browse the repository at this point in the history
  • Loading branch information
nlf authored and fritzy committed Oct 13, 2022
1 parent a35c784 commit cee3fd9
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 105 deletions.
22 changes: 22 additions & 0 deletions node_modules/@npmcli/config/lib/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict'

class ErrInvalidAuth extends Error {
constructor (problems) {
let message = 'Invalid auth configuration found: '
message += problems.map((problem) => {
if (problem.action === 'delete') {
return `\`${problem.key}\` is not allowed in ${problem.where} config`
} else if (problem.action === 'rename') {
return `\`${problem.from}\` must be renamed to \`${problem.to}\` in ${problem.where} config`
}
}).join(', ')
message += '\nPlease run `npm config fix` to repair your configuration.`'
super(message)
this.code = 'ERR_INVALID_AUTH'
this.problems = problems
}
}

module.exports = {
ErrInvalidAuth,
}
198 changes: 106 additions & 92 deletions node_modules/@npmcli/config/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ const parseField = require('./parse-field.js')
const typeDescription = require('./type-description.js')
const setEnvs = require('./set-envs.js')

const {
ErrInvalidAuth,
} = require('./errors.js')

// types that can be saved back to
const confFileTypes = new Set([
'global',
Expand Down Expand Up @@ -280,26 +284,10 @@ class Config {
await this.loadGlobalConfig()
process.emit('timeEnd', 'config:load:global')

// warn if anything is not valid
process.emit('time', 'config:load:validate')
this.validate()
process.emit('timeEnd', 'config:load:validate')

// set this before calling setEnvs, so that we don't have to share
// symbols, as that module also does a bunch of get operations
this[_loaded] = true

process.emit('time', 'config:load:credentials')
const reg = this.get('registry')
const creds = this.getCredentialsByURI(reg)
// ignore this error because a failed set will strip out anything that
// might be a security hazard, which was the intention.
try {
this.setCredentialsByURI(reg, creds)
// eslint-disable-next-line no-empty
} catch (_) {}
process.emit('timeEnd', 'config:load:credentials')

// set proper globalPrefix now that everything is loaded
this.globalPrefix = this.get('prefix')

Expand Down Expand Up @@ -399,15 +387,58 @@ class Config {
validate (where) {
if (!where) {
let valid = true
for (const [entryWhere] of this.data.entries()) {
const authProblems = []

for (const entryWhere of this.data.keys()) {
// no need to validate our defaults, we know they're fine
// cli was already validated when parsed the first time
if (entryWhere === 'default' || entryWhere === 'builtin' || entryWhere === 'cli') {
continue
}
const ret = this.validate(entryWhere)
valid = valid && ret

if (['global', 'user', 'project'].includes(entryWhere)) {
// after validating everything else, we look for old auth configs we no longer support
// if these keys are found, we build up a list of them and the appropriate action and
// attach it as context on the thrown error

// first, keys that should be removed
for (const key of ['_authtoken', '-authtoken']) {
if (this.get(key, entryWhere)) {
authProblems.push({ action: 'delete', key, where: entryWhere })
}
}

// NOTE we pull registry without restricting to the current 'where' because we want to
// suggest scoping things to the registry they would be applied to, which is the default
// regardless of where it was defined
const nerfedReg = nerfDart(this.get('registry'))
// keys that should be nerfed but currently are not
for (const key of ['_auth', '_authToken', 'username', '_password']) {
if (this.get(key, entryWhere)) {
// username and _password must both exist in the same file to be recognized correctly
if (key === 'username' && !this.get('_password', entryWhere)) {
authProblems.push({ action: 'delete', key, where: entryWhere })
} else if (key === '_password' && !this.get('username', entryWhere)) {
authProblems.push({ action: 'delete', key, where: entryWhere })
} else {
authProblems.push({
action: 'rename',
from: key,
to: `${nerfedReg}:${key}`,
where: entryWhere,
})
}
}
}
}
}

if (authProblems.length) {
throw new ErrInvalidAuth(authProblems)
}

return valid
} else {
const obj = this.data.get(where)
Expand All @@ -423,6 +454,40 @@ class Config {
}
}

// fixes problems identified by validate(), accepts the 'problems' property from a thrown
// ErrInvalidAuth to avoid having to check everything again
repair (problems) {
if (!problems) {
try {
this.validate()
} catch (err) {
// coverage skipped here because we don't need to test re-throwing an error
// istanbul ignore next
if (err.code !== 'ERR_INVALID_AUTH') {
throw err
}

problems = err.problems
} finally {
if (!problems) {
problems = []
}
}
}

for (const problem of problems) {
// coverage disabled for else branch because it doesn't do anything and shouldn't
// istanbul ignore else
if (problem.action === 'delete') {
this.delete(problem.key, problem.where)
} else if (problem.action === 'rename') {
const old = this.get(problem.from, problem.where)
this.set(problem.to, old, problem.where)
this.delete(problem.from, problem.where)
}
}
}

// Returns true if the value is coming directly from the source defined
// in default definitions, if the current value for the key config is
// coming from any other different source, returns false
Expand Down Expand Up @@ -644,21 +709,19 @@ class Config {
if (!confFileTypes.has(where)) {
throw new Error('invalid config location param: ' + where)
}

const conf = this.data.get(where)
conf[_raw] = { ...conf.data }
conf[_loadError] = null

// upgrade auth configs to more secure variants before saving
if (where === 'user') {
const reg = this.get('registry')
const creds = this.getCredentialsByURI(reg)
// we ignore this error because the failed set already removed
// anything that might be a security hazard, and it won't be
// saved back to the .npmrc file, so we're good.
try {
this.setCredentialsByURI(reg, creds)
// eslint-disable-next-line no-empty
} catch (_) {}
// if email is nerfed, then we want to de-nerf it
const nerfed = nerfDart(this.get('registry'))
const email = this.get(`${nerfed}:email`, 'user')
if (email) {
this.delete(`${nerfed}:email`, 'user')
this.set('email', email, 'user')
}
}

const iniData = ini.stringify(conf.data).trim() + '\n'
Expand Down Expand Up @@ -686,14 +749,17 @@ class Config {
const nerfed = nerfDart(uri)
const def = nerfDart(this.get('registry'))
if (def === nerfed) {
// do not delete email, that shouldn't be nerfed any more.
// just delete the nerfed copy, if one exists.
this.delete(`-authtoken`, 'user')
this.delete(`_authToken`, 'user')
this.delete(`_authtoken`, 'user')
this.delete(`_auth`, 'user')
this.delete(`_password`, 'user')
this.delete(`username`, 'user')
// de-nerf email if it's nerfed to the default registry
const email = this.get(`${nerfed}:email`, 'user')
if (email) {
this.set('email', email, 'user')
}
}
this.delete(`${nerfed}:_authToken`, 'user')
this.delete(`${nerfed}:_auth`, 'user')
Expand All @@ -706,28 +772,9 @@ class Config {

setCredentialsByURI (uri, { token, username, password, email, certfile, keyfile }) {
const nerfed = nerfDart(uri)
const def = nerfDart(this.get('registry'))

if (def === nerfed) {
// remove old style auth info not limited to a single registry
this.delete('_password', 'user')
this.delete('username', 'user')
this.delete('_auth', 'user')
this.delete('_authtoken', 'user')
this.delete('-authtoken', 'user')
this.delete('_authToken', 'user')
}

// email used to be nerfed always. if we're using the default
// registry, de-nerf it.
if (nerfed === def) {
email = email ||
this.get('email', 'user') ||
this.get(`${nerfed}:email`, 'user')
if (email) {
this.set('email', email, 'user')
}
}
// email is either provided, a top level key, or nothing
email = email || this.get('email', 'user')

// field that hasn't been used as documented for a LONG time,
// and as of npm 7.10.0, isn't used at all. We just always
Expand Down Expand Up @@ -765,15 +812,17 @@ class Config {
// this has to be a bit more complicated to support legacy data of all forms
getCredentialsByURI (uri) {
const nerfed = nerfDart(uri)
const def = nerfDart(this.get('registry'))
const creds = {}

const deprecatedAuthWarning = [
'`_auth`, `_authToken`, `username` and `_password` must be scoped to a registry.',
'see `npm help npmrc` for more information.',
].join(' ')

// email is handled differently, it used to always be nerfed and now it never should be
// if it's set nerfed to the default registry, then we copy it to the unnerfed key
// TODO: evaluate removing 'email' from the credentials object returned here
const email = this.get(`${nerfed}:email`) || this.get('email')
if (email) {
if (nerfed === def) {
this.set('email', email, 'user')
}
creds.email = email
}

Expand All @@ -785,13 +834,8 @@ class Config {
// cert/key may be used in conjunction with other credentials, thus no `return`
}

const defaultToken = nerfDart(this.get('registry')) && this.get('_authToken')
const tokenReg = this.get(`${nerfed}:_authToken`) || defaultToken

const tokenReg = this.get(`${nerfed}:_authToken`)
if (tokenReg) {
if (tokenReg === defaultToken) {
log.warn('config', deprecatedAuthWarning)
}
creds.token = tokenReg
return creds
}
Expand All @@ -816,37 +860,7 @@ class Config {
return creds
}

// at this point, we can only use the values if the URI is the
// default registry.
const defaultNerf = nerfDart(this.get('registry'))
if (nerfed !== defaultNerf) {
return creds
}

const userDef = this.get('username')
const passDef = this.get('_password')
if (userDef && passDef) {
log.warn('config', deprecatedAuthWarning)
creds.username = userDef
creds.password = Buffer.from(passDef, 'base64').toString('utf8')
const auth = `${creds.username}:${creds.password}`
creds.auth = Buffer.from(auth, 'utf8').toString('base64')
return creds
}

// Handle the old-style _auth=<base64> style for the default
// registry, if set.
const auth = this.get('_auth')
if (!auth) {
return creds
}

log.warn('config', deprecatedAuthWarning)
const authDecode = Buffer.from(auth, 'base64').toString('utf8')
const authSplit = authDecode.split(':')
creds.username = authSplit.shift()
creds.password = authSplit.join(':')
creds.auth = auth
// at this point, nothing else is usable so just return what we do have
return creds
}

Expand Down
17 changes: 9 additions & 8 deletions node_modules/@npmcli/config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@npmcli/config",
"version": "4.2.2",
"version": "5.0.0",
"files": [
"bin/",
"lib/"
Expand All @@ -16,9 +16,6 @@
"scripts": {
"test": "tap",
"snap": "tap",
"preversion": "npm test",
"postversion": "npm publish",
"prepublishOnly": "git push origin --follow-tags",
"lint": "eslint \"**/*.js\"",
"postlint": "template-oss-check",
"lintfix": "npm run lint -- --fix",
Expand All @@ -27,11 +24,15 @@
},
"tap": {
"check-coverage": true,
"coverage-map": "map.js"
"coverage-map": "map.js",
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
]
},
"devDependencies": {
"@npmcli/eslint-config": "^3.0.1",
"@npmcli/template-oss": "3.6.0",
"@npmcli/template-oss": "4.5.0",
"tap": "^16.0.1"
},
"dependencies": {
Expand All @@ -45,10 +46,10 @@
"walk-up-path": "^1.0.0"
},
"engines": {
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
},
"templateOSS": {
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
"version": "3.6.0"
"version": "4.5.0"
}
}
9 changes: 5 additions & 4 deletions package-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
"@isaacs/string-locale-compare": "^1.1.0",
"@npmcli/arborist": "^6.0.0-pre.4",
"@npmcli/ci-detect": "^3.0.0",
"@npmcli/config": "^4.2.1",
"@npmcli/config": "^5.0.0",
"@npmcli/fs": "^2.1.0",
"@npmcli/map-workspaces": "^2.0.3",
"@npmcli/package-json": "^2.0.0",
Expand Down Expand Up @@ -2164,9 +2164,10 @@
}
},
"node_modules/@npmcli/config": {
"version": "4.2.2",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@npmcli/config/-/config-5.0.0.tgz",
"integrity": "sha512-TfJ3IRw5eKtzvzCxWbmy74KfO1ikKoWr2oPzpugo3RqSneAF/PNFZuSAuubvyv5qKjAj0hU4BC7VI2o3eOAT2A==",
"inBundle": true,
"license": "ISC",
"dependencies": {
"@npmcli/map-workspaces": "^2.0.2",
"ini": "^3.0.0",
Expand All @@ -2178,7 +2179,7 @@
"walk-up-path": "^1.0.0"
},
"engines": {
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
"node_modules/@npmcli/disparity-colors": {
Expand Down
Loading

0 comments on commit cee3fd9

Please sign in to comment.