@webex/plugin-authorization-browser-first-party 3.6.0-next.4 → 3.6.0-next.6

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.
@@ -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
- * Stores the interval ID for QR code polling
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
- pollingRequest: null,
86
- eventEmitter: new _events.EventEmitter(),
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
@@ -249,8 +290,8 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
249
290
  */
250
291
  initQRCodeLogin: function initQRCodeLogin() {
251
292
  var _this3 = this;
252
- if (this.pollingRequest) {
253
- this.eventEmitter.emit('qRCodeLogin', {
293
+ if (this.pollingTimer) {
294
+ this.eventEmitter.emit(Events.qRCodeLogin, {
254
295
  eventType: 'getUserCodeFailure',
255
296
  data: {
256
297
  message: 'There is already a polling request'
@@ -276,7 +317,7 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
276
317
  user_code = _res$body.user_code,
277
318
  verification_uri = _res$body.verification_uri,
278
319
  verification_uri_complete = _res$body.verification_uri_complete;
279
- _this3.eventEmitter.emit('qRCodeLogin', {
320
+ _this3.eventEmitter.emit(Events.qRCodeLogin, {
280
321
  eventType: 'getUserCodeSuccess',
281
322
  userData: {
282
323
  userCode: user_code,
@@ -287,7 +328,7 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
287
328
  // if device authorization success, then start to poll server to check whether the user has completed authorization
288
329
  _this3._startQRCodePolling(res.body);
289
330
  }).catch(function (res) {
290
- _this3.eventEmitter.emit('qRCodeLogin', {
331
+ _this3.eventEmitter.emit(Events.qRCodeLogin, {
291
332
  eventType: 'getUserCodeFailure',
292
333
  data: res.body
293
334
  });
@@ -301,10 +342,11 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
301
342
  * @emits #qRCodeLogin
302
343
  */
303
344
  _startQRCodePolling: function _startQRCodePolling() {
304
- var _this4 = this;
345
+ var _options$interval,
346
+ _this4 = this;
305
347
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
306
348
  if (!options.device_code) {
307
- this.eventEmitter.emit('qRCodeLogin', {
349
+ this.eventEmitter.emit(Events.qRCodeLogin, {
308
350
  eventType: 'authorizationFailure',
309
351
  data: {
310
352
  message: 'A deviceCode is required'
@@ -312,8 +354,8 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
312
354
  });
313
355
  return;
314
356
  }
315
- if (this.pollingRequest) {
316
- this.eventEmitter.emit('qRCodeLogin', {
357
+ if (this.pollingTimer) {
358
+ this.eventEmitter.emit(Events.qRCodeLogin, {
317
359
  eventType: 'authorizationFailure',
318
360
  data: {
319
361
  message: 'There is already a polling request'
@@ -322,15 +364,21 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
322
364
  return;
323
365
  }
324
366
  var deviceCode = options.device_code,
325
- _options$interval = options.interval,
326
- interval = _options$interval === void 0 ? 2 : _options$interval,
327
367
  _options$expires_in = options.expires_in,
328
368
  expiresIn = _options$expires_in === void 0 ? 300 : _options$expires_in;
329
- var attempts = 0;
330
- var maxAttempts = expiresIn / interval;
331
- this.pollingRequest = setInterval(function () {
332
- attempts += 1;
333
- var currentAttempts = attempts;
369
+ var interval = (_options$interval = options.interval) !== null && _options$interval !== void 0 ? _options$interval : 2;
370
+ this.pollingExpirationTimer = setTimeout(function () {
371
+ _this4.cancelQRCodePolling(false);
372
+ _this4.eventEmitter.emit(Events.qRCodeLogin, {
373
+ eventType: 'authorizationFailure',
374
+ data: {
375
+ message: 'Authorization timed out'
376
+ }
377
+ });
378
+ }, expiresIn * 1000);
379
+ var polling = function polling() {
380
+ _this4.pollingId += 1;
381
+ _this4.currentPollingId = _this4.pollingId;
334
382
  _this4.webex.request({
335
383
  method: 'POST',
336
384
  service: 'oauth-helper',
@@ -346,40 +394,45 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
346
394
  sendImmediately: true
347
395
  }
348
396
  }).then(function (res) {
349
- if (_this4.pollingRequest === null) return;
350
- _this4.eventEmitter.emit('qRCodeLogin', {
397
+ // if the pollingId has changed, it means that the polling request has been canceled
398
+ if (_this4.currentPollingId !== _this4.pollingId) return;
399
+ _this4.eventEmitter.emit(Events.qRCodeLogin, {
351
400
  eventType: 'authorizationSuccess',
352
401
  data: res.body
353
402
  });
354
403
  _this4.cancelQRCodePolling();
355
404
  }).catch(function (res) {
356
- if (_this4.pollingRequest === null) return;
357
- if (currentAttempts >= maxAttempts) {
358
- _this4.eventEmitter.emit('qRCodeLogin', {
359
- eventType: 'authorizationFailure',
360
- data: {
361
- message: 'Authorization timed out'
362
- }
363
- });
364
- _this4.cancelQRCodePolling();
405
+ // if the pollingId has changed, it means that the polling request has been canceled
406
+ if (_this4.currentPollingId !== _this4.pollingId) return;
407
+
408
+ // When server sends 400 status code with message 'slow_down', it means that last request happened too soon.
409
+ // So, skip one interval and then poll again.
410
+ if (res.statusCode === 400 && res.body.message === 'slow_down') {
411
+ schedulePolling(interval * 2);
365
412
  return;
366
413
  }
414
+
367
415
  // if the statusCode is 428 which means that the authorization request is still pending
368
416
  // as the end user hasn't yet completed the user-interaction steps. So keep polling.
369
417
  if (res.statusCode === 428) {
370
- _this4.eventEmitter.emit('qRCodeLogin', {
418
+ _this4.eventEmitter.emit(Events.qRCodeLogin, {
371
419
  eventType: 'authorizationPending',
372
420
  data: res.body
373
421
  });
422
+ schedulePolling(interval);
374
423
  return;
375
424
  }
376
425
  _this4.cancelQRCodePolling();
377
- _this4.eventEmitter.emit('qRCodeLogin', {
426
+ _this4.eventEmitter.emit(Events.qRCodeLogin, {
378
427
  eventType: 'authorizationFailure',
379
428
  data: res.body
380
429
  });
381
430
  });
382
- }, interval * 1000);
431
+ };
432
+ var schedulePolling = function schedulePolling(interval) {
433
+ return _this4.pollingTimer = setTimeout(polling, interval * 1000);
434
+ };
435
+ schedulePolling(interval);
383
436
  },
384
437
  /**
385
438
  * cancel polling request
@@ -388,13 +441,17 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
388
441
  * @returns {void}
389
442
  */
390
443
  cancelQRCodePolling: function cancelQRCodePolling() {
391
- if (this.pollingRequest) {
392
- clearInterval(this.pollingRequest);
393
- this.eventEmitter.emit('qRCodeLogin', {
444
+ var withCancelEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
445
+ if (this.pollingTimer && withCancelEvent) {
446
+ this.eventEmitter.emit(Events.qRCodeLogin, {
394
447
  eventType: 'pollingCanceled'
395
448
  });
396
- this.pollingRequest = null;
397
449
  }
450
+ this.currentPollingId = null;
451
+ clearTimeout(this.pollingExpirationTimer);
452
+ this.pollingExpirationTimer = null;
453
+ clearTimeout(this.pollingTimer);
454
+ this.pollingTimer = null;
398
455
  },
399
456
  /**
400
457
  * Extracts the orgId from the returned code from idbroker
@@ -504,7 +561,7 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
504
561
  throw new Error("CSRF token ".concat(token, " does not match stored token ").concat(sessionToken));
505
562
  }
506
563
  },
507
- version: "3.6.0-next.4"
564
+ version: "3.6.0-next.6"
508
565
  }, ((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
566
  var _default = exports.default = Authorization;
510
567
  //# 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":"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"}
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","initQRCodeLogin","_this3","emit","eventType","data","message","service","resource","scope","_res$body","user_code","verification_uri","verification_uri_complete","userData","userCode","verificationUri","verificationUriComplete","_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","search","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 * 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 this.eventEmitter.emit(Events.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(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 = _interopRequireDefault(require("./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","_interopRequireDefault","_config","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} from './authorization';\nexport {default as config} from './config';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAIA,IAAAA,UAAA,GAAAC,OAAA;AAEA,IAAAC,cAAA,GAAAC,sBAAA,CAAAF,OAAA;AACA,IAAAG,OAAA,GAAAD,sBAAA,CAAAF,OAAA;AAPA;AACA;AACA;;AAOA,IAAMI,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"}
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
@@ -26,23 +26,23 @@
26
26
  "@webex/eslint-config-legacy": "0.0.0",
27
27
  "@webex/jest-config-legacy": "0.0.0",
28
28
  "@webex/legacy-tools": "0.0.0",
29
- "@webex/test-helper-chai": "3.6.0-next.3",
30
- "@webex/test-helper-mocha": "3.6.0-next.3",
31
- "@webex/test-helper-mock-webex": "3.6.0-next.3",
32
- "@webex/test-helper-test-users": "3.6.0-next.3",
29
+ "@webex/test-helper-chai": "3.6.0-next.4",
30
+ "@webex/test-helper-mocha": "3.6.0-next.4",
31
+ "@webex/test-helper-mock-webex": "3.6.0-next.4",
32
+ "@webex/test-helper-test-users": "3.6.0-next.4",
33
33
  "eslint": "^8.24.0",
34
34
  "prettier": "^2.7.1",
35
35
  "sinon": "^9.2.4"
36
36
  },
37
37
  "dependencies": {
38
- "@webex/common": "3.6.0-next.3",
39
- "@webex/storage-adapter-local-storage": "3.6.0-next.3",
40
- "@webex/test-helper-automation": "3.6.0-next.3",
41
- "@webex/test-helper-chai": "3.6.0-next.3",
42
- "@webex/test-helper-mocha": "3.6.0-next.3",
43
- "@webex/test-helper-mock-webex": "3.6.0-next.3",
44
- "@webex/test-helper-test-users": "3.6.0-next.3",
45
- "@webex/webex-core": "3.6.0-next.3",
38
+ "@webex/common": "3.6.0-next.4",
39
+ "@webex/storage-adapter-local-storage": "3.6.0-next.4",
40
+ "@webex/test-helper-automation": "3.6.0-next.4",
41
+ "@webex/test-helper-chai": "3.6.0-next.4",
42
+ "@webex/test-helper-mocha": "3.6.0-next.4",
43
+ "@webex/test-helper-mock-webex": "3.6.0-next.4",
44
+ "@webex/test-helper-test-users": "3.6.0-next.4",
45
+ "@webex/webex-core": "3.6.0-next.4",
46
46
  "crypto-js": "^4.1.1",
47
47
  "lodash": "^4.17.21",
48
48
  "uuid": "^3.3.2"
@@ -56,5 +56,5 @@
56
56
  "test:style": "eslint ./src/**/*.*",
57
57
  "test:unit": "webex-legacy-tools test --unit --runner jest"
58
58
  },
59
- "version": "3.6.0-next.4"
59
+ "version": "3.6.0-next.6"
60
60
  }
@@ -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 interval ID for QR code polling
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
- pollingRequest: null,
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
- eventEmitter: new EventEmitter(),
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
@@ -260,8 +302,8 @@ const Authorization = WebexPlugin.extend({
260
302
  * @emits #qRCodeLogin
261
303
  */
262
304
  initQRCodeLogin() {
263
- if (this.pollingRequest) {
264
- this.eventEmitter.emit('qRCodeLogin', {
305
+ if (this.pollingTimer) {
306
+ this.eventEmitter.emit(Events.qRCodeLogin, {
265
307
  eventType: 'getUserCodeFailure',
266
308
  data: {message: 'There is already a polling request'},
267
309
  });
@@ -285,19 +327,19 @@ const Authorization = WebexPlugin.extend({
285
327
  })
286
328
  .then((res) => {
287
329
  const {user_code, verification_uri, verification_uri_complete} = res.body;
288
- this.eventEmitter.emit('qRCodeLogin', {
330
+ this.eventEmitter.emit(Events.qRCodeLogin, {
289
331
  eventType: 'getUserCodeSuccess',
290
332
  userData: {
291
333
  userCode: user_code,
292
334
  verificationUri: verification_uri,
293
335
  verificationUriComplete: verification_uri_complete,
294
- }
336
+ },
295
337
  });
296
338
  // if device authorization success, then start to poll server to check whether the user has completed authorization
297
339
  this._startQRCodePolling(res.body);
298
340
  })
299
341
  .catch((res) => {
300
- this.eventEmitter.emit('qRCodeLogin', {
342
+ this.eventEmitter.emit(Events.qRCodeLogin, {
301
343
  eventType: 'getUserCodeFailure',
302
344
  data: res.body,
303
345
  });
@@ -313,30 +355,36 @@ const Authorization = WebexPlugin.extend({
313
355
  */
314
356
  _startQRCodePolling(options = {}) {
315
357
  if (!options.device_code) {
316
- this.eventEmitter.emit('qRCodeLogin', {
358
+ this.eventEmitter.emit(Events.qRCodeLogin, {
317
359
  eventType: 'authorizationFailure',
318
360
  data: {message: 'A deviceCode is required'},
319
361
  });
320
362
  return;
321
363
  }
322
364
 
323
- if (this.pollingRequest) {
324
- this.eventEmitter.emit('qRCodeLogin', {
365
+ if (this.pollingTimer) {
366
+ this.eventEmitter.emit(Events.qRCodeLogin, {
325
367
  eventType: 'authorizationFailure',
326
368
  data: {message: 'There is already a polling request'},
327
369
  });
328
370
  return;
329
371
  }
330
372
 
331
- const {device_code: deviceCode, interval = 2, expires_in: expiresIn = 300} = options;
373
+ const {device_code: deviceCode, expires_in: expiresIn = 300} = options;
374
+ let interval = options.interval ?? 2;
332
375
 
333
- let attempts = 0;
334
- const maxAttempts = expiresIn / interval;
376
+ this.pollingExpirationTimer = setTimeout(() => {
377
+ this.cancelQRCodePolling(false);
378
+ this.eventEmitter.emit(Events.qRCodeLogin, {
379
+ eventType: 'authorizationFailure',
380
+ data: {message: 'Authorization timed out'},
381
+ });
382
+ }, expiresIn * 1000);
335
383
 
336
- this.pollingRequest = setInterval(() => {
337
- attempts += 1;
384
+ const polling = () => {
385
+ this.pollingId += 1;
386
+ this.currentPollingId = this.pollingId;
338
387
 
339
- const currentAttempts = attempts;
340
388
  this.webex
341
389
  .request({
342
390
  method: 'POST',
@@ -354,43 +402,50 @@ const Authorization = WebexPlugin.extend({
354
402
  },
355
403
  })
356
404
  .then((res) => {
357
- if (this.pollingRequest === null) return;
405
+ // if the pollingId has changed, it means that the polling request has been canceled
406
+ if (this.currentPollingId !== this.pollingId) return;
358
407
 
359
- this.eventEmitter.emit('qRCodeLogin', {
408
+ this.eventEmitter.emit(Events.qRCodeLogin, {
360
409
  eventType: 'authorizationSuccess',
361
410
  data: res.body,
362
411
  });
363
412
  this.cancelQRCodePolling();
364
413
  })
365
414
  .catch((res) => {
366
- if (this.pollingRequest === null) return;
415
+ // if the pollingId has changed, it means that the polling request has been canceled
416
+ if (this.currentPollingId !== this.pollingId) return;
367
417
 
368
- if (currentAttempts >= maxAttempts) {
369
- this.eventEmitter.emit('qRCodeLogin', {
370
- eventType: 'authorizationFailure',
371
- data: {message: 'Authorization timed out'}
372
- });
373
- this.cancelQRCodePolling();
418
+ // When server sends 400 status code with message 'slow_down', it means that last request happened too soon.
419
+ // So, skip one interval and then poll again.
420
+ if (res.statusCode === 400 && res.body.message === 'slow_down') {
421
+ schedulePolling(interval * 2);
374
422
  return;
375
423
  }
424
+
376
425
  // if the statusCode is 428 which means that the authorization request is still pending
377
426
  // as the end user hasn't yet completed the user-interaction steps. So keep polling.
378
427
  if (res.statusCode === 428) {
379
- this.eventEmitter.emit('qRCodeLogin', {
428
+ this.eventEmitter.emit(Events.qRCodeLogin, {
380
429
  eventType: 'authorizationPending',
381
- data: res.body
430
+ data: res.body,
382
431
  });
432
+ schedulePolling(interval);
383
433
  return;
384
434
  }
385
435
 
386
436
  this.cancelQRCodePolling();
387
437
 
388
- this.eventEmitter.emit('qRCodeLogin', {
438
+ this.eventEmitter.emit(Events.qRCodeLogin, {
389
439
  eventType: 'authorizationFailure',
390
- data: res.body
440
+ data: res.body,
391
441
  });
392
442
  });
393
- }, interval * 1000);
443
+ };
444
+
445
+ const schedulePolling = (interval) =>
446
+ (this.pollingTimer = setTimeout(polling, interval * 1000));
447
+
448
+ schedulePolling(interval);
394
449
  },
395
450
 
396
451
  /**
@@ -399,14 +454,19 @@ const Authorization = WebexPlugin.extend({
399
454
  * @memberof AuthorizationBrowserFirstParty
400
455
  * @returns {void}
401
456
  */
402
- cancelQRCodePolling() {
403
- if (this.pollingRequest) {
404
- clearInterval(this.pollingRequest);
405
- this.eventEmitter.emit('qRCodeLogin', {
457
+ cancelQRCodePolling(withCancelEvent = true) {
458
+ if (this.pollingTimer && withCancelEvent) {
459
+ this.eventEmitter.emit(Events.qRCodeLogin, {
406
460
  eventType: 'pollingCanceled',
407
461
  });
408
- this.pollingRequest = null;
409
462
  }
463
+
464
+ this.currentPollingId = null;
465
+
466
+ clearTimeout(this.pollingExpirationTimer);
467
+ this.pollingExpirationTimer = null;
468
+ clearTimeout(this.pollingTimer);
469
+ this.pollingTimer = null;
410
470
  },
411
471
 
412
472
  /**
package/src/index.js CHANGED
@@ -14,5 +14,5 @@ registerPlugin('authorization', Authorization, {
14
14
  proxies,
15
15
  });
16
16
 
17
- export {default} from './authorization';
17
+ export {default, Events} from './authorization';
18
18
  export {default as config} from './config';
@@ -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.stub(Services.prototype, 'collectPreauthCatalog').resolves();
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('http://127.0.0.1:8000/?error=invalid_scope&error_description=The%20requested%20scope%20is%20invalid.');
275
- }
276
- catch (e) {
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
 
@@ -446,14 +446,14 @@ describe('plugin-authorization-browser-first-party', () => {
446
446
  describe('#initQRCodeLogin()', () => {
447
447
  it('should prevent concurrent request if there is already a polling request', async () => {
448
448
  const webex = makeWebex('http://example.com');
449
-
450
- webex.authorization.pollingRequest = 1;
449
+
450
+ webex.authorization.pollingTimer = 1;
451
451
  const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
452
452
  webex.authorization.initQRCodeLogin();
453
-
453
+
454
454
  assert.calledOnce(emitSpy);
455
- assert.equal(emitSpy.getCall(0).args[1].eventType, 'getUserCodeFailure');
456
- webex.authorization.pollingRequest = null;
455
+ assert.equal(emitSpy.getCall(0).args[1].eventType, 'getUserCodeFailure');
456
+ webex.authorization.pollingTimer = null;
457
457
  });
458
458
 
459
459
  it('should send correct request parameters to the API', async () => {
@@ -461,19 +461,19 @@ describe('plugin-authorization-browser-first-party', () => {
461
461
  const testClientId = 'test-client-id';
462
462
  const testScope = 'test-scope';
463
463
  const sampleData = {
464
- device_code: "test123",
464
+ device_code: 'test123',
465
465
  expires_in: 300,
466
- user_code: "421175",
467
- verification_uri: "http://example.com",
468
- verification_uri_complete: "http://example.com",
469
- interval: 2
466
+ user_code: '421175',
467
+ verification_uri: 'http://example.com',
468
+ verification_uri_complete: 'http://example.com',
469
+ interval: 2,
470
470
  };
471
471
 
472
472
  const webex = makeWebex('http://example.com', undefined, undefined, {
473
473
  credentials: {
474
474
  client_id: testClientId,
475
475
  scope: testScope,
476
- }
476
+ },
477
477
  });
478
478
  webex.request.onFirstCall().resolves({statusCode: 200, body: sampleData});
479
479
  sinon.spy(webex.authorization, '_startQRCodePolling');
@@ -481,11 +481,11 @@ describe('plugin-authorization-browser-first-party', () => {
481
481
 
482
482
  webex.authorization.initQRCodeLogin();
483
483
  clock.tick(2000);
484
- await clock.runAllAsync()
484
+ await clock.runAllAsync();
485
485
 
486
486
  assert.calledTwice(webex.request);
487
487
  assert.calledOnce(webex.authorization._startQRCodePolling);
488
- assert.equal(emitSpy.getCall(0).args[1].eventType, 'getUserCodeSuccess');
488
+ assert.equal(emitSpy.getCall(0).args[1].eventType, 'getUserCodeSuccess');
489
489
 
490
490
  const request = webex.request.getCall(0);
491
491
 
@@ -498,18 +498,18 @@ describe('plugin-authorization-browser-first-party', () => {
498
498
  const clock = sinon.useFakeTimers();
499
499
  const webex = makeWebex('http://example.com');
500
500
  const sampleData = {
501
- device_code: "test123",
501
+ device_code: 'test123',
502
502
  expires_in: 300,
503
- user_code: "421175",
504
- verification_uri: "http://example.com",
505
- verification_uri_complete: "http://example.com",
506
- interval: 2
503
+ user_code: '421175',
504
+ verification_uri: 'http://example.com',
505
+ verification_uri_complete: 'http://example.com',
506
+ interval: 2,
507
507
  };
508
508
  webex.request.resolves().resolves({statusCode: 200, body: sampleData});
509
509
 
510
510
  webex.authorization.initQRCodeLogin();
511
511
  clock.tick(2000);
512
- await clock.runAllAsync()
512
+ await clock.runAllAsync();
513
513
 
514
514
  const request = webex.request.getCall(0);
515
515
  assert.equal(request.args[0].method, 'POST');
@@ -517,7 +517,7 @@ describe('plugin-authorization-browser-first-party', () => {
517
517
  assert.equal(request.args[0].resource, '/actions/device/authorize');
518
518
  clock.restore();
519
519
  });
520
-
520
+
521
521
  it('should emit getUserCodeFailure event', async () => {
522
522
  const clock = sinon.useFakeTimers();
523
523
  const webex = makeWebex('http://example.com');
@@ -526,7 +526,7 @@ describe('plugin-authorization-browser-first-party', () => {
526
526
 
527
527
  webex.authorization.initQRCodeLogin();
528
528
 
529
- await clock.runAllAsync()
529
+ await clock.runAllAsync();
530
530
 
531
531
  assert.calledOnce(emitSpy);
532
532
  assert.equal(emitSpy.getCall(0).args[1].eventType, 'getUserCodeFailure');
@@ -537,15 +537,15 @@ describe('plugin-authorization-browser-first-party', () => {
537
537
  describe('#_startQRCodePolling()', () => {
538
538
  it('requires a deviceCode', () => {
539
539
  const webex = makeWebex('http://example.com');
540
-
540
+
541
541
  const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
542
542
 
543
543
  webex.authorization._startQRCodePolling({});
544
544
 
545
545
  assert.calledOnce(emitSpy);
546
- assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationFailure');
546
+ assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationFailure');
547
547
  });
548
-
548
+
549
549
  it('should send correct request parameters to the API', async () => {
550
550
  const clock = sinon.useFakeTimers();
551
551
  const testClientId = 'test-client-id';
@@ -560,7 +560,7 @@ describe('plugin-authorization-browser-first-party', () => {
560
560
  const webex = makeWebex('http://example.com', undefined, undefined, {
561
561
  credentials: {
562
562
  client_id: testClientId,
563
- }
563
+ },
564
564
  });
565
565
 
566
566
  webex.request.onFirstCall().resolves({statusCode: 200, body: {access_token: 'token'}});
@@ -569,7 +569,7 @@ describe('plugin-authorization-browser-first-party', () => {
569
569
 
570
570
  webex.authorization._startQRCodePolling(options);
571
571
  clock.tick(2000);
572
- await clock.runAllAsync()
572
+ await clock.runAllAsync();
573
573
 
574
574
  assert.calledOnce(webex.request);
575
575
 
@@ -577,7 +577,10 @@ describe('plugin-authorization-browser-first-party', () => {
577
577
 
578
578
  assert.equal(request.args[0].form.client_id, testClientId);
579
579
  assert.equal(request.args[0].form.device_code, testDeviceCode);
580
- assert.equal(request.args[0].form.grant_type, 'urn:ietf:params:oauth:grant-type:device_code');
580
+ assert.equal(
581
+ request.args[0].form.grant_type,
582
+ 'urn:ietf:params:oauth:grant-type:device_code'
583
+ );
581
584
 
582
585
  assert.calledOnce(webex.authorization.cancelQRCodePolling);
583
586
  assert.calledTwice(emitSpy);
@@ -593,23 +596,26 @@ describe('plugin-authorization-browser-first-party', () => {
593
596
  const options = {
594
597
  device_code: 'test-device-code',
595
598
  interval: 2,
596
- expires_in: 300
599
+ expires_in: 300,
597
600
  };
598
-
599
- webex.request.onFirstCall().rejects({statusCode: 428, body: {message: 'authorization_pending'}});
601
+
602
+ webex.request
603
+ .onFirstCall()
604
+ .rejects({statusCode: 428, body: {message: 'authorization_pending'}});
600
605
  webex.request.onSecondCall().resolves({statusCode: 200, body: {access_token: 'token'}});
601
606
  sinon.spy(webex.authorization, 'cancelQRCodePolling');
602
607
  const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
603
-
608
+
604
609
  webex.authorization._startQRCodePolling(options);
605
- clock.tick(4000);
606
- await clock.runAllAsync()
607
-
610
+ await clock.tickAsync(4000);
611
+ //await clock.runAllAsync()
612
+
608
613
  assert.calledTwice(webex.request);
609
614
  assert.calledOnce(webex.authorization.cancelQRCodePolling);
610
- assert.calledTwice(emitSpy);
611
- assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationSuccess');
612
- assert.equal(emitSpy.getCall(1).args[1].eventType, 'pollingCanceled');
615
+ assert.calledThrice(emitSpy);
616
+ assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationPending');
617
+ assert.equal(emitSpy.getCall(1).args[1].eventType, 'authorizationSuccess');
618
+ assert.equal(emitSpy.getCall(2).args[1].eventType, 'pollingCanceled');
613
619
  clock.restore();
614
620
  });
615
621
 
@@ -619,23 +625,21 @@ describe('plugin-authorization-browser-first-party', () => {
619
625
  const options = {
620
626
  device_code: 'test-device-code',
621
627
  interval: 5,
622
- expires_in: 10
628
+ expires_in: 9,
623
629
  };
624
-
630
+
625
631
  webex.request.rejects({statusCode: 428, body: {message: 'authorizationPending'}});
626
632
  sinon.spy(webex.authorization, 'cancelQRCodePolling');
627
633
  const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
628
634
 
629
635
  webex.authorization._startQRCodePolling(options);
630
- clock.tick(10000);
631
- await clock.runAllAsync()
632
-
633
- assert.calledTwice(webex.request);
636
+ await clock.tickAsync(10_000);
637
+
638
+ assert.calledOnce(webex.request);
634
639
  assert.calledOnce(webex.authorization.cancelQRCodePolling);
635
- assert.calledThrice(emitSpy);
636
- assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationPending');
640
+ assert.calledTwice(emitSpy);
641
+ assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationPending');
637
642
  assert.equal(emitSpy.getCall(1).args[1].eventType, 'authorizationFailure');
638
- assert.equal(emitSpy.getCall(2).args[1].eventType, 'pollingCanceled');
639
643
  clock.restore();
640
644
  });
641
645
 
@@ -644,54 +648,129 @@ describe('plugin-authorization-browser-first-party', () => {
644
648
  const options = {
645
649
  device_code: 'test-device-code',
646
650
  interval: 2,
647
- expires_in: 300
651
+ expires_in: 300,
648
652
  };
649
-
650
- webex.authorization.pollingRequest = 1;
653
+
654
+ webex.authorization.pollingTimer = 1;
651
655
 
652
656
  const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
653
657
  webex.authorization._startQRCodePolling(options);
654
658
 
655
659
  assert.calledOnce(emitSpy);
656
- assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationFailure');
657
- webex.authorization.pollingRequest = null;
660
+ assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationFailure');
661
+ webex.authorization.pollingTimer = null;
662
+ });
663
+
664
+ it('should skip a interval when server ask for slow_down', async () => {
665
+ const clock = sinon.useFakeTimers();
666
+ const webex = makeWebex('http://example.com');
667
+ const options = {
668
+ device_code: 'test-device-code',
669
+ interval: 2,
670
+ expires_in: 300,
671
+ };
672
+
673
+ webex.request.onFirstCall().rejects({statusCode: 400, body: {message: 'slow_down'}});
674
+ webex.request.onSecondCall().resolves({statusCode: 200, body: {access_token: 'token'}});
675
+ sinon.spy(webex.authorization, 'cancelQRCodePolling');
676
+ const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
677
+
678
+ webex.authorization._startQRCodePolling(options);
679
+ await clock.tickAsync(4000);
680
+
681
+ // Request only once because of slow_down
682
+ assert.calledOnce(webex.request);
683
+
684
+ // Wait for next interval
685
+ await clock.tickAsync(2000);
686
+
687
+ assert.calledTwice(webex.request);
688
+ assert.calledOnce(webex.authorization.cancelQRCodePolling);
689
+ assert.calledTwice(emitSpy);
690
+ assert.equal(emitSpy.getCall(0).args[1].eventType, 'authorizationSuccess');
691
+ assert.equal(emitSpy.getCall(1).args[1].eventType, 'pollingCanceled');
692
+ clock.restore();
693
+ });
694
+
695
+ it('should ignore the response from the previous polling', async () => {
696
+ const clock = sinon.useFakeTimers();
697
+ const webex = makeWebex('http://example.com');
698
+ const options = {
699
+ device_code: 'test-device-code',
700
+ interval: 2,
701
+ expires_in: 300,
702
+ };
703
+
704
+ webex.request.onFirstCall().callsFake(() => {
705
+ return new Promise((resolve) => {
706
+ setTimeout(() => {
707
+ resolve({statusCode: 200, body: {access_token: 'token'}});
708
+ }, 1000);
709
+ });
710
+ });
711
+
712
+ webex.request
713
+ .onSecondCall()
714
+ .rejects({statusCode: 428, body: {message: 'authorizationPending'}});
715
+ sinon.spy(webex.authorization, 'cancelQRCodePolling');
716
+ const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
717
+
718
+ webex.authorization._startQRCodePolling(options);
719
+ await clock.tickAsync(2500);
720
+
721
+ webex.authorization.cancelQRCodePolling();
722
+
723
+ // Start new polling
724
+
725
+ webex.authorization._startQRCodePolling(options);
726
+
727
+ // Wait for next interval
728
+ await clock.tickAsync(3000);
729
+
730
+ assert.calledTwice(webex.request);
731
+ assert.calledOnce(webex.authorization.cancelQRCodePolling);
732
+ assert.calledTwice(emitSpy);
733
+ // authorizationSuccess event should not be emitted
734
+ assert.equal(emitSpy.getCall(0).args[1].eventType, 'pollingCanceled');
735
+ assert.equal(emitSpy.getCall(1).args[1].eventType, 'authorizationPending');
736
+ clock.restore();
658
737
  });
659
738
  });
660
739
 
661
740
  describe('#cancelQRCodePolling()', () => {
662
741
  it('should stop polling after cancellation', async () => {
663
- const clock = sinon.useFakeTimers();
664
- const webex = makeWebex('http://example.com');
665
- const options = {
666
- device_code: 'test-device-code',
667
- interval: 2,
668
- expires_in: 300
669
- };
670
-
671
- webex.request.rejects({statusCode: 428, body: {message: 'authorizationPending'}});
672
- const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
673
-
674
- webex.authorization._startQRCodePolling(options);
675
- // First poll
676
- clock.tick(2000);
677
- assert.calledOnce(webex.request);
678
-
679
- webex.authorization.cancelQRCodePolling();
680
- // Wait for next interval
681
- clock.tick(2000);
682
-
683
- const eventArgs = emitSpy.getCall(0).args;
684
-
685
- // Verify no additional requests were made
686
- assert.calledOnce(webex.request);
687
- assert.calledOnce(emitSpy);
688
- assert.equal(eventArgs[1].eventType, 'pollingCanceled');
689
- clock.restore();
690
- });
742
+ const clock = sinon.useFakeTimers();
743
+ const webex = makeWebex('http://example.com');
744
+ const options = {
745
+ device_code: 'test-device-code',
746
+ interval: 2,
747
+ expires_in: 300,
748
+ };
749
+
750
+ webex.request.rejects({statusCode: 428, body: {message: 'authorizationPending'}});
751
+ const emitSpy = sinon.spy(webex.authorization.eventEmitter, 'emit');
752
+
753
+ webex.authorization._startQRCodePolling(options);
754
+ // First poll
755
+ clock.tick(2000);
756
+ assert.calledOnce(webex.request);
757
+
758
+ webex.authorization.cancelQRCodePolling();
759
+ // Wait for next interval
760
+ clock.tick(2000);
761
+
762
+ const eventArgs = emitSpy.getCall(0).args;
763
+
764
+ // Verify no additional requests were made
765
+ assert.calledOnce(webex.request);
766
+ assert.calledOnce(emitSpy);
767
+ assert.equal(eventArgs[1].eventType, 'pollingCanceled');
768
+ clock.restore();
769
+ });
691
770
  it('should clear interval and reset polling request', () => {
692
771
  const clock = sinon.useFakeTimers();
693
772
  const webex = makeWebex('http://example.com');
694
-
773
+
695
774
  const options = {
696
775
  device_code: 'test_device_code',
697
776
  interval: 2,
@@ -699,22 +778,21 @@ describe('plugin-authorization-browser-first-party', () => {
699
778
  };
700
779
 
701
780
  webex.authorization._startQRCodePolling(options);
702
- assert.isDefined(webex.authorization.pollingRequest);
703
-
781
+ assert.isDefined(webex.authorization.pollingTimer);
782
+
704
783
  webex.authorization.cancelQRCodePolling();
705
- assert.isNull(webex.authorization.pollingRequest);
706
-
784
+ assert.isNull(webex.authorization.pollingTimer);
785
+
707
786
  clock.restore();
708
787
  });
709
-
788
+
710
789
  it('should handle cancellation when no polling is in progress', () => {
711
790
  const webex = makeWebex('http://example.com');
712
- assert.isNull(webex.authorization.pollingRequest);
713
-
791
+ assert.isNull(webex.authorization.pollingTimer);
792
+
714
793
  webex.authorization.cancelQRCodePolling();
715
- assert.isNull(webex.authorization.pollingRequest);
794
+ assert.isNull(webex.authorization.pollingTimer);
716
795
  });
717
-
718
796
  });
719
797
 
720
798
  describe('#_generateCodeChallenge', () => {
@@ -836,7 +914,7 @@ describe('plugin-authorization-browser-first-party', () => {
836
914
  const orgId = webex.authorization._extractOrgIdFromCode(code);
837
915
 
838
916
  assert.isUndefined(orgId);
839
- })
917
+ });
840
918
  });
841
919
  });
842
920
  });