|
1 | | -var log = require('npmlog') |
2 | | -var npm = require('../npm.js') |
3 | | -var output = require('../utils/output') |
4 | | -var openUrl = require('../utils/open-url') |
| 1 | +'use strict' |
| 2 | + |
| 3 | +const BB = require('bluebird') |
| 4 | + |
| 5 | +const figgyPudding = require('figgy-pudding') |
| 6 | +const log = require('npmlog') |
| 7 | +const npmConfig = require('../config/figgy-config.js') |
| 8 | +const npmFetch = require('npm-registry-fetch') |
| 9 | +const output = require('../utils/output.js') |
| 10 | +const openUrl = BB.promisify(require('../utils/open-url.js')) |
| 11 | +const otplease = require('../utils/otplease.js') |
| 12 | +const profile = require('libnpm/profile') |
| 13 | + |
| 14 | +const SsoOpts = figgyPudding({ |
| 15 | + ssoType: 'sso-type', |
| 16 | + 'sso-type': {}, |
| 17 | + ssoPollFrequency: 'sso-poll-frequency', |
| 18 | + 'sso-poll-frequency': {} |
| 19 | +}) |
5 | 20 |
|
6 | 21 | module.exports.login = function login (creds, registry, scope, cb) { |
7 | | - var ssoType = npm.config.get('sso-type') |
| 22 | + const opts = SsoOpts(npmConfig()).concat({creds, registry, scope}) |
| 23 | + const ssoType = opts.ssoType |
8 | 24 | if (!ssoType) { return cb(new Error('Missing option: sso-type')) } |
9 | 25 |
|
10 | | - var params = { |
11 | | - // We're reusing the legacy login endpoint, so we need some dummy |
12 | | - // stuff here to pass validation. They're never used. |
13 | | - auth: { |
14 | | - username: 'npm_' + ssoType + '_auth_dummy_user', |
15 | | - password: 'placeholder', |
16 | | - |
17 | | - authType: ssoType |
18 | | - } |
| 26 | + // We're reusing the legacy login endpoint, so we need some dummy |
| 27 | + // stuff here to pass validation. They're never used. |
| 28 | + const auth = { |
| 29 | + username: 'npm_' + ssoType + '_auth_dummy_user', |
| 30 | + password: 'placeholder', |
| 31 | + |
| 32 | + authType: ssoType |
19 | 33 | } |
20 | | - npm.registry.adduser(registry, params, function (er, doc) { |
21 | | - if (er) return cb(er) |
22 | | - if (!doc || !doc.token) return cb(new Error('no SSO token returned')) |
23 | | - if (!doc.sso) return cb(new Error('no SSO URL returned by services')) |
24 | | - |
25 | | - openUrl(doc.sso, 'to complete your login please visit', function () { |
26 | | - pollForSession(registry, doc.token, function (err, username) { |
27 | | - if (err) return cb(err) |
28 | 34 |
|
29 | | - log.info('adduser', 'Authorized user %s', username) |
30 | | - var scopeMessage = scope ? ' to scope ' + scope : '' |
31 | | - output('Logged in as %s%s on %s.', username, scopeMessage, registry) |
32 | | - |
33 | | - cb(null, { token: doc.token }) |
34 | | - }) |
| 35 | + otplease(opts, |
| 36 | + opts => profile.loginCouch(auth.username, auth.password, opts) |
| 37 | + ).then(({token, sso}) => { |
| 38 | + if (!token) { throw new Error('no SSO token returned') } |
| 39 | + if (!sso) { throw new Error('no SSO URL returned by services') } |
| 40 | + return openUrl(sso, 'to complete your login please visit').then(() => { |
| 41 | + return pollForSession(registry, token, opts) |
| 42 | + }).then(username => { |
| 43 | + log.info('adduser', 'Authorized user %s', username) |
| 44 | + var scopeMessage = scope ? ' to scope ' + scope : '' |
| 45 | + output('Logged in as %s%s on %s.', username, scopeMessage, registry) |
| 46 | + return {token} |
35 | 47 | }) |
36 | | - }) |
| 48 | + }).nodeify(cb) |
37 | 49 | } |
38 | 50 |
|
39 | | -function pollForSession (registry, token, cb) { |
| 51 | +function pollForSession (registry, token, opts) { |
40 | 52 | log.info('adduser', 'Polling for validated SSO session') |
41 | | - npm.registry.whoami(registry, { |
42 | | - auth: { |
43 | | - token: token |
44 | | - } |
45 | | - }, function (er, username) { |
46 | | - if (er && er.statusCode !== 401) { |
47 | | - cb(er) |
48 | | - } else if (!username) { |
49 | | - setTimeout(function () { |
50 | | - pollForSession(registry, token, cb) |
51 | | - }, npm.config.get('sso-poll-frequency')) |
52 | | - } else { |
53 | | - cb(null, username) |
| 53 | + return npmFetch.json( |
| 54 | + '/-/whoami', opts.concat({registry, forceAuth: {token}}) |
| 55 | + ).then( |
| 56 | + ({username}) => username, |
| 57 | + err => { |
| 58 | + if (err.code === 'E401') { |
| 59 | + return sleep(opts['sso-poll-frequency']).then(() => { |
| 60 | + return pollForSession(registry, token, opts) |
| 61 | + }) |
| 62 | + } else { |
| 63 | + throw err |
| 64 | + } |
54 | 65 | } |
| 66 | + ) |
| 67 | +} |
| 68 | + |
| 69 | +function sleep (time) { |
| 70 | + return new BB((resolve) => { |
| 71 | + setTimeout(resolve, time) |
55 | 72 | }) |
56 | 73 | } |
0 commit comments