npm-profile
Advanced tools
Comparing version 3.0.2 to 4.0.0
@@ -0,1 +1,7 @@ | ||
# v4.0.0 (2018-08-28) | ||
## BREAKING CHANGES: | ||
- Networking and auth-related options now use the latest [`npm-registry-fetch` config format](https://www.npmjs.com/package/npm-registry-fetch#fetch-opts). | ||
# v3.0.2 (2018-06-07) | ||
@@ -2,0 +8,0 @@ |
389
index.js
'use strict' | ||
const fetch = require('make-fetch-happen').defaults({retry: false}) | ||
const fetch = require('npm-registry-fetch') | ||
const {HttpErrorBase} = require('npm-registry-fetch/errors.js') | ||
const os = require('os') | ||
const pudding = require('figgy-pudding') | ||
const validate = require('aproba') | ||
const url = require('url') | ||
const os = require('os') | ||
@@ -19,10 +21,17 @@ exports.adduserCouch = adduserCouch | ||
const ProfileConfig = pudding({ | ||
creds: {}, | ||
hostname: {}, | ||
otp: {} | ||
}) | ||
// try loginWeb, catch the "not supported" message and fall back to couch | ||
function login (opener, prompter, conf) { | ||
function login (opener, prompter, opts) { | ||
validate('FFO', arguments) | ||
return loginWeb(opener, conf).catch(er => { | ||
opts = ProfileConfig(opts) | ||
return loginWeb(opener, opts).catch(er => { | ||
if (er instanceof WebLoginNotSupported) { | ||
process.emit('log', 'verbose', 'web login not supported, trying couch') | ||
return prompter(conf.creds) | ||
.then(data => loginCouch(data.username, data.password, conf)) | ||
return prompter(opts.creds) | ||
.then(data => loginCouch(data.username, data.password, opts)) | ||
} else { | ||
@@ -34,9 +43,10 @@ throw er | ||
function adduser (opener, prompter, conf) { | ||
function adduser (opener, prompter, opts) { | ||
validate('FFO', arguments) | ||
return adduserWeb(opener, conf).catch(er => { | ||
opts = ProfileConfig(opts) | ||
return adduserWeb(opener, opts).catch(er => { | ||
if (er instanceof WebLoginNotSupported) { | ||
process.emit('log', 'verbose', 'web adduser not supported, trying couch') | ||
return prompter(conf.creds) | ||
.then(data => adduserCouch(data.username, data.email, data.password, conf)) | ||
return prompter(opts.creds) | ||
.then(data => adduserCouch(data.username, data.email, data.password, opts)) | ||
} else { | ||
@@ -48,68 +58,44 @@ throw er | ||
function adduserWeb (opener, conf) { | ||
function adduserWeb (opener, opts) { | ||
validate('FO', arguments) | ||
const body = { create: true } | ||
process.emit('log', 'verbose', 'web adduser', 'before first POST') | ||
return webAuth(opener, conf, body) | ||
return webAuth(opener, opts, body) | ||
} | ||
function loginWeb (opener, conf) { | ||
function loginWeb (opener, opts) { | ||
validate('FO', arguments) | ||
process.emit('log', 'verbose', 'web login', 'before first POST') | ||
return webAuth(opener, conf, {}) | ||
return webAuth(opener, opts, {}) | ||
} | ||
function webAuth (opener, conf, body) { | ||
if (!conf.opts) conf.opts = {} | ||
const target = url.resolve(conf.registry, '-/v1/login') | ||
body.hostname = conf.hostname || os.hostname() | ||
return fetchJSON({ | ||
target: target, | ||
function webAuth (opener, opts, body) { | ||
opts = ProfileConfig(opts) | ||
body.hostname = opts.hostname || os.hostname() | ||
const target = '/-/v1/login' | ||
return fetch(target, opts.concat({ | ||
method: 'POST', | ||
body: body, | ||
opts: conf.opts, | ||
saveResponse: true | ||
}).then(result => { | ||
const res = result[0] | ||
const content = result[1] | ||
body | ||
})).then(res => { | ||
return Promise.all([res, res.json()]) | ||
}).then(([res, content]) => { | ||
const {doneUrl, loginUrl} = content | ||
process.emit('log', 'verbose', 'web auth', 'got response', content) | ||
const doneUrl = content.doneUrl | ||
const loginUrl = content.loginUrl | ||
if (typeof doneUrl !== 'string' || | ||
typeof loginUrl !== 'string' || | ||
!doneUrl || !loginUrl) { | ||
throw new WebLoginInvalidResponse('POST', target, res, content) | ||
if ( | ||
typeof doneUrl !== 'string' || | ||
typeof loginUrl !== 'string' || | ||
!doneUrl || | ||
!loginUrl | ||
) { | ||
throw new WebLoginInvalidResponse('POST', res, content) | ||
} | ||
return content | ||
}).then(({doneUrl, loginUrl}) => { | ||
process.emit('log', 'verbose', 'web auth', 'opening url pair') | ||
const doneConf = { | ||
target: doneUrl, | ||
method: 'GET', | ||
opts: conf.opts, | ||
saveResponse: true | ||
} | ||
return opener(loginUrl).then(() => fetchJSON(doneConf)).then(onDone) | ||
function onDone (result) { | ||
const res = result[0] | ||
const content = result[1] | ||
if (res.status === 200) { | ||
if (!content.token) { | ||
throw new WebLoginInvalidResponse('GET', doneUrl, res, content) | ||
} else { | ||
return content | ||
} | ||
} else if (res.status === 202) { | ||
const retry = +res.headers.get('retry-after') | ||
if (retry > 0) { | ||
return new Promise(resolve => setTimeout(resolve, 1000 * retry)) | ||
.then(() => fetchJSON(doneConf)).then(onDone) | ||
} else { | ||
return fetchJSON(doneConf).then(onDone) | ||
} | ||
} else { | ||
throw new WebLoginInvalidResponse('GET', doneUrl, res, content) | ||
} | ||
} | ||
return opener(loginUrl).then( | ||
() => webAuthCheckLogin(doneUrl, opts.concat({cache: false})) | ||
) | ||
}).catch(er => { | ||
if ((er.statusCode >= 400 && er.statusCode <= 499) || er.statusCode === 500) { | ||
throw new WebLoginNotSupported('POST', target, { | ||
throw new WebLoginNotSupported('POST', { | ||
status: er.statusCode, | ||
@@ -124,6 +110,29 @@ headers: { raw: () => er.headers } | ||
function adduserCouch (username, email, password, conf) { | ||
function webAuthCheckLogin (doneUrl, opts) { | ||
return fetch(doneUrl, opts).then(res => { | ||
return Promise.all([res, res.json()]) | ||
}).then(([res, content]) => { | ||
if (res.status === 200) { | ||
if (!content.token) { | ||
throw new WebLoginInvalidResponse('GET', res, content) | ||
} else { | ||
return content | ||
} | ||
} else if (res.status === 202) { | ||
const retry = +res.headers.get('retry-after') * 1000 | ||
if (retry > 0) { | ||
return sleep(retry).then(() => webAuthCheckLogin(doneUrl, opts)) | ||
} else { | ||
return webAuthCheckLogin(doneUrl, opts) | ||
} | ||
} else { | ||
throw new WebLoginInvalidResponse('GET', res, content) | ||
} | ||
}) | ||
} | ||
function adduserCouch (username, email, password, opts) { | ||
validate('SSSO', arguments) | ||
if (!conf.opts) conf.opts = {} | ||
const userobj = { | ||
opts = ProfileConfig(opts) | ||
const body = { | ||
_id: 'org.couchdb.user:' + username, | ||
@@ -138,19 +147,21 @@ name: username, | ||
const logObj = {} | ||
Object.keys(userobj).forEach(k => { | ||
logObj[k] = k === 'password' ? 'XXXXX' : userobj[k] | ||
Object.keys(body).forEach(k => { | ||
logObj[k] = k === 'password' ? 'XXXXX' : body[k] | ||
}) | ||
process.emit('log', 'verbose', 'adduser', 'before first PUT', logObj) | ||
const target = url.resolve(conf.registry, '-/user/org.couchdb.user:' + encodeURIComponent(username)) | ||
return fetchJSON({target: target, method: 'PUT', body: userobj, opts: conf.opts}) | ||
.then(result => { | ||
result.username = username | ||
return result | ||
}) | ||
const target = '/-/user/org.couchdb.user:' + encodeURIComponent(username) | ||
return fetch.json(target, opts.concat({ | ||
method: 'PUT', | ||
body | ||
})).then(result => { | ||
result.username = username | ||
return result | ||
}) | ||
} | ||
function loginCouch (username, password, conf) { | ||
function loginCouch (username, password, opts) { | ||
validate('SSO', arguments) | ||
const userobj = { | ||
opts = ProfileConfig(opts) | ||
const body = { | ||
_id: 'org.couchdb.user:' + username, | ||
@@ -164,9 +175,12 @@ name: username, | ||
const logObj = {} | ||
Object.keys(userobj).forEach(k => { | ||
logObj[k] = k === 'password' ? 'XXXXX' : userobj[k] | ||
Object.keys(body).forEach(k => { | ||
logObj[k] = k === 'password' ? 'XXXXX' : body[k] | ||
}) | ||
process.emit('log', 'verbose', 'login', 'before first PUT', logObj) | ||
const target = url.resolve(conf.registry, '-/user/org.couchdb.user:' + encodeURIComponent(username)) | ||
return fetchJSON(Object.assign({method: 'PUT', target: target, body: userobj}, conf)).catch(err => { | ||
const target = '-/user/org.couchdb.user:' + encodeURIComponent(username) | ||
return fetch.json(target, opts.concat({ | ||
method: 'PUT', | ||
body | ||
})).catch(err => { | ||
if (err.code === 'E400') { | ||
@@ -177,20 +191,19 @@ err.message = `There is no user with the username "${username}".` | ||
if (err.code !== 'E409') throw err | ||
return fetchJSON(Object.assign({method: 'GET', target: target + '?write=true'}, conf)).then(result => { | ||
return fetch.json(target, opts.concat({ | ||
query: {write: true} | ||
})).then(result => { | ||
Object.keys(result).forEach(function (k) { | ||
if (!userobj[k] || k === 'roles') { | ||
userobj[k] = result[k] | ||
if (!body[k] || k === 'roles') { | ||
body[k] = result[k] | ||
} | ||
}) | ||
const req = { | ||
return fetch.json(`${target}/-rev/${body._rev}`, opts.concat({ | ||
method: 'PUT', | ||
target: target + '/-rev/' + userobj._rev, | ||
body: userobj, | ||
auth: { | ||
basic: { | ||
username: username, | ||
password: password | ||
} | ||
body, | ||
forceAuth: { | ||
username, | ||
password, | ||
otp: opts.otp | ||
} | ||
} | ||
return fetchJSON(Object.assign({}, conf, req)) | ||
})) | ||
}) | ||
@@ -203,11 +216,9 @@ }).then(result => { | ||
function get (conf) { | ||
function get (opts) { | ||
validate('O', arguments) | ||
const target = url.resolve(conf.registry, '-/npm/v1/user') | ||
return fetchJSON(Object.assign({target: target}, conf)) | ||
return fetch.json('/-/npm/v1/user', opts) | ||
} | ||
function set (profile, conf) { | ||
function set (profile, opts) { | ||
validate('OO', arguments) | ||
const target = url.resolve(conf.registry, '-/npm/v1/user') | ||
Object.keys(profile).forEach(key => { | ||
@@ -217,12 +228,16 @@ // profile keys can't be empty strings, but they CAN be null | ||
}) | ||
return fetchJSON(Object.assign({target: target, method: 'POST', body: profile}, conf)) | ||
return fetch.json('/-/npm/v1/user', ProfileConfig(opts, { | ||
method: 'POST', | ||
body: profile | ||
})) | ||
} | ||
function listTokens (conf) { | ||
function listTokens (opts) { | ||
validate('O', arguments) | ||
opts = ProfileConfig(opts) | ||
return untilLastPage(`-/npm/v1/tokens`) | ||
return untilLastPage('/-/npm/v1/tokens') | ||
function untilLastPage (href, objects) { | ||
return fetchJSON(Object.assign({target: url.resolve(conf.registry, href)}, conf)).then(result => { | ||
return fetch.json(href, opts).then(result => { | ||
objects = objects ? objects.concat(result.objects) : result.objects | ||
@@ -238,53 +253,26 @@ if (result.urls.next) { | ||
function removeToken (tokenKey, conf) { | ||
function removeToken (tokenKey, opts) { | ||
validate('SO', arguments) | ||
const target = url.resolve(conf.registry, `-/npm/v1/tokens/token/${tokenKey}`) | ||
return fetchJSON(Object.assign({target: target, method: 'DELETE'}, conf)) | ||
const target = `/-/npm/v1/tokens/token/${tokenKey}` | ||
return fetch(target, ProfileConfig(opts, { | ||
method: 'DELETE', | ||
ignoreBody: true | ||
})).then(() => null) | ||
} | ||
function createToken (password, readonly, cidrs, conf) { | ||
function createToken (password, readonly, cidrs, opts) { | ||
validate('SBAO', arguments) | ||
const target = url.resolve(conf.registry, '-/npm/v1/tokens') | ||
const props = { | ||
password: password, | ||
readonly: readonly, | ||
cidr_whitelist: cidrs | ||
} | ||
return fetchJSON(Object.assign({target: target, method: 'POST', body: props}, conf)) | ||
} | ||
function FetchError (err, method, target) { | ||
err.method = method | ||
err.href = target | ||
return err | ||
} | ||
class HttpErrorBase extends Error { | ||
constructor (method, target, res, body) { | ||
super() | ||
this.headers = res.headers.raw() | ||
this.statusCode = res.status | ||
this.code = 'E' + res.status | ||
this.method = method | ||
this.target = target | ||
this.body = body | ||
this.pkgid = packageName(target) | ||
} | ||
} | ||
class HttpErrorGeneral extends HttpErrorBase { | ||
constructor (method, target, res, body) { | ||
super(method, target, res, body) | ||
if (body && body.error) { | ||
this.message = `Registry returned ${this.statusCode} for ${this.method} on ${this.target}: ${body.error}` | ||
} else { | ||
this.message = `Registry returned ${this.statusCode} for ${this.method} on ${this.target}` | ||
return fetch.json('/-/npm/v1/tokens', ProfileConfig(opts, { | ||
method: 'POST', | ||
body: { | ||
password: password, | ||
readonly: readonly, | ||
cidr_whitelist: cidrs | ||
} | ||
Error.captureStackTrace(this, HttpErrorGeneral) | ||
} | ||
})) | ||
} | ||
class WebLoginInvalidResponse extends HttpErrorBase { | ||
constructor (method, target, res, body) { | ||
super(method, target, res, body) | ||
constructor (method, res, body) { | ||
super(method, res, body) | ||
this.message = 'Invalid response from web login endpoint' | ||
@@ -296,4 +284,4 @@ Error.captureStackTrace(this, WebLoginInvalidResponse) | ||
class WebLoginNotSupported extends HttpErrorBase { | ||
constructor (method, target, res, body) { | ||
super(method, target, res, body) | ||
constructor (method, res, body) { | ||
super(method, res, body) | ||
this.message = 'Web login not supported' | ||
@@ -305,107 +293,4 @@ this.code = 'ENYI' | ||
class HttpErrorAuthOTP extends HttpErrorBase { | ||
constructor (method, target, res, body) { | ||
super(method, target, res, body) | ||
this.message = 'OTP required for authentication' | ||
this.code = 'EOTP' | ||
Error.captureStackTrace(this, HttpErrorAuthOTP) | ||
} | ||
function sleep (ms) { | ||
return new Promise((resolve, reject) => setTimeout(resolve, ms)) | ||
} | ||
class HttpErrorAuthIPAddress extends HttpErrorBase { | ||
constructor (method, target, res, body) { | ||
super(method, target, res, body) | ||
this.message = 'Login is not allowed from your IP address' | ||
this.code = 'EAUTHIP' | ||
Error.captureStackTrace(this, HttpErrorAuthIPAddress) | ||
} | ||
} | ||
class HttpErrorAuthUnknown extends HttpErrorBase { | ||
constructor (method, target, res, body) { | ||
super(method, target, res, body) | ||
this.message = 'Unable to authenticate, need: ' + res.headers.get('www-authenticate') | ||
this.code = 'EAUTHUNKNOWN' | ||
Error.captureStackTrace(this, HttpErrorAuthUnknown) | ||
} | ||
} | ||
function authHeaders (auth) { | ||
const headers = {} | ||
if (!auth) return headers | ||
if (auth.otp) headers['npm-otp'] = auth.otp | ||
if (auth.token) { | ||
headers['Authorization'] = 'Bearer ' + auth.token | ||
} else if (auth.basic) { | ||
const basic = auth.basic.username + ':' + auth.basic.password | ||
headers['Authorization'] = 'Basic ' + Buffer.from(basic).toString('base64') | ||
} | ||
return headers | ||
} | ||
function fetchJSON (conf) { | ||
const fetchOpts = { | ||
method: conf.method, | ||
headers: Object.assign({}, conf.headers || (conf.auth && authHeaders(conf.auth)) || {}) | ||
} | ||
if (conf.body != null) { | ||
fetchOpts.headers['Content-Type'] = 'application/json' | ||
fetchOpts.body = JSON.stringify(conf.body) | ||
} | ||
process.emit('log', 'http', 'request', '→', conf.method || 'GET', conf.target) | ||
return fetch.defaults(conf.opts || {})(conf.target, fetchOpts).catch(err => { | ||
throw new FetchError(err, conf.method, conf.target) | ||
}).then(res => { | ||
if (res.headers.has('npm-notice')) { | ||
process.emit('warn', 'notice', res.headers.get('npm-notice')) | ||
} | ||
if (res.headers.get('content-type') === 'application/json') { | ||
return res.json().then(content => [res, content]) | ||
} else { | ||
return res.buffer().then(content => { | ||
try { | ||
return [res, JSON.parse(content)] | ||
} catch (_) { | ||
return [res, content] | ||
} | ||
}) | ||
} | ||
}).then(result => { | ||
const res = result[0] | ||
const content = result[1] | ||
const retVal = conf.saveResponse ? result : content | ||
process.emit('log', 'http', res.status, `← ${res.statusText} (${conf.target})`) | ||
if (res.status === 401 && res.headers.get('www-authenticate')) { | ||
const auth = res.headers.get('www-authenticate').split(/,\s*/).map(s => s.toLowerCase()) | ||
if (auth.indexOf('ipaddress') !== -1) { | ||
throw new HttpErrorAuthIPAddress(conf.method, conf.target, res, content) | ||
} else if (auth.indexOf('otp') !== -1) { | ||
throw new HttpErrorAuthOTP(conf.method, conf.target, res, content) | ||
} else { | ||
throw new HttpErrorAuthUnknown(conf.method, conf.target, res, content) | ||
} | ||
} else if (res.status < 200 || res.status >= 300) { | ||
throw new HttpErrorGeneral(conf.method, conf.target, res, content) | ||
} else { | ||
return retVal | ||
} | ||
}) | ||
} | ||
function packageName (href) { | ||
try { | ||
let basePath = url.parse(href).pathname.substr(1) | ||
if (!basePath.match(/^-/)) { | ||
basePath = basePath.split('/') | ||
var index = basePath.indexOf('_rewrite') | ||
if (index === -1) { | ||
index = basePath.length - 1 | ||
} else { | ||
index++ | ||
} | ||
return decodeURIComponent(basePath[index]) | ||
} | ||
} catch (_) { | ||
// this is ok | ||
} | ||
} |
{ | ||
"name": "npm-profile", | ||
"version": "3.0.2", | ||
"version": "4.0.0", | ||
"description": "Library for updating an npmjs.com profile", | ||
@@ -10,3 +10,4 @@ "keywords": [], | ||
"aproba": "^1.1.2 || 2", | ||
"make-fetch-happen": "^2.5.0 || 3 || 4" | ||
"figgy-pudding": "^3.4.1", | ||
"npm-registry-fetch": "^3.3.0" | ||
}, | ||
@@ -13,0 +14,0 @@ "main": "index.js", |
220
README.md
@@ -7,5 +7,4 @@ # npm-profile | ||
const profile = require('npm-profile') | ||
profile.get(registry, {token}).then(result => { | ||
// … | ||
}) | ||
const result = await profile.get(registry, {token}) | ||
//... | ||
``` | ||
@@ -18,6 +17,24 @@ | ||
## Functions | ||
## Table of Contents | ||
### profile.adduser(opener, prompter, config) → Promise | ||
* [API](#api) | ||
* Login and Account Creation | ||
* [`adduser()`](#adduser) | ||
* [`login()`](#login) | ||
* [`adduserWeb()`](#adduser-web) | ||
* [`loginWeb()`](#login-web) | ||
* [`adduserCouch()`](#adduser-couch) | ||
* [`loginCouch()`](#login-couch) | ||
* Profile Data Management | ||
* [`get()`](#get) | ||
* [`set()`](#set) | ||
* Token Management | ||
* [`listTokens()`](#list-tokens) | ||
* [`removeToken()`](#remove-token) | ||
* [`createToken()`](#create-token) | ||
## API | ||
### <a name="adduser"></a> `> profile.adduser(opener, prompter, [opts]) → Promise` | ||
Tries to create a user new web based login, if that fails it falls back to | ||
@@ -28,9 +45,6 @@ using the legacy CouchDB APIs. | ||
* `prompter` Function (creds) → Promise, returns a promise that resolves to an object with `username`, `email` and `password` properties. | ||
* `config` Object | ||
* [`opts`](#opts) Object (optional) plus extra keys: | ||
* `creds` Object, passed through to prompter, common values are: | ||
* `username` String, default value for username | ||
* `email` String, default value for email | ||
* `registry` String (for reference, the npm registry is `https://registry.npmjs.org`) | ||
* `opts` Object, [make-fetch-happen options](https://www.npmjs.com/package/make-fetch-happen#extra-options) for setting | ||
things like cache, proxy, SSL CA and retry rules. | ||
@@ -56,3 +70,3 @@ #### **Promise Value** | ||
### profile.login(opener, prompter, config) → Promise | ||
### <a name="login"></a> `> profile.login(opener, prompter, [opts]) → Promise` | ||
@@ -64,10 +78,5 @@ Tries to login using new web based login, if that fails it falls back to | ||
* `prompter` Function (creds) → Promise, returns a promise that resolves to an object with `username`, and `password` properties. | ||
* `config` Object | ||
* [`opts`](#opts) Object (optional) plus extra keys: | ||
* `creds` Object, passed through to prompter, common values are: | ||
* `name` String, default value for username | ||
* `registry` String (for reference, the npm registry is `https://registry.npmjs.org`) | ||
* `auth` Object, properties: `otp` | ||
the one-time password from a two-factor authentication device. | ||
* `opts` Object, [make-fetch-happen options](https://www.npmjs.com/package/make-fetch-happen#extra-options) for setting | ||
things like cache, proxy, SSL CA and retry rules. | ||
@@ -97,3 +106,3 @@ #### **Promise Value** | ||
### profile.adduserWeb(opener, config) → Promise | ||
### <a name="adduser-web"></a> `> profile.adduserWeb(opener, [opts]) → Promise` | ||
@@ -104,6 +113,3 @@ Tries to create a user new web based login, if that fails it falls back to | ||
* `opener` Function (url) → Promise, returns a promise that resolves after a browser has been opened for the user at `url`. | ||
* `config` Object | ||
* `registry` String (for reference, the npm registry is `https://registry.npmjs.org`) | ||
* `opts` Object, [make-fetch-happen options](https://www.npmjs.com/package/make-fetch-happen#extra-options) for setting | ||
things like cache, proxy, SSL CA and retry rules. | ||
* [`opts`](#opts) Object | ||
@@ -133,3 +139,3 @@ #### **Promise Value** | ||
### profile.loginWeb(opener, config) → Promise | ||
### <a name="login-web"></a> `> profile.loginWeb(opener, [opts]) → Promise` | ||
@@ -140,6 +146,3 @@ Tries to login using new web based login, if that fails it falls back to | ||
* `opener` Function (url) → Promise, returns a promise that resolves after a browser has been opened for the user at `url`. | ||
* `config` Object | ||
* `registry` String (for reference, the npm registry is `https://registry.npmjs.org`) | ||
* `opts` Object, [make-fetch-happen options](https://www.npmjs.com/package/make-fetch-happen#extra-options) for setting | ||
things like cache, proxy, SSL CA and retry rules. | ||
* [`opts`](#opts) Object (optional) | ||
@@ -163,3 +166,2 @@ #### **Promise Value** | ||
If the action was denied because it came from an IP address that this action | ||
@@ -171,8 +173,7 @@ on this account isn't allowed from then the `code` will be set to `EAUTHIP`. | ||
### profile.adduserCouch(username, email, password, config) → Promise | ||
### <a name="adduser-couch"></a> `> profile.adduserCouch(username, email, password, [opts]) → Promise` | ||
```js | ||
profile.adduser(username, email, password, {registry}).then(result => { | ||
// do something with result.token | ||
}) | ||
const {token} = await profile.adduser(username, email, password, {registry}) | ||
// `token` can be passed in through `opts` for authentication. | ||
``` | ||
@@ -190,6 +191,3 @@ | ||
* `password` String | ||
* `config` Object | ||
* `registry` String (for reference, the npm registry is `https://registry.npmjs.org`) | ||
* `opts` Object, [make-fetch-happen options](https://www.npmjs.com/package/make-fetch-happen#extra-options) for setting | ||
things like cache, proxy, SSL CA and retry rules. | ||
* [`opts`](#opts) Object (optional) | ||
@@ -218,14 +216,15 @@ #### **Promise Value** | ||
### profile.loginCouch(username, password, config) → Promise | ||
### <a name="login-couch"></a> `> profile.loginCouch(username, password, [opts]) → Promise` | ||
```js | ||
profile.login(username, password, {registry}).catch(err => { | ||
let token | ||
try { | ||
{token} = await profile.login(username, password, {registry}) | ||
} catch (err) { | ||
if (err.code === 'otp') { | ||
return getOTPFromSomewhere().then(otp => { | ||
return profile.login(username, password, {registry, auth: {otp}}) | ||
}) | ||
const otp = await getOTPFromSomewhere() | ||
{token} = await profile.login(username, password, {otp}) | ||
} | ||
}).then(result => { | ||
// do something with result.token | ||
}) | ||
} | ||
// `token` can now be passed in through `opts` for authentication. | ||
``` | ||
@@ -236,12 +235,7 @@ | ||
future authentication. This is what you use as an `authToken` in an `.npmrc`. | ||
* `username` String | ||
* `email` String | ||
* `password` String | ||
* `config` Object | ||
* `registry` String (for reference, the npm registry is `https://registry.npmjs.org`) | ||
* `auth` Object, properties: `otp` — the one-time password from a two-factor | ||
authentication device. | ||
* `opts` Object, [make-fetch-happen options](https://www.npmjs.com/package/make-fetch-happen#extra-options) for setting | ||
things like cache, proxy, SSL CA and retry rules. | ||
* [`opts`](#opts) Object (optional) | ||
@@ -271,21 +265,13 @@ #### **Promise Value** | ||
### profile.get(config) → Promise | ||
### <a name="get"></a> `> profile.get([opts]) → Promise` | ||
```js | ||
profile.get(registry, {auth: {token}}).then(userProfile => { | ||
// do something with userProfile | ||
}) | ||
const {name, email} = await profile.get({token}) | ||
console.log(`${token} belongs to https://npm.im/~${name}, (mailto:${email})`) | ||
``` | ||
Fetch profile information for the authenticated user. | ||
* `config` Object | ||
* `registry` String (for reference, the npm registry is `https://registry.npmjs.org`) | ||
* `auth` Object, properties: `token` — a bearer token returned from | ||
`adduser`, `login` or `createToken`, or, `username`, `password` (and | ||
optionally `otp`). Authenticating for this command via a username and | ||
password will likely not be supported in the future. | ||
* `opts` Object, [make-fetch-happen options](https://www.npmjs.com/package/make-fetch-happen#extra-options) for setting | ||
things like cache, proxy, SSL CA and retry rules. | ||
* [`opts`](#opts) Object | ||
#### **Promise Value** | ||
@@ -331,6 +317,6 @@ | ||
### profile.set(profileData, config) → Promise | ||
### <a name="set"></a> `> profile.set(profileData, [opts]) → Promise` | ||
```js | ||
profile.set({github: 'great-github-account-name'}, {registry, auth: {token}}) | ||
await profile.set({github: 'great-github-account-name'}, {token}) | ||
``` | ||
@@ -342,10 +328,3 @@ | ||
below for caveats relating to `password`, `tfa` and `cidr_whitelist`. | ||
* `config` Object | ||
* `registry` String (for reference, the npm registry is `https://registry.npmjs.org`) | ||
* `auth` Object, properties: `token` — a bearer token returned from | ||
`adduser`, `login` or `createToken`, or, `username`, `password` (and | ||
optionally `otp`). Authenticating for this command via a username and | ||
password will likely not be supported in the future. | ||
* `opts` Object, [make-fetch-happen options](https://www.npmjs.com/package/make-fetch-happen#extra-options) for setting | ||
things like cache, proxy, SSL CA and retry rules. | ||
* [`opts`](#opts) Object (optional) | ||
@@ -360,3 +339,8 @@ #### **SETTING `password`** | ||
```js | ||
profile.set({password: {old: 'abc123', new: 'my new (more secure) password'}}, {registry, auth: {token}}) | ||
await profile.set({ | ||
password: { | ||
old: 'abc123', | ||
new: 'my new (more secure) password' | ||
} | ||
}, {token}) | ||
``` | ||
@@ -371,3 +355,5 @@ | ||
```js | ||
profile.set({cidr_whitelist: [ '8.8.8.8/32' ], {registry, auth: {token}}) | ||
await profile.set({ | ||
cidr_whitelist: [ '8.8.8.8/32' ] | ||
}, {token}) | ||
// ↑ only one of google's dns servers can now access this account. | ||
@@ -382,3 +368,3 @@ ``` | ||
you'll need to disable it with `profile.set({tfa: {password, mode: 'disable'}, …)`. | ||
2. `profile.set({tfa: {password, mode}}, {registry, auth: {token}})` | ||
2. `profile.set({tfa: {password, mode}}, {registry, token})` | ||
* Note that the user's `password` is required here in the `tfa` object, | ||
@@ -404,3 +390,3 @@ regardless of how you're authenticating. | ||
`profile.set` with `tfa` set to an array of TWO codes from the user's | ||
authenticator, eg: `profile.set(tfa: [otp1, otp2]}, registry, {token})` | ||
authenticator, eg: `profile.set(tfa: [otp1, otp2]}, {registry, token})` | ||
5. On success you'll get a result object with a `tfa` property that has an | ||
@@ -415,3 +401,3 @@ array of one-time-use recovery codes. These are used to authenticate | ||
```js | ||
profile.set({tfa: {password, mode: 'disable'}, {registry, auth: {token}}} | ||
await profile.set({tfa: {password, mode: 'disable'}}, {token}) | ||
``` | ||
@@ -437,8 +423,7 @@ | ||
### profile.listTokens(config) → Promise | ||
### <a name="list-tokens"></a> `> profile.listTokens([opts]) → Promise` | ||
```js | ||
profile.listTokens(registry, {token}).then(tokens => { | ||
// do something with tokens | ||
}) | ||
const tokens = await profile.listTokens({registry, token}) | ||
console.log(`Number of tokens in your accounts: ${tokens.length}`) | ||
``` | ||
@@ -448,10 +433,3 @@ | ||
* `config` Object | ||
* `registry` String (for reference, the npm registry is `https://registry.npmjs.org`) | ||
* `auth` Object, properties: `token` — a bearer token returned from | ||
`adduser`, `login` or `createToken`, or, `username`, `password` (and | ||
optionally `otp`). Authenticating for this command via a username and | ||
password will likely not be supported in the future. | ||
* `opts` Object, [make-fetch-happen options](https://www.npmjs.com/package/make-fetch-happen#extra-options) for setting | ||
things like cache, proxy, SSL CA and retry rules. | ||
* [`opts`](#opts) Object (optional) | ||
@@ -483,8 +461,7 @@ #### **Promise Value** | ||
### profile.removeToken(token|key, config) → Promise | ||
### <a name="remove-token"><a> `> profile.removeToken(token|key, opts) → Promise` | ||
```js | ||
profile.removeToken(key, registry, {token}).then(() => { | ||
// token is gone! | ||
}) | ||
await profile.removeToken(key, {token}) | ||
// token is gone! | ||
``` | ||
@@ -495,10 +472,3 @@ | ||
* `token|key` String, either a complete authentication token or the key returned by `profile.listTokens`. | ||
* `config` Object | ||
* `registry` String (for reference, the npm registry is `https://registry.npmjs.org`) | ||
* `auth` Object, properties: `token` — a bearer token returned from | ||
`adduser`, `login` or `createToken`, or, `username`, `password` (and | ||
optionally `otp`). Authenticating for this command via a username and | ||
password will likely not be supported in the future. | ||
* `opts` Object, [make-fetch-happen options](https://www.npmjs.com/package/make-fetch-happen#extra-options) for setting | ||
things like cache, proxy, SSL CA and retry rules. | ||
* [`opts`](#opts) Object (optional) | ||
@@ -523,8 +493,9 @@ #### **Promise Value** | ||
### profile.createToken(password, readonly, cidr_whitelist, config) → Promise | ||
### <a name="create-token"></a> `> profile.createToken(password, readonly, cidr_whitelist, [opts]) → Promise` | ||
```js | ||
profile.createToken(password, readonly, cidr_whitelist, registry, {token, otp}).then(newToken => { | ||
// do something with the newToken | ||
}) | ||
const newToken = await profile.createToken( | ||
password, readonly, cidr_whitelist, {token, otp} | ||
) | ||
// do something with the newToken | ||
``` | ||
@@ -537,10 +508,3 @@ | ||
* `cidr_whitelist` Array | ||
* `config` Object | ||
* `registry` String (for reference, the npm registry is `https://registry.npmjs.org`) | ||
* `auth` Object, properties: `token` — a bearer token returned from | ||
`adduser`, `login` or `createToken`, or, `username`, `password` (and | ||
optionally `otp`). Authenticating for this command via a username and | ||
password will likely not be supported in the future. | ||
* `opts` Object, [make-fetch-happen options](https://www.npmjs.com/package/make-fetch-happen#extra-options) for setting | ||
things like cache, proxy, SSL CA and retry rules. | ||
* [`opts`](#opts) Object Optional | ||
@@ -552,3 +516,3 @@ #### **Promise Value** | ||
``` | ||
```js | ||
{ | ||
@@ -577,8 +541,24 @@ token: String, | ||
## Logging | ||
### <a name="opts"></a> options objects | ||
The various API functions accept an optional `opts` object as a final | ||
argument. This opts object can either be a regular Object, or a | ||
[`figgy-pudding`](https://npm.im/figgy-pudding) options object instance. | ||
Unless otherwise noted, the options accepted are the same as the | ||
[`npm-registry-fetch` | ||
options](https://www.npmjs.com/package/npm-registry-fetch#fetch-opts). | ||
Of particular note are `opts.registry`, and the auth-related options: | ||
* `opts.token` - used for Bearer auth | ||
* `opts.username` and `opts.password` - used for Basic auth | ||
* `opts.otp` - the 2fa OTP token | ||
## <a name="logging"></a> Logging | ||
This modules logs by emitting `log` events on the global `process` object. | ||
These events look like this: | ||
``` | ||
```js | ||
process.emit('log', 'loglevel', 'feature', 'message part 1', 'part 2', 'part 3', 'etc') | ||
@@ -595,9 +575,9 @@ ``` | ||
```js | ||
process.emit('log', 'http', 'request', '→', conf.method || 'GET', conf.target) | ||
``` | ||
process.emit('log', 'http', 'request', '→',conf.method || 'GET', conf.target) | ||
``` | ||
To handle the log events, you would do something like this: | ||
``` | ||
```js | ||
const log = require('npmlog') | ||
@@ -604,0 +584,0 @@ process.on('log', function (level) { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
29232
3
261
557
13
+ Addedfiggy-pudding@^3.4.1
+ Addednpm-registry-fetch@^3.3.0
+ AddedJSONStream@1.3.5(transitive)
+ Addedbuiltins@1.0.3(transitive)
+ Addedhosted-git-info@2.8.9(transitive)
+ Addedjsonparse@1.3.1(transitive)
+ Addednpm-package-arg@6.1.1(transitive)
+ Addednpm-registry-fetch@3.9.1(transitive)
+ Addedos-homedir@1.0.2(transitive)
+ Addedos-tmpdir@1.0.2(transitive)
+ Addedosenv@0.1.5(transitive)
+ Addedsemver@5.7.2(transitive)
+ Addedthrough@2.3.8(transitive)
+ Addedvalidate-npm-package-name@3.0.0(transitive)
- Removedmake-fetch-happen@^2.5.0 || 3 || 4