Skip to content

Commit

Permalink
fix: run input.start around help and openining urls
Browse files Browse the repository at this point in the history
This also refactors auth and prompt related files to use
promises and new npm-profile behavior
  • Loading branch information
lukekarrys committed May 2, 2024
1 parent 4cbc2d4 commit 261ea19
Show file tree
Hide file tree
Showing 31 changed files with 459 additions and 571 deletions.
2 changes: 1 addition & 1 deletion lib/commands/access.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const npa = require('npm-package-arg')
const { output } = require('proc-log')
const pkgJson = require('@npmcli/package-json')
const localeCompare = require('@isaacs/string-locale-compare')('en')
const otplease = require('../utils/otplease.js')
const { otplease } = require('../utils/auth.js')
const getIdentity = require('../utils/get-identity.js')
const BaseCommand = require('../base-cmd.js')

Expand Down
2 changes: 1 addition & 1 deletion lib/commands/deprecate.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const fetch = require('npm-registry-fetch')
const otplease = require('../utils/otplease.js')
const { otplease } = require('../utils/auth.js')
const npa = require('npm-package-arg')
const semver = require('semver')
const getIdentity = require('../utils/get-identity.js')
Expand Down
2 changes: 1 addition & 1 deletion lib/commands/dist-tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const npa = require('npm-package-arg')
const regFetch = require('npm-registry-fetch')
const semver = require('semver')
const { log, output } = require('proc-log')
const otplease = require('../utils/otplease.js')
const { otplease } = require('../utils/auth.js')
const pkgJson = require('@npmcli/package-json')
const BaseCommand = require('../base-cmd.js')

Expand Down
3 changes: 1 addition & 2 deletions lib/commands/fund.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ const { output } = require('proc-log')
const npa = require('npm-package-arg')
const { depth } = require('treeverse')
const { readTree: getFundingInfo, normalizeFunding, isValidFunding } = require('libnpmfund')

const openUrl = require('../utils/open-url.js')
const { openUrl } = require('../utils/open-url.js')
const ArboristWorkspaceCmd = require('../arborist-cmd.js')

const getPrintableName = ({ name, version }) => {
Expand Down
10 changes: 6 additions & 4 deletions lib/commands/help.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const spawn = require('@npmcli/promise-spawn')
const path = require('path')
const openUrl = require('../utils/open-url.js')
const { openUrl } = require('../utils/open-url.js')
const { glob } = require('glob')
const { output } = require('proc-log')
const { output, input } = require('proc-log')
const localeCompare = require('@isaacs/string-locale-compare')('en')
const { deref } = require('../utils/cmd-list.js')
const BaseCommand = require('../base-cmd.js')
Expand Down Expand Up @@ -95,13 +95,15 @@ class Help extends BaseCommand {
args = ['emacsclient', ['-e', `(woman-find-file '${man}')`]]
}

return spawn(...args, { stdio: 'inherit' }).catch(err => {
try {
await input.start(() => spawn(...args, { stdio: 'inherit' }))
} catch (err) {
if (err.code) {
throw new Error(`help process exited with code: ${err.code}`)
} else {
throw err
}
})
}
}

// Returns the path to the html version of the man page
Expand Down
2 changes: 1 addition & 1 deletion lib/commands/hook.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const hookApi = require('libnpmhook')
const otplease = require('../utils/otplease.js')
const { otplease } = require('../utils/auth.js')
const relativeDate = require('tiny-relative-date')
const { output } = require('proc-log')
const BaseCommand = require('../base-cmd.js')
Expand Down
2 changes: 1 addition & 1 deletion lib/commands/org.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const liborg = require('libnpmorg')
const otplease = require('../utils/otplease.js')
const { otplease } = require('../utils/auth.js')
const BaseCommand = require('../base-cmd.js')
const { output } = require('proc-log')

