diff --git a/lib/utils/get-identity.js b/lib/utils/get-identity.js index 41d882473ab7b..d8f59da14247a 100644 --- a/lib/utils/get-identity.js +++ b/lib/utils/get-identity.js @@ -12,7 +12,9 @@ module.exports = async (npm, opts) => { // No username, but we have other credentials; fetch the username from registry if (creds.token || creds.certfile && creds.keyfile) { const registryData = await npmFetch.json('/-/whoami', { ...opts }) - return registryData.username + if (typeof registryData?.username === 'string') { + return registryData.username + } } // At this point, even if they have a credentials object, it doesn't have a diff --git a/test/lib/commands/whoami.js b/test/lib/commands/whoami.js index a4532390bc66b..8291b092dc167 100644 --- a/test/lib/commands/whoami.js +++ b/test/lib/commands/whoami.js @@ -1,6 +1,7 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm') const MockRegistry = require('@npmcli/mock-registry') +const nock = require('nock') const username = 'foo' const auth = { '//registry.npmjs.org/:_authToken': 'test-auth-token' } @@ -67,3 +68,27 @@ t.test('not logged in', async t => { }) await t.rejects(npm.exec('whoami', []), { code: 'ENEEDAUTH' }) }) + +t.test('non-string username in response', async t => { + nock.disableNetConnect() + t.teardown(() => { + nock.enableNetConnect() + }) + + const server = nock('https://registry.npmjs.org', { + reqheaders: { + authorization: 'Bearer abcd1234', + }, + }) + .get('/-/whoami') + .reply(200, { username: null }) + + const { npm } = await loadMockNpm(t, { + config: { + '//registry.npmjs.org/:_authToken': 'abcd1234', + }, + }) + + await t.rejects(npm.exec('whoami', []), { code: 'ENEEDAUTH' }) + t.ok(server.isDone()) +})