@webex/webex-core 2.60.0-next.8 → 2.60.1
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/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/credentials-config.js +2 -1
- package/dist/credentials-config.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/interceptors/auth.js +3 -4
- package/dist/interceptors/auth.js.map +1 -1
- package/dist/interceptors/default-options.js +3 -4
- package/dist/interceptors/default-options.js.map +1 -1
- package/dist/interceptors/embargo.js +3 -4
- package/dist/interceptors/embargo.js.map +1 -1
- package/dist/interceptors/network-timing.js +3 -4
- package/dist/interceptors/network-timing.js.map +1 -1
- package/dist/interceptors/payload-transformer.js +3 -4
- package/dist/interceptors/payload-transformer.js.map +1 -1
- package/dist/interceptors/rate-limit.js +3 -4
- package/dist/interceptors/rate-limit.js.map +1 -1
- package/dist/interceptors/redirect.js +6 -7
- package/dist/interceptors/redirect.js.map +1 -1
- package/dist/interceptors/request-event.js +8 -9
- package/dist/interceptors/request-event.js.map +1 -1
- package/dist/interceptors/request-logger.js +15 -12
- package/dist/interceptors/request-logger.js.map +1 -1
- package/dist/interceptors/request-timing.js +3 -4
- package/dist/interceptors/request-timing.js.map +1 -1
- package/dist/interceptors/response-logger.js +10 -10
- package/dist/interceptors/response-logger.js.map +1 -1
- package/dist/interceptors/user-agent.js +7 -8
- package/dist/interceptors/user-agent.js.map +1 -1
- package/dist/interceptors/webex-tracking-id.js +3 -4
- package/dist/interceptors/webex-tracking-id.js.map +1 -1
- package/dist/interceptors/webex-user-agent.js +8 -9
- package/dist/interceptors/webex-user-agent.js.map +1 -1
- package/dist/lib/batcher.js +5 -8
- package/dist/lib/batcher.js.map +1 -1
- package/dist/lib/credentials/credentials.js +35 -73
- package/dist/lib/credentials/credentials.js.map +1 -1
- package/dist/lib/credentials/grant-errors.js +5 -5
- package/dist/lib/credentials/grant-errors.js.map +1 -1
- package/dist/lib/credentials/scope.js +2 -21
- package/dist/lib/credentials/scope.js.map +1 -1
- package/dist/lib/credentials/token-collection.js +2 -1
- package/dist/lib/credentials/token-collection.js.map +1 -1
- package/dist/lib/credentials/token.js +10 -11
- package/dist/lib/credentials/token.js.map +1 -1
- package/dist/lib/page.js +2 -1
- package/dist/lib/page.js.map +1 -1
- package/dist/lib/services/constants.js +6 -3
- package/dist/lib/services/constants.js.map +1 -1
- package/dist/lib/services/index.js +2 -2
- package/dist/lib/services/index.js.map +1 -1
- package/dist/lib/services/interceptors/server-error.js +3 -4
- package/dist/lib/services/interceptors/server-error.js.map +1 -1
- package/dist/lib/services/interceptors/service.js +5 -8
- package/dist/lib/services/interceptors/service.js.map +1 -1
- package/dist/lib/services/metrics.js +2 -1
- package/dist/lib/services/metrics.js.map +1 -1
- package/dist/lib/services/service-catalog.js +5 -5
- package/dist/lib/services/service-catalog.js.map +1 -1
- package/dist/lib/services/service-fed-ramp.js +2 -1
- package/dist/lib/services/service-fed-ramp.js.map +1 -1
- package/dist/lib/services/service-host.js +2 -1
- package/dist/lib/services/service-host.js.map +1 -1
- package/dist/lib/services/service-registry.js +4 -3
- package/dist/lib/services/service-registry.js.map +1 -1
- package/dist/lib/services/service-state.js +2 -1
- package/dist/lib/services/service-state.js.map +1 -1
- package/dist/lib/services/service-url.js +2 -1
- package/dist/lib/services/service-url.js.map +1 -1
- package/dist/lib/services/services.js +9 -7
- package/dist/lib/services/services.js.map +1 -1
- package/dist/lib/stateless-webex-plugin.js +2 -1
- package/dist/lib/stateless-webex-plugin.js.map +1 -1
- package/dist/lib/storage/decorators.js +16 -18
- package/dist/lib/storage/decorators.js.map +1 -1
- package/dist/lib/storage/errors.js +5 -5
- package/dist/lib/storage/errors.js.map +1 -1
- package/dist/lib/storage/make-webex-plugin-store.js +10 -8
- package/dist/lib/storage/make-webex-plugin-store.js.map +1 -1
- package/dist/lib/storage/make-webex-store.js.map +1 -1
- package/dist/lib/storage/memory-store-adapter.js +2 -1
- package/dist/lib/storage/memory-store-adapter.js.map +1 -1
- package/dist/lib/webex-core-plugin-mixin.js +14 -13
- package/dist/lib/webex-core-plugin-mixin.js.map +1 -1
- package/dist/lib/webex-http-error.js +3 -4
- package/dist/lib/webex-http-error.js.map +1 -1
- package/dist/lib/webex-internal-core-plugin-mixin.js +14 -13
- package/dist/lib/webex-internal-core-plugin-mixin.js.map +1 -1
- package/dist/lib/webex-plugin.js +8 -5
- package/dist/lib/webex-plugin.js.map +1 -1
- package/dist/plugins/logger.js +3 -2
- package/dist/plugins/logger.js.map +1 -1
- package/dist/webex-core.js +38 -37
- package/dist/webex-core.js.map +1 -1
- package/dist/webex-internal-core.js +2 -1
- package/dist/webex-internal-core.js.map +1 -1
- package/package.json +20 -21
- package/src/lib/credentials/credentials.js +40 -82
- package/src/lib/credentials/scope.js +2 -19
- package/src/lib/services/interceptors/service.js +2 -2
- package/src/lib/services/service-catalog.js +1 -3
- package/src/lib/services/services.js +0 -1
- package/src/webex-core.js +1 -13
- package/test/unit/spec/credentials/credentials.js +13 -169
- package/test/unit/spec/interceptors/auth.js +0 -3
- package/test/unit/spec/interceptors/webex-user-agent.js +6 -6
- package/test/unit/spec/services/interceptors/service.js +3 -9
- package/test/unit/spec/webex-core.js +0 -12
- package/dist/lib/constants.js +0 -13
- package/dist/lib/constants.js.map +0 -1
- package/src/lib/constants.js +0 -6
- package/test/unit/spec/credentials/scope.js +0 -55
|
@@ -13,11 +13,10 @@ 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
|
|
17
|
-
import {filterScope,
|
|
16
|
+
import grantErrors from './grant-errors';
|
|
17
|
+
import {filterScope, sortScope} from './scope';
|
|
18
18
|
import Token from './token';
|
|
19
19
|
import TokenCollection from './token-collection';
|
|
20
|
-
import {METRICS} from '../constants';
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
22
|
* @class
|
|
@@ -49,25 +48,6 @@ const Credentials = WebexPlugin.extend({
|
|
|
49
48
|
return Boolean(this.supertoken && this.supertoken.canRefresh);
|
|
50
49
|
},
|
|
51
50
|
},
|
|
52
|
-
isUnverifiedGuest: {
|
|
53
|
-
deps: ['supertoken'],
|
|
54
|
-
/**
|
|
55
|
-
* Returns true if the user is an unverified guest
|
|
56
|
-
* @returns {boolean}
|
|
57
|
-
*/
|
|
58
|
-
fn() {
|
|
59
|
-
let isGuest = false;
|
|
60
|
-
try {
|
|
61
|
-
isGuest =
|
|
62
|
-
JSON.parse(base64.decode(this.supertoken.access_token.split('.')[1])).user_type ===
|
|
63
|
-
'guest';
|
|
64
|
-
} catch {
|
|
65
|
-
/* the non-guest token is formatted differently so catch is expected */
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return isGuest;
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
51
|
},
|
|
72
52
|
|
|
73
53
|
props: {
|
|
@@ -260,15 +240,8 @@ const Credentials = WebexPlugin.extend({
|
|
|
260
240
|
*/
|
|
261
241
|
downscope(scope) {
|
|
262
242
|
return this.supertoken.downscope(scope).catch((reason) => {
|
|
263
|
-
|
|
264
|
-
this.logger.warn(`credentials: failed to downscope supertoken to "${scope}"`, failReason);
|
|
243
|
+
this.logger.trace(`credentials: failed to downscope supertoken to ${scope}`, reason);
|
|
265
244
|
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
|
-
});
|
|
272
245
|
|
|
273
246
|
return Promise.resolve(new Token({scope, ...this.supertoken.serialize()}), {
|
|
274
247
|
parent: this,
|
|
@@ -349,12 +322,12 @@ const Credentials = WebexPlugin.extend({
|
|
|
349
322
|
}
|
|
350
323
|
|
|
351
324
|
if (!scope) {
|
|
352
|
-
scope = filterScope('spark:kms', this.
|
|
325
|
+
scope = filterScope('spark:kms', this.config.scope);
|
|
353
326
|
}
|
|
354
327
|
|
|
355
328
|
scope = sortScope(scope);
|
|
356
329
|
|
|
357
|
-
if (scope === sortScope(this.
|
|
330
|
+
if (scope === sortScope(this.config.scope)) {
|
|
358
331
|
return Promise.resolve(this.supertoken);
|
|
359
332
|
}
|
|
360
333
|
|
|
@@ -504,23 +477,6 @@ const Credentials = WebexPlugin.extend({
|
|
|
504
477
|
|
|
505
478
|
return supertoken
|
|
506
479
|
.refresh()
|
|
507
|
-
.catch((error) => {
|
|
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.
|
|
511
|
-
this.unset('supertoken');
|
|
512
|
-
while (this.userTokens.models.length) {
|
|
513
|
-
try {
|
|
514
|
-
this.userTokens.remove(this.userTokens.models[0]);
|
|
515
|
-
} catch (err) {
|
|
516
|
-
this.logger.warn('credentials: failed to remove user token', err);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
this.webex.trigger('client:InvalidRequestError');
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
return Promise.reject(error);
|
|
523
|
-
})
|
|
524
480
|
.then((st) => {
|
|
525
481
|
// clear refresh timer
|
|
526
482
|
if (this.refreshTimer) {
|
|
@@ -529,44 +485,46 @@ const Credentials = WebexPlugin.extend({
|
|
|
529
485
|
}
|
|
530
486
|
this.supertoken = st;
|
|
531
487
|
|
|
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
488
|
return Promise.all(
|
|
545
|
-
tokens.map((token) =>
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
});
|
|
563
|
-
})
|
|
564
|
-
);
|
|
565
|
-
})
|
|
489
|
+
tokens.map((token) =>
|
|
490
|
+
this.downscope(token.scope)
|
|
491
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
492
|
+
.then((t) => {
|
|
493
|
+
this.logger.info(`credentials: revoking token for ${token.scope}`);
|
|
494
|
+
|
|
495
|
+
return token
|
|
496
|
+
.revoke()
|
|
497
|
+
.catch((err) => {
|
|
498
|
+
this.logger.warn('credentials: failed to revoke user token', err);
|
|
499
|
+
})
|
|
500
|
+
.then(() => {
|
|
501
|
+
this.userTokens.remove(token.scope);
|
|
502
|
+
this.userTokens.add(t);
|
|
503
|
+
});
|
|
504
|
+
})
|
|
505
|
+
)
|
|
566
506
|
);
|
|
567
507
|
})
|
|
568
508
|
.then(() => {
|
|
569
509
|
this.scheduleRefresh(this.supertoken.expires);
|
|
510
|
+
})
|
|
511
|
+
.catch((error) => {
|
|
512
|
+
const {InvalidRequestError} = grantErrors;
|
|
513
|
+
|
|
514
|
+
if (error instanceof InvalidRequestError) {
|
|
515
|
+
// Error: The refresh token provided is expired, revoked, malformed, or invalid. Hence emit an event to the client, an opportunity to logout.
|
|
516
|
+
this.unset('supertoken');
|
|
517
|
+
while (this.userTokens.models.length) {
|
|
518
|
+
try {
|
|
519
|
+
this.userTokens.remove(this.userTokens.models[0]);
|
|
520
|
+
} catch (err) {
|
|
521
|
+
this.logger.warn('credentials: failed to remove user token', err);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
this.webex.trigger('client:InvalidRequestError');
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return Promise.reject(error);
|
|
570
528
|
});
|
|
571
529
|
},
|
|
572
530
|
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {difference} from 'lodash';
|
|
6
|
-
|
|
7
5
|
/**
|
|
8
6
|
* sorts a list of scopes
|
|
9
7
|
* @param {string} scope
|
|
@@ -19,7 +17,7 @@ export function sortScope(scope) {
|
|
|
19
17
|
|
|
20
18
|
/**
|
|
21
19
|
* sorts a list of scopes and filters the specified scope
|
|
22
|
-
* @param {string
|
|
20
|
+
* @param {string} toFilter
|
|
23
21
|
* @param {string} scope
|
|
24
22
|
* @returns {string}
|
|
25
23
|
*/
|
|
@@ -27,25 +25,10 @@ export function filterScope(toFilter, scope) {
|
|
|
27
25
|
if (!scope) {
|
|
28
26
|
return '';
|
|
29
27
|
}
|
|
30
|
-
const toFilterArr = Array.isArray(toFilter) ? toFilter : [toFilter];
|
|
31
28
|
|
|
32
29
|
return scope
|
|
33
30
|
.split(' ')
|
|
34
|
-
.filter((item) =>
|
|
31
|
+
.filter((item) => item !== toFilter)
|
|
35
32
|
.sort()
|
|
36
33
|
.join(' ');
|
|
37
34
|
}
|
|
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
|
-
}
|
|
@@ -36,11 +36,11 @@ export default class ServiceInterceptor extends Interceptor {
|
|
|
36
36
|
|
|
37
37
|
// Destructure commonly referenced namespaces.
|
|
38
38
|
const {services} = this.webex.internal;
|
|
39
|
-
const {service, resource
|
|
39
|
+
const {service, resource} = options;
|
|
40
40
|
|
|
41
41
|
// Attempt to collect the service url.
|
|
42
42
|
return services
|
|
43
|
-
.waitForService({name: service
|
|
43
|
+
.waitForService({name: service})
|
|
44
44
|
.then((serviceUrl) => {
|
|
45
45
|
// Generate the combined service url and resource.
|
|
46
46
|
options.uri = this.generateUri(serviceUrl, resource);
|
|
@@ -413,8 +413,6 @@ const ServiceCatalog = AmpState.extend({
|
|
|
413
413
|
resolve();
|
|
414
414
|
}
|
|
415
415
|
|
|
416
|
-
const validatedTimeout = typeof timeout === 'number' && timeout >= 0 ? timeout : 60;
|
|
417
|
-
|
|
418
416
|
const timeoutTimer = setTimeout(
|
|
419
417
|
() =>
|
|
420
418
|
reject(
|
|
@@ -422,7 +420,7 @@ const ServiceCatalog = AmpState.extend({
|
|
|
422
420
|
`services: timeout occured while waiting for '${serviceGroup}' catalog to populate`
|
|
423
421
|
)
|
|
424
422
|
),
|
|
425
|
-
|
|
423
|
+
timeout ? timeout * 1000 : 60000
|
|
426
424
|
);
|
|
427
425
|
|
|
428
426
|
this.once(serviceGroup, () => {
|
|
@@ -682,7 +682,6 @@ const Services = WebexPlugin.extend({
|
|
|
682
682
|
* @returns {object}
|
|
683
683
|
*/
|
|
684
684
|
_formatReceivedHostmap(serviceHostmap) {
|
|
685
|
-
this._updateHostCatalog(serviceHostmap.hostCatalog);
|
|
686
685
|
// map the host catalog items to a formatted hostmap
|
|
687
686
|
const formattedHostmap = Object.keys(serviceHostmap.hostCatalog).reduce((accumulator, key) => {
|
|
688
687
|
if (serviceHostmap.hostCatalog[key].length === 0) {
|
package/src/webex-core.js
CHANGED
|
@@ -6,12 +6,7 @@ import {EventEmitter} from 'events';
|
|
|
6
6
|
import util from 'util';
|
|
7
7
|
|
|
8
8
|
import {proxyEvents, retry, transferEvents} from '@webex/common';
|
|
9
|
-
import {
|
|
10
|
-
HttpStatusInterceptor,
|
|
11
|
-
defaults as requestDefaults,
|
|
12
|
-
protoprepareFetchOptions as prepareFetchOptions,
|
|
13
|
-
setTimingsAndFetch as _setTimingsAndFetch,
|
|
14
|
-
} from '@webex/http-core';
|
|
9
|
+
import {HttpStatusInterceptor, defaults as requestDefaults} from '@webex/http-core';
|
|
15
10
|
import {defaultsDeep, get, isFunction, isString, last, merge, omit, set, unset} from 'lodash';
|
|
16
11
|
import AmpState from 'ampersand-state';
|
|
17
12
|
import uuid from 'uuid';
|
|
@@ -407,13 +402,6 @@ const WebexCore = AmpState.extend({
|
|
|
407
402
|
interceptors: ints,
|
|
408
403
|
});
|
|
409
404
|
|
|
410
|
-
this.prepareFetchOptions = prepareFetchOptions({
|
|
411
|
-
json: true,
|
|
412
|
-
interceptors: ints,
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
this.setTimingsAndFetch = _setTimingsAndFetch;
|
|
416
|
-
|
|
417
405
|
let sessionId = `${get(this, 'config.trackingIdPrefix', 'webex-js-sdk')}_${get(
|
|
418
406
|
this,
|
|
419
407
|
'config.trackingIdBase',
|
|
@@ -11,7 +11,6 @@ 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';
|
|
15
14
|
|
|
16
15
|
/* eslint camelcase: [0] */
|
|
17
16
|
|
|
@@ -60,35 +59,6 @@ describe('webex-core', () => {
|
|
|
60
59
|
});
|
|
61
60
|
});
|
|
62
61
|
|
|
63
|
-
describe('#isUnverifiedGuest', () => {
|
|
64
|
-
let credentials;
|
|
65
|
-
let webex;
|
|
66
|
-
beforeEach(() => {
|
|
67
|
-
//generate the webex instance
|
|
68
|
-
webex = new MockWebex();
|
|
69
|
-
credentials = new Credentials(undefined, {parent: webex});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should have #isUnverifiedGuest', () => {
|
|
73
|
-
assert.exists(credentials.isUnverifiedGuest);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should get the user status and return as a boolean', () => {
|
|
77
|
-
credentials.set('supertoken', 'AT');
|
|
78
|
-
assert.isFalse(credentials.isUnverifiedGuest);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('should get guest user ', () => {
|
|
82
|
-
credentials.set('supertoken', 'eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyX3R5cGUiOiJndWVzdCJ9');
|
|
83
|
-
assert.isTrue(credentials.isUnverifiedGuest);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('should get login user ', () => {
|
|
87
|
-
credentials.set('supertoken', 'dGhpc2lzbm90YXJlYWx1c2VydG9rZW4=');
|
|
88
|
-
assert.isFalse(credentials.isUnverifiedGuest);
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
62
|
describe('#canAuthorize', () => {
|
|
93
63
|
it('indicates if the current state has enough information to populate an auth header, even if a token refresh or token downscope is required', () => {
|
|
94
64
|
const webex = new MockWebex();
|
|
@@ -447,11 +417,7 @@ describe('webex-core', () => {
|
|
|
447
417
|
});
|
|
448
418
|
|
|
449
419
|
it('schedules a refreshTimer', () => {
|
|
450
|
-
const webex = new MockWebex(
|
|
451
|
-
children: {
|
|
452
|
-
metrics: Metrics,
|
|
453
|
-
},
|
|
454
|
-
});
|
|
420
|
+
const webex = new MockWebex();
|
|
455
421
|
const supertoken = makeToken(webex, {
|
|
456
422
|
access_token: 'ST',
|
|
457
423
|
refresh_token: 'RT',
|
|
@@ -464,7 +430,6 @@ describe('webex-core', () => {
|
|
|
464
430
|
});
|
|
465
431
|
|
|
466
432
|
sinon.stub(supertoken, 'refresh').returns(Promise.resolve(supertoken2));
|
|
467
|
-
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
468
433
|
const credentials = new Credentials(supertoken, {parent: webex});
|
|
469
434
|
|
|
470
435
|
webex.trigger('change:config');
|
|
@@ -499,19 +464,7 @@ describe('webex-core', () => {
|
|
|
499
464
|
});
|
|
500
465
|
|
|
501
466
|
describe('#getUserToken()', () => {
|
|
502
|
-
it('resolves with the supertoken if the supertoken matches the requested scopes'
|
|
503
|
-
const webex = new MockWebex();
|
|
504
|
-
const credentials = new Credentials(undefined, {parent: webex});
|
|
505
|
-
|
|
506
|
-
webex.trigger('change:config');
|
|
507
|
-
const st = makeToken(webex, {access_token: 'ST', scope: 'scope1'});
|
|
508
|
-
|
|
509
|
-
credentials.set({
|
|
510
|
-
supertoken: st,
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
return credentials.getUserToken('scope1').then((result) => assert.deepEqual(result, st));
|
|
514
|
-
});
|
|
467
|
+
// it('resolves with the supertoken if the supertoken matches the requested scopes');
|
|
515
468
|
|
|
516
469
|
it('resolves with the token identified by the specified scopes', () => {
|
|
517
470
|
const webex = new MockWebex();
|
|
@@ -539,25 +492,6 @@ describe('webex-core', () => {
|
|
|
539
492
|
]);
|
|
540
493
|
});
|
|
541
494
|
|
|
542
|
-
it('uses the supertoken.scope instead of the config.scope for downscope', () => {
|
|
543
|
-
const webex = new MockWebex();
|
|
544
|
-
const credentials = new Credentials(undefined, {parent: webex});
|
|
545
|
-
|
|
546
|
-
webex.trigger('change:config');
|
|
547
|
-
const st = makeToken(webex, {access_token: 'ST', scope: 'scope1 spark:kms'});
|
|
548
|
-
|
|
549
|
-
credentials.set({
|
|
550
|
-
supertoken: st,
|
|
551
|
-
scope: 'invalidScope scope1',
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
sinon.stub(credentials, 'downscope').returns(Promise.resolve());
|
|
555
|
-
|
|
556
|
-
return credentials.getUserToken().then(() => {
|
|
557
|
-
assert.calledWith(credentials.downscope, 'scope1');
|
|
558
|
-
});
|
|
559
|
-
});
|
|
560
|
-
|
|
561
495
|
describe('when no matching token is found', () => {
|
|
562
496
|
it('downscopes the supertoken', () => {
|
|
563
497
|
const webex = new MockWebex();
|
|
@@ -595,13 +529,13 @@ describe('webex-core', () => {
|
|
|
595
529
|
it('resolves with a token containing all but the kms scopes', () => {
|
|
596
530
|
const webex = new MockWebex();
|
|
597
531
|
|
|
532
|
+
webex.config.credentials.scope = 'scope1 spark:kms';
|
|
598
533
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
599
534
|
|
|
600
535
|
webex.trigger('change:config');
|
|
601
536
|
|
|
602
537
|
credentials.supertoken = makeToken(webex, {
|
|
603
538
|
access_token: 'ST',
|
|
604
|
-
scope: 'scope1 spark:kms',
|
|
605
539
|
});
|
|
606
540
|
|
|
607
541
|
// const t2 = makeToken(webex, {
|
|
@@ -628,11 +562,9 @@ describe('webex-core', () => {
|
|
|
628
562
|
const webex = new MockWebex({
|
|
629
563
|
children: {
|
|
630
564
|
logger: Logger,
|
|
631
|
-
metrics: Metrics,
|
|
632
565
|
},
|
|
633
566
|
});
|
|
634
567
|
|
|
635
|
-
webex.config.metrics = config.metrics;
|
|
636
568
|
webex.config.credentials.scope = 'scope1 spark:kms';
|
|
637
569
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
638
570
|
|
|
@@ -642,11 +574,9 @@ describe('webex-core', () => {
|
|
|
642
574
|
access_token: 'ST',
|
|
643
575
|
});
|
|
644
576
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
sinon.stub(credentials.logger, 'warn').callsFake(() => {});
|
|
649
|
-
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
577
|
+
sinon
|
|
578
|
+
.stub(credentials.supertoken, 'downscope')
|
|
579
|
+
.returns(Promise.reject(new Error('downscope failed')));
|
|
650
580
|
|
|
651
581
|
const t1 = makeToken(webex, {
|
|
652
582
|
access_token: 'AT1',
|
|
@@ -657,27 +587,14 @@ describe('webex-core', () => {
|
|
|
657
587
|
userTokens: [t1],
|
|
658
588
|
});
|
|
659
589
|
|
|
660
|
-
return credentials
|
|
661
|
-
|
|
662
|
-
assert.
|
|
663
|
-
credentials.logger.warn,
|
|
664
|
-
'credentials: failed to downscope supertoken to "scope2"'
|
|
665
|
-
);
|
|
666
|
-
assert.calledWith(
|
|
667
|
-
webex.internal.metrics.submitClientMetrics,
|
|
668
|
-
'JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED',
|
|
669
|
-
{fields: {failReason, requestedScope: 'scope2'}}
|
|
670
|
-
);
|
|
671
|
-
});
|
|
590
|
+
return credentials
|
|
591
|
+
.getUserToken('scope2')
|
|
592
|
+
.then((t) => assert.equal(t.access_token, credentials.supertoken.access_token));
|
|
672
593
|
});
|
|
673
594
|
});
|
|
674
595
|
|
|
675
596
|
it('is blocked while a token refresh is inflight', () => {
|
|
676
|
-
const webex = new MockWebex(
|
|
677
|
-
children: {
|
|
678
|
-
metrics: Metrics,
|
|
679
|
-
},
|
|
680
|
-
});
|
|
597
|
+
const webex = new MockWebex();
|
|
681
598
|
|
|
682
599
|
webex.config.credentials.scope = 'scope1 spark:kms';
|
|
683
600
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
@@ -703,7 +620,6 @@ describe('webex-core', () => {
|
|
|
703
620
|
const at2 = makeToken(webex, {access_token: 'ST2ATD'});
|
|
704
621
|
|
|
705
622
|
sinon.stub(supertoken2, 'downscope').returns(Promise.resolve(at2));
|
|
706
|
-
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
707
623
|
|
|
708
624
|
return Promise.all([
|
|
709
625
|
credentials.refresh(),
|
|
@@ -835,24 +751,18 @@ describe('webex-core', () => {
|
|
|
835
751
|
|
|
836
752
|
describe('#refresh()', () => {
|
|
837
753
|
it('refreshes and downscopes the supertoken, and revokes previous tokens', () => {
|
|
838
|
-
const webex = new MockWebex(
|
|
839
|
-
children: {
|
|
840
|
-
metrics: Metrics,
|
|
841
|
-
},
|
|
842
|
-
});
|
|
754
|
+
const webex = new MockWebex();
|
|
843
755
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
844
756
|
|
|
845
757
|
webex.trigger('change:config');
|
|
846
758
|
const st = makeToken(webex, {
|
|
847
759
|
access_token: 'ST',
|
|
848
760
|
refresh_token: 'RT',
|
|
849
|
-
scope: 'scope1 scope2',
|
|
850
761
|
});
|
|
851
762
|
|
|
852
763
|
const st2 = makeToken(webex, {
|
|
853
764
|
access_token: 'ST2',
|
|
854
765
|
refresh_token: 'RT2',
|
|
855
|
-
scope: 'scope1 scope2',
|
|
856
766
|
});
|
|
857
767
|
|
|
858
768
|
const t1 = makeToken(webex, {
|
|
@@ -869,7 +779,6 @@ describe('webex-core', () => {
|
|
|
869
779
|
sinon.stub(st, 'refresh').returns(Promise.resolve(st2));
|
|
870
780
|
sinon.stub(t1, 'revoke').returns(Promise.resolve());
|
|
871
781
|
sinon.spy(credentials, 'scheduleRefresh');
|
|
872
|
-
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
873
782
|
|
|
874
783
|
credentials.set({
|
|
875
784
|
supertoken: st,
|
|
@@ -889,11 +798,7 @@ describe('webex-core', () => {
|
|
|
889
798
|
});
|
|
890
799
|
|
|
891
800
|
it('refreshes and downscopes the supertoken even if revocation of previous token fails', () => {
|
|
892
|
-
const webex = new MockWebex(
|
|
893
|
-
children: {
|
|
894
|
-
metrics: Metrics,
|
|
895
|
-
},
|
|
896
|
-
});
|
|
801
|
+
const webex = new MockWebex();
|
|
897
802
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
898
803
|
|
|
899
804
|
webex.trigger('change:config');
|
|
@@ -905,7 +810,6 @@ describe('webex-core', () => {
|
|
|
905
810
|
const st2 = makeToken(webex, {
|
|
906
811
|
access_token: 'ST2',
|
|
907
812
|
refresh_token: 'RT2',
|
|
908
|
-
scope: 'scope1 scope2',
|
|
909
813
|
});
|
|
910
814
|
|
|
911
815
|
const t1 = makeToken(webex, {
|
|
@@ -922,7 +826,6 @@ describe('webex-core', () => {
|
|
|
922
826
|
sinon.stub(st, 'refresh').returns(Promise.resolve(st2));
|
|
923
827
|
sinon.stub(t1, 'revoke').returns(Promise.reject());
|
|
924
828
|
sinon.spy(credentials, 'scheduleRefresh');
|
|
925
|
-
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
926
829
|
|
|
927
830
|
credentials.set({
|
|
928
831
|
supertoken: st,
|
|
@@ -945,7 +848,6 @@ describe('webex-core', () => {
|
|
|
945
848
|
const webex = new MockWebex({
|
|
946
849
|
children: {
|
|
947
850
|
logger: Logger,
|
|
948
|
-
metrics: Metrics,
|
|
949
851
|
},
|
|
950
852
|
});
|
|
951
853
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
@@ -954,11 +856,9 @@ describe('webex-core', () => {
|
|
|
954
856
|
const st = makeToken(webex, {
|
|
955
857
|
access_token: 'ST',
|
|
956
858
|
refresh_token: 'RT',
|
|
957
|
-
scope: '',
|
|
958
859
|
});
|
|
959
860
|
|
|
960
861
|
sinon.stub(st, 'refresh').returns(Promise.resolve(makeToken(webex, {access_token: 'ST2'})));
|
|
961
|
-
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
962
862
|
|
|
963
863
|
const t1 = makeToken(webex, {
|
|
964
864
|
access_token: 'AT1',
|
|
@@ -974,7 +874,7 @@ describe('webex-core', () => {
|
|
|
974
874
|
});
|
|
975
875
|
|
|
976
876
|
it('allows #getUserToken() to be revoked, but #getUserToken() promises will not resolve until the suport token has been refreshed', () => {
|
|
977
|
-
const webex = new MockWebex(
|
|
877
|
+
const webex = new MockWebex();
|
|
978
878
|
const credentials = new Credentials(undefined, {parent: webex});
|
|
979
879
|
|
|
980
880
|
webex.trigger('change:config');
|
|
@@ -1000,7 +900,6 @@ describe('webex-core', () => {
|
|
|
1000
900
|
|
|
1001
901
|
sinon.stub(st1, 'refresh').returns(Promise.resolve(st2));
|
|
1002
902
|
sinon.stub(st2, 'downscope').returns(Promise.resolve(t2));
|
|
1003
|
-
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
1004
903
|
|
|
1005
904
|
credentials.set({
|
|
1006
905
|
supertoken: st1,
|
|
@@ -1057,61 +956,6 @@ describe('webex-core', () => {
|
|
|
1057
956
|
assert.calledWith(triggerSpy, sinon.match('client:InvalidRequestError'));
|
|
1058
957
|
});
|
|
1059
958
|
});
|
|
1060
|
-
|
|
1061
|
-
it('exclude invalid scopes from user token, log and call metrics when fetched supertoken scope mismatch with the configured scope', () => {
|
|
1062
|
-
const webex = new MockWebex({
|
|
1063
|
-
children: {
|
|
1064
|
-
logger: Logger,
|
|
1065
|
-
metrics: Metrics,
|
|
1066
|
-
},
|
|
1067
|
-
});
|
|
1068
|
-
const credentials = new Credentials(undefined, {parent: webex});
|
|
1069
|
-
|
|
1070
|
-
webex.trigger('change:config');
|
|
1071
|
-
const st = makeToken(webex, {
|
|
1072
|
-
access_token: 'ST',
|
|
1073
|
-
refresh_token: 'RT',
|
|
1074
|
-
});
|
|
1075
|
-
|
|
1076
|
-
const st2 = makeToken(webex, {
|
|
1077
|
-
access_token: 'ST2',
|
|
1078
|
-
refresh_token: 'RT2',
|
|
1079
|
-
scope: 'scope1',
|
|
1080
|
-
});
|
|
1081
|
-
|
|
1082
|
-
const userToken = makeToken(webex, {
|
|
1083
|
-
access_token: 'AT1',
|
|
1084
|
-
scope: 'scope1 invalidScope1',
|
|
1085
|
-
});
|
|
1086
|
-
|
|
1087
|
-
credentials.set({
|
|
1088
|
-
supertoken: st,
|
|
1089
|
-
userTokens: [userToken],
|
|
1090
|
-
});
|
|
1091
|
-
const invalidScopes = 'invalidScope1 invalidScope2';
|
|
1092
|
-
credentials.config.scope = `scope1 ${invalidScopes}`;
|
|
1093
|
-
|
|
1094
|
-
sinon.stub(st2, 'downscope').returns(Promise.resolve());
|
|
1095
|
-
sinon.stub(st, 'refresh').returns(Promise.resolve(st2));
|
|
1096
|
-
sinon.spy(credentials, 'downscope');
|
|
1097
|
-
sinon.spy(credentials, 'scheduleRefresh');
|
|
1098
|
-
|
|
1099
|
-
sinon.stub(credentials.logger, 'warn').callsFake(() => {});
|
|
1100
|
-
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
1101
|
-
|
|
1102
|
-
return credentials.refresh().then(() => {
|
|
1103
|
-
assert.calledWith(
|
|
1104
|
-
credentials.logger.warn,
|
|
1105
|
-
`credentials: "${invalidScopes}" scope(s) are invalid because not listed in the supertoken, they will be excluded from user token requests.`
|
|
1106
|
-
);
|
|
1107
|
-
assert.calledWith(
|
|
1108
|
-
webex.internal.metrics.submitClientMetrics,
|
|
1109
|
-
'JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH',
|
|
1110
|
-
{fields: {invalidScopes}}
|
|
1111
|
-
);
|
|
1112
|
-
assert.calledWith(credentials.downscope, 'scope1');
|
|
1113
|
-
});
|
|
1114
|
-
});
|
|
1115
959
|
});
|
|
1116
960
|
|
|
1117
961
|
describe('#scheduleRefresh()', () => {
|
|
@@ -12,7 +12,6 @@ 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';
|
|
16
15
|
|
|
17
16
|
const {assert} = chai;
|
|
18
17
|
|
|
@@ -29,7 +28,6 @@ describe('webex-core', () => {
|
|
|
29
28
|
children: {
|
|
30
29
|
credentials: Credentials,
|
|
31
30
|
logger: Logger,
|
|
32
|
-
metrics: Metrics,
|
|
33
31
|
},
|
|
34
32
|
config: merge(cloneDeep(config), {credentials: {client_secret: 'fake'}}),
|
|
35
33
|
});
|
|
@@ -43,7 +41,6 @@ describe('webex-core', () => {
|
|
|
43
41
|
);
|
|
44
42
|
|
|
45
43
|
interceptor = Reflect.apply(AuthInterceptor.create, webex, []);
|
|
46
|
-
sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
|
|
47
44
|
});
|
|
48
45
|
|
|
49
46
|
describe('#onRequest()', () => {
|