From ee1ddad5dd693ece1d9faf4622b9f1281f4fbf79 Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Tue, 28 May 2019 10:32:36 -0500 Subject: [PATCH 01/18] feat: add new token manager for ICP4D Introduce a constructor parameter, `authentication_type`, for specifying the authentication pattern. Required for using ICP4D --- .gitignore | 1 + auth/icp-token-manager.ts | 97 +++ auth/jwt-token-manager.ts | 169 +++++ iam-token-manager/v1.ts | 178 +---- lib/base_service.ts | 56 +- lib/requestwrapper.ts | 6 +- package-lock.json | 1361 ++++++++++++++----------------------- package.json | 1 + tsconfig.json | 1 + 9 files changed, 841 insertions(+), 1029 deletions(-) create mode 100644 auth/icp-token-manager.ts create mode 100644 auth/jwt-token-manager.ts diff --git a/.gitignore b/.gitignore index 0a5e89dd7..127f68f6f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ doc/ .env .eslintcache lib/*.js +auth/*.js iam-token-manager/*.js index.js .nyc_output diff --git a/auth/icp-token-manager.ts b/auth/icp-token-manager.ts new file mode 100644 index 000000000..6d187e587 --- /dev/null +++ b/auth/icp-token-manager.ts @@ -0,0 +1,97 @@ +/** + * Copyright 2019 IBM Corp. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import extend = require('extend'); +import { sendRequest } from '../lib/requestwrapper'; +import { JwtTokenManager } from './jwt-token-manager'; + +export type Options = { + url: string; + accessToken?: string; + username?: string; + password?: string; +} + +// this interface is a representation of the response +// object from the ICP service +export interface IcpTokenData { + username: string; + role: string; + permissions: string[]; + sub: string; + iss: string; + aud: string; + uid: string; + _messageCode_: string; + message: string; + accessToken: string; +} + +export class IcpTokenManagerV1 extends JwtTokenManager { + private username: string; + private password: string; + + /** + * ICP Token Manager Service + * + * Retreives, stores, and refreshes ICP tokens. + * + * @param {Object} options + * @param {String} options.icpApikey + * @param {String} options.icpAccessToken + * @param {String} options.url - url of the icp api to retrieve tokens from + * @constructor + */ + constructor(options: Options) { + super(options); + + this.tokenName = 'accessToken'; + + if (this.url) { + this.url = this.url + '/v1/preauth/validateAuth'; + } else { + // this is required + console.error('`url` is a required parameter for the ICP token manager.'); + } + if (options.username) { + this.username = options.username; + } + if (options.password) { + this.password = options.password; + } + // username and password are required too, unless there's access token + } + + /** + * Request an ICP token using a basic auth header. + * + * @param {Function} cb - The callback that handles the response. + * @returns {void} + */ + protected requestToken(cb: Function): void { + const parameters = { + options: { + url: this.url, + method: 'GET', + headers: { + Authorization: + this.computeBasicAuthHeader(this.username, this.password), + }, + } + }; + sendRequest(parameters, cb); + } +} diff --git a/auth/jwt-token-manager.ts b/auth/jwt-token-manager.ts new file mode 100644 index 000000000..864aa380e --- /dev/null +++ b/auth/jwt-token-manager.ts @@ -0,0 +1,169 @@ +/** + * Copyright 2015 IBM Corp. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import extend = require('extend'); +import jwt = require('jsonwebtoken'); +import { sendRequest } from '../lib/requestwrapper'; + +function getCurrentTime(): number { + return Math.floor(Date.now() / 1000); +} + +export type Options = { + accessToken?: string; + url?: string; +} + +export class JwtTokenManager { + protected url: string; + protected tokenName: string; + protected userAccessToken: string; + private tokenInfo: any; + private timeToLive: number; + private expireTime: number; + + /** + * Token Manager Service + * + * Retreives, stores, and refreshes JSON web tokens. + * + * @param {Object} options + * @param {String} options.url - url of the api to retrieve tokens from + * @param {String} options.accessToken + * @constructor + */ + constructor(options: Options) { + this.tokenInfo = {}; + + this.tokenName = 'access_token'; + + if (options.url) { + this.url = options.url; + } + if (options.accessToken) { + this.userAccessToken = options.accessToken; + } + } + + /** + * This function sends an access token back through a callback. The source of the token + * is determined by the following logic: + * 1. If user provides their own managed access token, assume it is valid and send it + * 2. a) If this class is managing tokens and does not yet have one, make a request for one + * b) If this class is managing tokens and the token has expired, request a new one + * 3. If this class is managing tokens and has a valid token stored, send it + * + * @param {Function} cb - callback function that the token will be passed to + */ + public getToken(cb: Function) { + if (this.userAccessToken) { + // 1. use user-managed token + return cb(null, this.userAccessToken); + } else if (!this.tokenInfo[this.tokenName] || this.isTokenExpired()) { + // 2. request a new token + this.requestToken((err, tokenResponse) => { + this.saveTokenInfo(tokenResponse); + return cb(err, this.tokenInfo[this.tokenName]); + }); + } else { + // 3. use valid, sdk-managed token + return cb(null, this.tokenInfo[this.tokenName]); + } + } + + /** + * Set a self-managed access token. + * The access token should be valid and not yet expired. + * + * By using this method, you accept responsibility for managing the + * access token yourself. You must set a new access token before this + * one expires. Failing to do so will result in authentication errors + * after this token expires. + * + * @param {string} accessToken - A valid, non-expired access token + * @returns {void} + */ + public setAccessToken(accessToken: string): void { + this.userAccessToken = accessToken; + } + + /** + * Request a JWT using an API key. + * + * @param {Function} cb - The callback that handles the response. + * @returns {void} + */ + protected requestToken(cb: Function): void { + cb(null, 'token'); + } + + /** + * Compute and return a Basic Authorization header from a username and password. + * + * @param {string} username - The username or client id + * @param {string} password - The password or client secret + * @returns {string} + */ + protected computeBasicAuthHeader(username, password): string { + const encodedCreds = Buffer.from(`${username}:${password}`).toString('base64'); + return `Basic ${encodedCreds}`; + } + + /** + * Check if currently stored token is expired. + * + * Using a buffer to prevent the edge case of the + * token expiring before the request could be made. + * + * The buffer will be a fraction of the total TTL. Using 80%. + * + * @private + * @returns {boolean} + */ + private isTokenExpired(): boolean { + const { timeToLive, expireTime } = this; + + if (!timeToLive || !expireTime) { + return true; + } + + const fractionOfTtl = 0.8; + const currentTime = getCurrentTime(); + const refreshTime = expireTime - (timeToLive * (1.0 - fractionOfTtl)); + return refreshTime < currentTime; + } + + /** + * Decode the access token and save the response from the JWT service to the object's state. + * + * @param tokenResponse - Response object from JWT service request + * @private + * @returns {void} + */ + private saveTokenInfo(tokenResponse): void { + const accessToken = tokenResponse[this.tokenName]; + + // the time of expiration is found by decoding the JWT access token + const decodedResponse = jwt.decode(accessToken); + const { exp, iat } = decodedResponse; + + // exp is the time of expire and iat is the time of token retrieval + this.timeToLive = exp - iat; + this.expireTime = exp; + + this.tokenInfo = extend({}, tokenResponse); + } +} diff --git a/iam-token-manager/v1.ts b/iam-token-manager/v1.ts index bb8946037..92ec54d9b 100644 --- a/iam-token-manager/v1.ts +++ b/iam-token-manager/v1.ts @@ -15,6 +15,7 @@ */ import extend = require('extend'); +import { JwtTokenManager } from '../auth/jwt-token-manager'; import { sendRequest } from '../lib/requestwrapper'; /** @@ -34,9 +35,11 @@ function onlyOne(a: any, b: any): boolean { const CLIENT_ID_SECRET_WARNING = 'Warning: Client ID and Secret must BOTH be given, or the defaults will be used.'; export type Options = { + url?: string; + iamUrl?: string; iamApikey?: string; + accessToken?: string; iamAccessToken?: string; - iamUrl?: string; iamClientId?: string; iamClientSecret?: string; } @@ -52,13 +55,8 @@ export interface IamTokenData { expiration: number; } -export class IamTokenManagerV1 { - name: string; - serviceVersion: string; - protected iamUrl: string; - protected tokenInfo: IamTokenData; +export class IamTokenManagerV1 extends JwtTokenManager { private iamApikey: string; - private userAccessToken: string; private iamClientId: string; private iamClientSecret: string; @@ -74,8 +72,10 @@ export class IamTokenManagerV1 { * @constructor */ constructor(options: Options) { - this.iamUrl = options.iamUrl || 'https://iam.cloud.ibm.com/identity/token'; - this.tokenInfo = {} as IamTokenData; + super(options); + + this.url = this.url || options.iamUrl || 'https://iam.cloud.ibm.com/identity/token'; + if (options.iamApikey) { this.iamApikey = options.iamApikey; } @@ -94,38 +94,6 @@ export class IamTokenManagerV1 { } } - /** - * This function sends an access token back through a callback. The source of the token - * is determined by the following logic: - * 1. If user provides their own managed access token, assume it is valid and send it - * 2. If this class is managing tokens and does not yet have one, make a request for one - * 3. If this class is managing tokens and the token has expired, refresh it - * 4. If this class is managing tokens and has a valid token stored, send it - * - * @param {Function} cb - callback function that the token will be passed to - */ - public getToken(cb: Function) { - if (this.userAccessToken) { - // 1. use user-managed token - return cb(null, this.userAccessToken); - } else if (!this.tokenInfo.access_token || this.isRefreshTokenExpired()) { - // 2. request an initial token - this.requestToken((err, tokenResponse) => { - this.saveTokenInfo(tokenResponse); - return cb(err, this.tokenInfo.access_token); - }); - } else if (this.isTokenExpired()) { - // 3. refresh a token - this.refreshToken((err, tokenResponse) => { - this.saveTokenInfo(tokenResponse); - return cb(err, this.tokenInfo.access_token); - }); - } else { - // 4. use valid managed token - return cb(null, this.tokenInfo.access_token); - } - } - /** * Set the IAM 'client_id' and 'client_secret' values. * These values are used to compute the Authorization header used @@ -146,36 +114,31 @@ export class IamTokenManagerV1 { } } - /** - * Set a self-managed IAM access token. - * The access token should be valid and not yet expired. - * - * By using this method, you accept responsibility for managing the - * access token yourself. You must set a new access token before this - * one expires. Failing to do so will result in authentication errors - * after this token expires. - * - * @param {string} iamAccessToken - A valid, non-expired IAM access token - * @returns {void} - */ - public setAccessToken(iamAccessToken: string): void { - this.userAccessToken = iamAccessToken; - } - /** * Request an IAM token using an API key. * * @param {Function} cb - The callback that handles the response. * @returns {void} */ - private requestToken(cb: Function): void { + protected requestToken(cb: Function): void { + // Use bx:bx as default auth header creds. + let clientId = 'bx'; + let clientSecret = 'bx'; + + // If both the clientId and secret were specified by the user, then use them. + if (this.iamClientId && this.iamClientSecret) { + clientId = this.iamClientId; + clientSecret = this.iamClientSecret; + } + const parameters = { options: { - url: this.iamUrl, + url: this.url, method: 'POST', headers: { 'Content-type': 'application/x-www-form-urlencoded', - Authorization: this.computeIamAuthHeader() + Authorization: + this.computeBasicAuthHeader(clientId, clientSecret), }, form: { grant_type: 'urn:ibm:params:oauth:grant-type:apikey', @@ -186,99 +149,4 @@ export class IamTokenManagerV1 { }; sendRequest(parameters, cb); } - - /** - * Refresh an IAM token using a refresh token. - * - * @param {Function} cb - The callback that handles the response. - * @returns {void} - */ - private refreshToken(cb: Function) { - const parameters = { - options: { - url: this.iamUrl, - method: 'POST', - headers: { - 'Content-type': 'application/x-www-form-urlencoded', - Authorization: this.computeIamAuthHeader() - }, - form: { - grant_type: 'refresh_token', - refresh_token: this.tokenInfo.refresh_token - } - } - }; - sendRequest(parameters, cb); - } - - /** - * Check if currently stored token is expired. - * - * Using a buffer to prevent the edge case of the - * token expiring before the request could be made. - * - * The buffer will be a fraction of the total TTL. Using 80%. - * - * @private - * @returns {boolean} - */ - private isTokenExpired(): boolean { - if (!this.tokenInfo.expires_in || !this.tokenInfo.expiration) { - return true; - }; - const fractionOfTtl = 0.8; - const timeToLive = this.tokenInfo.expires_in; - const expireTime = this.tokenInfo.expiration; - const currentTime = Math.floor(Date.now() / 1000); - const refreshTime = expireTime - (timeToLive * (1.0 - fractionOfTtl)); - return refreshTime < currentTime; - } - - /** - * Used as a fail-safe to prevent the condition of a refresh token expiring, - * which could happen after around 30 days. This function will return true - * if it has been at least 7 days and 1 hour since the last token was - * retrieved. - * - * @private - * @returns {boolean} - */ - private isRefreshTokenExpired(): boolean { - if (!this.tokenInfo.expiration) { - return true; - }; - const sevenDays = 7 * 24 * 3600; - const currentTime = Math.floor(Date.now() / 1000); - const newTokenTime = this.tokenInfo.expiration + sevenDays; - return newTokenTime < currentTime; - } - - /** - * Save the response from the IAM service request to the object's state. - * - * @param {IamTokenData} tokenResponse - Response object from IAM service request - * @private - * @returns {void} - */ - private saveTokenInfo(tokenResponse: IamTokenData): void { - this.tokenInfo = extend({}, tokenResponse); - } - - /** - * Compute and return the Authorization header to be used with the - * IAM token server interactions (retrieve and refresh access token). - */ - private computeIamAuthHeader(): string { - // Use bx:bx as default auth header creds. - let clientId = 'bx'; - let clientSecret = 'bx'; - - // If both the clientId and secret were specified by the user, then use them. - if (this.iamClientId && this.iamClientSecret) { - clientId = this.iamClientId; - clientSecret = this.iamClientSecret; - } - const encodedCreds = Buffer.from(`${clientId}:${clientSecret}`).toString('base64'); - return `Basic ${encodedCreds}`; - } } diff --git a/lib/base_service.ts b/lib/base_service.ts index dbb757eb6..d206fec1a 100644 --- a/lib/base_service.ts +++ b/lib/base_service.ts @@ -16,6 +16,7 @@ import extend = require('extend'); import vcapServices = require('vcap_services'); +import { IcpTokenManagerV1 } from '../auth/icp-token-manager'; import { IamTokenManagerV1 } from '../iam-token-manager/v1'; import { stripTrailingSlash } from './helper'; import { readCredentialsFile } from './read-credentials-file'; @@ -37,10 +38,12 @@ export interface UserOptions { headers?: HeaderOptions; token?: string; iam_access_token?: string; + icp_access_token?: string; iam_apikey?: string; iam_url?: string; iam_client_id?: string; iam_client_secret?: string; + authentication_type?: string; disable_ssl_verification?: boolean; } @@ -56,6 +59,7 @@ export interface Credentials { password?: string; url?: string; iam_access_token?: string; + icp_access_token?: string; iam_apikey?: string; iam_url?: string; } @@ -65,7 +69,8 @@ function hasCredentials(obj: any): boolean { obj && ((obj.username && obj.password) || obj.iam_access_token || - obj.iam_apikey) + obj.iam_apikey || + obj.icp_access_token) ); } @@ -73,6 +78,10 @@ function isForICP(cred: string): boolean { return cred && cred.startsWith('icp-'); } +function isForICP4D(obj: any): boolean { + return obj && (obj.authentication_type === 'icp4d' || obj.icp_access_token); +} + function hasBasicCredentials(obj: any): boolean { return obj && obj.username && obj.password && !usesBasicForIam(obj); } @@ -127,6 +136,8 @@ export class BaseService { * @param {string} [options.iam_url] - url for iam service api, needed for services in staging * @param {string} [options.iam_client_id] - client id (username) for request to iam service * @param {string} [options.iam_client_secret] - secret (password) for request to iam service + * @param {string} [options.icp_access_token] - icp access token provided and managed by user + * @param {string} [options.authentication_type] - authentication pattern to be used. can be iam, basic, or icp4d * @param {string} [options.username] - required unless use_unauthenticated is set * @param {string} [options.password] - required unless use_unauthenticated is set * @param {boolean} [options.use_unauthenticated] - skip credential requirement @@ -160,21 +171,28 @@ export class BaseService { options, _options ); - if (hasIamCredentials(_options)) { + if (_options.authentication_type === 'iam' || hasIamCredentials(_options)) { this.tokenManager = new IamTokenManagerV1({ - iamApikey: _options.iam_apikey, - iamAccessToken: _options.iam_access_token, - iamUrl: _options.iam_url, + iamApikey: _options.iam_apikey || _options.password, + accessToken: _options.iam_access_token, + url: _options.iam_url, iamClientId: _options.iam_client_id, iamClientSecret: _options.iam_client_secret }); } else if (usesBasicForIam(_options)) { this.tokenManager = new IamTokenManagerV1({ iamApikey: _options.password, - iamUrl: _options.iam_url, + url: _options.iam_url, iamClientId: _options.iam_client_id, iamClientSecret: _options.iam_client_secret }); + } else if (isForICP4D(_options)) { + this.tokenManager = new IcpTokenManagerV1({ + url: _options.url, + username: _options.username, + password: _options.password, + accessToken: _options.icp_access_token + }); } else { this.tokenManager = null; } @@ -210,6 +228,9 @@ export class BaseService { if (this._options.iam_url) { credentials.iam_url = this._options.iam_url; } + if (this._options.icp_access_token) { + credentials.icp_access_token = this._options.icp_access_token; + } return credentials; } @@ -222,15 +243,20 @@ export class BaseService { * one expires. Failing to do so will result in authentication errors * after this token expires. * - * @param {string} iam_access_token - A valid, non-expired IAM access token + * @param {string} access_token - A valid, non-expired IAM access token * @returns {void} */ - public setAccessToken(iam_access_token: string) { // tslint:disable-line variable-name + public setAccessToken(access_token: string) { // tslint:disable-line variable-name if (this.tokenManager) { - this.tokenManager.setAccessToken(iam_access_token); + this.tokenManager.setAccessToken(access_token); + } else if (this._options.authentication_type === 'icp4d') { + this.tokenManager = new IcpTokenManagerV1({ + accessToken: access_token, + url: this._options.url + }); } else { this.tokenManager = new IamTokenManagerV1({ - iamAccessToken: iam_access_token + accessToken: access_token }); } } @@ -309,7 +335,7 @@ export class BaseService { const errorMessage = 'Insufficient credentials provided in ' + 'constructor argument. Refer to the documentation for the ' + 'required parameters. Common examples are username/password and ' + - 'iam_access_token.'; + 'iam_apikey.'; throw new Error(errorMessage); } // handle iam_apikey containing an ICP api key @@ -322,7 +348,7 @@ export class BaseService { } if (!hasIamCredentials(_options) && !usesBasicForIam(_options)) { - if (hasBasicCredentials(_options)) { + if (_options.authentication_type === 'basic' || hasBasicCredentials(_options)) { // Calculate and add Authorization header to base options const encodedCredentials = Buffer.from( `${_options.username}:${_options.password}` @@ -369,6 +395,8 @@ export class BaseService { const iamAccessToken: string = envObj[`${_name}_IAM_ACCESS_TOKEN`] || envObj[`${nameWithUnderscore}_IAM_ACCESS_TOKEN`]; const iamApiKey: string = envObj[`${_name}_IAM_APIKEY`] || envObj[`${nameWithUnderscore}_IAM_APIKEY`]; const iamUrl: string = envObj[`${_name}_IAM_URL`] || envObj[`${nameWithUnderscore}_IAM_URL`]; + const icpAccessToken: string = envObj[`${_name}_ICP_ACCESS_TOKEN`] || envObj[`${nameWithUnderscore}_ICP_ACCESS_TOKEN`]; + const authenticationType: string = envObj[`${_name}_AUTHENTICATION_TYPE`] || envObj[`${nameWithUnderscore}_AUTHENTICATION_TYPE`]; return { username, @@ -376,7 +404,9 @@ export class BaseService { url, iam_access_token: iamAccessToken, iam_apikey: iamApiKey, - iam_url: iamUrl + iam_url: iamUrl, + icp_access_token: icpAccessToken, + authentication_type: authenticationType, }; } /** diff --git a/lib/requestwrapper.ts b/lib/requestwrapper.ts index 4a3dba958..3ff2a212e 100644 --- a/lib/requestwrapper.ts +++ b/lib/requestwrapper.ts @@ -22,8 +22,6 @@ import querystring = require('querystring'); import { PassThrough as readableStream } from 'stream'; import { buildRequestFileObject, getMissingParams, isEmptyObject, isFileParam } from './helper'; -// tslint:disable-next-line:no-var-requires -const pkg = require('../package.json'); const isBrowser = typeof window === 'object'; const globalTransactionId = 'x-global-transaction-id'; @@ -289,7 +287,9 @@ export function sendRequest(parameters, _callback) { httpsAgent: new https.Agent({ rejectUnauthorized }), }; - axios(extend(true, {}, options, requestParams)) + const finalParams = extend(true, {}, options, requestParams); + + axios(finalParams) .then(res => { delete res.config; delete res.request; diff --git a/package-lock.json b/package-lock.json index ececfeebf..93c2e7abe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1776,6 +1776,11 @@ "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=", "dev": true }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -2585,6 +2590,14 @@ "safer-buffer": "^2.1.0" } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", @@ -4853,6 +4866,23 @@ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", "dev": true }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -4865,6 +4895,25 @@ "verror": "1.10.0" } }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -4969,17 +5018,40 @@ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", "dev": true }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, "lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" }, "lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", - "dev": true + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, "lodash.set": { "version": "4.3.2", @@ -5559,8 +5631,7 @@ "dependencies": { "JSONStream": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "bundled": true, "dev": true, "requires": { "jsonparse": "^1.2.0", @@ -5569,14 +5640,12 @@ }, "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "bundled": true, "dev": true }, "agent-base": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", - "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "bundled": true, "dev": true, "requires": { "es6-promisify": "^5.0.0" @@ -5584,8 +5653,7 @@ }, "agentkeepalive": { "version": "3.4.1", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.4.1.tgz", - "integrity": "sha512-MPIwsZU9PP9kOrZpyu2042kYA8Fdt/AedQYkYXucHgF9QoD9dXVp0ypuGnHXSR0hTstBxdt85Xkh4JolYfK5wg==", + "bundled": true, "dev": true, "requires": { "humanize-ms": "^1.2.1" @@ -5593,8 +5661,7 @@ }, "ajv": { "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "bundled": true, "dev": true, "requires": { "co": "^4.6.0", @@ -5605,8 +5672,7 @@ }, "ansi-align": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "bundled": true, "dev": true, "requires": { "string-width": "^2.0.0" @@ -5614,14 +5680,12 @@ }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "bundled": true, "dev": true }, "ansi-styles": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "bundled": true, "dev": true, "requires": { "color-convert": "^1.9.0" @@ -5629,32 +5693,27 @@ }, "ansicolors": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", - "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", + "bundled": true, "dev": true }, "ansistyles": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz", - "integrity": "sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk=", + "bundled": true, "dev": true }, "aproba": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "bundled": true, "dev": true }, "archy": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "bundled": true, "dev": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "bundled": true, "dev": true, "requires": { "delegates": "^1.0.0", @@ -5663,8 +5722,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -5678,8 +5736,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -5689,14 +5746,12 @@ }, "asap": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "bundled": true, "dev": true }, "asn1": { "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "bundled": true, "dev": true, "requires": { "safer-buffer": "~2.1.0" @@ -5704,38 +5759,32 @@ }, "assert-plus": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "bundled": true, "dev": true }, "asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "bundled": true, "dev": true }, "aws-sign2": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "bundled": true, "dev": true }, "aws4": { "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "bundled": true, "dev": true }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "bundled": true, "dev": true }, "bcrypt-pbkdf": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -5744,8 +5793,7 @@ }, "bin-links": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-1.1.2.tgz", - "integrity": "sha512-8eEHVgYP03nILphilltWjeIjMbKyJo3wvp9K816pHbhP301ismzw15mxAAEVQ/USUwcP++1uNrbERbp8lOA6Fg==", + "bundled": true, "dev": true, "requires": { "bluebird": "^3.5.0", @@ -5757,8 +5805,7 @@ }, "block-stream": { "version": "0.0.9", - "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "bundled": true, "dev": true, "requires": { "inherits": "~2.0.0" @@ -5766,14 +5813,12 @@ }, "bluebird": { "version": "3.5.3", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", - "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", + "bundled": true, "dev": true }, "boxen": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "bundled": true, "dev": true, "requires": { "ansi-align": "^2.0.0", @@ -5787,8 +5832,7 @@ }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "bundled": true, "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -5797,32 +5841,27 @@ }, "buffer-from": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", + "bundled": true, "dev": true }, "builtins": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "bundled": true, "dev": true }, "byline": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", - "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=", + "bundled": true, "dev": true }, "byte-size": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-5.0.1.tgz", - "integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==", + "bundled": true, "dev": true }, "cacache": { "version": "11.3.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", - "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", + "bundled": true, "dev": true, "requires": { "bluebird": "^3.5.3", @@ -5843,14 +5882,12 @@ "dependencies": { "chownr": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "bundled": true, "dev": true }, "lru-cache": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "bundled": true, "dev": true, "requires": { "yallist": "^3.0.2" @@ -5858,8 +5895,7 @@ }, "unique-filename": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "bundled": true, "dev": true, "requires": { "unique-slug": "^2.0.0" @@ -5867,40 +5903,34 @@ }, "yallist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "bundled": true, "dev": true } } }, "call-limit": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/call-limit/-/call-limit-1.1.0.tgz", - "integrity": "sha1-b9YbA/PaQqLNDsK2DwK9DnGZH+o=", + "bundled": true, "dev": true }, "camelcase": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "bundled": true, "dev": true }, "capture-stack-trace": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=", + "bundled": true, "dev": true }, "caseless": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "bundled": true, "dev": true }, "chalk": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "bundled": true, "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -5910,20 +5940,17 @@ }, "chownr": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "bundled": true, "dev": true }, "ci-info": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "bundled": true, "dev": true }, "cidr-regex": { "version": "2.0.10", - "resolved": "https://registry.npmjs.org/cidr-regex/-/cidr-regex-2.0.10.tgz", - "integrity": "sha512-sB3ogMQXWvreNPbJUZMRApxuRYd+KoIo4RGQ81VatjmMW6WJPo+IJZ2846FGItr9VzKo5w7DXzijPLGtSd0N3Q==", + "bundled": true, "dev": true, "requires": { "ip-regex": "^2.1.0" @@ -5931,14 +5958,12 @@ }, "cli-boxes": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "bundled": true, "dev": true }, "cli-columns": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cli-columns/-/cli-columns-3.1.2.tgz", - "integrity": "sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4=", + "bundled": true, "dev": true, "requires": { "string-width": "^2.0.0", @@ -5947,8 +5972,7 @@ }, "cli-table3": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", - "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "bundled": true, "dev": true, "requires": { "colors": "^1.1.2", @@ -5958,8 +5982,7 @@ }, "cliui": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "bundled": true, "dev": true, "requires": { "string-width": "^2.1.1", @@ -5969,14 +5992,12 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "bundled": true, "dev": true }, "strip-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "bundled": true, "dev": true, "requires": { "ansi-regex": "^3.0.0" @@ -5986,14 +6007,12 @@ }, "clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "bundled": true, "dev": true }, "cmd-shim": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-2.0.2.tgz", - "integrity": "sha1-b8vamUg6j9FdfTChlspp1oii79s=", + "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -6002,20 +6021,17 @@ }, "co": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "bundled": true, "dev": true }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "bundled": true, "dev": true }, "color-convert": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "bundled": true, "dev": true, "requires": { "color-name": "^1.1.1" @@ -6023,21 +6039,18 @@ }, "color-name": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "bundled": true, "dev": true }, "colors": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", - "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", + "bundled": true, "dev": true, "optional": true }, "columnify": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", - "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", + "bundled": true, "dev": true, "requires": { "strip-ansi": "^3.0.0", @@ -6046,8 +6059,7 @@ }, "combined-stream": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "bundled": true, "dev": true, "requires": { "delayed-stream": "~1.0.0" @@ -6055,14 +6067,12 @@ }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "bundled": true, "dev": true }, "concat-stream": { "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "bundled": true, "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -6073,8 +6083,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -6088,8 +6097,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -6099,8 +6107,7 @@ }, "config-chain": { "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "bundled": true, "dev": true, "requires": { "ini": "^1.3.4", @@ -6109,8 +6116,7 @@ }, "configstore": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "bundled": true, "dev": true, "requires": { "dot-prop": "^4.1.0", @@ -6123,14 +6129,12 @@ }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "bundled": true, "dev": true }, "copy-concurrently": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "bundled": true, "dev": true, "requires": { "aproba": "^1.1.1", @@ -6143,28 +6147,24 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "bundled": true, "dev": true }, "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "bundled": true, "dev": true } } }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "bundled": true, "dev": true }, "create-error-class": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "bundled": true, "dev": true, "requires": { "capture-stack-trace": "^1.0.0" @@ -6172,8 +6172,7 @@ }, "cross-spawn": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "bundled": true, "dev": true, "requires": { "lru-cache": "^4.0.1", @@ -6183,20 +6182,17 @@ }, "crypto-random-string": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "bundled": true, "dev": true }, "cyclist": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "bundled": true, "dev": true }, "dashdash": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "bundled": true, "dev": true, "requires": { "assert-plus": "^1.0.0" @@ -6204,8 +6200,7 @@ }, "debug": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "bundled": true, "dev": true, "requires": { "ms": "2.0.0" @@ -6213,40 +6208,34 @@ "dependencies": { "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "bundled": true, "dev": true } } }, "debuglog": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "bundled": true, "dev": true }, "decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "bundled": true, "dev": true }, "decode-uri-component": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "bundled": true, "dev": true }, "deep-extend": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz", - "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", + "bundled": true, "dev": true }, "defaults": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "bundled": true, "dev": true, "requires": { "clone": "^1.0.2" @@ -6254,32 +6243,27 @@ }, "delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "bundled": true, "dev": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "bundled": true, "dev": true }, "detect-indent": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", - "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=", + "bundled": true, "dev": true }, "detect-newline": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "bundled": true, "dev": true }, "dezalgo": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "bundled": true, "dev": true, "requires": { "asap": "^2.0.0", @@ -6288,8 +6272,7 @@ }, "dot-prop": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "bundled": true, "dev": true, "requires": { "is-obj": "^1.0.0" @@ -6297,20 +6280,17 @@ }, "dotenv": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", - "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==", + "bundled": true, "dev": true }, "duplexer3": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "bundled": true, "dev": true }, "duplexify": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", - "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", + "bundled": true, "dev": true, "requires": { "end-of-stream": "^1.0.0", @@ -6321,8 +6301,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -6336,8 +6315,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -6347,8 +6325,7 @@ }, "ecc-jsbn": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -6358,14 +6335,12 @@ }, "editor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz", - "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=", + "bundled": true, "dev": true }, "encoding": { "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "bundled": true, "dev": true, "requires": { "iconv-lite": "~0.4.13" @@ -6373,8 +6348,7 @@ }, "end-of-stream": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "bundled": true, "dev": true, "requires": { "once": "^1.4.0" @@ -6382,14 +6356,12 @@ }, "err-code": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", - "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", + "bundled": true, "dev": true }, "errno": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "bundled": true, "dev": true, "requires": { "prr": "~1.0.1" @@ -6397,14 +6369,12 @@ }, "es6-promise": { "version": "4.2.6", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", - "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==", + "bundled": true, "dev": true }, "es6-promisify": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "bundled": true, "dev": true, "requires": { "es6-promise": "^4.0.3" @@ -6412,14 +6382,12 @@ }, "escape-string-regexp": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "bundled": true, "dev": true }, "execa": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "bundled": true, "dev": true, "requires": { "cross-spawn": "^5.0.1", @@ -6433,52 +6401,44 @@ "dependencies": { "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "bundled": true, "dev": true } } }, "extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "bundled": true, "dev": true }, "extsprintf": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "bundled": true, "dev": true }, "fast-deep-equal": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "bundled": true, "dev": true }, "fast-json-stable-stringify": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "bundled": true, "dev": true }, "figgy-pudding": { "version": "3.5.1", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", - "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", + "bundled": true, "dev": true }, "find-npm-prefix": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz", - "integrity": "sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==", + "bundled": true, "dev": true }, "find-up": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "bundled": true, "dev": true, "requires": { "locate-path": "^2.0.0" @@ -6486,8 +6446,7 @@ }, "flush-write-stream": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", - "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", + "bundled": true, "dev": true, "requires": { "inherits": "^2.0.1", @@ -6496,8 +6455,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -6511,8 +6469,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -6522,14 +6479,12 @@ }, "forever-agent": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "bundled": true, "dev": true }, "form-data": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "bundled": true, "dev": true, "requires": { "asynckit": "^0.4.0", @@ -6539,8 +6494,7 @@ }, "from2": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "bundled": true, "dev": true, "requires": { "inherits": "^2.0.1", @@ -6549,8 +6503,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -6564,8 +6517,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -6575,8 +6527,7 @@ }, "fs-minipass": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "bundled": true, "dev": true, "requires": { "minipass": "^2.2.1" @@ -6584,8 +6535,7 @@ }, "fs-vacuum": { "version": "1.2.10", - "resolved": "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz", - "integrity": "sha1-t2Kb7AekAxolSP35n17PHMizHjY=", + "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -6595,8 +6545,7 @@ }, "fs-write-stream-atomic": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -6607,14 +6556,12 @@ "dependencies": { "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "bundled": true, "dev": true }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -6628,8 +6575,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -6639,14 +6585,12 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "bundled": true, "dev": true }, "fstream": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -6657,8 +6601,7 @@ }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "bundled": true, "dev": true, "requires": { "aproba": "^1.0.3", @@ -6673,14 +6616,12 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "bundled": true, "dev": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "bundled": true, "dev": true, "requires": { "code-point-at": "^1.0.0", @@ -6692,14 +6633,12 @@ }, "genfun": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", - "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", + "bundled": true, "dev": true }, "gentle-fs": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/gentle-fs/-/gentle-fs-2.0.1.tgz", - "integrity": "sha512-cEng5+3fuARewXktTEGbwsktcldA+YsnUEaXZwcK/3pjSE1X9ObnTs+/8rYf8s+RnIcQm2D5x3rwpN7Zom8Bew==", + "bundled": true, "dev": true, "requires": { "aproba": "^1.1.2", @@ -6714,28 +6653,24 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "bundled": true, "dev": true }, "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "bundled": true, "dev": true } } }, "get-caller-file": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "bundled": true, "dev": true }, "get-stream": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "bundled": true, "dev": true, "requires": { "pump": "^3.0.0" @@ -6743,8 +6678,7 @@ }, "getpass": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "bundled": true, "dev": true, "requires": { "assert-plus": "^1.0.0" @@ -6752,8 +6686,7 @@ }, "glob": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "bundled": true, "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -6766,8 +6699,7 @@ }, "global-dirs": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "bundled": true, "dev": true, "requires": { "ini": "^1.3.4" @@ -6775,8 +6707,7 @@ }, "got": { "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "bundled": true, "dev": true, "requires": { "create-error-class": "^3.0.0", @@ -6794,28 +6725,24 @@ "dependencies": { "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "bundled": true, "dev": true } } }, "graceful-fs": { "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "bundled": true, "dev": true }, "har-schema": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "bundled": true, "dev": true }, "har-validator": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", - "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "bundled": true, "dev": true, "requires": { "ajv": "^5.3.0", @@ -6824,32 +6751,27 @@ }, "has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "bundled": true, "dev": true }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "bundled": true, "dev": true }, "hosted-git-info": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "bundled": true, "dev": true }, "http-cache-semantics": { "version": "3.8.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "bundled": true, "dev": true }, "http-proxy-agent": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "bundled": true, "dev": true, "requires": { "agent-base": "4", @@ -6858,8 +6780,7 @@ }, "http-signature": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "bundled": true, "dev": true, "requires": { "assert-plus": "^1.0.0", @@ -6869,8 +6790,7 @@ }, "https-proxy-agent": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", - "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "bundled": true, "dev": true, "requires": { "agent-base": "^4.1.0", @@ -6879,8 +6799,7 @@ }, "humanize-ms": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "bundled": true, "dev": true, "requires": { "ms": "^2.0.0" @@ -6888,8 +6807,7 @@ }, "iconv-lite": { "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "bundled": true, "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -6897,14 +6815,12 @@ }, "iferr": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-1.0.2.tgz", - "integrity": "sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg==", + "bundled": true, "dev": true }, "ignore-walk": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "bundled": true, "dev": true, "requires": { "minimatch": "^3.0.4" @@ -6912,20 +6828,17 @@ }, "import-lazy": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "bundled": true, "dev": true }, "imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "bundled": true, "dev": true }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "bundled": true, "dev": true, "requires": { "once": "^1.3.0", @@ -6934,20 +6847,17 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "bundled": true, "dev": true }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "bundled": true, "dev": true }, "init-package-json": { "version": "1.10.3", - "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz", - "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==", + "bundled": true, "dev": true, "requires": { "glob": "^7.1.1", @@ -6962,26 +6872,22 @@ }, "invert-kv": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "bundled": true, "dev": true }, "ip": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "bundled": true, "dev": true }, "ip-regex": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "bundled": true, "dev": true }, "is-ci": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.1.0.tgz", - "integrity": "sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg==", + "bundled": true, "dev": true, "requires": { "ci-info": "^1.0.0" @@ -6989,16 +6895,14 @@ "dependencies": { "ci-info": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "bundled": true, "dev": true } } }, "is-cidr": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-3.0.0.tgz", - "integrity": "sha512-8Xnnbjsb0x462VoYiGlhEi+drY8SFwrHiSYuzc/CEwco55vkehTaxAyIjEdpi3EMvLPPJAJi9FlzP+h+03gp0Q==", + "bundled": true, "dev": true, "requires": { "cidr-regex": "^2.0.10" @@ -7006,8 +6910,7 @@ }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "bundled": true, "dev": true, "requires": { "number-is-nan": "^1.0.0" @@ -7015,8 +6918,7 @@ }, "is-installed-globally": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "bundled": true, "dev": true, "requires": { "global-dirs": "^0.1.0", @@ -7025,20 +6927,17 @@ }, "is-npm": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", + "bundled": true, "dev": true }, "is-obj": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "bundled": true, "dev": true }, "is-path-inside": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "bundled": true, "dev": true, "requires": { "path-is-inside": "^1.0.1" @@ -7046,87 +6945,73 @@ }, "is-redirect": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "bundled": true, "dev": true }, "is-retry-allowed": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", - "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "bundled": true, "dev": true }, "is-stream": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "bundled": true, "dev": true }, "is-typedarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "bundled": true, "dev": true }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "bundled": true, "dev": true }, "isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "bundled": true, "dev": true }, "isstream": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "bundled": true, "dev": true }, "jsbn": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "bundled": true, "dev": true, "optional": true }, "json-parse-better-errors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "bundled": true, "dev": true }, "json-schema": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "bundled": true, "dev": true }, "json-schema-traverse": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "bundled": true, "dev": true }, "json-stringify-safe": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "bundled": true, "dev": true }, "jsonparse": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "bundled": true, "dev": true }, "jsprim": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "bundled": true, "dev": true, "requires": { "assert-plus": "1.0.0", @@ -7137,8 +7022,7 @@ }, "latest-version": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "bundled": true, "dev": true, "requires": { "package-json": "^4.0.0" @@ -7146,14 +7030,12 @@ }, "lazy-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazy-property/-/lazy-property-1.0.0.tgz", - "integrity": "sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc=", + "bundled": true, "dev": true }, "lcid": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "bundled": true, "dev": true, "requires": { "invert-kv": "^1.0.0" @@ -7161,8 +7043,7 @@ }, "libcipm": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/libcipm/-/libcipm-3.0.3.tgz", - "integrity": "sha512-71V5CpTI+zFydTc5IjJ/tx8JHbXEJvmYF2zaSVW1V3X1rRnRjXqh44iuiyry1xgi3ProUQ1vX1uwFiWs00+2og==", + "bundled": true, "dev": true, "requires": { "bin-links": "^1.1.2", @@ -7184,8 +7065,7 @@ }, "libnpm": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/libnpm/-/libnpm-2.0.1.tgz", - "integrity": "sha512-qTKoxyJvpBxHZQB6k0AhSLajyXq9ZE/lUsZzuHAplr2Bpv9G+k4YuYlExYdUCeVRRGqcJt8hvkPh4tBwKoV98w==", + "bundled": true, "dev": true, "requires": { "bin-links": "^1.1.2", @@ -7212,8 +7092,7 @@ }, "libnpmaccess": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-3.0.1.tgz", - "integrity": "sha512-RlZ7PNarCBt+XbnP7R6PoVgOq9t+kou5rvhaInoNibhPO7eMlRfS0B8yjatgn2yaHIwWNyoJDolC/6Lc5L/IQA==", + "bundled": true, "dev": true, "requires": { "aproba": "^2.0.0", @@ -7224,16 +7103,14 @@ "dependencies": { "aproba": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "bundled": true, "dev": true } } }, "libnpmconfig": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/libnpmconfig/-/libnpmconfig-1.2.1.tgz", - "integrity": "sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==", + "bundled": true, "dev": true, "requires": { "figgy-pudding": "^3.5.1", @@ -7243,8 +7120,7 @@ "dependencies": { "find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "bundled": true, "dev": true, "requires": { "locate-path": "^3.0.0" @@ -7252,8 +7128,7 @@ }, "locate-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "bundled": true, "dev": true, "requires": { "p-locate": "^3.0.0", @@ -7262,8 +7137,7 @@ }, "p-limit": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", - "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "bundled": true, "dev": true, "requires": { "p-try": "^2.0.0" @@ -7271,8 +7145,7 @@ }, "p-locate": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "bundled": true, "dev": true, "requires": { "p-limit": "^2.0.0" @@ -7280,16 +7153,14 @@ }, "p-try": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "bundled": true, "dev": true } } }, "libnpmhook": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/libnpmhook/-/libnpmhook-5.0.2.tgz", - "integrity": "sha512-vLenmdFWhRfnnZiNFPNMog6CK7Ujofy2TWiM2CrpZUjBRIhHkJeDaAbJdYCT6W4lcHtyrJR8yXW8KFyq6UAp1g==", + "bundled": true, "dev": true, "requires": { "aproba": "^2.0.0", @@ -7300,8 +7171,7 @@ }, "libnpmorg": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/libnpmorg/-/libnpmorg-1.0.0.tgz", - "integrity": "sha512-o+4eVJBoDGMgRwh2lJY0a8pRV2c/tQM/SxlqXezjcAg26Qe9jigYVs+Xk0vvlYDWCDhP0g74J8UwWeAgsB7gGw==", + "bundled": true, "dev": true, "requires": { "aproba": "^2.0.0", @@ -7312,16 +7182,14 @@ "dependencies": { "aproba": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "bundled": true, "dev": true } } }, "libnpmpublish": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-1.1.1.tgz", - "integrity": "sha512-nefbvJd/wY38zdt+b9SHL6171vqBrMtZ56Gsgfd0duEKb/pB8rDT4/ObUQLrHz1tOfht1flt2zM+UGaemzAG5g==", + "bundled": true, "dev": true, "requires": { "aproba": "^2.0.0", @@ -7337,8 +7205,7 @@ }, "libnpmsearch": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/libnpmsearch/-/libnpmsearch-2.0.0.tgz", - "integrity": "sha512-vd+JWbTGzOSfiOc+72MU6y7WqmBXn49egCCrIXp27iE/88bX8EpG64ST1blWQI1bSMUr9l1AKPMVsqa2tS5KWA==", + "bundled": true, "dev": true, "requires": { "figgy-pudding": "^3.5.1", @@ -7348,8 +7215,7 @@ }, "libnpmteam": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/libnpmteam/-/libnpmteam-1.0.1.tgz", - "integrity": "sha512-gDdrflKFCX7TNwOMX1snWojCoDE5LoRWcfOC0C/fqF7mBq8Uz9zWAX4B2RllYETNO7pBupBaSyBDkTAC15cAMg==", + "bundled": true, "dev": true, "requires": { "aproba": "^2.0.0", @@ -7360,16 +7226,14 @@ "dependencies": { "aproba": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "bundled": true, "dev": true } } }, "libnpx": { "version": "10.2.0", - "resolved": "https://registry.npmjs.org/libnpx/-/libnpx-10.2.0.tgz", - "integrity": "sha512-X28coei8/XRCt15cYStbLBph+KGhFra4VQhRBPuH/HHMkC5dxM8v24RVgUsvODKCrUZ0eTgiTqJp6zbl0sskQQ==", + "bundled": true, "dev": true, "requires": { "dotenv": "^5.0.1", @@ -7384,8 +7248,7 @@ }, "locate-path": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "bundled": true, "dev": true, "requires": { "p-locate": "^2.0.0", @@ -7394,8 +7257,7 @@ }, "lock-verify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.1.0.tgz", - "integrity": "sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg==", + "bundled": true, "dev": true, "requires": { "npm-package-arg": "^6.1.0", @@ -7404,8 +7266,7 @@ }, "lockfile": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", - "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==", + "bundled": true, "dev": true, "requires": { "signal-exit": "^3.0.2" @@ -7413,14 +7274,12 @@ }, "lodash._baseindexof": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", - "integrity": "sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=", + "bundled": true, "dev": true }, "lodash._baseuniq": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz", - "integrity": "sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=", + "bundled": true, "dev": true, "requires": { "lodash._createset": "~4.0.0", @@ -7429,20 +7288,17 @@ }, "lodash._bindcallback": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", - "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=", + "bundled": true, "dev": true }, "lodash._cacheindexof": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", - "integrity": "sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=", + "bundled": true, "dev": true }, "lodash._createcache": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", - "integrity": "sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=", + "bundled": true, "dev": true, "requires": { "lodash._getnative": "^3.0.0" @@ -7450,62 +7306,52 @@ }, "lodash._createset": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz", - "integrity": "sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=", + "bundled": true, "dev": true }, "lodash._getnative": { "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "bundled": true, "dev": true }, "lodash._root": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "bundled": true, "dev": true }, "lodash.clonedeep": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "bundled": true, "dev": true }, "lodash.restparam": { "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "bundled": true, "dev": true }, "lodash.union": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=", + "bundled": true, "dev": true }, "lodash.uniq": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "bundled": true, "dev": true }, "lodash.without": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz", - "integrity": "sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=", + "bundled": true, "dev": true }, "lowercase-keys": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "bundled": true, "dev": true }, "lru-cache": { "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "bundled": true, "dev": true, "requires": { "pseudomap": "^1.0.2", @@ -7514,8 +7360,7 @@ }, "make-dir": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "bundled": true, "dev": true, "requires": { "pify": "^3.0.0" @@ -7523,8 +7368,7 @@ }, "make-fetch-happen": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz", - "integrity": "sha512-7R5ivfy9ilRJ1EMKIOziwrns9fGeAD4bAha8EB7BIiBBLHm2KeTUGCrICFt2rbHfzheTLynv50GnNTK1zDTrcQ==", + "bundled": true, "dev": true, "requires": { "agentkeepalive": "^3.4.1", @@ -7542,14 +7386,12 @@ }, "meant": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/meant/-/meant-1.0.1.tgz", - "integrity": "sha512-UakVLFjKkbbUwNWJ2frVLnnAtbb7D7DsloxRd3s/gDpI8rdv8W5Hp3NaDb+POBI1fQdeussER6NB8vpcRURvlg==", + "bundled": true, "dev": true }, "mem": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "bundled": true, "dev": true, "requires": { "mimic-fn": "^1.0.0" @@ -7557,14 +7399,12 @@ }, "mime-db": { "version": "1.35.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", - "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==", + "bundled": true, "dev": true }, "mime-types": { "version": "2.1.19", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", - "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "bundled": true, "dev": true, "requires": { "mime-db": "~1.35.0" @@ -7572,14 +7412,12 @@ }, "mimic-fn": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "bundled": true, "dev": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "bundled": true, "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -7587,14 +7425,12 @@ }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "bundled": true, "dev": true }, "minipass": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.3.tgz", - "integrity": "sha512-/jAn9/tEX4gnpyRATxgHEOV6xbcyxgT7iUnxo9Y3+OB0zX00TgKIv/2FZCf5brBbICcwbLqVv2ImjvWWrQMSYw==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "^5.1.2", @@ -7603,16 +7439,14 @@ "dependencies": { "yallist": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", + "bundled": true, "dev": true } } }, "minizlib": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.1.tgz", - "integrity": "sha512-TrfjCjk4jLhcJyGMYymBH6oTXcWjYbUAXTHDbtnWHjZC25h0cdajHuPE1zxb4DVmu8crfh+HwH/WMuyLG0nHBg==", + "bundled": true, "dev": true, "requires": { "minipass": "^2.2.1" @@ -7620,8 +7454,7 @@ }, "mississippi": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "bundled": true, "dev": true, "requires": { "concat-stream": "^1.5.0", @@ -7638,8 +7471,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "bundled": true, "dev": true, "requires": { "minimist": "0.0.8" @@ -7647,8 +7479,7 @@ }, "move-concurrently": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "bundled": true, "dev": true, "requires": { "aproba": "^1.1.1", @@ -7661,28 +7492,24 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "bundled": true, "dev": true } } }, "ms": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "bundled": true, "dev": true }, "mute-stream": { "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "bundled": true, "dev": true }, "node-fetch-npm": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", - "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", + "bundled": true, "dev": true, "requires": { "encoding": "^0.1.11", @@ -7692,8 +7519,7 @@ }, "node-gyp": { "version": "3.8.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", - "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "bundled": true, "dev": true, "requires": { "fstream": "^1.0.0", @@ -7712,8 +7538,7 @@ "dependencies": { "nopt": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "bundled": true, "dev": true, "requires": { "abbrev": "1" @@ -7721,14 +7546,12 @@ }, "semver": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "bundled": true, "dev": true }, "tar": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "bundled": true, "dev": true, "requires": { "block-stream": "*", @@ -7740,8 +7563,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "bundled": true, "dev": true, "requires": { "abbrev": "1", @@ -7750,8 +7572,7 @@ }, "normalize-package-data": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "bundled": true, "dev": true, "requires": { "hosted-git-info": "^2.1.4", @@ -7762,8 +7583,7 @@ "dependencies": { "resolve": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", - "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "bundled": true, "dev": true, "requires": { "path-parse": "^1.0.6" @@ -7773,8 +7593,7 @@ }, "npm-audit-report": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/npm-audit-report/-/npm-audit-report-1.3.2.tgz", - "integrity": "sha512-abeqS5ONyXNaZJPGAf6TOUMNdSe1Y6cpc9MLBRn+CuUoYbfdca6AxOyXVlfIv9OgKX+cacblbG5w7A6ccwoTPw==", + "bundled": true, "dev": true, "requires": { "cli-table3": "^0.5.0", @@ -7783,20 +7602,17 @@ }, "npm-bundled": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", - "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", + "bundled": true, "dev": true }, "npm-cache-filename": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz", - "integrity": "sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE=", + "bundled": true, "dev": true }, "npm-install-checks": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-3.0.0.tgz", - "integrity": "sha1-1K7N/VGlPjcjt7L5Oy7ijjB7wNc=", + "bundled": true, "dev": true, "requires": { "semver": "^2.3.0 || 3.x || 4 || 5" @@ -7804,8 +7620,7 @@ }, "npm-lifecycle": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-2.1.0.tgz", - "integrity": "sha512-QbBfLlGBKsktwBZLj6AviHC6Q9Y3R/AY4a2PYSIRhSKSS0/CxRyD/PfxEX6tPeOCXQgMSNdwGeECacstgptc+g==", + "bundled": true, "dev": true, "requires": { "byline": "^5.0.0", @@ -7820,14 +7635,12 @@ }, "npm-logical-tree": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz", - "integrity": "sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg==", + "bundled": true, "dev": true }, "npm-package-arg": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz", - "integrity": "sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA==", + "bundled": true, "dev": true, "requires": { "hosted-git-info": "^2.6.0", @@ -7838,8 +7651,7 @@ }, "npm-packlist": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz", - "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", + "bundled": true, "dev": true, "requires": { "ignore-walk": "^3.0.1", @@ -7848,8 +7660,7 @@ }, "npm-pick-manifest": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz", - "integrity": "sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA==", + "bundled": true, "dev": true, "requires": { "figgy-pudding": "^3.5.1", @@ -7859,8 +7670,7 @@ }, "npm-profile": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.1.tgz", - "integrity": "sha512-NQ1I/1Q7YRtHZXkcuU1/IyHeLy6pd+ScKg4+DQHdfsm769TGq6HPrkbuNJVJS4zwE+0mvvmeULzQdWn2L2EsVA==", + "bundled": true, "dev": true, "requires": { "aproba": "^1.1.2 || 2", @@ -7870,8 +7680,7 @@ }, "npm-registry-fetch": { "version": "3.9.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-3.9.0.tgz", - "integrity": "sha512-srwmt8YhNajAoSAaDWndmZgx89lJwIZ1GWxOuckH4Coek4uHv5S+o/l9FLQe/awA+JwTnj4FJHldxhlXdZEBmw==", + "bundled": true, "dev": true, "requires": { "JSONStream": "^1.3.4", @@ -7884,8 +7693,7 @@ }, "npm-run-path": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "bundled": true, "dev": true, "requires": { "path-key": "^2.0.0" @@ -7893,14 +7701,12 @@ }, "npm-user-validate": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-1.0.0.tgz", - "integrity": "sha1-jOyg9c6gTU6TUZ73LQVXp1Ei6VE=", + "bundled": true, "dev": true }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "bundled": true, "dev": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -7911,26 +7717,22 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "bundled": true, "dev": true }, "oauth-sign": { "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "bundled": true, "dev": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "bundled": true, "dev": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "bundled": true, "dev": true, "requires": { "wrappy": "1" @@ -7938,20 +7740,17 @@ }, "opener": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", - "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==", + "bundled": true, "dev": true }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "bundled": true, "dev": true }, "os-locale": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "bundled": true, "dev": true, "requires": { "execa": "^0.7.0", @@ -7961,14 +7760,12 @@ }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "bundled": true, "dev": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "bundled": true, "dev": true, "requires": { "os-homedir": "^1.0.0", @@ -7977,14 +7774,12 @@ }, "p-finally": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "bundled": true, "dev": true }, "p-limit": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "bundled": true, "dev": true, "requires": { "p-try": "^1.0.0" @@ -7992,8 +7787,7 @@ }, "p-locate": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "bundled": true, "dev": true, "requires": { "p-limit": "^1.1.0" @@ -8001,14 +7795,12 @@ }, "p-try": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "bundled": true, "dev": true }, "package-json": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "bundled": true, "dev": true, "requires": { "got": "^6.7.1", @@ -8019,8 +7811,7 @@ }, "pacote": { "version": "9.5.0", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.0.tgz", - "integrity": "sha512-aUplXozRbzhaJO48FaaeClmN+2Mwt741MC6M3bevIGZwdCaP7frXzbUOfOWa91FPHoLITzG0hYaKY363lxO3bg==", + "bundled": true, "dev": true, "requires": { "bluebird": "^3.5.3", @@ -8054,8 +7845,7 @@ "dependencies": { "lru-cache": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "bundled": true, "dev": true, "requires": { "yallist": "^3.0.2" @@ -8063,8 +7853,7 @@ }, "minipass": { "version": "2.3.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", - "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "^5.1.2", @@ -8073,16 +7862,14 @@ }, "yallist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "bundled": true, "dev": true } } }, "parallel-transform": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "bundled": true, "dev": true, "requires": { "cyclist": "~0.2.2", @@ -8092,8 +7879,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -8107,8 +7893,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -8118,68 +7903,57 @@ }, "path-exists": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "bundled": true, "dev": true }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "bundled": true, "dev": true }, "path-is-inside": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "bundled": true, "dev": true }, "path-key": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "bundled": true, "dev": true }, "path-parse": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "bundled": true, "dev": true }, "performance-now": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "bundled": true, "dev": true }, "pify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "bundled": true, "dev": true }, "prepend-http": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "bundled": true, "dev": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "bundled": true, "dev": true }, "promise-inflight": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "bundled": true, "dev": true }, "promise-retry": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", - "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "bundled": true, "dev": true, "requires": { "err-code": "^1.0.0", @@ -8188,16 +7962,14 @@ "dependencies": { "retry": { "version": "0.10.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", - "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "bundled": true, "dev": true } } }, "promzard": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", - "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", + "bundled": true, "dev": true, "requires": { "read": "1" @@ -8205,14 +7977,12 @@ }, "proto-list": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "bundled": true, "dev": true }, "protoduck": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", - "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", + "bundled": true, "dev": true, "requires": { "genfun": "^5.0.0" @@ -8220,26 +7990,22 @@ }, "prr": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "bundled": true, "dev": true }, "pseudomap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "bundled": true, "dev": true }, "psl": { "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "bundled": true, "dev": true }, "pump": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "bundled": true, "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -8248,8 +8014,7 @@ }, "pumpify": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "bundled": true, "dev": true, "requires": { "duplexify": "^3.6.0", @@ -8259,8 +8024,7 @@ "dependencies": { "pump": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "bundled": true, "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -8271,26 +8035,22 @@ }, "punycode": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "bundled": true, "dev": true }, "qrcode-terminal": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", - "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", + "bundled": true, "dev": true }, "qs": { "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "bundled": true, "dev": true }, "query-string": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.2.0.tgz", - "integrity": "sha512-5wupExkIt8RYL4h/FE+WTg3JHk62e6fFPWtAZA9J5IWK1PfTfKkMS93HBUHcFpeYi9KsY5pFbh+ldvEyaz5MyA==", + "bundled": true, "dev": true, "requires": { "decode-uri-component": "^0.2.0", @@ -8299,14 +8059,12 @@ }, "qw": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/qw/-/qw-1.0.1.tgz", - "integrity": "sha1-77/cdA+a0FQwRCassYNBLMi5ltQ=", + "bundled": true, "dev": true }, "rc": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.7.tgz", - "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", + "bundled": true, "dev": true, "requires": { "deep-extend": "^0.5.1", @@ -8317,16 +8075,14 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "bundled": true, "dev": true } } }, "read": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "bundled": true, "dev": true, "requires": { "mute-stream": "~0.0.4" @@ -8334,8 +8090,7 @@ }, "read-cmd-shim": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz", - "integrity": "sha1-LV0Vd4ajfAVdIgd8MsU/gynpHHs=", + "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2" @@ -8343,8 +8098,7 @@ }, "read-installed": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=", + "bundled": true, "dev": true, "requires": { "debuglog": "^1.0.1", @@ -8358,8 +8112,7 @@ }, "read-package-json": { "version": "2.0.13", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.13.tgz", - "integrity": "sha512-/1dZ7TRZvGrYqE0UAfN6qQb5GYBsNcqS1C0tNK601CFOJmtHI7NIGXwetEPU/OtoFHZL3hDxm4rolFFVE9Bnmg==", + "bundled": true, "dev": true, "requires": { "glob": "^7.1.1", @@ -8371,8 +8124,7 @@ }, "read-package-tree": { "version": "5.2.2", - "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.2.2.tgz", - "integrity": "sha512-rW3XWUUkhdKmN2JKB4FL563YAgtINifso5KShykufR03nJ5loGFlkUMe1g/yxmqX073SoYYTsgXu7XdDinKZuA==", + "bundled": true, "dev": true, "requires": { "debuglog": "^1.0.1", @@ -8384,8 +8136,7 @@ }, "readable-stream": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz", - "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", + "bundled": true, "dev": true, "requires": { "inherits": "^2.0.3", @@ -8395,8 +8146,7 @@ }, "readdir-scoped-modules": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz", - "integrity": "sha1-n6+jfShr5dksuuve4DDcm19AZ0c=", + "bundled": true, "dev": true, "requires": { "debuglog": "^1.0.1", @@ -8407,8 +8157,7 @@ }, "registry-auth-token": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", - "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "bundled": true, "dev": true, "requires": { "rc": "^1.1.6", @@ -8417,8 +8166,7 @@ }, "registry-url": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "bundled": true, "dev": true, "requires": { "rc": "^1.0.1" @@ -8426,8 +8174,7 @@ }, "request": { "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "bundled": true, "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -8454,32 +8201,27 @@ }, "require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "bundled": true, "dev": true }, "require-main-filename": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "bundled": true, "dev": true }, "resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "bundled": true, "dev": true }, "retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "bundled": true, "dev": true }, "rimraf": { "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "bundled": true, "dev": true, "requires": { "glob": "^7.1.3" @@ -8487,8 +8229,7 @@ }, "run-queue": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "bundled": true, "dev": true, "requires": { "aproba": "^1.1.1" @@ -8496,34 +8237,29 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "bundled": true, "dev": true } } }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "bundled": true, "dev": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "bundled": true, "dev": true }, "semver": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "bundled": true, "dev": true }, "semver-diff": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "bundled": true, "dev": true, "requires": { "semver": "^5.0.3" @@ -8531,14 +8267,12 @@ }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "bundled": true, "dev": true }, "sha": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sha/-/sha-2.0.1.tgz", - "integrity": "sha1-YDCCL70smCOUn49y7WQR7lzyWq4=", + "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -8547,8 +8281,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -8562,8 +8295,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -8573,8 +8305,7 @@ }, "shebang-command": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "bundled": true, "dev": true, "requires": { "shebang-regex": "^1.0.0" @@ -8582,38 +8313,32 @@ }, "shebang-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "bundled": true, "dev": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "bundled": true, "dev": true }, "slash": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "bundled": true, "dev": true }, "slide": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "bundled": true, "dev": true }, "smart-buffer": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.1.tgz", - "integrity": "sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg==", + "bundled": true, "dev": true }, "socks": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.2.0.tgz", - "integrity": "sha512-uRKV9uXQ9ytMbGm2+DilS1jB7N3AC0mmusmW5TVWjNuBZjxS8+lX38fasKVY9I4opv/bY/iqTbcpFFaTwpfwRg==", + "bundled": true, "dev": true, "requires": { "ip": "^1.1.5", @@ -8622,8 +8347,7 @@ }, "socks-proxy-agent": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz", - "integrity": "sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw==", + "bundled": true, "dev": true, "requires": { "agent-base": "~4.2.0", @@ -8632,14 +8356,12 @@ }, "sorted-object": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz", - "integrity": "sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw=", + "bundled": true, "dev": true }, "sorted-union-stream": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz", - "integrity": "sha1-x3lMfgd4gAUv9xqNSi27Sppjisc=", + "bundled": true, "dev": true, "requires": { "from2": "^1.3.0", @@ -8648,8 +8370,7 @@ "dependencies": { "from2": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-1.3.0.tgz", - "integrity": "sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0=", + "bundled": true, "dev": true, "requires": { "inherits": "~2.0.1", @@ -8658,14 +8379,12 @@ }, "isarray": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "bundled": true, "dev": true }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -8676,16 +8395,14 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "bundled": true, "dev": true } } }, "spdx-correct": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "bundled": true, "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -8694,14 +8411,12 @@ }, "spdx-exceptions": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", + "bundled": true, "dev": true }, "spdx-expression-parse": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "bundled": true, "dev": true, "requires": { "spdx-exceptions": "^2.1.0", @@ -8710,14 +8425,12 @@ }, "spdx-license-ids": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", - "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", + "bundled": true, "dev": true }, "sshpk": { "version": "1.14.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", - "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "bundled": true, "dev": true, "requires": { "asn1": "~0.2.3", @@ -8733,8 +8446,7 @@ }, "ssri": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "bundled": true, "dev": true, "requires": { "figgy-pudding": "^3.5.1" @@ -8742,8 +8454,7 @@ }, "stream-each": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", - "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", + "bundled": true, "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -8752,8 +8463,7 @@ }, "stream-iterate": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/stream-iterate/-/stream-iterate-1.2.0.tgz", - "integrity": "sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE=", + "bundled": true, "dev": true, "requires": { "readable-stream": "^2.1.5", @@ -8762,8 +8472,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -8777,8 +8486,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -8788,20 +8496,17 @@ }, "stream-shift": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "bundled": true, "dev": true }, "strict-uri-encode": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=", + "bundled": true, "dev": true }, "string-width": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "bundled": true, "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -8810,20 +8515,17 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "bundled": true, "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "bundled": true, "dev": true }, "strip-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "bundled": true, "dev": true, "requires": { "ansi-regex": "^3.0.0" @@ -8833,8 +8535,7 @@ }, "string_decoder": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", - "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -8842,14 +8543,12 @@ }, "stringify-package": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.0.tgz", - "integrity": "sha512-JIQqiWmLiEozOC0b0BtxZ/AOUtdUZHCBPgqIZ2kSJJqGwgb9neo44XdTHUC4HZSGqi03hOeB7W/E8rAlKnGe9g==", + "bundled": true, "dev": true }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "bundled": true, "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -8857,20 +8556,17 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "bundled": true, "dev": true }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "bundled": true, "dev": true }, "supports-color": { "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "bundled": true, "dev": true, "requires": { "has-flag": "^3.0.0" @@ -8878,8 +8574,7 @@ }, "tar": { "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", - "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "bundled": true, "dev": true, "requires": { "chownr": "^1.1.1", @@ -8893,14 +8588,12 @@ "dependencies": { "chownr": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "bundled": true, "dev": true }, "minipass": { "version": "2.3.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", - "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "^5.1.2", @@ -8909,16 +8602,14 @@ }, "yallist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "bundled": true, "dev": true } } }, "term-size": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "bundled": true, "dev": true, "requires": { "execa": "^0.7.0" @@ -8926,20 +8617,17 @@ }, "text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "bundled": true, "dev": true }, "through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "bundled": true, "dev": true }, "through2": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "bundled": true, "dev": true, "requires": { "readable-stream": "^2.1.5", @@ -8948,8 +8636,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -8963,8 +8650,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -8974,20 +8660,17 @@ }, "timed-out": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "bundled": true, "dev": true }, "tiny-relative-date": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz", - "integrity": "sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==", + "bundled": true, "dev": true }, "tough-cookie": { "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "bundled": true, "dev": true, "requires": { "psl": "^1.1.24", @@ -8996,8 +8679,7 @@ }, "tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "bundled": true, "dev": true, "requires": { "safe-buffer": "^5.0.1" @@ -9005,33 +8687,28 @@ }, "tweetnacl": { "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "bundled": true, "dev": true, "optional": true }, "typedarray": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "bundled": true, "dev": true }, "uid-number": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", - "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=", + "bundled": true, "dev": true }, "umask": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", - "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=", + "bundled": true, "dev": true }, "unique-filename": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "bundled": true, "dev": true, "requires": { "unique-slug": "^2.0.0" @@ -9039,8 +8716,7 @@ }, "unique-slug": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", - "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", + "bundled": true, "dev": true, "requires": { "imurmurhash": "^0.1.4" @@ -9048,8 +8724,7 @@ }, "unique-string": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "bundled": true, "dev": true, "requires": { "crypto-random-string": "^1.0.0" @@ -9057,20 +8732,17 @@ }, "unpipe": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "bundled": true, "dev": true }, "unzip-response": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "bundled": true, "dev": true }, "update-notifier": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "bundled": true, "dev": true, "requires": { "boxen": "^1.2.1", @@ -9087,8 +8759,7 @@ }, "url-parse-lax": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "bundled": true, "dev": true, "requires": { "prepend-http": "^1.0.1" @@ -9096,26 +8767,22 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "bundled": true, "dev": true }, "util-extend": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=", + "bundled": true, "dev": true }, "uuid": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "bundled": true, "dev": true }, "validate-npm-package-license": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "bundled": true, "dev": true, "requires": { "spdx-correct": "^3.0.0", @@ -9124,8 +8791,7 @@ }, "validate-npm-package-name": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "bundled": true, "dev": true, "requires": { "builtins": "^1.0.3" @@ -9133,8 +8799,7 @@ }, "verror": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "bundled": true, "dev": true, "requires": { "assert-plus": "^1.0.0", @@ -9144,8 +8809,7 @@ }, "wcwidth": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "bundled": true, "dev": true, "requires": { "defaults": "^1.0.3" @@ -9153,8 +8817,7 @@ }, "which": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "bundled": true, "dev": true, "requires": { "isexe": "^2.0.0" @@ -9162,14 +8825,12 @@ }, "which-module": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "bundled": true, "dev": true }, "wide-align": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "bundled": true, "dev": true, "requires": { "string-width": "^1.0.2" @@ -9177,8 +8838,7 @@ "dependencies": { "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "bundled": true, "dev": true, "requires": { "code-point-at": "^1.0.0", @@ -9190,8 +8850,7 @@ }, "widest-line": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.0.tgz", - "integrity": "sha1-AUKk6KJD+IgsAjOqDgKBqnYVInM=", + "bundled": true, "dev": true, "requires": { "string-width": "^2.1.1" @@ -9199,8 +8858,7 @@ }, "worker-farm": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", - "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", + "bundled": true, "dev": true, "requires": { "errno": "~0.1.7" @@ -9208,8 +8866,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "bundled": true, "dev": true, "requires": { "string-width": "^1.0.1", @@ -9218,8 +8875,7 @@ "dependencies": { "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "bundled": true, "dev": true, "requires": { "code-point-at": "^1.0.0", @@ -9231,14 +8887,12 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "bundled": true, "dev": true }, "write-file-atomic": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", - "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", + "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -9248,32 +8902,27 @@ }, "xdg-basedir": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "bundled": true, "dev": true }, "xtend": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "bundled": true, "dev": true }, "y18n": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "bundled": true, "dev": true }, "yallist": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "bundled": true, "dev": true }, "yargs": { "version": "11.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz", - "integrity": "sha512-Rjp+lMYQOWtgqojx1dEWorjCofi1YN7AoFvYV7b1gx/7dAAeuI4kN5SZiEvr0ZmsZTOpDRcCqrpI10L31tFkBw==", + "bundled": true, "dev": true, "requires": { "cliui": "^4.0.0", @@ -9292,16 +8941,14 @@ "dependencies": { "y18n": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "bundled": true, "dev": true } } }, "yargs-parser": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "bundled": true, "dev": true, "requires": { "camelcase": "^4.1.0" @@ -10214,8 +9861,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -10559,8 +10205,7 @@ "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" }, "semver-regex": { "version": "2.0.0", diff --git a/package.json b/package.json index c753d43ed..6beed1ff9 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "file-type": "^7.7.1", "form-data": "^2.3.3", "isstream": "~0.1.2", + "jsonwebtoken": "^8.5.1", "mime-types": "~2.1.18", "object.omit": "~3.0.0", "object.pick": "~1.3.0", diff --git a/tsconfig.json b/tsconfig.json index 940728210..0881180bb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -58,6 +58,7 @@ "include": [ "./lib/*.ts", "./iam-token-manager/*.ts", + "./auth/*.ts", "index.ts" ] } From cfa3e1be6bf08b3d8492eab25ccc7496a5f2d79f Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Tue, 28 May 2019 11:25:45 -0500 Subject: [PATCH 02/18] feat: add `IcpTokenManagerV1` as a top-level export of the package Also, make `authentication_type` non-case-sensitive --- README.md | 3 +++ index.ts | 1 + lib/base_service.ts | 10 +++++++++ test/unit/iamTokenManager.test.js | 37 ++++++++++++++----------------- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 799d7f0ac..cf0597067 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,9 @@ This Class is the base class that all generated service-specific classes inherit ### IamTokenManagerV1 This Class contains logic for managing an IAM token over its lifetime. Tokens can be requested or set manually. When requested, the token manager will either return the current token, request a new token or refresh the current token if it is expired. If a token is manually set, it must be managed by the user. +### IcpTokenManagerV1 +This Class is similar in function to IamTokenManagerV1. The only difference is that the `url` parameter is required, it takes a `username` and `password` instead of an API key, and manages tokens for instances of ICP4D. To use this token manager in an SDK, the parameter `authentication_type` must be set to `icp4d` in the constructor. + ### isFileParam This function takes an Object and returns `true` if the object is a Stream, a Buffer, has a `value` property, or has a `data` property that is a file param (checked recursively). diff --git a/index.ts b/index.ts index eb46c3d21..6c46f3450 100644 --- a/index.ts +++ b/index.ts @@ -20,6 +20,7 @@ export { BaseService } from './lib/base_service'; export { IamTokenManagerV1 } from './iam-token-manager/v1'; +export { IcpTokenManagerV1 } from './auth/icp-token-manager'; export * from './lib/helper'; export { default as qs } from './lib/querystring'; export { default as contentType } from './lib/content-type'; diff --git a/lib/base_service.ts b/lib/base_service.ts index d206fec1a..e5d33c08f 100644 --- a/lib/base_service.ts +++ b/lib/base_service.ts @@ -62,6 +62,7 @@ export interface Credentials { icp_access_token?: string; iam_apikey?: string; iam_url?: string; + authentication_type?: string; } function hasCredentials(obj: any): boolean { @@ -171,6 +172,12 @@ export class BaseService { options, _options ); + + // make authentication_type non-case-sensitive + if (typeof _options.authentication_type === 'string') { + _options.authentication_type = _options.authentication_type.toLowerCase(); + } + if (_options.authentication_type === 'iam' || hasIamCredentials(_options)) { this.tokenManager = new IamTokenManagerV1({ iamApikey: _options.iam_apikey || _options.password, @@ -231,6 +238,9 @@ export class BaseService { if (this._options.icp_access_token) { credentials.icp_access_token = this._options.icp_access_token; } + if (this._options.authentication_type) { + credentials.authentication_type = this._options.authentication_type; + } return credentials; } diff --git a/test/unit/iamTokenManager.test.js b/test/unit/iamTokenManager.test.js index a122a18e3..210bad25e 100644 --- a/test/unit/iamTokenManager.test.js +++ b/test/unit/iamTokenManager.test.js @@ -4,6 +4,11 @@ const requestWrapper = require('../../lib/requestwrapper'); requestWrapper.sendRequest = jest.fn(); +const jwt = require('jsonwebtoken'); +jwt.decode = jest.fn(() => { + return { exp: 100, iat: 100 }; +}); + const IamTokenManagerV1 = require('../../iam-token-manager/v1').IamTokenManagerV1; const CLIENT_ID_SECRET_WARNING = @@ -22,19 +27,16 @@ describe('iam_token_manager_v1', function() { const userManagedToken = 'abcd-1234'; const instance = new IamTokenManagerV1({ iamAccessToken: userManagedToken }); const requestMock = jest.spyOn(instance, 'requestToken'); - const refreshMock = jest.spyOn(instance, 'refreshToken'); instance.getToken(function(err, token) { expect(token).toBe(userManagedToken); expect(requestMock).not.toHaveBeenCalled(); - expect(refreshMock).not.toHaveBeenCalled(); done(); }); }); it('should turn an iam apikey into an access token', function(done) { const instance = new IamTokenManagerV1({ iamApikey: 'abcd-1234' }); - const refreshMock = jest.spyOn(instance, 'refreshToken'); const accessToken = '9012'; const iamResponse = { @@ -51,7 +53,6 @@ describe('iam_token_manager_v1', function() { instance.getToken(function(err, token) { expect(token).toBe(accessToken); - expect(refreshMock).not.toHaveBeenCalled(); done(); }); }); @@ -85,7 +86,7 @@ describe('iam_token_manager_v1', function() { instance.getToken(function(err, token) { expect(token).toBe(accessToken); - expect(requestMock).not.toHaveBeenCalled(); + expect(requestMock).toHaveBeenCalled(); done(); }); }); @@ -93,7 +94,6 @@ describe('iam_token_manager_v1', function() { it('should use a valid access token if one is stored', function(done) { const instance = new IamTokenManagerV1({ iamApikey: 'abcd-1234' }); const requestMock = jest.spyOn(instance, 'requestToken'); - const refreshMock = jest.spyOn(instance, 'refreshToken'); const accessToken = '1234'; const currentTokenInfo = { @@ -105,10 +105,11 @@ describe('iam_token_manager_v1', function() { }; instance.tokenInfo = currentTokenInfo; + instance.timeToLive = currentTokenInfo.expires_in; + instance.expireTime = currentTokenInfo.expiration; instance.getToken(function(err, token) { expect(token).toBe(accessToken); - expect(refreshMock).not.toHaveBeenCalled(); expect(requestMock).not.toHaveBeenCalled(); done(); }); @@ -117,7 +118,6 @@ describe('iam_token_manager_v1', function() { it('should return a user-managed access token if one is set post-construction', function(done) { const instance = new IamTokenManagerV1({ iamApikey: 'abcd-1234' }); const requestMock = jest.spyOn(instance, 'requestToken'); - const refreshMock = jest.spyOn(instance, 'refreshToken'); const accessToken = '9012'; const currentTokenInfo = { @@ -133,7 +133,6 @@ describe('iam_token_manager_v1', function() { instance.getToken(function(err, token) { expect(token).toBe(accessToken); - expect(refreshMock).not.toHaveBeenCalled(); expect(requestMock).not.toHaveBeenCalled(); done(); }); @@ -167,14 +166,13 @@ describe('iam_token_manager_v1', function() { instance.getToken(function(err, token) { expect(token).toBe(accessToken); - expect(requestMock).not.toHaveBeenCalled(); + expect(requestMock).toHaveBeenCalled(); done(); }); }); it('should request a new token when refresh token does not have expiration field', function(done) { const instance = new IamTokenManagerV1({ iamApikey: 'abcd-1234' }); - const refreshMock = jest.spyOn(instance, 'refreshToken'); const currentTokenInfo = { access_token: '1234', @@ -199,7 +197,6 @@ describe('iam_token_manager_v1', function() { instance.getToken(function(err, token) { expect(token).toBe(accessToken); - expect(refreshMock).not.toHaveBeenCalled(); done(); }); }); @@ -208,7 +205,7 @@ describe('iam_token_manager_v1', function() { const instance = new IamTokenManagerV1({ iamApikey: 'abcd-1234' }); requestWrapper.sendRequest.mockImplementation((parameters, _callback) => { - _callback(); + _callback(null, { access_token: 'abcd' }); }); instance.getToken(function() { @@ -227,7 +224,7 @@ describe('iam_token_manager_v1', function() { }); requestWrapper.sendRequest.mockImplementation((parameters, _callback) => { - _callback(); + _callback(null, { access_token: 'abcd' }); }); instance.getToken(function() { @@ -252,7 +249,7 @@ describe('iam_token_manager_v1', function() { console.log.mockRestore(); requestWrapper.sendRequest.mockImplementation((parameters, _callback) => { - _callback(); + _callback(null, { access_token: 'abcd' }); }); instance.getToken(function() { @@ -276,7 +273,7 @@ describe('iam_token_manager_v1', function() { console.log.mockRestore(); requestWrapper.sendRequest.mockImplementation((parameters, _callback) => { - _callback(); + _callback(null, { access_token: 'abcd' }); }); instance.getToken(function() { @@ -295,7 +292,7 @@ describe('iam_token_manager_v1', function() { instance.setIamAuthorizationInfo('foo', 'bar'); requestWrapper.sendRequest.mockImplementation((parameters, _callback) => { - _callback(); + _callback(null, { access_token: 'abcd' }); }); instance.getToken(function() { @@ -321,7 +318,7 @@ describe('iam_token_manager_v1', function() { console.log.mockRestore(); requestWrapper.sendRequest.mockImplementation((parameters, _callback) => { - _callback(); + _callback(null, { access_token: 'abcd' }); }); instance.getToken(function() { @@ -347,7 +344,7 @@ describe('iam_token_manager_v1', function() { console.log.mockRestore(); requestWrapper.sendRequest.mockImplementation((parameters, _callback) => { - _callback(); + _callback(null, { access_token: 'abcd' }); }); instance.getToken(function() { @@ -366,7 +363,7 @@ describe('iam_token_manager_v1', function() { instance.setIamAuthorizationInfo(null, null); requestWrapper.sendRequest.mockImplementation((parameters, _callback) => { - _callback(); + _callback(null, { access_token: 'abcd' }); }); instance.getToken(function() { From de711e797e8182db806ff9dcf4995d51a47475da Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Tue, 28 May 2019 11:50:00 -0500 Subject: [PATCH 03/18] docs: add some documentation on `authentication_type` in the README --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index cf0597067..e00e5ec90 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,19 @@ import { BaseService } from 'ibm-cloud-sdk-core'; class YourSDK extends BaseService { ... } ``` +## Authentication Types +There are several flavors of authentication supported in this package. To specify the intended authentication pattern to use, the user can pass in the parameter `authentication_type`. This parameter is optional, but it may become required in a future major release. The options for this parameter are `basic`, `iam`, and `icp4d`. + +### basic +This indicates Basic Auth is to be used. Users will pass in a `username` and `password` and the SDK will generate a Basic Auth header to send with requests to the service. + +### iam +This indicates that IAM token authentication is to be used. Users can pass in an `iam_apikey` or an `iam_access_token`. If an API key is used, the SDK will manage the token for the user. In either case, the SDK will generate a Bearer Auth header to send with requests to the service. + +### icp4d +This indicates that the service is an instance of ICP4D, which has its own version of token authentication. Users can pass in a `username` and `password`, or an `icp_access_token`. If a username and password is given, the SDK will manage the token for the user. +A `url` is **required** for this type. In order to use ICP4D authentication, this option **must** be passed in. + ## Available Modules ### BaseService This Class is the base class that all generated service-specific classes inherit from. It implements credentials handling and other shared behavior. From bd902ebd8d14e63ae74a4e71046d2edfb7441d45 Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Tue, 28 May 2019 15:05:54 -0500 Subject: [PATCH 04/18] chore: address pr comments --- README.md | 2 +- auth/icp-token-manager.ts | 24 ++++++++++++++++-------- auth/jwt-token-manager.ts | 9 +++++---- iam-token-manager/v1.ts | 13 ++++++++++--- index.ts | 2 +- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index e00e5ec90..e2706b5b8 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ This Class is the base class that all generated service-specific classes inherit ### IamTokenManagerV1 This Class contains logic for managing an IAM token over its lifetime. Tokens can be requested or set manually. When requested, the token manager will either return the current token, request a new token or refresh the current token if it is expired. If a token is manually set, it must be managed by the user. -### IcpTokenManagerV1 +### Icp4dTokenManagerV1 This Class is similar in function to IamTokenManagerV1. The only difference is that the `url` parameter is required, it takes a `username` and `password` instead of an API key, and manages tokens for instances of ICP4D. To use this token manager in an SDK, the parameter `authentication_type` must be set to `icp4d` in the constructor. ### isFileParam diff --git a/auth/icp-token-manager.ts b/auth/icp-token-manager.ts index 6d187e587..ce2584a6f 100644 --- a/auth/icp-token-manager.ts +++ b/auth/icp-token-manager.ts @@ -26,7 +26,7 @@ export type Options = { } // this interface is a representation of the response -// object from the ICP service +// object from the ICP4D authentication service export interface IcpTokenData { username: string; role: string; @@ -40,7 +40,7 @@ export interface IcpTokenData { accessToken: string; } -export class IcpTokenManagerV1 extends JwtTokenManager { +export class Icp4dTokenManagerV1 extends JwtTokenManager { private username: string; private password: string; @@ -50,9 +50,10 @@ export class IcpTokenManagerV1 extends JwtTokenManager { * Retreives, stores, and refreshes ICP tokens. * * @param {Object} options - * @param {String} options.icpApikey - * @param {String} options.icpAccessToken - * @param {String} options.url - url of the icp api to retrieve tokens from + * @param {String} options.username + * @param {String} options.password + * @param {String} options.accessToken - user-managed access token + * @param {String} options.url - URL for the ICP4D cluster * @constructor */ constructor(options: Options) { @@ -75,13 +76,20 @@ export class IcpTokenManagerV1 extends JwtTokenManager { // username and password are required too, unless there's access token } + /** + * Callback for handling response. + * + * @callback requestTokenCallback + * @param {Error} An error if there is one, null otherwise + * @param {Object} The response if request is successful, null otherwise + */ /** * Request an ICP token using a basic auth header. * - * @param {Function} cb - The callback that handles the response. + * @param {requestTokenCallback} callback - The callback that handles the response. * @returns {void} */ - protected requestToken(cb: Function): void { + protected requestToken(callback: Function): void { const parameters = { options: { url: this.url, @@ -92,6 +100,6 @@ export class IcpTokenManagerV1 extends JwtTokenManager { }, } }; - sendRequest(parameters, cb); + sendRequest(parameters, callback); } } diff --git a/auth/jwt-token-manager.ts b/auth/jwt-token-manager.ts index 864aa380e..ca50d35e9 100644 --- a/auth/jwt-token-manager.ts +++ b/auth/jwt-token-manager.ts @@ -1,5 +1,5 @@ /** - * Copyright 2015 IBM Corp. All Rights Reserved. + * Copyright 2019 IBM Corp. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -107,7 +107,8 @@ export class JwtTokenManager { * @returns {void} */ protected requestToken(cb: Function): void { - cb(null, 'token'); + const err = new Error('`requestToken` MUST be overridden by a subclass of JwtTokenManager.'); + cb(err, null); } /** @@ -142,8 +143,8 @@ export class JwtTokenManager { const fractionOfTtl = 0.8; const currentTime = getCurrentTime(); - const refreshTime = expireTime - (timeToLive * (1.0 - fractionOfTtl)); - return refreshTime < currentTime; + const timeForNewToken = expireTime - (timeToLive * (1.0 - fractionOfTtl)); + return timeForNewToken < currentTime; } /** diff --git a/iam-token-manager/v1.ts b/iam-token-manager/v1.ts index 92ec54d9b..74ce80d28 100644 --- a/iam-token-manager/v1.ts +++ b/iam-token-manager/v1.ts @@ -114,13 +114,20 @@ export class IamTokenManagerV1 extends JwtTokenManager { } } + /** + * Callback for handling response. + * + * @callback requestTokenCallback + * @param {Error} An error if there is one, null otherwise + * @param {Object} The response if request is successful, null otherwise + */ /** * Request an IAM token using an API key. * - * @param {Function} cb - The callback that handles the response. + * @param {requestTokenCallback} callback - The callback that handles the response. * @returns {void} */ - protected requestToken(cb: Function): void { + protected requestToken(callback: Function): void { // Use bx:bx as default auth header creds. let clientId = 'bx'; let clientSecret = 'bx'; @@ -147,6 +154,6 @@ export class IamTokenManagerV1 extends JwtTokenManager { } } }; - sendRequest(parameters, cb); + sendRequest(parameters, callback); } } diff --git a/index.ts b/index.ts index 6c46f3450..47e06322c 100644 --- a/index.ts +++ b/index.ts @@ -20,7 +20,7 @@ export { BaseService } from './lib/base_service'; export { IamTokenManagerV1 } from './iam-token-manager/v1'; -export { IcpTokenManagerV1 } from './auth/icp-token-manager'; +export { Icp4dTokenManagerV1 } from './auth/icp-token-manager'; export * from './lib/helper'; export { default as qs } from './lib/querystring'; export { default as contentType } from './lib/content-type'; From 4f2f78910ea632ab70d82072187188a1d908bd7f Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Tue, 28 May 2019 15:27:23 -0500 Subject: [PATCH 05/18] feat: carry `disable_ssl_verification` through to token managers --- auth/icp-token-manager.ts | 3 +++ auth/jwt-token-manager.ts | 8 +++++++- iam-token-manager/v1.ts | 5 ++++- lib/base_service.ts | 28 +++++++++++++++++----------- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/auth/icp-token-manager.ts b/auth/icp-token-manager.ts index ce2584a6f..004d41a33 100644 --- a/auth/icp-token-manager.ts +++ b/auth/icp-token-manager.ts @@ -23,6 +23,7 @@ export type Options = { accessToken?: string; username?: string; password?: string; + disableSslVerification?: boolean; } // this interface is a representation of the response @@ -54,6 +55,7 @@ export class Icp4dTokenManagerV1 extends JwtTokenManager { * @param {String} options.password * @param {String} options.accessToken - user-managed access token * @param {String} options.url - URL for the ICP4D cluster + * @param {Boolean} options.disableSslVerification - disable SSL verification for token request * @constructor */ constructor(options: Options) { @@ -98,6 +100,7 @@ export class Icp4dTokenManagerV1 extends JwtTokenManager { Authorization: this.computeBasicAuthHeader(this.username, this.password), }, + rejectUnauthorized: this.rejectUnauthorized, } }; sendRequest(parameters, callback); diff --git a/auth/jwt-token-manager.ts b/auth/jwt-token-manager.ts index ca50d35e9..f0db87cf3 100644 --- a/auth/jwt-token-manager.ts +++ b/auth/jwt-token-manager.ts @@ -25,12 +25,14 @@ function getCurrentTime(): number { export type Options = { accessToken?: string; url?: string; + disableSslVerification?: boolean; } export class JwtTokenManager { protected url: string; protected tokenName: string; protected userAccessToken: string; + protected rejectUnauthorized: boolean; private tokenInfo: any; private timeToLive: number; private expireTime: number; @@ -42,7 +44,8 @@ export class JwtTokenManager { * * @param {Object} options * @param {String} options.url - url of the api to retrieve tokens from - * @param {String} options.accessToken + * @param {String} [options.accessToken] - user-managed access token + * @param {String} [options.disableSslVerification] - pass in to disable SSL verification on requests. defaults to false * @constructor */ constructor(options: Options) { @@ -53,9 +56,12 @@ export class JwtTokenManager { if (options.url) { this.url = options.url; } + if (options.accessToken) { this.userAccessToken = options.accessToken; } + + this.rejectUnauthorized = !options.disableSslVerification; } /** diff --git a/iam-token-manager/v1.ts b/iam-token-manager/v1.ts index 74ce80d28..1f4c20422 100644 --- a/iam-token-manager/v1.ts +++ b/iam-token-manager/v1.ts @@ -42,6 +42,7 @@ export type Options = { iamAccessToken?: string; iamClientId?: string; iamClientSecret?: string; + disableSslVerification?: boolean; } // this interface is a representation of the response @@ -69,6 +70,7 @@ export class IamTokenManagerV1 extends JwtTokenManager { * @param {String} options.iamApikey * @param {String} options.iamAccessToken * @param {String} options.iamUrl - url of the iam api to retrieve tokens from + * @param {Boolean} options.disableSslVerification - disable SSL verification for token request * @constructor */ constructor(options: Options) { @@ -151,7 +153,8 @@ export class IamTokenManagerV1 extends JwtTokenManager { grant_type: 'urn:ibm:params:oauth:grant-type:apikey', apikey: this.iamApikey, response_type: 'cloud_iam' - } + }, + rejectUnauthorized: this.rejectUnauthorized, } }; sendRequest(parameters, callback); diff --git a/lib/base_service.ts b/lib/base_service.ts index e5d33c08f..c5d1c6041 100644 --- a/lib/base_service.ts +++ b/lib/base_service.ts @@ -16,7 +16,7 @@ import extend = require('extend'); import vcapServices = require('vcap_services'); -import { IcpTokenManagerV1 } from '../auth/icp-token-manager'; +import { Icp4dTokenManagerV1 } from '../auth/icp-token-manager'; import { IamTokenManagerV1 } from '../iam-token-manager/v1'; import { stripTrailingSlash } from './helper'; import { readCredentialsFile } from './read-credentials-file'; @@ -178,34 +178,38 @@ export class BaseService { _options.authentication_type = _options.authentication_type.toLowerCase(); } + // rejectUnauthorized should only be false if disable_ssl_verification is true + // used to disable ssl checking for icp + this._options.rejectUnauthorized = !options.disable_ssl_verification; + if (_options.authentication_type === 'iam' || hasIamCredentials(_options)) { this.tokenManager = new IamTokenManagerV1({ iamApikey: _options.iam_apikey || _options.password, accessToken: _options.iam_access_token, url: _options.iam_url, iamClientId: _options.iam_client_id, - iamClientSecret: _options.iam_client_secret + iamClientSecret: _options.iam_client_secret, + disableSslVerification: options.disable_ssl_verification, }); } else if (usesBasicForIam(_options)) { this.tokenManager = new IamTokenManagerV1({ iamApikey: _options.password, url: _options.iam_url, iamClientId: _options.iam_client_id, - iamClientSecret: _options.iam_client_secret + iamClientSecret: _options.iam_client_secret, + disableSslVerification: options.disable_ssl_verification, }); } else if (isForICP4D(_options)) { - this.tokenManager = new IcpTokenManagerV1({ + this.tokenManager = new Icp4dTokenManagerV1({ url: _options.url, username: _options.username, password: _options.password, - accessToken: _options.icp_access_token + accessToken: _options.icp_access_token, + disableSslVerification: options.disable_ssl_verification, }); } else { this.tokenManager = null; } - // rejectUnauthorized should only be false if disable_ssl_verification is true - // used to disable ssl checking for icp - this._options.rejectUnauthorized = !options.disable_ssl_verification; } /** @@ -260,13 +264,15 @@ export class BaseService { if (this.tokenManager) { this.tokenManager.setAccessToken(access_token); } else if (this._options.authentication_type === 'icp4d') { - this.tokenManager = new IcpTokenManagerV1({ + this.tokenManager = new Icp4dTokenManagerV1({ accessToken: access_token, - url: this._options.url + url: this._options.url, + disableSslVerification: this._options.disable_ssl_verification, }); } else { this.tokenManager = new IamTokenManagerV1({ - accessToken: access_token + accessToken: access_token, + disableSslVerification: this._options.disable_ssl_verification, }); } } From 70cfc2328bf19d2a6cfc2c3e678178a3f38e23ac Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Wed, 29 May 2019 17:26:10 -0500 Subject: [PATCH 06/18] refactor: re-organize auth folder in sdk --- auth/iam-token-manager-v1.ts | 162 ++++++++++++++++++ ...ken-manager.ts => icp-token-manager-v1.ts} | 2 +- ...ken-manager.ts => jwt-token-manager-v1.ts} | 0 iam-token-manager/v1.ts | 146 +--------------- index.ts | 4 +- lib/base_service.ts | 4 +- test/unit/baseService.test.js | 4 +- 7 files changed, 173 insertions(+), 149 deletions(-) create mode 100644 auth/iam-token-manager-v1.ts rename auth/{icp-token-manager.ts => icp-token-manager-v1.ts} (98%) rename auth/{jwt-token-manager.ts => jwt-token-manager-v1.ts} (100%) diff --git a/auth/iam-token-manager-v1.ts b/auth/iam-token-manager-v1.ts new file mode 100644 index 000000000..26f3e5d92 --- /dev/null +++ b/auth/iam-token-manager-v1.ts @@ -0,0 +1,162 @@ +/** + * Copyright 2015 IBM Corp. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import extend = require('extend'); +import { JwtTokenManager } from '../auth/jwt-token-manager-v1'; +import { sendRequest } from '../lib/requestwrapper'; + +/** + * Check for only one of two elements being defined. + * Returns true if a is defined and b is undefined, + * or vice versa. Returns false if both are defined + * or both are undefined. + * + * @param {any} a - The first object + * @param {any} b - The second object + * @returns {boolean} + */ +function onlyOne(a: any, b: any): boolean { + return Boolean((a && !b) || (b && !a)); +} + +const CLIENT_ID_SECRET_WARNING = 'Warning: Client ID and Secret must BOTH be given, or the defaults will be used.'; + +export type Options = { + url?: string; + iamUrl?: string; + iamApikey?: string; + accessToken?: string; + iamAccessToken?: string; + iamClientId?: string; + iamClientSecret?: string; + disableSslVerification?: boolean; +} + +// this interface is a representation of the response +// object from the IAM service, hence the snake_case +// parameter names +export interface IamTokenData { + access_token: string; + refresh_token: string; + token_type: string; + expires_in: number; + expiration: number; +} + +export class IamTokenManagerV1 extends JwtTokenManager { + private iamApikey: string; + private iamClientId: string; + private iamClientSecret: string; + + /** + * IAM Token Manager Service + * + * Retreives, stores, and refreshes IAM tokens. + * + * @param {Object} options + * @param {String} options.iamApikey + * @param {String} options.iamAccessToken + * @param {String} options.iamUrl - url of the iam api to retrieve tokens from + * @param {Boolean} options.disableSslVerification - disable SSL verification for token request + * @constructor + */ + constructor(options: Options) { + super(options); + + this.url = this.url || options.iamUrl || 'https://iam.cloud.ibm.com/identity/token'; + + if (options.iamApikey) { + this.iamApikey = options.iamApikey; + } + if (options.iamAccessToken) { + this.userAccessToken = options.iamAccessToken; + } + if (options.iamClientId) { + this.iamClientId = options.iamClientId; + } + if (options.iamClientSecret) { + this.iamClientSecret = options.iamClientSecret; + } + if (onlyOne(options.iamClientId, options.iamClientSecret)) { + // tslint:disable-next-line + console.log(CLIENT_ID_SECRET_WARNING); + } + } + + /** + * Set the IAM 'client_id' and 'client_secret' values. + * These values are used to compute the Authorization header used + * when retrieving or refreshing the IAM access token. + * If these values are not set, then a default Authorization header + * will be used when interacting with the IAM token server. + * + * @param {string} iamClientId - The client id + * @param {string} iamClientSecret - The client secret + * @returns {void} + */ + public setIamAuthorizationInfo(iamClientId: string, iamClientSecret: string): void { + this.iamClientId = iamClientId; + this.iamClientSecret = iamClientSecret; + if (onlyOne(iamClientId, iamClientSecret)) { + // tslint:disable-next-line + console.log(CLIENT_ID_SECRET_WARNING); + } + } + + /** + * Callback for handling response. + * + * @callback requestTokenCallback + * @param {Error} An error if there is one, null otherwise + * @param {Object} The response if request is successful, null otherwise + */ + /** + * Request an IAM token using an API key. + * + * @param {requestTokenCallback} callback - The callback that handles the response. + * @returns {void} + */ + protected requestToken(callback: Function): void { + // Use bx:bx as default auth header creds. + let clientId = 'bx'; + let clientSecret = 'bx'; + + // If both the clientId and secret were specified by the user, then use them. + if (this.iamClientId && this.iamClientSecret) { + clientId = this.iamClientId; + clientSecret = this.iamClientSecret; + } + + const parameters = { + options: { + url: this.url, + method: 'POST', + headers: { + 'Content-type': 'application/x-www-form-urlencoded', + Authorization: + this.computeBasicAuthHeader(clientId, clientSecret), + }, + form: { + grant_type: 'urn:ibm:params:oauth:grant-type:apikey', + apikey: this.iamApikey, + response_type: 'cloud_iam' + }, + rejectUnauthorized: this.rejectUnauthorized, + } + }; + sendRequest(parameters, callback); + } +} diff --git a/auth/icp-token-manager.ts b/auth/icp-token-manager-v1.ts similarity index 98% rename from auth/icp-token-manager.ts rename to auth/icp-token-manager-v1.ts index 004d41a33..c1f93b072 100644 --- a/auth/icp-token-manager.ts +++ b/auth/icp-token-manager-v1.ts @@ -16,7 +16,7 @@ import extend = require('extend'); import { sendRequest } from '../lib/requestwrapper'; -import { JwtTokenManager } from './jwt-token-manager'; +import { JwtTokenManager } from './jwt-token-manager-v1'; export type Options = { url: string; diff --git a/auth/jwt-token-manager.ts b/auth/jwt-token-manager-v1.ts similarity index 100% rename from auth/jwt-token-manager.ts rename to auth/jwt-token-manager-v1.ts diff --git a/iam-token-manager/v1.ts b/iam-token-manager/v1.ts index 1f4c20422..953eaf14d 100644 --- a/iam-token-manager/v1.ts +++ b/iam-token-manager/v1.ts @@ -14,149 +14,11 @@ * limitations under the License. */ -import extend = require('extend'); -import { JwtTokenManager } from '../auth/jwt-token-manager'; -import { sendRequest } from '../lib/requestwrapper'; - /** - * Check for only one of two elements being defined. - * Returns true if a is defined and b is undefined, - * or vice versa. Returns false if both are defined - * or both are undefined. - * - * @param {any} a - The first object - * @param {any} b - The second object - * @returns {boolean} + * @module iam-token-manager-v1 */ -function onlyOne(a: any, b: any): boolean { - return Boolean((a && !b) || (b && !a)); -} - -const CLIENT_ID_SECRET_WARNING = 'Warning: Client ID and Secret must BOTH be given, or the defaults will be used.'; - -export type Options = { - url?: string; - iamUrl?: string; - iamApikey?: string; - accessToken?: string; - iamAccessToken?: string; - iamClientId?: string; - iamClientSecret?: string; - disableSslVerification?: boolean; -} - -// this interface is a representation of the response -// object from the IAM service, hence the snake_case -// parameter names -export interface IamTokenData { - access_token: string; - refresh_token: string; - token_type: string; - expires_in: number; - expiration: number; -} - -export class IamTokenManagerV1 extends JwtTokenManager { - private iamApikey: string; - private iamClientId: string; - private iamClientSecret: string; - - /** - * IAM Token Manager Service - * - * Retreives, stores, and refreshes IAM tokens. - * - * @param {Object} options - * @param {String} options.iamApikey - * @param {String} options.iamAccessToken - * @param {String} options.iamUrl - url of the iam api to retrieve tokens from - * @param {Boolean} options.disableSslVerification - disable SSL verification for token request - * @constructor - */ - constructor(options: Options) { - super(options); - - this.url = this.url || options.iamUrl || 'https://iam.cloud.ibm.com/identity/token'; - - if (options.iamApikey) { - this.iamApikey = options.iamApikey; - } - if (options.iamAccessToken) { - this.userAccessToken = options.iamAccessToken; - } - if (options.iamClientId) { - this.iamClientId = options.iamClientId; - } - if (options.iamClientSecret) { - this.iamClientSecret = options.iamClientSecret; - } - if (onlyOne(options.iamClientId, options.iamClientSecret)) { - // tslint:disable-next-line - console.log(CLIENT_ID_SECRET_WARNING); - } - } - - /** - * Set the IAM 'client_id' and 'client_secret' values. - * These values are used to compute the Authorization header used - * when retrieving or refreshing the IAM access token. - * If these values are not set, then a default Authorization header - * will be used when interacting with the IAM token server. - * - * @param {string} iamClientId - The client id - * @param {string} iamClientSecret - The client secret - * @returns {void} - */ - public setIamAuthorizationInfo(iamClientId: string, iamClientSecret: string): void { - this.iamClientId = iamClientId; - this.iamClientSecret = iamClientSecret; - if (onlyOne(iamClientId, iamClientSecret)) { - // tslint:disable-next-line - console.log(CLIENT_ID_SECRET_WARNING); - } - } - - /** - * Callback for handling response. - * - * @callback requestTokenCallback - * @param {Error} An error if there is one, null otherwise - * @param {Object} The response if request is successful, null otherwise - */ - /** - * Request an IAM token using an API key. - * - * @param {requestTokenCallback} callback - The callback that handles the response. - * @returns {void} - */ - protected requestToken(callback: Function): void { - // Use bx:bx as default auth header creds. - let clientId = 'bx'; - let clientSecret = 'bx'; - // If both the clientId and secret were specified by the user, then use them. - if (this.iamClientId && this.iamClientSecret) { - clientId = this.iamClientId; - clientSecret = this.iamClientSecret; - } +// Exporting the module here for compatibility. To be removed in major release. - const parameters = { - options: { - url: this.url, - method: 'POST', - headers: { - 'Content-type': 'application/x-www-form-urlencoded', - Authorization: - this.computeBasicAuthHeader(clientId, clientSecret), - }, - form: { - grant_type: 'urn:ibm:params:oauth:grant-type:apikey', - apikey: this.iamApikey, - response_type: 'cloud_iam' - }, - rejectUnauthorized: this.rejectUnauthorized, - } - }; - sendRequest(parameters, callback); - } -} +import { IamTokenManagerV1 } from '../auth/iam-token-manager-v1'; +export { IamTokenManagerV1 }; diff --git a/index.ts b/index.ts index 47e06322c..572d27de1 100644 --- a/index.ts +++ b/index.ts @@ -19,8 +19,8 @@ */ export { BaseService } from './lib/base_service'; -export { IamTokenManagerV1 } from './iam-token-manager/v1'; -export { Icp4dTokenManagerV1 } from './auth/icp-token-manager'; +export { IamTokenManagerV1 } from './auth/iam-token-manager-v1'; +export { Icp4dTokenManagerV1 } from './auth/icp-token-manager-v1'; export * from './lib/helper'; export { default as qs } from './lib/querystring'; export { default as contentType } from './lib/content-type'; diff --git a/lib/base_service.ts b/lib/base_service.ts index c5d1c6041..f84aafc15 100644 --- a/lib/base_service.ts +++ b/lib/base_service.ts @@ -16,8 +16,8 @@ import extend = require('extend'); import vcapServices = require('vcap_services'); -import { Icp4dTokenManagerV1 } from '../auth/icp-token-manager'; -import { IamTokenManagerV1 } from '../iam-token-manager/v1'; +import { IamTokenManagerV1 } from '../auth/iam-token-manager-v1'; +import { Icp4dTokenManagerV1 } from '../auth/icp-token-manager-v1'; import { stripTrailingSlash } from './helper'; import { readCredentialsFile } from './read-credentials-file'; import { sendRequest } from './requestwrapper'; diff --git a/test/unit/baseService.test.js b/test/unit/baseService.test.js index 250fb901e..1cb8f6c1b 100644 --- a/test/unit/baseService.test.js +++ b/test/unit/baseService.test.js @@ -298,7 +298,7 @@ describe('BaseService', function() { expect(instance.tokenManager).not.toBeNull(); expect(instance.tokenManager.iamApikey).toBeDefined(); expect(instance.tokenManager.userAccessToken).toBeDefined(); - expect(instance.tokenManager.iamUrl).toBeDefined(); + expect(instance.tokenManager.url).toBeDefined(); expect(instance.tokenManager.iamClientId).toBeDefined(); expect(instance.tokenManager.iamClientSecret).toBeDefined(); }); @@ -315,7 +315,7 @@ describe('BaseService', function() { expect(instance.tokenManager).toBeDefined(); expect(instance.tokenManager).not.toBeNull(); expect(instance.tokenManager.iamApikey).toBeDefined(); - expect(instance.tokenManager.iamUrl).toBeDefined(); + expect(instance.tokenManager.url).toBeDefined(); expect(instance.tokenManager.iamClientId).toBeDefined(); expect(instance.tokenManager.iamClientSecret).toBeDefined(); }); From d91cd064c5830d4c2a34af5463b25b9668b05673 Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Wed, 29 May 2019 17:35:53 -0500 Subject: [PATCH 07/18] refactor: remove disable_ssl_verification support in iam --- auth/iam-token-manager-v1.ts | 3 --- auth/icp-token-manager-v1.ts | 1 + auth/jwt-token-manager-v1.ts | 4 ---- lib/base_service.ts | 3 --- 4 files changed, 1 insertion(+), 10 deletions(-) diff --git a/auth/iam-token-manager-v1.ts b/auth/iam-token-manager-v1.ts index 26f3e5d92..0f7250578 100644 --- a/auth/iam-token-manager-v1.ts +++ b/auth/iam-token-manager-v1.ts @@ -42,7 +42,6 @@ export type Options = { iamAccessToken?: string; iamClientId?: string; iamClientSecret?: string; - disableSslVerification?: boolean; } // this interface is a representation of the response @@ -70,7 +69,6 @@ export class IamTokenManagerV1 extends JwtTokenManager { * @param {String} options.iamApikey * @param {String} options.iamAccessToken * @param {String} options.iamUrl - url of the iam api to retrieve tokens from - * @param {Boolean} options.disableSslVerification - disable SSL verification for token request * @constructor */ constructor(options: Options) { @@ -154,7 +152,6 @@ export class IamTokenManagerV1 extends JwtTokenManager { apikey: this.iamApikey, response_type: 'cloud_iam' }, - rejectUnauthorized: this.rejectUnauthorized, } }; sendRequest(parameters, callback); diff --git a/auth/icp-token-manager-v1.ts b/auth/icp-token-manager-v1.ts index c1f93b072..b90bc9d7b 100644 --- a/auth/icp-token-manager-v1.ts +++ b/auth/icp-token-manager-v1.ts @@ -76,6 +76,7 @@ export class Icp4dTokenManagerV1 extends JwtTokenManager { this.password = options.password; } // username and password are required too, unless there's access token + this.rejectUnauthorized = !options.disableSslVerification; } /** diff --git a/auth/jwt-token-manager-v1.ts b/auth/jwt-token-manager-v1.ts index f0db87cf3..fc7a9797a 100644 --- a/auth/jwt-token-manager-v1.ts +++ b/auth/jwt-token-manager-v1.ts @@ -25,7 +25,6 @@ function getCurrentTime(): number { export type Options = { accessToken?: string; url?: string; - disableSslVerification?: boolean; } export class JwtTokenManager { @@ -45,7 +44,6 @@ export class JwtTokenManager { * @param {Object} options * @param {String} options.url - url of the api to retrieve tokens from * @param {String} [options.accessToken] - user-managed access token - * @param {String} [options.disableSslVerification] - pass in to disable SSL verification on requests. defaults to false * @constructor */ constructor(options: Options) { @@ -60,8 +58,6 @@ export class JwtTokenManager { if (options.accessToken) { this.userAccessToken = options.accessToken; } - - this.rejectUnauthorized = !options.disableSslVerification; } /** diff --git a/lib/base_service.ts b/lib/base_service.ts index f84aafc15..c777741a3 100644 --- a/lib/base_service.ts +++ b/lib/base_service.ts @@ -189,7 +189,6 @@ export class BaseService { url: _options.iam_url, iamClientId: _options.iam_client_id, iamClientSecret: _options.iam_client_secret, - disableSslVerification: options.disable_ssl_verification, }); } else if (usesBasicForIam(_options)) { this.tokenManager = new IamTokenManagerV1({ @@ -197,7 +196,6 @@ export class BaseService { url: _options.iam_url, iamClientId: _options.iam_client_id, iamClientSecret: _options.iam_client_secret, - disableSslVerification: options.disable_ssl_verification, }); } else if (isForICP4D(_options)) { this.tokenManager = new Icp4dTokenManagerV1({ @@ -272,7 +270,6 @@ export class BaseService { } else { this.tokenManager = new IamTokenManagerV1({ accessToken: access_token, - disableSslVerification: this._options.disable_ssl_verification, }); } } From 4ba77ca33fa46d5c1bab4230c15e9dc878fc1e58 Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Thu, 30 May 2019 16:38:35 -0500 Subject: [PATCH 08/18] refactor: refactor the token expiration time calculation also, rename JwtTokenManager to JwtTokenManagerV1 --- auth/iam-token-manager-v1.ts | 4 +- ...anager-v1.ts => icp4d-token-manager-v1.ts} | 8 +- auth/jwt-token-manager-v1.ts | 77 +++++++++++++------ index.ts | 2 +- lib/base_service.ts | 2 +- 5 files changed, 60 insertions(+), 33 deletions(-) rename auth/{icp-token-manager-v1.ts => icp4d-token-manager-v1.ts} (92%) diff --git a/auth/iam-token-manager-v1.ts b/auth/iam-token-manager-v1.ts index 0f7250578..90ea8a512 100644 --- a/auth/iam-token-manager-v1.ts +++ b/auth/iam-token-manager-v1.ts @@ -15,7 +15,7 @@ */ import extend = require('extend'); -import { JwtTokenManager } from '../auth/jwt-token-manager-v1'; +import { JwtTokenManagerV1 } from '../auth/jwt-token-manager-v1'; import { sendRequest } from '../lib/requestwrapper'; /** @@ -55,7 +55,7 @@ export interface IamTokenData { expiration: number; } -export class IamTokenManagerV1 extends JwtTokenManager { +export class IamTokenManagerV1 extends JwtTokenManagerV1 { private iamApikey: string; private iamClientId: string; private iamClientSecret: string; diff --git a/auth/icp-token-manager-v1.ts b/auth/icp4d-token-manager-v1.ts similarity index 92% rename from auth/icp-token-manager-v1.ts rename to auth/icp4d-token-manager-v1.ts index b90bc9d7b..241e389e1 100644 --- a/auth/icp-token-manager-v1.ts +++ b/auth/icp4d-token-manager-v1.ts @@ -16,7 +16,7 @@ import extend = require('extend'); import { sendRequest } from '../lib/requestwrapper'; -import { JwtTokenManager } from './jwt-token-manager-v1'; +import { JwtTokenManagerV1 } from './jwt-token-manager-v1'; export type Options = { url: string; @@ -41,7 +41,7 @@ export interface IcpTokenData { accessToken: string; } -export class Icp4dTokenManagerV1 extends JwtTokenManager { +export class Icp4dTokenManagerV1 extends JwtTokenManagerV1 { private username: string; private password: string; @@ -66,9 +66,9 @@ export class Icp4dTokenManagerV1 extends JwtTokenManager { if (this.url) { this.url = this.url + '/v1/preauth/validateAuth'; } else { - // this is required - console.error('`url` is a required parameter for the ICP token manager.'); + throw new Error('`url` is a required parameter for Icp4dTokenManagerV1'); } + if (options.username) { this.username = options.username; } diff --git a/auth/jwt-token-manager-v1.ts b/auth/jwt-token-manager-v1.ts index fc7a9797a..bcacf20cf 100644 --- a/auth/jwt-token-manager-v1.ts +++ b/auth/jwt-token-manager-v1.ts @@ -27,13 +27,12 @@ export type Options = { url?: string; } -export class JwtTokenManager { +export class JwtTokenManagerV1 { protected url: string; protected tokenName: string; protected userAccessToken: string; - protected rejectUnauthorized: boolean; + protected rejectUnauthorized: boolean; // for icp4d only private tokenInfo: any; - private timeToLive: number; private expireTime: number; /** @@ -47,8 +46,10 @@ export class JwtTokenManager { * @constructor */ constructor(options: Options) { - this.tokenInfo = {}; + // all parameters are optional + options = options || {} as Options; + this.tokenInfo = {}; this.tokenName = 'access_token'; if (options.url) { @@ -77,8 +78,16 @@ export class JwtTokenManager { } else if (!this.tokenInfo[this.tokenName] || this.isTokenExpired()) { // 2. request a new token this.requestToken((err, tokenResponse) => { - this.saveTokenInfo(tokenResponse); - return cb(err, this.tokenInfo[this.tokenName]); + if (!err) { + try { + this.saveTokenInfo(tokenResponse); + } catch(e) { + // send lower level error through callback for user to handle + err = e; + } + } + // return null for access_token if there is an error + return cb(err, this.tokenInfo[this.tokenName] || null); }); } else { // 3. use valid, sdk-managed token @@ -109,7 +118,7 @@ export class JwtTokenManager { * @returns {void} */ protected requestToken(cb: Function): void { - const err = new Error('`requestToken` MUST be overridden by a subclass of JwtTokenManager.'); + const err = new Error('`requestToken` MUST be overridden by a subclass of JwtTokenManagerV1.'); cb(err, null); } @@ -126,31 +135,25 @@ export class JwtTokenManager { } /** - * Check if currently stored token is expired. - * - * Using a buffer to prevent the edge case of the - * token expiring before the request could be made. - * - * The buffer will be a fraction of the total TTL. Using 80%. + * Check if currently stored token is "expired" + * i.e. past the window to request a new token * * @private * @returns {boolean} */ private isTokenExpired(): boolean { - const { timeToLive, expireTime } = this; + const { expireTime } = this; - if (!timeToLive || !expireTime) { + if (!expireTime) { return true; } - const fractionOfTtl = 0.8; const currentTime = getCurrentTime(); - const timeForNewToken = expireTime - (timeToLive * (1.0 - fractionOfTtl)); - return timeForNewToken < currentTime; + return expireTime < currentTime; } /** - * Decode the access token and save the response from the JWT service to the object's state. + * Save the JWT service response and the calculated expiration time to the object's state. * * @param tokenResponse - Response object from JWT service request * @private @@ -159,14 +162,38 @@ export class JwtTokenManager { private saveTokenInfo(tokenResponse): void { const accessToken = tokenResponse[this.tokenName]; - // the time of expiration is found by decoding the JWT access token - const decodedResponse = jwt.decode(accessToken); - const { exp, iat } = decodedResponse; + if (!accessToken) { + throw new Error('Access token not present in response'); + } + this.expireTime = this.calculateTimeForNewToken(accessToken); + this.tokenInfo = extend({}, tokenResponse); + } + + /** + * Decode the access token and calculate the time to request a new token. + * + * A time buffer prevents the edge case of the token expiring before the request could be made. + * The buffer will be a fraction of the total time to live - we are using 80% + * + * @param accessToken - JSON Web Token received from the service + * @private + * @returns {void} + */ + private calculateTimeForNewToken(accessToken): number { + // the time of expiration is found by decoding the JWT access token // exp is the time of expire and iat is the time of token retrieval - this.timeToLive = exp - iat; - this.expireTime = exp; + let timeForNewToken; + const decodedResponse = jwt.decode(accessToken); + if (decodedResponse) { + const { exp, iat } = decodedResponse; + const fractionOfTtl = 0.8; + const timeToLive = exp - iat; + timeForNewToken = exp - (timeToLive * (1.0 - fractionOfTtl)); + } else { + throw new Error('Access token recieved is not a valid JWT'); + } - this.tokenInfo = extend({}, tokenResponse); + return timeForNewToken; } } diff --git a/index.ts b/index.ts index 572d27de1..422f8dcb4 100644 --- a/index.ts +++ b/index.ts @@ -20,7 +20,7 @@ export { BaseService } from './lib/base_service'; export { IamTokenManagerV1 } from './auth/iam-token-manager-v1'; -export { Icp4dTokenManagerV1 } from './auth/icp-token-manager-v1'; +export { Icp4dTokenManagerV1 } from './auth/icp4d-token-manager-v1'; export * from './lib/helper'; export { default as qs } from './lib/querystring'; export { default as contentType } from './lib/content-type'; diff --git a/lib/base_service.ts b/lib/base_service.ts index c777741a3..8bd877de4 100644 --- a/lib/base_service.ts +++ b/lib/base_service.ts @@ -17,7 +17,7 @@ import extend = require('extend'); import vcapServices = require('vcap_services'); import { IamTokenManagerV1 } from '../auth/iam-token-manager-v1'; -import { Icp4dTokenManagerV1 } from '../auth/icp-token-manager-v1'; +import { Icp4dTokenManagerV1 } from '../auth/icp4d-token-manager-v1'; import { stripTrailingSlash } from './helper'; import { readCredentialsFile } from './read-credentials-file'; import { sendRequest } from './requestwrapper'; From 81a5da217c9fe32a0940bd5ceabde12e489530dc Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Thu, 30 May 2019 16:40:56 -0500 Subject: [PATCH 09/18] test: add unit tests for JwtTokenManagerV1 --- test/unit/jwtTokenManager.v1.test.js | 226 +++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 test/unit/jwtTokenManager.v1.test.js diff --git a/test/unit/jwtTokenManager.v1.test.js b/test/unit/jwtTokenManager.v1.test.js new file mode 100644 index 000000000..884c88118 --- /dev/null +++ b/test/unit/jwtTokenManager.v1.test.js @@ -0,0 +1,226 @@ +/* eslint-disable no-alert, no-console */ +'use strict'; + +const { JwtTokenManagerV1 } = require('../../auth/jwt-token-manager-v1'); +const jwt = require('jsonwebtoken'); + +function getCurrentTime() { + return Math.floor(Date.now() / 1000); +} + +const ACCESS_TOKEN = 'abc123'; + +describe('iam_token_manager_v1', () => { + it('should initialize base variables', () => { + const url = 'service.com'; + const instance = new JwtTokenManagerV1({ url, accessToken: ACCESS_TOKEN }); + + expect(instance.url).toBe(url); + expect(instance.userAccessToken).toBe(ACCESS_TOKEN); + expect(instance.tokenName).toBe('access_token'); + expect(instance.tokenInfo).toEqual({}); + }); + + describe('getToken', () => { + it('should return user-managed token if present', done => { + const instance = new JwtTokenManagerV1({ accessToken: ACCESS_TOKEN }); + instance.getToken((err, res) => { + expect(err).toBeNull(); + expect(res).toBe(ACCESS_TOKEN); + done(); + }); + }); + + it('should request a token if no token is stored', done => { + const instance = new JwtTokenManagerV1(); + const saveTokenInfoSpy = jest.spyOn(instance, 'saveTokenInfo'); + + const decodeSpy = jest + .spyOn(jwt, 'decode') + .mockImplementation(token => ({ iat: 0, exp: 100 })); + + const requestTokenSpy = jest + .spyOn(instance, 'requestToken') + .mockImplementation(cb => cb(null, { access_token: ACCESS_TOKEN })); + + instance.getToken((err, res) => { + expect(requestTokenSpy).toHaveBeenCalled(); + expect(saveTokenInfoSpy).toHaveBeenCalled(); + expect(decodeSpy).toHaveBeenCalled(); + expect(err).toBeNull(); + expect(res).toBe(ACCESS_TOKEN); + + saveTokenInfoSpy.mockRestore(); + decodeSpy.mockRestore(); + requestTokenSpy.mockRestore(); + done(); + }); + }); + + it('should request a token if token is stored but expired', done => { + const instance = new JwtTokenManagerV1(); + instance.tokenInfo.access_token = '987zxc'; + + const saveTokenInfoSpy = jest.spyOn(instance, 'saveTokenInfo'); + const decodeSpy = jest + .spyOn(jwt, 'decode') + .mockImplementation(token => ({ iat: 0, exp: 100 })); + + const requestTokenSpy = jest + .spyOn(instance, 'requestToken') + .mockImplementation(cb => cb(null, { access_token: ACCESS_TOKEN })); + + instance.getToken((err, res) => { + expect(requestTokenSpy).toHaveBeenCalled(); + expect(saveTokenInfoSpy).toHaveBeenCalled(); + expect(decodeSpy).toHaveBeenCalled(); + expect(err).toBeNull(); + expect(res).toBe(ACCESS_TOKEN); + + saveTokenInfoSpy.mockRestore(); + decodeSpy.mockRestore(); + requestTokenSpy.mockRestore(); + done(); + }); + }); + + it('should not save token info if token request returned an error', done => { + const instance = new JwtTokenManagerV1(); + + const saveTokenInfoSpy = jest.spyOn(instance, 'saveTokenInfo'); + const requestTokenSpy = jest + .spyOn(instance, 'requestToken') + .mockImplementation(cb => cb(new Error(), null)); + + instance.getToken((err, res) => { + expect(requestTokenSpy).toHaveBeenCalled(); + expect(saveTokenInfoSpy).not.toHaveBeenCalled(); + expect(err).toBeInstanceOf(Error); + expect(res).toBe(null); + + saveTokenInfoSpy.mockRestore(); + requestTokenSpy.mockRestore(); + done(); + }); + }); + + it('should catch lower level errors and send through callback', done => { + const instance = new JwtTokenManagerV1(); + const saveTokenInfoSpy = jest.spyOn(instance, 'saveTokenInfo'); + + // because there is no access token, calling `saveTokenInfo` will + // throw an error to be caught and returned in the callback + const requestTokenSpy = jest + .spyOn(instance, 'requestToken') + .mockImplementation(cb => cb(null, { arbitrary_data: '12345' })); + + instance.getToken((err, res) => { + expect(err).toBeInstanceOf(Error); + expect(res).toBeNull(); + + saveTokenInfoSpy.mockRestore(); + requestTokenSpy.mockRestore(); + done(); + }); + }); + + it('should use an sdk-managed token if present and not expired', done => { + const instance = new JwtTokenManagerV1(); + instance.tokenInfo.access_token = ACCESS_TOKEN; + instance.expireTime = getCurrentTime() + 1000; + instance.getToken((err, res) => { + expect(err).toBeNull(); + expect(res).toBe(ACCESS_TOKEN); + done(); + }); + }); + }); + + it('should set userAccessToken with setAccessToken', () => { + const instance = new JwtTokenManagerV1(); + + expect(instance.url).toBe(undefined); + expect(instance.userAccessToken).toBe(undefined); + + instance.setAccessToken(ACCESS_TOKEN); + expect(instance.userAccessToken).toBe(ACCESS_TOKEN); + }); + + it('should callback with error if requestToken is not overriden', done => { + const instance = new JwtTokenManagerV1(); + + instance.requestToken((err, res) => { + expect(err).toBeInstanceOf(Error); + expect(res).toBeNull(); + done(); + }); + }); + + it('should return a basic auth header with computeBasicAuthHeader', () => { + const instance = new JwtTokenManagerV1(); + + const header = instance.computeBasicAuthHeader('bx', 'bx'); + expect(header).toBe('Basic Yng6Yng='); + }); + + describe('isTokenExpired', () => { + it('should return true if current time is past expire time', () => { + const instance = new JwtTokenManagerV1(); + instance.expireTime = getCurrentTime() - 1000; + + expect(instance.isTokenExpired()).toBe(true); + }); + + it('should return false if current time has not reached expire time', () => { + const instance = new JwtTokenManagerV1(); + instance.expireTime = getCurrentTime() + 1000; + + expect(instance.isTokenExpired()).toBe(false); + }); + + it('should return true if expire time has not been set', () => { + const instance = new JwtTokenManagerV1(); + expect(instance.isTokenExpired()).toBe(true); + }); + }); + + describe('saveTokenInfo', () => { + it('should save information to object state', () => { + const instance = new JwtTokenManagerV1(); + + const expireTime = 100; + instance.calculateTimeForNewToken = jest.fn(token => expireTime); + + const tokenResponse = { access_token: ACCESS_TOKEN }; + + instance.saveTokenInfo(tokenResponse); + expect(instance.expireTime).toBe(expireTime); + expect(instance.tokenInfo).toEqual(tokenResponse); + expect(instance.calculateTimeForNewToken).toHaveBeenCalledWith(ACCESS_TOKEN); + }); + + it('should throw an error when access token is undefined', () => { + const instance = new JwtTokenManagerV1(); + const tokenResponse = {}; + + expect(() => instance.saveTokenInfo(tokenResponse)).toThrow(); + }); + }); + + describe('calculateTimeForNewToken', () => { + it('should calculate time for new token based on valid jwt', () => { + const instance = new JwtTokenManagerV1(); + const decodeSpy = jest + .spyOn(jwt, 'decode') + .mockImplementation(token => ({ iat: 0, exp: 100 })); + + expect(instance.calculateTimeForNewToken(ACCESS_TOKEN)).toBe(80); + decodeSpy.mockRestore(); + }); + + it('should throw an error if token is not a valid jwt', () => { + const instance = new JwtTokenManagerV1(); + expect(() => instance.calculateTimeForNewToken()).toThrow(); + }); + }); +}); From 6d718fae456edc420c969ef6c8578a83e410ea48 Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Fri, 31 May 2019 13:40:53 -0500 Subject: [PATCH 10/18] test: add unit tests for icp token manager --- test/unit/icpTokenManager.v1.test.js | 70 ++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 test/unit/icpTokenManager.v1.test.js diff --git a/test/unit/icpTokenManager.v1.test.js b/test/unit/icpTokenManager.v1.test.js new file mode 100644 index 000000000..4fd10b106 --- /dev/null +++ b/test/unit/icpTokenManager.v1.test.js @@ -0,0 +1,70 @@ +/* eslint-disable no-alert, no-console */ +'use strict'; + +const { Icp4dTokenManagerV1 } = require('../../auth/icp4d-token-manager-v1'); + +// mock sendRequest +jest.mock('../../lib/requestwrapper'); +const { RequestWrapper } = require('../../lib/requestwrapper'); +const mockSendRequest = jest.fn(); +RequestWrapper.mockImplementation(() => { + return { + sendRequest: mockSendRequest, + }; +}); + +describe('iam_token_manager_v1', () => { + describe('constructor', () => { + it('should initialize base variables', () => { + const instance = new Icp4dTokenManagerV1({ + url: 'tokenservice.com', + username: 'sherlock', + password: 'holmes', + accessToken: 'abc123', + }); + + expect(instance.tokenName).toBe('accessToken'); + expect(instance.url).toBe('tokenservice.com/v1/preauth/validateAuth'); + expect(instance.username).toBe('sherlock'); + expect(instance.password).toBe('holmes'); + expect(instance.rejectUnauthorized).toBe(true); + expect(instance.userAccessToken).toBe('abc123'); + }); + + it('should set rejectUnauthorized based on disableSslVerification', () => { + const instance = new Icp4dTokenManagerV1({ + url: 'tokenservice.com', + disableSslVerification: true, + }); + + expect(instance.rejectUnauthorized).toBe(false); + }); + + it('should throw an error if `url` is not given', () => { + expect(() => new Icp4dTokenManagerV1()).toThrow(); + }); + }); + + describe('requestToken', () => { + it('should call sendRequest with all request options', () => { + const noop = () => {}; + const instance = new Icp4dTokenManagerV1({ url: 'tokenservice.com' }); + instance.requestToken(noop); + + // extract arguments sendRequest was called with + const params = mockSendRequest.mock.calls[0][0]; + const callback = mockSendRequest.mock.calls[0][1]; + + expect(mockSendRequest).toHaveBeenCalled(); + expect(params.options).toBeDefined(); + expect(params.options.url).toBe('tokenservice.com/v1/preauth/validateAuth'); + expect(params.options.method).toBe('GET'); + expect(params.options.rejectUnauthorized).toBe(true); + expect(params.options.headers).toBeDefined(); + + // encoding of undefined:undefined + expect(params.options.headers.Authorization).toBe('Basic dW5kZWZpbmVkOnVuZGVmaW5lZA=='); + expect(callback).toBe(noop); + }); + }); +}); From 3adbe104142dcad59f6544c8ff4d8d303bfa38f9 Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Fri, 31 May 2019 14:35:06 -0500 Subject: [PATCH 11/18] test: add unit tests for base service changes --- lib/base_service.ts | 18 +++--- test/unit/baseService.test.js | 105 ++++++++++++++++++++++++++++++++-- 2 files changed, 111 insertions(+), 12 deletions(-) diff --git a/lib/base_service.ts b/lib/base_service.ts index 136c60d3b..0fee8ff6b 100644 --- a/lib/base_service.ts +++ b/lib/base_service.ts @@ -162,10 +162,13 @@ export class BaseService { ); } const options = extend({}, userOptions); + const _options = this.initCredentials(options); + if (options.url) { _options.url = stripTrailingSlash(options.url); } + const serviceClass = this.constructor as typeof BaseService; this._options = extend( { qs: {}, url: serviceClass.URL }, @@ -174,18 +177,13 @@ export class BaseService { _options ); - // make authentication_type non-case-sensitive - if (typeof _options.authentication_type === 'string') { - _options.authentication_type = _options.authentication_type.toLowerCase(); - } - // rejectUnauthorized should only be false if disable_ssl_verification is true // used to disable ssl checking for icp this._options.rejectUnauthorized = !options.disable_ssl_verification; if (_options.authentication_type === 'iam' || hasIamCredentials(_options)) { this.tokenManager = new IamTokenManagerV1({ - iamApikey: _options.iam_apikey || _options.password, + iamApikey: _options.iam_apikey, accessToken: _options.iam_access_token, url: _options.iam_url, iamClientId: _options.iam_client_id, @@ -346,6 +344,12 @@ export class BaseService { options, _options ); + + // make authentication_type non-case-sensitive + if (typeof _options.authentication_type === 'string') { + _options.authentication_type = _options.authentication_type.toLowerCase(); + } + if (!_options.use_unauthenticated) { if (!hasCredentials(_options)) { const errorMessage = 'Insufficient credentials provided in ' + @@ -363,7 +367,7 @@ export class BaseService { delete options.iam_apikey; } - if (!hasIamCredentials(_options) && !usesBasicForIam(_options)) { + if (!hasIamCredentials(_options) && !usesBasicForIam(_options) && !isForICP4D(_options)) { if (_options.authentication_type === 'basic' || hasBasicCredentials(_options)) { // Calculate and add Authorization header to base options const encodedCredentials = Buffer.from( diff --git a/test/unit/baseService.test.js b/test/unit/baseService.test.js index dcf4c8130..37f5ca3df 100644 --- a/test/unit/baseService.test.js +++ b/test/unit/baseService.test.js @@ -100,6 +100,29 @@ describe('BaseService', function() { expect(instance._options.headers['X-Watson-Authorization-Token']).toBe('foo'); }); + it('should return all credentials with getServiceCredentials', function() { + const instance = new TestService({ + username: 'test', + password: 'test', + url: 'test', + iam_access_token: 'test', + iam_apikey: 'test', + iam_url: 'test', + icp_access_token: 'test', + authentication_type: 'test', + }); + const creds = instance.getServiceCredentials(); + + expect(creds.username).toBeDefined(); + expect(creds.password).toBeDefined(); + expect(creds.url).toBeDefined(); + expect(creds.iam_access_token).toBeDefined(); + expect(creds.iam_apikey).toBeDefined(); + expect(creds.iam_url).toBeDefined(); + expect(creds.icp_access_token).toBeDefined(); + expect(creds.authentication_type).toBeDefined(); + }); + it('should return hard-coded credentials', function() { const instance = new TestService({ username: 'user', password: 'pass' }); const actual = instance.getServiceCredentials(); @@ -111,16 +134,28 @@ describe('BaseService', function() { expect(actual).toEqual(expected); }); - it('should return credentials and url from the environment', function() { - process.env.TEST_USERNAME = 'env_user'; - process.env.TEST_PASSWORD = 'env_pass'; + it('should return all credentials and url from the environment', function() { + process.env.TEST_USERNAME = 'test'; + process.env.TEST_PASSWORD = 'test'; process.env.TEST_URL = 'http://foo'; + process.env.TEST_API_KEY = 'test'; + process.env.TEST_IAM_ACCESS_TOKEN = 'test'; + process.env.TEST_IAM_APIKEY = 'test'; + process.env.TEST_IAM_URL = 'test'; + process.env.TEST_ICP_ACCESS_TOKEN = 'test'; + process.env.TEST_AUTHENTICATION_TYPE = 'test'; + const instance = new TestService(); const actual = instance.getServiceCredentials(); const expected = { - username: 'env_user', - password: 'env_pass', + username: 'test', + password: 'test', url: 'http://foo', + iam_access_token: 'test', + iam_apikey: 'test', + iam_url: 'test', + icp_access_token: 'test', + authentication_type: 'test', }; expect(actual).toEqual(expected); }); @@ -335,6 +370,22 @@ describe('BaseService', function() { expect(instance.tokenManager).not.toBeNull(); }); + it('should create an icp4d token manager if setAccessToken is called and auth type is `icp4d`', function() { + const instance = new TestService({ + username: 'user', + password: 'pass', + url: 'service.com', + }); + expect(instance.tokenManager).toBeNull(); + + // this is sort of a bizarre use case... + instance._options.authentication_type = 'icp4d'; + + instance.setAccessToken('abcd-1234'); + expect(instance.tokenManager).toBeDefined(); + expect(instance.tokenManager).not.toBeNull(); + }); + it('should create a token manager instance if env variables specify iam credentials', function() { process.env.TEST_IAM_APIKEY = 'test1234'; const instance = new TestService(); @@ -360,6 +411,40 @@ describe('BaseService', function() { expect(instance._options.headers).toBeUndefined(); }); + it('should create an iam token manager instance if authentication_type is `iam`', function() { + const apikey = 'abcd-1234'; + const instance = new TestService({ + authentication_type: 'iam', + iam_apikey: apikey, + }); + expect(instance.tokenManager).toBeDefined(); + expect(instance.tokenManager).not.toBeNull(); + expect(instance.tokenManager.iamApikey).toBe(apikey); + expect(instance._options.headers).toBeUndefined(); + }); + + it('should create an icp4d token manager instance if authentication_type is `icp4d`', function() { + const instance = new TestService({ + authentication_type: 'ICP4D', // using all caps to prove case insensitivity + username: 'test', + password: 'test', + url: 'service.com', + }); + expect(instance.tokenManager).toBeDefined(); + expect(instance.tokenManager).not.toBeNull(); + expect(instance._options.headers).toBeUndefined(); + }); + + it('should create an icp4d token manager instance if given icp_access_token', function() { + const instance = new TestService({ + icp_access_token: 'test', + url: 'service.com', + }); + expect(instance.tokenManager).toBeDefined(); + expect(instance.tokenManager).not.toBeNull(); + expect(instance._options.headers).toBeUndefined(); + }); + it('should not create a basic auth header if iam creds are given', function() { const apikey = 'abcd-1234'; const instance = new TestService({ @@ -426,6 +511,16 @@ describe('BaseService', function() { expect(authHeader.startsWith('Basic')).toBe(true); }); + it('should convert authentication_type to lower case', function() { + const instance = new TestService({ + authentication_type: 'ICP4D', + icp_access_token: 'abc123', + url: 'someservice.com', + }); + + expect(instance._options.authentication_type).toBe('icp4d'); + }); + describe('check credentials for common problems', function() { function assertConstructorThrows(params) { expect(() => { From 12028fc6a644f8eedbb8c709c9613310a19df85b Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Mon, 3 Jun 2019 11:14:19 -0500 Subject: [PATCH 12/18] refactor: move computeBasicAuthHeader to its own module --- README.md | 2 +- auth/iam-token-manager-v1.ts | 6 +- auth/icp4d-token-manager-v1.ts | 4 +- auth/index.ts | 20 ++ auth/jwt-token-manager-v1.ts | 12 -- auth/utils.ts | 27 +++ lib/base_service.ts | 9 +- package-lock.json | 301 ++++++++++++++------------- test/unit/iamTokenManager.test.js | 2 +- test/unit/icpTokenManager.v1.test.js | 2 +- test/unit/jwtTokenManager.v1.test.js | 9 +- 11 files changed, 213 insertions(+), 181 deletions(-) create mode 100644 auth/index.ts create mode 100644 auth/utils.ts diff --git a/README.md b/README.md index e2706b5b8..7177191cc 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ This indicates that IAM token authentication is to be used. Users can pass in an ### icp4d This indicates that the service is an instance of ICP4D, which has its own version of token authentication. Users can pass in a `username` and `password`, or an `icp_access_token`. If a username and password is given, the SDK will manage the token for the user. -A `url` is **required** for this type. In order to use ICP4D authentication, this option **must** be passed in. +A `url` is **required** for this type. In order to use an SDK-managed token with ICP4D authentication, this option **must** be passed in. ## Available Modules ### BaseService diff --git a/auth/iam-token-manager-v1.ts b/auth/iam-token-manager-v1.ts index 5a68ea3e4..6f0049a92 100644 --- a/auth/iam-token-manager-v1.ts +++ b/auth/iam-token-manager-v1.ts @@ -15,7 +15,8 @@ */ import extend = require('extend'); -import { JwtTokenManagerV1 } from '../auth/jwt-token-manager-v1'; +import { JwtTokenManagerV1 } from './jwt-token-manager-v1'; +import { computeBasicAuthHeader } from './utils'; /** * Check for only one of two elements being defined. @@ -143,8 +144,7 @@ export class IamTokenManagerV1 extends JwtTokenManagerV1 { method: 'POST', headers: { 'Content-type': 'application/x-www-form-urlencoded', - Authorization: - this.computeBasicAuthHeader(clientId, clientSecret), + Authorization: computeBasicAuthHeader(clientId, clientSecret), }, form: { grant_type: 'urn:ibm:params:oauth:grant-type:apikey', diff --git a/auth/icp4d-token-manager-v1.ts b/auth/icp4d-token-manager-v1.ts index 8c13e055b..d075559d4 100644 --- a/auth/icp4d-token-manager-v1.ts +++ b/auth/icp4d-token-manager-v1.ts @@ -16,6 +16,7 @@ import extend = require('extend'); import { JwtTokenManagerV1 } from './jwt-token-manager-v1'; +import { computeBasicAuthHeader } from './utils'; export type Options = { url: string; @@ -97,8 +98,7 @@ export class Icp4dTokenManagerV1 extends JwtTokenManagerV1 { url: this.url, method: 'GET', headers: { - Authorization: - this.computeBasicAuthHeader(this.username, this.password), + Authorization: computeBasicAuthHeader(this.username, this.password), }, rejectUnauthorized: this.rejectUnauthorized, } diff --git a/auth/index.ts b/auth/index.ts new file mode 100644 index 000000000..4edd6966b --- /dev/null +++ b/auth/index.ts @@ -0,0 +1,20 @@ +/** + * Copyright 2019 IBM Corp. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { IamTokenManagerV1 } from './iam-token-manager-v1'; +export { Icp4dTokenManagerV1 } from './icp4d-token-manager-v1'; +export { JwtTokenManagerV1 } from './jwt-token-manager-v1'; +export * from './utils'; diff --git a/auth/jwt-token-manager-v1.ts b/auth/jwt-token-manager-v1.ts index c199ecfda..9ee0a667f 100644 --- a/auth/jwt-token-manager-v1.ts +++ b/auth/jwt-token-manager-v1.ts @@ -125,18 +125,6 @@ export class JwtTokenManagerV1 { cb(err, null); } - /** - * Compute and return a Basic Authorization header from a username and password. - * - * @param {string} username - The username or client id - * @param {string} password - The password or client secret - * @returns {string} - */ - protected computeBasicAuthHeader(username, password): string { - const encodedCreds = Buffer.from(`${username}:${password}`).toString('base64'); - return `Basic ${encodedCreds}`; - } - /** * Check if currently stored token is "expired" * i.e. past the window to request a new token diff --git a/auth/utils.ts b/auth/utils.ts new file mode 100644 index 000000000..7fe2fb4e3 --- /dev/null +++ b/auth/utils.ts @@ -0,0 +1,27 @@ +/** + * Copyright 2019 IBM Corp. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Compute and return a Basic Authorization header from a username and password. + * + * @param {string} username - The username or client id + * @param {string} password - The password or client secret + * @returns {string} - A Basic Auth header with format "Basic " + */ +export function computeBasicAuthHeader(username: string, password: string): string { + const encodedCreds = Buffer.from(`${username}:${password}`).toString('base64'); + return `Basic ${encodedCreds}`; +} diff --git a/lib/base_service.ts b/lib/base_service.ts index 0fee8ff6b..3c7bc7de2 100644 --- a/lib/base_service.ts +++ b/lib/base_service.ts @@ -16,8 +16,7 @@ import extend = require('extend'); import vcapServices = require('vcap_services'); -import { IamTokenManagerV1 } from '../auth/iam-token-manager-v1'; -import { Icp4dTokenManagerV1 } from '../auth/icp4d-token-manager-v1'; +import { computeBasicAuthHeader, IamTokenManagerV1, Icp4dTokenManagerV1 } from '../auth'; import { stripTrailingSlash } from './helper'; import { readCredentialsFile } from './read-credentials-file'; import { RequestWrapper } from './requestwrapper'; @@ -370,10 +369,8 @@ export class BaseService { if (!hasIamCredentials(_options) && !usesBasicForIam(_options) && !isForICP4D(_options)) { if (_options.authentication_type === 'basic' || hasBasicCredentials(_options)) { // Calculate and add Authorization header to base options - const encodedCredentials = Buffer.from( - `${_options.username}:${_options.password}` - ).toString('base64'); - const authHeader = { Authorization: `Basic ${encodedCredentials}` }; + const encodedCredentials = computeBasicAuthHeader(_options.username, _options.password); + const authHeader = { Authorization: `${encodedCredentials}` }; _options.headers = extend(authHeader, _options.headers); } } diff --git a/package-lock.json b/package-lock.json index 2e7133d13..baa4e9ed9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,10 +44,10 @@ "ms": "^2.1.1" } }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true } } @@ -181,6 +181,12 @@ "requires": { "ms": "^2.1.1" } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true } } }, @@ -265,6 +271,14 @@ "dev": true, "requires": { "semver": "6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", + "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", + "dev": true + } } }, "@commitlint/lint": { @@ -598,9 +612,9 @@ "dev": true }, "@octokit/endpoint": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.1.3.tgz", - "integrity": "sha512-ePx9kcUo0agRk0HaXhl+pKMXpBH1O3CAygwWIh7GT5i5kcUr8QowS0GBaZPirr1e0PqaFYr41hQfcUBA1R5AEQ==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.1.4.tgz", + "integrity": "sha512-DypS8gbbcc9rlOCDW0wV9a+B18+ylduj6PpxeE+qa3IK1h5b0eW4CKj5pxxXWOZUYhEKwgOnh3+Q+Y/hx/bOPw==", "dev": true, "requires": { "deepmerge": "3.2.0", @@ -669,9 +683,9 @@ } }, "@octokit/rest": { - "version": "16.27.0", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.27.0.tgz", - "integrity": "sha512-UvCxVOCfHzEhOaltSKQBy81kMqQ+hglF3rAR4STut4WWr2tXvVnrIkGxeblO0TvmTt5zuxfgQfgG5kAHUT44RA==", + "version": "16.27.3", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.27.3.tgz", + "integrity": "sha512-WWH/SHF4kus6FG+EAfX7/JYH70EjgFYa4AAd2Lf1hgmgzodhrsoxpXPSZliZ5BdJruZPMP7ZYaPoTrYCCKYzmQ==", "dev": true, "requires": { "@octokit/request": "^4.0.1", @@ -765,6 +779,12 @@ "redent": "^2.0.0", "trim-newlines": "^2.0.0" } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true } } }, @@ -800,6 +820,12 @@ "requires": { "ms": "^2.1.1" } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true } } }, @@ -836,6 +862,12 @@ "requires": { "ms": "^2.1.1" } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true } } }, @@ -949,6 +981,12 @@ "redent": "^2.0.0", "trim-newlines": "^2.0.0" } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true } } }, @@ -1081,9 +1119,9 @@ } }, "@types/lodash": { - "version": "4.14.132", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.132.tgz", - "integrity": "sha512-RNUU1rrh85NgUJcjOOr96YXr+RHwInGbaQCZmlitqOaCKXffj8bh+Zxwuq5rjDy5OgzFldDVoqk4pyLEDiwxIw==", + "version": "4.14.133", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.133.tgz", + "integrity": "sha512-/3JqnvPnY58GLzG3Y7fpphOhATV1DDZ/Ak3DQufjlRK5E4u+s0CfClfNFtAGBabw+jDGtRFbOZe+Z02ZMWCBNQ==", "dev": true }, "@types/marked": { @@ -1404,12 +1442,12 @@ "dev": true }, "axios": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", - "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", + "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", "requires": { - "follow-redirects": "^1.3.0", - "is-buffer": "^1.1.5" + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" } }, "babel-code-frame": { @@ -1674,9 +1712,9 @@ "dev": true }, "bottleneck": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.18.1.tgz", - "integrity": "sha512-EhSYARs0MHsNRBPrp1TaeHpgmWFUpA6yl3NNBPjGNilBaQZr4iSbrJ16JbQVXuZkIaB7YVYfaiMiRq7NgyZFQg==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.0.tgz", + "integrity": "sha512-0U9t0ALx89RC0AlHVxmDNl1UdlBZYE6RusW57EsR808WirvWbP2VNAp7i3FyIemGqTxQlaZ0MICAet9Myp0N1Q==", "dev": true }, "brace-expansion": { @@ -2122,12 +2160,6 @@ "redent": "^2.0.0", "trim-newlines": "^2.0.0" } - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true } } }, @@ -2243,14 +2275,6 @@ "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - } } }, "cssom": { @@ -2326,11 +2350,11 @@ "dev": true }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { - "ms": "^2.1.1" + "ms": "2.0.0" } }, "decamelize": { @@ -2482,12 +2506,6 @@ "requires": { "graceful-fs": "^4.1.6" } - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true } } }, @@ -2758,12 +2776,6 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", "dev": true - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true } } }, @@ -2807,12 +2819,6 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", "dev": true - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true } } }, @@ -2971,12 +2977,6 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, @@ -3237,11 +3237,11 @@ } }, "follow-redirects": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", - "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", "requires": { - "debug": "^3.2.6" + "debug": "=3.1.0" } }, "for-in": { @@ -4134,6 +4134,12 @@ "kind-of": "^4.0.0" }, "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", @@ -4146,9 +4152,9 @@ } }, "highlight.js": { - "version": "9.15.7", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.7.tgz", - "integrity": "sha512-6AgA4zXNQZbgvhuJQhL+8JEd+XiPyzRxHpoRnhU084/ZoLqvMRjFQ3eSXvcUlLpLByA++TDYiFr0r4CHRHRJBQ==", + "version": "9.15.8", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.8.tgz", + "integrity": "sha512-RrapkKQWwE+wKdF73VsOa2RQdIoO3mxwJ4P8mhbI6KYJUraUHRKM5w5zQQKXNk0xNL4UVRdulV9SBJcmzJNzVA==", "dev": true }, "hook-std": { @@ -4180,23 +4186,6 @@ "requires": { "agent-base": "4", "debug": "3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } } }, "http-signature": { @@ -4384,6 +4373,12 @@ "kind-of": "^3.0.2" }, "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -4402,9 +4397,9 @@ "dev": true }, "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" }, "is-callable": { "version": "1.1.4", @@ -4430,6 +4425,12 @@ "kind-of": "^3.0.2" }, "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -4516,6 +4517,12 @@ "kind-of": "^3.0.2" }, "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -4670,6 +4677,14 @@ "@babel/types": "^7.4.0", "istanbul-lib-coverage": "^2.0.5", "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz", + "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==", + "dev": true + } } }, "istanbul-lib-report": { @@ -4716,6 +4731,12 @@ "ms": "^2.1.1" } }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5102,14 +5123,6 @@ "natural-compare": "^1.4.0", "pretty-format": "^24.8.0", "semver": "^5.5.0" - }, - "dependencies": { - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - } } }, "jest-util": { @@ -5329,6 +5342,13 @@ "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^5.6.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } } }, "jsprim": { @@ -5596,12 +5616,6 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true } } }, @@ -5833,9 +5847,9 @@ "dev": true }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "mute-stream": { "version": "0.0.7", @@ -5940,14 +5954,6 @@ "semver": "^5.5.0", "shellwords": "^0.1.1", "which": "^1.3.0" - }, - "dependencies": { - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - } } }, "normalize-package-data": { @@ -5960,14 +5966,6 @@ "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - } } }, "normalize-path": { @@ -9495,6 +9493,12 @@ "is-descriptor": "^0.1.0" } }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -10514,6 +10518,12 @@ "p-locate": "^4.1.0" } }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, "p-limit": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", @@ -10575,6 +10585,12 @@ "type-fest": "^0.5.0" } }, + "semver": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz", + "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==", + "dev": true + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -10674,16 +10690,9 @@ } }, "semver": { -<<<<<<< HEAD "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" -======= - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", - "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", - "dev": true ->>>>>>> master }, "semver-regex": { "version": "2.0.0", @@ -10857,12 +10866,6 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, @@ -10926,6 +10929,12 @@ "kind-of": "^3.2.0" }, "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -11384,6 +11393,12 @@ "kind-of": "^3.0.2" }, "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -11492,14 +11507,6 @@ "semver": "^5.3.0", "tslib": "^1.8.0", "tsutils": "^2.12.1" - }, - "dependencies": { - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - } } }, "tslint-config-prettier": { @@ -11649,9 +11656,9 @@ "dev": true }, "uglify-js": { - "version": "3.5.15", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.15.tgz", - "integrity": "sha512-fe7aYFotptIddkwcm6YuA0HmknBZ52ZzOsUxZEdhhkSsz7RfjHDX2QDxwKTiv4JQ5t5NhfmpgAK+J7LiDhKSqg==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", "dev": true, "optional": true, "requires": { diff --git a/test/unit/iamTokenManager.test.js b/test/unit/iamTokenManager.test.js index 20fc123d9..bf34cf518 100644 --- a/test/unit/iamTokenManager.test.js +++ b/test/unit/iamTokenManager.test.js @@ -9,7 +9,7 @@ jwt.decode = jest.fn(() => { return { exp: 100, iat: 100 }; }); -const IamTokenManagerV1 = require('../../iam-token-manager/v1').IamTokenManagerV1; +const { IamTokenManagerV1 } = require('../../iam-token-manager/v1'); // testing compatibility const mockSendRequest = jest.fn(); RequestWrapper.mockImplementation(() => { diff --git a/test/unit/icpTokenManager.v1.test.js b/test/unit/icpTokenManager.v1.test.js index 4fd10b106..b34d6dabc 100644 --- a/test/unit/icpTokenManager.v1.test.js +++ b/test/unit/icpTokenManager.v1.test.js @@ -1,7 +1,7 @@ /* eslint-disable no-alert, no-console */ 'use strict'; -const { Icp4dTokenManagerV1 } = require('../../auth/icp4d-token-manager-v1'); +const { Icp4dTokenManagerV1 } = require('../../auth'); // mock sendRequest jest.mock('../../lib/requestwrapper'); diff --git a/test/unit/jwtTokenManager.v1.test.js b/test/unit/jwtTokenManager.v1.test.js index faf27b850..9c249b16a 100644 --- a/test/unit/jwtTokenManager.v1.test.js +++ b/test/unit/jwtTokenManager.v1.test.js @@ -1,7 +1,7 @@ /* eslint-disable no-alert, no-console */ 'use strict'; -const { JwtTokenManagerV1 } = require('../../auth/jwt-token-manager-v1'); +const { JwtTokenManagerV1 } = require('../../auth'); const jwt = require('jsonwebtoken'); function getCurrentTime() { @@ -157,13 +157,6 @@ describe('iam_token_manager_v1', () => { }); }); - it('should return a basic auth header with computeBasicAuthHeader', () => { - const instance = new JwtTokenManagerV1(); - - const header = instance.computeBasicAuthHeader('bx', 'bx'); - expect(header).toBe('Basic Yng6Yng='); - }); - describe('isTokenExpired', () => { it('should return true if current time is past expire time', () => { const instance = new JwtTokenManagerV1(); From 799a876d75f4ee111e3c26f9e2f908e29d7363a5 Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Mon, 3 Jun 2019 11:26:13 -0500 Subject: [PATCH 13/18] refactor: rename icp_access_token to icp4d_access_token --- README.md | 2 +- lib/base_service.ts | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7177191cc..550dcc356 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ This indicates Basic Auth is to be used. Users will pass in a `username` and `pa This indicates that IAM token authentication is to be used. Users can pass in an `iam_apikey` or an `iam_access_token`. If an API key is used, the SDK will manage the token for the user. In either case, the SDK will generate a Bearer Auth header to send with requests to the service. ### icp4d -This indicates that the service is an instance of ICP4D, which has its own version of token authentication. Users can pass in a `username` and `password`, or an `icp_access_token`. If a username and password is given, the SDK will manage the token for the user. +This indicates that the service is an instance of ICP4D, which has its own version of token authentication. Users can pass in a `username` and `password`, or an `icp4d_access_token`. If a username and password is given, the SDK will manage the token for the user. A `url` is **required** for this type. In order to use an SDK-managed token with ICP4D authentication, this option **must** be passed in. ## Available Modules diff --git a/lib/base_service.ts b/lib/base_service.ts index 3c7bc7de2..492576c97 100644 --- a/lib/base_service.ts +++ b/lib/base_service.ts @@ -37,7 +37,7 @@ export interface UserOptions { headers?: HeaderOptions; token?: string; iam_access_token?: string; - icp_access_token?: string; + icp4d_access_token?: string; iam_apikey?: string; iam_url?: string; iam_client_id?: string; @@ -58,7 +58,7 @@ export interface Credentials { password?: string; url?: string; iam_access_token?: string; - icp_access_token?: string; + icp4d_access_token?: string; iam_apikey?: string; iam_url?: string; authentication_type?: string; @@ -70,7 +70,7 @@ function hasCredentials(obj: any): boolean { ((obj.username && obj.password) || obj.iam_access_token || obj.iam_apikey || - obj.icp_access_token) + obj.icp4d_access_token) ); } @@ -79,7 +79,7 @@ function isForICP(cred: string): boolean { } function isForICP4D(obj: any): boolean { - return obj && (obj.authentication_type === 'icp4d' || obj.icp_access_token); + return obj && (obj.authentication_type === 'icp4d' || obj.icp4d_access_token); } function hasBasicCredentials(obj: any): boolean { @@ -137,7 +137,7 @@ export class BaseService { * @param {string} [options.iam_url] - url for iam service api, needed for services in staging * @param {string} [options.iam_client_id] - client id (username) for request to iam service * @param {string} [options.iam_client_secret] - secret (password) for request to iam service - * @param {string} [options.icp_access_token] - icp access token provided and managed by user + * @param {string} [options.icp4d_access_token] - icp access token provided and managed by user * @param {string} [options.authentication_type] - authentication pattern to be used. can be iam, basic, or icp4d * @param {string} [options.username] - required unless use_unauthenticated is set * @param {string} [options.password] - required unless use_unauthenticated is set @@ -200,7 +200,7 @@ export class BaseService { url: _options.url, username: _options.username, password: _options.password, - accessToken: _options.icp_access_token, + accessToken: _options.icp4d_access_token, disableSslVerification: options.disable_ssl_verification, }); } else { @@ -237,8 +237,8 @@ export class BaseService { if (this._options.iam_url) { credentials.iam_url = this._options.iam_url; } - if (this._options.icp_access_token) { - credentials.icp_access_token = this._options.icp_access_token; + if (this._options.icp4d_access_token) { + credentials.icp4d_access_token = this._options.icp4d_access_token; } if (this._options.authentication_type) { credentials.authentication_type = this._options.authentication_type; @@ -412,7 +412,7 @@ export class BaseService { const iamAccessToken: string = envObj[`${_name}_IAM_ACCESS_TOKEN`] || envObj[`${nameWithUnderscore}_IAM_ACCESS_TOKEN`]; const iamApiKey: string = envObj[`${_name}_IAM_APIKEY`] || envObj[`${nameWithUnderscore}_IAM_APIKEY`]; const iamUrl: string = envObj[`${_name}_IAM_URL`] || envObj[`${nameWithUnderscore}_IAM_URL`]; - const icpAccessToken: string = envObj[`${_name}_ICP_ACCESS_TOKEN`] || envObj[`${nameWithUnderscore}_ICP_ACCESS_TOKEN`]; + const icp4dAccessToken: string = envObj[`${_name}_ICP4D_ACCESS_TOKEN`] || envObj[`${nameWithUnderscore}_ICP4D_ACCESS_TOKEN`]; const authenticationType: string = envObj[`${_name}_AUTHENTICATION_TYPE`] || envObj[`${nameWithUnderscore}_AUTHENTICATION_TYPE`]; return { @@ -422,7 +422,7 @@ export class BaseService { iam_access_token: iamAccessToken, iam_apikey: iamApiKey, iam_url: iamUrl, - icp_access_token: icpAccessToken, + icp4d_access_token: icp4dAccessToken, authentication_type: authenticationType, }; } From 0f4ece71540bfc461fa3927a30bdc6940a8dd5c9 Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Mon, 3 Jun 2019 11:28:52 -0500 Subject: [PATCH 14/18] docs: update copyright date in iam-token-manager-v1.js --- auth/iam-token-manager-v1.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth/iam-token-manager-v1.ts b/auth/iam-token-manager-v1.ts index 6f0049a92..d62902362 100644 --- a/auth/iam-token-manager-v1.ts +++ b/auth/iam-token-manager-v1.ts @@ -1,5 +1,5 @@ /** - * Copyright 2015 IBM Corp. All Rights Reserved. + * Copyright 2019 IBM Corp. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 1fc9fb1d0db9a2ab1d8afa44cf2d6bc4267d0ba5 Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Mon, 3 Jun 2019 11:50:45 -0500 Subject: [PATCH 15/18] build: ignore linting .js files under auth directory --- .eslintignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintignore b/.eslintignore index 639a446d6..866e70bbc 100644 --- a/.eslintignore +++ b/.eslintignore @@ -8,5 +8,6 @@ node_modules/ **/*v*.js !test/**/*.js lib/*.js +auth/*.js index.js scripts/typedoc/ \ No newline at end of file From 91cbaf0cab2b9f428b56b41d40a9bfdc14a22999 Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Mon, 3 Jun 2019 12:06:08 -0500 Subject: [PATCH 16/18] test: update base service test to use icp4d_access_token --- test/unit/baseService.test.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/unit/baseService.test.js b/test/unit/baseService.test.js index 37f5ca3df..a4cd04f94 100644 --- a/test/unit/baseService.test.js +++ b/test/unit/baseService.test.js @@ -108,7 +108,7 @@ describe('BaseService', function() { iam_access_token: 'test', iam_apikey: 'test', iam_url: 'test', - icp_access_token: 'test', + icp4d_access_token: 'test', authentication_type: 'test', }); const creds = instance.getServiceCredentials(); @@ -119,7 +119,7 @@ describe('BaseService', function() { expect(creds.iam_access_token).toBeDefined(); expect(creds.iam_apikey).toBeDefined(); expect(creds.iam_url).toBeDefined(); - expect(creds.icp_access_token).toBeDefined(); + expect(creds.icp4d_access_token).toBeDefined(); expect(creds.authentication_type).toBeDefined(); }); @@ -142,7 +142,7 @@ describe('BaseService', function() { process.env.TEST_IAM_ACCESS_TOKEN = 'test'; process.env.TEST_IAM_APIKEY = 'test'; process.env.TEST_IAM_URL = 'test'; - process.env.TEST_ICP_ACCESS_TOKEN = 'test'; + process.env.TEST_ICP4D_ACCESS_TOKEN = 'test'; process.env.TEST_AUTHENTICATION_TYPE = 'test'; const instance = new TestService(); @@ -154,7 +154,7 @@ describe('BaseService', function() { iam_access_token: 'test', iam_apikey: 'test', iam_url: 'test', - icp_access_token: 'test', + icp4d_access_token: 'test', authentication_type: 'test', }; expect(actual).toEqual(expected); @@ -435,9 +435,9 @@ describe('BaseService', function() { expect(instance._options.headers).toBeUndefined(); }); - it('should create an icp4d token manager instance if given icp_access_token', function() { + it('should create an icp4d token manager instance if given icp4d_access_token', function() { const instance = new TestService({ - icp_access_token: 'test', + icp4d_access_token: 'test', url: 'service.com', }); expect(instance.tokenManager).toBeDefined(); @@ -514,7 +514,7 @@ describe('BaseService', function() { it('should convert authentication_type to lower case', function() { const instance = new TestService({ authentication_type: 'ICP4D', - icp_access_token: 'abc123', + icp4d_access_token: 'abc123', url: 'someservice.com', }); From 9ac1ceed002d13f1d589018b0f0f49d6a27d781b Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Tue, 4 Jun 2019 14:23:46 -0500 Subject: [PATCH 17/18] docs: remove references to "refreshing" tokens --- README.md | 2 +- auth/iam-token-manager-v1.ts | 4 ++-- auth/icp4d-token-manager-v1.ts | 2 +- auth/jwt-token-manager-v1.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 550dcc356..3e617d1ac 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ A `url` is **required** for this type. In order to use an SDK-managed token with This Class is the base class that all generated service-specific classes inherit from. It implements credentials handling and other shared behavior. ### IamTokenManagerV1 -This Class contains logic for managing an IAM token over its lifetime. Tokens can be requested or set manually. When requested, the token manager will either return the current token, request a new token or refresh the current token if it is expired. If a token is manually set, it must be managed by the user. +This Class contains logic for managing an IAM token over its lifetime. Tokens can be requested or set manually. When requested, the token manager will either return the current token or request a new token if one is not saved or the the current token is expired. If a token is manually set, it must be managed by the user. ### Icp4dTokenManagerV1 This Class is similar in function to IamTokenManagerV1. The only difference is that the `url` parameter is required, it takes a `username` and `password` instead of an API key, and manages tokens for instances of ICP4D. To use this token manager in an SDK, the parameter `authentication_type` must be set to `icp4d` in the constructor. diff --git a/auth/iam-token-manager-v1.ts b/auth/iam-token-manager-v1.ts index d62902362..955445560 100644 --- a/auth/iam-token-manager-v1.ts +++ b/auth/iam-token-manager-v1.ts @@ -63,7 +63,7 @@ export class IamTokenManagerV1 extends JwtTokenManagerV1 { /** * IAM Token Manager Service * - * Retreives, stores, and refreshes IAM tokens. + * Retreives and stores IAM access tokens. * * @param {Object} options * @param {String} options.iamApikey @@ -97,7 +97,7 @@ export class IamTokenManagerV1 extends JwtTokenManagerV1 { /** * Set the IAM 'client_id' and 'client_secret' values. * These values are used to compute the Authorization header used - * when retrieving or refreshing the IAM access token. + * when retrieving the IAM access token. * If these values are not set, then a default Authorization header * will be used when interacting with the IAM token server. * diff --git a/auth/icp4d-token-manager-v1.ts b/auth/icp4d-token-manager-v1.ts index d075559d4..3698e7b45 100644 --- a/auth/icp4d-token-manager-v1.ts +++ b/auth/icp4d-token-manager-v1.ts @@ -48,7 +48,7 @@ export class Icp4dTokenManagerV1 extends JwtTokenManagerV1 { /** * ICP Token Manager Service * - * Retreives, stores, and refreshes ICP tokens. + * Retreives and stores ICP access tokens. * * @param {Object} options * @param {String} options.username diff --git a/auth/jwt-token-manager-v1.ts b/auth/jwt-token-manager-v1.ts index 9ee0a667f..ddf765b7b 100644 --- a/auth/jwt-token-manager-v1.ts +++ b/auth/jwt-token-manager-v1.ts @@ -39,7 +39,7 @@ export class JwtTokenManagerV1 { /** * Token Manager Service * - * Retreives, stores, and refreshes JSON web tokens. + * Retreives and stores JSON web tokens. * * @param {Object} options * @param {String} options.url - url of the api to retrieve tokens from From dc3165d4e40f3de6a95ab7d9cc1b19c2d1e3eef1 Mon Sep 17 00:00:00 2001 From: Dustin Popp Date: Wed, 5 Jun 2019 12:58:05 -0500 Subject: [PATCH 18/18] refactor: add parameter `icp4d_url` --- auth/icp4d-token-manager-v1.ts | 3 +- lib/base_service.ts | 21 ++++++++++---- test/unit/baseService.test.js | 28 ++++++++++++++++++- ...1.test.js => icp4dTokenManager.v1.test.js} | 6 +++- 4 files changed, 50 insertions(+), 8 deletions(-) rename test/unit/{icpTokenManager.v1.test.js => icp4dTokenManager.v1.test.js} (90%) diff --git a/auth/icp4d-token-manager-v1.ts b/auth/icp4d-token-manager-v1.ts index 3698e7b45..e62cc53ba 100644 --- a/auth/icp4d-token-manager-v1.ts +++ b/auth/icp4d-token-manager-v1.ts @@ -65,7 +65,8 @@ export class Icp4dTokenManagerV1 extends JwtTokenManagerV1 { if (this.url) { this.url = this.url + '/v1/preauth/validateAuth'; - } else { + } else if (!this.userAccessToken) { + // url is not needed if the user specifies their own access token throw new Error('`url` is a required parameter for Icp4dTokenManagerV1'); } diff --git a/lib/base_service.ts b/lib/base_service.ts index 492576c97..15297a6b9 100644 --- a/lib/base_service.ts +++ b/lib/base_service.ts @@ -36,8 +36,9 @@ export interface UserOptions { use_unauthenticated?: boolean; headers?: HeaderOptions; token?: string; - iam_access_token?: string; icp4d_access_token?: string; + icp4d_url?: string; + iam_access_token?: string; iam_apikey?: string; iam_url?: string; iam_client_id?: string; @@ -57,8 +58,9 @@ export interface Credentials { username?: string; password?: string; url?: string; - iam_access_token?: string; icp4d_access_token?: string; + icp4d_url?: string; + iam_access_token?: string; iam_apikey?: string; iam_url?: string; authentication_type?: string; @@ -137,7 +139,8 @@ export class BaseService { * @param {string} [options.iam_url] - url for iam service api, needed for services in staging * @param {string} [options.iam_client_id] - client id (username) for request to iam service * @param {string} [options.iam_client_secret] - secret (password) for request to iam service - * @param {string} [options.icp4d_access_token] - icp access token provided and managed by user + * @param {string} [options.icp4d_access_token] - icp for data access token provided and managed by user + * @param {string} [options.icp4d_url] - icp for data base url - used for authentication * @param {string} [options.authentication_type] - authentication pattern to be used. can be iam, basic, or icp4d * @param {string} [options.username] - required unless use_unauthenticated is set * @param {string} [options.password] - required unless use_unauthenticated is set @@ -196,8 +199,11 @@ export class BaseService { iamClientSecret: _options.iam_client_secret, }); } else if (isForICP4D(_options)) { + if (!_options.icp4d_url && !_options.icp4d_access_token) { + throw new Error('`icp4d_url` is required when using an SDK-managed token for ICP4D.'); + } this.tokenManager = new Icp4dTokenManagerV1({ - url: _options.url, + url: _options.icp4d_url, username: _options.username, password: _options.password, accessToken: _options.icp4d_access_token, @@ -240,6 +246,9 @@ export class BaseService { if (this._options.icp4d_access_token) { credentials.icp4d_access_token = this._options.icp4d_access_token; } + if (this._options.icp4d_url) { + credentials.icp4d_url = this._options.icp4d_url; + } if (this._options.authentication_type) { credentials.authentication_type = this._options.authentication_type; } @@ -264,7 +273,7 @@ export class BaseService { } else if (this._options.authentication_type === 'icp4d') { this.tokenManager = new Icp4dTokenManagerV1({ accessToken: access_token, - url: this._options.url, + url: this._options.icp4d_url, disableSslVerification: this._options.disable_ssl_verification, }); } else { @@ -413,6 +422,7 @@ export class BaseService { const iamApiKey: string = envObj[`${_name}_IAM_APIKEY`] || envObj[`${nameWithUnderscore}_IAM_APIKEY`]; const iamUrl: string = envObj[`${_name}_IAM_URL`] || envObj[`${nameWithUnderscore}_IAM_URL`]; const icp4dAccessToken: string = envObj[`${_name}_ICP4D_ACCESS_TOKEN`] || envObj[`${nameWithUnderscore}_ICP4D_ACCESS_TOKEN`]; + const icp4dUrl: string = envObj[`${_name}_ICP4D_URL`] || envObj[`${nameWithUnderscore}_ICP4D_URL`]; const authenticationType: string = envObj[`${_name}_AUTHENTICATION_TYPE`] || envObj[`${nameWithUnderscore}_AUTHENTICATION_TYPE`]; return { @@ -423,6 +433,7 @@ export class BaseService { iam_apikey: iamApiKey, iam_url: iamUrl, icp4d_access_token: icp4dAccessToken, + icp4d_url: icp4dUrl, authentication_type: authenticationType, }; } diff --git a/test/unit/baseService.test.js b/test/unit/baseService.test.js index a4cd04f94..8b2d55caf 100644 --- a/test/unit/baseService.test.js +++ b/test/unit/baseService.test.js @@ -109,6 +109,7 @@ describe('BaseService', function() { iam_apikey: 'test', iam_url: 'test', icp4d_access_token: 'test', + icp4d_url: 'test', authentication_type: 'test', }); const creds = instance.getServiceCredentials(); @@ -120,6 +121,7 @@ describe('BaseService', function() { expect(creds.iam_apikey).toBeDefined(); expect(creds.iam_url).toBeDefined(); expect(creds.icp4d_access_token).toBeDefined(); + expect(creds.icp4d_url).toBeDefined(); expect(creds.authentication_type).toBeDefined(); }); @@ -143,6 +145,7 @@ describe('BaseService', function() { process.env.TEST_IAM_APIKEY = 'test'; process.env.TEST_IAM_URL = 'test'; process.env.TEST_ICP4D_ACCESS_TOKEN = 'test'; + process.env.TEST_ICP4D_URL = 'test'; process.env.TEST_AUTHENTICATION_TYPE = 'test'; const instance = new TestService(); @@ -155,6 +158,7 @@ describe('BaseService', function() { iam_apikey: 'test', iam_url: 'test', icp4d_access_token: 'test', + icp4d_url: 'test', authentication_type: 'test', }; expect(actual).toEqual(expected); @@ -428,7 +432,8 @@ describe('BaseService', function() { authentication_type: 'ICP4D', // using all caps to prove case insensitivity username: 'test', password: 'test', - url: 'service.com', + url: 'service.com/api', + icp4d_url: 'host.com:1234', }); expect(instance.tokenManager).toBeDefined(); expect(instance.tokenManager).not.toBeNull(); @@ -445,6 +450,27 @@ describe('BaseService', function() { expect(instance._options.headers).toBeUndefined(); }); + it('should throw an error if an icp4d url is not given when using sdk-managed tokens', function() { + expect(() => { + new TestService({ + username: 'test', + password: 'test', + authentication_type: 'icp4d', + url: 'service.com', + }); + }).toThrow(); + }); + + it('should not throw an error if an icp4d url is missing when using user-managed tokens', function() { + const instance = new TestService({ + icp4d_access_token: 'test', + url: 'service.com', + }); + expect(instance.tokenManager).toBeDefined(); + expect(instance.tokenManager).not.toBeNull(); + expect(instance._options.headers).toBeUndefined(); + }); + it('should not create a basic auth header if iam creds are given', function() { const apikey = 'abcd-1234'; const instance = new TestService({ diff --git a/test/unit/icpTokenManager.v1.test.js b/test/unit/icp4dTokenManager.v1.test.js similarity index 90% rename from test/unit/icpTokenManager.v1.test.js rename to test/unit/icp4dTokenManager.v1.test.js index b34d6dabc..b37fbddb8 100644 --- a/test/unit/icpTokenManager.v1.test.js +++ b/test/unit/icp4dTokenManager.v1.test.js @@ -13,7 +13,7 @@ RequestWrapper.mockImplementation(() => { }; }); -describe('iam_token_manager_v1', () => { +describe('icp4d_token_manager_v1', () => { describe('constructor', () => { it('should initialize base variables', () => { const instance = new Icp4dTokenManagerV1({ @@ -43,6 +43,10 @@ describe('iam_token_manager_v1', () => { it('should throw an error if `url` is not given', () => { expect(() => new Icp4dTokenManagerV1()).toThrow(); }); + + it('should not throw an error if `url` is not given but using user-managed access token', () => { + expect(() => new Icp4dTokenManagerV1({ accessToken: 'token' })).not.toThrow(); + }); }); describe('requestToken', () => {