@blinkmobile/bm-identity
Advanced tools
Comparing version 3.3.0 to 4.0.0
@@ -5,2 +5,14 @@ # Change Log | ||
## 4.0.0 - 2018-02-01 | ||
### Added | ||
- `refreshToken` option to `login()` function | ||
### Removed | ||
- `getProfile()` function | ||
- `email` login provider | ||
- `sms` login provider | ||
## 3.3.0 - 2018-01-24 | ||
@@ -7,0 +19,0 @@ |
42
index.js
@@ -10,3 +10,2 @@ /* @flow */ | ||
const tenant = require('./lib/common/tenant.js') | ||
const profile = require('./lib/auth0/profile.js') | ||
const verifyJWT = require('./lib/auth0/verify-jwt.js') | ||
@@ -64,17 +63,2 @@ const auth0ClientFactory = require('./lib/auth0/client-factory.js') | ||
/** | ||
* Get the Auth0 profile for the current user. | ||
* @param {String} [accessToken] - The access token generated after a successful login. If not passed, will attempt to get the access token from the file system. | ||
* @returns {Object} The Auth0 profile. | ||
*/ | ||
getProfile ( | ||
accessToken /* : string | void */ | ||
) /* : Promise<Auth0Profile> */ { | ||
if (accessToken) { | ||
return profile.getByJWT(accessToken) | ||
} else { | ||
return profile.getByClient((privateVars.get(this) || {}).clientName) | ||
} | ||
} | ||
/** | ||
* Get access token generated after a successful login | ||
@@ -138,23 +122,2 @@ * @returns {String} The access token generated after a successful login. | ||
/* :: | ||
export type Auth0Identity = { | ||
user_id: string, | ||
provider: string, | ||
connection: string, | ||
isSocial: boolean | ||
} | ||
export type Auth0Profile = { | ||
email_verified: boolean, | ||
email: string, | ||
clientID: string, | ||
updated_at: string, // date | ||
name: string, | ||
picture: string, // url | ||
user_id: string, | ||
nickname: string, | ||
identities: Auth0Identity[], | ||
created_at: string, // date | ||
global_client_id: string | ||
} | ||
export type AWSCredentials = { | ||
@@ -167,7 +130,6 @@ accessKeyId : string, | ||
export type LoginOptions = { | ||
email?: string | true, | ||
password?: string, | ||
sms?: string | true, | ||
username?: string | true, | ||
storeJwt?: boolean | ||
storeJwt?: boolean, | ||
refreshToken?: boolean | ||
} | ||
@@ -174,0 +136,0 @@ |
@@ -13,7 +13,7 @@ /* @flow */ | ||
const userConfig = require('../utils/user-config.js') | ||
const getRefreshToken = require('../utils/get-refresh-token.js') | ||
const constants = require('../constants.js') | ||
function isExpired ( | ||
date /* : Date */, | ||
offsetSeconds /* : number | void */ | ||
date /* : Date */ | ||
) /* : boolean */ { | ||
@@ -23,4 +23,3 @@ if (!date) { | ||
} | ||
const offsetMS = offsetSeconds ? (offsetSeconds * 1000) : 0 | ||
return date.getTime() < Date.now() + offsetMS | ||
return date.getTime() < Date.now() | ||
} | ||
@@ -52,40 +51,40 @@ | ||
// If token has expired, return error | ||
if (isExpired(expiryDate)) { | ||
return Promise.reject(new Error('Unauthorised, your access token has expired. Please login again.')) | ||
// If token has not yet expired we can continue | ||
if (!isExpired(expiryDate)) { | ||
return Promise.resolve(jwt) | ||
} | ||
// If token expires after a certain time based on config, | ||
// get a new access token. | ||
if (isExpired(expiryDate, decoded.refreshIdTokenBeforeSeconds)) { | ||
return new Promise((resolve, reject) => { | ||
request.post(`${constants.AUTH0_URL}/delegation`, { | ||
json: { | ||
client_id: clientId, | ||
id_token: jwt, | ||
scope: 'passthrough', | ||
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', | ||
api_type: 'auth0' | ||
} | ||
}, (err, status, data) => { | ||
if (err) { | ||
return reject(err) | ||
} | ||
if (data.error) { | ||
return reject(new Error(data.error_description)) | ||
} | ||
// If token has expired, refresh with refresh_token | ||
return getRefreshToken() | ||
.then((refreshToken) => { | ||
if (!refreshToken) { | ||
return Promise.reject(new Error('Unauthorised, your access token has expired. Please login again.')) | ||
} | ||
// Store the new jwt to use next time. | ||
userConfig.getStore().update((config) => { | ||
config.accessToken = data.id_token | ||
return config | ||
}).then(() => resolve(data.id_token)) | ||
return new Promise((resolve, reject) => { | ||
request.post(`${constants.AUTH0_URL}/oauth/token`, { | ||
json: { | ||
client_id: clientId, | ||
refresh_token: refreshToken, | ||
grant_type: 'refresh_token' | ||
} | ||
}, (err, status, data) => { | ||
if (err) { | ||
return reject(err) | ||
} | ||
if (data.error) { | ||
return reject(new Error(data.error_description)) | ||
} | ||
// Store the new jwt to use next time. | ||
userConfig.getStore().update((config) => { | ||
config.id_token = data.id_token | ||
config.access_token = data.access_token | ||
return config | ||
}).then(() => resolve(data.id_token)) | ||
}) | ||
}) | ||
}) | ||
} | ||
// If token has not yet expired we can continue | ||
return Promise.resolve(jwt) | ||
} | ||
module.exports = verifyJWT |
@@ -17,4 +17,2 @@ /* @flow */ | ||
const UsernameLoginProvider = require('../login-providers/username.js') | ||
const EmailLoginProvider = require('../login-providers/email.js') | ||
const SmsLoginProvider = require('../login-providers/sms.js') | ||
const BrowserLoginProvider = require('../login-providers/browser.js') | ||
@@ -28,4 +26,2 @@ | ||
* <li>username: {@link UsernameLoginProvider}</li> | ||
* <li>email: {@link EmailLoginProvider}</li> | ||
* <li>sms: {@link SMSLoginProvider}</li> | ||
* <li>social (or undefined): {@link BrowserLoginProvider}</li> | ||
@@ -38,4 +34,2 @@ * </ol> | ||
* @param {String} [options.password] - The password. | ||
* @param {String} [options.email] - The email to send a verification code to. | ||
* @param {String} [options.sms] - The phone number to send a verification code to. | ||
* @param {Boolean} [options.social=true] - True if intending to use a social account to login e.g. Google. | ||
@@ -53,12 +47,6 @@ * @returns {String} The JWT generated after a successful login. | ||
const loginProvider = new UsernameLoginProvider(clientId) | ||
return loginProvider.login(options.username === true ? null : options.username, options.password, options.storeJwt) | ||
} else if (options.email) { | ||
const loginProvider = new EmailLoginProvider(clientId) | ||
return loginProvider.login(options.email === true ? null : options.email, options.storeJwt) | ||
} else if (options.sms) { | ||
const loginProvider = new SmsLoginProvider(clientId) | ||
return loginProvider.login(options.sms === true ? null : options.sms, options.storeJwt) | ||
return loginProvider.login(options.username === true ? null : options.username, options.password, options.storeJwt, options.refreshToken) | ||
} else { | ||
const loginProvider = new BrowserLoginProvider(clientId) | ||
return loginProvider.login(options.storeJwt) | ||
return loginProvider.login(options.storeJwt, options.refreshToken) | ||
} | ||
@@ -65,0 +53,0 @@ }) |
@@ -15,2 +15,56 @@ /* @flow */ | ||
function removeTokens () /* : Promise<string | void> */ { | ||
let refreshToken | ||
return userConfig.getStore().update(config => { | ||
refreshToken = config.refresh_token | ||
config.access_token = undefined | ||
config.id_token = undefined | ||
config.refresh_token = undefined | ||
return config | ||
}) | ||
.then(() => refreshToken) | ||
} | ||
function auth0Logout ( | ||
clientId /* : string */ | ||
) /* : Promise<void> */ { | ||
return new Promise((resolve, reject) => { | ||
request.get(`${constants.AUTH0_URL}/v2/logout?client_id=${clientId}`, (err, status, body) => { | ||
if (err) { | ||
reject(err) | ||
} else { | ||
resolve() | ||
} | ||
}) | ||
}) | ||
} | ||
function revokeRefreshToken ( | ||
clientId /* : string */, | ||
refreshToken /* : string | void */ | ||
) /* : Promise<void> */ { | ||
if (!refreshToken) { | ||
return Promise.resolve() | ||
} | ||
return new Promise((resolve, reject) => { | ||
var options = { | ||
method: 'POST', | ||
url: `${constants.AUTH0_URL}/oauth/revoke`, | ||
body: { | ||
client_id: clientId, | ||
token: refreshToken | ||
}, | ||
json: true | ||
} | ||
request(options, function (error, response, body) { | ||
if (error) { | ||
reject(error) | ||
} else { | ||
resolve() | ||
} | ||
}) | ||
}) | ||
} | ||
/** | ||
@@ -23,19 +77,11 @@ * Logout of a client. | ||
) /* : Promise<void> */ { | ||
return auth0ClientFactory.getClientIdByName(clientName).then(clientId => { | ||
return new Promise((resolve, reject) => { | ||
request.get(`${constants.AUTH0_URL}/v2/logout?client_id=${clientId}`, (err, status, body) => { | ||
if (err) { | ||
reject(err) | ||
return | ||
} | ||
userConfig.getStore().update(config => { | ||
if (config.accessToken) { | ||
delete config.accessToken | ||
} | ||
return config | ||
}).then(() => resolve()) | ||
}) | ||
}) | ||
}) | ||
return Promise.all([ | ||
auth0ClientFactory.getClientIdByName(clientName), | ||
removeTokens() | ||
]) | ||
.then(([clientId, refreshToken]) => Promise.all([ | ||
auth0Logout(clientId), | ||
revokeRefreshToken(clientId, refreshToken) | ||
])) | ||
.then(() => {}) | ||
} | ||
@@ -42,0 +88,0 @@ |
@@ -6,5 +6,6 @@ /* @flow */ | ||
AUTH0_URL: 'https://blinkmobile.auth0.com', | ||
AUTH0_CALLBACK_URL: 'https://auth.blinkm.io/index.html' | ||
AUTH0_CALLBACK_URL: 'https://auth.blinkm.io/index.html', | ||
SCOPE: 'openid email' | ||
} | ||
module.exports = Object.freeze(constants) |
@@ -38,3 +38,4 @@ /* @flow */ | ||
login ( | ||
storeJwt /* : ?boolean */ | ||
storeJwt /* : ?boolean */, | ||
refreshToken /* : ?boolean */ | ||
) /* : Promise<string> */ { | ||
@@ -46,3 +47,3 @@ // Generate the verifier, and the corresponding challenge | ||
response_type: 'code', | ||
scope: 'openid refreshIdTokenBeforeSeconds serviceSettingsUrl email', | ||
scope: constants.SCOPE + (refreshToken ? ' offline_access' : ''), | ||
client_id: (privateVars.get(this) || {}).clientId, | ||
@@ -85,11 +86,11 @@ redirect_uri: constants.AUTH0_CALLBACK_URL, | ||
} | ||
resolve(body.id_token) | ||
resolve(body) | ||
}) | ||
})) | ||
.then((jwt) => { | ||
.then((body) => { | ||
if (storeJwt) { | ||
// Must use this.storeJWT instead of super.storeJWT to support bug in Node 4. | ||
return this.storeJWT(jwt) | ||
return this.storeJWT(body) | ||
} | ||
return jwt | ||
return body.id_token | ||
}) | ||
@@ -96,0 +97,0 @@ } |
@@ -5,3 +5,2 @@ /* @flow */ | ||
const request = require('request') | ||
const inquirer = require('inquirer') | ||
@@ -33,8 +32,11 @@ const constants = require('../constants.js') | ||
storeJWT ( | ||
jwt /* : string */ | ||
body /* : Object */ | ||
) /* : Promise<string> */ { | ||
return userConfig.getStore().update((config) => { | ||
config.accessToken = jwt | ||
config.accessToken = undefined | ||
config.access_token = body.access_token | ||
config.id_token = body.id_token | ||
config.refresh_token = body.refresh_token | ||
return config | ||
}).then(() => jwt) | ||
}).then(() => body.id_token) | ||
} | ||
@@ -46,3 +48,2 @@ | ||
* @param {String} password - The password to login with. | ||
* @param {String} connection - The connection to use. E.g. 'Username-Password-Authentication', 'sms' or 'email'. | ||
* @returns {String} The JWT generated after a successful login. | ||
@@ -53,14 +54,13 @@ */ | ||
password /* : string */, | ||
connection /* : string */, | ||
storeJwt /* : ?boolean */ | ||
storeJwt /* : ?boolean */, | ||
refreshToken /* : ?boolean */ | ||
) /* : Promise<string> */ { | ||
return new Promise((resolve, reject) => { | ||
request.post(`${constants.AUTH0_URL}/oauth/ro`, { | ||
request.post(`${constants.AUTH0_URL}/oauth/token`, { | ||
json: { | ||
client_id: (privateVars.get(this) || {}).clientId, | ||
scope: 'openid refreshIdTokenBeforeSeconds serviceSettingsUrl email', | ||
scope: constants.SCOPE + (refreshToken ? ' offline_access' : ''), | ||
grant_type: 'password', | ||
connection: connection, | ||
username: username, | ||
password: password | ||
username, | ||
password | ||
} | ||
@@ -77,44 +77,15 @@ }, (err, status, body) => { | ||
resolve(body.id_token) | ||
resolve(body) | ||
}) | ||
}) | ||
.then((jwt) => { | ||
.then((body) => { | ||
if (storeJwt) { | ||
// Must use this.storeJWT instead of super.storeJWT to support bug in Node 4. | ||
return this.storeJWT(jwt) | ||
return this.storeJWT(body) | ||
} | ||
return jwt | ||
return body.id_token | ||
}) | ||
} | ||
/** | ||
* Prompt for a verification code to login. This will internally request and store the JWT as well. | ||
* @param {String} message - The message to display in the prompt. | ||
* @param {String} username - The username to login with. | ||
* @param {String} connection - The connection to use. E.g. 'sms' or 'email'. | ||
* @returns {String} The JWT generated after a successful login. | ||
*/ | ||
promptForCode ( | ||
message /* : string */, | ||
username /* : string */, | ||
connection /* : string */, | ||
storeJwt /* : ?boolean */ | ||
) /* : Promise<string> */ { | ||
// Wait for user to input verification code. | ||
const questions = [{ | ||
type: 'input', | ||
name: 'code', | ||
message: message | ||
}] | ||
return inquirer.prompt(questions).then(results => { | ||
if (!results.code) { | ||
return Promise.reject(new Error('Verification code was not specified.')) | ||
} | ||
// Use code to login. | ||
return this.requestJWT(username, results.code, connection, storeJwt) | ||
}) | ||
} | ||
} | ||
module.exports = LoginProviderBase |
@@ -36,3 +36,4 @@ /* @flow */ | ||
password /* : string | void */, | ||
storeJwt /* : ?boolean */ | ||
storeJwt /* : ?boolean */, | ||
refreshToken /* : ?boolean */ | ||
) /* : Promise<string> */ { | ||
@@ -47,3 +48,3 @@ return this._getCredentials(username, password).then(results => { | ||
return super.requestJWT(results.username, results.password, 'Username-Password-Authentication', storeJwt) | ||
return super.requestJWT(results.username, results.password, storeJwt, refreshToken) | ||
}) | ||
@@ -50,0 +51,0 @@ } |
@@ -17,5 +17,6 @@ /* @flow */ | ||
function getJWT () /* : Promise<string | void> */ { | ||
return userConfig.getStore().load().then(config => config.accessToken) | ||
// Returning accessToken if id_token is not set to be backward compatible | ||
return userConfig.getStore().load().then(config => config.id_token || config.accessToken) | ||
} | ||
module.exports = getJWT |
{ | ||
"name": "@blinkmobile/bm-identity", | ||
"description": "Helper functions for Blink Mobiles single identity", | ||
"version": "3.3.0", | ||
"version": "4.0.0", | ||
"author": "BlinkMobile <developers@blinkmobile.com.au> (https://github.com/blinkmobile)", | ||
@@ -22,3 +22,3 @@ "bugs": { | ||
"devDependencies": { | ||
"ava": "^0.24.0", | ||
"ava": "^0.25.0", | ||
"eslint": "^4.0.0", | ||
@@ -31,3 +31,3 @@ "eslint-config-standard": "^10.0.0", | ||
"fixpack": "^2.3.1", | ||
"flow-bin": "^0.63.0", | ||
"flow-bin": "^0.64.0", | ||
"jsdoc": "^3.4.2", | ||
@@ -63,3 +63,3 @@ "npm-run-all": "^4.0.0", | ||
"nyc": "nyc check-coverage", | ||
"posttest": "npm run nyc && npm run eslint && npm run flow_check", | ||
"posttest": "npm run eslint && npm run flow_check", | ||
"pretest": "npm run fixpack", | ||
@@ -66,0 +66,0 @@ "test": "npm run ava" |
@@ -31,5 +31,4 @@ # bm-identity.js [![npm](https://img.shields.io/npm/v/@blinkmobile/bm-identity.svg?maxAge=2592000)](https://www.npmjs.com/package/@blinkmobile/bm-identity) [![AppVeyor Status](https://img.shields.io/appveyor/ci/blinkmobile/bm-identity-js/master.svg)](https://ci.appveyor.com/project/blinkmobile/bm-identity-js) [![Travis CI Status](https://travis-ci.org/blinkmobile/bm-identity.js.svg?branch=master)](https://travis-ci.org/blinkmobile/bm-identity.js) [![Greenkeeper badge](https://badges.greenkeeper.io/blinkmobile/bm-identity.js.svg)](https://greenkeeper.io/) | ||
password? : String, // Will be prompted for password if username is truthy | ||
email? : String|Boolean, // Can also pass true to be prompted for email address | ||
sms? : String|Boolean, // Can also pass true to be prompted for phone number | ||
storeJwt? : Boolean, // Set to true to store jwt on local file system, defaults to false | ||
refreshToken? : Boolean, // Set to true will request a refresh token as well as an access token | ||
} | ||
@@ -80,19 +79,2 @@ ``` | ||
### Get Profile | ||
If `accessToken` is not passed, will attempt to get the access token from the file system. | ||
See [Auth0 Profile Structure](https://auth0.com/docs/user-profile/user-profile-structure) for available properties. | ||
```js | ||
getProfile (accessToken: String | undefined) => Promise{Auth0Profile} | ||
``` | ||
```js | ||
blinkMobileIdentity.getProfile() | ||
.then(profile => { | ||
// Use Auth0 profile | ||
}); | ||
``` | ||
### Get Access Token | ||
@@ -99,0 +81,0 @@ |
@@ -16,7 +16,7 @@ 'use strict' | ||
const DECODED = { | ||
exp: (Date.now() / 1000) + 43200, // 12 hours after tests are run | ||
refreshIdTokenBeforeSeconds: 86400 // 24 hours | ||
exp: (Date.now() / 1000) + 43200 // 12 hours after tests are run | ||
} | ||
const DATA = { | ||
id_token: JWT | ||
id_token: JWT, | ||
access_token: JWT | ||
} | ||
@@ -38,3 +38,5 @@ | ||
return Promise.resolve(updateFn({})) | ||
}) | ||
}), | ||
'../utils/get-refresh-token.js': () => Promise.resolve('123abc') | ||
}, overrides)) | ||
@@ -89,4 +91,4 @@ } | ||
test('verifyJWT() should reject if jwt is expired', (t) => { | ||
t.plan(1) | ||
test('verifyJWT() should call request.post() if jwt is expired', (t) => { | ||
t.plan(2) | ||
const verifyJWT = t.context.getTestSubject({ | ||
@@ -97,22 +99,9 @@ 'jsonwebtoken': jsonwebtokenMock((jwt) => { | ||
} | ||
}) | ||
}) | ||
return verifyJWT(JWT, CLIENT_ID) | ||
.catch((error) => { | ||
t.deepEqual(error, new Error('Unauthorised, your access token has expired. Please login again.')) | ||
}) | ||
}) | ||
test('verifyJWT() should call request.post() if jwt expires after a certain period', (t) => { | ||
t.plan(2) | ||
const verifyJWT = t.context.getTestSubject({ | ||
}), | ||
'request': requestMock((url, body, callback) => { | ||
t.is(url, `${constants.AUTH0_URL}/delegation`) | ||
t.is(url, `${constants.AUTH0_URL}/oauth/token`) | ||
t.deepEqual(body.json, { | ||
client_id: CLIENT_ID, | ||
id_token: JWT, | ||
scope: 'passthrough', | ||
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', | ||
api_type: 'auth0' | ||
refresh_token: '123abc', | ||
grant_type: 'refresh_token' | ||
}) | ||
@@ -128,2 +117,7 @@ callback(null, {}, {}) | ||
const verifyJWT = t.context.getTestSubject({ | ||
'jsonwebtoken': jsonwebtokenMock((jwt) => { | ||
return { | ||
exp: (Date.now() / 1000) - 1 // 1 second before test is run (expired) | ||
} | ||
}), | ||
'request': requestMock((url, body, callback) => { | ||
@@ -140,2 +134,7 @@ callback(new Error('Test error message')) | ||
const verifyJWT = t.context.getTestSubject({ | ||
'jsonwebtoken': jsonwebtokenMock((jwt) => { | ||
return { | ||
exp: (Date.now() / 1000) - 1 // 1 second before test is run (expired) | ||
} | ||
}), | ||
'request': requestMock((url, body, callback) => { | ||
@@ -158,6 +157,12 @@ callback(null, {}, { | ||
const verifyJWT = t.context.getTestSubject({ | ||
'jsonwebtoken': jsonwebtokenMock((jwt) => { | ||
return { | ||
exp: (Date.now() / 1000) - 1 // 1 second before test is run (expired) | ||
} | ||
}), | ||
'../utils/user-config.js': userConfigStoreMock(null, (updateFn) => { | ||
const config = updateFn({}) | ||
t.deepEqual(config, { | ||
accessToken: JWT | ||
access_token: JWT, | ||
id_token: JWT | ||
}) | ||
@@ -164,0 +169,0 @@ return Promise.resolve() |
@@ -23,10 +23,2 @@ 'use strict' | ||
t.context.emailLoginProvider = loginProviderMock((clientId, email) => { | ||
return Promise.resolve(JWT) | ||
}) | ||
t.context.smsLoginProvider = loginProviderMock((clientId, phoneNumber) => { | ||
return Promise.resolve(JWT) | ||
}) | ||
t.context.browserLoginProvider = loginProviderMock((clientId) => { | ||
@@ -43,4 +35,2 @@ return Promise.resolve(JWT) | ||
'../login-providers/username.js': t.context.usernameLoginProvider, | ||
'../login-providers/email.js': t.context.emailLoginProvider, | ||
'../login-providers/sms.js': t.context.smsLoginProvider, | ||
'../login-providers/browser.js': t.context.browserLoginProvider | ||
@@ -68,4 +58,2 @@ }) | ||
'../login-providers/username.js': t.context.usernameLoginProvider, | ||
'../login-providers/email.js': t.context.emailLoginProvider, | ||
'../login-providers/sms.js': t.context.smsLoginProvider, | ||
'../login-providers/browser.js': t.context.browserLoginProvider | ||
@@ -91,4 +79,2 @@ }) | ||
}), | ||
'../login-providers/email.js': t.context.emailLoginProvider, | ||
'../login-providers/sms.js': t.context.smsLoginProvider, | ||
'../login-providers/browser.js': t.context.browserLoginProvider | ||
@@ -99,5 +85,3 @@ }) | ||
username: 'test', | ||
password: 'pass', | ||
email: 'email', | ||
sms: '12345' | ||
password: 'pass' | ||
}) | ||
@@ -120,4 +104,2 @@ .catch(() => { | ||
}), | ||
'../login-providers/email.js': t.context.emailLoginProvider, | ||
'../login-providers/sms.js': t.context.smsLoginProvider, | ||
'../login-providers/browser.js': t.context.browserLoginProvider | ||
@@ -128,5 +110,3 @@ }) | ||
username: true, | ||
password: 'pass', | ||
email: 'email', | ||
sms: '12345' | ||
password: 'pass' | ||
}) | ||
@@ -139,96 +119,2 @@ .catch(() => { | ||
test.cb('login() should create an emailLoginProvider if all options but username are', (t) => { | ||
const commonLogin = proxyquire(TEST_SUBJECT, { | ||
'../auth0/client-factory.js': t.context.auth0ClientFactory, | ||
'../login-providers/username.js': t.context.usernameLoginProvider, | ||
'../login-providers/email.js': loginProviderMock((clientId, email) => { | ||
t.is(clientId, CLIENT_ID) | ||
t.is(email, 'email') | ||
t.end() | ||
return Promise.resolve(JWT) | ||
}), | ||
'../login-providers/sms.js': t.context.smsLoginProvider, | ||
'../login-providers/browser.js': t.context.browserLoginProvider | ||
}) | ||
commonLogin.login(t.context.clientName, { | ||
email: 'email', | ||
sms: '12345' | ||
}) | ||
.catch(() => { | ||
t.fail() | ||
t.end() | ||
}) | ||
}) | ||
test.cb('login() should create a emailLoginProvider and call login() with null if email is passed in as true', (t) => { | ||
const commonLogin = proxyquire(TEST_SUBJECT, { | ||
'../auth0/client-factory.js': t.context.auth0ClientFactory, | ||
'../login-providers/username.js': t.context.usernameLoginProvider, | ||
'../login-providers/email.js': loginProviderMock((clientId, email) => { | ||
t.is(clientId, CLIENT_ID) | ||
t.is(email, null) | ||
t.end() | ||
return Promise.resolve(JWT) | ||
}), | ||
'../login-providers/sms.js': t.context.smsLoginProvider, | ||
'../login-providers/browser.js': t.context.browserLoginProvider | ||
}) | ||
commonLogin.login(t.context.clientName, { | ||
email: true, | ||
sms: '12345' | ||
}) | ||
.catch(() => { | ||
t.fail() | ||
t.end() | ||
}) | ||
}) | ||
test.cb('login() should create an smsLoginProvider if only the sms option is passed', (t) => { | ||
const commonLogin = proxyquire(TEST_SUBJECT, { | ||
'../auth0/client-factory.js': t.context.auth0ClientFactory, | ||
'../login-providers/username.js': t.context.usernameLoginProvider, | ||
'../login-providers/email.js': t.context.emailLoginProvider, | ||
'../login-providers/sms.js': loginProviderMock((clientId, phoneNumber) => { | ||
t.is(clientId, CLIENT_ID) | ||
t.is(phoneNumber, '12345') | ||
t.end() | ||
return Promise.resolve(JWT) | ||
}), | ||
'../login-providers/browser.js': t.context.browserLoginProvider | ||
}) | ||
commonLogin.login(t.context.clientName, { | ||
sms: '12345' | ||
}) | ||
.catch(() => { | ||
t.fail() | ||
t.end() | ||
}) | ||
}) | ||
test.cb('login() should create a smsLoginProvider and call login() with null if sms is passed in as true', (t) => { | ||
const commonLogin = proxyquire(TEST_SUBJECT, { | ||
'../auth0/client-factory.js': t.context.auth0ClientFactory, | ||
'../login-providers/username.js': t.context.usernameLoginProvider, | ||
'../login-providers/email.js': t.context.emailLoginProvider, | ||
'../login-providers/sms.js': loginProviderMock((clientId, phoneNumber) => { | ||
t.is(clientId, CLIENT_ID) | ||
t.is(phoneNumber, null) | ||
t.end() | ||
return Promise.resolve(JWT) | ||
}), | ||
'../login-providers/browser.js': t.context.browserLoginProvider | ||
}) | ||
commonLogin.login(t.context.clientName, { | ||
sms: true | ||
}) | ||
.catch(() => { | ||
t.fail() | ||
t.end() | ||
}) | ||
}) | ||
test.cb('login() should create an browserLoginProvider if no option are passed', (t) => { | ||
@@ -238,4 +124,2 @@ const commonLogin = proxyquire(TEST_SUBJECT, { | ||
'../login-providers/username.js': t.context.usernameLoginProvider, | ||
'../login-providers/email.js': t.context.emailLoginProvider, | ||
'../login-providers/sms.js': t.context.smsLoginProvider, | ||
'../login-providers/browser.js': loginProviderMock((clientId, phoneNumber) => { | ||
@@ -259,4 +143,2 @@ t.is(clientId, CLIENT_ID) | ||
'../login-providers/username.js': t.context.usernameLoginProvider, | ||
'../login-providers/email.js': t.context.emailLoginProvider, | ||
'../login-providers/sms.js': t.context.smsLoginProvider, | ||
'../login-providers/browser.js': loginProviderMock((clientId, storeJwt) => { | ||
@@ -275,4 +157,2 @@ t.falsy(storeJwt) | ||
'../login-providers/username.js': t.context.usernameLoginProvider, | ||
'../login-providers/email.js': t.context.emailLoginProvider, | ||
'../login-providers/sms.js': t.context.smsLoginProvider, | ||
'../login-providers/browser.js': loginProviderMock((clientId, storeJwt) => { | ||
@@ -291,4 +171,2 @@ t.is(storeJwt, true) | ||
'../login-providers/username.js': t.context.usernameLoginProvider, | ||
'../login-providers/email.js': t.context.emailLoginProvider, | ||
'../login-providers/sms.js': t.context.smsLoginProvider, | ||
'../login-providers/browser.js': loginProviderMock((clientId, storeJwt) => { | ||
@@ -295,0 +173,0 @@ t.is(storeJwt, false) |
@@ -5,6 +5,5 @@ 'use strict' | ||
function loginProviderBaseMock (storeJwtFn, requestJwtFn, promptForCodeFn) { | ||
function loginProviderBaseMock (storeJwtFn, requestJwtFn) { | ||
storeJwtFn = storeJwtFn || ((jwt) => Promise.resolve(jwt)) | ||
requestJwtFn = requestJwtFn || ((u, p, c) => Promise.resolve('jwt')) | ||
promptForCodeFn = promptForCodeFn || ((m, u, c) => Promise.resolve('jwt')) | ||
return class LoginProvider { | ||
@@ -25,6 +24,2 @@ constructor (clientId, clientName) { | ||
} | ||
promptForCode (message, username, connection) { | ||
return promptForCodeFn(message, username, connection) | ||
} | ||
} | ||
@@ -31,0 +26,0 @@ } |
@@ -77,3 +77,3 @@ 'use strict' | ||
response_type: 'code', | ||
scope: 'openid refreshIdTokenBeforeSeconds serviceSettingsUrl email', | ||
scope: constants.SCOPE, | ||
client_id: CLIENT_ID, | ||
@@ -80,0 +80,0 @@ redirect_uri: constants.AUTH0_CALLBACK_URL, |
@@ -6,3 +6,2 @@ 'use strict' | ||
const inquirerMock = require('../helpers/inquirer.js') | ||
const userConfigStoreMock = require('../helpers/user-config.js') | ||
@@ -19,4 +18,2 @@ const requestMock = require('../helpers/request.js') | ||
const CONNECTION = 'username-password' | ||
const MESSAGE = 'prompt message: ' | ||
const CODE = 'abc123' | ||
@@ -33,8 +30,2 @@ test.beforeEach((t) => { | ||
}) | ||
t.context.inquirer = inquirerMock((questions) => { | ||
return Promise.resolve({ | ||
code: CODE | ||
}) | ||
}) | ||
}) | ||
@@ -44,3 +35,2 @@ | ||
const LoginProviderBase = proxyquire(TEST_SUBJECT, { | ||
'inquirer': t.context.inquirer, | ||
'request': t.context.request, | ||
@@ -51,3 +41,3 @@ '../utils/user-config.js': t.context.userConfigStore | ||
loginProviderBase.storeJWT(JWT) | ||
loginProviderBase.storeJWT({ id_token: JWT }) | ||
.then((jwt) => { | ||
@@ -65,3 +55,2 @@ t.is(jwt, JWT) | ||
const LoginProviderBase = proxyquire(TEST_SUBJECT, { | ||
'inquirer': t.context.inquirer, | ||
'request': t.context.request, | ||
@@ -85,7 +74,5 @@ '../utils/user-config.js': t.context.userConfigStore | ||
const LoginProviderBase = proxyquire(TEST_SUBJECT, { | ||
'inquirer': t.context.inquirer, | ||
'request': requestMock((url, body, callback) => { | ||
t.is(url, `${constants.AUTH0_URL}/oauth/ro`) | ||
t.is(url, `${constants.AUTH0_URL}/oauth/token`) | ||
t.deepEqual(body.json, { | ||
connection: CONNECTION, | ||
username: USERNAME, | ||
@@ -95,3 +82,3 @@ password: PASSWORD, | ||
grant_type: 'password', | ||
scope: 'openid refreshIdTokenBeforeSeconds serviceSettingsUrl email' | ||
scope: constants.SCOPE | ||
}) | ||
@@ -114,3 +101,2 @@ t.end() | ||
const LoginProviderBase = proxyquire(TEST_SUBJECT, { | ||
'inquirer': t.context.inquirer, | ||
'request': requestMock((url, body, callback) => { | ||
@@ -128,3 +114,2 @@ callback(new Error('Test error message')) | ||
const LoginProviderBase = proxyquire(TEST_SUBJECT, { | ||
'inquirer': t.context.inquirer, | ||
'request': requestMock((url, body, callback) => { | ||
@@ -150,50 +135,1 @@ callback(null, {}, { | ||
}) | ||
test.cb('promptForCode() should prompt with the messge passed in', (t) => { | ||
const LoginProviderBase = proxyquire(TEST_SUBJECT, { | ||
'inquirer': inquirerMock((questions) => { | ||
t.is(questions.length, 1) | ||
t.deepEqual(questions[0], { | ||
type: 'input', | ||
name: 'code', | ||
message: MESSAGE | ||
}) | ||
t.end() | ||
return Promise.resolve({ | ||
code: CODE | ||
}) | ||
}), | ||
'request': t.context.request, | ||
'../utils/user-config.js': t.context.userConfigStore | ||
}) | ||
const loginProviderBase = new LoginProviderBase(CLIENT_ID) | ||
loginProviderBase.promptForCode(MESSAGE, USERNAME, CONNECTION) | ||
.catch((error) => { | ||
t.fail(error) | ||
t.end() | ||
}) | ||
}) | ||
test.cb('promptForCode() should reject if prompt does not return code', (t) => { | ||
const LoginProviderBase = proxyquire(TEST_SUBJECT, { | ||
'inquirer': inquirerMock((questions) => { | ||
return Promise.resolve({ | ||
code: '' | ||
}) | ||
}), | ||
'request': t.context.request, | ||
'../utils/user-config.js': t.context.userConfigStore | ||
}) | ||
const loginProviderBase = new LoginProviderBase(CLIENT_ID) | ||
loginProviderBase.promptForCode(MESSAGE, USERNAME, CONNECTION) | ||
.then(() => { | ||
t.fail() | ||
t.end() | ||
}) | ||
.catch(error => { | ||
t.deepEqual(error, new Error('Verification code was not specified.')) | ||
t.end() | ||
}) | ||
}) |
@@ -121,3 +121,2 @@ 'use strict' | ||
t.is(password, PASSWORD) | ||
t.is(connection, 'Username-Password-Authentication') | ||
t.end() | ||
@@ -124,0 +123,0 @@ return Promise.resolve(JWT) |
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
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
86279
44
2218
157