const path = require('path')
const libaccess = require('libnpmaccess')
const readPackageJson = require('read-package-json-fast')
const otplease = require('../utils/otplease.js')
const getIdentity = require('../utils/get-identity.js')
const log = require('../utils/log-shim.js')
const BaseCommand = require('../base-command.js')
const subcommands = [
'public',
'restricted',
'grant',
'revoke',
'ls-packages',
'ls-collaborators',
'edit',
'2fa-required',
'2fa-not-required',
]
const deprecated = [
'2fa-not-required',
'2fa-required',
'ls-collaborators',
'ls-packages',
'public',
'restricted',
]
class Access extends BaseCommand {
static description = 'Set access level on published packages'
static name = 'access'
static params = [
'registry',
'otp',
]
static ignoreImplicitWorkspace = true
static usage = [
'public [<package>]',
'restricted [<package>]',
'grant <read-only|read-write> <scope:team> [<package>]',
'revoke <scope:team> [<package>]',
'2fa-required [<package>]',
'2fa-not-required [<package>]',
'ls-packages [<user>|<scope>|<scope:team>]',
'ls-collaborators [<package> [<user>]]',
'edit [<package>]',
]
async completion (opts) {
const argv = opts.conf.argv.remain
if (argv.length === 2) {
return subcommands
}
switch (argv[2]) {
case 'grant':
if (argv.length === 3) {
return ['read-only', 'read-write']
} else {
return []
}
case 'public':
case 'restricted':
case 'ls-packages':
case 'ls-collaborators':
case 'edit':
case '2fa-required':
case '2fa-not-required':
case 'revoke':
return []
default:
throw new Error(argv[2] + ' not recognized')
}
}
async exec ([cmd, ...args]) {
if (!cmd) {
throw this.usageError('Subcommand is required.')
}
if (!subcommands.includes(cmd) || !this[cmd]) {
throw this.usageError(`${cmd} is not a recognized subcommand.`)
}
if (deprecated.includes(cmd)) {
log.warn('access', `${cmd} subcommand will be removed in the next version of npm`)
}
return this[cmd](args, {
...this.npm.flatOptions,
})
}
public ([pkg], opts) {
return this.modifyPackage(pkg, opts, libaccess.public)
}
restricted ([pkg], opts) {
return this.modifyPackage(pkg, opts, libaccess.restricted)
}
async grant ([perms, scopeteam, pkg], opts) {
if (!perms || (perms !== 'read-only' && perms !== 'read-write')) {
throw this.usageError('First argument must be either `read-only` or `read-write`.')
}
if (!scopeteam) {
throw this.usageError('`<scope:team>` argument is required.')
}
const [, scope, team] = scopeteam.match(/^@?([^:]+):(.*)$/) || []
if (!scope && !team) {
throw this.usageError(
'Second argument used incorrect format.\n' +
'Example: @example:developers'
)
}
return this.modifyPackage(pkg, opts, (pkgName, opts) =>
libaccess.grant(pkgName, scopeteam, perms, opts), false)
}
async revoke ([scopeteam, pkg], opts) {
if (!scopeteam) {
throw this.usageError('`<scope:team>` argument is required.')
}
const [, scope, team] = scopeteam.match(/^@?([^:]+):(.*)$/) || []
if (!scope || !team) {
throw this.usageError(
'First argument used incorrect format.\n' +
'Example: @example:developers'
)
}
return this.modifyPackage(pkg, opts, (pkgName, opts) =>
libaccess.revoke(pkgName, scopeteam, opts))
}
get ['2fa-required'] () {
return this.tfaRequired
}
tfaRequired ([pkg], opts) {
return this.modifyPackage(pkg, opts, libaccess.tfaRequired, false)
}
get ['2fa-not-required'] () {
return this.tfaNotRequired
}
tfaNotRequired ([pkg], opts) {
return this.modifyPackage(pkg, opts, libaccess.tfaNotRequired, false)
}
get ['ls-packages'] () {
return this.lsPackages
}
async lsPackages ([owner], opts) {
if (!owner) {
owner = await getIdentity(this.npm, opts)
}
const pkgs = await libaccess.lsPackages(owner, opts)
// TODO - print these out nicely (breaking change)
this.npm.output(JSON.stringify(pkgs, null, 2))
}
get ['ls-collaborators'] () {
return this.lsCollaborators
}
async lsCollaborators ([pkg, usr], opts) {
const pkgName = await this.getPackage(pkg, false)
const collabs = await libaccess.lsCollaborators(pkgName, usr, opts)
// TODO - print these out nicely (breaking change)
this.npm.output(JSON.stringify(collabs, null, 2))
}
async edit () {
throw new Error('edit subcommand is not implemented')
}
modifyPackage (pkg, opts, fn, requireScope = true) {
return this.getPackage(pkg, requireScope)
.then(pkgName => otplease(this.npm, opts, opts => fn(pkgName, opts)))
}
async getPackage (name, requireScope) {
if (name && name.trim()) {
return name.trim()
} else {
try {
const pkg = await readPackageJson(path.resolve(this.npm.prefix, 'package.json'))
name = pkg.name
} catch (err) {
if (err.code === 'ENOENT') {
throw new Error(
'no package name passed to command and no package.json found'
)
} else {
throw err
}
}
if (requireScope && !name.match(/^@[^/]+\/.*$/)) {
throw this.usageError('This command is only available for scoped packages.')
} else {
return name
}
}
}
}
module.exports = Access
| Name | Type | Size | Permission | Actions |
|---|---|---|---|---|
| access.js | File | 5.45 KB | 0644 |
|
| adduser.js | File | 2.2 KB | 0644 |
|
| audit.js | File | 11.95 KB | 0644 |
|
| bin.js | File | 729 B | 0644 |
|
| birthday.js | File | 508 B | 0644 |
|
| bugs.js | File | 815 B | 0644 |
|
| cache.js | File | 7.08 KB | 0644 |
|
| ci.js | File | 3.63 KB | 0644 |
|
| completion.js | File | 8.91 KB | 0644 |
|
| config.js | File | 8.11 KB | 0644 |
|
| dedupe.js | File | 1.37 KB | 0644 |
|
| deprecate.js | File | 2.06 KB | 0644 |
|
| diff.js | File | 8.1 KB | 0644 |
|
| dist-tag.js | File | 5.47 KB | 0644 |
|
| docs.js | File | 447 B | 0644 |
|
| doctor.js | File | 9.22 KB | 0644 |
|
| edit.js | File | 2 KB | 0644 |
|
| exec.js | File | 2.44 KB | 0644 |
|
| explain.js | File | 3.55 KB | 0644 |
|
| explore.js | File | 2.33 KB | 0644 |
|
| find-dupes.js | File | 602 B | 0644 |
|
| fund.js | File | 6.37 KB | 0644 |
|
| get.js | File | 524 B | 0644 |
|
| help-search.js | File | 5.62 KB | 0644 |
|
| help.js | File | 4.53 KB | 0644 |
|
| hook.js | File | 3.93 KB | 0644 |
|
| init.js | File | 6.81 KB | 0644 |
|
| install-ci-test.js | File | 377 B | 0644 |
|
| install-test.js | File | 374 B | 0644 |
|
| install.js | File | 5.11 KB | 0644 |
|
| link.js | File | 5.02 KB | 0644 |
|
| ll.js | File | 234 B | 0644 |
|
| logout.js | File | 1.34 KB | 0644 |
|
| ls.js | File | 16.94 KB | 0644 |
|
| org.js | File | 4.2 KB | 0644 |
|
| outdated.js | File | 8.84 KB | 0644 |
|
| owner.js | File | 5.88 KB | 0644 |
|
| pack.js | File | 2.36 KB | 0644 |
|
| ping.js | File | 874 B | 0644 |
|
| pkg.js | File | 3.47 KB | 0644 |
|
| prefix.js | File | 343 B | 0644 |
|
| profile.js | File | 11.25 KB | 0644 |
|
| prune.js | File | 779 B | 0644 |
|
| publish.js | File | 6.33 KB | 0644 |
|
| query.js | File | 2.81 KB | 0644 |
|
| rebuild.js | File | 2.16 KB | 0644 |
|
| repo.js | File | 1.24 KB | 0644 |
|
| restart.js | File | 351 B | 0644 |
|
| root.js | File | 298 B | 0644 |
|
| run-script.js | File | 6.9 KB | 0644 |
|
| search.js | File | 2.72 KB | 0644 |
|
| set-script.js | File | 2.63 KB | 0644 |
|
| set.js | File | 572 B | 0644 |
|
| shrinkwrap.js | File | 2.64 KB | 0644 |
|
| star.js | File | 1.87 KB | 0644 |
|
| stars.js | File | 1.03 KB | 0644 |
|
| start.js | File | 341 B | 0644 |
|
| stop.js | File | 336 B | 0644 |
|
| team.js | File | 4.44 KB | 0644 |
|
| test.js | File | 336 B | 0644 |
|
| token.js | File | 6.79 KB | 0644 |
|
| uninstall.js | File | 1.52 KB | 0644 |
|
| unpublish.js | File | 4.51 KB | 0644 |
|
| unstar.js | File | 182 B | 0644 |
|
| update.js | File | 1.7 KB | 0644 |
|
| version.js | File | 3.6 KB | 0644 |
|
| view.js | File | 14.38 KB | 0644 |
|
| whoami.js | File | 514 B | 0644 |
|