Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

npm-profile

Package Overview
Dependencies
Maintainers
2
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

npm-profile - npm Package Compare versions

Comparing version 2.0.5 to 3.0.0

CHANGELOG.md

184

index.js

@@ -5,5 +5,10 @@ 'use strict'

const url = require('url')
const os = require('os')
exports.adduserCouch = adduserCouch
exports.loginCouch = loginCouch
exports.adduserWeb = adduserWeb
exports.loginWeb = loginWeb
exports.login = login
exports.adduser = adduser
exports.login = login
exports.get = get

@@ -15,3 +20,105 @@ exports.set = set

function adduser (username, email, password, conf) {
// try loginWeb, catch the "not supported" message and fall back to couch
function login (opener, prompter, conf) {
validate('FFO', arguments)
return loginWeb(opener, conf).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))
} else {
throw er
}
})
}
function adduser (opener, prompter, conf) {
validate('FFO', arguments)
return adduserWeb(opener, conf).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))
} else {
throw er
}
})
}
function adduserWeb (opener, conf) {
validate('FO', arguments)
const body = { create: true }
process.emit('log', 'verbose', 'web adduser', 'before first POST')
return webAuth(opener, conf, body)
}
function loginWeb (opener, conf) {
validate('FO', arguments)
process.emit('log', 'verbose', 'web login', 'before first POST')
return webAuth(opener, conf, {})
}
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,
method: 'POST',
body: body,
opts: conf.opts,
saveResponse: true
}).then(result => {
const res = result[0]
const content = result[1]
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)
}
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)
}
}
}).catch(er => {
if (er.statusCode >= 400 && er.statusCode <= 499) {
throw new WebLoginNotSupported('POST', target, {
status: er.statusCode,
headers: { raw: () => er.headers }
}, er.body)
} else {
throw er
}
})
}
function adduserCouch (username, email, password, conf) {
validate('SSSO', arguments)

@@ -37,5 +144,9 @@ if (!conf.opts) conf.opts = {}

return fetchJSON({target: target, method: 'PUT', body: userobj, opts: conf.opts})
.then(result => {
result.username = username
return result
})
}
function login (username, password, conf) {
function loginCouch (username, password, conf) {
validate('SSO', arguments)

@@ -58,3 +169,6 @@ const userobj = {

return fetchJSON(Object.assign({method: 'PUT', target: target, body: userobj}, conf)).catch(err => {
if (err.code === 'E400') err.message = `There is no user with the username "${username}".`
if (err.code === 'E400') {
err.message = `There is no user with the username "${username}".`
throw err
}
if (err.code !== 'E409') throw err

@@ -80,2 +194,5 @@ return fetchJSON(Object.assign({method: 'GET', target: target + '?write=true'}, conf)).then(result => {

})
}).then(result => {
result.username = username
return result
})

@@ -153,28 +270,50 @@ }

class General extends HttpErrorBase {
class HttpErrorGeneral extends HttpErrorBase {
constructor (method, target, res, body) {
super(method, target, res, body)
this.message = `Registry returned ${this.statusCode} for ${this.method} on ${this.href}`
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}`
}
Error.captureStackTrace(this, HttpErrorGeneral)
}
}
class AuthOTP extends HttpErrorBase {
class WebLoginInvalidResponse extends HttpErrorBase {
constructor (method, target, res, body) {
super(method, target, res, body)
this.message = 'Invalid response from web login endpoint'
Error.captureStackTrace(this, WebLoginInvalidResponse)
}
}
class WebLoginNotSupported extends HttpErrorBase {
constructor (method, target, res, body) {
super(method, target, res, body)
this.message = 'Web login not supported'
this.code = 'ENYI'
Error.captureStackTrace(this, WebLoginNotSupported)
}
}
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, AuthOTP)
Error.captureStackTrace(this, HttpErrorAuthOTP)
}
}
class AuthIPAddress extends HttpErrorBase {
constructor (res, body) {
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, AuthIPAddress)
Error.captureStackTrace(this, HttpErrorAuthIPAddress)
}
}
class AuthUnknown extends HttpErrorBase {
class HttpErrorAuthUnknown extends HttpErrorBase {
constructor (method, target, res, body) {

@@ -184,3 +323,3 @@ super(method, target, res, body)

this.code = 'EAUTHIP'
Error.captureStackTrace(this, AuthIPAddress)
Error.captureStackTrace(this, HttpErrorAuthUnknown)
}

@@ -211,3 +350,3 @@ }

}
process.emit('log', 'http', 'request', '→',conf.method || 'GET', conf.target)
process.emit('log', 'http', 'request', '→', conf.method || 'GET', conf.target)
return fetch.defaults(conf.opts || {})(conf.target, fetchOpts).catch(err => {

@@ -230,2 +369,3 @@ throw new FetchError(err, conf.method, conf.target)

const content = result[1]
const retVal = conf.saveResponse ? result : content
process.emit('log', 'http', res.status, `← ${res.statusText} (${conf.target})`)

@@ -235,16 +375,12 @@ if (res.status === 401 && res.headers.get('www-authenticate')) {

if (auth.indexOf('ipaddress') !== -1) {
throw new AuthIPAddress(conf.method, conf.target, res, content)
throw new HttpErrorAuthIPAddress(conf.method, conf.target, res, content)
} else if (auth.indexOf('otp') !== -1) {
throw new AuthOTP(conf.method, conf.target, res, content)
throw new HttpErrorAuthOTP(conf.method, conf.target, res, content)
} else {
throw new AuthUnknown(conf.method, conf.target, res, content)
throw new HttpErrorAuthUnknown(conf.method, conf.target, res, content)
}
} else if (res.status < 200 || res.status >= 300) {
if (typeof content === 'object' && content.error) {
return content
} else {
throw new General(conf.method, conf.target, res, content)
}
throw new HttpErrorGeneral(conf.method, conf.target, res, content)
} else {
return content
return retVal
}

@@ -270,2 +406,2 @@ })

}
}
}

3

package.json
{
"name": "npm-profile",
"version": "2.0.5",
"version": "3.0.0",
"description": "Library for updating an npmjs.com profile",

@@ -22,4 +22,5 @@ "keywords": [],

"files": [
"CHANGELOG.md",
"index.js"
]
}

@@ -19,4 +19,146 @@ # npm-profile

### profile.adduser(username, email, password, config) → Promise
### profile.adduser(opener, prompter, config) → Promise
Tries to create a user new web based login, if that fails it falls back to
using the legacy CouchDB APIs.
* `opener` Function (url) → Promise, returns a promise that resolves after a browser has been opened for the user at `url`.
* `prompter` Function (creds) → Promise, returns a promise that resolves to an object with `username`, `email` and `password` properties.
* `config` Object
* `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.
#### **Promise Value**
An object with the following properties:
* `token` String, to be used to authenticate further API calls
* `username` String, the username the user authenticated as
#### **Promise Rejection**
An error object indicating what went wrong.
The `headers` property will contain the HTTP headers of the response.
If the action was denied because it came from an IP address that this action
on this account isn't allowed from then the `code` will be set to `EAUTHIP`.
Otherwise the code will be `'E'` followed by the HTTP response code, for
example a Forbidden response would be `E403`.
### profile.login(opener, prompter, config) → Promise
Tries to login using new web based login, if that fails it falls back to
using the legacy CouchDB APIs.
* `opener` Function (url) → Promise, returns a promise that resolves after a browser has been opened for the user at `url`.
* `prompter` Function (creds) → Promise, returns a promise that resolves to an object with `username`, and `password` properties.
* `config` Object
* `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.
#### **Promise Value**
An object with the following properties:
* `token` String, to be used to authenticate further API calls
* `username` String, the username the user authenticated as
#### **Promise Rejection**
An error object indicating what went wrong.
The `headers` property will contain the HTTP headers of the response.
If the action was denied because an OTP is required then `code` will be set
to `EOTP`. This error code can only come from a legacy CouchDB login and so
this should be retried with loginCouch.
If the action was denied because it came from an IP address that this action
on this account isn't allowed from then the `code` will be set to `EAUTHIP`.
Otherwise the code will be `'E'` followed by the HTTP response code, for
example a Forbidden response would be `E403`.
### profile.adduserWeb(opener, config) → Promise
Tries to create a user new web based login, if that fails it falls back to
using the legacy CouchDB APIs.
* `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.
#### **Promise Value**
An object with the following properties:
* `token` String, to be used to authenticate further API calls
* `username` String, the username the user authenticated as
#### **Promise Rejection**
An error object indicating what went wrong.
The `headers` property will contain the HTTP headers of the response.
If the registry does not support web-login then an error will be thrown with
its `code` property set to `ENYI` . You should retry with `adduserCouch`.
If you use `adduser` then this fallback will be done automatically.
If the action was denied because it came from an IP address that this action
on this account isn't allowed from then the `code` will be set to `EAUTHIP`.
Otherwise the code will be `'E'` followed by the HTTP response code, for
example a Forbidden response would be `E403`.
### profile.loginWeb(opener, config) → Promise
Tries to login using new web based login, if that fails it falls back to
using the legacy CouchDB APIs.
* `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.
#### **Promise Value**
An object with the following properties:
* `token` String, to be used to authenticate further API calls
* `username` String, the username the user authenticated as
#### **Promise Rejection**
An error object indicating what went wrong.
The `headers` property will contain the HTTP headers of the response.
If the registry does not support web-login then an error will be thrown with
its `code` property set to `ENYI` . You should retry with `loginCouch`.
If you use `login` then this fallback will be done automatically.
If the action was denied because it came from an IP address that this action
on this account isn't allowed from then the `code` will be set to `EAUTHIP`.
Otherwise the code will be `'E'` followed by the HTTP response code, for
example a Forbidden response would be `E403`.
### profile.adduserCouch(username, email, password, config) → Promise
```js

@@ -45,4 +187,7 @@ profile.adduser(username, email, password, {registry}).then(result => {

An object with a `token` property that can be passed into future authentication requests.
An object with the following properties:
* `token` String, to be used to authenticate further API calls
* `username` String, the username the user authenticated as
#### **Promise Rejection**

@@ -63,3 +208,3 @@

### profile.login(username, password, config) → Promise
### profile.loginCouch(username, password, config) → Promise

@@ -94,4 +239,7 @@ ```js

An object with a `token` property that can be passed into future authentication requests.
An object with the following properties:
* `token` String, to be used to authenticate further API calls
* `username` String, the username the user authenticated as
#### **Promise Rejection**

@@ -98,0 +246,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc