summaryrefslogtreecommitdiff
path: root/deps/npm/lib/token.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/lib/token.js')
-rw-r--r--deps/npm/lib/token.js211
1 files changed, 211 insertions, 0 deletions
diff --git a/deps/npm/lib/token.js b/deps/npm/lib/token.js
new file mode 100644
index 0000000000..a182b633d2
--- /dev/null
+++ b/deps/npm/lib/token.js
@@ -0,0 +1,211 @@
+'use strict'
+const profile = require('npm-profile')
+const npm = require('./npm.js')
+const output = require('./utils/output.js')
+const Table = require('cli-table2')
+const Bluebird = require('bluebird')
+const isCidrV4 = require('is-cidr').isCidrV4
+const isCidrV6 = require('is-cidr').isCidrV6
+const readUserInfo = require('./utils/read-user-info.js')
+const ansistyles = require('ansistyles')
+const log = require('npmlog')
+const pulseTillDone = require('./utils/pulse-till-done.js')
+
+module.exports = token
+
+token.usage =
+ 'npm token list\n' +
+ 'npm token delete <tokenKey>\n' +
+ 'npm token create [--read-only] [--cidr=list]\n'
+
+token.subcommands = ['list', 'delete', 'create']
+
+token.completion = function (opts, cb) {
+ var argv = opts.conf.argv.remain
+
+ switch (argv[2]) {
+ case 'list':
+ case 'delete':
+ case 'create':
+ return cb(null, [])
+ default:
+ return cb(new Error(argv[2] + ' not recognized'))
+ }
+}
+
+function withCb (prom, cb) {
+ prom.then((value) => cb(null, value), cb)
+}
+
+function token (args, cb) {
+ log.gauge.show('token')
+ if (args.length === 0) return withCb(list([]), cb)
+ switch (args[0]) {
+ case 'list':
+ case 'ls':
+ withCb(list(), cb)
+ break
+ case 'delete':
+ case 'rel':
+ case 'remove':
+ case 'rm':
+ withCb(rm(args.slice(1)), cb)
+ break
+ case 'create':
+ withCb(create(args.slice(1)), cb)
+ break
+ default:
+ cb(new Error('Unknown profile command: ' + args[0]))
+ }
+}
+
+function generateTokenIds (tokens, minLength) {
+ const byId = {}
+ tokens.forEach((token) => {
+ token.id = token.key
+ for (let ii = minLength; ii < token.key.length; ++ii) {
+ if (!tokens.some((ot) => ot !== token && ot.key.slice(0, ii) === token.key.slice(0, ii))) {
+ token.id = token.key.slice(0, ii)
+ break
+ }
+ }
+ byId[token.id] = token
+ })
+ return byId
+}
+
+function config () {
+ const conf = {
+ json: npm.config.get('json'),
+ parseable: npm.config.get('parseable'),
+ registry: npm.config.get('registry'),
+ otp: npm.config.get('otp')
+ }
+ conf.auth = npm.config.getCredentialsByURI(conf.registry)
+ if (conf.otp) conf.auth.otp = conf.otp
+ return conf
+}
+
+function list (args) {
+ const conf = config()
+ log.info('token', 'getting list')
+ return pulseTillDone.withPromise(profile.listTokens(conf)).then((tokens) => {
+ if (conf.json) {
+ output(JSON.stringify(tokens, null, 2))
+ return
+ } else if (conf.parseable) {
+ output(['key', 'token', 'created', 'readonly', 'CIDR whitelist'].join('\t'))
+ tokens.forEach((token) => {
+ output([
+ token.key,
+ token.token,
+ token.created,
+ token.readonly ? 'true' : 'false',
+ token.cidr_whitelist ? token.cidr_whitelist.join(',') : ''
+ ].join('\t'))
+ })
+ return
+ }
+ generateTokenIds(tokens, 6)
+ const idWidth = tokens.reduce((acc, token) => Math.max(acc, token.id.length), 0)
+ const table = new Table({
+ head: ['id', 'token', 'created', 'readonly', 'CIDR whitelist'],
+ colWidths: [Math.max(idWidth, 2) + 2, 9, 12, 10]
+ })
+ tokens.forEach((token) => {
+ table.push([
+ token.id,
+ token.token + '…',
+ String(token.created).slice(0, 10),
+ token.readonly ? 'yes' : 'no',
+ token.cidr_whitelist ? token.cidr_whitelist.join(', ') : ''
+ ])
+ })
+ output(table.toString())
+ })
+}
+
+function rm (args) {
+ if (args.length === 0) {
+ throw new Error('npm token delete <tokenKey>')
+ }
+ const conf = config()
+ const toRemove = []
+ const progress = log.newItem('removing tokens', toRemove.length)
+ progress.info('token', 'getting existing list')
+ return pulseTillDone.withPromise(profile.listTokens(conf).then((tokens) => {
+ args.forEach((id) => {
+ const matches = tokens.filter((token) => token.key.indexOf(id) === 0)
+ if (matches.length === 1) {
+ toRemove.push(matches[0].key)
+ } else if (matches.length > 1) {
+ throw new Error(`Token ID "${id}" was ambiguous, a new token may have been created since you last ran \`npm-profile token list\`.`)
+ } else {
+ const tokenMatches = tokens.filter((token) => id.indexOf(token.token) === 0)
+ if (tokenMatches === 0) {
+ throw new Error(`Unknown token id or value "${id}".`)
+ }
+ toRemove.push(id)
+ }
+ })
+ return Bluebird.map(toRemove, (key) => {
+ progress.info('token', 'removing', key)
+ profile.removeToken(key, conf).then(() => profile.completeWork(1))
+ })
+ })).then(() => {
+ if (conf.json) {
+ output(JSON.stringify(toRemove))
+ } else if (conf.parseable) {
+ output(toRemove.join('\t'))
+ } else {
+ output('Removed ' + toRemove.length + ' token' + (toRemove.length !== 1 ? 's' : ''))
+ }
+ })
+}
+
+function create (args) {
+ const conf = config()
+ const cidr = npm.config.get('cidr')
+ const readonly = npm.config.get('read-only')
+
+ const validCIDR = validateCIDRList(cidr)
+ return readUserInfo.password().then((password) => {
+ log.info('token', 'creating')
+ return profile.createToken(password, readonly, validCIDR, conf).catch((ex) => {
+ if (ex.code !== 'EOTP') throw ex
+ log.info('token', 'failed because it requires OTP')
+ return readUserInfo.otp('Authenticator provided OTP:').then((otp) => {
+ conf.auth.otp = otp
+ log.info('token', 'creating with OTP')
+ return pulseTillDone.withPromise(profile.createToken(password, readonly, validCIDR, conf))
+ })
+ })
+ }).then((result) => {
+ delete result.key
+ delete result.updated
+ if (conf.json) {
+ output(JSON.stringify(result))
+ } else if (conf.parseable) {
+ Object.keys(result).forEach((k) => output(k + '\t' + result[k]))
+ } else {
+ const table = new Table()
+ Object.keys(result).forEach((k) => table.push({[ansistyles.bright(k)]: String(result[k])}))
+ output(table.toString())
+ }
+ })
+}
+
+function validateCIDR (cidr) {
+ if (isCidrV6(cidr)) {
+ throw new Error('CIDR whitelist can only contain IPv4 addresses, ' + cidr + ' is IPv6')
+ }
+ if (!isCidrV4(cidr)) {
+ throw new Error('CIDR whitelist contains invalid CIDR entry: ' + cidr)
+ }
+}
+
+function validateCIDRList (cidrs) {
+ const list = Array.isArray(cidrs) ? cidrs : cidrs ? cidrs.split(/,\s*/) : []
+ list.forEach(validateCIDR)
+ return list
+}