diff --git a/lib/utils/auth.js b/lib/utils/auth.js index 8b9125a1c3ef0..729ce32c2a7a8 100644 --- a/lib/utils/auth.js +++ b/lib/utils/auth.js @@ -8,16 +8,27 @@ const adduser = async (npm, { creds, ...opts }) => { const authType = npm.config.get('auth-type') let res if (authType === 'web') { - res = await profile.adduserWeb((url, emitter) => { - openUrlPrompt( - npm, - url, - 'Create your account at', - 'Press ENTER to open in the browser...', - emitter - ) - }, opts) - } else { + try { + res = await profile.adduserWeb((url, emitter) => { + openUrlPrompt( + npm, + url, + 'Create your account at', + 'Press ENTER to open in the browser...', + emitter + ) + }, opts) + } catch (err) { + if (err.code === 'ENYI') { + log.verbose('web add user not supported, trying couch') + } else { + throw err + } + } + } + + // auth type !== web or ENYI error w/ web adduser + if (!res) { const username = await read.username('Username:', creds.username) const password = await read.password('Password:', creds.password) const email = await read.email('Email: (this IS public) ', creds.email) @@ -44,16 +55,27 @@ const login = async (npm, { creds, ...opts }) => { const authType = npm.config.get('auth-type') let res if (authType === 'web') { - res = await profile.loginWeb((url, emitter) => { - openUrlPrompt( - npm, - url, - 'Login at', - 'Press ENTER to open in the browser...', - emitter - ) - }, opts) - } else { + try { + res = await profile.loginWeb((url, emitter) => { + openUrlPrompt( + npm, + url, + 'Login at', + 'Press ENTER to open in the browser...', + emitter + ) + }, opts) + } catch (err) { + if (err.code === 'ENYI') { + log.verbose('web login not supported, trying couch') + } else { + throw err + } + } + } + + // auth type !== web or ENYI error w/ web login + if (!res) { const username = await read.username('Username:', creds.username) const password = await read.password('Password:', creds.password) res = await otplease(npm, opts, (reqOpts) => diff --git a/test/lib/commands/adduser.js b/test/lib/commands/adduser.js index 90ed10df70274..ddfbb945b2fcf 100644 --- a/test/lib/commands/adduser.js +++ b/test/lib/commands/adduser.js @@ -174,5 +174,49 @@ t.test('web', t => { '//registry.npmjs.org/:_authToken': 'npm_test-token', }) }) + + t.test('server error', async t => { + const { npm } = await loadMockNpm(t, { + config: { 'auth-type': 'web' }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.nock.post(registry.fullPath('/-/v1/login')) + .reply(503, {}) + await t.rejects( + npm.exec('adduser', []), + { message: /503/ } + ) + }) + + t.test('fallback', async t => { + const stdin = new stream.PassThrough() + stdin.write('test-user\n') + stdin.write('test-password\n') + stdin.write('test-email@npmjs.org\n') + mockGlobals(t, { + 'process.stdin': stdin, + 'process.stdout': new stream.PassThrough(), // to quiet readline + }, { replace: true }) + const { npm } = await loadMockNpm(t, { + config: { 'auth-type': 'web' }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.nock.post(registry.fullPath('/-/v1/login')) + .reply(404, {}) + registry.couchadduser({ + username: 'test-user', + password: 'test-password', + email: 'test-email@npmjs.org', + token: 'npm_test-token', + }) + await npm.exec('adduser', []) + t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') + }) t.end() }) diff --git a/test/lib/commands/login.js b/test/lib/commands/login.js index ae7e3ffab0f02..63666670712ef 100644 --- a/test/lib/commands/login.js +++ b/test/lib/commands/login.js @@ -139,5 +139,45 @@ t.test('web', t => { '//registry.npmjs.org/:_authToken': 'npm_test-token', }) }) + t.test('server error', async t => { + const { npm } = await loadMockNpm(t, { + config: { 'auth-type': 'web' }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.nock.post(registry.fullPath('/-/v1/login')) + .reply(503, {}) + await t.rejects( + npm.exec('login', []), + { message: /503/ } + ) + }) + t.test('fallback', async t => { + const stdin = new stream.PassThrough() + stdin.write('test-user\n') + stdin.write('test-password\n') + mockGlobals(t, { + 'process.stdin': stdin, + 'process.stdout': new stream.PassThrough(), // to quiet readline + }, { replace: true }) + const { npm } = await loadMockNpm(t, { + config: { 'auth-type': 'web' }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.nock.post(registry.fullPath('/-/v1/login')) + .reply(404, {}) + registry.couchlogin({ + username: 'test-user', + password: 'test-password', + token: 'npm_test-token', + }) + await npm.exec('login', []) + t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') + }) t.end() })