Expand Down
2 changes: 1 addition & 1 deletion lib/commands/owner.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const npa = require('npm-package-arg')
const npmFetch = require('npm-registry-fetch')
const pacote = require('pacote')
const { log, output } = require('proc-log')
const otplease = require('../utils/otplease.js')
const { otplease } = require('../utils/auth.js')
const pkgJson = require('@npmcli/package-json')
const BaseCommand = require('../base-cmd.js')
const { redact } = require('@npmcli/redact')
Expand Down
24 changes: 12 additions & 12 deletions lib/commands/profile.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const { inspect } = require('util')
const { URL } = require('url')
const { log, output } = require('proc-log')
const npmProfile = require('npm-profile')
const { get, set, createToken } = require('npm-profile')
const qrcodeTerminal = require('qrcode-terminal')
const otplease = require('../utils/otplease.js')
const { otplease } = require('../utils/auth.js')
const readUserInfo = require('../utils/read-user-info.js')
const BaseCommand = require('../base-cmd.js')

Expand Down Expand Up @@ -101,7 +101,7 @@ class Profile extends BaseCommand {

async get (args) {
const tfa = 'two-factor auth'
const info = await npmProfile.get({ ...this.npm.flatOptions })
const info = await get({ ...this.npm.flatOptions })

if (!info.cidr_whitelist) {
delete info.cidr_whitelist
Expand Down Expand Up @@ -199,7 +199,7 @@ class Profile extends BaseCommand {
}

// FIXME: Work around to not clear everything other than what we're setting
const user = await npmProfile.get(conf)
const user = await get(conf)
const newUser = {}

for (const key of writableProfileKeys) {
Expand All @@ -208,7 +208,7 @@ class Profile extends BaseCommand {

newUser[prop] = value

const result = await otplease(this.npm, conf, c => npmProfile.set(newUser, c))
const result = await otplease(this.npm, conf, c => set(newUser, c))

if (this.npm.config.get('json')) {
output.standard(JSON.stringify({ [prop]: result[prop] }, null, 2))
Expand Down Expand Up @@ -273,7 +273,7 @@ class Profile extends BaseCommand {

if (auth.basic) {
log.info('profile', 'Updating authentication to bearer token')
const result = await npmProfile.createToken(
const result = await createToken(
auth.basic.password, false, [], { ...this.npm.flatOptions }
)

Expand All @@ -297,12 +297,12 @@ class Profile extends BaseCommand {
info.tfa.password = password

log.info('profile', 'Determine if tfa is pending')
const userInfo = await npmProfile.get({ ...this.npm.flatOptions })
const userInfo = await get({ ...this.npm.flatOptions })

const conf = { ...this.npm.flatOptions }
if (userInfo && userInfo.tfa && userInfo.tfa.pending) {
log.info('profile', 'Resetting two-factor authentication')
await npmProfile.set({ tfa: { password, mode: 'disable' } }, conf)
await set({ tfa: { password, mode: 'disable' } }, conf)
} else if (userInfo && userInfo.tfa) {
if (!conf.otp) {
conf.otp = await readUserInfo.otp(
Expand All @@ -312,7 +312,7 @@ class Profile extends BaseCommand {
}

log.info('profile', 'Setting two-factor authentication to ' + mode)
const challenge = await npmProfile.set(info, conf)
const challenge = await set(info, conf)

if (challenge.tfa === null) {
output.standard('Two factor authentication mode changed to: ' + mode)
Expand Down Expand Up @@ -341,7 +341,7 @@ class Profile extends BaseCommand {

log.info('profile', 'Finalizing two-factor authentication')

const result = await npmProfile.set({ tfa: [interactiveOTP] }, conf)
const result = await set({ tfa: [interactiveOTP] }, conf)

output.standard(
'2FA successfully enabled. Below are your recovery codes, ' +
Expand All @@ -359,7 +359,7 @@ class Profile extends BaseCommand {

async disable2fa () {
const conf = { ...this.npm.flatOptions }
const info = await npmProfile.get(conf)
const info = await get(conf)

if (!info.tfa || info.tfa.pending) {
output.standard('Two factor authentication not enabled.')
Expand All @@ -375,7 +375,7 @@ class Profile extends BaseCommand {

log.info('profile', 'disabling tfa')

await npmProfile.set({ tfa: { password: password, mode: 'disable' } }, conf)
await set({ tfa: { password: password, mode: 'disable' } }, conf)

if (this.npm.config.get('json')) {
output.standard(JSON.stringify({ tfa: false }, null, 2))
Expand Down
2 changes: 1 addition & 1 deletion lib/commands/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const pacote = require('pacote')
const npa = require('npm-package-arg')
const npmFetch = require('npm-registry-fetch')
const { redactLog: replaceInfo } = require('@npmcli/redact')
const otplease = require('../utils/otplease.js')
const { otplease } = require('../utils/auth.js')
const { getContents, logTar } = require('../utils/tar.js')
// for historical reasons, publishConfig in package.json can contain ANY config
// keys that npm supports in .npmrc files and elsewhere. We *may* want to
Expand Down
2 changes: 1 addition & 1 deletion lib/commands/team.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const columns = require('cli-columns')
const libteam = require('libnpmteam')
const { output } = require('proc-log')
const otplease = require('../utils/otplease.js')
const { otplease } = require('../utils/auth.js')

const BaseCommand = require('../base-cmd.js')
class Team extends BaseCommand {
Expand Down
12 changes: 6 additions & 6 deletions lib/commands/token.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { log, output } = require('proc-log')
const profile = require('npm-profile')
const otplease = require('../utils/otplease.js')
const { listTokens, createToken, removeToken } = require('npm-profile')
const { otplease } = require('../utils/auth.js')
const readUserInfo = require('../utils/read-user-info.js')
const BaseCommand = require('../base-cmd.js')

Expand Down Expand Up @@ -48,7 +48,7 @@ class Token extends BaseCommand {
const json = this.npm.config.get('json')
const parseable = this.npm.config.get('parseable')
log.info('token', 'getting list')
const tokens = await profile.listTokens(this.npm.flatOptions)
const tokens = await listTokens(this.npm.flatOptions)
if (json) {
output.standard(JSON.stringify(tokens, null, 2))
return
Expand Down Expand Up @@ -92,7 +92,7 @@ class Token extends BaseCommand {
const toRemove = []
const opts = { ...this.npm.flatOptions }
log.info('token', `removing ${toRemove.length} tokens`)
const tokens = await profile.listTokens(opts)
const tokens = await listTokens(opts)
args.forEach(id => {
const matches = tokens.filter(token => token.key.indexOf(id) === 0)
if (matches.length === 1) {
Expand All @@ -113,7 +113,7 @@ class Token extends BaseCommand {
})
await Promise.all(
toRemove.map(key => {
return otplease(this.npm, opts, c => profile.removeToken(key, c))
return otplease(this.npm, opts, c => removeToken(key, c))
})
)
if (json) {
Expand All @@ -137,7 +137,7 @@ class Token extends BaseCommand {
const result = await otplease(
this.npm,
{ ...this.npm.flatOptions },
c => profile.createToken(password, readonly, validCIDR, c)
c => createToken(password, readonly, validCIDR, c)
)
delete result.key
delete result.updated
Expand Down
2 changes: 1 addition & 1 deletion lib/commands/unpublish.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const { output, log } = require('proc-log')
const pkgJson = require('@npmcli/package-json')
const { flatten } = require('@npmcli/config/lib/definitions')
const getIdentity = require('../utils/get-identity.js')
const otplease = require('../utils/otplease.js')
const { otplease } = require('../utils/auth.js')
const BaseCommand = require('../base-cmd.js')

const LAST_REMAINING_VERSION_ERROR = 'Refusing to delete the last version of the package. ' +
Expand Down
2 changes: 1 addition & 1 deletion lib/package-url-cmd.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const pacote = require('pacote')
const openUrl = require('./utils/open-url.js')
const { openUrl } = require('./utils/open-url.js')
const { log } = require('proc-log')
const BaseCommand = require('./base-cmd.js')

Expand Down
63 changes: 36 additions & 27 deletions lib/utils/auth.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,43 @@
const profile = require('npm-profile')
const { webAuthOpener, adduserWeb, loginWeb, loginCouch, adduserCouch } = require('npm-profile')
const { log } = require('proc-log')
const openUrlPrompt = require('../utils/open-url-prompt.js')
const { createOpener } = require('../utils/open-url.js')
const read = require('../utils/read-user-info.js')
const otplease = require('../utils/otplease.js')

const otplease = async (npm, opts, fn) => {
try {
return await fn(opts)
} catch (err) {
if (!process.stdin.isTTY || !process.stdout.isTTY) {
throw err
}

// web otp
if (err.code === 'EOTP' && err.body?.authUrl && err.body?.doneUrl) {
const otp = await webAuthOpener(
createOpener(npm, 'Authenticate your account at'),
err.body.authUrl,
err.body.doneUrl,
opts
)
return await fn({ ...opts, otp })
}

// classic otp
if (err.code === 'EOTP' || (err.code === 'E401' && /one-time pass/.test(err.body))) {
const otp = await read.otp('This operation requires a one-time password.\nEnter OTP:')
return await fn({ ...opts, otp })
}

throw err
}
}

const adduser = async (npm, { creds, ...opts }) => {
const authType = npm.config.get('auth-type')
let res
if (authType === 'web') {
try {
res = await profile.adduserWeb((url, emitter) => {
openUrlPrompt(
npm,
url,
'Create your account at',
'Press ENTER to open in the browser...',
emitter
)
}, opts)
res = await adduserWeb(createOpener(npm, 'Create your account at'), opts)
} catch (err) {
if (err.code === 'ENYI') {
log.verbose('web add user not supported, trying couch')
Expand All @@ -35,9 +55,7 @@ const adduser = async (npm, { creds, ...opts }) => {
// npm registry quirk: If you "add" an existing user with their current
// password, it's effectively a login, and if that account has otp you'll
// be prompted for it.
res = await otplease(npm, opts, (reqOpts) =>
profile.adduserCouch(username, email, password, reqOpts)
)
res = await otplease(npm, opts, (reqOpts) => adduserCouch(username, email, password, reqOpts))
}

// We don't know the username if it was a web login, all we can reliably log is scope and registry
Expand All @@ -56,15 +74,7 @@ const login = async (npm, { creds, ...opts }) => {
let res
if (authType === 'web') {
try {
res = await profile.loginWeb((url, emitter) => {
openUrlPrompt(
npm,
url,
'Login at',
'Press ENTER to open in the browser...',
emitter
)
}, opts)
res = await loginWeb(createOpener(npm, 'Login at'), opts)
} catch (err) {
if (err.code === 'ENYI') {
log.verbose('web login not supported, trying couch')
Expand All @@ -78,9 +88,7 @@ const login = async (npm, { creds, ...opts }) => {
if (!res) {
const username = await read.username('Username:', creds.username)
const password = await read.password('Password:', creds.password)
res = await otplease(npm, opts, (reqOpts) =>
profile.loginCouch(username, password, reqOpts)
)
res = await otplease(npm, opts, (reqOpts) => loginCouch(username, password, reqOpts))
}

// We don't know the username if it was a web login, all we can reliably log is scope and registry
Expand All @@ -97,4 +105,5 @@ const login = async (npm, { creds, ...opts }) => {
module.exports = {
adduser,
login,
otplease,
}

0 comments on commit 261ea19

Please sign in to comment.