@webex/webex-core 3.0.0-beta.274 → 3.0.0-beta.276
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/batcher.js +1 -1
- package/dist/lib/constants.js +14 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/credentials/credentials.js +45 -22
- package/dist/lib/credentials/credentials.js.map +1 -1
- package/dist/lib/credentials/scope.js +21 -6
- package/dist/lib/credentials/scope.js.map +1 -1
- package/dist/lib/credentials/token.js +1 -1
- package/dist/lib/services/services.js +1 -1
- package/dist/plugins/logger.js +1 -1
- package/dist/webex-core.js +2 -2
- package/package.json +14 -14
- package/src/lib/constants.js +6 -0
- package/src/lib/credentials/credentials.js +63 -40
- package/src/lib/credentials/scope.js +19 -2
- package/test/unit/spec/credentials/credentials.js +140 -13
- package/test/unit/spec/credentials/scope.js +55 -0
- package/test/unit/spec/interceptors/auth.js +3 -0
package/dist/lib/batcher.js
CHANGED
|
@@ -282,7 +282,7 @@ var Batcher = _webexPlugin.default.extend({
|
|
|
282
282
|
fingerprintResponse: function fingerprintResponse(item) {
|
|
283
283
|
throw new Error('fingerprintResponse() must be implemented');
|
|
284
284
|
},
|
|
285
|
-
version: "3.0.0-beta.
|
|
285
|
+
version: "3.0.0-beta.276"
|
|
286
286
|
});
|
|
287
287
|
var _default2 = Batcher;
|
|
288
288
|
exports.default = _default2;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
4
|
+
_Object$defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.METRICS = void 0;
|
|
8
|
+
// Metric to do with WDM registration
|
|
9
|
+
var METRICS = {
|
|
10
|
+
JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED: 'JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED',
|
|
11
|
+
JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH: 'JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH'
|
|
12
|
+
};
|
|
13
|
+
exports.METRICS = METRICS;
|
|
14
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["METRICS","JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED","JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH"],"sources":["constants.js"],"sourcesContent":["// Metric to do with WDM registration\nexport const METRICS = {\n JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED: 'JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED',\n JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH:\n 'JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH',\n};\n"],"mappings":";;;;;;;AAAA;AACO,IAAMA,OAAO,GAAG;EACrBC,mCAAmC,EAAE,qCAAqC;EAC1EC,+CAA+C,EAC7C;AACJ,CAAC;AAAC"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _typeof = require("@babel/runtime-corejs2/helpers/typeof");
|
|
3
4
|
var _Object$keys2 = require("@babel/runtime-corejs2/core-js/object/keys");
|
|
4
5
|
var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs2/core-js/object/get-own-property-symbols");
|
|
5
6
|
var _Object$getOwnPropertyDescriptor2 = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
|
|
6
7
|
var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptors");
|
|
7
8
|
var _Object$defineProperties = require("@babel/runtime-corejs2/core-js/object/define-properties");
|
|
8
9
|
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
10
|
+
var _WeakMap = require("@babel/runtime-corejs2/core-js/weak-map");
|
|
9
11
|
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
10
12
|
_Object$defineProperty(exports, "__esModule", {
|
|
11
13
|
value: true
|
|
@@ -31,11 +33,14 @@ var _common = require("@webex/common");
|
|
|
31
33
|
var _commonTimers = require("@webex/common-timers");
|
|
32
34
|
var _webexPlugin = _interopRequireDefault(require("../webex-plugin"));
|
|
33
35
|
var _decorators = require("../storage/decorators");
|
|
34
|
-
var _grantErrors =
|
|
36
|
+
var _grantErrors = _interopRequireWildcard(require("./grant-errors"));
|
|
35
37
|
var _scope = require("./scope");
|
|
36
38
|
var _token = _interopRequireDefault(require("./token"));
|
|
37
39
|
var _tokenCollection = _interopRequireDefault(require("./token-collection"));
|
|
40
|
+
var _constants = require("../constants");
|
|
38
41
|
var _dec, _dec2, _dec3, _dec4, _dec5, _dec6, _obj;
|
|
42
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof _WeakMap !== "function") return null; var cacheBabelInterop = new _WeakMap(); var cacheNodeInterop = new _WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
43
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = _Object$defineProperty && _Object$getOwnPropertyDescriptor2; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? _Object$getOwnPropertyDescriptor2(obj, key) : null; if (desc && (desc.get || desc.set)) { _Object$defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
39
44
|
function ownKeys(object, enumerableOnly) { var keys = _Object$keys2(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return _Object$getOwnPropertyDescriptor2(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
40
45
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor2(source, key)); }); } return target; }
|
|
41
46
|
/**
|
|
@@ -268,8 +273,16 @@ var Credentials = _webexPlugin.default.extend((_dec = (0, _common.oneFlight)({
|
|
|
268
273
|
downscope: function downscope(scope) {
|
|
269
274
|
var _this2 = this;
|
|
270
275
|
return this.supertoken.downscope(scope).catch(function (reason) {
|
|
271
|
-
|
|
276
|
+
var _reason$body;
|
|
277
|
+
var failReason = (_reason$body = reason === null || reason === void 0 ? void 0 : reason.body) !== null && _reason$body !== void 0 ? _reason$body : reason;
|
|
278
|
+
_this2.logger.warn("credentials: failed to downscope supertoken to \"".concat(scope, "\""), failReason);
|
|
272
279
|
_this2.logger.trace("credentials: falling back to supertoken for ".concat(scope));
|
|
280
|
+
_this2.webex.internal.metrics.submitClientMetrics(_constants.METRICS.JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED, {
|
|
281
|
+
fields: {
|
|
282
|
+
requestedScope: scope,
|
|
283
|
+
failReason: failReason
|
|
284
|
+
}
|
|
285
|
+
});
|
|
273
286
|
return _promise.default.resolve(new _token.default(_objectSpread({
|
|
274
287
|
scope: scope
|
|
275
288
|
}, _this2.supertoken.serialize())), {
|
|
@@ -341,10 +354,10 @@ var Credentials = _webexPlugin.default.extend((_dec = (0, _common.oneFlight)({
|
|
|
341
354
|
return _promise.default.reject(new Error('Current state cannot produce an access token'));
|
|
342
355
|
}
|
|
343
356
|
if (!scope) {
|
|
344
|
-
scope = (0, _scope.filterScope)('spark:kms', _this4.
|
|
357
|
+
scope = (0, _scope.filterScope)('spark:kms', _this4.supertoken.scope);
|
|
345
358
|
}
|
|
346
359
|
scope = (0, _scope.sortScope)(scope);
|
|
347
|
-
if (scope === (0, _scope.sortScope)(_this4.
|
|
360
|
+
if (scope === (0, _scope.sortScope)(_this4.supertoken.scope)) {
|
|
348
361
|
return _promise.default.resolve(_this4.supertoken);
|
|
349
362
|
}
|
|
350
363
|
var token = _this4.userTokens.get(scope);
|
|
@@ -476,15 +489,40 @@ var Credentials = _webexPlugin.default.extend((_dec = (0, _common.oneFlight)({
|
|
|
476
489
|
if (this.webex.internal.services) {
|
|
477
490
|
this.webex.internal.services.updateCredentialsConfig();
|
|
478
491
|
}
|
|
479
|
-
return supertoken.refresh().
|
|
492
|
+
return supertoken.refresh().catch(function (error) {
|
|
493
|
+
if (error instanceof _grantErrors.OAuthError) {
|
|
494
|
+
// Error: super token refresh failed with 400 status code.
|
|
495
|
+
// Hence emit an event to the client, an opportunity to logout.
|
|
496
|
+
_this6.unset('supertoken');
|
|
497
|
+
while (_this6.userTokens.models.length) {
|
|
498
|
+
try {
|
|
499
|
+
_this6.userTokens.remove(_this6.userTokens.models[0]);
|
|
500
|
+
} catch (err) {
|
|
501
|
+
_this6.logger.warn('credentials: failed to remove user token', err);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
_this6.webex.trigger('client:InvalidRequestError');
|
|
505
|
+
}
|
|
506
|
+
return _promise.default.reject(error);
|
|
507
|
+
}).then(function (st) {
|
|
480
508
|
// clear refresh timer
|
|
481
509
|
if (_this6.refreshTimer) {
|
|
482
510
|
clearTimeout(_this6.refreshTimer);
|
|
483
511
|
_this6.unset('refreshTimer');
|
|
484
512
|
}
|
|
485
513
|
_this6.supertoken = st;
|
|
514
|
+
var invalidScopes = (0, _scope.diffScopes)(_this6.config.scope, st.scope);
|
|
515
|
+
if (invalidScopes !== '') {
|
|
516
|
+
_this6.logger.warn("credentials: \"".concat(invalidScopes, "\" scope(s) are invalid because not listed in the supertoken, they will be excluded from user token requests."));
|
|
517
|
+
_this6.webex.internal.metrics.submitClientMetrics(_constants.METRICS.JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH, {
|
|
518
|
+
fields: {
|
|
519
|
+
invalidScopes: invalidScopes
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
}
|
|
486
523
|
return _promise.default.all(tokens.map(function (token) {
|
|
487
|
-
|
|
524
|
+
var tokenScope = (0, _scope.filterScope)((0, _scope.diffScopes)(token.scope, st.scope), token.scope);
|
|
525
|
+
return _this6.downscope(tokenScope)
|
|
488
526
|
// eslint-disable-next-line max-nested-callbacks
|
|
489
527
|
.then(function (t) {
|
|
490
528
|
_this6.logger.info("credentials: revoking token for ".concat(token.scope));
|
|
@@ -498,21 +536,6 @@ var Credentials = _webexPlugin.default.extend((_dec = (0, _common.oneFlight)({
|
|
|
498
536
|
}));
|
|
499
537
|
}).then(function () {
|
|
500
538
|
_this6.scheduleRefresh(_this6.supertoken.expires);
|
|
501
|
-
}).catch(function (error) {
|
|
502
|
-
var InvalidRequestError = _grantErrors.default.InvalidRequestError;
|
|
503
|
-
if (error instanceof InvalidRequestError) {
|
|
504
|
-
// Error: The refresh token provided is expired, revoked, malformed, or invalid. Hence emit an event to the client, an opportunity to logout.
|
|
505
|
-
_this6.unset('supertoken');
|
|
506
|
-
while (_this6.userTokens.models.length) {
|
|
507
|
-
try {
|
|
508
|
-
_this6.userTokens.remove(_this6.userTokens.models[0]);
|
|
509
|
-
} catch (err) {
|
|
510
|
-
_this6.logger.warn('credentials: failed to remove user token', err);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
_this6.webex.trigger('client:InvalidRequestError');
|
|
514
|
-
}
|
|
515
|
-
return _promise.default.reject(error);
|
|
516
539
|
});
|
|
517
540
|
},
|
|
518
541
|
/**
|
|
@@ -535,7 +558,7 @@ var Credentials = _webexPlugin.default.extend((_dec = (0, _common.oneFlight)({
|
|
|
535
558
|
this.refresh();
|
|
536
559
|
}
|
|
537
560
|
},
|
|
538
|
-
version: "3.0.0-beta.
|
|
561
|
+
version: "3.0.0-beta.276"
|
|
539
562
|
}, ((0, _applyDecoratedDescriptor2.default)(_obj, "getUserToken", [_dec, _dec2], (0, _getOwnPropertyDescriptor.default)(_obj, "getUserToken"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "initialize", [_dec3], (0, _getOwnPropertyDescriptor.default)(_obj, "initialize"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "invalidate", [_common.oneFlight, _dec4], (0, _getOwnPropertyDescriptor.default)(_obj, "invalidate"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "refresh", [_common.oneFlight, _dec5, _dec6], (0, _getOwnPropertyDescriptor.default)(_obj, "refresh"), _obj)), _obj)));
|
|
540
563
|
var _default = Credentials;
|
|
541
564
|
exports.default = _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Credentials","WebexPlugin","extend","oneFlight","keyFactory","scope","waitForValue","persist","whileInFlight","collections","userTokens","TokenCollection","dataTypes","token","makeStateDataType","Token","dataType","derived","canAuthorize","deps","fn","Boolean","supertoken","canRefresh","config","jwtRefreshCallback","isUnverifiedGuest","isGuest","JSON","parse","base64","decode","access_token","split","user_type","props","prop","namespace","session","isRefreshing","default","type","ready","refreshTimer","undefined","buildLoginUrl","options","clientType","state","Error","client_id","redirect_uri","response_type","toBase64Url","authorizeUrl","querystring","stringify","getOrgId","logger","info","extractOrgIdFromJWT","e","extractOrgIdFromUserToken","f","decodedJWT","jwt","realm","fields","length","buildLogoutUrl","logoutUrl","cisService","service","goto","calcRefreshTimeout","expiration","Math","floor","random","constructor","_dataTypes","forEach","key","set","bind","args","downscope","catch","reason","trace","resolve","serialize","parent","getClientToken","webex","request","method","uri","tokenUrl","form","grant_type","self_contained_token","auth","user","pass","client_secret","sendImmediately","shouldRefreshAccessToken","then","res","body","statusCode","reject","ErrorConstructor","grantErrors","select","error","_res","getUserToken","once","filterScope","sortScope","get","tap","t","add","initialize","attrs","authorization","expires","scheduleRefresh","prototype","listenToOnce","authorizationString","parsed","url","query","href","substr","indexOf","invalidate","clearTimeout","unset","err","warn","models","remove","refresh","tokens","requestAccessTokenFromJwt","internal","services","updateCredentialsConfig","st","all","map","revoke","InvalidRequestError","trigger","expiresIn","timeoutLength","safeSetTimeout"],"sources":["credentials.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport querystring from 'querystring';\nimport url from 'url';\n\nimport jwt from 'jsonwebtoken';\nimport {base64, makeStateDataType, oneFlight, tap, whileInFlight} from '@webex/common';\nimport {safeSetTimeout} from '@webex/common-timers';\nimport {clone, cloneDeep, isObject, isEmpty} from 'lodash';\n\nimport WebexPlugin from '../webex-plugin';\nimport {persist, waitForValue} from '../storage/decorators';\n\nimport grantErrors from './grant-errors';\nimport {filterScope, sortScope} from './scope';\nimport Token from './token';\nimport TokenCollection from './token-collection';\n\n/**\n * @class\n */\nconst Credentials = WebexPlugin.extend({\n collections: {\n userTokens: TokenCollection,\n },\n\n dataTypes: {\n token: makeStateDataType(Token, 'token').dataType,\n },\n\n derived: {\n canAuthorize: {\n deps: ['supertoken', 'supertoken.canAuthorize', 'canRefresh'],\n fn() {\n return Boolean((this.supertoken && this.supertoken.canAuthorize) || this.canRefresh);\n },\n },\n canRefresh: {\n deps: ['supertoken', 'supertoken.canRefresh'],\n fn() {\n // If we're operating in JWT mode, we have to delegate to the consumer\n if (this.config.jwtRefreshCallback) {\n return true;\n }\n\n return Boolean(this.supertoken && this.supertoken.canRefresh);\n },\n },\n isUnverifiedGuest: {\n deps: ['supertoken'],\n /**\n * Returns true if the user is an unverified guest\n * @returns {boolean}\n */\n fn() {\n let isGuest = false;\n try {\n isGuest =\n JSON.parse(base64.decode(this.supertoken.access_token.split('.')[1])).user_type ===\n 'guest';\n } catch {\n /* the non-guest token is formatted differently so catch is expected */\n }\n\n return isGuest;\n },\n },\n },\n\n props: {\n supertoken: makeStateDataType(Token, 'token').prop,\n },\n\n namespace: 'Credentials',\n\n session: {\n isRefreshing: {\n default: false,\n type: 'boolean',\n },\n /**\n * Becomes `true` once the {@link loaded} event fires.\n * @see {@link WebexPlugin#ready}\n * @instance\n * @memberof Credentials\n * @type {boolean}\n */\n ready: {\n default: false,\n type: 'boolean',\n },\n refreshTimer: {\n default: undefined,\n type: 'any',\n },\n },\n\n /**\n * Generates an OAuth Login URL. Prefers the api.ciscospark.com proxy if the\n * instance is initialize with an authorizatUrl, but fallsback to idbroker\n * as the base otherwise.\n * @instance\n * @memberof Credentials\n * @param {Object} [options={}]\n * @returns {string}\n */\n buildLoginUrl(options = {clientType: 'public'}) {\n /* eslint-disable camelcase */\n if (options.state && !isObject(options.state)) {\n throw new Error('if specified, `options.state` must be an object');\n }\n\n options.client_id = this.config.client_id;\n options.redirect_uri = this.config.redirect_uri;\n options.scope = this.config.scope;\n\n options = cloneDeep(options);\n\n if (!options.response_type) {\n options.response_type = options.clientType === 'public' ? 'token' : 'code';\n }\n Reflect.deleteProperty(options, 'clientType');\n\n if (options.state) {\n if (!isEmpty(options.state)) {\n options.state = base64.toBase64Url(JSON.stringify(options.state));\n } else {\n delete options.state;\n }\n }\n\n return `${this.config.authorizeUrl}?${querystring.stringify(options)}`;\n /* eslint-enable camelcase */\n },\n\n /**\n * Get the determined OrgId.\n *\n * @throws {Error} - If the OrgId could not be determined.\n * @returns {string} - The OrgId.\n */\n getOrgId() {\n this.logger.info('credentials: attempting to retrieve the OrgId from token');\n\n try {\n // Attempt to extract a client-authenticated token's OrgId.\n this.logger.info('credentials: trying to extract OrgId from JWT');\n\n return this.extractOrgIdFromJWT(this.supertoken.access_token);\n } catch (e) {\n // Attempt to extract a user token's OrgId.\n this.logger.info('credentials: could not extract OrgId from JWT');\n this.logger.info('credentials: attempting to extract OrgId from user token');\n\n try {\n return this.extractOrgIdFromUserToken(this.supertoken?.access_token);\n } catch (f) {\n this.logger.info('credentials: could not extract OrgId from user token');\n throw f;\n }\n }\n },\n\n /**\n * Extract the OrgId [realm] from a provided JWT.\n *\n * @private\n * @param {string} token - The JWT to extract the OrgId from.\n * @throws {Error} - If the token does not pass JWT general/realm validation.\n * @returns {string} - The OrgId.\n */\n extractOrgIdFromJWT(token = '') {\n // Decoded the provided token.\n const decodedJWT = jwt.decode(token);\n\n // Validate that the provided token is a JWT.\n if (!decodedJWT) {\n throw new Error('unable to extract the OrgId from the provided JWT');\n }\n\n if (!decodedJWT.realm) {\n throw new Error('the provided JWT does not contain an OrgId');\n }\n\n // Return the OrgId [realm].\n return decodedJWT.realm;\n },\n\n /**\n * Extract the OrgId [realm] from a provided user token.\n *\n * @private\n * @param {string} token - The user token to extract the OrgId from.\n * @throws {Error} - Will throw an error if the provided token is invalid.\n * @returns {string} - The OrgId.\n */\n extractOrgIdFromUserToken(token = '') {\n // Split the provided token into subsections.\n const fields = token.split('_');\n\n // Validate that the provided token has the proper amount of sections.\n if (fields.length !== 3) {\n throw new Error('the provided token is not a valid format');\n }\n\n // Return the token section that contains the OrgId.\n return fields[2];\n },\n\n /**\n * Generates a Logout URL\n * @instance\n * @memberof Credentials\n * @param {Object} [options={}]\n * @returns {[type]}\n */\n buildLogoutUrl(options = {}) {\n return `${this.config.logoutUrl}?${querystring.stringify({\n cisService: this.config.service,\n goto: this.config.redirect_uri,\n ...options,\n })}`;\n },\n\n /**\n * Generates a number between 60% - 90% of expired value\n * @instance\n * @memberof Credentials\n * @param {number} expiration\n * @private\n * @returns {number}\n */\n calcRefreshTimeout(expiration) {\n return Math.floor(((Math.floor(Math.random() * 4) + 6) / 10) * expiration);\n },\n\n constructor(...args) {\n // HACK to deal with the fact that AmpersandState#dataTypes#set is a pure\n // function.\n this._dataTypes = cloneDeep(this._dataTypes);\n Object.keys(this._dataTypes).forEach((key) => {\n if (this._dataTypes[key].set) {\n this._dataTypes[key].set = this._dataTypes[key].set.bind(this);\n }\n });\n // END HACK\n Reflect.apply(WebexPlugin, this, args);\n },\n\n /**\n * Downscopes a token\n * @instance\n * @memberof Credentials\n * @param {string} scope\n * @private\n * @returns {Promise<Token>}\n */\n downscope(scope) {\n return this.supertoken.downscope(scope).catch((reason) => {\n this.logger.trace(`credentials: failed to downscope supertoken to ${scope}`, reason);\n this.logger.trace(`credentials: falling back to supertoken for ${scope}`);\n\n return Promise.resolve(new Token({scope, ...this.supertoken.serialize()}), {\n parent: this,\n });\n });\n },\n\n /**\n * Requests a client credentials grant and returns the token. Given the\n * limited use for such tokens as this time, this method does not cache its\n * token.\n * @instance\n * @memberof Credentials\n * @param {Object} options\n * @returns {Promise<Token>}\n */\n getClientToken(options = {}) {\n this.logger.info('credentials: requesting client credentials grant');\n\n return this.webex\n .request({\n /* eslint-disable camelcase */\n method: 'POST',\n uri: options.uri || this.config.tokenUrl,\n form: {\n grant_type: 'client_credentials',\n scope: options.scope || 'webexsquare:admin',\n self_contained_token: true,\n },\n auth: {\n user: this.config.client_id,\n pass: this.config.client_secret,\n sendImmediately: true,\n },\n shouldRefreshAccessToken: false,\n /* eslint-enable camelcase */\n })\n .then((res) => new Token(res.body, {parent: this}))\n .catch((res) => {\n if (res.statusCode !== 400) {\n return Promise.reject(res);\n }\n\n const ErrorConstructor = grantErrors.select(res.body.error);\n\n return Promise.reject(new ErrorConstructor(res._res || res));\n });\n },\n\n @oneFlight({keyFactory: (scope) => scope})\n @waitForValue('@')\n /**\n * Resolves with a token with the specified scopes. If no scope is specified,\n * defaults to omit(webex.credentials.scope, 'spark:kms'). If no such token is\n * available, downscopes the supertoken to that scope.\n * @instance\n * @memberof Credentials\n * @param {string} scope\n * @returns {Promise<Token>}\n */\n getUserToken(scope) {\n return Promise.resolve(\n !this.isRefreshing ||\n new Promise((resolve) => {\n this.logger.info(\n 'credentials: token refresh inflight; delaying getUserToken until refresh completes'\n );\n this.once('change:isRefreshing', () => {\n this.logger.info('credentials: token refresh complete; reinvoking getUserToken');\n resolve();\n });\n })\n ).then(() => {\n if (!this.canAuthorize) {\n this.logger.info('credentials: cannot produce an access token from current state');\n\n return Promise.reject(new Error('Current state cannot produce an access token'));\n }\n\n if (!scope) {\n scope = filterScope('spark:kms', this.config.scope);\n }\n\n scope = sortScope(scope);\n\n if (scope === sortScope(this.config.scope)) {\n return Promise.resolve(this.supertoken);\n }\n\n const token = this.userTokens.get(scope);\n\n // we should also check for the token.access_token since token object does\n // not get cleared on unsetting while logging out.\n if (!token || !token.access_token) {\n return this.downscope(scope).then(tap((t) => this.userTokens.add(t)));\n }\n\n return Promise.resolve(token);\n });\n },\n\n @persist('@')\n /**\n * Initializer\n * @instance\n * @memberof Credentials\n * @param {Object} attrs\n * @param {Object} options\n * @private\n * @returns {Credentials}\n */\n initialize(attrs, options) {\n if (attrs) {\n if (typeof attrs === 'string') {\n this.supertoken = attrs;\n }\n\n if (attrs.access_token) {\n this.supertoken = attrs;\n }\n\n if (attrs.authorization) {\n if (attrs.authorization.supertoken) {\n this.supertoken = attrs.authorization.supertoken;\n } else {\n this.supertoken = attrs.authorization;\n }\n }\n\n // schedule refresh\n if (this.supertoken && this.supertoken.expires) {\n this.scheduleRefresh(this.supertoken.expires);\n }\n }\n\n Reflect.apply(WebexPlugin.prototype.initialize, this, [attrs, options]);\n\n this.listenToOnce(this.parent, 'change:config', () => {\n if (this.config.authorizationString) {\n const parsed = url.parse(this.config.authorizationString, true);\n\n /* eslint-disable camelcase */\n this.config.client_id = parsed.query.client_id;\n this.config.redirect_uri = parsed.query.redirect_uri;\n this.config.scope = parsed.query.scope;\n this.config.authorizeUrl = parsed.href.substr(0, parsed.href.indexOf('?'));\n /* eslint-enable camelcase */\n }\n });\n\n this.webex.once('loaded', () => {\n this.ready = true;\n });\n },\n\n @oneFlight\n @waitForValue('@')\n /**\n * Clears all tokens from store them from the stores.\n *\n * This is no longer quite the right name for this method, but all of the\n * alternatives I'm coming up with are already taken.\n * @instance\n * @memberof Credentials\n * @returns {Promise}\n */\n invalidate() {\n this.logger.info('credentials: invalidating tokens');\n\n // clear refresh timer\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.unset('refreshTimer');\n }\n\n try {\n this.unset('supertoken');\n } catch (err) {\n this.logger.warn('credentials: failed to clear supertoken', err);\n }\n\n while (this.userTokens.models.length) {\n try {\n this.userTokens.remove(this.userTokens.models[0]);\n } catch (err) {\n this.logger.warn('credentials: failed to remove user token', err);\n }\n }\n\n this.logger.info('credentials: finished removing tokens');\n\n // Return a promise to give the storage layer a tick or two to clear\n // localStorage\n return Promise.resolve();\n },\n\n @oneFlight\n @whileInFlight('isRefreshing')\n @waitForValue('@')\n /**\n * Removes the supertoken and child tokens, then refreshes the supertoken;\n * subsequent calls to {@link Credentials#getUserToken()} will re-downscope\n * child tokens. Enqueus revocation of previous previousTokens. Yes, that's\n * the correct number of \"previous\"es.\n * @instance\n * @memberof Credentials\n * @returns {Promise}\n */\n refresh() {\n this.logger.info('credentials: refresh requested');\n\n const {supertoken} = this;\n const tokens = clone(this.userTokens.models);\n\n // This is kind of a leaky abstraction, since it relies on the authorization\n // plugin, but the only alternatives I see are\n // 1. put all JWT support in core\n // 2. have separate jwt and non-jwt auth plugins\n // while I like #2 from a code simplicity standpoint, the third-party DX\n // isn't great\n if (this.config.jwtRefreshCallback) {\n return (\n this.config\n .jwtRefreshCallback(this.webex)\n // eslint-disable-next-line no-shadow\n .then((jwt) => this.webex.authorization.requestAccessTokenFromJwt({jwt}))\n );\n }\n\n if (this.webex.internal.services) {\n this.webex.internal.services.updateCredentialsConfig();\n }\n\n return supertoken\n .refresh()\n .then((st) => {\n // clear refresh timer\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.unset('refreshTimer');\n }\n this.supertoken = st;\n\n return Promise.all(\n tokens.map((token) =>\n this.downscope(token.scope)\n // eslint-disable-next-line max-nested-callbacks\n .then((t) => {\n this.logger.info(`credentials: revoking token for ${token.scope}`);\n\n return token\n .revoke()\n .catch((err) => {\n this.logger.warn('credentials: failed to revoke user token', err);\n })\n .then(() => {\n this.userTokens.remove(token.scope);\n this.userTokens.add(t);\n });\n })\n )\n );\n })\n .then(() => {\n this.scheduleRefresh(this.supertoken.expires);\n })\n .catch((error) => {\n const {InvalidRequestError} = grantErrors;\n\n if (error instanceof InvalidRequestError) {\n // Error: The refresh token provided is expired, revoked, malformed, or invalid. Hence emit an event to the client, an opportunity to logout.\n this.unset('supertoken');\n while (this.userTokens.models.length) {\n try {\n this.userTokens.remove(this.userTokens.models[0]);\n } catch (err) {\n this.logger.warn('credentials: failed to remove user token', err);\n }\n }\n this.webex.trigger('client:InvalidRequestError');\n }\n\n return Promise.reject(error);\n });\n },\n\n /**\n * Schedules a token refresh or refreshes the token if token has expired\n * @instance\n * @memberof Credentials\n * @param {number} expires\n * @private\n * @returns {undefined}\n */\n scheduleRefresh(expires) {\n const expiresIn = expires - Date.now();\n\n if (expiresIn > 0) {\n const timeoutLength = this.calcRefreshTimeout(expiresIn);\n\n this.refreshTimer = safeSetTimeout(() => this.refresh(), timeoutLength);\n } else {\n this.refresh();\n }\n },\n});\n\nexport default Credentials;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["Credentials","WebexPlugin","extend","oneFlight","keyFactory","scope","waitForValue","persist","whileInFlight","collections","userTokens","TokenCollection","dataTypes","token","makeStateDataType","Token","dataType","derived","canAuthorize","deps","fn","Boolean","supertoken","canRefresh","config","jwtRefreshCallback","isUnverifiedGuest","isGuest","JSON","parse","base64","decode","access_token","split","user_type","props","prop","namespace","session","isRefreshing","default","type","ready","refreshTimer","undefined","buildLoginUrl","options","clientType","state","Error","client_id","redirect_uri","response_type","toBase64Url","authorizeUrl","querystring","stringify","getOrgId","logger","info","extractOrgIdFromJWT","e","extractOrgIdFromUserToken","f","decodedJWT","jwt","realm","fields","length","buildLogoutUrl","logoutUrl","cisService","service","goto","calcRefreshTimeout","expiration","Math","floor","random","constructor","_dataTypes","forEach","key","set","bind","args","downscope","catch","reason","failReason","body","warn","trace","webex","internal","metrics","submitClientMetrics","METRICS","JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED","requestedScope","resolve","serialize","parent","getClientToken","request","method","uri","tokenUrl","form","grant_type","self_contained_token","auth","user","pass","client_secret","sendImmediately","shouldRefreshAccessToken","then","res","statusCode","reject","ErrorConstructor","grantErrors","select","error","_res","getUserToken","once","filterScope","sortScope","get","tap","t","add","initialize","attrs","authorization","expires","scheduleRefresh","prototype","listenToOnce","authorizationString","parsed","url","query","href","substr","indexOf","invalidate","clearTimeout","unset","err","models","remove","refresh","tokens","requestAccessTokenFromJwt","services","updateCredentialsConfig","OAuthError","trigger","st","invalidScopes","diffScopes","JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH","all","map","tokenScope","revoke","expiresIn","timeoutLength","safeSetTimeout"],"sources":["credentials.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport querystring from 'querystring';\nimport url from 'url';\n\nimport jwt from 'jsonwebtoken';\nimport {base64, makeStateDataType, oneFlight, tap, whileInFlight} from '@webex/common';\nimport {safeSetTimeout} from '@webex/common-timers';\nimport {clone, cloneDeep, isObject, isEmpty} from 'lodash';\n\nimport WebexPlugin from '../webex-plugin';\nimport {persist, waitForValue} from '../storage/decorators';\n\nimport grantErrors, {OAuthError} from './grant-errors';\nimport {filterScope, diffScopes, sortScope} from './scope';\nimport Token from './token';\nimport TokenCollection from './token-collection';\nimport {METRICS} from '../constants';\n\n/**\n * @class\n */\nconst Credentials = WebexPlugin.extend({\n collections: {\n userTokens: TokenCollection,\n },\n\n dataTypes: {\n token: makeStateDataType(Token, 'token').dataType,\n },\n\n derived: {\n canAuthorize: {\n deps: ['supertoken', 'supertoken.canAuthorize', 'canRefresh'],\n fn() {\n return Boolean((this.supertoken && this.supertoken.canAuthorize) || this.canRefresh);\n },\n },\n canRefresh: {\n deps: ['supertoken', 'supertoken.canRefresh'],\n fn() {\n // If we're operating in JWT mode, we have to delegate to the consumer\n if (this.config.jwtRefreshCallback) {\n return true;\n }\n\n return Boolean(this.supertoken && this.supertoken.canRefresh);\n },\n },\n isUnverifiedGuest: {\n deps: ['supertoken'],\n /**\n * Returns true if the user is an unverified guest\n * @returns {boolean}\n */\n fn() {\n let isGuest = false;\n try {\n isGuest =\n JSON.parse(base64.decode(this.supertoken.access_token.split('.')[1])).user_type ===\n 'guest';\n } catch {\n /* the non-guest token is formatted differently so catch is expected */\n }\n\n return isGuest;\n },\n },\n },\n\n props: {\n supertoken: makeStateDataType(Token, 'token').prop,\n },\n\n namespace: 'Credentials',\n\n session: {\n isRefreshing: {\n default: false,\n type: 'boolean',\n },\n /**\n * Becomes `true` once the {@link loaded} event fires.\n * @see {@link WebexPlugin#ready}\n * @instance\n * @memberof Credentials\n * @type {boolean}\n */\n ready: {\n default: false,\n type: 'boolean',\n },\n refreshTimer: {\n default: undefined,\n type: 'any',\n },\n },\n\n /**\n * Generates an OAuth Login URL. Prefers the api.ciscospark.com proxy if the\n * instance is initialize with an authorizatUrl, but fallsback to idbroker\n * as the base otherwise.\n * @instance\n * @memberof Credentials\n * @param {Object} [options={}]\n * @returns {string}\n */\n buildLoginUrl(options = {clientType: 'public'}) {\n /* eslint-disable camelcase */\n if (options.state && !isObject(options.state)) {\n throw new Error('if specified, `options.state` must be an object');\n }\n\n options.client_id = this.config.client_id;\n options.redirect_uri = this.config.redirect_uri;\n options.scope = this.config.scope;\n\n options = cloneDeep(options);\n\n if (!options.response_type) {\n options.response_type = options.clientType === 'public' ? 'token' : 'code';\n }\n Reflect.deleteProperty(options, 'clientType');\n\n if (options.state) {\n if (!isEmpty(options.state)) {\n options.state = base64.toBase64Url(JSON.stringify(options.state));\n } else {\n delete options.state;\n }\n }\n\n return `${this.config.authorizeUrl}?${querystring.stringify(options)}`;\n /* eslint-enable camelcase */\n },\n\n /**\n * Get the determined OrgId.\n *\n * @throws {Error} - If the OrgId could not be determined.\n * @returns {string} - The OrgId.\n */\n getOrgId() {\n this.logger.info('credentials: attempting to retrieve the OrgId from token');\n\n try {\n // Attempt to extract a client-authenticated token's OrgId.\n this.logger.info('credentials: trying to extract OrgId from JWT');\n\n return this.extractOrgIdFromJWT(this.supertoken.access_token);\n } catch (e) {\n // Attempt to extract a user token's OrgId.\n this.logger.info('credentials: could not extract OrgId from JWT');\n this.logger.info('credentials: attempting to extract OrgId from user token');\n\n try {\n return this.extractOrgIdFromUserToken(this.supertoken?.access_token);\n } catch (f) {\n this.logger.info('credentials: could not extract OrgId from user token');\n throw f;\n }\n }\n },\n\n /**\n * Extract the OrgId [realm] from a provided JWT.\n *\n * @private\n * @param {string} token - The JWT to extract the OrgId from.\n * @throws {Error} - If the token does not pass JWT general/realm validation.\n * @returns {string} - The OrgId.\n */\n extractOrgIdFromJWT(token = '') {\n // Decoded the provided token.\n const decodedJWT = jwt.decode(token);\n\n // Validate that the provided token is a JWT.\n if (!decodedJWT) {\n throw new Error('unable to extract the OrgId from the provided JWT');\n }\n\n if (!decodedJWT.realm) {\n throw new Error('the provided JWT does not contain an OrgId');\n }\n\n // Return the OrgId [realm].\n return decodedJWT.realm;\n },\n\n /**\n * Extract the OrgId [realm] from a provided user token.\n *\n * @private\n * @param {string} token - The user token to extract the OrgId from.\n * @throws {Error} - Will throw an error if the provided token is invalid.\n * @returns {string} - The OrgId.\n */\n extractOrgIdFromUserToken(token = '') {\n // Split the provided token into subsections.\n const fields = token.split('_');\n\n // Validate that the provided token has the proper amount of sections.\n if (fields.length !== 3) {\n throw new Error('the provided token is not a valid format');\n }\n\n // Return the token section that contains the OrgId.\n return fields[2];\n },\n\n /**\n * Generates a Logout URL\n * @instance\n * @memberof Credentials\n * @param {Object} [options={}]\n * @returns {[type]}\n */\n buildLogoutUrl(options = {}) {\n return `${this.config.logoutUrl}?${querystring.stringify({\n cisService: this.config.service,\n goto: this.config.redirect_uri,\n ...options,\n })}`;\n },\n\n /**\n * Generates a number between 60% - 90% of expired value\n * @instance\n * @memberof Credentials\n * @param {number} expiration\n * @private\n * @returns {number}\n */\n calcRefreshTimeout(expiration) {\n return Math.floor(((Math.floor(Math.random() * 4) + 6) / 10) * expiration);\n },\n\n constructor(...args) {\n // HACK to deal with the fact that AmpersandState#dataTypes#set is a pure\n // function.\n this._dataTypes = cloneDeep(this._dataTypes);\n Object.keys(this._dataTypes).forEach((key) => {\n if (this._dataTypes[key].set) {\n this._dataTypes[key].set = this._dataTypes[key].set.bind(this);\n }\n });\n // END HACK\n Reflect.apply(WebexPlugin, this, args);\n },\n\n /**\n * Downscopes a token\n * @instance\n * @memberof Credentials\n * @param {string} scope\n * @private\n * @returns {Promise<Token>}\n */\n downscope(scope) {\n return this.supertoken.downscope(scope).catch((reason) => {\n const failReason = reason?.body ?? reason;\n this.logger.warn(`credentials: failed to downscope supertoken to \"${scope}\"`, failReason);\n this.logger.trace(`credentials: falling back to supertoken for ${scope}`);\n this.webex.internal.metrics.submitClientMetrics(METRICS.JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED, {\n fields: {\n requestedScope: scope,\n failReason,\n },\n });\n\n return Promise.resolve(new Token({scope, ...this.supertoken.serialize()}), {\n parent: this,\n });\n });\n },\n\n /**\n * Requests a client credentials grant and returns the token. Given the\n * limited use for such tokens as this time, this method does not cache its\n * token.\n * @instance\n * @memberof Credentials\n * @param {Object} options\n * @returns {Promise<Token>}\n */\n getClientToken(options = {}) {\n this.logger.info('credentials: requesting client credentials grant');\n\n return this.webex\n .request({\n /* eslint-disable camelcase */\n method: 'POST',\n uri: options.uri || this.config.tokenUrl,\n form: {\n grant_type: 'client_credentials',\n scope: options.scope || 'webexsquare:admin',\n self_contained_token: true,\n },\n auth: {\n user: this.config.client_id,\n pass: this.config.client_secret,\n sendImmediately: true,\n },\n shouldRefreshAccessToken: false,\n /* eslint-enable camelcase */\n })\n .then((res) => new Token(res.body, {parent: this}))\n .catch((res) => {\n if (res.statusCode !== 400) {\n return Promise.reject(res);\n }\n\n const ErrorConstructor = grantErrors.select(res.body.error);\n\n return Promise.reject(new ErrorConstructor(res._res || res));\n });\n },\n\n @oneFlight({keyFactory: (scope) => scope})\n @waitForValue('@')\n /**\n * Resolves with a token with the specified scopes. If no scope is specified,\n * defaults to omit(webex.credentials.scope, 'spark:kms'). If no such token is\n * available, downscopes the supertoken to that scope.\n * @instance\n * @memberof Credentials\n * @param {string} scope\n * @returns {Promise<Token>}\n */\n getUserToken(scope) {\n return Promise.resolve(\n !this.isRefreshing ||\n new Promise((resolve) => {\n this.logger.info(\n 'credentials: token refresh inflight; delaying getUserToken until refresh completes'\n );\n this.once('change:isRefreshing', () => {\n this.logger.info('credentials: token refresh complete; reinvoking getUserToken');\n resolve();\n });\n })\n ).then(() => {\n if (!this.canAuthorize) {\n this.logger.info('credentials: cannot produce an access token from current state');\n\n return Promise.reject(new Error('Current state cannot produce an access token'));\n }\n\n if (!scope) {\n scope = filterScope('spark:kms', this.supertoken.scope);\n }\n\n scope = sortScope(scope);\n\n if (scope === sortScope(this.supertoken.scope)) {\n return Promise.resolve(this.supertoken);\n }\n\n const token = this.userTokens.get(scope);\n\n // we should also check for the token.access_token since token object does\n // not get cleared on unsetting while logging out.\n if (!token || !token.access_token) {\n return this.downscope(scope).then(tap((t) => this.userTokens.add(t)));\n }\n\n return Promise.resolve(token);\n });\n },\n\n @persist('@')\n /**\n * Initializer\n * @instance\n * @memberof Credentials\n * @param {Object} attrs\n * @param {Object} options\n * @private\n * @returns {Credentials}\n */\n initialize(attrs, options) {\n if (attrs) {\n if (typeof attrs === 'string') {\n this.supertoken = attrs;\n }\n\n if (attrs.access_token) {\n this.supertoken = attrs;\n }\n\n if (attrs.authorization) {\n if (attrs.authorization.supertoken) {\n this.supertoken = attrs.authorization.supertoken;\n } else {\n this.supertoken = attrs.authorization;\n }\n }\n\n // schedule refresh\n if (this.supertoken && this.supertoken.expires) {\n this.scheduleRefresh(this.supertoken.expires);\n }\n }\n\n Reflect.apply(WebexPlugin.prototype.initialize, this, [attrs, options]);\n\n this.listenToOnce(this.parent, 'change:config', () => {\n if (this.config.authorizationString) {\n const parsed = url.parse(this.config.authorizationString, true);\n\n /* eslint-disable camelcase */\n this.config.client_id = parsed.query.client_id;\n this.config.redirect_uri = parsed.query.redirect_uri;\n this.config.scope = parsed.query.scope;\n this.config.authorizeUrl = parsed.href.substr(0, parsed.href.indexOf('?'));\n /* eslint-enable camelcase */\n }\n });\n\n this.webex.once('loaded', () => {\n this.ready = true;\n });\n },\n\n @oneFlight\n @waitForValue('@')\n /**\n * Clears all tokens from store them from the stores.\n *\n * This is no longer quite the right name for this method, but all of the\n * alternatives I'm coming up with are already taken.\n * @instance\n * @memberof Credentials\n * @returns {Promise}\n */\n invalidate() {\n this.logger.info('credentials: invalidating tokens');\n\n // clear refresh timer\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.unset('refreshTimer');\n }\n\n try {\n this.unset('supertoken');\n } catch (err) {\n this.logger.warn('credentials: failed to clear supertoken', err);\n }\n\n while (this.userTokens.models.length) {\n try {\n this.userTokens.remove(this.userTokens.models[0]);\n } catch (err) {\n this.logger.warn('credentials: failed to remove user token', err);\n }\n }\n\n this.logger.info('credentials: finished removing tokens');\n\n // Return a promise to give the storage layer a tick or two to clear\n // localStorage\n return Promise.resolve();\n },\n\n @oneFlight\n @whileInFlight('isRefreshing')\n @waitForValue('@')\n /**\n * Removes the supertoken and child tokens, then refreshes the supertoken;\n * subsequent calls to {@link Credentials#getUserToken()} will re-downscope\n * child tokens. Enqueus revocation of previous previousTokens. Yes, that's\n * the correct number of \"previous\"es.\n * @instance\n * @memberof Credentials\n * @returns {Promise}\n */\n refresh() {\n this.logger.info('credentials: refresh requested');\n\n const {supertoken} = this;\n const tokens = clone(this.userTokens.models);\n\n // This is kind of a leaky abstraction, since it relies on the authorization\n // plugin, but the only alternatives I see are\n // 1. put all JWT support in core\n // 2. have separate jwt and non-jwt auth plugins\n // while I like #2 from a code simplicity standpoint, the third-party DX\n // isn't great\n if (this.config.jwtRefreshCallback) {\n return (\n this.config\n .jwtRefreshCallback(this.webex)\n // eslint-disable-next-line no-shadow\n .then((jwt) => this.webex.authorization.requestAccessTokenFromJwt({jwt}))\n );\n }\n\n if (this.webex.internal.services) {\n this.webex.internal.services.updateCredentialsConfig();\n }\n\n return supertoken\n .refresh()\n .catch((error) => {\n if (error instanceof OAuthError) {\n // Error: super token refresh failed with 400 status code.\n // Hence emit an event to the client, an opportunity to logout.\n this.unset('supertoken');\n while (this.userTokens.models.length) {\n try {\n this.userTokens.remove(this.userTokens.models[0]);\n } catch (err) {\n this.logger.warn('credentials: failed to remove user token', err);\n }\n }\n this.webex.trigger('client:InvalidRequestError');\n }\n\n return Promise.reject(error);\n })\n .then((st) => {\n // clear refresh timer\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.unset('refreshTimer');\n }\n this.supertoken = st;\n\n const invalidScopes = diffScopes(this.config.scope, st.scope);\n\n if (invalidScopes !== '') {\n this.logger.warn(\n `credentials: \"${invalidScopes}\" scope(s) are invalid because not listed in the supertoken, they will be excluded from user token requests.`\n );\n this.webex.internal.metrics.submitClientMetrics(\n METRICS.JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH,\n {fields: {invalidScopes}}\n );\n }\n\n return Promise.all(\n tokens.map((token) => {\n const tokenScope = filterScope(diffScopes(token.scope, st.scope), token.scope);\n\n return (\n this.downscope(tokenScope)\n // eslint-disable-next-line max-nested-callbacks\n .then((t) => {\n this.logger.info(`credentials: revoking token for ${token.scope}`);\n\n return token\n .revoke()\n .catch((err) => {\n this.logger.warn('credentials: failed to revoke user token', err);\n })\n .then(() => {\n this.userTokens.remove(token.scope);\n this.userTokens.add(t);\n });\n })\n );\n })\n );\n })\n .then(() => {\n this.scheduleRefresh(this.supertoken.expires);\n });\n },\n\n /**\n * Schedules a token refresh or refreshes the token if token has expired\n * @instance\n * @memberof Credentials\n * @param {number} expires\n * @private\n * @returns {undefined}\n */\n scheduleRefresh(expires) {\n const expiresIn = expires - Date.now();\n\n if (expiresIn > 0) {\n const timeoutLength = this.calcRefreshTimeout(expiresIn);\n\n this.refreshTimer = safeSetTimeout(() => this.refresh(), timeoutLength);\n } else {\n this.refresh();\n }\n },\n});\n\nexport default Credentials;\n"],"mappings":"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"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
4
|
+
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
4
5
|
_Object$defineProperty(exports, "__esModule", {
|
|
5
6
|
value: true
|
|
6
7
|
});
|
|
8
|
+
exports.diffScopes = diffScopes;
|
|
7
9
|
exports.filterScope = filterScope;
|
|
8
10
|
exports.sortScope = sortScope;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*/
|
|
12
|
-
|
|
11
|
+
var _isArray = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/array/is-array"));
|
|
12
|
+
var _difference2 = _interopRequireDefault(require("lodash/difference"));
|
|
13
13
|
/**
|
|
14
14
|
* sorts a list of scopes
|
|
15
15
|
* @param {string} scope
|
|
@@ -24,7 +24,7 @@ function sortScope(scope) {
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* sorts a list of scopes and filters the specified scope
|
|
27
|
-
* @param {string} toFilter
|
|
27
|
+
* @param {string|string[]} toFilter
|
|
28
28
|
* @param {string} scope
|
|
29
29
|
* @returns {string}
|
|
30
30
|
*/
|
|
@@ -32,8 +32,23 @@ function filterScope(toFilter, scope) {
|
|
|
32
32
|
if (!scope) {
|
|
33
33
|
return '';
|
|
34
34
|
}
|
|
35
|
+
var toFilterArr = (0, _isArray.default)(toFilter) ? toFilter : [toFilter];
|
|
35
36
|
return scope.split(' ').filter(function (item) {
|
|
36
|
-
return item
|
|
37
|
+
return !toFilterArr.includes(item);
|
|
37
38
|
}).sort().join(' ');
|
|
38
39
|
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Returns a string containing all items in scopeA that are not in scopeB, or an empty string if there are none.
|
|
43
|
+
*
|
|
44
|
+
* @param {string} scopeA
|
|
45
|
+
* @param {string} scopeB
|
|
46
|
+
* @returns {string}
|
|
47
|
+
*/
|
|
48
|
+
function diffScopes(scopeA, scopeB) {
|
|
49
|
+
var _scopeA$split, _scopeB$split;
|
|
50
|
+
var a = (_scopeA$split = scopeA === null || scopeA === void 0 ? void 0 : scopeA.split(' ')) !== null && _scopeA$split !== void 0 ? _scopeA$split : [];
|
|
51
|
+
var b = (_scopeB$split = scopeB === null || scopeB === void 0 ? void 0 : scopeB.split(' ')) !== null && _scopeB$split !== void 0 ? _scopeB$split : [];
|
|
52
|
+
return (0, _difference2.default)(a, b).sort().join(' ');
|
|
53
|
+
}
|
|
39
54
|
//# sourceMappingURL=scope.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["sortScope","scope","split","sort","join","filterScope","toFilter","filter","item"],"sources":["scope.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\n/**\n * sorts a list of scopes\n * @param {string} scope\n * @returns {string}\n */\nexport function sortScope(scope) {\n if (!scope) {\n return '';\n }\n\n return scope.split(' ').sort().join(' ');\n}\n\n/**\n * sorts a list of scopes and filters the specified scope\n * @param {string} toFilter\n * @param {string} scope\n * @returns {string}\n */\nexport function filterScope(toFilter, scope) {\n if (!scope) {\n return '';\n }\n\n return scope\n .split(' ')\n .filter((item) => item
|
|
1
|
+
{"version":3,"names":["sortScope","scope","split","sort","join","filterScope","toFilter","toFilterArr","filter","item","includes","diffScopes","scopeA","scopeB","a","b"],"sources":["scope.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport {difference} from 'lodash';\n\n/**\n * sorts a list of scopes\n * @param {string} scope\n * @returns {string}\n */\nexport function sortScope(scope) {\n if (!scope) {\n return '';\n }\n\n return scope.split(' ').sort().join(' ');\n}\n\n/**\n * sorts a list of scopes and filters the specified scope\n * @param {string|string[]} toFilter\n * @param {string} scope\n * @returns {string}\n */\nexport function filterScope(toFilter, scope) {\n if (!scope) {\n return '';\n }\n const toFilterArr = Array.isArray(toFilter) ? toFilter : [toFilter];\n\n return scope\n .split(' ')\n .filter((item) => !toFilterArr.includes(item))\n .sort()\n .join(' ');\n}\n\n/**\n * Returns a string containing all items in scopeA that are not in scopeB, or an empty string if there are none.\n *\n * @param {string} scopeA\n * @param {string} scopeB\n * @returns {string}\n */\nexport function diffScopes(scopeA, scopeB) {\n const a = scopeA?.split(' ') ?? [];\n const b = scopeB?.split(' ') ?? [];\n\n return difference(a, b).sort().join(' ');\n}\n"],"mappings":";;;;;;;;;;;;AAMA;AACA;AACA;AACA;AACA;AACO,SAASA,SAAS,CAACC,KAAK,EAAE;EAC/B,IAAI,CAACA,KAAK,EAAE;IACV,OAAO,EAAE;EACX;EAEA,OAAOA,KAAK,CAACC,KAAK,CAAC,GAAG,CAAC,CAACC,IAAI,EAAE,CAACC,IAAI,CAAC,GAAG,CAAC;AAC1C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,WAAW,CAACC,QAAQ,EAAEL,KAAK,EAAE;EAC3C,IAAI,CAACA,KAAK,EAAE;IACV,OAAO,EAAE;EACX;EACA,IAAMM,WAAW,GAAG,sBAAcD,QAAQ,CAAC,GAAGA,QAAQ,GAAG,CAACA,QAAQ,CAAC;EAEnE,OAAOL,KAAK,CACTC,KAAK,CAAC,GAAG,CAAC,CACVM,MAAM,CAAC,UAACC,IAAI;IAAA,OAAK,CAACF,WAAW,CAACG,QAAQ,CAACD,IAAI,CAAC;EAAA,EAAC,CAC7CN,IAAI,EAAE,CACNC,IAAI,CAAC,GAAG,CAAC;AACd;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASO,UAAU,CAACC,MAAM,EAAEC,MAAM,EAAE;EAAA;EACzC,IAAMC,CAAC,oBAAGF,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAEV,KAAK,CAAC,GAAG,CAAC,yDAAI,EAAE;EAClC,IAAMa,CAAC,oBAAGF,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAEX,KAAK,CAAC,GAAG,CAAC,yDAAI,EAAE;EAElC,OAAO,0BAAWY,CAAC,EAAEC,CAAC,CAAC,CAACZ,IAAI,EAAE,CAACC,IAAI,CAAC,GAAG,CAAC;AAC1C"}
|
|
@@ -527,7 +527,7 @@ var Token = _webexPlugin.default.extend((_dec = (0, _common.oneFlight)({
|
|
|
527
527
|
return res.body;
|
|
528
528
|
});
|
|
529
529
|
},
|
|
530
|
-
version: "3.0.0-beta.
|
|
530
|
+
version: "3.0.0-beta.276"
|
|
531
531
|
}, ((0, _applyDecoratedDescriptor2.default)(_obj, "downscope", [_dec], (0, _getOwnPropertyDescriptor.default)(_obj, "downscope"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "refresh", [_common.oneFlight], (0, _getOwnPropertyDescriptor.default)(_obj, "refresh"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "revoke", [_common.oneFlight], (0, _getOwnPropertyDescriptor.default)(_obj, "revoke"), _obj)), _obj)));
|
|
532
532
|
var _default = Token;
|
|
533
533
|
exports.default = _default;
|
package/dist/plugins/logger.js
CHANGED
|
@@ -57,7 +57,7 @@ var Logger = _webexPlugin.default.extend({
|
|
|
57
57
|
info: wrapConsoleMethod('info'),
|
|
58
58
|
debug: wrapConsoleMethod('debug'),
|
|
59
59
|
trace: wrapConsoleMethod('trace'),
|
|
60
|
-
version: "3.0.0-beta.
|
|
60
|
+
version: "3.0.0-beta.276"
|
|
61
61
|
});
|
|
62
62
|
(0, _webexCore.registerPlugin)('logger', Logger);
|
|
63
63
|
var _default = Logger;
|
package/dist/webex-core.js
CHANGED
|
@@ -99,7 +99,7 @@ var MAX_FILE_SIZE_IN_MB = 2048;
|
|
|
99
99
|
* @class
|
|
100
100
|
*/
|
|
101
101
|
var WebexCore = _ampersandState.default.extend((_obj = {
|
|
102
|
-
version: "3.0.0-beta.
|
|
102
|
+
version: "3.0.0-beta.276",
|
|
103
103
|
children: {
|
|
104
104
|
internal: _webexInternalCore.default
|
|
105
105
|
},
|
|
@@ -641,7 +641,7 @@ var WebexCore = _ampersandState.default.extend((_obj = {
|
|
|
641
641
|
});
|
|
642
642
|
}
|
|
643
643
|
}, ((0, _applyDecoratedDescriptor2.default)(_obj, "_uploadPhaseUpload", [_common.retry], (0, _getOwnPropertyDescriptor.default)(_obj, "_uploadPhaseUpload"), _obj)), _obj));
|
|
644
|
-
WebexCore.version = "3.0.0-beta.
|
|
644
|
+
WebexCore.version = "3.0.0-beta.276";
|
|
645
645
|
(0, _webexInternalCorePluginMixin.default)(_webexInternalCore.default, _config.default, interceptors);
|
|
646
646
|
(0, _webexCorePluginMixin.default)(WebexCore, _config.default, interceptors);
|
|
647
647
|
var _default = WebexCore;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webex/webex-core",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.276",
|
|
4
4
|
"description": "Plugin handling for Cisco Webex",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"contributors": [
|
|
@@ -31,24 +31,24 @@
|
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@sinonjs/fake-timers": "^6.0.1",
|
|
34
|
-
"@webex/test-helper-chai": "3.0.0-beta.
|
|
35
|
-
"@webex/test-helper-make-local-url": "3.0.0-beta.
|
|
36
|
-
"@webex/test-helper-mocha": "3.0.0-beta.
|
|
37
|
-
"@webex/test-helper-mock-webex": "3.0.0-beta.
|
|
38
|
-
"@webex/test-helper-refresh-callback": "3.0.0-beta.
|
|
39
|
-
"@webex/test-helper-test-users": "3.0.0-beta.
|
|
34
|
+
"@webex/test-helper-chai": "3.0.0-beta.276",
|
|
35
|
+
"@webex/test-helper-make-local-url": "3.0.0-beta.276",
|
|
36
|
+
"@webex/test-helper-mocha": "3.0.0-beta.276",
|
|
37
|
+
"@webex/test-helper-mock-webex": "3.0.0-beta.276",
|
|
38
|
+
"@webex/test-helper-refresh-callback": "3.0.0-beta.276",
|
|
39
|
+
"@webex/test-helper-test-users": "3.0.0-beta.276",
|
|
40
40
|
"chai": "^4.3.4",
|
|
41
41
|
"chai-as-promised": "^7.1.1",
|
|
42
42
|
"sinon": "^9.2.4"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@webex/common": "3.0.0-beta.
|
|
46
|
-
"@webex/common-timers": "3.0.0-beta.
|
|
47
|
-
"@webex/http-core": "3.0.0-beta.
|
|
48
|
-
"@webex/internal-plugin-device": "3.0.0-beta.
|
|
49
|
-
"@webex/plugin-logger": "3.0.0-beta.
|
|
50
|
-
"@webex/storage-adapter-spec": "3.0.0-beta.
|
|
51
|
-
"@webex/webex-core": "3.0.0-beta.
|
|
45
|
+
"@webex/common": "3.0.0-beta.276",
|
|
46
|
+
"@webex/common-timers": "3.0.0-beta.276",
|
|
47
|
+
"@webex/http-core": "3.0.0-beta.276",
|
|
48
|
+
"@webex/internal-plugin-device": "3.0.0-beta.276",
|
|
49
|
+
"@webex/plugin-logger": "3.0.0-beta.276",
|
|
50
|
+
"@webex/storage-adapter-spec": "3.0.0-beta.276",
|
|
51
|
+
"@webex/webex-core": "3.0.0-beta.276",
|
|
52
52
|
"ampersand-collection": "^2.0.2",
|
|
53
53
|
"ampersand-events": "^2.0.2",
|
|
54
54
|
"ampersand-state": "^5.0.3",
|
|
@@ -13,10 +13,11 @@ import {clone, cloneDeep, isObject, isEmpty} from 'lodash';
|
|
|
13
13
|
import WebexPlugin from '../webex-plugin';
|
|
14
14
|
import {persist, waitForValue} from '../storage/decorators';
|
|
15
15
|
|
|
16
|
-
import grantErrors from './grant-errors';
|
|
17
|
-
import {filterScope, sortScope} from './scope';
|
|
16
|
+
import grantErrors, {OAuthError} from './grant-errors';
|
|
17
|
+
import {filterScope, diffScopes, sortScope} from './scope';
|
|
18
18
|
import Token from './token';
|
|
19
19
|
import TokenCollection from './token-collection';
|
|
20
|
+
import {METRICS} from '../constants';
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* @class
|
|
@@ -259,8 +260,15 @@ const Credentials = WebexPlugin.extend({
|
|
|
259
260
|
*/
|
|
260
261
|
downscope(scope) {
|
|
261
262
|
return this.supertoken.downscope(scope).catch((reason) => {
|
|
262
|
-
|
|
263
|
+
const failReason = reason?.body ?? reason;
|
|
264
|
+
this.logger.warn(`credentials: failed to downscope supertoken to "${scope}"`, failReason);
|
|
263
265
|
this.logger.trace(`credentials: falling back to supertoken for ${scope}`);
|
|
266
|
+
this.webex.internal.metrics.submitClientMetrics(METRICS.JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED, {
|
|
267
|
+
fields: {
|
|
268
|
+
requestedScope: scope,
|
|
269
|
+
failReason,
|
|
270
|
+
},
|
|
271
|
+
});
|
|
264
272
|
|
|
265
273
|
return Promise.resolve(new Token({scope, ...this.supertoken.serialize()}), {
|
|
266
274
|
parent: this,
|
|
@@ -341,12 +349,12 @@ const Credentials = WebexPlugin.extend({
|
|
|
341
349
|
}
|
|
342
350
|
|
|
343
351
|
if (!scope) {
|
|
344
|
-
scope = filterScope('spark:kms', this.
|
|
352
|
+
scope = filterScope('spark:kms', this.supertoken.scope);
|
|
345
353
|
}
|
|
346
354
|
|
|
347
355
|
scope = sortScope(scope);
|
|
348
356
|
|
|
349
|
-
if (scope === sortScope(this.
|
|
357
|
+
if (scope === sortScope(this.supertoken.scope)) {
|
|
350
358
|
return Promise.resolve(this.supertoken);
|
|
351
359
|
}
|
|
352
360
|
|
|
@@ -496,42 +504,10 @@ const Credentials = WebexPlugin.extend({
|
|
|
496
504
|
|
|
497
505
|
return supertoken
|
|
498
506
|
.refresh()
|
|
499
|
-
.then((st) => {
|
|
500
|
-
// clear refresh timer
|
|
501
|
-
if (this.refreshTimer) {
|
|
502
|
-
clearTimeout(this.refreshTimer);
|
|
503
|
-
this.unset('refreshTimer');
|
|
504
|
-
}
|
|
505
|
-
this.supertoken = st;
|
|
506
|
-
|
|
507
|
-
return Promise.all(
|
|
508
|
-
tokens.map((token) =>
|
|
509
|
-
this.downscope(token.scope)
|
|
510
|
-
// eslint-disable-next-line max-nested-callbacks
|
|
511
|
-
.then((t) => {
|
|
512
|
-
this.logger.info(`credentials: revoking token for ${token.scope}`);
|
|
513
|
-
|
|
514
|
-
return token
|
|
515
|
-
.revoke()
|
|
516
|
-
.catch((err) => {
|
|
517
|
-
this.logger.warn('credentials: failed to revoke user token', err);
|
|
518
|
-
})
|
|
519
|
-
.then(() => {
|
|
520
|
-
this.userTokens.remove(token.scope);
|
|
521
|
-
this.userTokens.add(t);
|
|
522
|
-
});
|
|
523
|
-
})
|
|
524
|
-
)
|
|
525
|
-
);
|
|
526
|
-
})
|
|
527
|
-
.then(() => {
|
|
528
|
-
this.scheduleRefresh(this.supertoken.expires);
|
|
529
|
-
})
|
|
530
507
|
.catch((error) => {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
// Error: The refresh token provided is expired, revoked, malformed, or invalid. Hence emit an event to the client, an opportunity to logout.
|
|
508
|
+
if (error instanceof OAuthError) {
|
|
509
|
+
// Error: super token refresh failed with 400 status code.
|
|
510
|
+
// Hence emit an event to the client, an opportunity to logout.
|
|
535
511
|
this.unset('supertoken');
|
|
536
512
|
while (this.userTokens.models.length) {
|
|
537
513
|
try {
|
|
@@ -544,6 +520,53 @@ const Credentials = WebexPlugin.extend({
|
|
|
544
520
|
}
|
|
545
521
|
|
|
546
522
|
return Promise.reject(error);
|
|
523
|
+
})
|
|
524
|
+
.then((st) => {
|
|
525
|
+
// clear refresh timer
|
|
526
|
+
if (this.refreshTimer) {
|
|
527
|
+
clearTimeout(this.refreshTimer);
|
|
528
|
+
this.unset('refreshTimer');
|
|
529
|
+
}
|
|
530
|
+
this.supertoken = st;
|
|
531
|
+
|
|
532
|
+
const invalidScopes = diffScopes(this.config.scope, st.scope);
|
|
533
|
+
|
|
534
|
+
if (invalidScopes !== '') {
|
|
535
|
+
this.logger.warn(
|
|
536
|
+
`credentials: "${invalidScopes}" scope(s) are invalid because not listed in the supertoken, they will be excluded from user token requests.`
|
|
537
|
+
);
|
|
538
|
+
this.webex.internal.metrics.submitClientMetrics(
|
|
539
|
+
METRICS.JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH,
|
|
540
|
+
{fields: {invalidScopes}}
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
return Promise.all(
|
|
545
|
+
tokens.map((token) => {
|
|
546
|
+
const tokenScope = filterScope(diffScopes(token.scope, st.scope), token.scope);
|
|
547
|
+
|
|
548
|
+
return (
|
|
549
|
+
this.downscope(tokenScope)
|
|
550
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
551
|
+
.then((t) => {
|
|
552
|
+
this.logger.info(`credentials: revoking token for ${token.scope}`);
|
|
553
|
+
|
|
554
|
+
return token
|
|
555
|
+
.revoke()
|
|
556
|
+
.catch((err) => {
|
|
557
|
+
this.logger.warn('credentials: failed to revoke user token', err);
|
|
558
|
+
})
|
|
559
|
+
.then(() => {
|
|
560
|
+
this.userTokens.remove(token.scope);
|
|
561
|
+
this.userTokens.add(t);
|
|
562
|
+
});
|
|
563
|
+
})
|
|
564
|
+
);
|
|
565
|
+
})
|
|
566
|
+
);
|
|
567
|
+
})
|
|
568
|
+
.then(() => {
|
|
569
|
+
this.scheduleRefresh(this.supertoken.expires);
|
|
547
570
|
});
|
|
548
571
|
},
|
|
549
572
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import {difference} from 'lodash';
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
8
|
* sorts a list of scopes
|
|
7
9
|
* @param {string} scope
|
|
@@ -17,7 +19,7 @@ export function sortScope(scope) {
|
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* sorts a list of scopes and filters the specified scope
|
|
20
|
-
* @param {string} toFilter
|
|
22
|
+
* @param {string|string[]} toFilter
|
|
21
23
|
* @param {string} scope
|
|
22
24
|
* @returns {string}
|
|
23
25
|
*/
|
|
@@ -25,10 +27,25 @@ export function filterScope(toFilter, scope) {
|
|
|
25
27
|
if (!scope) {
|
|
26
28
|
return '';
|
|
27
29
|
}
|
|
30
|
+
const toFilterArr = Array.isArray(toFilter) ? toFilter : [toFilter];
|
|
28
31
|
|
|
29
32
|
return scope
|
|
30
33
|
.split(' ')
|
|
31
|
-
.filter((item) => item
|
|
34
|
+
.filter((item) => !toFilterArr.includes(item))
|
|
32
35
|
.sort()
|
|
33
36
|
.join(' ');
|
|
34
37
|
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Returns a string containing all items in scopeA that are not in scopeB, or an empty string if there are none.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} scopeA
|
|
43
|
+
* @param {string} scopeB
|
|
44
|
+
* @returns {string}
|
|
45
|
+
*/
|
|
46
|
+
export function diffScopes(scopeA, scopeB) {
|
|
47
|
+
const a = scopeA?.split(' ') ?? [];
|
|
48
|
+
const b = scopeB?.split(' ') ?? [];
|
|
49
|
+
|
|
50
|
+
return difference(a, b).sort().join(' ');
|
|
51
|
+
}
|
|
@@ -11,6 +11,7 @@ import {inBrowser} from '@webex/common';
|
|
|
11
11
|
import FakeTimers from '@sinonjs/fake-timers';
|
|
12
12
|
import {skipInBrowser} from '@webex/test-helper-mocha';
|
|
13
13
|
import Logger from '@webex/plugin-logger';
|
|
14
|
+
import Metrics, {config} from '@webex/internal-plugin-metrics';
|
|
14
15
|
|
|
15
16
|
/* eslint camelcase: [0] */
|
|
16
17
|
|
|
@@ -445,7 +446,11 @@ describe('webex-core', () => {
|
|
|
445
446
|
});
|
|
446
447
|
|
|
447
448
|
it('schedules a refreshTimer', () => {
|
|
448
|
-
const webex = new MockWebex(
|
|
449
|
+
const webex = new MockWebex({
|
|
450
|
+
children: {
|
|
451
|
+
metrics: Metrics,
|
|
452
|
+
},
|
|
453
|
+
});
|
|
449
454
|
const supertoken = makeToken(webex, {
|
|
450
455
|
access_token: 'ST',
|
|
451
456
|
refresh_token: 'RT',
|
|
@@ -458,6 +463,7 @@ describe('webex-core', () => {
|
|
|
458
463
|
});
|
|
459
464
|
|
|
460
465
|
sinon.stub(supertoken, 'refresh').returns(Promise.resolve(supertoken2));
|
|
466
|
+
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
461
467
|
const credentials = new Credentials(supertoken, {parent: webex});
|
|
462
468
|
|
|
463
469
|
webex.trigger('change:config');
|
|
@@ -492,7 +498,19 @@ describe('webex-core', () => {
|
|
|
492
498
|
});
|
|
493
499
|
|
|
494
500
|
describe('#getUserToken()', () => {
|
|
495
|
-
it('resolves with the supertoken if the supertoken matches the requested scopes')
|
|
501
|
+
it('resolves with the supertoken if the supertoken matches the requested scopes', () => {
|
|
502
|
+
const webex = new MockWebex();
|
|
503
|
+
const credentials = new Credentials(undefined, {parent: webex});
|
|
504
|
+
|
|
505
|
+
webex.trigger('change:config');
|
|
506
|
+
const st = makeToken(webex, {access_token: 'ST', scope: 'scope1'});
|
|
507
|
+
|
|
508
|
+
credentials.set({
|
|
509
|
+
supertoken: st,
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
return credentials.getUserToken('scope1').then((result) => assert.deepEqual(result, st));
|
|
513
|
+
});
|
|
496
514
|
|
|
497
515
|
it('resolves with the token identified by the specified scopes', () => {
|
|
498
516
|
const webex = new MockWebex();
|
|
@@ -520,6 +538,25 @@ describe('webex-core', () => {
|
|
|
520
538
|
]);
|
|
521
539
|
});
|
|
522
540
|
|
|
541
|
+
it('uses the supertoken.scope instead of the config.scope for downscope', () => {
|
|
542
|
+
const webex = new MockWebex();
|
|
543
|
+
const credentials = new Credentials(undefined, {parent: webex});
|
|
544
|
+
|
|
545
|
+
webex.trigger('change:config');
|
|
546
|
+
const st = makeToken(webex, {access_token: 'ST', scope: 'scope1 spark:kms'});
|
|
547
|
+
|
|
548
|
+
credentials.set({
|
|
549
|
+
supertoken: st,
|
|
550
|
+
scope: 'invalidScope scope1',
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
sinon.stub(credentials, 'downscope').returns(Promise.resolve());
|
|
554
|
+
|
|
555
|
+
return credentials.getUserToken().then(() => {
|
|
556
|
+
assert.calledWith(credentials.downscope, 'scope1');
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
|
|
523
560
|
describe('when no matching token is found', () => {
|
|
524
561
|
it('downscopes the supertoken', () => {
|
|
525
562
|
const webex = new MockWebex();
|
|
@@ -557,13 +594,13 @@ describe('webex-core', () => {
|
|
|
557
594
|
it('resolves with a token containing all but the kms scopes', () => {
|
|
558
595
|
const webex = new MockWebex();
|
|
559
596
|
|
|
560
|
-
webex.config.credentials.scope = 'scope1 spark:kms';
|
|
561
597
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
562
598
|
|
|
563
599
|
webex.trigger('change:config');
|
|
564
600
|
|
|
565
601
|
credentials.supertoken = makeToken(webex, {
|
|
566
602
|
access_token: 'ST',
|
|
603
|
+
scope: 'scope1 spark:kms',
|
|
567
604
|
});
|
|
568
605
|
|
|
569
606
|
// const t2 = makeToken(webex, {
|
|
@@ -590,9 +627,11 @@ describe('webex-core', () => {
|
|
|
590
627
|
const webex = new MockWebex({
|
|
591
628
|
children: {
|
|
592
629
|
logger: Logger,
|
|
630
|
+
metrics: Metrics,
|
|
593
631
|
},
|
|
594
632
|
});
|
|
595
633
|
|
|
634
|
+
webex.config.metrics = config.metrics;
|
|
596
635
|
webex.config.credentials.scope = 'scope1 spark:kms';
|
|
597
636
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
598
637
|
|
|
@@ -602,9 +641,11 @@ describe('webex-core', () => {
|
|
|
602
641
|
access_token: 'ST',
|
|
603
642
|
});
|
|
604
643
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
644
|
+
const failReason = 'downscope failed';
|
|
645
|
+
sinon.stub(credentials.supertoken, 'downscope').returns(Promise.reject(failReason));
|
|
646
|
+
|
|
647
|
+
sinon.stub(credentials.logger, 'warn').callsFake(() => {});
|
|
648
|
+
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
608
649
|
|
|
609
650
|
const t1 = makeToken(webex, {
|
|
610
651
|
access_token: 'AT1',
|
|
@@ -615,14 +656,27 @@ describe('webex-core', () => {
|
|
|
615
656
|
userTokens: [t1],
|
|
616
657
|
});
|
|
617
658
|
|
|
618
|
-
return credentials
|
|
619
|
-
.
|
|
620
|
-
|
|
659
|
+
return credentials.getUserToken('scope2').then((t) => {
|
|
660
|
+
assert.equal(t.access_token, credentials.supertoken.access_token);
|
|
661
|
+
assert.calledWith(
|
|
662
|
+
credentials.logger.warn,
|
|
663
|
+
'credentials: failed to downscope supertoken to "scope2"'
|
|
664
|
+
);
|
|
665
|
+
assert.calledWith(
|
|
666
|
+
webex.internal.metrics.submitClientMetrics,
|
|
667
|
+
'JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED',
|
|
668
|
+
{fields: {failReason, requestedScope: 'scope2'}}
|
|
669
|
+
);
|
|
670
|
+
});
|
|
621
671
|
});
|
|
622
672
|
});
|
|
623
673
|
|
|
624
674
|
it('is blocked while a token refresh is inflight', () => {
|
|
625
|
-
const webex = new MockWebex(
|
|
675
|
+
const webex = new MockWebex({
|
|
676
|
+
children: {
|
|
677
|
+
metrics: Metrics,
|
|
678
|
+
},
|
|
679
|
+
});
|
|
626
680
|
|
|
627
681
|
webex.config.credentials.scope = 'scope1 spark:kms';
|
|
628
682
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
@@ -648,6 +702,7 @@ describe('webex-core', () => {
|
|
|
648
702
|
const at2 = makeToken(webex, {access_token: 'ST2ATD'});
|
|
649
703
|
|
|
650
704
|
sinon.stub(supertoken2, 'downscope').returns(Promise.resolve(at2));
|
|
705
|
+
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
651
706
|
|
|
652
707
|
return Promise.all([
|
|
653
708
|
credentials.refresh(),
|
|
@@ -778,18 +833,24 @@ describe('webex-core', () => {
|
|
|
778
833
|
|
|
779
834
|
describe('#refresh()', () => {
|
|
780
835
|
it('refreshes and downscopes the supertoken, and revokes previous tokens', () => {
|
|
781
|
-
const webex = new MockWebex(
|
|
836
|
+
const webex = new MockWebex({
|
|
837
|
+
children: {
|
|
838
|
+
metrics: Metrics,
|
|
839
|
+
},
|
|
840
|
+
});
|
|
782
841
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
783
842
|
|
|
784
843
|
webex.trigger('change:config');
|
|
785
844
|
const st = makeToken(webex, {
|
|
786
845
|
access_token: 'ST',
|
|
787
846
|
refresh_token: 'RT',
|
|
847
|
+
scope: 'scope1 scope2',
|
|
788
848
|
});
|
|
789
849
|
|
|
790
850
|
const st2 = makeToken(webex, {
|
|
791
851
|
access_token: 'ST2',
|
|
792
852
|
refresh_token: 'RT2',
|
|
853
|
+
scope: 'scope1 scope2',
|
|
793
854
|
});
|
|
794
855
|
|
|
795
856
|
const t1 = makeToken(webex, {
|
|
@@ -806,6 +867,7 @@ describe('webex-core', () => {
|
|
|
806
867
|
sinon.stub(st, 'refresh').returns(Promise.resolve(st2));
|
|
807
868
|
sinon.stub(t1, 'revoke').returns(Promise.resolve());
|
|
808
869
|
sinon.spy(credentials, 'scheduleRefresh');
|
|
870
|
+
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
809
871
|
|
|
810
872
|
credentials.set({
|
|
811
873
|
supertoken: st,
|
|
@@ -825,7 +887,11 @@ describe('webex-core', () => {
|
|
|
825
887
|
});
|
|
826
888
|
|
|
827
889
|
it('refreshes and downscopes the supertoken even if revocation of previous token fails', () => {
|
|
828
|
-
const webex = new MockWebex(
|
|
890
|
+
const webex = new MockWebex({
|
|
891
|
+
children: {
|
|
892
|
+
metrics: Metrics,
|
|
893
|
+
},
|
|
894
|
+
});
|
|
829
895
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
830
896
|
|
|
831
897
|
webex.trigger('change:config');
|
|
@@ -837,6 +903,7 @@ describe('webex-core', () => {
|
|
|
837
903
|
const st2 = makeToken(webex, {
|
|
838
904
|
access_token: 'ST2',
|
|
839
905
|
refresh_token: 'RT2',
|
|
906
|
+
scope: 'scope1 scope2',
|
|
840
907
|
});
|
|
841
908
|
|
|
842
909
|
const t1 = makeToken(webex, {
|
|
@@ -853,6 +920,7 @@ describe('webex-core', () => {
|
|
|
853
920
|
sinon.stub(st, 'refresh').returns(Promise.resolve(st2));
|
|
854
921
|
sinon.stub(t1, 'revoke').returns(Promise.reject());
|
|
855
922
|
sinon.spy(credentials, 'scheduleRefresh');
|
|
923
|
+
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
856
924
|
|
|
857
925
|
credentials.set({
|
|
858
926
|
supertoken: st,
|
|
@@ -875,6 +943,7 @@ describe('webex-core', () => {
|
|
|
875
943
|
const webex = new MockWebex({
|
|
876
944
|
children: {
|
|
877
945
|
logger: Logger,
|
|
946
|
+
metrics: Metrics,
|
|
878
947
|
},
|
|
879
948
|
});
|
|
880
949
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
@@ -883,9 +952,11 @@ describe('webex-core', () => {
|
|
|
883
952
|
const st = makeToken(webex, {
|
|
884
953
|
access_token: 'ST',
|
|
885
954
|
refresh_token: 'RT',
|
|
955
|
+
scope: '',
|
|
886
956
|
});
|
|
887
957
|
|
|
888
958
|
sinon.stub(st, 'refresh').returns(Promise.resolve(makeToken(webex, {access_token: 'ST2'})));
|
|
959
|
+
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
889
960
|
|
|
890
961
|
const t1 = makeToken(webex, {
|
|
891
962
|
access_token: 'AT1',
|
|
@@ -901,7 +972,7 @@ describe('webex-core', () => {
|
|
|
901
972
|
});
|
|
902
973
|
|
|
903
974
|
it('allows #getUserToken() to be revoked, but #getUserToken() promises will not resolve until the suport token has been refreshed', () => {
|
|
904
|
-
const webex = new MockWebex();
|
|
975
|
+
const webex = new MockWebex({children: {metrics: Metrics}});
|
|
905
976
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
906
977
|
|
|
907
978
|
webex.trigger('change:config');
|
|
@@ -927,6 +998,7 @@ describe('webex-core', () => {
|
|
|
927
998
|
|
|
928
999
|
sinon.stub(st1, 'refresh').returns(Promise.resolve(st2));
|
|
929
1000
|
sinon.stub(st2, 'downscope').returns(Promise.resolve(t2));
|
|
1001
|
+
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
930
1002
|
|
|
931
1003
|
credentials.set({
|
|
932
1004
|
supertoken: st1,
|
|
@@ -983,6 +1055,61 @@ describe('webex-core', () => {
|
|
|
983
1055
|
assert.calledWith(triggerSpy, sinon.match('client:InvalidRequestError'));
|
|
984
1056
|
});
|
|
985
1057
|
});
|
|
1058
|
+
|
|
1059
|
+
it('exclude invalid scopes from user token, log and call metrics when fetched supertoken scope mismatch with the configured scope', () => {
|
|
1060
|
+
const webex = new MockWebex({
|
|
1061
|
+
children: {
|
|
1062
|
+
logger: Logger,
|
|
1063
|
+
metrics: Metrics,
|
|
1064
|
+
},
|
|
1065
|
+
});
|
|
1066
|
+
const credentials = new Credentials(undefined, {parent: webex});
|
|
1067
|
+
|
|
1068
|
+
webex.trigger('change:config');
|
|
1069
|
+
const st = makeToken(webex, {
|
|
1070
|
+
access_token: 'ST',
|
|
1071
|
+
refresh_token: 'RT',
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
const st2 = makeToken(webex, {
|
|
1075
|
+
access_token: 'ST2',
|
|
1076
|
+
refresh_token: 'RT2',
|
|
1077
|
+
scope: 'scope1',
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
const userToken = makeToken(webex, {
|
|
1081
|
+
access_token: 'AT1',
|
|
1082
|
+
scope: 'scope1 invalidScope1',
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
credentials.set({
|
|
1086
|
+
supertoken: st,
|
|
1087
|
+
userTokens: [userToken],
|
|
1088
|
+
});
|
|
1089
|
+
const invalidScopes = 'invalidScope1 invalidScope2';
|
|
1090
|
+
credentials.config.scope = `scope1 ${invalidScopes}`;
|
|
1091
|
+
|
|
1092
|
+
sinon.stub(st2, 'downscope').returns(Promise.resolve());
|
|
1093
|
+
sinon.stub(st, 'refresh').returns(Promise.resolve(st2));
|
|
1094
|
+
sinon.spy(credentials, 'downscope');
|
|
1095
|
+
sinon.spy(credentials, 'scheduleRefresh');
|
|
1096
|
+
|
|
1097
|
+
sinon.stub(credentials.logger, 'warn').callsFake(() => {});
|
|
1098
|
+
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
1099
|
+
|
|
1100
|
+
return credentials.refresh().then(() => {
|
|
1101
|
+
assert.calledWith(
|
|
1102
|
+
credentials.logger.warn,
|
|
1103
|
+
`credentials: "${invalidScopes}" scope(s) are invalid because not listed in the supertoken, they will be excluded from user token requests.`
|
|
1104
|
+
);
|
|
1105
|
+
assert.calledWith(
|
|
1106
|
+
webex.internal.metrics.submitClientMetrics,
|
|
1107
|
+
'JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH',
|
|
1108
|
+
{fields: {invalidScopes}}
|
|
1109
|
+
);
|
|
1110
|
+
assert.calledWith(credentials.downscope, 'scope1');
|
|
1111
|
+
});
|
|
1112
|
+
});
|
|
986
1113
|
});
|
|
987
1114
|
|
|
988
1115
|
describe('#scheduleRefresh()', () => {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {assert} from '@webex/test-helper-chai';
|
|
2
|
+
import {sortScope, filterScope, diffScopes} from '@webex/webex-core/src/lib/credentials/scope';
|
|
3
|
+
|
|
4
|
+
describe('webex-core', () => {
|
|
5
|
+
describe('scope utils', () => {
|
|
6
|
+
describe('sortScope', () => {
|
|
7
|
+
it('should sort scopes alphabetically', () => {
|
|
8
|
+
assert.equal(sortScope(undefined), '');
|
|
9
|
+
assert.equal(sortScope(''), '');
|
|
10
|
+
assert.equal(sortScope('a'), 'a');
|
|
11
|
+
assert.equal(sortScope('b c a'), 'a b c');
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('filterScope', () => {
|
|
16
|
+
it('should filter out one scope from the original scope and sort the result', () => {
|
|
17
|
+
assert.equal(filterScope('a', undefined), '');
|
|
18
|
+
assert.equal(filterScope('a', ''), '');
|
|
19
|
+
assert.equal(filterScope('a', 'a'), '');
|
|
20
|
+
assert.equal(filterScope('a', 'a b c'), 'b c');
|
|
21
|
+
assert.equal(filterScope('c', 'a c b'), 'a b');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should filter out a list of scopes from the original scope and sort the result', () => {
|
|
25
|
+
assert.equal(filterScope([], 'a'), 'a');
|
|
26
|
+
assert.equal(filterScope(['a', 'b'], undefined), '');
|
|
27
|
+
assert.equal(filterScope(['a', 'b'], ''), '');
|
|
28
|
+
assert.equal(filterScope(['a', 'b'], 'a'), '');
|
|
29
|
+
assert.equal(filterScope(['a', 'b'], 'a b c'), 'c');
|
|
30
|
+
assert.equal(filterScope(['a', 'd'], 'a c a b'), 'b c');
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('diffScopes', () => {
|
|
35
|
+
it('should return an empty string, if all items in the first scope are contained in the second scope', () => {
|
|
36
|
+
assert.deepEqual(diffScopes(undefined, undefined), '');
|
|
37
|
+
assert.deepEqual(diffScopes(undefined, ''), '');
|
|
38
|
+
assert.deepEqual(diffScopes('', undefined), '');
|
|
39
|
+
assert.deepEqual(diffScopes('', ''), '');
|
|
40
|
+
assert.deepEqual(diffScopes('a', 'a'), '');
|
|
41
|
+
assert.deepEqual(diffScopes('a b c', 'a b c'), '');
|
|
42
|
+
assert.deepEqual(diffScopes(undefined, 'a b c'), '');
|
|
43
|
+
assert.deepEqual(diffScopes('a b c', 'a b c d'), '');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should return a string containing all items in the first scope that are not in the second scope', () => {
|
|
47
|
+
assert.deepEqual(diffScopes('a', undefined), 'a');
|
|
48
|
+
assert.deepEqual(diffScopes('a', 'b'), 'a');
|
|
49
|
+
assert.deepEqual(diffScopes('a b c', 'a b'), 'c');
|
|
50
|
+
assert.deepEqual(diffScopes('a b c d', 'a b c'), 'd');
|
|
51
|
+
assert.deepEqual(diffScopes('a b c', undefined), 'a b c');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -12,6 +12,7 @@ import Logger from '@webex/plugin-logger';
|
|
|
12
12
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
13
13
|
import {AuthInterceptor, config, Credentials, WebexHttpError, Token} from '@webex/webex-core';
|
|
14
14
|
import {cloneDeep, merge} from 'lodash';
|
|
15
|
+
import Metrics from '@webex/internal-plugin-metrics';
|
|
15
16
|
|
|
16
17
|
const {assert} = chai;
|
|
17
18
|
|
|
@@ -28,6 +29,7 @@ describe('webex-core', () => {
|
|
|
28
29
|
children: {
|
|
29
30
|
credentials: Credentials,
|
|
30
31
|
logger: Logger,
|
|
32
|
+
metrics: Metrics,
|
|
31
33
|
},
|
|
32
34
|
config: merge(cloneDeep(config), {credentials: {client_secret: 'fake'}}),
|
|
33
35
|
});
|
|
@@ -41,6 +43,7 @@ describe('webex-core', () => {
|
|
|
41
43
|
);
|
|
42
44
|
|
|
43
45
|
interceptor = Reflect.apply(AuthInterceptor.create, webex, []);
|
|
46
|
+
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
44
47
|
});
|
|
45
48
|
|
|
46
49
|
describe('#onRequest()', () => {
|