Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorGar <gar+gh@danger.computer>2022-09-21 23:07:30 +0300
committerGitHub <noreply@github.com>2022-09-21 23:07:30 +0300
commit314311c61b8f341715c168199d52976ee3237077 (patch)
tree18ce4d66ecf0a73ba974f1ed1ccf3c032fb7cd72 /test
parentd3ff2aa9b57d7448c5770ba307118ce4c3b6a888 (diff)
feat: separate login/adduser, remove auth types (#5550)
The difference between `adduser` and `login` depends on the `auth-type`. - `web`: the POST to `/-/v1/login` contains a `{ create: true }` value in its payload for `adduser` - `legacy` the `PUT` request to `/-/user/org.couchdb.user:${username}` contains an `email` value in its payload for `adduser`. BREAKING CHANGE: `login`, `adduser`, and `auth-type` changes - This removes all `auth-type` configs except `web` and `legacy`. - `login` and `adduser` are now separate commands that send different data to the registry. - `auth-type` config values `web` and `legacy` only try their respective methods, npm no longer tries them all and waits to see which one doesn't fail.
Diffstat (limited to 'test')
-rw-r--r--test/fixtures/mock-registry.js57
-rw-r--r--test/lib/auth/legacy.js429
-rw-r--r--test/lib/auth/oauth.js28
-rw-r--r--test/lib/auth/saml.js28
-rw-r--r--test/lib/auth/sso.js236
-rw-r--r--test/lib/commands/adduser.js315
-rw-r--r--test/lib/commands/login.js151
7 files changed, 357 insertions, 887 deletions
diff --git a/test/fixtures/mock-registry.js b/test/fixtures/mock-registry.js
index 65d475962..d978929b6 100644
--- a/test/fixtures/mock-registry.js
+++ b/test/fixtures/mock-registry.js
@@ -111,17 +111,12 @@ class MockRegistry {
}
}
- couchlogin ({ username, password, email, otp, token = 'npm_default-test-token' }) {
- this.nock = this.nock
- .post('/-/v1/login').reply(401, { error: 'You must be logged in to publish packages.' })
- if (otp) {
- // TODO otp failure results in a 401 with
- // {"ok":false,"error":"failed to authenticate: Could not authenticate ${username}: bad otp"}
- }
+ couchadduser ({ username, email, password, token = 'npm_default-test-token' }) {
this.nock = this.nock.put(`/-/user/org.couchdb.user:${username}`, body => {
this.#tap.match(body, {
_id: `org.couchdb.user:${username}`,
name: username,
+ email, // Sole difference from couchlogin
password,
type: 'user',
roles: [],
@@ -131,13 +126,59 @@ class MockRegistry {
}
return true
}).reply(201, {
- ok: true,
id: 'org.couchdb.user:undefined',
rev: '_we_dont_use_revs_any_more',
token,
})
}
+ couchlogin ({ username, password, token = 'npm_default-test-token' }) {
+ this.nock = this.nock.put(`/-/user/org.couchdb.user:${username}`, body => {
+ this.#tap.match(body, {
+ _id: `org.couchdb.user:${username}`,
+ name: username,
+ password,
+ type: 'user',
+ roles: [],
+ })
+ if (!body.date) {
+ return false
+ }
+ return true
+ }).reply(201, {
+ id: 'org.couchdb.user:undefined',
+ rev: '_we_dont_use_revs_any_more',
+ token,
+ })
+ }
+
+ webadduser ({ username, password, token = 'npm_default-test-token' }) {
+ const doneUrl = new URL('/npm-cli-test/done', this.#registry).href
+ const loginUrl = new URL('/npm-cli-test/login', this.#registry).href
+ this.nock = this.nock
+ .post('/-/v1/login', body => {
+ this.#tap.ok(body.create) // Sole difference from weblogin
+ this.#tap.ok(body.hostname)
+ return true
+ })
+ .reply(200, { doneUrl, loginUrl })
+ .get('/npm-cli-test/done')
+ .reply(200, { token })
+ }
+
+ weblogin ({ token = 'npm_default-test-token' }) {
+ const doneUrl = new URL('/npm-cli-test/done', this.#registry).href
+ const loginUrl = new URL('/npm-cli-test/login', this.#registry).href
+ this.nock = this.nock
+ .post('/-/v1/login', body => {
+ this.#tap.ok(body.hostname)
+ return true
+ })
+ .reply(200, { doneUrl, loginUrl })
+ .get('/npm-cli-test/done')
+ .reply(200, { token })
+ }
+
// team can be a team or a username
getPackages ({ team, packages = {}, times = 1 }) {
if (team.startsWith('@')) {
diff --git a/test/lib/auth/legacy.js b/test/lib/auth/legacy.js
deleted file mode 100644
index 39d977d43..000000000
--- a/test/lib/auth/legacy.js
+++ /dev/null
@@ -1,429 +0,0 @@
-const t = require('tap')
-
-let log = ''
-
-const token = '24528a24f240'
-const profile = {}
-const read = {}
-const legacy = t.mock('../../../lib/auth/legacy.js', {
- 'proc-log': {
- info: (...msgs) => {
- log += msgs.join(' ')
- },
- },
- 'npm-profile': profile,
- '../../../lib/utils/open-url-prompt.js': (_npm, url) => {
- if (!url) {
- throw Object.assign(new Error('failed open url'), { code: 'ERROR' })
- }
- },
- '../../../lib/utils/read-user-info.js': read,
-})
-
-const npm = {
- config: {
- get: () => null,
- },
-}
-
-t.test('login using username/password with token result', async (t) => {
- profile.login = () => {
- return { token }
- }
-
- const {
- message,
- newCreds,
- } = await legacy(npm, {
- creds: {
- username: 'u',
- password: 'p',
- email: 'u@npmjs.org',
- alwaysAuth: false,
- },
- registry: 'https://registry.npmjs.org/',
- scope: '',
- })
-
- t.equal(
- message,
- 'Logged in as u on https://registry.npmjs.org/.',
- 'should have correct message result'
- )
-
- t.equal(
- log,
- 'login Authorized user u',
- 'should have correct message result'
- )
-
- t.same(
- newCreds,
- { token },
- 'should return expected obj from profile.login'
- )
-
- log = ''
- delete profile.login
-})
-
-t.test('login using username/password with user info result', async (t) => {
- profile.login = () => {
- return null
- }
-
- const {
- message,
- newCreds,
- } = await legacy(npm, {
- creds: {
- username: 'u',
- password: 'p',
- email: 'u@npmjs.org',
- alwaysAuth: false,
- },
- registry: 'https://registry.npmjs.org/',
- scope: '',
- })
-
- t.equal(
- message,
- 'Logged in as u on https://registry.npmjs.org/.',
- 'should have correct message result'
- )
-
- t.same(
- newCreds,
- {
- username: 'u',
- password: 'p',
- email: 'u@npmjs.org',
- alwaysAuth: false,
- },
- 'should return used credentials'
- )
-
- log = ''
- delete profile.login
-})
-
-t.test('login otp requested', async (t) => {
- t.plan(5)
-
- profile.login = () => Promise.reject(Object.assign(
- new Error('needs otp'),
- { code: 'EOTP' }
- ))
- profile.loginCouch = (username, password, { otp }) => {
- t.equal(username, 'u', 'should use provided username to loginCouch')
- t.equal(password, 'p', 'should use provided password to loginCouch')
- t.equal(otp, '1234', 'should use provided otp code to loginCouch')
-
- return { token }
- }
- read.otp = () => Promise.resolve('1234')
-
- const {
- message,
- newCreds,
- } = await legacy(npm, {
- creds: {
- username: 'u',
- password: 'p',
- email: 'u@npmjs.org',
- alwaysAuth: false,
- },
- registry: 'https://registry.npmjs.org/',
- scope: '',
- })
-
- t.equal(
- message,
- 'Logged in as u on https://registry.npmjs.org/.',
- 'should have correct message result'
- )
-
- t.same(
- newCreds,
- { token },
- 'should return token from loginCouch result'
- )
-
- log = ''
- delete profile.login
- delete profile.loginCouch
- delete read.otp
-})
-
-t.test('login missing basic credential info', async (t) => {
- profile.login = () => Promise.reject(Object.assign(
- new Error('missing info'),
- { code: 'ERROR' }
- ))
-
- await t.rejects(
- legacy(npm, {
- creds: {
- username: 'u',
- password: 'p',
- },
- registry: 'https://registry.npmjs.org/',
- scope: '',
- }),
- { code: 'ERROR' },
- 'should throw server response error'
- )
-
- log = ''
- delete profile.login
-})
-
-t.test('create new user when user not found', async (t) => {
- t.plan(6)
-
- profile.login = () => Promise.reject(Object.assign(
- new Error('User does not exist'),
- { code: 'ERROR' }
- ))
- profile.adduserCouch = (username, email, password) => {
- t.equal(username, 'u', 'should use provided username to adduserCouch')
- t.equal(email, 'u@npmjs.org', 'should use provided email to adduserCouch')
- t.equal(password, 'p', 'should use provided password to adduserCouch')
-
- return { token }
- }
-
- const {
- message,
- newCreds,
- } = await legacy(npm, {
- creds: {
- username: 'u',
- password: 'p',
- email: 'u@npmjs.org',
- alwaysAuth: false,
- },
- registry: 'https://registry.npmjs.org/',
- scope: '',
- })
-
- t.equal(
- message,
- 'Logged in as u on https://registry.npmjs.org/.',
- 'should have correct message result'
- )
-
- t.equal(
- log,
- 'login Authorized user u',
- 'should have correct message result'
- )
-
- t.same(
- newCreds,
- { token },
- 'should return expected obj from profile.login'
- )
-
- log = ''
- delete profile.adduserCouch
- delete profile.login
-})
-
-t.test('prompts for user info if required', async (t) => {
- t.plan(4)
-
- profile.login = async (opener, prompt, opts) => {
- t.equal(opts.creds.alwaysAuth, true, 'should have refs to creds if any')
- await opener('https://registry.npmjs.org/-/v1/login')
- const creds = await prompt(opts.creds)
- return creds
- }
- read.username = () => Promise.resolve('foo')
- read.password = () => Promise.resolve('pass')
- read.email = () => Promise.resolve('foo@npmjs.org')
-
- const {
- message,
- newCreds,
- } = await legacy(npm, {
- creds: {
- alwaysAuth: true,
- },
- registry: 'https://registry.npmjs.org/',
- scope: '',
- })
-
- t.equal(
- message,
- 'Logged in as foo on https://registry.npmjs.org/.',
- 'should have correct message result'
- )
-
- t.equal(
- log,
- 'login Authorized user foo',
- 'should have correct message result'
- )
-
- t.same(
- newCreds,
- {
- username: 'foo',
- password: 'pass',
- email: 'foo@npmjs.org',
- alwaysAuth: true,
- },
- 'should return result from profile.login containing prompt info'
- )
-
- log = ''
- delete profile.login
- delete read.username
- delete read.password
- delete read.email
-})
-
-t.test('request otp when creating new user', async (t) => {
- t.plan(3)
-
- profile.login = () => Promise.reject(Object.assign(
- new Error('User does not exist'),
- { code: 'ERROR' }
- ))
- profile.adduserCouch = () => Promise.reject(Object.assign(
- new Error('needs otp'),
- { code: 'EOTP' }
- ))
- profile.loginCouch = (username, password, { otp }) => {
- t.equal(username, 'u', 'should use provided username to loginCouch')
- t.equal(password, 'p', 'should use provided password to loginCouch')
- t.equal(otp, '1234', 'should now use provided otp code to loginCouch')
-
- return { token }
- }
- read.otp = () => Promise.resolve('1234')
-
- await legacy(npm, {
- creds: {
- username: 'u',
- password: 'p',
- email: 'u@npmjs.org',
- alwaysAuth: false,
- },
- registry: 'https://registry.npmjs.org/',
- scope: '',
- })
-
- log = ''
- delete profile.adduserCouch
- delete profile.login
- delete profile.loginCouch
- delete read.otp
-})
-
-t.test('unknown error during user creation', async (t) => {
- profile.login = () => Promise.reject(Object.assign(
- new Error('missing info'),
- { code: 'ERROR' }
- ))
- profile.adduserCouch = () => Promise.reject(Object.assign(
- new Error('unkown error'),
- { code: 'ERROR' }
- ))
-
- await t.rejects(
- legacy(npm, {
- creds: {
- username: 'u',
- password: 'p',
- email: 'u@npmjs.org',
- alwaysAuth: false,
- },
- registry: 'https://registry.npmjs.org/',
- scope: '',
- }),
- { code: 'ERROR' },
- 'should throw unknown error'
- )
-
- log = ''
- delete profile.adduserCouch
- delete profile.login
-})
-
-t.test('open url error', async (t) => {
- profile.login = async (opener, prompt, opts) => {
- await opener()
- }
-
- await t.rejects(
- legacy(npm, {
- creds: {
- username: 'u',
- password: 'p',
- },
- registry: 'https://registry.npmjs.org/',
- scope: '',
- }),
- { message: 'failed open url', code: 'ERROR' },
- 'should throw unknown error'
- )
-
- log = ''
- delete profile.login
-})
-
-t.test('login no credentials provided', async (t) => {
- profile.login = () => ({ token })
-
- await legacy(npm, {
- creds: {
- username: undefined,
- password: undefined,
- email: undefined,
- alwaysAuth: undefined,
- },
- registry: 'https://registry.npmjs.org/',
- scope: '',
- })
-
- t.equal(
- log,
- 'login Authorized',
- 'should have correct message result'
- )
-
- log = ''
- delete profile.login
-})
-
-t.test('scoped login', async (t) => {
- profile.login = () => ({ token })
-
- const { message } = await legacy(npm, {
- creds: {
- username: 'u',
- password: 'p',
- email: 'u@npmjs.org',
- alwaysAuth: false,
- },
- registry: 'https://diff-registry.npmjs.org/',
- scope: 'myscope',
- })
-
- t.equal(
- message,
- 'Logged in as u to scope myscope on https://diff-registry.npmjs.org/.',
- 'should have correct message result'
- )
-
- t.equal(
- log,
- 'login Authorized user u',
- 'should have correct message result'
- )
-
- log = ''
- delete profile.login
-})
diff --git a/test/lib/auth/oauth.js b/test/lib/auth/oauth.js
deleted file mode 100644
index 0c317fb9a..000000000
--- a/test/lib/auth/oauth.js
+++ /dev/null
@@ -1,28 +0,0 @@
-const t = require('tap')
-
-t.test('oauth login', (t) => {
- t.plan(3)
- const oauthOpts = {
- creds: {},
- registry: 'https://diff-registry.npmjs.org/',
- scope: 'myscope',
- }
-
- const npm = {
- config: {
- set: (key, value) => {
- t.equal(key, 'sso-type', 'should define sso-type')
- t.equal(value, 'oauth', 'should set sso-type to oauth')
- },
- },
- }
- const oauth = t.mock('../../../lib/auth/oauth.js', {
- '../../../lib/auth/sso.js': (npm, opts) => {
- t.equal(opts, oauthOpts, 'should forward opts')
- },
- })
-
- oauth(npm, oauthOpts)
-
- t.end()
-})
diff --git a/test/lib/auth/saml.js b/test/lib/auth/saml.js
deleted file mode 100644
index 1558e0db8..000000000
--- a/test/lib/auth/saml.js
+++ /dev/null
@@ -1,28 +0,0 @@
-const t = require('tap')
-
-t.test('saml login', (t) => {
- t.plan(3)
- const samlOpts = {
- creds: {},
- registry: 'https://diff-registry.npmjs.org/',
- scope: 'myscope',
- }
-
- const npm = {
- config: {
- set: (key, value) => {
- t.equal(key, 'sso-type', 'should define sso-type')
- t.equal(value, 'saml', 'should set sso-type to saml')
- },
- },
- }
- const saml = t.mock('../../../lib/auth/saml.js', {
- '../../../lib/auth/sso.js': (npm, opts) => {
- t.equal(opts, samlOpts, 'should forward opts')
- },
- })
-
- saml(npm, samlOpts)
-
- t.end()
-})
diff --git a/test/lib/auth/sso.js b/test/lib/auth/sso.js
deleted file mode 100644
index 8d70077ad..000000000
--- a/test/lib/auth/sso.js
+++ /dev/null
@@ -1,236 +0,0 @@
-const t = require('tap')
-
-let log = ''
-
-const _flatOptions = {
- ssoType: 'oauth',
-}
-const token = '24528a24f240'
-const SSO_URL = 'https://registry.npmjs.org/{SSO_URL}'
-const profile = {}
-const npmFetch = {}
-const sso = t.mock('../../../lib/auth/sso.js', {
- 'proc-log': {
- info: (...msgs) => {
- log += msgs.join(' ') + '\n'
- },
- },
- 'npm-profile': profile,
- 'npm-registry-fetch': npmFetch,
- '../../../lib/utils/open-url.js': async (npm, url, msg) => {
- if (!url) {
- throw Object.assign(
- new Error('failed open url'),
- { code: 'ERROR' }
- )
- }
- },
-})
-
-const npm = {
- flatOptions: _flatOptions,
-}
-
-t.test('empty login', async (t) => {
- _flatOptions.ssoType = false
-
- await t.rejects(
- sso(npm, {}),
- { message: 'Missing option: sso-type' },
- 'should throw if no sso-type defined in flatOptions'
- )
-
- _flatOptions.ssoType = 'oauth'
- log = ''
-})
-
-t.test('simple login', async (t) => {
- t.plan(6)
-
- profile.loginCouch = (username, password, opts) => {
- t.equal(username, 'npm_oauth_auth_dummy_user', 'should use dummy user')
- t.equal(password, 'placeholder', 'should use dummy password')
- t.same(
- opts,
- {
- creds: {},
- registry: 'https://registry.npmjs.org/',
- scope: '',
- ssoType: 'oauth',
- },
- 'should use dummy password'
- )
-
- return { token, sso: SSO_URL }
- }
- npmFetch.json = () => Promise.resolve({ username: 'foo' })
-
- const {
- message,
- newCreds,
- } = await sso(npm, {
- creds: {},
- registry: 'https://registry.npmjs.org/',
- scope: '',
- })
-
- t.equal(
- message,
- 'Logged in as foo on https://registry.npmjs.org/.',
- 'should have correct message result'
- )
-
- t.equal(
- log,
- 'adduser Polling for validated SSO session\nadduser Authorized user foo\n',
- 'should have correct logged info msg'
- )
-
- t.same(
- newCreds,
- { token },
- 'should return expected resulting credentials'
- )
-
- log = ''
- delete profile.loginCouch
- delete npmFetch.json
-})
-
-t.test('polling retry', async (t) => {
- t.plan(3)
-
- profile.loginCouch = () => ({ token, sso: SSO_URL })
- npmFetch.json = () => {
- // assert expected values during retry
- npmFetch.json = (url, { registry, forceAuth: { token: expected } }) => {
- t.equal(
- url,
- '/-/whoami',
- 'should reach for expected endpoint'
- )
-
- t.equal(
- registry,
- 'https://registry.npmjs.org/',
- 'should use expected registry value'
- )
-
- t.equal(
- expected,
- token,
- 'should use expected token retrieved from initial loginCouch'
- )
-
- return Promise.resolve({ username: 'foo' })
- }
-
- // initial fetch returns retry code
- return Promise.reject(Object.assign(
- new Error('nothing yet'),
- { code: 'E401' }
- ))
- }
-
- await sso(npm, {
- creds: {},
- registry: 'https://registry.npmjs.org/',
- scope: '',
- })
-
- log = ''
- delete profile.loginCouch
- delete npmFetch.json
-})
-
-t.test('polling error', async (t) => {
- profile.loginCouch = () => ({ token, sso: SSO_URL })
- npmFetch.json = () => Promise.reject(Object.assign(
- new Error('unknown error'),
- { code: 'ERROR' }
- ))
-
- await t.rejects(
- sso(npm, {
- creds: {},
- registry: 'https://registry.npmjs.org/',
- scope: '',
- }),
- { message: 'unknown error', code: 'ERROR' },
- 'should throw unknown error'
- )
-
- log = ''
- delete profile.loginCouch
- delete npmFetch.json
-})
-
-t.test('no token retrieved from loginCouch', async (t) => {
- profile.loginCouch = () => ({})
-
- await t.rejects(
- sso(npm, {
- creds: {},
- registry: 'https://registry.npmjs.org/',
- scope: '',
- }),
- { message: 'no SSO token returned' },
- 'should throw no SSO token returned error'
- )
-
- log = ''
- delete profile.loginCouch
-})
-
-t.test('no sso url retrieved from loginCouch', async (t) => {
- profile.loginCouch = () => Promise.resolve({ token })
-
- await t.rejects(
- sso(npm, {
- creds: {},
- registry: 'https://registry.npmjs.org/',
- scope: '',
- }),
- { message: 'no SSO URL returned by services' },
- 'should throw no SSO url returned error'
- )
-
- log = ''
- delete profile.loginCouch
-})
-
-t.test('scoped login', async (t) => {
- profile.loginCouch = () => ({ token, sso: SSO_URL })
- npmFetch.json = () => Promise.resolve({ username: 'foo' })
-
- const {
- message,
- newCreds,
- } = await sso(npm, {
- creds: {},
- registry: 'https://diff-registry.npmjs.org/',
- scope: 'myscope',
- })
-
- t.equal(
- message,
- 'Logged in as foo to scope myscope on https://diff-registry.npmjs.org/.',
- 'should have correct message result'
- )
-
- t.equal(
- log,
- 'adduser Polling for validated SSO session\nadduser Authorized user foo\n',
- 'should have correct logged info msg'
- )
-
- t.same(
- newCreds,
- { token },
- 'should return expected resulting credentials'
- )
-
- log = ''
- delete profile.loginCouch
- delete npmFetch.json
-})
diff --git a/test/lib/commands/adduser.js b/test/lib/commands/adduser.js
index 94e58a6d3..4ff65e57f 100644
--- a/test/lib/commands/adduser.js
+++ b/test/lib/commands/adduser.js
@@ -1,7 +1,7 @@
const t = require('tap')
-const path = require('path')
const fs = require('fs')
-const os = require('os')
+const path = require('path')
+const ini = require('ini')
const { load: loadMockNpm } = require('../../fixtures/mock-npm.js')
const mockGlobals = require('../../fixtures/mock-globals.js')
@@ -14,170 +14,169 @@ t.test('usage', async t => {
t.match(adduser.usage, 'adduser', 'usage has command name in it')
})
-t.test('simple login', 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, home } = await loadMockNpm(t, {
- homeDir: {
- // These all get cleaned up by config.setCredentialsByURI
- '.npmrc': [
- '_token=user',
- '_password=user',
- 'username=user',
- '_auth=user',
- '_authtoken=user',
- '-authtoken=user',
- '_authToken=user',
- '//registry.npmjs.org/:_authToken=user',
- '//registry.npmjs.org/:always-auth=user',
- '//registry.npmjs.org/:email=test-email-old@npmjs.org',
- ].join('\n'),
- },
- })
- const registry = new MockRegistry({
- tap: t,
- registry: npm.config.get('registry'),
+t.test('legacy', async t => {
+ t.test('simple adduser', 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, home } = await loadMockNpm(t, {
+ homeDir: {
+ // These all get cleaned up by config.setCredentialsByURI
+ '.npmrc': [
+ '_token=user',
+ '_password=user',
+ 'username=user',
+ '_auth=user',
+ '_authtoken=user',
+ '-authtoken=user',
+ '_authToken=user',
+ '//registry.npmjs.org/:_authToken=user',
+ '//registry.npmjs.org/:always-auth=user',
+ '//registry.npmjs.org/:email=test-email-old@npmjs.org',
+ ].join('\n'),
+ },
+ })
+ const registry = new MockRegistry({
+ tap: t,
+ registry: npm.config.get('registry'),
+ })
+ 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('email'), 'test-email-old@npmjs.org')
+ t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token')
+ const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8'))
+ t.same(rc, {
+ '//registry.npmjs.org/:_authToken': 'npm_test-token',
+ email: 'test-email-old@npmjs.org',
+ }, 'should only have token and un-nerfed old email')
})
- registry.couchlogin({
- username: 'test-user',
- password: 'test-password',
- email: 'test-email@npmjs.org',
- token: 'npm_test-token',
- })
- await npm.exec('adduser', [])
- t.same(npm.config.get('email'), 'test-email-old@npmjs.org')
- t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token')
- const rc = fs.readFileSync(path.join(home, '.npmrc'), 'utf8')
- t.same(
- rc.trim().split(os.EOL), [
- '//registry.npmjs.org/:_authToken=npm_test-token',
- 'email=test-email-old@npmjs.org',
- ], 'should only have token and un-nerfed old email'
- )
-})
-t.test('bad auth type', async t => {
- const { npm } = await loadMockNpm(t, {
- config: {
- 'auth-type': 'foo',
- },
+ t.test('scoped adduser', 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, home } = await loadMockNpm(t, {
+ config: {
+ scope: '@myscope',
+ },
+ })
+ const registry = new MockRegistry({
+ tap: t,
+ registry: npm.config.get('registry'),
+ })
+ 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.same(npm.config.get('@myscope:registry'), 'https://registry.npmjs.org/')
+ const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8'))
+ t.same(rc, {
+ '//registry.npmjs.org/:_authToken': 'npm_test-token',
+ '@myscope:registry': 'https://registry.npmjs.org/',
+ }, 'should only have token and scope:registry')
})
- await t.rejects(npm.exec('adduser', []), {
- message: 'no such auth module',
- })
-})
-t.test('auth-type sso warning', async t => {
- const { logs } = await loadMockNpm(t, {
- config: {
- 'auth-type': 'sso',
- },
+ t.test('scoped adduser with valid scoped registry config', 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, home } = await loadMockNpm(t, {
+ homeDir: {
+ '.npmrc': '@myscope:registry=https://diff-registry.npmjs.org',
+ },
+ config: {
+ scope: '@myscope',
+ },
+ })
+ const registry = new MockRegistry({
+ tap: t,
+ registry: 'https://diff-registry.npmjs.org',
+ })
+ 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('//diff-registry.npmjs.org/:_authToken'), 'npm_test-token')
+ t.same(npm.config.get('@myscope:registry'), 'https://diff-registry.npmjs.org')
+ const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8'))
+ t.same(rc, {
+ '@myscope:registry': 'https://diff-registry.npmjs.org',
+ '//diff-registry.npmjs.org/:_authToken': 'npm_test-token',
+ }, 'should only have token and scope:registry')
})
- t.matchSnapshot({ warn: logs.warn }, 'warning')
-})
-t.test('scoped login', 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, home } = await loadMockNpm(t, {
- config: {
- scope: '@myscope',
- },
- })
- const registry = new MockRegistry({
- tap: t,
- registry: npm.config.get('registry'),
+ t.test('save config failure', 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, {
+ homeDir: {
+ '.npmrc': {},
+ },
+ })
+ const registry = new MockRegistry({
+ tap: t,
+ registry: npm.config.get('registry'),
+ })
+ registry.couchadduser({
+ username: 'test-user',
+ password: 'test-password',
+ email: 'test-email@npmjs.org',
+ token: 'npm_test-token',
+ })
+ await t.rejects(npm.exec('adduser', []))
})
- registry.couchlogin({
- 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.same(npm.config.get('@myscope:registry'), 'https://registry.npmjs.org/')
- const rc = fs.readFileSync(path.join(home, '.npmrc'), 'utf8')
- t.same(
- rc.trim().split(os.EOL), [
- '//registry.npmjs.org/:_authToken=npm_test-token',
- '@myscope:registry=https://registry.npmjs.org/',
- ], 'should only have token and scope:registry')
-})
-
-t.test('scoped login with valid scoped registry config', 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, home } = await loadMockNpm(t, {
- homeDir: {
- '.npmrc': '@myscope:registry=https://diff-registry.npmjs.org',
- },
- config: {
- scope: '@myscope',
- },
- })
- const registry = new MockRegistry({
- tap: t,
- registry: 'https://diff-registry.npmjs.org',
- })
- registry.couchlogin({
- username: 'test-user',
- password: 'test-password',
- email: 'test-email@npmjs.org',
- token: 'npm_test-token',
- })
- await npm.exec('adduser', [])
- t.same(npm.config.get('//diff-registry.npmjs.org/:_authToken'), 'npm_test-token')
- t.same(npm.config.get('@myscope:registry'), 'https://diff-registry.npmjs.org')
- const rc = fs.readFileSync(path.join(home, '.npmrc'), 'utf8')
- t.same(rc.trim().split(os.EOL),
- [
- '@myscope:registry=https://diff-registry.npmjs.org',
- '//diff-registry.npmjs.org/:_authToken=npm_test-token',
- ], 'should only have token and scope:registry')
+ t.end()
})
-t.test('save config failure', 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, {
- homeDir: {
- '.npmrc': {},
- },
- })
- const registry = new MockRegistry({
- tap: t,
- registry: npm.config.get('registry'),
- })
- registry.couchlogin({
- username: 'test-user',
- password: 'test-password',
- email: 'test-email@npmjs.org',
- token: 'npm_test-token',
+t.test('web', t => {
+ t.test('basic adduser', async t => {
+ const { npm, home } = await loadMockNpm(t, {
+ config: { 'auth-type': 'web' },
+ })
+ const registry = new MockRegistry({
+ tap: t,
+ registry: npm.config.get('registry'),
+ })
+ registry.webadduser({ token: 'npm_test-token' })
+ await npm.exec('adduser', [])
+ t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token')
+ const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8'))
+ t.same(rc, {
+ '//registry.npmjs.org/:_authToken': 'npm_test-token',
+ })
})
- await t.rejects(npm.exec('adduser', []))
+ t.end()
})
diff --git a/test/lib/commands/login.js b/test/lib/commands/login.js
new file mode 100644
index 000000000..8d2742131
--- /dev/null
+++ b/test/lib/commands/login.js
@@ -0,0 +1,151 @@
+const t = require('tap')
+const fs = require('fs')
+const path = require('path')
+const ini = require('ini')
+
+const { load: loadMockNpm } = require('../../fixtures/mock-npm.js')
+const mockGlobals = require('../../fixtures/mock-globals.js')
+const MockRegistry = require('../../fixtures/mock-registry.js')
+const stream = require('stream')
+
+t.test('usage', async t => {
+ const { npm } = await loadMockNpm(t)
+ const login = await npm.cmd('login')
+ t.match(login.usage, 'login', 'usage has command name in it')
+})
+
+t.test('legacy', t => {
+ t.test('basic login', 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, home } = await loadMockNpm(t, {
+ config: { 'auth-type': 'legacy' },
+ homeDir: {
+ // These all get cleaned up by config.setCredentialsByURI
+ '.npmrc': [
+ '_token=user',
+ '_password=user',
+ 'username=user',
+ '_auth=user',
+ '_authtoken=user',
+ '-authtoken=user',
+ '_authToken=user',
+ '//registry.npmjs.org/:_authToken=user',
+ '//registry.npmjs.org/:always-auth=user',
+ '//registry.npmjs.org/:email=test-email-old@npmjs.org',
+ ].join('\n'),
+ },
+ })
+ const registry = new MockRegistry({
+ tap: t,
+ registry: npm.config.get('registry'),
+ })
+ 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')
+ const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8'))
+ t.same(rc, {
+ '//registry.npmjs.org/:_authToken': 'npm_test-token',
+ email: 'test-email-old@npmjs.org',
+ }, 'should only have token and un-nerfed old email')
+ })
+
+ t.test('scoped login default registry', 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, home } = await loadMockNpm(t, {
+ config: {
+ 'auth-type': 'legacy',
+ scope: '@npmcli',
+ },
+ })
+ const registry = new MockRegistry({
+ tap: t,
+ registry: npm.config.get('registry'),
+ })
+ 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.same(npm.config.get('@npmcli:registry'), 'https://registry.npmjs.org/')
+ const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8'))
+ t.same(rc, {
+ '//registry.npmjs.org/:_authToken': 'npm_test-token',
+ '@npmcli:registry': 'https://registry.npmjs.org/',
+ }, 'should only have token and scope:registry')
+ })
+
+ t.test('scoped login scoped registry', 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, home } = await loadMockNpm(t, {
+ config: {
+ 'auth-type': 'legacy',
+ scope: '@npmcli',
+ },
+ homeDir: {
+ '.npmrc': '@npmcli:registry=https://diff-registry.npmjs.org',
+ },
+ })
+ const registry = new MockRegistry({
+ tap: t,
+ registry: 'https://diff-registry.npmjs.org',
+ })
+ registry.couchlogin({
+ username: 'test-user',
+ password: 'test-password',
+ token: 'npm_test-token',
+ })
+ await npm.exec('login', [])
+ t.same(npm.config.get('//diff-registry.npmjs.org/:_authToken'), 'npm_test-token')
+ t.same(npm.config.get('@npmcli:registry'), 'https://diff-registry.npmjs.org')
+ const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8'))
+ t.same(rc, {
+ '@npmcli:registry': 'https://diff-registry.npmjs.org',
+ '//diff-registry.npmjs.org/:_authToken': 'npm_test-token',
+ }, 'should only have token and scope:registry')
+ })
+ t.end()
+})
+
+t.test('web', t => {
+ t.test('basic login', async t => {
+ const { npm, home } = await loadMockNpm(t, {
+ config: { 'auth-type': 'web' },
+ })
+ const registry = new MockRegistry({
+ tap: t,
+ registry: npm.config.get('registry'),
+ })
+ registry.weblogin({ token: 'npm_test-token' })
+ await npm.exec('login', [])
+ t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token')
+ const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8'))
+ t.same(rc, {
+ '//registry.npmjs.org/:_authToken': 'npm_test-token',
+ })
+ })
+ t.end()
+})