%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/npm/test/lib/commands/ |
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/npm/test/lib/commands/profile.js |
const t = require('tap') const mockNpm = require('../../fixtures/mock-npm') const mockProfile = async (t, { npmProfile, readUserInfo, qrcode, config, ...opts } = {}) => { const mocks = { 'npm-profile': npmProfile || { async get () {}, async set () {}, async createToken () {}, }, 'qrcode-terminal': qrcode || { generate: (url, cb) => cb() }, 'cli-table3': class extends Array { toString () { return this.filter(Boolean) .map(i => [...Object.entries(i)].map(v => v.join(': '))) .join('\n') } }, '{LIB}/utils/read-user-info.js': readUserInfo || { async password () {}, async otp () {}, }, } const mock = await mockNpm(t, { ...opts, command: 'profile', config: { color: false, ...config, }, mocks: { ...mocks, ...opts.mocks, }, }) return { ...mock, result: () => mock.joinedOutput(), } } const userProfile = { tfa: { pending: false, mode: 'auth-and-writes' }, name: 'foo', email: 'foo@github.com', email_verified: true, created: '2015-02-26T01:26:37.384Z', updated: '2020-08-12T16:19:35.326Z', cidr_whitelist: null, fullname: 'Foo Bar', homepage: 'https://github.com', freenode: 'foobar', twitter: 'https://twitter.com/npmjs', github: 'https://github.com/npm', } t.test('no args', async t => { const { profile } = await mockProfile(t) await t.rejects(profile.exec([]), await profile.usage) }) t.test('profile get no args', async t => { const defaultNpmProfile = { async get () { return userProfile }, } t.test('default output', async t => { const { profile, result } = await mockProfile(t, { npmProfile: defaultNpmProfile }) await profile.exec(['get']) t.matchSnapshot(result(), 'should output table with contents') }) t.test('--json', async t => { const { profile, result } = await mockProfile(t, { npmProfile: defaultNpmProfile, config: { json: true }, }) await profile.exec(['get']) t.same(JSON.parse(result()), userProfile, 'should output json profile result') }) t.test('--parseable', async t => { const { profile, result } = await mockProfile(t, { npmProfile: defaultNpmProfile, config: { parseable: true }, }) await profile.exec(['get']) t.matchSnapshot(result(), 'should output all profile info as parseable result') }) t.test('--color', async t => { const { profile, result } = await mockProfile(t, { npmProfile: defaultNpmProfile, config: { color: 'always' }, }) await profile.exec(['get']) t.matchSnapshot(result(), 'should output all profile info with color result') }) t.test('no tfa enabled', async t => { const npmProfile = { async get () { return { ...userProfile, tfa: null, } }, } const { profile, result } = await mockProfile(t, { npmProfile }) await profile.exec(['get']) t.matchSnapshot(result(), 'should output expected profile values') }) t.test('unverified email', async t => { const npmProfile = { async get () { return { ...userProfile, email_verified: false, } }, } const { profile, result } = await mockProfile(t, { npmProfile }) await profile.exec(['get']) t.matchSnapshot(result(), 'should output table with contents') }) t.test('profile has cidr_whitelist item', async t => { const npmProfile = { async get () { return { ...userProfile, cidr_whitelist: ['192.168.1.1'], } }, } const { profile, result } = await mockProfile(t, { npmProfile }) await profile.exec(['get']) t.matchSnapshot(result(), 'should output table with contents') }) }) t.test('profile get <key>', async t => { const npmProfile = { async get () { return userProfile }, } t.test('default output', async t => { const { profile, result } = await mockProfile(t, { npmProfile }) await profile.exec(['get', 'name']) t.equal(result(), 'foo', 'should output value result') }) t.test('--json', async t => { const { profile, result } = await mockProfile(t, { npmProfile, config: { json: true }, }) await profile.exec(['get', 'name']) t.same( JSON.parse(result()), userProfile, 'should output json profile result ignoring args filter' ) }) t.test('--parseable', async t => { const { profile, result } = await mockProfile(t, { npmProfile, config: { parseable: true }, }) await profile.exec(['get', 'name']) t.matchSnapshot(result(), 'should output parseable result value') }) }) t.test('profile get multiple args', async t => { const npmProfile = { async get () { return userProfile }, } t.test('default output', async t => { const { profile, result } = await mockProfile(t, { npmProfile, }) await profile.exec(['get', 'name', 'email', 'github']) t.matchSnapshot(result(), 'should output all keys') }) t.test('--json', async t => { const config = { json: true } const { profile, result } = await mockProfile(t, { npmProfile, config, }) await profile.exec(['get', 'name', 'email', 'github']) t.same(JSON.parse(result()), userProfile, 'should output json profile result and ignore args') }) t.test('--parseable', async t => { const config = { parseable: true } const { profile, result } = await mockProfile(t, { npmProfile, config, }) await profile.exec(['get', 'name', 'email', 'github']) t.matchSnapshot(result(), 'should output parseable profile value results') }) t.test('comma separated', async t => { const { profile, result } = await mockProfile(t, { npmProfile, }) await profile.exec(['get', 'name,email,github']) t.matchSnapshot(result(), 'should output all keys') }) }) t.test('profile set <key> <value>', async t => { t.test('no key', async t => { const { profile } = await mockProfile(t) await t.rejects( profile.exec(['set']), /npm profile set <prop> <value>/, 'should throw proper usage message' ) }) t.test('no value', async t => { const { profile } = await mockProfile(t) await t.rejects( profile.exec(['set', 'email']), /npm profile set <prop> <value>/, 'should throw proper usage message' ) }) t.test('set password', async t => { const { profile } = await mockProfile(t) await t.rejects( profile.exec(['set', 'password', '1234']), /Do not include your current or new passwords on the command line./, 'should throw an error refusing to set password from args' ) }) t.test('unwritable key', async t => { const { profile } = await mockProfile(t) await await t.rejects( profile.exec(['set', 'name', 'foo']), /"name" is not a property we can set./, 'should throw the unwritable key error' ) }) const defaultNpmProfile = t => ({ async get () { return userProfile }, async set (newUser) { t.match( newUser, { fullname: 'Lorem Ipsum', }, 'should set new value to key' ) return { ...userProfile, ...newUser, } }, }) t.test('writable key', async t => { t.test('default output', async t => { t.plan(2) const { profile, result } = await mockProfile(t, { npmProfile: defaultNpmProfile(t), }) await profile.exec(['set', 'fullname', 'Lorem Ipsum']) t.equal(result(), 'Set fullname to Lorem Ipsum', 'should output set key success msg') }) t.test('--json', async t => { t.plan(2) const config = { json: true } const { profile, result } = await mockProfile(t, { npmProfile: defaultNpmProfile(t), config, }) await profile.exec(['set', 'fullname', 'Lorem Ipsum']) t.same( JSON.parse(result()), { fullname: 'Lorem Ipsum', }, 'should output json set key success msg' ) }) t.test('--parseable', async t => { t.plan(2) const config = { parseable: true } const { profile, result } = await mockProfile(t, { npmProfile: defaultNpmProfile(t), config, }) await profile.exec(['set', 'fullname', 'Lorem Ipsum']) t.matchSnapshot(result(), 'should output parseable set key success msg') }) }) t.test('write new email', async t => { t.plan(2) const npmProfile = { async get () { return userProfile }, async set (newUser) { t.match( newUser, { email: 'foo@npmjs.com', }, 'should set new value to email' ) return { ...userProfile, ...newUser, } }, } const { profile, result } = await mockProfile(t, { npmProfile, }) await profile.exec(['set', 'email', 'foo@npmjs.com']) t.equal(result(), 'Set email to foo@npmjs.com', 'should output set key success msg') }) t.test('change password', async t => { t.plan(5) const npmProfile = { async get () { return userProfile }, async set (newUser) { t.match( newUser, { password: { old: 'currentpassword1234', new: 'newpassword1234', }, }, 'should set new password' ) return { ...userProfile, } }, } const readUserInfo = { async password (label) { if (label === 'Current password: ') { t.ok('should interactively ask for password confirmation') } else if (label === 'New password: ') { t.ok('should interactively ask for new password') } else if (label === ' Again: ') { t.ok('should interactively ask for new password confirmation') } else { throw new Error('Unexpected label: ' + label) } return label === 'Current password: ' ? 'currentpassword1234' : 'newpassword1234' }, } const { profile, result } = await mockProfile(t, { npmProfile, readUserInfo, }) await profile.exec(['set', 'password']) t.equal(result(), 'Set password', 'should output set password success msg') }) t.test('password confirmation mismatch', async t => { t.plan(2) let passwordPromptCount = 0 const npmProfile = { async get () { return userProfile }, async set () { return { ...userProfile } }, } const readUserInfo = { async password (label) { passwordPromptCount++ switch (label) { case 'Current password: ': return 'currentpassword1234' case 'New password: ': return passwordPromptCount < 3 ? 'password-that-will-not-be-confirmed' : 'newpassword' case ' Again: ': return 'newpassword' default: return 'password1234' } }, } const { profile, result, logs } = await mockProfile(t, { npmProfile, readUserInfo, }) await profile.exec(['set', 'password']) t.equal( logs.warn[0][1], 'Passwords do not match, please try again.', 'should log password mismatch message' ) t.equal(result(), 'Set password', 'should output set password success msg') }) }) t.test('enable-2fa', async t => { t.test('invalid args', async t => { const { profile } = await mockProfile(t) await t.rejects( profile.exec(['enable-2fa', 'foo', 'bar']), /npm profile enable-2fa \[auth-and-writes|auth-only\]/, 'should throw usage error' ) }) t.test('invalid two factor auth mode', async t => { const { profile } = await mockProfile(t) await t.rejects( profile.exec(['enable-2fa', 'foo']), /Invalid two-factor authentication mode "foo"/, 'should throw invalid auth mode error' ) }) t.test('no support for --json output', async t => { const config = { json: true } const { profile } = await mockProfile(t, { config }) await t.rejects( profile.exec(['enable-2fa', 'auth-only']), 'Enabling two-factor authentication is an interactive ' + 'operation and JSON output mode is not available', 'should throw no support msg' ) }) t.test('no support for --parseable output', async t => { const config = { parseable: true } const { profile } = await mockProfile(t, { config }) await t.rejects( profile.exec(['enable-2fa', 'auth-only']), 'Enabling two-factor authentication is an interactive ' + 'operation and parseable output mode is not available', 'should throw no support msg' ) }) t.test('no bearer tokens returned by registry', async t => { t.plan(3) const npmProfile = { async createToken (pass) { t.match(pass, 'bar', 'should use password for basic auth') return {} }, } const { npm, profile } = await mockProfile(t, { npmProfile, }) // mock legacy basic auth style // XXX: use mock registry npm.config.getCredentialsByURI = reg => { t.equal(reg, npm.flatOptions.registry, 'should use expected registry') return { auth: Buffer.from('foo:bar').toString('base64') } } await t.rejects( profile.exec(['enable-2fa', 'auth-only']), 'Your registry https://registry.npmjs.org/ does ' + 'not seem to support bearer tokens. Bearer tokens ' + 'are required for two-factor authentication', 'should throw no support msg' ) }) t.test('from basic username/password auth', async t => { const npmProfile = { async createToken (pass) { return {} }, } const { npm, profile } = await mockProfile(t, { npmProfile, }) // mock legacy basic auth style with user/pass // XXX: use mock registry npm.config.getCredentialsByURI = () => { return { username: 'foo', password: 'bar' } } await t.rejects( profile.exec(['enable-2fa', 'auth-only']), 'Your registry https://registry.npmjs.org/ does ' + 'not seem to support bearer tokens. Bearer tokens ' + 'are required for two-factor authentication', 'should throw no support msg' ) }) t.test('no auth found', async t => { const { npm, profile } = await mockProfile(t) // XXX: use mock registry npm.config.getCredentialsByURI = () => ({}) await t.rejects( profile.exec(['enable-2fa', 'auth-only']), 'You need to be logged in to registry ' + 'https://registry.npmjs.org/ in order to enable 2fa' ) }) t.test('from basic auth, asks for otp', async t => { t.plan(9) const npmProfile = { async createToken (pass) { t.match(pass, 'bar', 'should use password for basic auth') return { token: 'token' } }, async get () { return userProfile }, async set (newProfile, conf) { t.match( newProfile, { tfa: { mode: 'auth-only', }, }, 'should set tfa mode' ) return { ...userProfile, tfa: null, } }, } const readUserInfo = { async password () { t.ok('should interactively ask for password confirmation') return 'password1234' }, async otp (label) { t.equal( label, 'Enter one-time password: ', 'should ask for otp confirmation' ) return '123456' }, } const { npm, profile, result } = await mockProfile(t, { npmProfile, readUserInfo, }) // mock legacy basic auth style // XXX: use mock registry npm.config.getCredentialsByURI = reg => { t.equal(reg, npm.flatOptions.registry, 'should use expected registry') return { auth: Buffer.from('foo:bar').toString('base64') } } npm.config.setCredentialsByURI = (registry, { token }) => { t.equal(registry, npm.flatOptions.registry, 'should set expected registry') t.equal(token, 'token', 'should set expected token') } npm.config.save = type => { t.equal(type, 'user', 'should save to user config') } await profile.exec(['enable-2fa', 'auth-only']) t.equal( result(), 'Two factor authentication mode changed to: auth-only', 'should output success msg' ) }) t.test('from token and set otp, retries on pending and verifies with qrcode', async t => { t.plan(4) let setCount = 0 const npmProfile = { async get () { return { ...userProfile, tfa: { pending: true, }, } }, async set (newProfile, conf) { setCount++ // when profile response shows that 2fa is pending the // first time calling npm-profile.set should reset 2fa if (setCount === 1) { t.match( newProfile, { tfa: { password: 'password1234', mode: 'disable', }, }, 'should reset 2fa' ) } else if (setCount === 2) { t.match( newProfile, { tfa: { mode: 'auth-only', }, }, 'should set tfa mode approprietly in follow-up call' ) } else if (setCount === 3) { t.match( newProfile, { tfa: ['123456'], }, 'should set tfa as otp code?' ) return { ...userProfile, tfa: ['123456', '789101'], } } return { ...userProfile, tfa: 'otpauth://foo?secret=1234', } }, } const readUserInfo = { async password () { return 'password1234' }, async otp () { return '123456' }, } const qrcode = { /* eslint-disable-next-line node/no-callback-literal */ generate: (url, cb) => cb('qrcode'), } const { npm, profile, result } = await mockProfile(t, { npmProfile, qrcode, readUserInfo, config: { otp: '1234' }, }) // XXX: use mock registry npm.config.getCredentialsByURI = () => { return { token: 'token' } } await profile.exec(['enable-2fa', 'auth-only']) t.matchSnapshot(result(), 'should output 2fa enablement success msgs') }) t.test('from token and set otp, retrieves invalid otp', async t => { const npmProfile = { async get () { return { ...userProfile, tfa: { pending: true, }, } }, async set (newProfile, conf) { return { ...userProfile, tfa: 'http://foo?secret=1234', } }, } const readUserInfo = { async password () { return 'password1234' }, async otp (label) { return '123456' }, } const { npm, profile } = await mockProfile(t, { npmProfile, readUserInfo, config: { otp: '1234' }, }) npm.config.getCredentialsByURI = () => { return { token: 'token' } } await t.rejects( profile.exec(['enable-2fa', 'auth-only']), /Unknown error enabling two-factor authentication./, 'should throw invalid 2fa auth url error' ) }) t.test('from token auth provides --otp config arg', async t => { const npmProfile = { async get () { return userProfile }, async set (newProfile, conf) { return { ...userProfile, tfa: null, } }, } const readUserInfo = { async password () { return 'password1234' }, async otp () { throw new Error('should not ask for otp') }, } const { npm, profile, result } = await mockProfile(t, { npmProfile, readUserInfo, config: { otp: '123456' }, }) npm.config.getCredentialsByURI = reg => { return { token: 'token' } } await profile.exec(['enable-2fa', 'auth-and-writes']) t.equal( result(), 'Two factor authentication mode changed to: auth-and-writes', 'should output success msg' ) }) t.test('missing tfa from user profile', async t => { const npmProfile = { async get () { return { ...userProfile, tfa: undefined, } }, async set (newProfile, conf) { return { ...userProfile, tfa: null, } }, } const readUserInfo = { async password () { return 'password1234' }, async otp () { return '123456' }, } const { npm, profile, result } = await mockProfile(t, { npmProfile, readUserInfo, }) npm.config.getCredentialsByURI = reg => { return { token: 'token' } } await profile.exec(['enable-2fa', 'auth-only']) t.equal( result(), 'Two factor authentication mode changed to: auth-only', 'should output success msg' ) }) t.test('defaults to auth-and-writes permission if no mode specified', async t => { const npmProfile = { async get () { return { ...userProfile, tfa: undefined, } }, async set (newProfile, conf) { return { ...userProfile, tfa: null, } }, } const readUserInfo = { async password () { return 'password1234' }, async otp () { return '123456' }, } const { npm, profile, result } = await mockProfile(t, { npmProfile, readUserInfo, }) npm.config.getCredentialsByURI = reg => { return { token: 'token' } } await profile.exec(['enable-2fa']) t.equal( result(), 'Two factor authentication mode changed to: auth-and-writes', 'should enable 2fa with auth-and-writes permission' ) }) }) t.test('disable-2fa', async t => { t.test('no tfa enabled', async t => { const npmProfile = { async get () { return { ...userProfile, tfa: null, } }, } const { profile, result } = await mockProfile(t, { npmProfile, }) await profile.exec(['disable-2fa']) t.equal(result(), 'Two factor authentication not enabled.', 'should output already disalbed msg') }) t.test('requests otp', async t => { const npmProfile = t => ({ async get () { return userProfile }, async set (newProfile, conf) { t.same( newProfile, { tfa: { password: 'password1234', mode: 'disable', }, }, 'should send the new info for setting in profile' ) }, }) const readUserInfo = t => ({ async password () { t.ok('should interactively ask for password confirmation') return 'password1234' }, async otp (label) { t.equal( label, 'Enter one-time password: ', 'should ask for otp confirmation' ) return '1234' }, }) t.test('default output', async t => { t.plan(4) const { profile, result } = await mockProfile(t, { npmProfile: npmProfile(t), readUserInfo: readUserInfo(t), }) await profile.exec(['disable-2fa']) t.equal(result(), 'Two factor authentication disabled.', 'should output already disabled msg') }) t.test('--json', async t => { t.plan(4) const config = { json: true } const { profile, result } = await mockProfile(t, { npmProfile: npmProfile(t), readUserInfo: readUserInfo(t), config, }) await profile.exec(['disable-2fa']) t.same(JSON.parse(result()), { tfa: false }, 'should output json already disabled msg') }) t.test('--parseable', async t => { t.plan(4) const config = { parseable: true } const { profile, result } = await mockProfile(t, { npmProfile: npmProfile(t), readUserInfo: readUserInfo(t), config, }) await profile.exec(['disable-2fa']) t.equal(result(), 'tfa\tfalse', 'should output parseable already disabled msg') }) }) t.test('--otp config already set', async t => { t.plan(2) const npmProfile = { async get () { return userProfile }, async set (newProfile, conf) { t.same( newProfile, { tfa: { password: 'password1234', mode: 'disable', }, }, 'should send the new info for setting in profile' ) }, } const readUserInfo = { async password () { return 'password1234' }, async otp (label) { throw new Error('should not ask for otp') }, } const { profile, result } = await mockProfile(t, { npmProfile, readUserInfo, config: { otp: '123456' }, }) await profile.exec(['disable-2fa']) t.equal(result(), 'Two factor authentication disabled.', 'should output already disalbed msg') }) }) t.test('unknown subcommand', async t => { const { profile } = await mockProfile(t) await t.rejects( profile.exec(['asfd']), /Unknown profile command: asfd/, 'should throw unknown cmd error' ) }) t.test('completion', async t => { const testComp = async (t, { argv, expect, title } = {}) => { const { profile } = await mockProfile(t) t.resolveMatch(profile.completion({ conf: { argv: { remain: argv } } }), expect, title) } t.test('npm profile autocomplete', async t => { await testComp(t, { argv: ['npm', 'profile'], expect: ['enable-2fa', 'disable-2fa', 'get', 'set'], title: 'should auto complete with subcommands', }) }) t.test('npm profile enable autocomplete', async t => { await testComp(t, { argv: ['npm', 'profile', 'enable-2fa'], expect: ['auth-and-writes', 'auth-only'], title: 'should auto complete with auth types', }) }) t.test('npm profile <subcmd> no autocomplete', async t => { const noAutocompleteCmds = ['disable-2fa', 'disable-tfa', 'get', 'set'] for (const subcmd of noAutocompleteCmds) { await t.test(subcmd, t => testComp(t, { argv: ['npm', 'profile', subcmd], expect: [], title: `${subcmd} should have no autocomplete`, })) } }) t.test('npm profile unknown subcommand autocomplete', async t => { const { profile } = await mockProfile(t) t.rejects( profile.completion({ conf: { argv: { remain: ['npm', 'profile', 'asdf'] } } }), { message: 'asdf not recognized' }, 'should throw unknown cmd error' ) }) })