@webex/plugin-authorization-browser-first-party 3.6.0-next.5 → 3.6.0-next.7
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/authorization.js +119 -39
- package/dist/authorization.js.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/authorization.js +122 -37
- package/src/index.js +1 -1
- package/test/unit/spec/authorization.js +212 -100
package/dist/authorization.js
CHANGED
|
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequ
|
|
|
5
5
|
_Object$defineProperty(exports, "__esModule", {
|
|
6
6
|
value: true
|
|
7
7
|
});
|
|
8
|
-
exports.default = void 0;
|
|
8
|
+
exports.default = exports.Events = void 0;
|
|
9
9
|
var _apply = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/reflect/apply"));
|
|
10
10
|
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
|
|
11
11
|
var _assign = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/assign"));
|
|
@@ -33,6 +33,16 @@ var lodash = require('lodash');
|
|
|
33
33
|
var OAUTH2_CSRF_TOKEN = 'oauth2-csrf-token';
|
|
34
34
|
var OAUTH2_CODE_VERIFIER = 'oauth2-code-verifier';
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Authorization plugin events
|
|
38
|
+
*/
|
|
39
|
+
var Events = exports.Events = {
|
|
40
|
+
/**
|
|
41
|
+
* QR code login events
|
|
42
|
+
*/
|
|
43
|
+
qRCodeLogin: 'qRCodeLogin'
|
|
44
|
+
};
|
|
45
|
+
|
|
36
46
|
/**
|
|
37
47
|
* Browser support for OAuth2. Automatically parses the URL query for an
|
|
38
48
|
* authorization code
|
|
@@ -76,14 +86,45 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
|
|
|
76
86
|
},
|
|
77
87
|
namespace: 'Credentials',
|
|
78
88
|
/**
|
|
79
|
-
*
|
|
89
|
+
* EventEmitter for authorization events
|
|
90
|
+
* @instance
|
|
91
|
+
* @memberof AuthorizationBrowserFirstParty
|
|
92
|
+
* @type {EventEmitter}
|
|
93
|
+
* @public
|
|
94
|
+
*/
|
|
95
|
+
eventEmitter: new _events.EventEmitter(),
|
|
96
|
+
/**
|
|
97
|
+
* Stores the timer ID for QR code polling
|
|
80
98
|
* @instance
|
|
81
99
|
* @memberof AuthorizationBrowserFirstParty
|
|
82
100
|
* @type {?number}
|
|
83
101
|
* @private
|
|
84
102
|
*/
|
|
85
|
-
|
|
86
|
-
|
|
103
|
+
pollingTimer: null,
|
|
104
|
+
/**
|
|
105
|
+
* Stores the expiration timer ID for QR code polling
|
|
106
|
+
* @instance
|
|
107
|
+
* @memberof AuthorizationBrowserFirstParty
|
|
108
|
+
* @type {?number}
|
|
109
|
+
* @private
|
|
110
|
+
*/
|
|
111
|
+
pollingExpirationTimer: null,
|
|
112
|
+
/**
|
|
113
|
+
* Monotonically increasing id to identify the current polling request
|
|
114
|
+
* @instance
|
|
115
|
+
* @memberof AuthorizationBrowserFirstParty
|
|
116
|
+
* @type {number}
|
|
117
|
+
* @private
|
|
118
|
+
*/
|
|
119
|
+
pollingId: 0,
|
|
120
|
+
/**
|
|
121
|
+
* Identifier for the current polling request
|
|
122
|
+
* @instance
|
|
123
|
+
* @memberof AuthorizationBrowserFirstParty
|
|
124
|
+
* @type {?number}
|
|
125
|
+
* @private
|
|
126
|
+
*/
|
|
127
|
+
currentPollingId: null,
|
|
87
128
|
/**
|
|
88
129
|
* Initializer
|
|
89
130
|
* @instance
|
|
@@ -241,6 +282,28 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
|
|
|
241
282
|
return _promise.default.reject(new ErrorConstructor(res._res || res));
|
|
242
283
|
});
|
|
243
284
|
},
|
|
285
|
+
/**
|
|
286
|
+
* Generate a QR code URL to launch the Webex app when scanning with the camera
|
|
287
|
+
* @instance
|
|
288
|
+
* @memberof AuthorizationBrowserFirstParty
|
|
289
|
+
* @param {String} verificationUrl
|
|
290
|
+
* @returns {String}
|
|
291
|
+
*/
|
|
292
|
+
_generateQRCodeVerificationUrl: function _generateQRCodeVerificationUrl(verificationUrl) {
|
|
293
|
+
var baseUrl = 'https://web.webex.com/deviceAuth';
|
|
294
|
+
var urlParams = new URLSearchParams(new URL(verificationUrl).search);
|
|
295
|
+
var userCode = urlParams.get('userCode');
|
|
296
|
+
if (userCode) {
|
|
297
|
+
var services = this.webex.internal.services;
|
|
298
|
+
var oauthHelperUrl = services.get('oauth-helper');
|
|
299
|
+
var newVerificationUrl = new URL(baseUrl);
|
|
300
|
+
newVerificationUrl.searchParams.set('usercode', userCode);
|
|
301
|
+
newVerificationUrl.searchParams.set('oauthhelper', oauthHelperUrl);
|
|
302
|
+
return newVerificationUrl.toString();
|
|
303
|
+
} else {
|
|
304
|
+
return verificationUrl;
|
|
305
|
+
}
|
|
306
|
+
},
|
|
244
307
|
/**
|
|
245
308
|
* Get an OAuth Login URL for QRCode. Generate QR code based on the returned URL.
|
|
246
309
|
* @instance
|
|
@@ -249,8 +312,8 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
|
|
|
249
312
|
*/
|
|
250
313
|
initQRCodeLogin: function initQRCodeLogin() {
|
|
251
314
|
var _this3 = this;
|
|
252
|
-
if (this.
|
|
253
|
-
this.eventEmitter.emit(
|
|
315
|
+
if (this.pollingTimer) {
|
|
316
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
254
317
|
eventType: 'getUserCodeFailure',
|
|
255
318
|
data: {
|
|
256
319
|
message: 'There is already a polling request'
|
|
@@ -276,18 +339,19 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
|
|
|
276
339
|
user_code = _res$body.user_code,
|
|
277
340
|
verification_uri = _res$body.verification_uri,
|
|
278
341
|
verification_uri_complete = _res$body.verification_uri_complete;
|
|
279
|
-
_this3.
|
|
342
|
+
var verificationUriComplete = _this3._generateQRCodeVerificationUrl(verification_uri_complete);
|
|
343
|
+
_this3.eventEmitter.emit(Events.qRCodeLogin, {
|
|
280
344
|
eventType: 'getUserCodeSuccess',
|
|
281
345
|
userData: {
|
|
282
346
|
userCode: user_code,
|
|
283
347
|
verificationUri: verification_uri,
|
|
284
|
-
verificationUriComplete:
|
|
348
|
+
verificationUriComplete: verificationUriComplete
|
|
285
349
|
}
|
|
286
350
|
});
|
|
287
351
|
// if device authorization success, then start to poll server to check whether the user has completed authorization
|
|
288
352
|
_this3._startQRCodePolling(res.body);
|
|
289
353
|
}).catch(function (res) {
|
|
290
|
-
_this3.eventEmitter.emit(
|
|
354
|
+
_this3.eventEmitter.emit(Events.qRCodeLogin, {
|
|
291
355
|
eventType: 'getUserCodeFailure',
|
|
292
356
|
data: res.body
|
|
293
357
|
});
|
|
@@ -301,10 +365,11 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
|
|
|
301
365
|
* @emits #qRCodeLogin
|
|
302
366
|
*/
|
|
303
367
|
_startQRCodePolling: function _startQRCodePolling() {
|
|
304
|
-
var
|
|
368
|
+
var _options$interval,
|
|
369
|
+
_this4 = this;
|
|
305
370
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
306
371
|
if (!options.device_code) {
|
|
307
|
-
this.eventEmitter.emit(
|
|
372
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
308
373
|
eventType: 'authorizationFailure',
|
|
309
374
|
data: {
|
|
310
375
|
message: 'A deviceCode is required'
|
|
@@ -312,8 +377,8 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
|
|
|
312
377
|
});
|
|
313
378
|
return;
|
|
314
379
|
}
|
|
315
|
-
if (this.
|
|
316
|
-
this.eventEmitter.emit(
|
|
380
|
+
if (this.pollingTimer) {
|
|
381
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
317
382
|
eventType: 'authorizationFailure',
|
|
318
383
|
data: {
|
|
319
384
|
message: 'There is already a polling request'
|
|
@@ -322,15 +387,21 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
|
|
|
322
387
|
return;
|
|
323
388
|
}
|
|
324
389
|
var deviceCode = options.device_code,
|
|
325
|
-
_options$interval = options.interval,
|
|
326
|
-
interval = _options$interval === void 0 ? 2 : _options$interval,
|
|
327
390
|
_options$expires_in = options.expires_in,
|
|
328
391
|
expiresIn = _options$expires_in === void 0 ? 300 : _options$expires_in;
|
|
329
|
-
var
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
392
|
+
var interval = (_options$interval = options.interval) !== null && _options$interval !== void 0 ? _options$interval : 2;
|
|
393
|
+
this.pollingExpirationTimer = setTimeout(function () {
|
|
394
|
+
_this4.cancelQRCodePolling(false);
|
|
395
|
+
_this4.eventEmitter.emit(Events.qRCodeLogin, {
|
|
396
|
+
eventType: 'authorizationFailure',
|
|
397
|
+
data: {
|
|
398
|
+
message: 'Authorization timed out'
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}, expiresIn * 1000);
|
|
402
|
+
var polling = function polling() {
|
|
403
|
+
_this4.pollingId += 1;
|
|
404
|
+
_this4.currentPollingId = _this4.pollingId;
|
|
334
405
|
_this4.webex.request({
|
|
335
406
|
method: 'POST',
|
|
336
407
|
service: 'oauth-helper',
|
|
@@ -346,40 +417,45 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
|
|
|
346
417
|
sendImmediately: true
|
|
347
418
|
}
|
|
348
419
|
}).then(function (res) {
|
|
349
|
-
if
|
|
350
|
-
_this4.
|
|
420
|
+
// if the pollingId has changed, it means that the polling request has been canceled
|
|
421
|
+
if (_this4.currentPollingId !== _this4.pollingId) return;
|
|
422
|
+
_this4.eventEmitter.emit(Events.qRCodeLogin, {
|
|
351
423
|
eventType: 'authorizationSuccess',
|
|
352
424
|
data: res.body
|
|
353
425
|
});
|
|
354
426
|
_this4.cancelQRCodePolling();
|
|
355
427
|
}).catch(function (res) {
|
|
356
|
-
if
|
|
357
|
-
if (
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
});
|
|
364
|
-
_this4.cancelQRCodePolling();
|
|
428
|
+
// if the pollingId has changed, it means that the polling request has been canceled
|
|
429
|
+
if (_this4.currentPollingId !== _this4.pollingId) return;
|
|
430
|
+
|
|
431
|
+
// When server sends 400 status code with message 'slow_down', it means that last request happened too soon.
|
|
432
|
+
// So, skip one interval and then poll again.
|
|
433
|
+
if (res.statusCode === 400 && res.body.message === 'slow_down') {
|
|
434
|
+
schedulePolling(interval * 2);
|
|
365
435
|
return;
|
|
366
436
|
}
|
|
437
|
+
|
|
367
438
|
// if the statusCode is 428 which means that the authorization request is still pending
|
|
368
439
|
// as the end user hasn't yet completed the user-interaction steps. So keep polling.
|
|
369
440
|
if (res.statusCode === 428) {
|
|
370
|
-
_this4.eventEmitter.emit(
|
|
441
|
+
_this4.eventEmitter.emit(Events.qRCodeLogin, {
|
|
371
442
|
eventType: 'authorizationPending',
|
|
372
443
|
data: res.body
|
|
373
444
|
});
|
|
445
|
+
schedulePolling(interval);
|
|
374
446
|
return;
|
|
375
447
|
}
|
|
376
448
|
_this4.cancelQRCodePolling();
|
|
377
|
-
_this4.eventEmitter.emit(
|
|
449
|
+
_this4.eventEmitter.emit(Events.qRCodeLogin, {
|
|
378
450
|
eventType: 'authorizationFailure',
|
|
379
451
|
data: res.body
|
|
380
452
|
});
|
|
381
453
|
});
|
|
382
|
-
}
|
|
454
|
+
};
|
|
455
|
+
var schedulePolling = function schedulePolling(interval) {
|
|
456
|
+
return _this4.pollingTimer = setTimeout(polling, interval * 1000);
|
|
457
|
+
};
|
|
458
|
+
schedulePolling(interval);
|
|
383
459
|
},
|
|
384
460
|
/**
|
|
385
461
|
* cancel polling request
|
|
@@ -388,13 +464,17 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
|
|
|
388
464
|
* @returns {void}
|
|
389
465
|
*/
|
|
390
466
|
cancelQRCodePolling: function cancelQRCodePolling() {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
this.eventEmitter.emit(
|
|
467
|
+
var withCancelEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
468
|
+
if (this.pollingTimer && withCancelEvent) {
|
|
469
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
394
470
|
eventType: 'pollingCanceled'
|
|
395
471
|
});
|
|
396
|
-
this.pollingRequest = null;
|
|
397
472
|
}
|
|
473
|
+
this.currentPollingId = null;
|
|
474
|
+
clearTimeout(this.pollingExpirationTimer);
|
|
475
|
+
this.pollingExpirationTimer = null;
|
|
476
|
+
clearTimeout(this.pollingTimer);
|
|
477
|
+
this.pollingTimer = null;
|
|
398
478
|
},
|
|
399
479
|
/**
|
|
400
480
|
* Extracts the orgId from the returned code from idbroker
|
|
@@ -504,7 +584,7 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
|
|
|
504
584
|
throw new Error("CSRF token ".concat(token, " does not match stored token ").concat(sessionToken));
|
|
505
585
|
}
|
|
506
586
|
},
|
|
507
|
-
version: "3.6.0-next.
|
|
587
|
+
version: "3.6.0-next.7"
|
|
508
588
|
}, ((0, _applyDecoratedDescriptor2.default)(_obj, "initiateAuthorizationCodeGrant", [_dec], (0, _getOwnPropertyDescriptor.default)(_obj, "initiateAuthorizationCodeGrant"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "requestAuthorizationCodeGrant", [_dec2, _common.oneFlight], (0, _getOwnPropertyDescriptor.default)(_obj, "requestAuthorizationCodeGrant"), _obj)), _obj)));
|
|
509
589
|
var _default = exports.default = Authorization;
|
|
510
590
|
//# sourceMappingURL=authorization.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_querystring","_interopRequireDefault","require","_url","_events","_common","_webexCore","_lodash","_uuid","_encBase64url","_cryptoJs","_dec","_dec2","_obj","lodash","OAUTH2_CSRF_TOKEN","OAUTH2_CODE_VERIFIER","Authorization","WebexPlugin","extend","whileInFlight","derived","isAuthenticating","deps","fn","isAuthorizing","session","default","type","ready","namespace","pollingRequest","eventEmitter","EventEmitter","initialize","_this","_len","arguments","length","attrs","Array","_key","ret","_apply","prototype","location","url","parse","webex","getWindow","href","_checkForErrors","code","query","state","JSON","base64","decode","codeVerifier","sessionStorage","getItem","removeItem","emailhash","_verifySecurityToken","_cleanUrl","preauthCatalogParams","orgId","_extractOrgIdFromCode","process","nextTick","internal","services","collectPreauthCatalog","catch","_promise","resolve","then","requestAuthorizationCodeGrant","error","logger","warn","initiateLogin","options","undefined","cloneDeep","email","emailHash","CryptoJS","SHA256","toString","csrf_token","_generateSecurityToken","code_challenge","_generateCodeChallenge","code_challenge_method","initiateAuthorizationCodeGrant","info","credentials","buildLoginUrl","_assign","response_type","logout","noRedirect","buildLogoutUrl","_this2","reject","Error","form","grant_type","redirect_uri","config","self_contained_token","code_verifier","request","method","uri","tokenUrl","auth","user","client_id","pass","client_secret","sendImmediately","shouldRefreshAccessToken","res","set","supertoken","body","statusCode","ErrorConstructor","grantErrors","select","_res","initQRCodeLogin","_this3","emit","eventType","data","message","service","resource","scope","_res$body","user_code","verification_uri","verification_uri_complete","userData","userCode","verificationUri","verificationUriComplete","_startQRCodePolling","_this4","device_code","deviceCode","_options$interval","interval","_options$expires_in","expires_in","expiresIn","attempts","maxAttempts","setInterval","currentAttempts","cancelQRCodePolling","clearInterval","split","history","replaceState","_deleteProperty","isEmpty","omit","encode","_stringify","search","querystring","stringify","format","safeCharacterMap","base64url","_safe_map","times","random","join","codeChallenge","setItem","token","uuid","v4","sessionToken","concat","version","_applyDecoratedDescriptor2","_getOwnPropertyDescriptor","oneFlight","_default","exports"],"sources":["authorization.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\n/* eslint camelcase: [0] */\n\nimport querystring from 'querystring';\nimport url from 'url';\nimport {EventEmitter} from 'events';\n\nimport {base64, oneFlight, whileInFlight} from '@webex/common';\nimport {grantErrors, WebexPlugin} from '@webex/webex-core';\nimport {cloneDeep, isEmpty, omit} from 'lodash';\nimport uuid from 'uuid';\nimport base64url from 'crypto-js/enc-base64url';\nimport CryptoJS from 'crypto-js';\n\n// Necessary to require lodash this way in order to stub\n// methods in the unit test\nconst lodash = require('lodash');\n\nconst OAUTH2_CSRF_TOKEN = 'oauth2-csrf-token';\nconst OAUTH2_CODE_VERIFIER = 'oauth2-code-verifier';\n\n/**\n * Browser support for OAuth2. Automatically parses the URL query for an\n * authorization code\n *\n * Use of this plugin for anything other than the Webex Web Client is strongly\n * discouraged and may be broken at any time\n * @class\n * @name AuthorizationBrowserFirstParty\n * @private\n */\nconst Authorization = WebexPlugin.extend({\n derived: {\n /**\n * Alias of {@link AuthorizationBrowserFirstParty#isAuthorizing}\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {boolean}\n */\n isAuthenticating: {\n deps: ['isAuthorizing'],\n fn() {\n return this.isAuthorizing;\n },\n },\n },\n\n session: {\n /**\n * Indicates if an Authorization Code exchange is inflight\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {boolean}\n */\n isAuthorizing: {\n default: false,\n type: 'boolean',\n },\n ready: {\n default: false,\n type: 'boolean',\n },\n },\n\n namespace: 'Credentials',\n\n\n /**\n * Stores the interval ID for QR code polling\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {?number}\n * @private\n */\n pollingRequest: null,\n\n eventEmitter: new EventEmitter(),\n\n /**\n * Initializer\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @private\n * @returns {Authorization}\n */\n // eslint-disable-next-line complexity\n initialize(...attrs) {\n const ret = Reflect.apply(WebexPlugin.prototype.initialize, this, attrs);\n const location = url.parse(this.webex.getWindow().location.href, true);\n\n this._checkForErrors(location);\n\n const {code} = location.query;\n\n if (!code) {\n this.ready = true;\n\n return ret;\n }\n\n if (location.query.state) {\n location.query.state = JSON.parse(base64.decode(location.query.state));\n } else {\n location.query.state = {};\n }\n\n const codeVerifier = this.webex.getWindow().sessionStorage.getItem(OAUTH2_CODE_VERIFIER);\n\n this.webex.getWindow().sessionStorage.removeItem(OAUTH2_CODE_VERIFIER);\n\n const {emailhash} = location.query.state;\n\n this._verifySecurityToken(location.query);\n this._cleanUrl(location);\n\n let preauthCatalogParams;\n\n const orgId = this._extractOrgIdFromCode(code);\n\n if (emailhash) {\n preauthCatalogParams = {emailhash};\n } else if (orgId) {\n preauthCatalogParams = {orgId};\n }\n\n // Wait until nextTick in case `credentials` hasn't initialized yet\n process.nextTick(() => {\n this.webex.internal.services\n .collectPreauthCatalog(preauthCatalogParams)\n .catch(() => Promise.resolve())\n .then(() => this.requestAuthorizationCodeGrant({code, codeVerifier}))\n .catch((error) => {\n this.logger.warn('authorization: failed initial authorization code grant request', error);\n })\n .then(() => {\n this.ready = true;\n });\n });\n\n return ret;\n },\n\n /**\n * Kicks off an oauth flow\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @returns {Promise}\n */\n initiateLogin(options = {}) {\n options = cloneDeep(options);\n if (options.email) {\n options.emailHash = CryptoJS.SHA256(options.email).toString();\n }\n delete options.email;\n options.state = options.state || {};\n options.state.csrf_token = this._generateSecurityToken();\n // catalog uses emailhash and redirectCI uses emailHash\n options.state.emailhash = options.emailHash;\n\n options.code_challenge = this._generateCodeChallenge();\n options.code_challenge_method = 'S256';\n\n return this.initiateAuthorizationCodeGrant(options);\n },\n\n @whileInFlight('isAuthorizing')\n /**\n * Kicks off the Implicit Code grant flow. Typically called via\n * {@link AuthorizationBrowserFirstParty#initiateLogin}\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @returns {Promise}\n */\n initiateAuthorizationCodeGrant(options) {\n this.logger.info('authorization: initiating authorization code grant flow');\n this.webex.getWindow().location = this.webex.credentials.buildLoginUrl(\n Object.assign({response_type: 'code'}, options)\n );\n\n return Promise.resolve();\n },\n\n /**\n * Called by {@link WebexCore#logout()}. Redirects to the logout page\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @param {boolean} options.noRedirect if true, does not redirect\n * @returns {Promise}\n */\n logout(options = {}) {\n if (!options.noRedirect) {\n this.webex.getWindow().location = this.webex.credentials.buildLogoutUrl(options);\n }\n },\n\n @whileInFlight('isAuthorizing')\n @oneFlight\n /**\n * Exchanges an authorization code for an access token\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @param {Object} options.code\n * @returns {Promise}\n */\n requestAuthorizationCodeGrant(options = {}) {\n this.logger.info('credentials: requesting authorization code grant');\n\n if (!options.code) {\n return Promise.reject(new Error('`options.code` is required'));\n }\n\n const form = {\n grant_type: 'authorization_code',\n redirect_uri: this.config.redirect_uri,\n code: options.code,\n self_contained_token: true,\n };\n\n if (options.codeVerifier) {\n form.code_verifier = options.codeVerifier;\n }\n\n return this.webex\n .request({\n method: 'POST',\n uri: this.config.tokenUrl,\n form,\n auth: {\n user: this.config.client_id,\n pass: this.config.client_secret,\n sendImmediately: true,\n },\n shouldRefreshAccessToken: false,\n })\n .then((res) => {\n this.webex.credentials.set({supertoken: res.body});\n })\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 /**\n * Get an OAuth Login URL for QRCode. Generate QR code based on the returned URL.\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @emits #qRCodeLogin\n */\n initQRCodeLogin() {\n if (this.pollingRequest) {\n this.eventEmitter.emit('qRCodeLogin', {\n eventType: 'getUserCodeFailure',\n data: {message: 'There is already a polling request'},\n });\n return;\n }\n\n this.webex\n .request({\n method: 'POST',\n service: 'oauth-helper',\n resource: '/actions/device/authorize',\n form: {\n client_id: this.config.client_id,\n scope: this.config.scope,\n },\n auth: {\n user: this.config.client_id,\n pass: this.config.client_secret,\n sendImmediately: true,\n },\n })\n .then((res) => {\n const {user_code, verification_uri, verification_uri_complete} = res.body;\n this.eventEmitter.emit('qRCodeLogin', {\n eventType: 'getUserCodeSuccess',\n userData: {\n userCode: user_code,\n verificationUri: verification_uri,\n verificationUriComplete: verification_uri_complete,\n }\n });\n // if device authorization success, then start to poll server to check whether the user has completed authorization\n this._startQRCodePolling(res.body);\n })\n .catch((res) => {\n this.eventEmitter.emit('qRCodeLogin', {\n eventType: 'getUserCodeFailure',\n data: res.body,\n });\n });\n },\n\n /**\n * Polling the server to check whether the user has completed authorization\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @emits #qRCodeLogin\n */\n _startQRCodePolling(options = {}) {\n if (!options.device_code) {\n this.eventEmitter.emit('qRCodeLogin', {\n eventType: 'authorizationFailure',\n data: {message: 'A deviceCode is required'},\n });\n return;\n }\n\n if (this.pollingRequest) {\n this.eventEmitter.emit('qRCodeLogin', {\n eventType: 'authorizationFailure',\n data: {message: 'There is already a polling request'},\n });\n return;\n }\n\n const {device_code: deviceCode, interval = 2, expires_in: expiresIn = 300} = options;\n\n let attempts = 0;\n const maxAttempts = expiresIn / interval;\n\n this.pollingRequest = setInterval(() => {\n attempts += 1;\n\n const currentAttempts = attempts;\n this.webex\n .request({\n method: 'POST',\n service: 'oauth-helper',\n resource: '/actions/device/token',\n form: {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n client_id: this.config.client_id,\n },\n auth: {\n user: this.config.client_id,\n pass: this.config.client_secret,\n sendImmediately: true,\n },\n })\n .then((res) => {\n if (this.pollingRequest === null) return;\n\n this.eventEmitter.emit('qRCodeLogin', {\n eventType: 'authorizationSuccess',\n data: res.body,\n });\n this.cancelQRCodePolling();\n })\n .catch((res) => {\n if (this.pollingRequest === null) return;\n\n if (currentAttempts >= maxAttempts) {\n this.eventEmitter.emit('qRCodeLogin', {\n eventType: 'authorizationFailure',\n data: {message: 'Authorization timed out'}\n });\n this.cancelQRCodePolling();\n return;\n }\n // if the statusCode is 428 which means that the authorization request is still pending\n // as the end user hasn't yet completed the user-interaction steps. So keep polling.\n if (res.statusCode === 428) {\n this.eventEmitter.emit('qRCodeLogin', {\n eventType: 'authorizationPending',\n data: res.body\n });\n return;\n }\n\n this.cancelQRCodePolling();\n\n this.eventEmitter.emit('qRCodeLogin', {\n eventType: 'authorizationFailure',\n data: res.body\n });\n });\n }, interval * 1000);\n },\n\n /**\n * cancel polling request\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @returns {void}\n */\n cancelQRCodePolling() {\n if (this.pollingRequest) {\n clearInterval(this.pollingRequest);\n this.eventEmitter.emit('qRCodeLogin', {\n eventType: 'pollingCanceled',\n });\n this.pollingRequest = null;\n }\n },\n\n /**\n * Extracts the orgId from the returned code from idbroker\n * Description of how to parse the code can be found here:\n * https://wiki.cisco.com/display/IDENTITY/Federated+Token+Validation\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {String} code\n * @private\n * @returns {String}\n */\n _extractOrgIdFromCode(code) {\n return code?.split('_')[2] || undefined;\n },\n\n /**\n * Checks if the result of the login redirect contains an error string\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} location\n * @private\n * @returns {Promise}\n */\n _checkForErrors(location) {\n const {query} = location;\n\n if (query && query.error) {\n const ErrorConstructor = grantErrors.select(query.error);\n\n throw new ErrorConstructor(query);\n }\n },\n\n /**\n * Removes no-longer needed values from the url (access token, csrf token, etc)\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} location\n * @private\n * @returns {Promise}\n */\n _cleanUrl(location) {\n location = cloneDeep(location);\n if (this.webex.getWindow().history && this.webex.getWindow().history.replaceState) {\n Reflect.deleteProperty(location.query, 'code');\n if (isEmpty(omit(location.query.state, 'csrf_token'))) {\n Reflect.deleteProperty(location.query, 'state');\n } else {\n location.query.state = base64.encode(\n JSON.stringify(omit(location.query.state, 'csrf_token'))\n );\n }\n location.search = querystring.stringify(location.query);\n Reflect.deleteProperty(location, 'query');\n this.webex.getWindow().history.replaceState({}, null, url.format(location));\n }\n },\n\n /**\n * Generates PKCE code verifier and code challenge and sets the the code verifier in sessionStorage\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @private\n * @returns {string}\n */\n _generateCodeChallenge() {\n this.logger.info('authorization: generating PKCE code challenge');\n\n // eslint-disable-next-line no-underscore-dangle\n const safeCharacterMap = base64url._safe_map;\n\n const codeVerifier = lodash\n .times(128, () => safeCharacterMap[lodash.random(0, safeCharacterMap.length - 1)])\n .join('');\n\n const codeChallenge = CryptoJS.SHA256(codeVerifier).toString(base64url);\n\n this.webex.getWindow().sessionStorage.setItem(OAUTH2_CODE_VERIFIER, codeVerifier);\n\n return codeChallenge;\n },\n\n /**\n * Generates a CSRF token and sticks in in sessionStorage\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @private\n * @returns {Promise}\n */\n _generateSecurityToken() {\n this.logger.info('authorization: generating csrf token');\n\n const token = uuid.v4();\n\n this.webex.getWindow().sessionStorage.setItem('oauth2-csrf-token', token);\n\n return token;\n },\n\n /**\n * Checks if the CSRF token in sessionStorage is the same as the one returned\n * in the url.\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} query\n * @private\n * @returns {Promise}\n */\n _verifySecurityToken(query) {\n const sessionToken = this.webex.getWindow().sessionStorage.getItem(OAUTH2_CSRF_TOKEN);\n\n this.webex.getWindow().sessionStorage.removeItem(OAUTH2_CSRF_TOKEN);\n if (!sessionToken) {\n return;\n }\n\n if (!query.state) {\n throw new Error(`Expected CSRF token ${sessionToken}, but not found in redirect query`);\n }\n\n if (!query.state.csrf_token) {\n throw new Error(`Expected CSRF token ${sessionToken}, but not found in redirect query`);\n }\n\n const token = query.state.csrf_token;\n\n if (token !== sessionToken) {\n throw new Error(`CSRF token ${token} does not match stored token ${sessionToken}`);\n }\n },\n});\n\nexport default Authorization;\n"],"mappings":";;;;;;;;;;;;;;;AAMA,IAAAA,YAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,IAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AAEA,IAAAG,OAAA,GAAAH,OAAA;AACA,IAAAI,UAAA,GAAAJ,OAAA;AACA,IAAAK,OAAA,GAAAL,OAAA;AACA,IAAAM,KAAA,GAAAP,sBAAA,CAAAC,OAAA;AACA,IAAAO,aAAA,GAAAR,sBAAA,CAAAC,OAAA;AACA,IAAAQ,SAAA,GAAAT,sBAAA,CAAAC,OAAA;AAAiC,IAAAS,IAAA,EAAAC,KAAA,EAAAC,IAAA;AAfjC;AACA;AACA;AAEA;AAaA;AACA;AACA,IAAMC,MAAM,GAAGZ,OAAO,CAAC,QAAQ,CAAC;AAEhC,IAAMa,iBAAiB,GAAG,mBAAmB;AAC7C,IAAMC,oBAAoB,GAAG,sBAAsB;;AAEnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAMC,aAAa,GAAGC,sBAAW,CAACC,MAAM,EAAAR,IAAA,GAuIrC,IAAAS,qBAAa,EAAC,eAAe,CAAC,EAAAR,KAAA,GAgC9B,IAAAQ,qBAAa,EAAC,eAAe,CAAC,GAAAP,IAAA,GAvKQ;EACvCQ,OAAO,EAAE;IACP;AACJ;AACA;AACA;AACA;AACA;IACIC,gBAAgB,EAAE;MAChBC,IAAI,EAAE,CAAC,eAAe,CAAC;MACvBC,EAAE,WAAAA,GAAA,EAAG;QACH,OAAO,IAAI,CAACC,aAAa;MAC3B;IACF;EACF,CAAC;EAEDC,OAAO,EAAE;IACP;AACJ;AACA;AACA;AACA;AACA;IACID,aAAa,EAAE;MACbE,OAAO,EAAE,KAAK;MACdC,IAAI,EAAE;IACR,CAAC;IACDC,KAAK,EAAE;MACLF,OAAO,EAAE,KAAK;MACdC,IAAI,EAAE;IACR;EACF,CAAC;EAEDE,SAAS,EAAE,aAAa;EAGxB;AACF;AACA;AACA;AACA;AACA;AACA;EACEC,cAAc,EAAE,IAAI;EAEpBC,YAAY,EAAE,IAAIC,oBAAY,CAAC,CAAC;EAEhC;AACF;AACA;AACA;AACA;AACA;AACA;EACE;EACAC,UAAU,WAAAA,WAAA,EAAW;IAAA,IAAAC,KAAA;IAAA,SAAAC,IAAA,GAAAC,SAAA,CAAAC,MAAA,EAAPC,KAAK,OAAAC,KAAA,CAAAJ,IAAA,GAAAK,IAAA,MAAAA,IAAA,GAAAL,IAAA,EAAAK,IAAA;MAALF,KAAK,CAAAE,IAAA,IAAAJ,SAAA,CAAAI,IAAA;IAAA;IACjB,IAAMC,GAAG,GAAG,IAAAC,MAAA,CAAAhB,OAAA,EAAcT,sBAAW,CAAC0B,SAAS,CAACV,UAAU,EAAE,IAAI,EAAEK,KAAK,CAAC;IACxE,IAAMM,QAAQ,GAAGC,YAAG,CAACC,KAAK,CAAC,IAAI,CAACC,KAAK,CAACC,SAAS,CAAC,CAAC,CAACJ,QAAQ,CAACK,IAAI,EAAE,IAAI,CAAC;IAEtE,IAAI,CAACC,eAAe,CAACN,QAAQ,CAAC;IAE9B,IAAOO,IAAI,GAAIP,QAAQ,CAACQ,KAAK,CAAtBD,IAAI;IAEX,IAAI,CAACA,IAAI,EAAE;MACT,IAAI,CAACvB,KAAK,GAAG,IAAI;MAEjB,OAAOa,GAAG;IACZ;IAEA,IAAIG,QAAQ,CAACQ,KAAK,CAACC,KAAK,EAAE;MACxBT,QAAQ,CAACQ,KAAK,CAACC,KAAK,GAAGC,IAAI,CAACR,KAAK,CAACS,cAAM,CAACC,MAAM,CAACZ,QAAQ,CAACQ,KAAK,CAACC,KAAK,CAAC,CAAC;IACxE,CAAC,MAAM;MACLT,QAAQ,CAACQ,KAAK,CAACC,KAAK,GAAG,CAAC,CAAC;IAC3B;IAEA,IAAMI,YAAY,GAAG,IAAI,CAACV,KAAK,CAACC,SAAS,CAAC,CAAC,CAACU,cAAc,CAACC,OAAO,CAAC5C,oBAAoB,CAAC;IAExF,IAAI,CAACgC,KAAK,CAACC,SAAS,CAAC,CAAC,CAACU,cAAc,CAACE,UAAU,CAAC7C,oBAAoB,CAAC;IAEtE,IAAO8C,SAAS,GAAIjB,QAAQ,CAACQ,KAAK,CAACC,KAAK,CAAjCQ,SAAS;IAEhB,IAAI,CAACC,oBAAoB,CAAClB,QAAQ,CAACQ,KAAK,CAAC;IACzC,IAAI,CAACW,SAAS,CAACnB,QAAQ,CAAC;IAExB,IAAIoB,oBAAoB;IAExB,IAAMC,KAAK,GAAG,IAAI,CAACC,qBAAqB,CAACf,IAAI,CAAC;IAE9C,IAAIU,SAAS,EAAE;MACbG,oBAAoB,GAAG;QAACH,SAAS,EAATA;MAAS,CAAC;IACpC,CAAC,MAAM,IAAII,KAAK,EAAE;MAChBD,oBAAoB,GAAG;QAACC,KAAK,EAALA;MAAK,CAAC;IAChC;;IAEA;IACAE,OAAO,CAACC,QAAQ,CAAC,YAAM;MACrBlC,KAAI,CAACa,KAAK,CAACsB,QAAQ,CAACC,QAAQ,CACzBC,qBAAqB,CAACP,oBAAoB,CAAC,CAC3CQ,KAAK,CAAC;QAAA,OAAMC,QAAA,CAAA/C,OAAA,CAAQgD,OAAO,CAAC,CAAC;MAAA,EAAC,CAC9BC,IAAI,CAAC;QAAA,OAAMzC,KAAI,CAAC0C,6BAA6B,CAAC;UAACzB,IAAI,EAAJA,IAAI;UAAEM,YAAY,EAAZA;QAAY,CAAC,CAAC;MAAA,EAAC,CACpEe,KAAK,CAAC,UAACK,KAAK,EAAK;QAChB3C,KAAI,CAAC4C,MAAM,CAACC,IAAI,CAAC,gEAAgE,EAAEF,KAAK,CAAC;MAC3F,CAAC,CAAC,CACDF,IAAI,CAAC,YAAM;QACVzC,KAAI,CAACN,KAAK,GAAG,IAAI;MACnB,CAAC,CAAC;IACN,CAAC,CAAC;IAEF,OAAOa,GAAG;EACZ,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;EACEuC,aAAa,WAAAA,cAAA,EAAe;IAAA,IAAdC,OAAO,GAAA7C,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAA8C,SAAA,GAAA9C,SAAA,MAAG,CAAC,CAAC;IACxB6C,OAAO,GAAG,IAAAE,iBAAS,EAACF,OAAO,CAAC;IAC5B,IAAIA,OAAO,CAACG,KAAK,EAAE;MACjBH,OAAO,CAACI,SAAS,GAAGC,iBAAQ,CAACC,MAAM,CAACN,OAAO,CAACG,KAAK,CAAC,CAACI,QAAQ,CAAC,CAAC;IAC/D;IACA,OAAOP,OAAO,CAACG,KAAK;IACpBH,OAAO,CAAC5B,KAAK,GAAG4B,OAAO,CAAC5B,KAAK,IAAI,CAAC,CAAC;IACnC4B,OAAO,CAAC5B,KAAK,CAACoC,UAAU,GAAG,IAAI,CAACC,sBAAsB,CAAC,CAAC;IACxD;IACAT,OAAO,CAAC5B,KAAK,CAACQ,SAAS,GAAGoB,OAAO,CAACI,SAAS;IAE3CJ,OAAO,CAACU,cAAc,GAAG,IAAI,CAACC,sBAAsB,CAAC,CAAC;IACtDX,OAAO,CAACY,qBAAqB,GAAG,MAAM;IAEtC,OAAO,IAAI,CAACC,8BAA8B,CAACb,OAAO,CAAC;EACrD,CAAC;EAGD;AACF;AACA;AACA;AACA;AACA;AACA;AACA;EACEa,8BAA8B,WAAAA,+BAACb,OAAO,EAAE;IACtC,IAAI,CAACH,MAAM,CAACiB,IAAI,CAAC,yDAAyD,CAAC;IAC3E,IAAI,CAAChD,KAAK,CAACC,SAAS,CAAC,CAAC,CAACJ,QAAQ,GAAG,IAAI,CAACG,KAAK,CAACiD,WAAW,CAACC,aAAa,CACpE,IAAAC,OAAA,CAAAxE,OAAA,EAAc;MAACyE,aAAa,EAAE;IAAM,CAAC,EAAElB,OAAO,CAChD,CAAC;IAED,OAAOR,QAAA,CAAA/C,OAAA,CAAQgD,OAAO,CAAC,CAAC;EAC1B,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;EACE0B,MAAM,WAAAA,OAAA,EAAe;IAAA,IAAdnB,OAAO,GAAA7C,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAA8C,SAAA,GAAA9C,SAAA,MAAG,CAAC,CAAC;IACjB,IAAI,CAAC6C,OAAO,CAACoB,UAAU,EAAE;MACvB,IAAI,CAACtD,KAAK,CAACC,SAAS,CAAC,CAAC,CAACJ,QAAQ,GAAG,IAAI,CAACG,KAAK,CAACiD,WAAW,CAACM,cAAc,CAACrB,OAAO,CAAC;IAClF;EACF,CAAC;EAID;AACF;AACA;AACA;AACA;AACA;AACA;AACA;EACEL,6BAA6B,WAAAA,8BAAA,EAAe;IAAA,IAAA2B,MAAA;IAAA,IAAdtB,OAAO,GAAA7C,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAA8C,SAAA,GAAA9C,SAAA,MAAG,CAAC,CAAC;IACxC,IAAI,CAAC0C,MAAM,CAACiB,IAAI,CAAC,kDAAkD,CAAC;IAEpE,IAAI,CAACd,OAAO,CAAC9B,IAAI,EAAE;MACjB,OAAOsB,QAAA,CAAA/C,OAAA,CAAQ8E,MAAM,CAAC,IAAIC,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChE;IAEA,IAAMC,IAAI,GAAG;MACXC,UAAU,EAAE,oBAAoB;MAChCC,YAAY,EAAE,IAAI,CAACC,MAAM,CAACD,YAAY;MACtCzD,IAAI,EAAE8B,OAAO,CAAC9B,IAAI;MAClB2D,oBAAoB,EAAE;IACxB,CAAC;IAED,IAAI7B,OAAO,CAACxB,YAAY,EAAE;MACxBiD,IAAI,CAACK,aAAa,GAAG9B,OAAO,CAACxB,YAAY;IAC3C;IAEA,OAAO,IAAI,CAACV,KAAK,CACdiE,OAAO,CAAC;MACPC,MAAM,EAAE,MAAM;MACdC,GAAG,EAAE,IAAI,CAACL,MAAM,CAACM,QAAQ;MACzBT,IAAI,EAAJA,IAAI;MACJU,IAAI,EAAE;QACJC,IAAI,EAAE,IAAI,CAACR,MAAM,CAACS,SAAS;QAC3BC,IAAI,EAAE,IAAI,CAACV,MAAM,CAACW,aAAa;QAC/BC,eAAe,EAAE;MACnB,CAAC;MACDC,wBAAwB,EAAE;IAC5B,CAAC,CAAC,CACD/C,IAAI,CAAC,UAACgD,GAAG,EAAK;MACbpB,MAAI,CAACxD,KAAK,CAACiD,WAAW,CAAC4B,GAAG,CAAC;QAACC,UAAU,EAAEF,GAAG,CAACG;MAAI,CAAC,CAAC;IACpD,CAAC,CAAC,CACDtD,KAAK,CAAC,UAACmD,GAAG,EAAK;MACd,IAAIA,GAAG,CAACI,UAAU,KAAK,GAAG,EAAE;QAC1B,OAAOtD,QAAA,CAAA/C,OAAA,CAAQ8E,MAAM,CAACmB,GAAG,CAAC;MAC5B;MAEA,IAAMK,gBAAgB,GAAGC,sBAAW,CAACC,MAAM,CAACP,GAAG,CAACG,IAAI,CAACjD,KAAK,CAAC;MAE3D,OAAOJ,QAAA,CAAA/C,OAAA,CAAQ8E,MAAM,CAAC,IAAIwB,gBAAgB,CAACL,GAAG,CAACQ,IAAI,IAAIR,GAAG,CAAC,CAAC;IAC9D,CAAC,CAAC;EACN,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;EACES,eAAe,WAAAA,gBAAA,EAAG;IAAA,IAAAC,MAAA;IAChB,IAAI,IAAI,CAACvG,cAAc,EAAE;MACvB,IAAI,CAACC,YAAY,CAACuG,IAAI,CAAC,aAAa,EAAE;QACpCC,SAAS,EAAE,oBAAoB;QAC/BC,IAAI,EAAE;UAACC,OAAO,EAAE;QAAoC;MACtD,CAAC,CAAC;MACF;IACF;IAEA,IAAI,CAAC1F,KAAK,CACPiE,OAAO,CAAC;MACPC,MAAM,EAAE,MAAM;MACdyB,OAAO,EAAE,cAAc;MACvBC,QAAQ,EAAE,2BAA2B;MACrCjC,IAAI,EAAE;QACJY,SAAS,EAAE,IAAI,CAACT,MAAM,CAACS,SAAS;QAChCsB,KAAK,EAAE,IAAI,CAAC/B,MAAM,CAAC+B;MACrB,CAAC;MACDxB,IAAI,EAAE;QACJC,IAAI,EAAE,IAAI,CAACR,MAAM,CAACS,SAAS;QAC3BC,IAAI,EAAE,IAAI,CAACV,MAAM,CAACW,aAAa;QAC/BC,eAAe,EAAE;MACnB;IACF,CAAC,CAAC,CACD9C,IAAI,CAAC,UAACgD,GAAG,EAAK;MACb,IAAAkB,SAAA,GAAiElB,GAAG,CAACG,IAAI;QAAlEgB,SAAS,GAAAD,SAAA,CAATC,SAAS;QAAEC,gBAAgB,GAAAF,SAAA,CAAhBE,gBAAgB;QAAEC,yBAAyB,GAAAH,SAAA,CAAzBG,yBAAyB;MAC7DX,MAAI,CAACtG,YAAY,CAACuG,IAAI,CAAC,aAAa,EAAE;QACpCC,SAAS,EAAE,oBAAoB;QAC/BU,QAAQ,EAAE;UACRC,QAAQ,EAAEJ,SAAS;UACnBK,eAAe,EAAEJ,gBAAgB;UACjCK,uBAAuB,EAAEJ;QAC3B;MACF,CAAC,CAAC;MACF;MACAX,MAAI,CAACgB,mBAAmB,CAAC1B,GAAG,CAACG,IAAI,CAAC;IACpC,CAAC,CAAC,CACDtD,KAAK,CAAC,UAACmD,GAAG,EAAK;MACdU,MAAI,CAACtG,YAAY,CAACuG,IAAI,CAAC,aAAa,EAAE;QACpCC,SAAS,EAAE,oBAAoB;QAC/BC,IAAI,EAAEb,GAAG,CAACG;MACZ,CAAC,CAAC;IACJ,CAAC,CAAC;EACN,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;EACEuB,mBAAmB,WAAAA,oBAAA,EAAe;IAAA,IAAAC,MAAA;IAAA,IAAdrE,OAAO,GAAA7C,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAA8C,SAAA,GAAA9C,SAAA,MAAG,CAAC,CAAC;IAC9B,IAAI,CAAC6C,OAAO,CAACsE,WAAW,EAAE;MACxB,IAAI,CAACxH,YAAY,CAACuG,IAAI,CAAC,aAAa,EAAE;QACpCC,SAAS,EAAE,sBAAsB;QACjCC,IAAI,EAAE;UAACC,OAAO,EAAE;QAA0B;MAC5C,CAAC,CAAC;MACF;IACF;IAEA,IAAI,IAAI,CAAC3G,cAAc,EAAE;MACvB,IAAI,CAACC,YAAY,CAACuG,IAAI,CAAC,aAAa,EAAE;QACpCC,SAAS,EAAE,sBAAsB;QACjCC,IAAI,EAAE;UAACC,OAAO,EAAE;QAAoC;MACtD,CAAC,CAAC;MACF;IACF;IAEA,IAAoBe,UAAU,GAA+CvE,OAAO,CAA7EsE,WAAW;MAAAE,iBAAA,GAA2DxE,OAAO,CAApDyE,QAAQ;MAARA,QAAQ,GAAAD,iBAAA,cAAG,CAAC,GAAAA,iBAAA;MAAAE,mBAAA,GAAiC1E,OAAO,CAAtC2E,UAAU;MAAEC,SAAS,GAAAF,mBAAA,cAAG,GAAG,GAAAA,mBAAA;IAEzE,IAAIG,QAAQ,GAAG,CAAC;IAChB,IAAMC,WAAW,GAAGF,SAAS,GAAGH,QAAQ;IAExC,IAAI,CAAC5H,cAAc,GAAGkI,WAAW,CAAC,YAAM;MACtCF,QAAQ,IAAI,CAAC;MAEb,IAAMG,eAAe,GAAGH,QAAQ;MAChCR,MAAI,CAACvG,KAAK,CACPiE,OAAO,CAAC;QACPC,MAAM,EAAE,MAAM;QACdyB,OAAO,EAAE,cAAc;QACvBC,QAAQ,EAAE,uBAAuB;QACjCjC,IAAI,EAAE;UACJC,UAAU,EAAE,8CAA8C;UAC1D4C,WAAW,EAAEC,UAAU;UACvBlC,SAAS,EAAEgC,MAAI,CAACzC,MAAM,CAACS;QACzB,CAAC;QACDF,IAAI,EAAE;UACJC,IAAI,EAAEiC,MAAI,CAACzC,MAAM,CAACS,SAAS;UAC3BC,IAAI,EAAE+B,MAAI,CAACzC,MAAM,CAACW,aAAa;UAC/BC,eAAe,EAAE;QACnB;MACF,CAAC,CAAC,CACD9C,IAAI,CAAC,UAACgD,GAAG,EAAK;QACb,IAAI2B,MAAI,CAACxH,cAAc,KAAK,IAAI,EAAE;QAElCwH,MAAI,CAACvH,YAAY,CAACuG,IAAI,CAAC,aAAa,EAAE;UACpCC,SAAS,EAAE,sBAAsB;UACjCC,IAAI,EAAEb,GAAG,CAACG;QACZ,CAAC,CAAC;QACFwB,MAAI,CAACY,mBAAmB,CAAC,CAAC;MAC5B,CAAC,CAAC,CACD1F,KAAK,CAAC,UAACmD,GAAG,EAAK;QACd,IAAI2B,MAAI,CAACxH,cAAc,KAAK,IAAI,EAAE;QAElC,IAAImI,eAAe,IAAIF,WAAW,EAAE;UAClCT,MAAI,CAACvH,YAAY,CAACuG,IAAI,CAAC,aAAa,EAAE;YACpCC,SAAS,EAAE,sBAAsB;YACjCC,IAAI,EAAE;cAACC,OAAO,EAAE;YAAyB;UAC3C,CAAC,CAAC;UACFa,MAAI,CAACY,mBAAmB,CAAC,CAAC;UAC1B;QACF;QACA;QACA;QACA,IAAIvC,GAAG,CAACI,UAAU,KAAK,GAAG,EAAE;UAC1BuB,MAAI,CAACvH,YAAY,CAACuG,IAAI,CAAC,aAAa,EAAE;YACpCC,SAAS,EAAE,sBAAsB;YACjCC,IAAI,EAAEb,GAAG,CAACG;UACZ,CAAC,CAAC;UACF;QACF;QAEAwB,MAAI,CAACY,mBAAmB,CAAC,CAAC;QAE1BZ,MAAI,CAACvH,YAAY,CAACuG,IAAI,CAAC,aAAa,EAAE;UACpCC,SAAS,EAAE,sBAAsB;UACjCC,IAAI,EAAEb,GAAG,CAACG;QACZ,CAAC,CAAC;MACJ,CAAC,CAAC;IACN,CAAC,EAAE4B,QAAQ,GAAG,IAAI,CAAC;EACrB,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;EACEQ,mBAAmB,WAAAA,oBAAA,EAAG;IACpB,IAAI,IAAI,CAACpI,cAAc,EAAE;MACvBqI,aAAa,CAAC,IAAI,CAACrI,cAAc,CAAC;MAClC,IAAI,CAACC,YAAY,CAACuG,IAAI,CAAC,aAAa,EAAE;QACpCC,SAAS,EAAE;MACb,CAAC,CAAC;MACF,IAAI,CAACzG,cAAc,GAAG,IAAI;IAC5B;EACF,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEoC,qBAAqB,WAAAA,sBAACf,IAAI,EAAE;IAC1B,OAAO,CAAAA,IAAI,aAAJA,IAAI,uBAAJA,IAAI,CAAEiH,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAIlF,SAAS;EACzC,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;EACEhC,eAAe,WAAAA,gBAACN,QAAQ,EAAE;IACxB,IAAOQ,KAAK,GAAIR,QAAQ,CAAjBQ,KAAK;IAEZ,IAAIA,KAAK,IAAIA,KAAK,CAACyB,KAAK,EAAE;MACxB,IAAMmD,gBAAgB,GAAGC,sBAAW,CAACC,MAAM,CAAC9E,KAAK,CAACyB,KAAK,CAAC;MAExD,MAAM,IAAImD,gBAAgB,CAAC5E,KAAK,CAAC;IACnC;EACF,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;EACEW,SAAS,WAAAA,UAACnB,QAAQ,EAAE;IAClBA,QAAQ,GAAG,IAAAuC,iBAAS,EAACvC,QAAQ,CAAC;IAC9B,IAAI,IAAI,CAACG,KAAK,CAACC,SAAS,CAAC,CAAC,CAACqH,OAAO,IAAI,IAAI,CAACtH,KAAK,CAACC,SAAS,CAAC,CAAC,CAACqH,OAAO,CAACC,YAAY,EAAE;MACjF,IAAAC,eAAA,CAAA7I,OAAA,EAAuBkB,QAAQ,CAACQ,KAAK,EAAE,MAAM,CAAC;MAC9C,IAAI,IAAAoH,eAAO,EAAC,IAAAC,YAAI,EAAC7H,QAAQ,CAACQ,KAAK,CAACC,KAAK,EAAE,YAAY,CAAC,CAAC,EAAE;QACrD,IAAAkH,eAAA,CAAA7I,OAAA,EAAuBkB,QAAQ,CAACQ,KAAK,EAAE,OAAO,CAAC;MACjD,CAAC,MAAM;QACLR,QAAQ,CAACQ,KAAK,CAACC,KAAK,GAAGE,cAAM,CAACmH,MAAM,CAClC,IAAAC,UAAA,CAAAjJ,OAAA,EAAe,IAAA+I,YAAI,EAAC7H,QAAQ,CAACQ,KAAK,CAACC,KAAK,EAAE,YAAY,CAAC,CACzD,CAAC;MACH;MACAT,QAAQ,CAACgI,MAAM,GAAGC,oBAAW,CAACC,SAAS,CAAClI,QAAQ,CAACQ,KAAK,CAAC;MACvD,IAAAmH,eAAA,CAAA7I,OAAA,EAAuBkB,QAAQ,EAAE,OAAO,CAAC;MACzC,IAAI,CAACG,KAAK,CAACC,SAAS,CAAC,CAAC,CAACqH,OAAO,CAACC,YAAY,CAAC,CAAC,CAAC,EAAE,IAAI,EAAEzH,YAAG,CAACkI,MAAM,CAACnI,QAAQ,CAAC,CAAC;IAC7E;EACF,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;EACEgD,sBAAsB,WAAAA,uBAAA,EAAG;IACvB,IAAI,CAACd,MAAM,CAACiB,IAAI,CAAC,+CAA+C,CAAC;;IAEjE;IACA,IAAMiF,gBAAgB,GAAGC,qBAAS,CAACC,SAAS;IAE5C,IAAMzH,YAAY,GAAG5C,MAAM,CACxBsK,KAAK,CAAC,GAAG,EAAE;MAAA,OAAMH,gBAAgB,CAACnK,MAAM,CAACuK,MAAM,CAAC,CAAC,EAAEJ,gBAAgB,CAAC3I,MAAM,GAAG,CAAC,CAAC,CAAC;IAAA,EAAC,CACjFgJ,IAAI,CAAC,EAAE,CAAC;IAEX,IAAMC,aAAa,GAAGhG,iBAAQ,CAACC,MAAM,CAAC9B,YAAY,CAAC,CAAC+B,QAAQ,CAACyF,qBAAS,CAAC;IAEvE,IAAI,CAAClI,KAAK,CAACC,SAAS,CAAC,CAAC,CAACU,cAAc,CAAC6H,OAAO,CAACxK,oBAAoB,EAAE0C,YAAY,CAAC;IAEjF,OAAO6H,aAAa;EACtB,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;EACE5F,sBAAsB,WAAAA,uBAAA,EAAG;IACvB,IAAI,CAACZ,MAAM,CAACiB,IAAI,CAAC,sCAAsC,CAAC;IAExD,IAAMyF,KAAK,GAAGC,aAAI,CAACC,EAAE,CAAC,CAAC;IAEvB,IAAI,CAAC3I,KAAK,CAACC,SAAS,CAAC,CAAC,CAACU,cAAc,CAAC6H,OAAO,CAAC,mBAAmB,EAAEC,KAAK,CAAC;IAEzE,OAAOA,KAAK;EACd,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE1H,oBAAoB,WAAAA,qBAACV,KAAK,EAAE;IAC1B,IAAMuI,YAAY,GAAG,IAAI,CAAC5I,KAAK,CAACC,SAAS,CAAC,CAAC,CAACU,cAAc,CAACC,OAAO,CAAC7C,iBAAiB,CAAC;IAErF,IAAI,CAACiC,KAAK,CAACC,SAAS,CAAC,CAAC,CAACU,cAAc,CAACE,UAAU,CAAC9C,iBAAiB,CAAC;IACnE,IAAI,CAAC6K,YAAY,EAAE;MACjB;IACF;IAEA,IAAI,CAACvI,KAAK,CAACC,KAAK,EAAE;MAChB,MAAM,IAAIoD,KAAK,wBAAAmF,MAAA,CAAwBD,YAAY,sCAAmC,CAAC;IACzF;IAEA,IAAI,CAACvI,KAAK,CAACC,KAAK,CAACoC,UAAU,EAAE;MAC3B,MAAM,IAAIgB,KAAK,wBAAAmF,MAAA,CAAwBD,YAAY,sCAAmC,CAAC;IACzF;IAEA,IAAMH,KAAK,GAAGpI,KAAK,CAACC,KAAK,CAACoC,UAAU;IAEpC,IAAI+F,KAAK,KAAKG,YAAY,EAAE;MAC1B,MAAM,IAAIlF,KAAK,eAAAmF,MAAA,CAAeJ,KAAK,mCAAAI,MAAA,CAAgCD,YAAY,CAAE,CAAC;IACpF;EACF,CAAC;EAAAE,OAAA;AACH,CAAC,OAAAC,0BAAA,CAAApK,OAAA,EAAAd,IAAA,qCAAAF,IAAA,OAAAqL,yBAAA,CAAArK,OAAA,EAAAd,IAAA,qCAAAA,IAAA,OAAAkL,0BAAA,CAAApK,OAAA,EAAAd,IAAA,oCAAAD,KAAA,EAlVEqL,iBAAS,OAAAD,yBAAA,CAAArK,OAAA,EAAAd,IAAA,oCAAAA,IAAA,IAAAA,IAAA,EAkVX,CAAC;AAAC,IAAAqL,QAAA,GAAAC,OAAA,CAAAxK,OAAA,GAEYV,aAAa"}
|
|
1
|
+
{"version":3,"names":["_querystring","_interopRequireDefault","require","_url","_events","_common","_webexCore","_lodash","_uuid","_encBase64url","_cryptoJs","_dec","_dec2","_obj","lodash","OAUTH2_CSRF_TOKEN","OAUTH2_CODE_VERIFIER","Events","exports","qRCodeLogin","Authorization","WebexPlugin","extend","whileInFlight","derived","isAuthenticating","deps","fn","isAuthorizing","session","default","type","ready","namespace","eventEmitter","EventEmitter","pollingTimer","pollingExpirationTimer","pollingId","currentPollingId","initialize","_this","_len","arguments","length","attrs","Array","_key","ret","_apply","prototype","location","url","parse","webex","getWindow","href","_checkForErrors","code","query","state","JSON","base64","decode","codeVerifier","sessionStorage","getItem","removeItem","emailhash","_verifySecurityToken","_cleanUrl","preauthCatalogParams","orgId","_extractOrgIdFromCode","process","nextTick","internal","services","collectPreauthCatalog","catch","_promise","resolve","then","requestAuthorizationCodeGrant","error","logger","warn","initiateLogin","options","undefined","cloneDeep","email","emailHash","CryptoJS","SHA256","toString","csrf_token","_generateSecurityToken","code_challenge","_generateCodeChallenge","code_challenge_method","initiateAuthorizationCodeGrant","info","credentials","buildLoginUrl","_assign","response_type","logout","noRedirect","buildLogoutUrl","_this2","reject","Error","form","grant_type","redirect_uri","config","self_contained_token","code_verifier","request","method","uri","tokenUrl","auth","user","client_id","pass","client_secret","sendImmediately","shouldRefreshAccessToken","res","set","supertoken","body","statusCode","ErrorConstructor","grantErrors","select","_res","_generateQRCodeVerificationUrl","verificationUrl","baseUrl","urlParams","URLSearchParams","URL","search","userCode","get","oauthHelperUrl","newVerificationUrl","searchParams","initQRCodeLogin","_this3","emit","eventType","data","message","service","resource","scope","_res$body","user_code","verification_uri","verification_uri_complete","verificationUriComplete","userData","verificationUri","_startQRCodePolling","_options$interval","_this4","device_code","deviceCode","_options$expires_in","expires_in","expiresIn","interval","setTimeout","cancelQRCodePolling","polling","schedulePolling","withCancelEvent","clearTimeout","split","history","replaceState","_deleteProperty","isEmpty","omit","encode","_stringify","querystring","stringify","format","safeCharacterMap","base64url","_safe_map","times","random","join","codeChallenge","setItem","token","uuid","v4","sessionToken","concat","version","_applyDecoratedDescriptor2","_getOwnPropertyDescriptor","oneFlight","_default"],"sources":["authorization.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\n/* eslint camelcase: [0] */\n\nimport querystring from 'querystring';\nimport url from 'url';\nimport {EventEmitter} from 'events';\n\nimport {base64, oneFlight, whileInFlight} from '@webex/common';\nimport {grantErrors, WebexPlugin} from '@webex/webex-core';\nimport {cloneDeep, isEmpty, omit} from 'lodash';\nimport uuid from 'uuid';\nimport base64url from 'crypto-js/enc-base64url';\nimport CryptoJS from 'crypto-js';\n\n// Necessary to require lodash this way in order to stub\n// methods in the unit test\nconst lodash = require('lodash');\n\nconst OAUTH2_CSRF_TOKEN = 'oauth2-csrf-token';\nconst OAUTH2_CODE_VERIFIER = 'oauth2-code-verifier';\n\n/**\n * Authorization plugin events\n */\nexport const Events = {\n /**\n * QR code login events\n */\n qRCodeLogin: 'qRCodeLogin',\n};\n\n/**\n * Browser support for OAuth2. Automatically parses the URL query for an\n * authorization code\n *\n * Use of this plugin for anything other than the Webex Web Client is strongly\n * discouraged and may be broken at any time\n * @class\n * @name AuthorizationBrowserFirstParty\n * @private\n */\nconst Authorization = WebexPlugin.extend({\n derived: {\n /**\n * Alias of {@link AuthorizationBrowserFirstParty#isAuthorizing}\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {boolean}\n */\n isAuthenticating: {\n deps: ['isAuthorizing'],\n fn() {\n return this.isAuthorizing;\n },\n },\n },\n\n session: {\n /**\n * Indicates if an Authorization Code exchange is inflight\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {boolean}\n */\n isAuthorizing: {\n default: false,\n type: 'boolean',\n },\n ready: {\n default: false,\n type: 'boolean',\n },\n },\n\n namespace: 'Credentials',\n\n /**\n * EventEmitter for authorization events\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {EventEmitter}\n * @public\n */\n eventEmitter: new EventEmitter(),\n\n /**\n * Stores the timer ID for QR code polling\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {?number}\n * @private\n */\n pollingTimer: null,\n /**\n * Stores the expiration timer ID for QR code polling\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {?number}\n * @private\n */\n pollingExpirationTimer: null,\n\n /**\n * Monotonically increasing id to identify the current polling request\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {number}\n * @private\n */\n pollingId: 0,\n\n /**\n * Identifier for the current polling request\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {?number}\n * @private\n */\n currentPollingId: null,\n\n /**\n * Initializer\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @private\n * @returns {Authorization}\n */\n // eslint-disable-next-line complexity\n initialize(...attrs) {\n const ret = Reflect.apply(WebexPlugin.prototype.initialize, this, attrs);\n const location = url.parse(this.webex.getWindow().location.href, true);\n\n this._checkForErrors(location);\n\n const {code} = location.query;\n\n if (!code) {\n this.ready = true;\n\n return ret;\n }\n\n if (location.query.state) {\n location.query.state = JSON.parse(base64.decode(location.query.state));\n } else {\n location.query.state = {};\n }\n\n const codeVerifier = this.webex.getWindow().sessionStorage.getItem(OAUTH2_CODE_VERIFIER);\n\n this.webex.getWindow().sessionStorage.removeItem(OAUTH2_CODE_VERIFIER);\n\n const {emailhash} = location.query.state;\n\n this._verifySecurityToken(location.query);\n this._cleanUrl(location);\n\n let preauthCatalogParams;\n\n const orgId = this._extractOrgIdFromCode(code);\n\n if (emailhash) {\n preauthCatalogParams = {emailhash};\n } else if (orgId) {\n preauthCatalogParams = {orgId};\n }\n\n // Wait until nextTick in case `credentials` hasn't initialized yet\n process.nextTick(() => {\n this.webex.internal.services\n .collectPreauthCatalog(preauthCatalogParams)\n .catch(() => Promise.resolve())\n .then(() => this.requestAuthorizationCodeGrant({code, codeVerifier}))\n .catch((error) => {\n this.logger.warn('authorization: failed initial authorization code grant request', error);\n })\n .then(() => {\n this.ready = true;\n });\n });\n\n return ret;\n },\n\n /**\n * Kicks off an oauth flow\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @returns {Promise}\n */\n initiateLogin(options = {}) {\n options = cloneDeep(options);\n if (options.email) {\n options.emailHash = CryptoJS.SHA256(options.email).toString();\n }\n delete options.email;\n options.state = options.state || {};\n options.state.csrf_token = this._generateSecurityToken();\n // catalog uses emailhash and redirectCI uses emailHash\n options.state.emailhash = options.emailHash;\n\n options.code_challenge = this._generateCodeChallenge();\n options.code_challenge_method = 'S256';\n\n return this.initiateAuthorizationCodeGrant(options);\n },\n\n @whileInFlight('isAuthorizing')\n /**\n * Kicks off the Implicit Code grant flow. Typically called via\n * {@link AuthorizationBrowserFirstParty#initiateLogin}\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @returns {Promise}\n */\n initiateAuthorizationCodeGrant(options) {\n this.logger.info('authorization: initiating authorization code grant flow');\n this.webex.getWindow().location = this.webex.credentials.buildLoginUrl(\n Object.assign({response_type: 'code'}, options)\n );\n\n return Promise.resolve();\n },\n\n /**\n * Called by {@link WebexCore#logout()}. Redirects to the logout page\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @param {boolean} options.noRedirect if true, does not redirect\n * @returns {Promise}\n */\n logout(options = {}) {\n if (!options.noRedirect) {\n this.webex.getWindow().location = this.webex.credentials.buildLogoutUrl(options);\n }\n },\n\n @whileInFlight('isAuthorizing')\n @oneFlight\n /**\n * Exchanges an authorization code for an access token\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @param {Object} options.code\n * @returns {Promise}\n */\n requestAuthorizationCodeGrant(options = {}) {\n this.logger.info('credentials: requesting authorization code grant');\n\n if (!options.code) {\n return Promise.reject(new Error('`options.code` is required'));\n }\n\n const form = {\n grant_type: 'authorization_code',\n redirect_uri: this.config.redirect_uri,\n code: options.code,\n self_contained_token: true,\n };\n\n if (options.codeVerifier) {\n form.code_verifier = options.codeVerifier;\n }\n\n return this.webex\n .request({\n method: 'POST',\n uri: this.config.tokenUrl,\n form,\n auth: {\n user: this.config.client_id,\n pass: this.config.client_secret,\n sendImmediately: true,\n },\n shouldRefreshAccessToken: false,\n })\n .then((res) => {\n this.webex.credentials.set({supertoken: res.body});\n })\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 /**\n * Generate a QR code URL to launch the Webex app when scanning with the camera\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {String} verificationUrl\n * @returns {String}\n */\n _generateQRCodeVerificationUrl(verificationUrl) {\n const baseUrl = 'https://web.webex.com/deviceAuth';\n const urlParams = new URLSearchParams(new URL(verificationUrl).search);\n const userCode = urlParams.get('userCode');\n\n if (userCode) {\n const {services} = this.webex.internal;\n const oauthHelperUrl = services.get('oauth-helper');\n const newVerificationUrl = new URL(baseUrl);\n newVerificationUrl.searchParams.set('usercode', userCode);\n newVerificationUrl.searchParams.set('oauthhelper', oauthHelperUrl);\n return newVerificationUrl.toString();\n } else {\n return verificationUrl;\n }\n },\n\n /**\n * Get an OAuth Login URL for QRCode. Generate QR code based on the returned URL.\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @emits #qRCodeLogin\n */\n initQRCodeLogin() {\n if (this.pollingTimer) {\n this.eventEmitter.emit(Events.qRCodeLogin, {\n eventType: 'getUserCodeFailure',\n data: {message: 'There is already a polling request'},\n });\n return;\n }\n\n this.webex\n .request({\n method: 'POST',\n service: 'oauth-helper',\n resource: '/actions/device/authorize',\n form: {\n client_id: this.config.client_id,\n scope: this.config.scope,\n },\n auth: {\n user: this.config.client_id,\n pass: this.config.client_secret,\n sendImmediately: true,\n },\n })\n .then((res) => {\n const {user_code, verification_uri, verification_uri_complete} = res.body;\n const verificationUriComplete = this._generateQRCodeVerificationUrl(verification_uri_complete);\n this.eventEmitter.emit(Events.qRCodeLogin, {\n eventType: 'getUserCodeSuccess',\n userData: {\n userCode: user_code,\n verificationUri: verification_uri,\n verificationUriComplete,\n },\n });\n // if device authorization success, then start to poll server to check whether the user has completed authorization\n this._startQRCodePolling(res.body);\n })\n .catch((res) => {\n this.eventEmitter.emit(Events.qRCodeLogin, {\n eventType: 'getUserCodeFailure',\n data: res.body,\n });\n });\n },\n\n /**\n * Polling the server to check whether the user has completed authorization\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @emits #qRCodeLogin\n */\n _startQRCodePolling(options = {}) {\n if (!options.device_code) {\n this.eventEmitter.emit(Events.qRCodeLogin, {\n eventType: 'authorizationFailure',\n data: {message: 'A deviceCode is required'},\n });\n return;\n }\n\n if (this.pollingTimer) {\n this.eventEmitter.emit(Events.qRCodeLogin, {\n eventType: 'authorizationFailure',\n data: {message: 'There is already a polling request'},\n });\n return;\n }\n\n const {device_code: deviceCode, expires_in: expiresIn = 300} = options;\n let interval = options.interval ?? 2;\n\n this.pollingExpirationTimer = setTimeout(() => {\n this.cancelQRCodePolling(false);\n this.eventEmitter.emit(Events.qRCodeLogin, {\n eventType: 'authorizationFailure',\n data: {message: 'Authorization timed out'},\n });\n }, expiresIn * 1000);\n\n const polling = () => {\n this.pollingId += 1;\n this.currentPollingId = this.pollingId;\n\n this.webex\n .request({\n method: 'POST',\n service: 'oauth-helper',\n resource: '/actions/device/token',\n form: {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n client_id: this.config.client_id,\n },\n auth: {\n user: this.config.client_id,\n pass: this.config.client_secret,\n sendImmediately: true,\n },\n })\n .then((res) => {\n // if the pollingId has changed, it means that the polling request has been canceled\n if (this.currentPollingId !== this.pollingId) return;\n\n this.eventEmitter.emit(Events.qRCodeLogin, {\n eventType: 'authorizationSuccess',\n data: res.body,\n });\n this.cancelQRCodePolling();\n })\n .catch((res) => {\n // if the pollingId has changed, it means that the polling request has been canceled\n if (this.currentPollingId !== this.pollingId) return;\n\n // When server sends 400 status code with message 'slow_down', it means that last request happened too soon.\n // So, skip one interval and then poll again.\n if (res.statusCode === 400 && res.body.message === 'slow_down') {\n schedulePolling(interval * 2);\n return;\n }\n\n // if the statusCode is 428 which means that the authorization request is still pending\n // as the end user hasn't yet completed the user-interaction steps. So keep polling.\n if (res.statusCode === 428) {\n this.eventEmitter.emit(Events.qRCodeLogin, {\n eventType: 'authorizationPending',\n data: res.body,\n });\n schedulePolling(interval);\n return;\n }\n\n this.cancelQRCodePolling();\n\n this.eventEmitter.emit(Events.qRCodeLogin, {\n eventType: 'authorizationFailure',\n data: res.body,\n });\n });\n };\n\n const schedulePolling = (interval) =>\n (this.pollingTimer = setTimeout(polling, interval * 1000));\n\n schedulePolling(interval);\n },\n\n /**\n * cancel polling request\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @returns {void}\n */\n cancelQRCodePolling(withCancelEvent = true) {\n if (this.pollingTimer && withCancelEvent) {\n this.eventEmitter.emit(Events.qRCodeLogin, {\n eventType: 'pollingCanceled',\n });\n }\n\n this.currentPollingId = null;\n\n clearTimeout(this.pollingExpirationTimer);\n this.pollingExpirationTimer = null;\n clearTimeout(this.pollingTimer);\n this.pollingTimer = null;\n },\n\n /**\n * Extracts the orgId from the returned code from idbroker\n * Description of how to parse the code can be found here:\n * https://wiki.cisco.com/display/IDENTITY/Federated+Token+Validation\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {String} code\n * @private\n * @returns {String}\n */\n _extractOrgIdFromCode(code) {\n return code?.split('_')[2] || undefined;\n },\n\n /**\n * Checks if the result of the login redirect contains an error string\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} location\n * @private\n * @returns {Promise}\n */\n _checkForErrors(location) {\n const {query} = location;\n\n if (query && query.error) {\n const ErrorConstructor = grantErrors.select(query.error);\n\n throw new ErrorConstructor(query);\n }\n },\n\n /**\n * Removes no-longer needed values from the url (access token, csrf token, etc)\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} location\n * @private\n * @returns {Promise}\n */\n _cleanUrl(location) {\n location = cloneDeep(location);\n if (this.webex.getWindow().history && this.webex.getWindow().history.replaceState) {\n Reflect.deleteProperty(location.query, 'code');\n if (isEmpty(omit(location.query.state, 'csrf_token'))) {\n Reflect.deleteProperty(location.query, 'state');\n } else {\n location.query.state = base64.encode(\n JSON.stringify(omit(location.query.state, 'csrf_token'))\n );\n }\n location.search = querystring.stringify(location.query);\n Reflect.deleteProperty(location, 'query');\n this.webex.getWindow().history.replaceState({}, null, url.format(location));\n }\n },\n\n /**\n * Generates PKCE code verifier and code challenge and sets the the code verifier in sessionStorage\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @private\n * @returns {string}\n */\n _generateCodeChallenge() {\n this.logger.info('authorization: generating PKCE code challenge');\n\n // eslint-disable-next-line no-underscore-dangle\n const safeCharacterMap = base64url._safe_map;\n\n const codeVerifier = lodash\n .times(128, () => safeCharacterMap[lodash.random(0, safeCharacterMap.length - 1)])\n .join('');\n\n const codeChallenge = CryptoJS.SHA256(codeVerifier).toString(base64url);\n\n this.webex.getWindow().sessionStorage.setItem(OAUTH2_CODE_VERIFIER, codeVerifier);\n\n return codeChallenge;\n },\n\n /**\n * Generates a CSRF token and sticks in in sessionStorage\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @private\n * @returns {Promise}\n */\n _generateSecurityToken() {\n this.logger.info('authorization: generating csrf token');\n\n const token = uuid.v4();\n\n this.webex.getWindow().sessionStorage.setItem('oauth2-csrf-token', token);\n\n return token;\n },\n\n /**\n * Checks if the CSRF token in sessionStorage is the same as the one returned\n * in the url.\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} query\n * @private\n * @returns {Promise}\n */\n _verifySecurityToken(query) {\n const sessionToken = this.webex.getWindow().sessionStorage.getItem(OAUTH2_CSRF_TOKEN);\n\n this.webex.getWindow().sessionStorage.removeItem(OAUTH2_CSRF_TOKEN);\n if (!sessionToken) {\n return;\n }\n\n if (!query.state) {\n throw new Error(`Expected CSRF token ${sessionToken}, but not found in redirect query`);\n }\n\n if (!query.state.csrf_token) {\n throw new Error(`Expected CSRF token ${sessionToken}, but not found in redirect query`);\n }\n\n const token = query.state.csrf_token;\n\n if (token !== sessionToken) {\n throw new Error(`CSRF token ${token} does not match stored token ${sessionToken}`);\n }\n },\n});\n\nexport default Authorization;\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _typeof = require("@babel/runtime-corejs2/helpers/typeof");
|
|
4
|
+
var _WeakMap = require("@babel/runtime-corejs2/core-js/weak-map");
|
|
3
5
|
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
6
|
+
var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
|
|
4
7
|
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
5
8
|
_Object$defineProperty(exports, "__esModule", {
|
|
6
9
|
value: true
|
|
7
10
|
});
|
|
11
|
+
_Object$defineProperty(exports, "Events", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function get() {
|
|
14
|
+
return _authorization.Events;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
8
17
|
_Object$defineProperty(exports, "config", {
|
|
9
18
|
enumerable: true,
|
|
10
19
|
get: function get() {
|
|
@@ -18,8 +27,10 @@ _Object$defineProperty(exports, "default", {
|
|
|
18
27
|
}
|
|
19
28
|
});
|
|
20
29
|
var _webexCore = require("@webex/webex-core");
|
|
21
|
-
var _authorization =
|
|
30
|
+
var _authorization = _interopRequireWildcard(require("./authorization"));
|
|
22
31
|
var _config = _interopRequireDefault(require("./config"));
|
|
32
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof _WeakMap) return null; var r = new _WeakMap(), t = new _WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
33
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = _Object$defineProperty && _Object$getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? _Object$getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? _Object$defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
23
34
|
/*!
|
|
24
35
|
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
25
36
|
*/
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_webexCore","require","_authorization","
|
|
1
|
+
{"version":3,"names":["_webexCore","require","_authorization","_interopRequireWildcard","_config","_interopRequireDefault","_getRequireWildcardCache","e","_WeakMap","r","t","__esModule","_typeof","default","has","get","n","__proto__","a","_Object$defineProperty","_Object$getOwnPropertyDescriptor","u","Object","prototype","hasOwnProperty","call","i","set","proxies","registerPlugin","Authorization","config"],"sources":["index.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport {registerPlugin} from '@webex/webex-core';\n\nimport Authorization from './authorization';\nimport config from './config';\n\nconst proxies = ['isAuthorizing', 'isAuthenticating'];\n\nregisterPlugin('authorization', Authorization, {\n config,\n proxies,\n});\n\nexport {default, Events} from './authorization';\nexport {default as config} from './config';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,IAAAA,UAAA,GAAAC,OAAA;AAEA,IAAAC,cAAA,GAAAC,uBAAA,CAAAF,OAAA;AACA,IAAAG,OAAA,GAAAC,sBAAA,CAAAJ,OAAA;AAA8B,SAAAK,yBAAAC,CAAA,6BAAAC,QAAA,mBAAAC,CAAA,OAAAD,QAAA,IAAAE,CAAA,OAAAF,QAAA,YAAAF,wBAAA,YAAAA,yBAAAC,CAAA,WAAAA,CAAA,GAAAG,CAAA,GAAAD,CAAA,KAAAF,CAAA;AAAA,SAAAJ,wBAAAI,CAAA,EAAAE,CAAA,SAAAA,CAAA,IAAAF,CAAA,IAAAA,CAAA,CAAAI,UAAA,SAAAJ,CAAA,eAAAA,CAAA,gBAAAK,OAAA,CAAAL,CAAA,0BAAAA,CAAA,WAAAM,OAAA,EAAAN,CAAA,QAAAG,CAAA,GAAAJ,wBAAA,CAAAG,CAAA,OAAAC,CAAA,IAAAA,CAAA,CAAAI,GAAA,CAAAP,CAAA,UAAAG,CAAA,CAAAK,GAAA,CAAAR,CAAA,OAAAS,CAAA,KAAAC,SAAA,UAAAC,CAAA,GAAAC,sBAAA,IAAAC,gCAAA,WAAAC,CAAA,IAAAd,CAAA,oBAAAc,CAAA,IAAAC,MAAA,CAAAC,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAlB,CAAA,EAAAc,CAAA,SAAAK,CAAA,GAAAR,CAAA,GAAAE,gCAAA,CAAAb,CAAA,EAAAc,CAAA,UAAAK,CAAA,KAAAA,CAAA,CAAAX,GAAA,IAAAW,CAAA,CAAAC,GAAA,IAAAR,sBAAA,CAAAH,CAAA,EAAAK,CAAA,EAAAK,CAAA,IAAAV,CAAA,CAAAK,CAAA,IAAAd,CAAA,CAAAc,CAAA,YAAAL,CAAA,CAAAH,OAAA,GAAAN,CAAA,EAAAG,CAAA,IAAAA,CAAA,CAAAiB,GAAA,CAAApB,CAAA,EAAAS,CAAA,GAAAA,CAAA;AAP9B;AACA;AACA;;AAOA,IAAMY,OAAO,GAAG,CAAC,eAAe,EAAE,kBAAkB,CAAC;AAErD,IAAAC,yBAAc,EAAC,eAAe,EAAEC,sBAAa,EAAE;EAC7CC,MAAM,EAANA,eAAM;EACNH,OAAO,EAAPA;AACF,CAAC,CAAC"}
|
package/package.json
CHANGED
package/src/authorization.js
CHANGED
|
@@ -22,6 +22,16 @@ const lodash = require('lodash');
|
|
|
22
22
|
const OAUTH2_CSRF_TOKEN = 'oauth2-csrf-token';
|
|
23
23
|
const OAUTH2_CODE_VERIFIER = 'oauth2-code-verifier';
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Authorization plugin events
|
|
27
|
+
*/
|
|
28
|
+
export const Events = {
|
|
29
|
+
/**
|
|
30
|
+
* QR code login events
|
|
31
|
+
*/
|
|
32
|
+
qRCodeLogin: 'qRCodeLogin',
|
|
33
|
+
};
|
|
34
|
+
|
|
25
35
|
/**
|
|
26
36
|
* Browser support for OAuth2. Automatically parses the URL query for an
|
|
27
37
|
* authorization code
|
|
@@ -67,17 +77,49 @@ const Authorization = WebexPlugin.extend({
|
|
|
67
77
|
|
|
68
78
|
namespace: 'Credentials',
|
|
69
79
|
|
|
80
|
+
/**
|
|
81
|
+
* EventEmitter for authorization events
|
|
82
|
+
* @instance
|
|
83
|
+
* @memberof AuthorizationBrowserFirstParty
|
|
84
|
+
* @type {EventEmitter}
|
|
85
|
+
* @public
|
|
86
|
+
*/
|
|
87
|
+
eventEmitter: new EventEmitter(),
|
|
70
88
|
|
|
71
89
|
/**
|
|
72
|
-
* Stores the
|
|
90
|
+
* Stores the timer ID for QR code polling
|
|
73
91
|
* @instance
|
|
74
92
|
* @memberof AuthorizationBrowserFirstParty
|
|
75
93
|
* @type {?number}
|
|
76
94
|
* @private
|
|
77
95
|
*/
|
|
78
|
-
|
|
96
|
+
pollingTimer: null,
|
|
97
|
+
/**
|
|
98
|
+
* Stores the expiration timer ID for QR code polling
|
|
99
|
+
* @instance
|
|
100
|
+
* @memberof AuthorizationBrowserFirstParty
|
|
101
|
+
* @type {?number}
|
|
102
|
+
* @private
|
|
103
|
+
*/
|
|
104
|
+
pollingExpirationTimer: null,
|
|
79
105
|
|
|
80
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Monotonically increasing id to identify the current polling request
|
|
108
|
+
* @instance
|
|
109
|
+
* @memberof AuthorizationBrowserFirstParty
|
|
110
|
+
* @type {number}
|
|
111
|
+
* @private
|
|
112
|
+
*/
|
|
113
|
+
pollingId: 0,
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Identifier for the current polling request
|
|
117
|
+
* @instance
|
|
118
|
+
* @memberof AuthorizationBrowserFirstParty
|
|
119
|
+
* @type {?number}
|
|
120
|
+
* @private
|
|
121
|
+
*/
|
|
122
|
+
currentPollingId: null,
|
|
81
123
|
|
|
82
124
|
/**
|
|
83
125
|
* Initializer
|
|
@@ -253,6 +295,30 @@ const Authorization = WebexPlugin.extend({
|
|
|
253
295
|
});
|
|
254
296
|
},
|
|
255
297
|
|
|
298
|
+
/**
|
|
299
|
+
* Generate a QR code URL to launch the Webex app when scanning with the camera
|
|
300
|
+
* @instance
|
|
301
|
+
* @memberof AuthorizationBrowserFirstParty
|
|
302
|
+
* @param {String} verificationUrl
|
|
303
|
+
* @returns {String}
|
|
304
|
+
*/
|
|
305
|
+
_generateQRCodeVerificationUrl(verificationUrl) {
|
|
306
|
+
const baseUrl = 'https://web.webex.com/deviceAuth';
|
|
307
|
+
const urlParams = new URLSearchParams(new URL(verificationUrl).search);
|
|
308
|
+
const userCode = urlParams.get('userCode');
|
|
309
|
+
|
|
310
|
+
if (userCode) {
|
|
311
|
+
const {services} = this.webex.internal;
|
|
312
|
+
const oauthHelperUrl = services.get('oauth-helper');
|
|
313
|
+
const newVerificationUrl = new URL(baseUrl);
|
|
314
|
+
newVerificationUrl.searchParams.set('usercode', userCode);
|
|
315
|
+
newVerificationUrl.searchParams.set('oauthhelper', oauthHelperUrl);
|
|
316
|
+
return newVerificationUrl.toString();
|
|
317
|
+
} else {
|
|
318
|
+
return verificationUrl;
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
|
|
256
322
|
/**
|
|
257
323
|
* Get an OAuth Login URL for QRCode. Generate QR code based on the returned URL.
|
|
258
324
|
* @instance
|
|
@@ -260,8 +326,8 @@ const Authorization = WebexPlugin.extend({
|
|
|
260
326
|
* @emits #qRCodeLogin
|
|
261
327
|
*/
|
|
262
328
|
initQRCodeLogin() {
|
|
263
|
-
if (this.
|
|
264
|
-
this.eventEmitter.emit(
|
|
329
|
+
if (this.pollingTimer) {
|
|
330
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
265
331
|
eventType: 'getUserCodeFailure',
|
|
266
332
|
data: {message: 'There is already a polling request'},
|
|
267
333
|
});
|
|
@@ -285,19 +351,20 @@ const Authorization = WebexPlugin.extend({
|
|
|
285
351
|
})
|
|
286
352
|
.then((res) => {
|
|
287
353
|
const {user_code, verification_uri, verification_uri_complete} = res.body;
|
|
288
|
-
this.
|
|
354
|
+
const verificationUriComplete = this._generateQRCodeVerificationUrl(verification_uri_complete);
|
|
355
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
289
356
|
eventType: 'getUserCodeSuccess',
|
|
290
357
|
userData: {
|
|
291
358
|
userCode: user_code,
|
|
292
359
|
verificationUri: verification_uri,
|
|
293
|
-
verificationUriComplete
|
|
294
|
-
}
|
|
360
|
+
verificationUriComplete,
|
|
361
|
+
},
|
|
295
362
|
});
|
|
296
363
|
// if device authorization success, then start to poll server to check whether the user has completed authorization
|
|
297
364
|
this._startQRCodePolling(res.body);
|
|
298
365
|
})
|
|
299
366
|
.catch((res) => {
|
|
300
|
-
this.eventEmitter.emit(
|
|
367
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
301
368
|
eventType: 'getUserCodeFailure',
|
|
302
369
|
data: res.body,
|
|
303
370
|
});
|
|
@@ -313,30 +380,36 @@ const Authorization = WebexPlugin.extend({
|
|
|
313
380
|
*/
|
|
314
381
|
_startQRCodePolling(options = {}) {
|
|
315
382
|
if (!options.device_code) {
|
|
316
|
-
this.eventEmitter.emit(
|
|
383
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
317
384
|
eventType: 'authorizationFailure',
|
|
318
385
|
data: {message: 'A deviceCode is required'},
|
|
319
386
|
});
|
|
320
387
|
return;
|
|
321
388
|
}
|
|
322
389
|
|
|
323
|
-
if (this.
|
|
324
|
-
this.eventEmitter.emit(
|
|
390
|
+
if (this.pollingTimer) {
|
|
391
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
325
392
|
eventType: 'authorizationFailure',
|
|
326
393
|
data: {message: 'There is already a polling request'},
|
|
327
394
|
});
|
|
328
395
|
return;
|
|
329
396
|
}
|
|
330
397
|
|
|
331
|
-
const {device_code: deviceCode,
|
|
398
|
+
const {device_code: deviceCode, expires_in: expiresIn = 300} = options;
|
|
399
|
+
let interval = options.interval ?? 2;
|
|
332
400
|
|
|
333
|
-
|
|
334
|
-
|
|
401
|
+
this.pollingExpirationTimer = setTimeout(() => {
|
|
402
|
+
this.cancelQRCodePolling(false);
|
|
403
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
404
|
+
eventType: 'authorizationFailure',
|
|
405
|
+
data: {message: 'Authorization timed out'},
|
|
406
|
+
});
|
|
407
|
+
}, expiresIn * 1000);
|
|
335
408
|
|
|
336
|
-
|
|
337
|
-
|
|
409
|
+
const polling = () => {
|
|
410
|
+
this.pollingId += 1;
|
|
411
|
+
this.currentPollingId = this.pollingId;
|
|
338
412
|
|
|
339
|
-
const currentAttempts = attempts;
|
|
340
413
|
this.webex
|
|
341
414
|
.request({
|
|
342
415
|
method: 'POST',
|
|
@@ -354,43 +427,50 @@ const Authorization = WebexPlugin.extend({
|
|
|
354
427
|
},
|
|
355
428
|
})
|
|
356
429
|
.then((res) => {
|
|
357
|
-
if
|
|
430
|
+
// if the pollingId has changed, it means that the polling request has been canceled
|
|
431
|
+
if (this.currentPollingId !== this.pollingId) return;
|
|
358
432
|
|
|
359
|
-
this.eventEmitter.emit(
|
|
433
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
360
434
|
eventType: 'authorizationSuccess',
|
|
361
435
|
data: res.body,
|
|
362
436
|
});
|
|
363
437
|
this.cancelQRCodePolling();
|
|
364
438
|
})
|
|
365
439
|
.catch((res) => {
|
|
366
|
-
if
|
|
440
|
+
// if the pollingId has changed, it means that the polling request has been canceled
|
|
441
|
+
if (this.currentPollingId !== this.pollingId) return;
|
|
367
442
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
});
|
|
373
|
-
this.cancelQRCodePolling();
|
|
443
|
+
// When server sends 400 status code with message 'slow_down', it means that last request happened too soon.
|
|
444
|
+
// So, skip one interval and then poll again.
|
|
445
|
+
if (res.statusCode === 400 && res.body.message === 'slow_down') {
|
|
446
|
+
schedulePolling(interval * 2);
|
|
374
447
|
return;
|
|
375
448
|
}
|
|
449
|
+
|
|
376
450
|
// if the statusCode is 428 which means that the authorization request is still pending
|
|
377
451
|
// as the end user hasn't yet completed the user-interaction steps. So keep polling.
|
|
378
452
|
if (res.statusCode === 428) {
|
|
379
|
-
this.eventEmitter.emit(
|
|
453
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
380
454
|
eventType: 'authorizationPending',
|
|
381
|
-
data: res.body
|
|
455
|
+
data: res.body,
|
|
382
456
|
});
|
|
457
|
+
schedulePolling(interval);
|
|
383
458
|
return;
|
|
384
459
|
}
|
|
385
460
|
|
|
386
461
|
this.cancelQRCodePolling();
|
|
387
462
|
|
|
388
|
-
this.eventEmitter.emit(
|
|
463
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
389
464
|
eventType: 'authorizationFailure',
|
|
390
|
-
data: res.body
|
|
465
|
+
data: res.body,
|
|
391
466
|
});
|
|
392
467
|
});
|
|
393
|
-
}
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
const schedulePolling = (interval) =>
|
|
471
|
+
(this.pollingTimer = setTimeout(polling, interval * 1000));
|
|
472
|
+
|
|
473
|
+
schedulePolling(interval);
|
|
394
474
|
},
|
|
395
475
|
|
|
396
476
|
/**
|
|
@@ -399,14 +479,19 @@ const Authorization = WebexPlugin.extend({
|
|
|
399
479
|
* @memberof AuthorizationBrowserFirstParty
|
|
400
480
|
* @returns {void}
|
|
401
481
|
*/
|
|
402
|
-
cancelQRCodePolling() {
|
|
403
|
-
if (this.
|
|
404
|
-
|
|
405
|
-
this.eventEmitter.emit('qRCodeLogin', {
|
|
482
|
+
cancelQRCodePolling(withCancelEvent = true) {
|
|
483
|
+
if (this.pollingTimer && withCancelEvent) {
|
|
484
|
+
this.eventEmitter.emit(Events.qRCodeLogin, {
|
|
406
485
|
eventType: 'pollingCanceled',
|
|
407
486
|
});
|
|
408
|
-
this.pollingRequest = null;
|
|
409
487
|
}
|
|
488
|
+
|
|
489
|
+
this.currentPollingId = null;
|
|
490
|
+
|
|
491
|
+
clearTimeout(this.pollingExpirationTimer);
|
|
492
|
+
this.pollingExpirationTimer = null;
|
|
493
|
+
clearTimeout(this.pollingTimer);
|
|
494
|
+
this.pollingTimer = null;
|
|
410
495
|
},
|
|
411
496
|
|
|
412
497
|
/**
|
package/src/index.js
CHANGED
|
@@ -18,7 +18,6 @@ import Authorization from '@webex/plugin-authorization-browser-first-party';
|
|
|
18
18
|
// Necessary to require lodash this way in order to stub the method
|
|
19
19
|
const lodash = require('lodash');
|
|
20
20
|
|
|
21
|
-
|
|
22
21
|
describe('plugin-authorization-browser-first-party', () => {
|
|
23
22
|
describe('Authorization', () => {
|
|
24
23
|
function makeWebex(
|
|
@@ -187,14 +186,16 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
187
186
|
const webex = makeWebex(
|
|
188
187
|
`http://example.com/?code=${code}&state=${base64.encode(
|
|
189
188
|
JSON.stringify({emailhash: 'someemailhash'})
|
|
190
|
-
)}
|
|
189
|
+
)}`
|
|
191
190
|
);
|
|
192
191
|
|
|
193
192
|
const requestAuthorizationCodeGrantStub = sinon.stub(
|
|
194
193
|
Authorization.prototype,
|
|
195
194
|
'requestAuthorizationCodeGrant'
|
|
196
195
|
);
|
|
197
|
-
const collectPreauthCatalogStub = sinon
|
|
196
|
+
const collectPreauthCatalogStub = sinon
|
|
197
|
+
.stub(Services.prototype, 'collectPreauthCatalog')
|
|
198
|
+
.resolves();
|
|
198
199
|
|
|
199
200
|
await webex.authorization.when('change:ready');
|
|
200
201
|
|
|
@@ -206,9 +207,7 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
206
207
|
|
|
207
208
|
it('collects the preauth catalog no emailhash is present in the state', async () => {
|
|
208
209
|
const code = 'authcode_clusterid_theOrgId';
|
|
209
|
-
const webex = makeWebex(
|
|
210
|
-
`http://example.com/?code=${code}`
|
|
211
|
-
);
|
|
210
|
+
const webex = makeWebex(`http://example.com/?code=${code}`);
|
|
212
211
|
|
|
213
212
|
const requestAuthorizationCodeGrantStub = sinon.stub(
|
|
214
213
|
Authorization.prototype,
|
|
@@ -271,12 +270,13 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
271
270
|
it('throws a grant error', () => {
|
|
272
271
|
let err = null;
|
|
273
272
|
try {
|
|
274
|
-
makeWebex(
|
|
275
|
-
|
|
276
|
-
|
|
273
|
+
makeWebex(
|
|
274
|
+
'http://127.0.0.1:8000/?error=invalid_scope&error_description=The%20requested%20scope%20is%20invalid.'
|
|
275
|
+
);
|
|
276
|
+
} catch (e) {
|
|
277
277
|
err = e;
|
|
278
278
|
}
|
|
279
|
-
expect(err?.message).toBe('Cannot convert object to primitive value')
|
|
279
|
+
expect(err?.message).toBe('Cannot convert object to primitive value');
|
|
280
280
|
});
|
|
281
281
|
});
|
|
282
282
|
|
|
@@ -443,17 +443,49 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
443
443
|
});
|
|
444
444
|
});
|
|
445
445
|
|
|
446
|
+
describe('#_generateQRCodeVerificationUrl()', () => {
|
|
447
|
+
it('should generate a QR code URL when a userCode is present', () => {
|
|
448
|
+
const verificationUrl = 'https://example.com/verify?userCode=123456';
|
|
449
|
+
const oauthHelperUrl = 'https://oauth-helper-a.wbx2.com/helperservice/v1';
|
|
450
|
+
const expectedUrl = 'https://web.webex.com/deviceAuth?usercode=123456&oauthhelper=https%3A%2F%2Foauth-helper-a.wbx2.com%2Fhelperservice%2Fv1';
|
|
451
|
+
|
|
452
|
+
const webex = makeWebex('http://example.com');
|
|
453
|
+
|
|
454
|
+
const oauthHelperSpy = sinon.stub(webex.internal.services, 'get').returns(oauthHelperUrl);
|
|
455
|
+
const result = webex.authorization._generateQRCodeVerificationUrl(verificationUrl);
|
|
456
|
+
|
|
457
|
+
assert.calledOnce(oauthHelperSpy);
|
|
458
|
+
assert.calledWithExactly(oauthHelperSpy, 'oauth-helper');
|
|
459
|
+
assert.equal(result, expectedUrl);
|
|
460
|
+
|
|
461
|
+
oauthHelperSpy.restore();
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it('should return the original verificationUrl when userCode is not present', () => {
|
|
465
|
+
const verificationUrl = 'https://example.com/verify';
|
|
466
|
+
const webex = makeWebex('http://example.com');
|
|
467
|
+
|
|
468
|
+
const oauthHelperSpy = sinon.stub(webex.internal.services, 'get');
|
|
469
|
+
const result = webex.authorization._generateQRCodeVerificationUrl(verificationUrl);
|
|
470
|
+
|
|
471
|
+
assert.notCalled(oauthHelperSpy);
|
|
472
|
+
assert.equal(result, verificationUrl);
|
|
473
|
+
|
|
474
|
+
oauthHelperSpy.restore();
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
|
|
446
478
|
describe('#initQRCodeLogin()', () => {
|
|
447
479
|
it('should prevent concurrent request if there is already a polling request', async () => {
|
|
448
480
|
const webex = makeWebex('http://example.com');
|
|
449
|
-
|
|
450
|
-
webex.authorization.
|
|
481
|
+
|
|
482
|
+
webex.authorization.pollingTimer = 1;
|
|
451
483
|
const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
|
|
452
484
|
webex.authorization.initQRCodeLogin();
|
|
453
|
-
|
|
485
|
+
|
|
454
486
|
assert.calledOnce(emitSpy);
|
|
455
|
-
assert.equal(emitSpy.getCall(0).args[1].eventType, 'getUserCodeFailure');
|
|
456
|
-
webex.authorization.
|
|
487
|
+
assert.equal(emitSpy.getCall(0).args[1].eventType, 'getUserCodeFailure');
|
|
488
|
+
webex.authorization.pollingTimer = null;
|
|
457
489
|
});
|
|
458
490
|
|
|
459
491
|
it('should send correct request parameters to the API', async () => {
|
|
@@ -461,31 +493,33 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
461
493
|
const testClientId = 'test-client-id';
|
|
462
494
|
const testScope = 'test-scope';
|
|
463
495
|
const sampleData = {
|
|
464
|
-
device_code:
|
|
496
|
+
device_code: 'test123',
|
|
465
497
|
expires_in: 300,
|
|
466
|
-
user_code:
|
|
467
|
-
verification_uri:
|
|
468
|
-
verification_uri_complete:
|
|
469
|
-
interval: 2
|
|
498
|
+
user_code: '421175',
|
|
499
|
+
verification_uri: 'http://example.com',
|
|
500
|
+
verification_uri_complete: 'http://example.com',
|
|
501
|
+
interval: 2,
|
|
470
502
|
};
|
|
471
503
|
|
|
472
504
|
const webex = makeWebex('http://example.com', undefined, undefined, {
|
|
473
505
|
credentials: {
|
|
474
506
|
client_id: testClientId,
|
|
475
507
|
scope: testScope,
|
|
476
|
-
}
|
|
508
|
+
},
|
|
477
509
|
});
|
|
478
510
|
webex.request.onFirstCall().resolves({statusCode: 200, body: sampleData});
|
|
479
511
|
sinon.spy(webex.authorization, '_startQRCodePolling');
|
|
512
|
+
sinon.spy(webex.authorization, '_generateQRCodeVerificationUrl');
|
|
480
513
|
const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
|
|
481
514
|
|
|
482
515
|
webex.authorization.initQRCodeLogin();
|
|
483
516
|
clock.tick(2000);
|
|
484
|
-
await clock.runAllAsync()
|
|
517
|
+
await clock.runAllAsync();
|
|
485
518
|
|
|
486
519
|
assert.calledTwice(webex.request);
|
|
487
520
|
assert.calledOnce(webex.authorization._startQRCodePolling);
|
|
488
|
-
assert.
|
|
521
|
+
assert.calledOnce(webex.authorization._generateQRCodeVerificationUrl);
|
|
522
|
+
assert.equal(emitSpy.getCall(0).args[1].eventType, 'getUserCodeSuccess');
|
|
489
523
|
|
|
490
524
|
const request = webex.request.getCall(0);
|
|
491
525
|
|
|
@@ -498,18 +532,18 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
498
532
|
const clock = sinon.useFakeTimers();
|
|
499
533
|
const webex = makeWebex('http://example.com');
|
|
500
534
|
const sampleData = {
|
|
501
|
-
device_code:
|
|
535
|
+
device_code: 'test123',
|
|
502
536
|
expires_in: 300,
|
|
503
|
-
user_code:
|
|
504
|
-
verification_uri:
|
|
505
|
-
verification_uri_complete:
|
|
506
|
-
interval: 2
|
|
537
|
+
user_code: '421175',
|
|
538
|
+
verification_uri: 'http://example.com',
|
|
539
|
+
verification_uri_complete: 'http://example.com',
|
|
540
|
+
interval: 2,
|
|
507
541
|
};
|
|
508
542
|
webex.request.resolves().resolves({statusCode: 200, body: sampleData});
|
|
509
543
|
|
|
510
544
|
webex.authorization.initQRCodeLogin();
|
|
511
545
|
clock.tick(2000);
|
|
512
|
-
await clock.runAllAsync()
|
|
546
|
+
await clock.runAllAsync();
|
|
513
547
|
|
|
514
548
|
const request = webex.request.getCall(0);
|
|
515
549
|
assert.equal(request.args[0].method, 'POST');
|
|
@@ -517,7 +551,7 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
517
551
|
assert.equal(request.args[0].resource, '/actions/device/authorize');
|
|
518
552
|
clock.restore();
|
|
519
553
|
});
|
|
520
|
-
|
|
554
|
+
|
|
521
555
|
it('should emit getUserCodeFailure event', async () => {
|
|
522
556
|
const clock = sinon.useFakeTimers();
|
|
523
557
|
const webex = makeWebex('http://example.com');
|
|
@@ -526,7 +560,7 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
526
560
|
|
|
527
561
|
webex.authorization.initQRCodeLogin();
|
|
528
562
|
|
|
529
|
-
await clock.runAllAsync()
|
|
563
|
+
await clock.runAllAsync();
|
|
530
564
|
|
|
531
565
|
assert.calledOnce(emitSpy);
|
|
532
566
|
assert.equal(emitSpy.getCall(0).args[1].eventType, 'getUserCodeFailure');
|
|
@@ -537,15 +571,15 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
537
571
|
describe('#_startQRCodePolling()', () => {
|
|
538
572
|
it('requires a deviceCode', () => {
|
|
539
573
|
const webex = makeWebex('http://example.com');
|
|
540
|
-
|
|
574
|
+
|
|
541
575
|
const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
|
|
542
576
|
|
|
543
577
|
webex.authorization._startQRCodePolling({});
|
|
544
578
|
|
|
545
579
|
assert.calledOnce(emitSpy);
|
|
546
|
-
assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationFailure');
|
|
580
|
+
assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationFailure');
|
|
547
581
|
});
|
|
548
|
-
|
|
582
|
+
|
|
549
583
|
it('should send correct request parameters to the API', async () => {
|
|
550
584
|
const clock = sinon.useFakeTimers();
|
|
551
585
|
const testClientId = 'test-client-id';
|
|
@@ -560,7 +594,7 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
560
594
|
const webex = makeWebex('http://example.com', undefined, undefined, {
|
|
561
595
|
credentials: {
|
|
562
596
|
client_id: testClientId,
|
|
563
|
-
}
|
|
597
|
+
},
|
|
564
598
|
});
|
|
565
599
|
|
|
566
600
|
webex.request.onFirstCall().resolves({statusCode: 200, body: {access_token: 'token'}});
|
|
@@ -569,7 +603,7 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
569
603
|
|
|
570
604
|
webex.authorization._startQRCodePolling(options);
|
|
571
605
|
clock.tick(2000);
|
|
572
|
-
await clock.runAllAsync()
|
|
606
|
+
await clock.runAllAsync();
|
|
573
607
|
|
|
574
608
|
assert.calledOnce(webex.request);
|
|
575
609
|
|
|
@@ -577,7 +611,10 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
577
611
|
|
|
578
612
|
assert.equal(request.args[0].form.client_id, testClientId);
|
|
579
613
|
assert.equal(request.args[0].form.device_code, testDeviceCode);
|
|
580
|
-
assert.equal(
|
|
614
|
+
assert.equal(
|
|
615
|
+
request.args[0].form.grant_type,
|
|
616
|
+
'urn:ietf:params:oauth:grant-type:device_code'
|
|
617
|
+
);
|
|
581
618
|
|
|
582
619
|
assert.calledOnce(webex.authorization.cancelQRCodePolling);
|
|
583
620
|
assert.calledTwice(emitSpy);
|
|
@@ -593,23 +630,26 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
593
630
|
const options = {
|
|
594
631
|
device_code: 'test-device-code',
|
|
595
632
|
interval: 2,
|
|
596
|
-
expires_in: 300
|
|
633
|
+
expires_in: 300,
|
|
597
634
|
};
|
|
598
|
-
|
|
599
|
-
webex.request
|
|
635
|
+
|
|
636
|
+
webex.request
|
|
637
|
+
.onFirstCall()
|
|
638
|
+
.rejects({statusCode: 428, body: {message: 'authorization_pending'}});
|
|
600
639
|
webex.request.onSecondCall().resolves({statusCode: 200, body: {access_token: 'token'}});
|
|
601
640
|
sinon.spy(webex.authorization, 'cancelQRCodePolling');
|
|
602
641
|
const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
|
|
603
|
-
|
|
642
|
+
|
|
604
643
|
webex.authorization._startQRCodePolling(options);
|
|
605
|
-
clock.
|
|
606
|
-
await clock.runAllAsync()
|
|
607
|
-
|
|
644
|
+
await clock.tickAsync(4000);
|
|
645
|
+
//await clock.runAllAsync()
|
|
646
|
+
|
|
608
647
|
assert.calledTwice(webex.request);
|
|
609
648
|
assert.calledOnce(webex.authorization.cancelQRCodePolling);
|
|
610
|
-
assert.
|
|
611
|
-
assert.equal(emitSpy.getCall(0).args[1].eventType, '
|
|
612
|
-
assert.equal(emitSpy.getCall(1).args[1].eventType, '
|
|
649
|
+
assert.calledThrice(emitSpy);
|
|
650
|
+
assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationPending');
|
|
651
|
+
assert.equal(emitSpy.getCall(1).args[1].eventType, 'authorizationSuccess');
|
|
652
|
+
assert.equal(emitSpy.getCall(2).args[1].eventType, 'pollingCanceled');
|
|
613
653
|
clock.restore();
|
|
614
654
|
});
|
|
615
655
|
|
|
@@ -619,23 +659,21 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
619
659
|
const options = {
|
|
620
660
|
device_code: 'test-device-code',
|
|
621
661
|
interval: 5,
|
|
622
|
-
expires_in:
|
|
662
|
+
expires_in: 9,
|
|
623
663
|
};
|
|
624
|
-
|
|
664
|
+
|
|
625
665
|
webex.request.rejects({statusCode: 428, body: {message: 'authorizationPending'}});
|
|
626
666
|
sinon.spy(webex.authorization, 'cancelQRCodePolling');
|
|
627
667
|
const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
|
|
628
668
|
|
|
629
669
|
webex.authorization._startQRCodePolling(options);
|
|
630
|
-
clock.
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
assert.calledTwice(webex.request);
|
|
670
|
+
await clock.tickAsync(10_000);
|
|
671
|
+
|
|
672
|
+
assert.calledOnce(webex.request);
|
|
634
673
|
assert.calledOnce(webex.authorization.cancelQRCodePolling);
|
|
635
|
-
assert.
|
|
636
|
-
assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationPending');
|
|
674
|
+
assert.calledTwice(emitSpy);
|
|
675
|
+
assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationPending');
|
|
637
676
|
assert.equal(emitSpy.getCall(1).args[1].eventType, 'authorizationFailure');
|
|
638
|
-
assert.equal(emitSpy.getCall(2).args[1].eventType, 'pollingCanceled');
|
|
639
677
|
clock.restore();
|
|
640
678
|
});
|
|
641
679
|
|
|
@@ -644,54 +682,129 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
644
682
|
const options = {
|
|
645
683
|
device_code: 'test-device-code',
|
|
646
684
|
interval: 2,
|
|
647
|
-
expires_in: 300
|
|
685
|
+
expires_in: 300,
|
|
648
686
|
};
|
|
649
|
-
|
|
650
|
-
webex.authorization.
|
|
687
|
+
|
|
688
|
+
webex.authorization.pollingTimer = 1;
|
|
651
689
|
|
|
652
690
|
const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
|
|
653
691
|
webex.authorization._startQRCodePolling(options);
|
|
654
692
|
|
|
655
693
|
assert.calledOnce(emitSpy);
|
|
656
|
-
assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationFailure');
|
|
657
|
-
webex.authorization.
|
|
694
|
+
assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationFailure');
|
|
695
|
+
webex.authorization.pollingTimer = null;
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
it('should skip a interval when server ask for slow_down', async () => {
|
|
699
|
+
const clock = sinon.useFakeTimers();
|
|
700
|
+
const webex = makeWebex('http://example.com');
|
|
701
|
+
const options = {
|
|
702
|
+
device_code: 'test-device-code',
|
|
703
|
+
interval: 2,
|
|
704
|
+
expires_in: 300,
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
webex.request.onFirstCall().rejects({statusCode: 400, body: {message: 'slow_down'}});
|
|
708
|
+
webex.request.onSecondCall().resolves({statusCode: 200, body: {access_token: 'token'}});
|
|
709
|
+
sinon.spy(webex.authorization, 'cancelQRCodePolling');
|
|
710
|
+
const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
|
|
711
|
+
|
|
712
|
+
webex.authorization._startQRCodePolling(options);
|
|
713
|
+
await clock.tickAsync(4000);
|
|
714
|
+
|
|
715
|
+
// Request only once because of slow_down
|
|
716
|
+
assert.calledOnce(webex.request);
|
|
717
|
+
|
|
718
|
+
// Wait for next interval
|
|
719
|
+
await clock.tickAsync(2000);
|
|
720
|
+
|
|
721
|
+
assert.calledTwice(webex.request);
|
|
722
|
+
assert.calledOnce(webex.authorization.cancelQRCodePolling);
|
|
723
|
+
assert.calledTwice(emitSpy);
|
|
724
|
+
assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationSuccess');
|
|
725
|
+
assert.equal(emitSpy.getCall(1).args[1].eventType, 'pollingCanceled');
|
|
726
|
+
clock.restore();
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
it('should ignore the response from the previous polling', async () => {
|
|
730
|
+
const clock = sinon.useFakeTimers();
|
|
731
|
+
const webex = makeWebex('http://example.com');
|
|
732
|
+
const options = {
|
|
733
|
+
device_code: 'test-device-code',
|
|
734
|
+
interval: 2,
|
|
735
|
+
expires_in: 300,
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
webex.request.onFirstCall().callsFake(() => {
|
|
739
|
+
return new Promise((resolve) => {
|
|
740
|
+
setTimeout(() => {
|
|
741
|
+
resolve({statusCode: 200, body: {access_token: 'token'}});
|
|
742
|
+
}, 1000);
|
|
743
|
+
});
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
webex.request
|
|
747
|
+
.onSecondCall()
|
|
748
|
+
.rejects({statusCode: 428, body: {message: 'authorizationPending'}});
|
|
749
|
+
sinon.spy(webex.authorization, 'cancelQRCodePolling');
|
|
750
|
+
const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
|
|
751
|
+
|
|
752
|
+
webex.authorization._startQRCodePolling(options);
|
|
753
|
+
await clock.tickAsync(2500);
|
|
754
|
+
|
|
755
|
+
webex.authorization.cancelQRCodePolling();
|
|
756
|
+
|
|
757
|
+
// Start new polling
|
|
758
|
+
|
|
759
|
+
webex.authorization._startQRCodePolling(options);
|
|
760
|
+
|
|
761
|
+
// Wait for next interval
|
|
762
|
+
await clock.tickAsync(3000);
|
|
763
|
+
|
|
764
|
+
assert.calledTwice(webex.request);
|
|
765
|
+
assert.calledOnce(webex.authorization.cancelQRCodePolling);
|
|
766
|
+
assert.calledTwice(emitSpy);
|
|
767
|
+
// authorizationSuccess event should not be emitted
|
|
768
|
+
assert.equal(emitSpy.getCall(0).args[1].eventType, 'pollingCanceled');
|
|
769
|
+
assert.equal(emitSpy.getCall(1).args[1].eventType, 'authorizationPending');
|
|
770
|
+
clock.restore();
|
|
658
771
|
});
|
|
659
772
|
});
|
|
660
773
|
|
|
661
774
|
describe('#cancelQRCodePolling()', () => {
|
|
662
775
|
it('should stop polling after cancellation', async () => {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
776
|
+
const clock = sinon.useFakeTimers();
|
|
777
|
+
const webex = makeWebex('http://example.com');
|
|
778
|
+
const options = {
|
|
779
|
+
device_code: 'test-device-code',
|
|
780
|
+
interval: 2,
|
|
781
|
+
expires_in: 300,
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
webex.request.rejects({statusCode: 428, body: {message: 'authorizationPending'}});
|
|
785
|
+
const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
|
|
786
|
+
|
|
787
|
+
webex.authorization._startQRCodePolling(options);
|
|
788
|
+
// First poll
|
|
789
|
+
clock.tick(2000);
|
|
790
|
+
assert.calledOnce(webex.request);
|
|
791
|
+
|
|
792
|
+
webex.authorization.cancelQRCodePolling();
|
|
793
|
+
// Wait for next interval
|
|
794
|
+
clock.tick(2000);
|
|
795
|
+
|
|
796
|
+
const eventArgs = emitSpy.getCall(0).args;
|
|
797
|
+
|
|
798
|
+
// Verify no additional requests were made
|
|
799
|
+
assert.calledOnce(webex.request);
|
|
800
|
+
assert.calledOnce(emitSpy);
|
|
801
|
+
assert.equal(eventArgs[1].eventType, 'pollingCanceled');
|
|
802
|
+
clock.restore();
|
|
803
|
+
});
|
|
691
804
|
it('should clear interval and reset polling request', () => {
|
|
692
805
|
const clock = sinon.useFakeTimers();
|
|
693
806
|
const webex = makeWebex('http://example.com');
|
|
694
|
-
|
|
807
|
+
|
|
695
808
|
const options = {
|
|
696
809
|
device_code: 'test_device_code',
|
|
697
810
|
interval: 2,
|
|
@@ -699,22 +812,21 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
699
812
|
};
|
|
700
813
|
|
|
701
814
|
webex.authorization._startQRCodePolling(options);
|
|
702
|
-
assert.isDefined(webex.authorization.
|
|
703
|
-
|
|
815
|
+
assert.isDefined(webex.authorization.pollingTimer);
|
|
816
|
+
|
|
704
817
|
webex.authorization.cancelQRCodePolling();
|
|
705
|
-
assert.isNull(webex.authorization.
|
|
706
|
-
|
|
818
|
+
assert.isNull(webex.authorization.pollingTimer);
|
|
819
|
+
|
|
707
820
|
clock.restore();
|
|
708
821
|
});
|
|
709
|
-
|
|
822
|
+
|
|
710
823
|
it('should handle cancellation when no polling is in progress', () => {
|
|
711
824
|
const webex = makeWebex('http://example.com');
|
|
712
|
-
assert.isNull(webex.authorization.
|
|
713
|
-
|
|
825
|
+
assert.isNull(webex.authorization.pollingTimer);
|
|
826
|
+
|
|
714
827
|
webex.authorization.cancelQRCodePolling();
|
|
715
|
-
assert.isNull(webex.authorization.
|
|
828
|
+
assert.isNull(webex.authorization.pollingTimer);
|
|
716
829
|
});
|
|
717
|
-
|
|
718
830
|
});
|
|
719
831
|
|
|
720
832
|
describe('#_generateCodeChallenge', () => {
|
|
@@ -836,7 +948,7 @@ describe('plugin-authorization-browser-first-party', () => {
|
|
|
836
948
|
const orgId = webex.authorization._extractOrgIdFromCode(code);
|
|
837
949
|
|
|
838
950
|
assert.isUndefined(orgId);
|
|
839
|
-
})
|
|
951
|
+
});
|
|
840
952
|
});
|
|
841
953
|
});
|
|
842
954
|
});
|