Skip to content

Commit

Permalink
Use de-figged npm-profile
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacs committed May 8, 2020
1 parent 3ae22b2 commit a982571
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 90 deletions.
10 changes: 5 additions & 5 deletions lib/adduser.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ try {

adduser.usage = usage(
'adduser',
'npm adduser [--registry=url] [--scope=@orgname] [--auth-type=legacy] [--always-auth]'
'npm adduser [--registry=url] [--scope=@orgname] [--always-auth]'
)

function adduser (args, cb) {
Expand All @@ -21,9 +21,9 @@ function adduser (args, cb) {
))
}

let registry = npm.config.get('registry')
const scope = npm.config.get('scope')
const creds = npm.config.getCredentialsByURI(npm.config.get('registry'))
let registry = npm.flatOptions.registry
const scope = npm.flatOptions.scope
const creds = npm.config.getCredentialsByURI(registry)

if (scope) {
const scopedRegistry = npm.config.get(scope + ':registry')
Expand All @@ -35,7 +35,7 @@ function adduser (args, cb) {

let auth
try {
auth = require('./auth/' + npm.config.get('auth-type'))
auth = require('./auth/' + npm.flatOptions.authType)
} catch (e) {
return cb(new Error('no such auth module'))
}
Expand Down
20 changes: 8 additions & 12 deletions lib/auth/legacy.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
const read = require('../utils/read-user-info.js')
const profile = require('npm-profile')
const log = require('npmlog')
const figgyPudding = require('figgy-pudding')
const npmConfig = require('../config/figgy-config.js')
const npm = require('../npm.js')
const output = require('../utils/output.js')
const openUrl = require('../utils/open-url')

Expand All @@ -26,16 +25,13 @@ const loginPrompter = (creds) => {
})
}

const LoginOpts = figgyPudding({
'always-auth': {},
creds: {},
log: {default: () => log},
registry: {},
scope: {}
})

module.exports.login = (creds = {}, registry, scope, cb) => {
const opts = LoginOpts(npmConfig()).concat({scope, registry, creds})
const opts = {
...npm.flatOptions,
scope,
registry,
creds
}
login(opts).then((newCreds) => cb(null, newCreds)).catch(cb)
}

Expand Down Expand Up @@ -66,7 +62,7 @@ function login (opts) {
newCreds.username = opts.creds.username
newCreds.password = opts.creds.password
newCreds.email = opts.creds.email
newCreds.alwaysAuth = opts['always-auth']
newCreds.alwaysAuth = opts.alwaysAuth
}

const usermsg = opts.creds.username ? ' user ' + opts.creds.username : ''
Expand Down
33 changes: 16 additions & 17 deletions lib/auth/sso.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
'use strict'

const BB = require('bluebird')
// XXX: To date, npm Enterprise Legacy is the only system that ever
// implemented support for this type of login. A better way to do
// SSO is to use the WebLogin type of login supported by the npm-login
// module. This more forward-looking login style is, ironically,
// supported by the '--auth-type=legacy' type of login.
// When and if npm Enterprise Legacy is no longer supported by the npm
// CLI, we can remove this, and fold the lib/auth/legacy.js back into
// lib/adduser.js

const figgyPudding = require('figgy-pudding')
const log = require('npmlog')
const npmConfig = require('../config/figgy-config.js')
const npm = require('../npm.js')
const npmFetch = require('npm-registry-fetch')
const output = require('../utils/output.js')
const openUrl = BB.promisify(require('../utils/open-url.js'))
const { promisify } = require('util')
const openUrl = promisify(require('../utils/open-url.js'))
const otplease = require('../utils/otplease.js')
const profile = require('npm-profile')

const SsoOpts = figgyPudding({
ssoType: 'sso-type',
'sso-type': {},
ssoPollFrequency: 'sso-poll-frequency',
'sso-poll-frequency': {}
})

