11cb0ef41Sopenharmony_ciconst t = require('tap')
21cb0ef41Sopenharmony_ciconst mockNpm = require('../../fixtures/mock-npm')
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ciconst mockProfile = async (t, { npmProfile, readUserInfo, qrcode, config, ...opts } = {}) => {
51cb0ef41Sopenharmony_ci  const mocks = {
61cb0ef41Sopenharmony_ci    'npm-profile': npmProfile || {
71cb0ef41Sopenharmony_ci      async get () {},
81cb0ef41Sopenharmony_ci      async set () {},
91cb0ef41Sopenharmony_ci      async createToken () {},
101cb0ef41Sopenharmony_ci    },
111cb0ef41Sopenharmony_ci    'qrcode-terminal': qrcode || { generate: (url, cb) => cb() },
121cb0ef41Sopenharmony_ci    'cli-table3': class extends Array {
131cb0ef41Sopenharmony_ci      toString () {
141cb0ef41Sopenharmony_ci        return this.filter(Boolean)
151cb0ef41Sopenharmony_ci          .map(i => [...Object.entries(i)].map(v => v.join(': ')))
161cb0ef41Sopenharmony_ci          .join('\n')
171cb0ef41Sopenharmony_ci      }
181cb0ef41Sopenharmony_ci    },
191cb0ef41Sopenharmony_ci    '{LIB}/utils/read-user-info.js': readUserInfo || {
201cb0ef41Sopenharmony_ci      async password () {},
211cb0ef41Sopenharmony_ci      async otp () {},
221cb0ef41Sopenharmony_ci    },
231cb0ef41Sopenharmony_ci  }
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci  const mock = await mockNpm(t, {
261cb0ef41Sopenharmony_ci    ...opts,
271cb0ef41Sopenharmony_ci    command: 'profile',
281cb0ef41Sopenharmony_ci    config: {
291cb0ef41Sopenharmony_ci      color: false,
301cb0ef41Sopenharmony_ci      ...config,
311cb0ef41Sopenharmony_ci    },
321cb0ef41Sopenharmony_ci    mocks: {
331cb0ef41Sopenharmony_ci      ...mocks,
341cb0ef41Sopenharmony_ci      ...opts.mocks,
351cb0ef41Sopenharmony_ci    },
361cb0ef41Sopenharmony_ci  })
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  return {
391cb0ef41Sopenharmony_ci    ...mock,
401cb0ef41Sopenharmony_ci    result: () => mock.joinedOutput(),
411cb0ef41Sopenharmony_ci  }
421cb0ef41Sopenharmony_ci}
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ciconst userProfile = {
451cb0ef41Sopenharmony_ci  tfa: { pending: false, mode: 'auth-and-writes' },
461cb0ef41Sopenharmony_ci  name: 'foo',
471cb0ef41Sopenharmony_ci  email: 'foo@github.com',
481cb0ef41Sopenharmony_ci  email_verified: true,
491cb0ef41Sopenharmony_ci  created: '2015-02-26T01:26:37.384Z',
501cb0ef41Sopenharmony_ci  updated: '2020-08-12T16:19:35.326Z',
511cb0ef41Sopenharmony_ci  cidr_whitelist: null,
521cb0ef41Sopenharmony_ci  fullname: 'Foo Bar',
531cb0ef41Sopenharmony_ci  homepage: 'https://github.com',
541cb0ef41Sopenharmony_ci  freenode: 'foobar',
551cb0ef41Sopenharmony_ci  twitter: 'https://twitter.com/npmjs',
561cb0ef41Sopenharmony_ci  github: 'https://github.com/npm',
571cb0ef41Sopenharmony_ci}
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_cit.test('no args', async t => {
601cb0ef41Sopenharmony_ci  const { profile } = await mockProfile(t)
611cb0ef41Sopenharmony_ci  await t.rejects(profile.exec([]), await profile.usage)
621cb0ef41Sopenharmony_ci})
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_cit.test('profile get no args', async t => {
651cb0ef41Sopenharmony_ci  const defaultNpmProfile = {
661cb0ef41Sopenharmony_ci    async get () {
671cb0ef41Sopenharmony_ci      return userProfile
681cb0ef41Sopenharmony_ci    },
691cb0ef41Sopenharmony_ci  }
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  t.test('default output', async t => {
721cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, { npmProfile: defaultNpmProfile })
731cb0ef41Sopenharmony_ci    await profile.exec(['get'])
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci    t.matchSnapshot(result(), 'should output table with contents')
761cb0ef41Sopenharmony_ci  })
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci  t.test('--json', async t => {
791cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
801cb0ef41Sopenharmony_ci      npmProfile: defaultNpmProfile,
811cb0ef41Sopenharmony_ci      config: { json: true },
821cb0ef41Sopenharmony_ci    })
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci    await profile.exec(['get'])
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci    t.same(JSON.parse(result()), userProfile, 'should output json profile result')
871cb0ef41Sopenharmony_ci  })
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci  t.test('--parseable', async t => {
901cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
911cb0ef41Sopenharmony_ci      npmProfile: defaultNpmProfile,
921cb0ef41Sopenharmony_ci      config: { parseable: true },
931cb0ef41Sopenharmony_ci    })
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci    await profile.exec(['get'])
961cb0ef41Sopenharmony_ci    t.matchSnapshot(result(), 'should output all profile info as parseable result')
971cb0ef41Sopenharmony_ci  })
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  t.test('--color', async t => {
1001cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
1011cb0ef41Sopenharmony_ci      npmProfile: defaultNpmProfile,
1021cb0ef41Sopenharmony_ci      config: { color: 'always' },
1031cb0ef41Sopenharmony_ci    })
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci    await profile.exec(['get'])
1061cb0ef41Sopenharmony_ci    t.matchSnapshot(result(), 'should output all profile info with color result')
1071cb0ef41Sopenharmony_ci  })
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci  t.test('no tfa enabled', async t => {
1101cb0ef41Sopenharmony_ci    const npmProfile = {
1111cb0ef41Sopenharmony_ci      async get () {
1121cb0ef41Sopenharmony_ci        return {
1131cb0ef41Sopenharmony_ci          ...userProfile,
1141cb0ef41Sopenharmony_ci          tfa: null,
1151cb0ef41Sopenharmony_ci        }
1161cb0ef41Sopenharmony_ci      },
1171cb0ef41Sopenharmony_ci    }
1181cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, { npmProfile })
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci    await profile.exec(['get'])
1211cb0ef41Sopenharmony_ci    t.matchSnapshot(result(), 'should output expected profile values')
1221cb0ef41Sopenharmony_ci  })
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci  t.test('unverified email', async t => {
1251cb0ef41Sopenharmony_ci    const npmProfile = {
1261cb0ef41Sopenharmony_ci      async get () {
1271cb0ef41Sopenharmony_ci        return {
1281cb0ef41Sopenharmony_ci          ...userProfile,
1291cb0ef41Sopenharmony_ci          email_verified: false,
1301cb0ef41Sopenharmony_ci        }
1311cb0ef41Sopenharmony_ci      },
1321cb0ef41Sopenharmony_ci    }
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, { npmProfile })
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci    await profile.exec(['get'])
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci    t.matchSnapshot(result(), 'should output table with contents')
1391cb0ef41Sopenharmony_ci  })
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci  t.test('profile has cidr_whitelist item', async t => {
1421cb0ef41Sopenharmony_ci    const npmProfile = {
1431cb0ef41Sopenharmony_ci      async get () {
1441cb0ef41Sopenharmony_ci        return {
1451cb0ef41Sopenharmony_ci          ...userProfile,
1461cb0ef41Sopenharmony_ci          cidr_whitelist: ['192.168.1.1'],
1471cb0ef41Sopenharmony_ci        }
1481cb0ef41Sopenharmony_ci      },
1491cb0ef41Sopenharmony_ci    }
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, { npmProfile })
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci    await profile.exec(['get'])
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci    t.matchSnapshot(result(), 'should output table with contents')
1561cb0ef41Sopenharmony_ci  })
1571cb0ef41Sopenharmony_ci})
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_cit.test('profile get <key>', async t => {
1601cb0ef41Sopenharmony_ci  const npmProfile = {
1611cb0ef41Sopenharmony_ci    async get () {
1621cb0ef41Sopenharmony_ci      return userProfile
1631cb0ef41Sopenharmony_ci    },
1641cb0ef41Sopenharmony_ci  }
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci  t.test('default output', async t => {
1671cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, { npmProfile })
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci    await profile.exec(['get', 'name'])
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci    t.equal(result(), 'foo', 'should output value result')
1721cb0ef41Sopenharmony_ci  })
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  t.test('--json', async t => {
1751cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
1761cb0ef41Sopenharmony_ci      npmProfile,
1771cb0ef41Sopenharmony_ci      config: { json: true },
1781cb0ef41Sopenharmony_ci    })
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ci    await profile.exec(['get', 'name'])
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci    t.same(
1831cb0ef41Sopenharmony_ci      JSON.parse(result()),
1841cb0ef41Sopenharmony_ci      userProfile,
1851cb0ef41Sopenharmony_ci      'should output json profile result ignoring args filter'
1861cb0ef41Sopenharmony_ci    )
1871cb0ef41Sopenharmony_ci  })
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci  t.test('--parseable', async t => {
1901cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
1911cb0ef41Sopenharmony_ci      npmProfile,
1921cb0ef41Sopenharmony_ci      config: { parseable: true },
1931cb0ef41Sopenharmony_ci    })
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci    await profile.exec(['get', 'name'])
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci    t.matchSnapshot(result(), 'should output parseable result value')
1981cb0ef41Sopenharmony_ci  })
1991cb0ef41Sopenharmony_ci})
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_cit.test('profile get multiple args', async t => {
2021cb0ef41Sopenharmony_ci  const npmProfile = {
2031cb0ef41Sopenharmony_ci    async get () {
2041cb0ef41Sopenharmony_ci      return userProfile
2051cb0ef41Sopenharmony_ci    },
2061cb0ef41Sopenharmony_ci  }
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci  t.test('default output', async t => {
2091cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
2101cb0ef41Sopenharmony_ci      npmProfile,
2111cb0ef41Sopenharmony_ci    })
2121cb0ef41Sopenharmony_ci    await profile.exec(['get', 'name', 'email', 'github'])
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci    t.matchSnapshot(result(), 'should output all keys')
2151cb0ef41Sopenharmony_ci  })
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ci  t.test('--json', async t => {
2181cb0ef41Sopenharmony_ci    const config = { json: true }
2191cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
2201cb0ef41Sopenharmony_ci      npmProfile,
2211cb0ef41Sopenharmony_ci      config,
2221cb0ef41Sopenharmony_ci    })
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ci    await profile.exec(['get', 'name', 'email', 'github'])
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci    t.same(JSON.parse(result()), userProfile, 'should output json profile result and ignore args')
2271cb0ef41Sopenharmony_ci  })
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ci  t.test('--parseable', async t => {
2301cb0ef41Sopenharmony_ci    const config = { parseable: true }
2311cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
2321cb0ef41Sopenharmony_ci      npmProfile,
2331cb0ef41Sopenharmony_ci      config,
2341cb0ef41Sopenharmony_ci    })
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci    await profile.exec(['get', 'name', 'email', 'github'])
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ci    t.matchSnapshot(result(), 'should output parseable profile value results')
2391cb0ef41Sopenharmony_ci  })
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci  t.test('comma separated', async t => {
2421cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
2431cb0ef41Sopenharmony_ci      npmProfile,
2441cb0ef41Sopenharmony_ci    })
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_ci    await profile.exec(['get', 'name,email,github'])
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci    t.matchSnapshot(result(), 'should output all keys')
2491cb0ef41Sopenharmony_ci  })
2501cb0ef41Sopenharmony_ci})
2511cb0ef41Sopenharmony_ci
2521cb0ef41Sopenharmony_cit.test('profile set <key> <value>', async t => {
2531cb0ef41Sopenharmony_ci  t.test('no key', async t => {
2541cb0ef41Sopenharmony_ci    const { profile } = await mockProfile(t)
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_ci    await t.rejects(
2571cb0ef41Sopenharmony_ci      profile.exec(['set']),
2581cb0ef41Sopenharmony_ci      /npm profile set <prop> <value>/,
2591cb0ef41Sopenharmony_ci      'should throw proper usage message'
2601cb0ef41Sopenharmony_ci    )
2611cb0ef41Sopenharmony_ci  })
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci  t.test('no value', async t => {
2641cb0ef41Sopenharmony_ci    const { profile } = await mockProfile(t)
2651cb0ef41Sopenharmony_ci    await t.rejects(
2661cb0ef41Sopenharmony_ci      profile.exec(['set', 'email']),
2671cb0ef41Sopenharmony_ci      /npm profile set <prop> <value>/,
2681cb0ef41Sopenharmony_ci      'should throw proper usage message'
2691cb0ef41Sopenharmony_ci    )
2701cb0ef41Sopenharmony_ci  })
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ci  t.test('set password', async t => {
2731cb0ef41Sopenharmony_ci    const { profile } = await mockProfile(t)
2741cb0ef41Sopenharmony_ci    await t.rejects(
2751cb0ef41Sopenharmony_ci      profile.exec(['set', 'password', '1234']),
2761cb0ef41Sopenharmony_ci      /Do not include your current or new passwords on the command line./,
2771cb0ef41Sopenharmony_ci      'should throw an error refusing to set password from args'
2781cb0ef41Sopenharmony_ci    )
2791cb0ef41Sopenharmony_ci  })
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ci  t.test('unwritable key', async t => {
2821cb0ef41Sopenharmony_ci    const { profile } = await mockProfile(t)
2831cb0ef41Sopenharmony_ci    await await t.rejects(
2841cb0ef41Sopenharmony_ci      profile.exec(['set', 'name', 'foo']),
2851cb0ef41Sopenharmony_ci      /"name" is not a property we can set./,
2861cb0ef41Sopenharmony_ci      'should throw the unwritable key error'
2871cb0ef41Sopenharmony_ci    )
2881cb0ef41Sopenharmony_ci  })
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci  const defaultNpmProfile = t => ({
2911cb0ef41Sopenharmony_ci    async get () {
2921cb0ef41Sopenharmony_ci      return userProfile
2931cb0ef41Sopenharmony_ci    },
2941cb0ef41Sopenharmony_ci    async set (newUser) {
2951cb0ef41Sopenharmony_ci      t.match(
2961cb0ef41Sopenharmony_ci        newUser,
2971cb0ef41Sopenharmony_ci        {
2981cb0ef41Sopenharmony_ci          fullname: 'Lorem Ipsum',
2991cb0ef41Sopenharmony_ci        },
3001cb0ef41Sopenharmony_ci        'should set new value to key'
3011cb0ef41Sopenharmony_ci      )
3021cb0ef41Sopenharmony_ci      return {
3031cb0ef41Sopenharmony_ci        ...userProfile,
3041cb0ef41Sopenharmony_ci        ...newUser,
3051cb0ef41Sopenharmony_ci      }
3061cb0ef41Sopenharmony_ci    },
3071cb0ef41Sopenharmony_ci  })
3081cb0ef41Sopenharmony_ci
3091cb0ef41Sopenharmony_ci  t.test('writable key', async t => {
3101cb0ef41Sopenharmony_ci    t.test('default output', async t => {
3111cb0ef41Sopenharmony_ci      t.plan(2)
3121cb0ef41Sopenharmony_ci
3131cb0ef41Sopenharmony_ci      const { profile, result } = await mockProfile(t, {
3141cb0ef41Sopenharmony_ci        npmProfile: defaultNpmProfile(t),
3151cb0ef41Sopenharmony_ci      })
3161cb0ef41Sopenharmony_ci
3171cb0ef41Sopenharmony_ci      await profile.exec(['set', 'fullname', 'Lorem Ipsum'])
3181cb0ef41Sopenharmony_ci      t.equal(result(), 'Set fullname to Lorem Ipsum', 'should output set key success msg')
3191cb0ef41Sopenharmony_ci    })
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_ci    t.test('--json', async t => {
3221cb0ef41Sopenharmony_ci      t.plan(2)
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_ci      const config = { json: true }
3251cb0ef41Sopenharmony_ci
3261cb0ef41Sopenharmony_ci      const { profile, result } = await mockProfile(t, {
3271cb0ef41Sopenharmony_ci        npmProfile: defaultNpmProfile(t),
3281cb0ef41Sopenharmony_ci        config,
3291cb0ef41Sopenharmony_ci      })
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_ci      await profile.exec(['set', 'fullname', 'Lorem Ipsum'])
3321cb0ef41Sopenharmony_ci
3331cb0ef41Sopenharmony_ci      t.same(
3341cb0ef41Sopenharmony_ci        JSON.parse(result()),
3351cb0ef41Sopenharmony_ci        {
3361cb0ef41Sopenharmony_ci          fullname: 'Lorem Ipsum',
3371cb0ef41Sopenharmony_ci        },
3381cb0ef41Sopenharmony_ci        'should output json set key success msg'
3391cb0ef41Sopenharmony_ci      )
3401cb0ef41Sopenharmony_ci    })
3411cb0ef41Sopenharmony_ci
3421cb0ef41Sopenharmony_ci    t.test('--parseable', async t => {
3431cb0ef41Sopenharmony_ci      t.plan(2)
3441cb0ef41Sopenharmony_ci
3451cb0ef41Sopenharmony_ci      const config = { parseable: true }
3461cb0ef41Sopenharmony_ci      const { profile, result } = await mockProfile(t, {
3471cb0ef41Sopenharmony_ci        npmProfile: defaultNpmProfile(t),
3481cb0ef41Sopenharmony_ci        config,
3491cb0ef41Sopenharmony_ci      })
3501cb0ef41Sopenharmony_ci
3511cb0ef41Sopenharmony_ci      await profile.exec(['set', 'fullname', 'Lorem Ipsum'])
3521cb0ef41Sopenharmony_ci
3531cb0ef41Sopenharmony_ci      t.matchSnapshot(result(), 'should output parseable set key success msg')
3541cb0ef41Sopenharmony_ci    })
3551cb0ef41Sopenharmony_ci  })
3561cb0ef41Sopenharmony_ci
3571cb0ef41Sopenharmony_ci  t.test('write new email', async t => {
3581cb0ef41Sopenharmony_ci    t.plan(2)
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_ci    const npmProfile = {
3611cb0ef41Sopenharmony_ci      async get () {
3621cb0ef41Sopenharmony_ci        return userProfile
3631cb0ef41Sopenharmony_ci      },
3641cb0ef41Sopenharmony_ci      async set (newUser) {
3651cb0ef41Sopenharmony_ci        t.match(
3661cb0ef41Sopenharmony_ci          newUser,
3671cb0ef41Sopenharmony_ci          {
3681cb0ef41Sopenharmony_ci            email: 'foo@npmjs.com',
3691cb0ef41Sopenharmony_ci          },
3701cb0ef41Sopenharmony_ci          'should set new value to email'
3711cb0ef41Sopenharmony_ci        )
3721cb0ef41Sopenharmony_ci        return {
3731cb0ef41Sopenharmony_ci          ...userProfile,
3741cb0ef41Sopenharmony_ci          ...newUser,
3751cb0ef41Sopenharmony_ci        }
3761cb0ef41Sopenharmony_ci      },
3771cb0ef41Sopenharmony_ci    }
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
3801cb0ef41Sopenharmony_ci      npmProfile,
3811cb0ef41Sopenharmony_ci    })
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ci    await profile.exec(['set', 'email', 'foo@npmjs.com'])
3841cb0ef41Sopenharmony_ci    t.equal(result(), 'Set email to foo@npmjs.com', 'should output set key success msg')
3851cb0ef41Sopenharmony_ci  })
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_ci  t.test('change password', async t => {
3881cb0ef41Sopenharmony_ci    t.plan(5)
3891cb0ef41Sopenharmony_ci
3901cb0ef41Sopenharmony_ci    const npmProfile = {
3911cb0ef41Sopenharmony_ci      async get () {
3921cb0ef41Sopenharmony_ci        return userProfile
3931cb0ef41Sopenharmony_ci      },
3941cb0ef41Sopenharmony_ci      async set (newUser) {
3951cb0ef41Sopenharmony_ci        t.match(
3961cb0ef41Sopenharmony_ci          newUser,
3971cb0ef41Sopenharmony_ci          {
3981cb0ef41Sopenharmony_ci            password: {
3991cb0ef41Sopenharmony_ci              old: 'currentpassword1234',
4001cb0ef41Sopenharmony_ci              new: 'newpassword1234',
4011cb0ef41Sopenharmony_ci            },
4021cb0ef41Sopenharmony_ci          },
4031cb0ef41Sopenharmony_ci          'should set new password'
4041cb0ef41Sopenharmony_ci        )
4051cb0ef41Sopenharmony_ci        return {
4061cb0ef41Sopenharmony_ci          ...userProfile,
4071cb0ef41Sopenharmony_ci        }
4081cb0ef41Sopenharmony_ci      },
4091cb0ef41Sopenharmony_ci    }
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci    const readUserInfo = {
4121cb0ef41Sopenharmony_ci      async password (label) {
4131cb0ef41Sopenharmony_ci        if (label === 'Current password: ') {
4141cb0ef41Sopenharmony_ci          t.ok('should interactively ask for password confirmation')
4151cb0ef41Sopenharmony_ci        } else if (label === 'New password: ') {
4161cb0ef41Sopenharmony_ci          t.ok('should interactively ask for new password')
4171cb0ef41Sopenharmony_ci        } else if (label === '       Again:     ') {
4181cb0ef41Sopenharmony_ci          t.ok('should interactively ask for new password confirmation')
4191cb0ef41Sopenharmony_ci        } else {
4201cb0ef41Sopenharmony_ci          throw new Error('Unexpected label: ' + label)
4211cb0ef41Sopenharmony_ci        }
4221cb0ef41Sopenharmony_ci
4231cb0ef41Sopenharmony_ci        return label === 'Current password: ' ? 'currentpassword1234' : 'newpassword1234'
4241cb0ef41Sopenharmony_ci      },
4251cb0ef41Sopenharmony_ci    }
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
4281cb0ef41Sopenharmony_ci      npmProfile,
4291cb0ef41Sopenharmony_ci      readUserInfo,
4301cb0ef41Sopenharmony_ci    })
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_ci    await profile.exec(['set', 'password'])
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_ci    t.equal(result(), 'Set password', 'should output set password success msg')
4351cb0ef41Sopenharmony_ci  })
4361cb0ef41Sopenharmony_ci
4371cb0ef41Sopenharmony_ci  t.test('password confirmation mismatch', async t => {
4381cb0ef41Sopenharmony_ci    t.plan(2)
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ci    let passwordPromptCount = 0
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci    const npmProfile = {
4431cb0ef41Sopenharmony_ci      async get () {
4441cb0ef41Sopenharmony_ci        return userProfile
4451cb0ef41Sopenharmony_ci      },
4461cb0ef41Sopenharmony_ci      async set () {
4471cb0ef41Sopenharmony_ci        return { ...userProfile }
4481cb0ef41Sopenharmony_ci      },
4491cb0ef41Sopenharmony_ci    }
4501cb0ef41Sopenharmony_ci
4511cb0ef41Sopenharmony_ci    const readUserInfo = {
4521cb0ef41Sopenharmony_ci      async password (label) {
4531cb0ef41Sopenharmony_ci        passwordPromptCount++
4541cb0ef41Sopenharmony_ci
4551cb0ef41Sopenharmony_ci        switch (label) {
4561cb0ef41Sopenharmony_ci          case 'Current password: ':
4571cb0ef41Sopenharmony_ci            return 'currentpassword1234'
4581cb0ef41Sopenharmony_ci          case 'New password: ':
4591cb0ef41Sopenharmony_ci            return passwordPromptCount < 3 ? 'password-that-will-not-be-confirmed' : 'newpassword'
4601cb0ef41Sopenharmony_ci          case '       Again:     ':
4611cb0ef41Sopenharmony_ci            return 'newpassword'
4621cb0ef41Sopenharmony_ci          default:
4631cb0ef41Sopenharmony_ci            return 'password1234'
4641cb0ef41Sopenharmony_ci        }
4651cb0ef41Sopenharmony_ci      },
4661cb0ef41Sopenharmony_ci    }
4671cb0ef41Sopenharmony_ci
4681cb0ef41Sopenharmony_ci    const { profile, result, logs } = await mockProfile(t, {
4691cb0ef41Sopenharmony_ci      npmProfile,
4701cb0ef41Sopenharmony_ci      readUserInfo,
4711cb0ef41Sopenharmony_ci    })
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci    await profile.exec(['set', 'password'])
4741cb0ef41Sopenharmony_ci
4751cb0ef41Sopenharmony_ci    t.equal(
4761cb0ef41Sopenharmony_ci      logs.warn[0][1],
4771cb0ef41Sopenharmony_ci      'Passwords do not match, please try again.',
4781cb0ef41Sopenharmony_ci      'should log password mismatch message'
4791cb0ef41Sopenharmony_ci    )
4801cb0ef41Sopenharmony_ci
4811cb0ef41Sopenharmony_ci    t.equal(result(), 'Set password', 'should output set password success msg')
4821cb0ef41Sopenharmony_ci  })
4831cb0ef41Sopenharmony_ci})
4841cb0ef41Sopenharmony_ci
4851cb0ef41Sopenharmony_cit.test('enable-2fa', async t => {
4861cb0ef41Sopenharmony_ci  t.test('invalid args', async t => {
4871cb0ef41Sopenharmony_ci    const { profile } = await mockProfile(t)
4881cb0ef41Sopenharmony_ci    await t.rejects(
4891cb0ef41Sopenharmony_ci      profile.exec(['enable-2fa', 'foo', 'bar']),
4901cb0ef41Sopenharmony_ci      /npm profile enable-2fa \[auth-and-writes|auth-only\]/,
4911cb0ef41Sopenharmony_ci      'should throw usage error'
4921cb0ef41Sopenharmony_ci    )
4931cb0ef41Sopenharmony_ci  })
4941cb0ef41Sopenharmony_ci
4951cb0ef41Sopenharmony_ci  t.test('invalid two factor auth mode', async t => {
4961cb0ef41Sopenharmony_ci    const { profile } = await mockProfile(t)
4971cb0ef41Sopenharmony_ci    await t.rejects(
4981cb0ef41Sopenharmony_ci      profile.exec(['enable-2fa', 'foo']),
4991cb0ef41Sopenharmony_ci      /Invalid two-factor authentication mode "foo"/,
5001cb0ef41Sopenharmony_ci      'should throw invalid auth mode error'
5011cb0ef41Sopenharmony_ci    )
5021cb0ef41Sopenharmony_ci  })
5031cb0ef41Sopenharmony_ci
5041cb0ef41Sopenharmony_ci  t.test('no support for --json output', async t => {
5051cb0ef41Sopenharmony_ci    const config = { json: true }
5061cb0ef41Sopenharmony_ci    const { profile } = await mockProfile(t, { config })
5071cb0ef41Sopenharmony_ci
5081cb0ef41Sopenharmony_ci    await t.rejects(
5091cb0ef41Sopenharmony_ci      profile.exec(['enable-2fa', 'auth-only']),
5101cb0ef41Sopenharmony_ci      'Enabling two-factor authentication is an interactive ' +
5111cb0ef41Sopenharmony_ci        'operation and JSON output mode is not available',
5121cb0ef41Sopenharmony_ci      'should throw no support msg'
5131cb0ef41Sopenharmony_ci    )
5141cb0ef41Sopenharmony_ci  })
5151cb0ef41Sopenharmony_ci
5161cb0ef41Sopenharmony_ci  t.test('no support for --parseable output', async t => {
5171cb0ef41Sopenharmony_ci    const config = { parseable: true }
5181cb0ef41Sopenharmony_ci    const { profile } = await mockProfile(t, { config })
5191cb0ef41Sopenharmony_ci
5201cb0ef41Sopenharmony_ci    await t.rejects(
5211cb0ef41Sopenharmony_ci      profile.exec(['enable-2fa', 'auth-only']),
5221cb0ef41Sopenharmony_ci      'Enabling two-factor authentication is an interactive ' +
5231cb0ef41Sopenharmony_ci        'operation and parseable output mode is not available',
5241cb0ef41Sopenharmony_ci      'should throw no support msg'
5251cb0ef41Sopenharmony_ci    )
5261cb0ef41Sopenharmony_ci  })
5271cb0ef41Sopenharmony_ci
5281cb0ef41Sopenharmony_ci  t.test('no bearer tokens returned by registry', async t => {
5291cb0ef41Sopenharmony_ci    t.plan(3)
5301cb0ef41Sopenharmony_ci
5311cb0ef41Sopenharmony_ci    const npmProfile = {
5321cb0ef41Sopenharmony_ci      async createToken (pass) {
5331cb0ef41Sopenharmony_ci        t.match(pass, 'bar', 'should use password for basic auth')
5341cb0ef41Sopenharmony_ci        return {}
5351cb0ef41Sopenharmony_ci      },
5361cb0ef41Sopenharmony_ci    }
5371cb0ef41Sopenharmony_ci
5381cb0ef41Sopenharmony_ci    const { npm, profile } = await mockProfile(t, {
5391cb0ef41Sopenharmony_ci      npmProfile,
5401cb0ef41Sopenharmony_ci    })
5411cb0ef41Sopenharmony_ci
5421cb0ef41Sopenharmony_ci    // mock legacy basic auth style
5431cb0ef41Sopenharmony_ci    // XXX: use mock registry
5441cb0ef41Sopenharmony_ci    npm.config.getCredentialsByURI = reg => {
5451cb0ef41Sopenharmony_ci      t.equal(reg, npm.flatOptions.registry, 'should use expected registry')
5461cb0ef41Sopenharmony_ci      return { auth: Buffer.from('foo:bar').toString('base64') }
5471cb0ef41Sopenharmony_ci    }
5481cb0ef41Sopenharmony_ci
5491cb0ef41Sopenharmony_ci    await t.rejects(
5501cb0ef41Sopenharmony_ci      profile.exec(['enable-2fa', 'auth-only']),
5511cb0ef41Sopenharmony_ci      'Your registry https://registry.npmjs.org/ does ' +
5521cb0ef41Sopenharmony_ci        'not seem to support bearer tokens. Bearer tokens ' +
5531cb0ef41Sopenharmony_ci        'are required for two-factor authentication',
5541cb0ef41Sopenharmony_ci      'should throw no support msg'
5551cb0ef41Sopenharmony_ci    )
5561cb0ef41Sopenharmony_ci  })
5571cb0ef41Sopenharmony_ci
5581cb0ef41Sopenharmony_ci  t.test('from basic username/password auth', async t => {
5591cb0ef41Sopenharmony_ci    const npmProfile = {
5601cb0ef41Sopenharmony_ci      async createToken (pass) {
5611cb0ef41Sopenharmony_ci        return {}
5621cb0ef41Sopenharmony_ci      },
5631cb0ef41Sopenharmony_ci    }
5641cb0ef41Sopenharmony_ci
5651cb0ef41Sopenharmony_ci    const { npm, profile } = await mockProfile(t, {
5661cb0ef41Sopenharmony_ci      npmProfile,
5671cb0ef41Sopenharmony_ci    })
5681cb0ef41Sopenharmony_ci
5691cb0ef41Sopenharmony_ci    // mock legacy basic auth style with user/pass
5701cb0ef41Sopenharmony_ci    // XXX: use mock registry
5711cb0ef41Sopenharmony_ci    npm.config.getCredentialsByURI = () => {
5721cb0ef41Sopenharmony_ci      return { username: 'foo', password: 'bar' }
5731cb0ef41Sopenharmony_ci    }
5741cb0ef41Sopenharmony_ci
5751cb0ef41Sopenharmony_ci    await t.rejects(
5761cb0ef41Sopenharmony_ci      profile.exec(['enable-2fa', 'auth-only']),
5771cb0ef41Sopenharmony_ci      'Your registry https://registry.npmjs.org/ does ' +
5781cb0ef41Sopenharmony_ci        'not seem to support bearer tokens. Bearer tokens ' +
5791cb0ef41Sopenharmony_ci        'are required for two-factor authentication',
5801cb0ef41Sopenharmony_ci      'should throw no support msg'
5811cb0ef41Sopenharmony_ci    )
5821cb0ef41Sopenharmony_ci  })
5831cb0ef41Sopenharmony_ci
5841cb0ef41Sopenharmony_ci  t.test('no auth found', async t => {
5851cb0ef41Sopenharmony_ci    const { npm, profile } = await mockProfile(t)
5861cb0ef41Sopenharmony_ci
5871cb0ef41Sopenharmony_ci    // XXX: use mock registry
5881cb0ef41Sopenharmony_ci    npm.config.getCredentialsByURI = () => ({})
5891cb0ef41Sopenharmony_ci
5901cb0ef41Sopenharmony_ci    await t.rejects(
5911cb0ef41Sopenharmony_ci      profile.exec(['enable-2fa', 'auth-only']),
5921cb0ef41Sopenharmony_ci      'You need to be logged in to registry ' + 'https://registry.npmjs.org/ in order to enable 2fa'
5931cb0ef41Sopenharmony_ci    )
5941cb0ef41Sopenharmony_ci  })
5951cb0ef41Sopenharmony_ci
5961cb0ef41Sopenharmony_ci  t.test('from basic auth, asks for otp', async t => {
5971cb0ef41Sopenharmony_ci    t.plan(9)
5981cb0ef41Sopenharmony_ci
5991cb0ef41Sopenharmony_ci    const npmProfile = {
6001cb0ef41Sopenharmony_ci      async createToken (pass) {
6011cb0ef41Sopenharmony_ci        t.match(pass, 'bar', 'should use password for basic auth')
6021cb0ef41Sopenharmony_ci        return { token: 'token' }
6031cb0ef41Sopenharmony_ci      },
6041cb0ef41Sopenharmony_ci      async get () {
6051cb0ef41Sopenharmony_ci        return userProfile
6061cb0ef41Sopenharmony_ci      },
6071cb0ef41Sopenharmony_ci      async set (newProfile, conf) {
6081cb0ef41Sopenharmony_ci        t.match(
6091cb0ef41Sopenharmony_ci          newProfile,
6101cb0ef41Sopenharmony_ci          {
6111cb0ef41Sopenharmony_ci            tfa: {
6121cb0ef41Sopenharmony_ci              mode: 'auth-only',
6131cb0ef41Sopenharmony_ci            },
6141cb0ef41Sopenharmony_ci          },
6151cb0ef41Sopenharmony_ci          'should set tfa mode'
6161cb0ef41Sopenharmony_ci        )
6171cb0ef41Sopenharmony_ci        return {
6181cb0ef41Sopenharmony_ci          ...userProfile,
6191cb0ef41Sopenharmony_ci          tfa: null,
6201cb0ef41Sopenharmony_ci        }
6211cb0ef41Sopenharmony_ci      },
6221cb0ef41Sopenharmony_ci    }
6231cb0ef41Sopenharmony_ci
6241cb0ef41Sopenharmony_ci    const readUserInfo = {
6251cb0ef41Sopenharmony_ci      async password () {
6261cb0ef41Sopenharmony_ci        t.ok('should interactively ask for password confirmation')
6271cb0ef41Sopenharmony_ci        return 'password1234'
6281cb0ef41Sopenharmony_ci      },
6291cb0ef41Sopenharmony_ci      async otp (label) {
6301cb0ef41Sopenharmony_ci        t.equal(
6311cb0ef41Sopenharmony_ci          label,
6321cb0ef41Sopenharmony_ci          'Enter one-time password: ',
6331cb0ef41Sopenharmony_ci          'should ask for otp confirmation'
6341cb0ef41Sopenharmony_ci        )
6351cb0ef41Sopenharmony_ci        return '123456'
6361cb0ef41Sopenharmony_ci      },
6371cb0ef41Sopenharmony_ci    }
6381cb0ef41Sopenharmony_ci
6391cb0ef41Sopenharmony_ci    const { npm, profile, result } = await mockProfile(t, {
6401cb0ef41Sopenharmony_ci      npmProfile,
6411cb0ef41Sopenharmony_ci      readUserInfo,
6421cb0ef41Sopenharmony_ci    })
6431cb0ef41Sopenharmony_ci
6441cb0ef41Sopenharmony_ci    // mock legacy basic auth style
6451cb0ef41Sopenharmony_ci    // XXX: use mock registry
6461cb0ef41Sopenharmony_ci    npm.config.getCredentialsByURI = reg => {
6471cb0ef41Sopenharmony_ci      t.equal(reg, npm.flatOptions.registry, 'should use expected registry')
6481cb0ef41Sopenharmony_ci      return { auth: Buffer.from('foo:bar').toString('base64') }
6491cb0ef41Sopenharmony_ci    }
6501cb0ef41Sopenharmony_ci    npm.config.setCredentialsByURI = (registry, { token }) => {
6511cb0ef41Sopenharmony_ci      t.equal(registry, npm.flatOptions.registry, 'should set expected registry')
6521cb0ef41Sopenharmony_ci      t.equal(token, 'token', 'should set expected token')
6531cb0ef41Sopenharmony_ci    }
6541cb0ef41Sopenharmony_ci    npm.config.save = type => {
6551cb0ef41Sopenharmony_ci      t.equal(type, 'user', 'should save to user config')
6561cb0ef41Sopenharmony_ci    }
6571cb0ef41Sopenharmony_ci
6581cb0ef41Sopenharmony_ci    await profile.exec(['enable-2fa', 'auth-only'])
6591cb0ef41Sopenharmony_ci    t.equal(
6601cb0ef41Sopenharmony_ci      result(),
6611cb0ef41Sopenharmony_ci      'Two factor authentication mode changed to: auth-only',
6621cb0ef41Sopenharmony_ci      'should output success msg'
6631cb0ef41Sopenharmony_ci    )
6641cb0ef41Sopenharmony_ci  })
6651cb0ef41Sopenharmony_ci
6661cb0ef41Sopenharmony_ci  t.test('from token and set otp, retries on pending and verifies with qrcode', async t => {
6671cb0ef41Sopenharmony_ci    t.plan(4)
6681cb0ef41Sopenharmony_ci
6691cb0ef41Sopenharmony_ci    let setCount = 0
6701cb0ef41Sopenharmony_ci    const npmProfile = {
6711cb0ef41Sopenharmony_ci      async get () {
6721cb0ef41Sopenharmony_ci        return {
6731cb0ef41Sopenharmony_ci          ...userProfile,
6741cb0ef41Sopenharmony_ci          tfa: {
6751cb0ef41Sopenharmony_ci            pending: true,
6761cb0ef41Sopenharmony_ci          },
6771cb0ef41Sopenharmony_ci        }
6781cb0ef41Sopenharmony_ci      },
6791cb0ef41Sopenharmony_ci      async set (newProfile, conf) {
6801cb0ef41Sopenharmony_ci        setCount++
6811cb0ef41Sopenharmony_ci
6821cb0ef41Sopenharmony_ci        // when profile response shows that 2fa is pending the
6831cb0ef41Sopenharmony_ci        // first time calling npm-profile.set should reset 2fa
6841cb0ef41Sopenharmony_ci        if (setCount === 1) {
6851cb0ef41Sopenharmony_ci          t.match(
6861cb0ef41Sopenharmony_ci            newProfile,
6871cb0ef41Sopenharmony_ci            {
6881cb0ef41Sopenharmony_ci              tfa: {
6891cb0ef41Sopenharmony_ci                password: 'password1234',
6901cb0ef41Sopenharmony_ci                mode: 'disable',
6911cb0ef41Sopenharmony_ci              },
6921cb0ef41Sopenharmony_ci            },
6931cb0ef41Sopenharmony_ci            'should reset 2fa'
6941cb0ef41Sopenharmony_ci          )
6951cb0ef41Sopenharmony_ci        } else if (setCount === 2) {
6961cb0ef41Sopenharmony_ci          t.match(
6971cb0ef41Sopenharmony_ci            newProfile,
6981cb0ef41Sopenharmony_ci            {
6991cb0ef41Sopenharmony_ci              tfa: {
7001cb0ef41Sopenharmony_ci                mode: 'auth-only',
7011cb0ef41Sopenharmony_ci              },
7021cb0ef41Sopenharmony_ci            },
7031cb0ef41Sopenharmony_ci            'should set tfa mode approprietly in follow-up call'
7041cb0ef41Sopenharmony_ci          )
7051cb0ef41Sopenharmony_ci        } else if (setCount === 3) {
7061cb0ef41Sopenharmony_ci          t.match(
7071cb0ef41Sopenharmony_ci            newProfile,
7081cb0ef41Sopenharmony_ci            {
7091cb0ef41Sopenharmony_ci              tfa: ['123456'],
7101cb0ef41Sopenharmony_ci            },
7111cb0ef41Sopenharmony_ci            'should set tfa as otp code?'
7121cb0ef41Sopenharmony_ci          )
7131cb0ef41Sopenharmony_ci          return {
7141cb0ef41Sopenharmony_ci            ...userProfile,
7151cb0ef41Sopenharmony_ci            tfa: ['123456', '789101'],
7161cb0ef41Sopenharmony_ci          }
7171cb0ef41Sopenharmony_ci        }
7181cb0ef41Sopenharmony_ci
7191cb0ef41Sopenharmony_ci        return {
7201cb0ef41Sopenharmony_ci          ...userProfile,
7211cb0ef41Sopenharmony_ci          tfa: 'otpauth://foo?secret=1234',
7221cb0ef41Sopenharmony_ci        }
7231cb0ef41Sopenharmony_ci      },
7241cb0ef41Sopenharmony_ci    }
7251cb0ef41Sopenharmony_ci
7261cb0ef41Sopenharmony_ci    const readUserInfo = {
7271cb0ef41Sopenharmony_ci      async password () {
7281cb0ef41Sopenharmony_ci        return 'password1234'
7291cb0ef41Sopenharmony_ci      },
7301cb0ef41Sopenharmony_ci      async otp () {
7311cb0ef41Sopenharmony_ci        return '123456'
7321cb0ef41Sopenharmony_ci      },
7331cb0ef41Sopenharmony_ci    }
7341cb0ef41Sopenharmony_ci
7351cb0ef41Sopenharmony_ci    const qrcode = {
7361cb0ef41Sopenharmony_ci      /* eslint-disable-next-line node/no-callback-literal */
7371cb0ef41Sopenharmony_ci      generate: (url, cb) => cb('qrcode'),
7381cb0ef41Sopenharmony_ci    }
7391cb0ef41Sopenharmony_ci
7401cb0ef41Sopenharmony_ci    const { npm, profile, result } = await mockProfile(t, {
7411cb0ef41Sopenharmony_ci      npmProfile,
7421cb0ef41Sopenharmony_ci      qrcode,
7431cb0ef41Sopenharmony_ci      readUserInfo,
7441cb0ef41Sopenharmony_ci      config: { otp: '1234' },
7451cb0ef41Sopenharmony_ci    })
7461cb0ef41Sopenharmony_ci
7471cb0ef41Sopenharmony_ci    // XXX: use mock registry
7481cb0ef41Sopenharmony_ci    npm.config.getCredentialsByURI = () => {
7491cb0ef41Sopenharmony_ci      return { token: 'token' }
7501cb0ef41Sopenharmony_ci    }
7511cb0ef41Sopenharmony_ci
7521cb0ef41Sopenharmony_ci    await profile.exec(['enable-2fa', 'auth-only'])
7531cb0ef41Sopenharmony_ci
7541cb0ef41Sopenharmony_ci    t.matchSnapshot(result(), 'should output 2fa enablement success msgs')
7551cb0ef41Sopenharmony_ci  })
7561cb0ef41Sopenharmony_ci
7571cb0ef41Sopenharmony_ci  t.test('from token and set otp, retrieves invalid otp', async t => {
7581cb0ef41Sopenharmony_ci    const npmProfile = {
7591cb0ef41Sopenharmony_ci      async get () {
7601cb0ef41Sopenharmony_ci        return {
7611cb0ef41Sopenharmony_ci          ...userProfile,
7621cb0ef41Sopenharmony_ci          tfa: {
7631cb0ef41Sopenharmony_ci            pending: true,
7641cb0ef41Sopenharmony_ci          },
7651cb0ef41Sopenharmony_ci        }
7661cb0ef41Sopenharmony_ci      },
7671cb0ef41Sopenharmony_ci      async set (newProfile, conf) {
7681cb0ef41Sopenharmony_ci        return {
7691cb0ef41Sopenharmony_ci          ...userProfile,
7701cb0ef41Sopenharmony_ci          tfa: 'http://foo?secret=1234',
7711cb0ef41Sopenharmony_ci        }
7721cb0ef41Sopenharmony_ci      },
7731cb0ef41Sopenharmony_ci    }
7741cb0ef41Sopenharmony_ci
7751cb0ef41Sopenharmony_ci    const readUserInfo = {
7761cb0ef41Sopenharmony_ci      async password () {
7771cb0ef41Sopenharmony_ci        return 'password1234'
7781cb0ef41Sopenharmony_ci      },
7791cb0ef41Sopenharmony_ci      async otp (label) {
7801cb0ef41Sopenharmony_ci        return '123456'
7811cb0ef41Sopenharmony_ci      },
7821cb0ef41Sopenharmony_ci    }
7831cb0ef41Sopenharmony_ci
7841cb0ef41Sopenharmony_ci    const { npm, profile } = await mockProfile(t, {
7851cb0ef41Sopenharmony_ci      npmProfile,
7861cb0ef41Sopenharmony_ci      readUserInfo,
7871cb0ef41Sopenharmony_ci      config: { otp: '1234' },
7881cb0ef41Sopenharmony_ci    })
7891cb0ef41Sopenharmony_ci
7901cb0ef41Sopenharmony_ci    npm.config.getCredentialsByURI = () => {
7911cb0ef41Sopenharmony_ci      return { token: 'token' }
7921cb0ef41Sopenharmony_ci    }
7931cb0ef41Sopenharmony_ci
7941cb0ef41Sopenharmony_ci    await t.rejects(
7951cb0ef41Sopenharmony_ci      profile.exec(['enable-2fa', 'auth-only']),
7961cb0ef41Sopenharmony_ci      /Unknown error enabling two-factor authentication./,
7971cb0ef41Sopenharmony_ci      'should throw invalid 2fa auth url error'
7981cb0ef41Sopenharmony_ci    )
7991cb0ef41Sopenharmony_ci  })
8001cb0ef41Sopenharmony_ci
8011cb0ef41Sopenharmony_ci  t.test('from token auth provides --otp config arg', async t => {
8021cb0ef41Sopenharmony_ci    const npmProfile = {
8031cb0ef41Sopenharmony_ci      async get () {
8041cb0ef41Sopenharmony_ci        return userProfile
8051cb0ef41Sopenharmony_ci      },
8061cb0ef41Sopenharmony_ci      async set (newProfile, conf) {
8071cb0ef41Sopenharmony_ci        return {
8081cb0ef41Sopenharmony_ci          ...userProfile,
8091cb0ef41Sopenharmony_ci          tfa: null,
8101cb0ef41Sopenharmony_ci        }
8111cb0ef41Sopenharmony_ci      },
8121cb0ef41Sopenharmony_ci    }
8131cb0ef41Sopenharmony_ci
8141cb0ef41Sopenharmony_ci    const readUserInfo = {
8151cb0ef41Sopenharmony_ci      async password () {
8161cb0ef41Sopenharmony_ci        return 'password1234'
8171cb0ef41Sopenharmony_ci      },
8181cb0ef41Sopenharmony_ci      async otp () {
8191cb0ef41Sopenharmony_ci        throw new Error('should not ask for otp')
8201cb0ef41Sopenharmony_ci      },
8211cb0ef41Sopenharmony_ci    }
8221cb0ef41Sopenharmony_ci
8231cb0ef41Sopenharmony_ci    const { npm, profile, result } = await mockProfile(t, {
8241cb0ef41Sopenharmony_ci      npmProfile,
8251cb0ef41Sopenharmony_ci      readUserInfo,
8261cb0ef41Sopenharmony_ci      config: { otp: '123456' },
8271cb0ef41Sopenharmony_ci    })
8281cb0ef41Sopenharmony_ci
8291cb0ef41Sopenharmony_ci    npm.config.getCredentialsByURI = reg => {
8301cb0ef41Sopenharmony_ci      return { token: 'token' }
8311cb0ef41Sopenharmony_ci    }
8321cb0ef41Sopenharmony_ci
8331cb0ef41Sopenharmony_ci    await profile.exec(['enable-2fa', 'auth-and-writes'])
8341cb0ef41Sopenharmony_ci
8351cb0ef41Sopenharmony_ci    t.equal(
8361cb0ef41Sopenharmony_ci      result(),
8371cb0ef41Sopenharmony_ci      'Two factor authentication mode changed to: auth-and-writes',
8381cb0ef41Sopenharmony_ci      'should output success msg'
8391cb0ef41Sopenharmony_ci    )
8401cb0ef41Sopenharmony_ci  })
8411cb0ef41Sopenharmony_ci
8421cb0ef41Sopenharmony_ci  t.test('missing tfa from user profile', async t => {
8431cb0ef41Sopenharmony_ci    const npmProfile = {
8441cb0ef41Sopenharmony_ci      async get () {
8451cb0ef41Sopenharmony_ci        return {
8461cb0ef41Sopenharmony_ci          ...userProfile,
8471cb0ef41Sopenharmony_ci          tfa: undefined,
8481cb0ef41Sopenharmony_ci        }
8491cb0ef41Sopenharmony_ci      },
8501cb0ef41Sopenharmony_ci      async set (newProfile, conf) {
8511cb0ef41Sopenharmony_ci        return {
8521cb0ef41Sopenharmony_ci          ...userProfile,
8531cb0ef41Sopenharmony_ci          tfa: null,
8541cb0ef41Sopenharmony_ci        }
8551cb0ef41Sopenharmony_ci      },
8561cb0ef41Sopenharmony_ci    }
8571cb0ef41Sopenharmony_ci
8581cb0ef41Sopenharmony_ci    const readUserInfo = {
8591cb0ef41Sopenharmony_ci      async password () {
8601cb0ef41Sopenharmony_ci        return 'password1234'
8611cb0ef41Sopenharmony_ci      },
8621cb0ef41Sopenharmony_ci      async otp () {
8631cb0ef41Sopenharmony_ci        return '123456'
8641cb0ef41Sopenharmony_ci      },
8651cb0ef41Sopenharmony_ci    }
8661cb0ef41Sopenharmony_ci
8671cb0ef41Sopenharmony_ci    const { npm, profile, result } = await mockProfile(t, {
8681cb0ef41Sopenharmony_ci      npmProfile,
8691cb0ef41Sopenharmony_ci      readUserInfo,
8701cb0ef41Sopenharmony_ci    })
8711cb0ef41Sopenharmony_ci
8721cb0ef41Sopenharmony_ci    npm.config.getCredentialsByURI = reg => {
8731cb0ef41Sopenharmony_ci      return { token: 'token' }
8741cb0ef41Sopenharmony_ci    }
8751cb0ef41Sopenharmony_ci
8761cb0ef41Sopenharmony_ci    await profile.exec(['enable-2fa', 'auth-only'])
8771cb0ef41Sopenharmony_ci
8781cb0ef41Sopenharmony_ci    t.equal(
8791cb0ef41Sopenharmony_ci      result(),
8801cb0ef41Sopenharmony_ci      'Two factor authentication mode changed to: auth-only',
8811cb0ef41Sopenharmony_ci      'should output success msg'
8821cb0ef41Sopenharmony_ci    )
8831cb0ef41Sopenharmony_ci  })
8841cb0ef41Sopenharmony_ci
8851cb0ef41Sopenharmony_ci  t.test('defaults to auth-and-writes permission if no mode specified', async t => {
8861cb0ef41Sopenharmony_ci    const npmProfile = {
8871cb0ef41Sopenharmony_ci      async get () {
8881cb0ef41Sopenharmony_ci        return {
8891cb0ef41Sopenharmony_ci          ...userProfile,
8901cb0ef41Sopenharmony_ci          tfa: undefined,
8911cb0ef41Sopenharmony_ci        }
8921cb0ef41Sopenharmony_ci      },
8931cb0ef41Sopenharmony_ci      async set (newProfile, conf) {
8941cb0ef41Sopenharmony_ci        return {
8951cb0ef41Sopenharmony_ci          ...userProfile,
8961cb0ef41Sopenharmony_ci          tfa: null,
8971cb0ef41Sopenharmony_ci        }
8981cb0ef41Sopenharmony_ci      },
8991cb0ef41Sopenharmony_ci    }
9001cb0ef41Sopenharmony_ci
9011cb0ef41Sopenharmony_ci    const readUserInfo = {
9021cb0ef41Sopenharmony_ci      async password () {
9031cb0ef41Sopenharmony_ci        return 'password1234'
9041cb0ef41Sopenharmony_ci      },
9051cb0ef41Sopenharmony_ci      async otp () {
9061cb0ef41Sopenharmony_ci        return '123456'
9071cb0ef41Sopenharmony_ci      },
9081cb0ef41Sopenharmony_ci    }
9091cb0ef41Sopenharmony_ci
9101cb0ef41Sopenharmony_ci    const { npm, profile, result } = await mockProfile(t, {
9111cb0ef41Sopenharmony_ci      npmProfile,
9121cb0ef41Sopenharmony_ci      readUserInfo,
9131cb0ef41Sopenharmony_ci    })
9141cb0ef41Sopenharmony_ci
9151cb0ef41Sopenharmony_ci    npm.config.getCredentialsByURI = reg => {
9161cb0ef41Sopenharmony_ci      return { token: 'token' }
9171cb0ef41Sopenharmony_ci    }
9181cb0ef41Sopenharmony_ci
9191cb0ef41Sopenharmony_ci    await profile.exec(['enable-2fa'])
9201cb0ef41Sopenharmony_ci    t.equal(
9211cb0ef41Sopenharmony_ci      result(),
9221cb0ef41Sopenharmony_ci      'Two factor authentication mode changed to: auth-and-writes',
9231cb0ef41Sopenharmony_ci      'should enable 2fa with auth-and-writes permission'
9241cb0ef41Sopenharmony_ci    )
9251cb0ef41Sopenharmony_ci  })
9261cb0ef41Sopenharmony_ci})
9271cb0ef41Sopenharmony_ci
9281cb0ef41Sopenharmony_cit.test('disable-2fa', async t => {
9291cb0ef41Sopenharmony_ci  t.test('no tfa enabled', async t => {
9301cb0ef41Sopenharmony_ci    const npmProfile = {
9311cb0ef41Sopenharmony_ci      async get () {
9321cb0ef41Sopenharmony_ci        return {
9331cb0ef41Sopenharmony_ci          ...userProfile,
9341cb0ef41Sopenharmony_ci          tfa: null,
9351cb0ef41Sopenharmony_ci        }
9361cb0ef41Sopenharmony_ci      },
9371cb0ef41Sopenharmony_ci    }
9381cb0ef41Sopenharmony_ci
9391cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
9401cb0ef41Sopenharmony_ci      npmProfile,
9411cb0ef41Sopenharmony_ci    })
9421cb0ef41Sopenharmony_ci
9431cb0ef41Sopenharmony_ci    await profile.exec(['disable-2fa'])
9441cb0ef41Sopenharmony_ci    t.equal(result(), 'Two factor authentication not enabled.',
9451cb0ef41Sopenharmony_ci      'should output already disalbed msg')
9461cb0ef41Sopenharmony_ci  })
9471cb0ef41Sopenharmony_ci
9481cb0ef41Sopenharmony_ci  t.test('requests otp', async t => {
9491cb0ef41Sopenharmony_ci    const npmProfile = t => ({
9501cb0ef41Sopenharmony_ci      async get () {
9511cb0ef41Sopenharmony_ci        return userProfile
9521cb0ef41Sopenharmony_ci      },
9531cb0ef41Sopenharmony_ci      async set (newProfile, conf) {
9541cb0ef41Sopenharmony_ci        t.same(
9551cb0ef41Sopenharmony_ci          newProfile,
9561cb0ef41Sopenharmony_ci          {
9571cb0ef41Sopenharmony_ci            tfa: {
9581cb0ef41Sopenharmony_ci              password: 'password1234',
9591cb0ef41Sopenharmony_ci              mode: 'disable',
9601cb0ef41Sopenharmony_ci            },
9611cb0ef41Sopenharmony_ci          },
9621cb0ef41Sopenharmony_ci          'should send the new info for setting in profile'
9631cb0ef41Sopenharmony_ci        )
9641cb0ef41Sopenharmony_ci      },
9651cb0ef41Sopenharmony_ci    })
9661cb0ef41Sopenharmony_ci
9671cb0ef41Sopenharmony_ci    const readUserInfo = t => ({
9681cb0ef41Sopenharmony_ci      async password () {
9691cb0ef41Sopenharmony_ci        t.ok('should interactively ask for password confirmation')
9701cb0ef41Sopenharmony_ci        return 'password1234'
9711cb0ef41Sopenharmony_ci      },
9721cb0ef41Sopenharmony_ci      async otp (label) {
9731cb0ef41Sopenharmony_ci        t.equal(
9741cb0ef41Sopenharmony_ci          label,
9751cb0ef41Sopenharmony_ci          'Enter one-time password: ',
9761cb0ef41Sopenharmony_ci          'should ask for otp confirmation'
9771cb0ef41Sopenharmony_ci        )
9781cb0ef41Sopenharmony_ci        return '1234'
9791cb0ef41Sopenharmony_ci      },
9801cb0ef41Sopenharmony_ci    })
9811cb0ef41Sopenharmony_ci
9821cb0ef41Sopenharmony_ci    t.test('default output', async t => {
9831cb0ef41Sopenharmony_ci      t.plan(4)
9841cb0ef41Sopenharmony_ci
9851cb0ef41Sopenharmony_ci      const { profile, result } = await mockProfile(t, {
9861cb0ef41Sopenharmony_ci        npmProfile: npmProfile(t),
9871cb0ef41Sopenharmony_ci        readUserInfo: readUserInfo(t),
9881cb0ef41Sopenharmony_ci      })
9891cb0ef41Sopenharmony_ci
9901cb0ef41Sopenharmony_ci      await profile.exec(['disable-2fa'])
9911cb0ef41Sopenharmony_ci      t.equal(result(), 'Two factor authentication disabled.', 'should output already disabled msg')
9921cb0ef41Sopenharmony_ci    })
9931cb0ef41Sopenharmony_ci
9941cb0ef41Sopenharmony_ci    t.test('--json', async t => {
9951cb0ef41Sopenharmony_ci      t.plan(4)
9961cb0ef41Sopenharmony_ci
9971cb0ef41Sopenharmony_ci      const config = { json: true }
9981cb0ef41Sopenharmony_ci
9991cb0ef41Sopenharmony_ci      const { profile, result } = await mockProfile(t, {
10001cb0ef41Sopenharmony_ci        npmProfile: npmProfile(t),
10011cb0ef41Sopenharmony_ci        readUserInfo: readUserInfo(t),
10021cb0ef41Sopenharmony_ci        config,
10031cb0ef41Sopenharmony_ci      })
10041cb0ef41Sopenharmony_ci
10051cb0ef41Sopenharmony_ci      await profile.exec(['disable-2fa'])
10061cb0ef41Sopenharmony_ci
10071cb0ef41Sopenharmony_ci      t.same(JSON.parse(result()), { tfa: false }, 'should output json already disabled msg')
10081cb0ef41Sopenharmony_ci    })
10091cb0ef41Sopenharmony_ci
10101cb0ef41Sopenharmony_ci    t.test('--parseable', async t => {
10111cb0ef41Sopenharmony_ci      t.plan(4)
10121cb0ef41Sopenharmony_ci
10131cb0ef41Sopenharmony_ci      const config = { parseable: true }
10141cb0ef41Sopenharmony_ci
10151cb0ef41Sopenharmony_ci      const { profile, result } = await mockProfile(t, {
10161cb0ef41Sopenharmony_ci        npmProfile: npmProfile(t),
10171cb0ef41Sopenharmony_ci        readUserInfo: readUserInfo(t),
10181cb0ef41Sopenharmony_ci        config,
10191cb0ef41Sopenharmony_ci      })
10201cb0ef41Sopenharmony_ci
10211cb0ef41Sopenharmony_ci      await profile.exec(['disable-2fa'])
10221cb0ef41Sopenharmony_ci
10231cb0ef41Sopenharmony_ci      t.equal(result(), 'tfa\tfalse', 'should output parseable already disabled msg')
10241cb0ef41Sopenharmony_ci    })
10251cb0ef41Sopenharmony_ci  })
10261cb0ef41Sopenharmony_ci
10271cb0ef41Sopenharmony_ci  t.test('--otp config already set', async t => {
10281cb0ef41Sopenharmony_ci    t.plan(2)
10291cb0ef41Sopenharmony_ci
10301cb0ef41Sopenharmony_ci    const npmProfile = {
10311cb0ef41Sopenharmony_ci      async get () {
10321cb0ef41Sopenharmony_ci        return userProfile
10331cb0ef41Sopenharmony_ci      },
10341cb0ef41Sopenharmony_ci      async set (newProfile, conf) {
10351cb0ef41Sopenharmony_ci        t.same(
10361cb0ef41Sopenharmony_ci          newProfile,
10371cb0ef41Sopenharmony_ci          {
10381cb0ef41Sopenharmony_ci            tfa: {
10391cb0ef41Sopenharmony_ci              password: 'password1234',
10401cb0ef41Sopenharmony_ci              mode: 'disable',
10411cb0ef41Sopenharmony_ci            },
10421cb0ef41Sopenharmony_ci          },
10431cb0ef41Sopenharmony_ci          'should send the new info for setting in profile'
10441cb0ef41Sopenharmony_ci        )
10451cb0ef41Sopenharmony_ci      },
10461cb0ef41Sopenharmony_ci    }
10471cb0ef41Sopenharmony_ci
10481cb0ef41Sopenharmony_ci    const readUserInfo = {
10491cb0ef41Sopenharmony_ci      async password () {
10501cb0ef41Sopenharmony_ci        return 'password1234'
10511cb0ef41Sopenharmony_ci      },
10521cb0ef41Sopenharmony_ci      async otp (label) {
10531cb0ef41Sopenharmony_ci        throw new Error('should not ask for otp')
10541cb0ef41Sopenharmony_ci      },
10551cb0ef41Sopenharmony_ci    }
10561cb0ef41Sopenharmony_ci
10571cb0ef41Sopenharmony_ci    const { profile, result } = await mockProfile(t, {
10581cb0ef41Sopenharmony_ci      npmProfile,
10591cb0ef41Sopenharmony_ci      readUserInfo,
10601cb0ef41Sopenharmony_ci      config: { otp: '123456' },
10611cb0ef41Sopenharmony_ci    })
10621cb0ef41Sopenharmony_ci
10631cb0ef41Sopenharmony_ci    await profile.exec(['disable-2fa'])
10641cb0ef41Sopenharmony_ci
10651cb0ef41Sopenharmony_ci    t.equal(result(), 'Two factor authentication disabled.', 'should output already disalbed msg')
10661cb0ef41Sopenharmony_ci  })
10671cb0ef41Sopenharmony_ci})
10681cb0ef41Sopenharmony_ci
10691cb0ef41Sopenharmony_cit.test('unknown subcommand', async t => {
10701cb0ef41Sopenharmony_ci  const { profile } = await mockProfile(t)
10711cb0ef41Sopenharmony_ci
10721cb0ef41Sopenharmony_ci  await t.rejects(
10731cb0ef41Sopenharmony_ci    profile.exec(['asfd']),
10741cb0ef41Sopenharmony_ci    /Unknown profile command: asfd/,
10751cb0ef41Sopenharmony_ci    'should throw unknown cmd error'
10761cb0ef41Sopenharmony_ci  )
10771cb0ef41Sopenharmony_ci})
10781cb0ef41Sopenharmony_ci
10791cb0ef41Sopenharmony_cit.test('completion', async t => {
10801cb0ef41Sopenharmony_ci  const testComp = async (t, { argv, expect, title } = {}) => {
10811cb0ef41Sopenharmony_ci    const { profile } = await mockProfile(t)
10821cb0ef41Sopenharmony_ci    t.resolveMatch(profile.completion({ conf: { argv: { remain: argv } } }), expect, title)
10831cb0ef41Sopenharmony_ci  }
10841cb0ef41Sopenharmony_ci
10851cb0ef41Sopenharmony_ci  t.test('npm profile autocomplete', async t => {
10861cb0ef41Sopenharmony_ci    await testComp(t, {
10871cb0ef41Sopenharmony_ci      argv: ['npm', 'profile'],
10881cb0ef41Sopenharmony_ci      expect: ['enable-2fa', 'disable-2fa', 'get', 'set'],
10891cb0ef41Sopenharmony_ci      title: 'should auto complete with subcommands',
10901cb0ef41Sopenharmony_ci    })
10911cb0ef41Sopenharmony_ci  })
10921cb0ef41Sopenharmony_ci
10931cb0ef41Sopenharmony_ci  t.test('npm profile enable autocomplete', async t => {
10941cb0ef41Sopenharmony_ci    await testComp(t, {
10951cb0ef41Sopenharmony_ci      argv: ['npm', 'profile', 'enable-2fa'],
10961cb0ef41Sopenharmony_ci      expect: ['auth-and-writes', 'auth-only'],
10971cb0ef41Sopenharmony_ci      title: 'should auto complete with auth types',
10981cb0ef41Sopenharmony_ci    })
10991cb0ef41Sopenharmony_ci  })
11001cb0ef41Sopenharmony_ci
11011cb0ef41Sopenharmony_ci  t.test('npm profile <subcmd> no autocomplete', async t => {
11021cb0ef41Sopenharmony_ci    const noAutocompleteCmds = ['disable-2fa', 'disable-tfa', 'get', 'set']
11031cb0ef41Sopenharmony_ci    for (const subcmd of noAutocompleteCmds) {
11041cb0ef41Sopenharmony_ci      await t.test(subcmd, t => testComp(t, {
11051cb0ef41Sopenharmony_ci        argv: ['npm', 'profile', subcmd],
11061cb0ef41Sopenharmony_ci        expect: [],
11071cb0ef41Sopenharmony_ci        title: `${subcmd} should have no autocomplete`,
11081cb0ef41Sopenharmony_ci      }))
11091cb0ef41Sopenharmony_ci    }
11101cb0ef41Sopenharmony_ci  })
11111cb0ef41Sopenharmony_ci
11121cb0ef41Sopenharmony_ci  t.test('npm profile unknown subcommand autocomplete', async t => {
11131cb0ef41Sopenharmony_ci    const { profile } = await mockProfile(t)
11141cb0ef41Sopenharmony_ci    t.rejects(
11151cb0ef41Sopenharmony_ci      profile.completion({ conf: { argv: { remain: ['npm', 'profile', 'asdf'] } } }),
11161cb0ef41Sopenharmony_ci      { message: 'asdf not recognized' },
11171cb0ef41Sopenharmony_ci      'should throw unknown cmd error'
11181cb0ef41Sopenharmony_ci    )
11191cb0ef41Sopenharmony_ci  })
11201cb0ef41Sopenharmony_ci})
1121