module.exports.login = function login (creds, registry, scope, cb) {
const opts = SsoOpts(npmConfig()).concat({creds, registry, scope})
log.warn('deprecated', 'SSO --auth-type is deprecated')
const opts = { ...npm.flatOptions, creds, registry, scope }
const ssoType = opts.ssoType
if (!ssoType) { return cb(new Error('Missing option: sso-type')) }

Expand Down Expand Up @@ -51,12 +52,12 @@ module.exports.login = function login (creds, registry, scope, cb) {
function pollForSession (registry, token, opts) {
log.info('adduser', 'Polling for validated SSO session')
return npmFetch.json(
'/-/whoami', opts.concat({registry, forceAuth: {token}})
'/-/whoami', { ...opts, registry, forceAuth: { token } }
).then(
({username}) => username,
err => {
if (err.code === 'E401') {
return sleep(opts['sso-poll-frequency']).then(() => {
return sleep(opts.ssoPollFrequency).then(() => {
return pollForSession(registry, token, opts)
})
} else {
Expand All @@ -67,7 +68,5 @@ function pollForSession (registry, token, opts) {
}

function sleep (time) {
return new BB((resolve) => {
setTimeout(resolve, time)
})
return new Promise((resolve) => setTimeout(resolve, time))
}
2 changes: 2 additions & 0 deletions lib/config/flat-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ const flatOptions = npm => npm.flatOptions || Object.freeze({
audit: npm.config.get('audit'),
auditLevel: npm.config.get('audit-level'),
authType: npm.config.get('auth-type'),
ssoType: npm.config.get('sso-type'),
ssoPollFrequency: npm.config.get('sso-poll-frequency'),
before: npm.config.get('before'),
browser: npm.config.get('browser'),
ca: npm.config.get('ca'),
Expand Down
2 changes: 1 addition & 1 deletion lib/npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@

config.set('scope', scopeifyScope(config.get('scope')))
npm.projectScope = config.get('scope') ||
scopeifyScope(getProjectScope(npm.prefix))
scopeifyScope(getProjectScope(npm.prefix))

startMetrics()

Expand Down
30 changes: 11 additions & 19 deletions lib/profile.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
'use strict'

const BB = require('bluebird')

const ansistyles = require('ansistyles')
const figgyPudding = require('figgy-pudding')
const inspect = require('util').inspect
const log = require('npmlog')
const npm = require('./npm.js')
Expand Down Expand Up @@ -53,13 +50,6 @@ function withCb (prom, cb) {
prom.then((value) => cb(null, value), cb)
}

const ProfileOpts = figgyPudding({
json: {},
otp: {},
parseable: {},
registry: {}
})

function profileCmd (args, cb) {
if (args.length === 0) return cb(new Error(profileCmd.usage))
log.gauge.show('profile')
Expand Down Expand Up @@ -93,7 +83,7 @@ const knownProfileKeys = qw`

function get (args) {
const tfa = 'two-factor auth'
const conf = ProfileOpts(npmConfig())
const conf = npm.flatOptions
return pulseTillDone.withPromise(profile.get(conf)).then((info) => {
if (!info.cidr_whitelist) delete info.cidr_whitelist
if (conf.json) {
Expand Down Expand Up @@ -139,7 +129,7 @@ const writableProfileKeys = qw`
email password fullname homepage freenode twitter github`

function set (args) {
let conf = ProfileOpts(npmConfig())
const conf = npm.flatOptions
const prop = (args[0] || '').toLowerCase().trim()
let value = args.length > 1 ? args.slice(1).join(' ') : null
if (prop !== 'password' && value === null) {
Expand All @@ -153,7 +143,7 @@ function set (args) {
if (writableProfileKeys.indexOf(prop) === -1) {
return Promise.reject(Error(`"${prop}" is not a property we can set. Valid properties are: ` + writableProfileKeys.join(', ')))
}
return BB.try(() => {
return Promise.resolve().then(() => {
if (prop === 'password') {
return readUserInfo.password('Current password: ').then((current) => {
return readPasswords().then((newpassword) => {
Expand Down Expand Up @@ -209,7 +199,7 @@ function enable2fa (args) {
' auth-only - Require two-factor authentication only when logging in\n' +
' auth-and-writes - Require two-factor authentication when logging in AND when publishing'))
}
const conf = ProfileOpts(npmConfig())
const conf = npm.flatOptions
if (conf.json || conf.parseable) {
return Promise.reject(new Error(
'Enabling two-factor authentication is an interactive operation and ' +
Expand All @@ -222,7 +212,7 @@ function enable2fa (args) {
}
}

return BB.try(() => {
return Promise.resolve().then(() => {
// if they're using legacy auth currently then we have to update them to a
// bearer token before continuing.
const auth = getAuth(conf)
Expand All @@ -233,7 +223,9 @@ function enable2fa (args) {
).then((result) => {
if (!result.token) throw new Error('Your registry ' + conf.registry + 'does not seem to support bearer tokens. Bearer tokens are required for two-factor authentication')
npm.config.setCredentialsByURI(conf.registry, {token: result.token})
return BB.fromNode((cb) => npm.config.save('user', cb))
return new Promise((res, rej) => {
npm.config.save('user', er => er ? rej(er) : res())
})
})
}
}).then(() => {
Expand Down Expand Up @@ -301,17 +293,17 @@ function getAuth (conf) {
}

function disable2fa (args) {
let conf = ProfileOpts(npmConfig())
let conf = npm.flatOptions
return pulseTillDone.withPromise(profile.get(conf)).then((info) => {
if (!info.tfa || info.tfa.pending) {
output('Two factor authentication not enabled.')
return
}
return readUserInfo.password().then((password) => {
return BB.try(() => {
return Promise.resolve().then(() => {
if (conf.otp) return
return readUserInfo.otp('Enter one-time password from your authenticator: ').then((otp) => {
conf = conf.concat({otp})
conf = { ...conf, otp }
})
}).then(() => {
log.info('profile', 'disabling tfa')
Expand Down
53 changes: 17 additions & 36 deletions lib/token.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@

const profile = require('npm-profile')
const npm = require('./npm.js')
const figgyPudding = require('figgy-pudding')
const npmConfig = require('./config/figgy-config.js')
const output = require('./utils/output.js')
const otplease = require('./utils/otplease.js')
const Table = require('cli-table3')
const Bluebird = require('bluebird')
const isCidrV4 = require('is-cidr').v4
const isCidrV6 = require('is-cidr').v6
const readUserInfo = require('./utils/read-user-info.js')
Expand Down Expand Up @@ -80,44 +77,28 @@ function generateTokenIds (tokens, minLength) {
return byId
}

const TokenConfig = figgyPudding({
auth: {},
registry: {},
otp: {},
cidr: {},
'read-only': {},
json: {},
parseable: {}
})

function config () {
let conf = TokenConfig(npmConfig())
const conf = { ...npm.flatOptions }
const creds = npm.config.getCredentialsByURI(conf.registry)
if (creds.token) {
conf = conf.concat({
auth: { token: creds.token }
})
conf.auth = { token: creds.token }
} else if (creds.username) {
conf = conf.concat({
auth: {
basic: {
username: creds.username,
password: creds.password
}
conf.auth = {
basic: {
username: creds.username,
password: creds.password
}
})
}
} else if (creds.auth) {
const auth = Buffer.from(creds.auth, 'base64').toString().split(':', 2)
conf = conf.concat({
auth: {
basic: {
username: auth[0],
password: auth[1]
}
conf.auth = {
basic: {
username: auth[0],
password: auth[1]
}
})
}
} else {
conf = conf.concat({ auth: {} })
conf.auth = {}
}
if (conf.otp) conf.auth.otp = conf.otp
return conf
Expand Down Expand Up @@ -176,7 +157,7 @@ function rm (args) {
if (matches.length === 1) {
toRemove.push(matches[0].key)
} else if (matches.length > 1) {
throw new Error(`Token ID "${id}" was ambiguous, a new token may have been created since you last ran \`npm-profile token list\`.`)
throw new Error(`Token ID "${id}" was ambiguous, a new token may have been created since you last ran \`npm token list\`.`)
} else {
const tokenMatches = tokens.filter((token) => id.indexOf(token.token) === 0)
if (tokenMatches === 0) {
Expand All @@ -185,11 +166,11 @@ function rm (args) {
toRemove.push(id)
}
})
return Bluebird.map(toRemove, (key) => {
return Promise.all(toRemove.map(key => {
return otplease(conf, conf => {
return profile.removeToken(key, conf)
})
})
}))
})).then(() => {
if (conf.json) {
output(JSON.stringify(toRemove))
Expand All @@ -204,7 +185,7 @@ function rm (args) {
function create (args) {
const conf = config()
const cidr = conf.cidr
const readonly = conf['read-only']
const readonly = conf.readOnly

const validCIDR = validateCIDRList(cidr)
return readUserInfo.password().then((password) => {
Expand Down

0 comments on commit a982571

Please sign in to comment.