@webex/webex-core 3.0.0-beta.4 → 3.0.0-beta.400

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.
Files changed (188) hide show
  1. package/dist/config.js +1 -11
  2. package/dist/config.js.map +1 -1
  3. package/dist/credentials-config.js +44 -64
  4. package/dist/credentials-config.js.map +1 -1
  5. package/dist/index.js +0 -76
  6. package/dist/index.js.map +1 -1
  7. package/dist/interceptors/auth.js +22 -55
  8. package/dist/interceptors/auth.js.map +1 -1
  9. package/dist/interceptors/default-options.js +0 -20
  10. package/dist/interceptors/default-options.js.map +1 -1
  11. package/dist/interceptors/embargo.js +0 -21
  12. package/dist/interceptors/embargo.js.map +1 -1
  13. package/dist/interceptors/network-timing.js +2 -21
  14. package/dist/interceptors/network-timing.js.map +1 -1
  15. package/dist/interceptors/payload-transformer.js +2 -22
  16. package/dist/interceptors/payload-transformer.js.map +1 -1
  17. package/dist/interceptors/rate-limit.js +25 -57
  18. package/dist/interceptors/rate-limit.js.map +1 -1
  19. package/dist/interceptors/redirect.js +4 -33
  20. package/dist/interceptors/redirect.js.map +1 -1
  21. package/dist/interceptors/request-event.js +3 -30
  22. package/dist/interceptors/request-event.js.map +1 -1
  23. package/dist/interceptors/request-logger.js +1 -30
  24. package/dist/interceptors/request-logger.js.map +1 -1
  25. package/dist/interceptors/request-timing.js +3 -22
  26. package/dist/interceptors/request-timing.js.map +1 -1
  27. package/dist/interceptors/response-logger.js +2 -31
  28. package/dist/interceptors/response-logger.js.map +1 -1
  29. package/dist/interceptors/user-agent.js +2 -29
  30. package/dist/interceptors/user-agent.js.map +1 -1
  31. package/dist/interceptors/webex-tracking-id.js +5 -28
  32. package/dist/interceptors/webex-tracking-id.js.map +1 -1
  33. package/dist/interceptors/webex-user-agent.js +5 -38
  34. package/dist/interceptors/webex-user-agent.js.map +1 -1
  35. package/dist/lib/batcher.js +3 -51
  36. package/dist/lib/batcher.js.map +1 -1
  37. package/dist/lib/constants.js +14 -0
  38. package/dist/lib/constants.js.map +1 -0
  39. package/dist/lib/credentials/credentials.js +98 -139
  40. package/dist/lib/credentials/credentials.js.map +1 -1
  41. package/dist/lib/credentials/grant-errors.js +0 -49
  42. package/dist/lib/credentials/grant-errors.js.map +1 -1
  43. package/dist/lib/credentials/index.js +1 -13
  44. package/dist/lib/credentials/index.js.map +1 -1
  45. package/dist/lib/credentials/scope.js +25 -14
  46. package/dist/lib/credentials/scope.js.map +1 -1
  47. package/dist/lib/credentials/token-collection.js +1 -7
  48. package/dist/lib/credentials/token-collection.js.map +1 -1
  49. package/dist/lib/credentials/token.js +42 -118
  50. package/dist/lib/credentials/token.js.map +1 -1
  51. package/dist/lib/page.js +13 -26
  52. package/dist/lib/page.js.map +1 -1
  53. package/dist/lib/services/constants.js +0 -2
  54. package/dist/lib/services/constants.js.map +1 -1
  55. package/dist/lib/services/index.js +1 -28
  56. package/dist/lib/services/index.js.map +1 -1
  57. package/dist/lib/services/interceptors/server-error.js +2 -23
  58. package/dist/lib/services/interceptors/server-error.js.map +1 -1
  59. package/dist/lib/services/interceptors/service.js +15 -35
  60. package/dist/lib/services/interceptors/service.js.map +1 -1
  61. package/dist/lib/services/metrics.js +0 -2
  62. package/dist/lib/services/metrics.js.map +1 -1
  63. package/dist/lib/services/service-catalog.js +12 -91
  64. package/dist/lib/services/service-catalog.js.map +1 -1
  65. package/dist/lib/services/service-fed-ramp.js +0 -2
  66. package/dist/lib/services/service-fed-ramp.js.map +1 -1
  67. package/dist/lib/services/service-host.js +47 -62
  68. package/dist/lib/services/service-host.js.map +1 -1
  69. package/dist/lib/services/service-registry.js +78 -90
  70. package/dist/lib/services/service-registry.js.map +1 -1
  71. package/dist/lib/services/service-state.js +3 -15
  72. package/dist/lib/services/service-state.js.map +1 -1
  73. package/dist/lib/services/service-url.js +4 -25
  74. package/dist/lib/services/service-url.js.map +1 -1
  75. package/dist/lib/services/services.js +135 -239
  76. package/dist/lib/services/services.js.map +1 -1
  77. package/dist/lib/stateless-webex-plugin.js +5 -28
  78. package/dist/lib/stateless-webex-plugin.js.map +1 -1
  79. package/dist/lib/storage/decorators.js +19 -62
  80. package/dist/lib/storage/decorators.js.map +1 -1
  81. package/dist/lib/storage/errors.js +0 -23
  82. package/dist/lib/storage/errors.js.map +1 -1
  83. package/dist/lib/storage/index.js +2 -16
  84. package/dist/lib/storage/index.js.map +1 -1
  85. package/dist/lib/storage/make-webex-plugin-store.js +11 -41
  86. package/dist/lib/storage/make-webex-plugin-store.js.map +1 -1
  87. package/dist/lib/storage/make-webex-store.js +8 -30
  88. package/dist/lib/storage/make-webex-store.js.map +1 -1
  89. package/dist/lib/storage/memory-store-adapter.js +1 -19
  90. package/dist/lib/storage/memory-store-adapter.js.map +1 -1
  91. package/dist/lib/webex-core-plugin-mixin.js +9 -29
  92. package/dist/lib/webex-core-plugin-mixin.js.map +1 -1
  93. package/dist/lib/webex-http-error.js +1 -31
  94. package/dist/lib/webex-http-error.js.map +1 -1
  95. package/dist/lib/webex-internal-core-plugin-mixin.js +9 -29
  96. package/dist/lib/webex-internal-core-plugin-mixin.js.map +1 -1
  97. package/dist/lib/webex-plugin.js +6 -40
  98. package/dist/lib/webex-plugin.js.map +1 -1
  99. package/dist/plugins/logger.js +3 -17
  100. package/dist/plugins/logger.js.map +1 -1
  101. package/dist/webex-core.js +84 -203
  102. package/dist/webex-core.js.map +1 -1
  103. package/dist/webex-internal-core.js +0 -10
  104. package/dist/webex-internal-core.js.map +1 -1
  105. package/package.json +14 -14
  106. package/src/config.js +9 -11
  107. package/src/credentials-config.js +110 -72
  108. package/src/index.js +4 -14
  109. package/src/interceptors/auth.js +36 -37
  110. package/src/interceptors/default-options.js +0 -1
  111. package/src/interceptors/embargo.js +1 -1
  112. package/src/interceptors/payload-transformer.js +1 -2
  113. package/src/interceptors/rate-limit.js +8 -5
  114. package/src/interceptors/redirect.js +14 -8
  115. package/src/interceptors/request-event.js +4 -8
  116. package/src/interceptors/request-logger.js +8 -5
  117. package/src/interceptors/response-logger.js +11 -8
  118. package/src/interceptors/user-agent.js +1 -2
  119. package/src/interceptors/webex-user-agent.js +3 -9
  120. package/src/lib/batcher.js +70 -69
  121. package/src/lib/constants.js +6 -0
  122. package/src/lib/credentials/credentials.js +173 -141
  123. package/src/lib/credentials/grant-errors.js +6 -7
  124. package/src/lib/credentials/index.js +1 -4
  125. package/src/lib/credentials/scope.js +24 -8
  126. package/src/lib/credentials/token-collection.js +1 -1
  127. package/src/lib/credentials/token.js +95 -81
  128. package/src/lib/page.js +10 -11
  129. package/src/lib/services/constants.js +3 -13
  130. package/src/lib/services/index.js +2 -2
  131. package/src/lib/services/interceptors/server-error.js +12 -7
  132. package/src/lib/services/interceptors/service.js +7 -6
  133. package/src/lib/services/metrics.js +1 -1
  134. package/src/lib/services/service-catalog.js +112 -100
  135. package/src/lib/services/service-fed-ramp.js +1 -2
  136. package/src/lib/services/service-host.js +10 -17
  137. package/src/lib/services/service-registry.js +69 -96
  138. package/src/lib/services/service-state.js +4 -6
  139. package/src/lib/services/service-url.js +24 -23
  140. package/src/lib/services/services.js +272 -249
  141. package/src/lib/stateless-webex-plugin.js +4 -2
  142. package/src/lib/storage/decorators.js +68 -66
  143. package/src/lib/storage/index.js +4 -6
  144. package/src/lib/storage/make-webex-plugin-store.js +34 -21
  145. package/src/lib/storage/make-webex-store.js +6 -7
  146. package/src/lib/storage/memory-store-adapter.js +3 -3
  147. package/src/lib/webex-core-plugin-mixin.js +10 -7
  148. package/src/lib/webex-http-error.js +7 -8
  149. package/src/lib/webex-internal-core-plugin-mixin.js +9 -6
  150. package/src/lib/webex-plugin.js +41 -34
  151. package/src/plugins/logger.js +8 -3
  152. package/src/webex-core.js +198 -117
  153. package/src/webex-internal-core.js +15 -9
  154. package/test/integration/spec/credentials/credentials.js +26 -30
  155. package/test/integration/spec/credentials/token.js +36 -33
  156. package/test/integration/spec/services/service-catalog.js +177 -156
  157. package/test/integration/spec/services/services.js +313 -304
  158. package/test/integration/spec/webex-core.js +98 -86
  159. package/test/unit/spec/_setup.js +26 -18
  160. package/test/unit/spec/credentials/credentials.js +352 -162
  161. package/test/unit/spec/credentials/scope.js +80 -0
  162. package/test/unit/spec/credentials/token.js +105 -77
  163. package/test/unit/spec/interceptors/auth.js +294 -243
  164. package/test/unit/spec/interceptors/default-options.js +36 -24
  165. package/test/unit/spec/interceptors/embargo.js +32 -27
  166. package/test/unit/spec/interceptors/network-timing.js +2 -2
  167. package/test/unit/spec/interceptors/payload-transformer.js +61 -52
  168. package/test/unit/spec/interceptors/rate-limit.js +104 -75
  169. package/test/unit/spec/interceptors/redirect.js +22 -20
  170. package/test/unit/spec/interceptors/request-timing.js +18 -22
  171. package/test/unit/spec/interceptors/user-agent.js +28 -16
  172. package/test/unit/spec/interceptors/webex-tracking-id.js +14 -8
  173. package/test/unit/spec/interceptors/webex-user-agent.js +83 -37
  174. package/test/unit/spec/lib/batcher.js +36 -32
  175. package/test/unit/spec/lib/page.js +36 -32
  176. package/test/unit/spec/lib/webex-plugin.js +1 -1
  177. package/test/unit/spec/services/interceptors/server-error.js +67 -90
  178. package/test/unit/spec/services/interceptors/service.js +23 -28
  179. package/test/unit/spec/services/service-catalog.js +19 -27
  180. package/test/unit/spec/services/service-host.js +29 -26
  181. package/test/unit/spec/services/service-registry.js +128 -170
  182. package/test/unit/spec/services/service-state.js +13 -22
  183. package/test/unit/spec/services/service-url.js +24 -43
  184. package/test/unit/spec/services/services.js +147 -41
  185. package/test/unit/spec/storage/persist.js +6 -9
  186. package/test/unit/spec/storage/wait-for-value.js +22 -21
  187. package/test/unit/spec/webex-core.js +90 -57
  188. package/test/unit/spec/webex-internal-core.js +56 -31
@@ -11,6 +11,7 @@ import {inBrowser} from '@webex/common';
11
11
  import FakeTimers from '@sinonjs/fake-timers';
12
12
  import {skipInBrowser} from '@webex/test-helper-mocha';
13
13
  import Logger from '@webex/plugin-logger';
14
+ import Metrics, {config} from '@webex/internal-plugin-metrics';
14
15
 
15
16
  /* eslint camelcase: [0] */
16
17
 
@@ -28,7 +29,8 @@ function promiseTick(count) {
28
29
  return promise;
29
30
  }
30
31
 
31
- const AUTHORIZATION_STRING = 'https://api.ciscospark.com/v1/authorize?client_id=MOCK_CLIENT_ID&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8000&scope=spark%3Arooms_read%20spark%3Ateams_read&state=set_state_here';
32
+ const AUTHORIZATION_STRING =
33
+ 'https://api.ciscospark.com/v1/authorize?client_id=MOCK_CLIENT_ID&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8000&scope=spark%3Arooms_read%20spark%3Ateams_read&state=set_state_here';
32
34
 
33
35
  describe('webex-core', () => {
34
36
  describe('Credentials', () => {
@@ -58,6 +60,34 @@ describe('webex-core', () => {
58
60
  });
59
61
  });
60
62
 
63
+ describe('#isUnverifiedGuest', () => {
64
+ let credentials;
65
+ let webex;
66
+ beforeEach('generate the webex instance', () => {
67
+ webex = new MockWebex();
68
+ credentials = new Credentials(undefined, {parent: webex});
69
+ });
70
+
71
+ it('should have #isUnverifiedGuest', () => {
72
+ assert.exists(credentials.isUnverifiedGuest);
73
+ });
74
+
75
+ it('should get the user status and return as a boolean', () => {
76
+ credentials.set('supertoken', 'AT');
77
+ assert.isFalse(credentials.isUnverifiedGuest);
78
+ });
79
+
80
+ it('should get guest user ', () => {
81
+ credentials.set('supertoken', 'eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyX3R5cGUiOiJndWVzdCJ9');
82
+ assert.isTrue(credentials.isUnverifiedGuest);
83
+ });
84
+
85
+ it('should get login user ', () => {
86
+ credentials.set('supertoken', 'dGhpc2lzbm90YXJlYWx1c2VydG9rZW4=');
87
+ assert.isFalse(credentials.isUnverifiedGuest);
88
+ });
89
+ });
90
+
61
91
  describe('#canAuthorize', () => {
62
92
  it('indicates if the current state has enough information to populate an auth header, even if a token refresh or token downscope is required', () => {
63
93
  const webex = new MockWebex();
@@ -69,7 +99,7 @@ describe('webex-core', () => {
69
99
  assert.isFalse(credentials.canAuthorize);
70
100
 
71
101
  credentials.supertoken = makeToken(webex, {
72
- access_token: 'AT'
102
+ access_token: 'AT',
73
103
  });
74
104
  assert.isTrue(credentials.canAuthorize);
75
105
 
@@ -77,13 +107,13 @@ describe('webex-core', () => {
77
107
  assert.isFalse(credentials.canAuthorize);
78
108
 
79
109
  credentials.supertoken = makeToken(webex, {
80
- access_token: 'AT'
110
+ access_token: 'AT',
81
111
  });
82
112
  assert.isTrue(credentials.canAuthorize);
83
113
 
84
114
  credentials.supertoken = makeToken(webex, {
85
115
  access_token: 'AT',
86
- expires: Date.now() - 10000
116
+ expires: Date.now() - 10000,
87
117
  });
88
118
  assert.isFalse(credentials.supertoken.canAuthorize);
89
119
  assert.isFalse(credentials.canRefresh);
@@ -95,7 +125,7 @@ describe('webex-core', () => {
95
125
  assert.isFalse(credentials.canAuthorize);
96
126
  credentials.supertoken = makeToken(webex, {
97
127
  access_token: 'AT',
98
- refresh_token: 'RT'
128
+ refresh_token: 'RT',
99
129
  });
100
130
  credentials.supertoken.unset('access_token');
101
131
  assert.isTrue(credentials.canAuthorize);
@@ -109,9 +139,13 @@ describe('webex-core', () => {
109
139
 
110
140
  webex.trigger('change:config');
111
141
  assert.isFalse(credentials.canRefresh);
112
- credentials.supertoken = makeToken(webex, {
113
- access_token: 'AT'
114
- }, {parent: true});
142
+ credentials.supertoken = makeToken(
143
+ webex,
144
+ {
145
+ access_token: 'AT',
146
+ },
147
+ {parent: true}
148
+ );
115
149
  assert.isFalse(credentials.canRefresh);
116
150
 
117
151
  webex.config.credentials.refreshCallback = inBrowser && noop;
@@ -120,7 +154,7 @@ describe('webex-core', () => {
120
154
  assert.isFalse(credentials.canRefresh);
121
155
  credentials.supertoken = makeToken(webex, {
122
156
  access_token: 'AT',
123
- refresh_token: 'RT'
157
+ refresh_token: 'RT',
124
158
  });
125
159
  assert.isTrue(credentials.supertoken.canRefresh);
126
160
  assert.isTrue(credentials.canRefresh);
@@ -131,8 +165,8 @@ describe('webex-core', () => {
131
165
  it('requires `state` to be an object', () => {
132
166
  const webex = new MockWebex({
133
167
  children: {
134
- credentials: Credentials
135
- }
168
+ credentials: Credentials,
169
+ },
136
170
  });
137
171
 
138
172
  webex.trigger('change:config)');
@@ -161,7 +195,7 @@ describe('webex-core', () => {
161
195
 
162
196
  assert.match(credentials.buildLoginUrl({state: {}}), /idbroker/);
163
197
  webex.config.credentials = {
164
- authorizationString: AUTHORIZATION_STRING
198
+ authorizationString: AUTHORIZATION_STRING,
165
199
  };
166
200
  credentials = new Credentials({}, {parent: webex});
167
201
  webex.trigger('change:config');
@@ -174,7 +208,12 @@ describe('webex-core', () => {
174
208
 
175
209
  webex.trigger('change:config');
176
210
 
177
- assert.equal(credentials.buildLoginUrl({state: {page: 'front'}}), `${process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'}/idb/oauth2/v1/authorize?state=eyJwYWdlIjoiZnJvbnQifQ&client_id=fake&redirect_uri=http%3A%2F%2Fexample.com&scope=scope%3Aone&response_type=code`);
211
+ assert.equal(
212
+ credentials.buildLoginUrl({state: {page: 'front'}}),
213
+ `${
214
+ process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'
215
+ }/idb/oauth2/v1/authorize?state=eyJwYWdlIjoiZnJvbnQifQ&client_id=fake&redirect_uri=http%3A%2F%2Fexample.com&scope=scope%3Aone&response_type=code`
216
+ );
178
217
  });
179
218
 
180
219
  skipInBrowser(it)('generates the login url with empty state param', () => {
@@ -183,11 +222,15 @@ describe('webex-core', () => {
183
222
 
184
223
  webex.trigger('change:config');
185
224
 
186
- assert.equal(credentials.buildLoginUrl({state: {}}), `${process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'}/idb/oauth2/v1/authorize?client_id=fake&redirect_uri=http%3A%2F%2Fexample.com&scope=scope%3Aone&response_type=code`);
225
+ assert.equal(
226
+ credentials.buildLoginUrl({state: {}}),
227
+ `${
228
+ process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'
229
+ }/idb/oauth2/v1/authorize?client_id=fake&redirect_uri=http%3A%2F%2Fexample.com&scope=scope%3Aone&response_type=code`
230
+ );
187
231
  });
188
232
  });
189
233
 
190
-
191
234
  describe('#buildLogoutUrl()', () => {
192
235
  skipInBrowser(it)('generates the logout url', () => {
193
236
  const webex = new MockWebex();
@@ -196,7 +239,12 @@ describe('webex-core', () => {
196
239
  const credentials = new Credentials(undefined, {parent: webex});
197
240
 
198
241
  webex.trigger('change:config');
199
- assert.equal(credentials.buildLogoutUrl(), `${process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'}/idb/oauth2/v1/logout?cisService=webex&goto=ru`);
242
+ assert.equal(
243
+ credentials.buildLogoutUrl(),
244
+ `${
245
+ process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'
246
+ }/idb/oauth2/v1/logout?cisService=webex&goto=ru`
247
+ );
200
248
  });
201
249
 
202
250
  skipInBrowser(it)('includes a token param if passed', () => {
@@ -206,7 +254,12 @@ describe('webex-core', () => {
206
254
  const credentials = new Credentials(undefined, {parent: webex});
207
255
 
208
256
  webex.trigger('change:config');
209
- assert.equal(credentials.buildLogoutUrl({token: 't'}), `${process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'}/idb/oauth2/v1/logout?cisService=webex&goto=ru&token=t`);
257
+ assert.equal(
258
+ credentials.buildLogoutUrl({token: 't'}),
259
+ `${
260
+ process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'
261
+ }/idb/oauth2/v1/logout?cisService=webex&goto=ru&token=t`
262
+ );
210
263
  });
211
264
 
212
265
  it('always fallsback to idbroker', () => {
@@ -224,7 +277,10 @@ describe('webex-core', () => {
224
277
  const credentials = new Credentials(undefined, {parent: webex});
225
278
 
226
279
  webex.trigger('change:config');
227
- assert.match(credentials.buildLogoutUrl({goto: 'http://example.com/'}), /goto=http%3A%2F%2Fexample.com%2F/);
280
+ assert.match(
281
+ credentials.buildLogoutUrl({goto: 'http://example.com/'}),
282
+ /goto=http%3A%2F%2Fexample.com%2F/
283
+ );
228
284
  });
229
285
  });
230
286
 
@@ -240,7 +296,8 @@ describe('webex-core', () => {
240
296
 
241
297
  it('should return the OrgId of JWT-authenticated user', () => {
242
298
  credentials.supertoken = {
243
- access_token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyZWFsbSI6Im15LXJlYWxtIn0.U16gzUsaRW1VVikJA2VeXRHPX716tG1_B42oxzy1UMk'
299
+ access_token:
300
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyZWFsbSI6Im15LXJlYWxtIn0.U16gzUsaRW1VVikJA2VeXRHPX716tG1_B42oxzy1UMk',
244
301
  };
245
302
 
246
303
  orgId = 'my-realm';
@@ -252,17 +309,14 @@ describe('webex-core', () => {
252
309
  orgId = 'this-is-an-org-id';
253
310
 
254
311
  credentials.supertoken = {
255
- access_token: `000_000_${orgId}`
312
+ access_token: `000_000_${orgId}`,
256
313
  };
257
314
 
258
315
  assert.equal(credentials.getOrgId(), orgId);
259
316
  });
260
317
 
261
318
  it('should throw if the OrgId was not determined', () =>
262
- assert.throws(
263
- () => credentials.getOrgId(),
264
- 'the provided token is not a valid format'
265
- ));
319
+ assert.throws(() => credentials.getOrgId(), 'the provided token is not a valid format'));
266
320
  });
267
321
 
268
322
  describe('#extractOrgIdFromJWT()', () => {
@@ -275,7 +329,8 @@ describe('webex-core', () => {
275
329
  });
276
330
 
277
331
  it('should return the OrgId of a provided JWT', () => {
278
- const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyZWFsbSI6Im15LXJlYWxtIn0.U16gzUsaRW1VVikJA2VeXRHPX716tG1_B42oxzy1UMk';
332
+ const jwt =
333
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyZWFsbSI6Im15LXJlYWxtIn0.U16gzUsaRW1VVikJA2VeXRHPX716tG1_B42oxzy1UMk';
279
334
  const realm = 'my-realm';
280
335
 
281
336
  assert.equal(credentials.extractOrgIdFromJWT(jwt), realm);
@@ -285,7 +340,8 @@ describe('webex-core', () => {
285
340
  assert.throws(() => credentials.extractOrgIdFromJWT('not-valid')));
286
341
 
287
342
  it('should throw if the provided JWT does not contain an OrgId', () => {
288
- const jwtNoOrg = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
343
+ const jwtNoOrg =
344
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
289
345
 
290
346
  assert.throws(() => credentials.extractOrgIdFromJWT(jwtNoOrg));
291
347
  });
@@ -324,7 +380,7 @@ describe('webex-core', () => {
324
380
  webex.config.credentials = {
325
381
  client_id: 'ci',
326
382
  redirect_uri: 'ru',
327
- scope: 's'
383
+ scope: 's',
328
384
  };
329
385
 
330
386
  let credentials = new Credentials(undefined, {parent: webex});
@@ -358,16 +414,26 @@ describe('webex-core', () => {
358
414
  'data.supertoken.access_token',
359
415
  'data.authorization',
360
416
  'data.authorization.supertoken',
361
- 'data.authorization.supertoken.access_token'
362
- ].reduce((acc, path) => acc.concat(['ST', 'Bearer ST'].map((str) => {
363
- const obj = {
364
- msg: `accepts token string "${str}" at path "${path.split('.').slice(1).join('.')}"`
365
- };
366
-
367
- set(obj, path, str);
368
-
369
- return obj;
370
- })), [])
417
+ 'data.authorization.supertoken.access_token',
418
+ ]
419
+ .reduce(
420
+ (acc, path) =>
421
+ acc.concat(
422
+ ['ST', 'Bearer ST'].map((str) => {
423
+ const obj = {
424
+ msg: `accepts token string "${str}" at path "${path
425
+ .split('.')
426
+ .slice(1)
427
+ .join('.')}"`,
428
+ };
429
+
430
+ set(obj, path, str);
431
+
432
+ return obj;
433
+ })
434
+ ),
435
+ []
436
+ )
371
437
  .forEach(({msg, data}) => {
372
438
  it(msg, () => {
373
439
  const webex = new MockWebex();
@@ -380,19 +446,24 @@ describe('webex-core', () => {
380
446
  });
381
447
 
382
448
  it('schedules a refreshTimer', () => {
383
- const webex = new MockWebex();
449
+ const webex = new MockWebex({
450
+ children: {
451
+ metrics: Metrics,
452
+ },
453
+ });
384
454
  const supertoken = makeToken(webex, {
385
455
  access_token: 'ST',
386
456
  refresh_token: 'RT',
387
- expires: Date.now() + 10000
457
+ expires: Date.now() + 10000,
388
458
  });
389
459
  const supertoken2 = makeToken(webex, {
390
460
  access_token: 'ST2',
391
461
  refresh_token: 'RT2',
392
- expires: Date.now() + 20000
462
+ expires: Date.now() + 20000,
393
463
  });
394
464
 
395
465
  sinon.stub(supertoken, 'refresh').returns(Promise.resolve(supertoken2));
466
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
396
467
  const credentials = new Credentials(supertoken, {parent: webex});
397
468
 
398
469
  webex.trigger('change:config');
@@ -414,7 +485,7 @@ describe('webex-core', () => {
414
485
  const supertoken = makeToken(webex, {
415
486
  access_token: 'ST',
416
487
  refresh_token: 'RT',
417
- expires: Date.now() - 10000
488
+ expires: Date.now() - 10000,
418
489
  });
419
490
 
420
491
  sinon.stub(supertoken, 'refresh').returns(Promise.reject());
@@ -427,7 +498,19 @@ describe('webex-core', () => {
427
498
  });
428
499
 
429
500
  describe('#getUserToken()', () => {
430
- it('resolves with the supertoken if the supertoken matches the requested scopes');
501
+ it('resolves with the supertoken if the supertoken matches the requested scopes', () => {
502
+ const webex = new MockWebex();
503
+ const credentials = new Credentials(undefined, {parent: webex});
504
+
505
+ webex.trigger('change:config');
506
+ const st = makeToken(webex, {access_token: 'ST', scope: 'scope1'});
507
+
508
+ credentials.set({
509
+ supertoken: st,
510
+ });
511
+
512
+ return credentials.getUserToken('scope1').then((result) => assert.deepEqual(result, st));
513
+ });
431
514
 
432
515
  it('resolves with the token identified by the specified scopes', () => {
433
516
  const webex = new MockWebex();
@@ -437,28 +520,43 @@ describe('webex-core', () => {
437
520
  const st = makeToken(webex, {access_token: 'ST'});
438
521
  const t1 = makeToken(webex, {
439
522
  access_token: 'AT1',
440
- scope: 'scope1'
523
+ scope: 'scope1',
441
524
  });
442
525
  const t2 = makeToken(webex, {
443
526
  access_token: 'AT2',
444
- scope: 'scope2'
527
+ scope: 'scope2',
445
528
  });
446
529
 
447
530
  credentials.set({
448
531
  supertoken: st,
449
- userTokens: [
450
- t1, t2
451
- ]
532
+ userTokens: [t1, t2],
452
533
  });
453
534
 
454
535
  return Promise.all([
455
- credentials.getUserToken('scope1')
456
- .then((result) => assert.deepEqual(result, t1)),
457
- credentials.getUserToken('scope2')
458
- .then((result) => assert.deepEqual(result, t2))
536
+ credentials.getUserToken('scope1').then((result) => assert.deepEqual(result, t1)),
537
+ credentials.getUserToken('scope2').then((result) => assert.deepEqual(result, t2)),
459
538
  ]);
460
539
  });
461
540
 
541
+ it('uses the supertoken.scope instead of the config.scope for downscope', () => {
542
+ const webex = new MockWebex();
543
+ const credentials = new Credentials(undefined, {parent: webex});
544
+
545
+ webex.trigger('change:config');
546
+ const st = makeToken(webex, {access_token: 'ST', scope: 'scope1 spark:kms'});
547
+
548
+ credentials.set({
549
+ supertoken: st,
550
+ scope: 'invalidScope scope1',
551
+ });
552
+
553
+ sinon.stub(credentials, 'downscope').returns(Promise.resolve());
554
+
555
+ return credentials.getUserToken().then(() => {
556
+ assert.calledWith(credentials.downscope, 'scope1');
557
+ });
558
+ });
559
+
462
560
  describe('when no matching token is found', () => {
463
561
  it('downscopes the supertoken', () => {
464
562
  const webex = new MockWebex();
@@ -467,42 +565,42 @@ describe('webex-core', () => {
467
565
  webex.trigger('change:config');
468
566
 
469
567
  credentials.supertoken = makeToken(webex, {
470
- access_token: 'ST'
568
+ access_token: 'ST',
471
569
  });
472
570
 
473
571
  const t2 = makeToken(webex, {
474
- access_token: 'AT2'
572
+ access_token: 'AT2',
475
573
  });
476
574
 
477
575
  sinon.stub(credentials.supertoken, 'downscope').returns(Promise.resolve(t2));
478
576
 
479
577
  const t1 = makeToken(webex, {
480
578
  access_token: 'AT1',
481
- scope: 'scope1'
579
+ scope: 'scope1',
482
580
  });
483
581
 
484
582
  credentials.set({
485
- userTokens: [t1]
583
+ userTokens: [t1],
486
584
  });
487
585
 
488
- return credentials.getUserToken('scope2')
586
+ return credentials
587
+ .getUserToken('scope2')
489
588
  .then((result) => assert.deepEqual(result, t2))
490
589
  .then(() => assert.calledWith(credentials.supertoken.downscope, 'scope2'));
491
590
  });
492
591
  });
493
592
 
494
-
495
593
  describe('when no scope is specified', () => {
496
594
  it('resolves with a token containing all but the kms scopes', () => {
497
595
  const webex = new MockWebex();
498
596
 
499
- webex.config.credentials.scope = 'scope1 spark:kms';
500
597
  const credentials = new Credentials(undefined, {parent: webex});
501
598
 
502
599
  webex.trigger('change:config');
503
600
 
504
601
  credentials.supertoken = makeToken(webex, {
505
- access_token: 'ST'
602
+ access_token: 'ST',
603
+ scope: 'scope1 spark:kms',
506
604
  });
507
605
 
508
606
  // const t2 = makeToken(webex, {
@@ -513,15 +611,14 @@ describe('webex-core', () => {
513
611
 
514
612
  const t1 = makeToken(webex, {
515
613
  access_token: 'AT1',
516
- scope: 'scope1'
614
+ scope: 'scope1',
517
615
  });
518
616
 
519
617
  credentials.set({
520
- userTokens: [t1]
618
+ userTokens: [t1],
521
619
  });
522
620
 
523
- return credentials.getUserToken()
524
- .then((result) => assert.deepEqual(result, t1));
621
+ return credentials.getUserToken().then((result) => assert.deepEqual(result, t1));
525
622
  });
526
623
  });
527
624
 
@@ -529,37 +626,57 @@ describe('webex-core', () => {
529
626
  it('falls back to the supertoken', () => {
530
627
  const webex = new MockWebex({
531
628
  children: {
532
- logger: Logger
533
- }
629
+ logger: Logger,
630
+ metrics: Metrics,
631
+ },
534
632
  });
535
633
 
634
+ webex.config.metrics = config.metrics;
536
635
  webex.config.credentials.scope = 'scope1 spark:kms';
537
636
  const credentials = new Credentials(undefined, {parent: webex});
538
637
 
539
638
  webex.trigger('change:config');
540
639
 
541
640
  credentials.supertoken = makeToken(webex, {
542
- access_token: 'ST'
641
+ access_token: 'ST',
543
642
  });
544
643
 
545
- sinon.stub(credentials.supertoken, 'downscope').returns(Promise.reject(new Error('downscope failed')));
644
+ const failReason = 'downscope failed';
645
+ sinon.stub(credentials.supertoken, 'downscope').returns(Promise.reject(failReason));
646
+
647
+ sinon.stub(credentials.logger, 'warn').callsFake(() => {});
648
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
546
649
 
547
650
  const t1 = makeToken(webex, {
548
651
  access_token: 'AT1',
549
- scope: 'scope1'
652
+ scope: 'scope1',
550
653
  });
551
654
 
552
655
  credentials.set({
553
- userTokens: [t1]
656
+ userTokens: [t1],
554
657
  });
555
658
 
556
- return credentials.getUserToken('scope2')
557
- .then((t) => assert.equal(t.access_token, credentials.supertoken.access_token));
659
+ return credentials.getUserToken('scope2').then((t) => {
660
+ assert.equal(t.access_token, credentials.supertoken.access_token);
661
+ assert.calledWith(
662
+ credentials.logger.warn,
663
+ 'credentials: failed to downscope supertoken to "scope2"'
664
+ );
665
+ assert.calledWith(
666
+ webex.internal.metrics.submitClientMetrics,
667
+ 'JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED',
668
+ {fields: {failReason, requestedScope: 'scope2'}}
669
+ );
670
+ });
558
671
  });
559
672
  });
560
673
 
561
674
  it('is blocked while a token refresh is inflight', () => {
562
- const webex = new MockWebex();
675
+ const webex = new MockWebex({
676
+ children: {
677
+ metrics: Metrics,
678
+ },
679
+ });
563
680
 
564
681
  webex.config.credentials.scope = 'scope1 spark:kms';
565
682
  const credentials = new Credentials(undefined, {parent: webex});
@@ -568,14 +685,16 @@ describe('webex-core', () => {
568
685
 
569
686
  const supertoken1 = makeToken(webex, {
570
687
  access_token: 'ST1',
571
- refresh_token: 'RT1'
688
+ refresh_token: 'RT1',
572
689
  });
573
690
 
574
691
  credentials.set({supertoken: supertoken1});
575
692
 
576
- sinon.stub(supertoken1, 'downscope').returns(Promise.resolve(new Token({access_token: 'ST1ATD'})));
693
+ sinon
694
+ .stub(supertoken1, 'downscope')
695
+ .returns(Promise.resolve(new Token({access_token: 'ST1ATD'})));
577
696
  const supertoken2 = makeToken(webex, {
578
- access_token: 'ST2'
697
+ access_token: 'ST2',
579
698
  });
580
699
 
581
700
  sinon.stub(supertoken1, 'refresh').returns(Promise.resolve(supertoken2));
@@ -583,11 +702,11 @@ describe('webex-core', () => {
583
702
  const at2 = makeToken(webex, {access_token: 'ST2ATD'});
584
703
 
585
704
  sinon.stub(supertoken2, 'downscope').returns(Promise.resolve(at2));
705
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
586
706
 
587
707
  return Promise.all([
588
708
  credentials.refresh(),
589
- credentials.getUserToken('scope2')
590
- .then((result) => assert.deepEqual(result, at2))
709
+ credentials.getUserToken('scope2').then((result) => assert.deepEqual(result, at2)),
591
710
  ]);
592
711
  });
593
712
  });
@@ -600,16 +719,16 @@ describe('webex-core', () => {
600
719
  webex.trigger('change:config');
601
720
  const st = makeToken(webex, {
602
721
  access_token: 'ST',
603
- refresh_token: 'RT'
722
+ refresh_token: 'RT',
604
723
  });
605
724
 
606
725
  const st2 = makeToken(webex, {
607
726
  access_token: 'ST2',
608
- refresh_token: 'RT2'
727
+ refresh_token: 'RT2',
609
728
  });
610
729
 
611
730
  credentials.set({
612
- supertoken: st
731
+ supertoken: st,
613
732
  });
614
733
 
615
734
  sinon.stub(credentials, 'refresh').returns(Promise.resolve(st2));
@@ -618,12 +737,11 @@ describe('webex-core', () => {
618
737
  assert.isDefined(credentials.refreshTimer);
619
738
  assert.notCalled(credentials.refresh);
620
739
 
621
- return credentials.invalidate()
622
- .then(() => {
623
- clock.tick(10000);
624
- assert.isUndefined(credentials.refreshTimer);
625
- assert.notCalled(credentials.refresh);
626
- });
740
+ return credentials.invalidate().then(() => {
741
+ clock.tick(10000);
742
+ assert.isUndefined(credentials.refreshTimer);
743
+ assert.notCalled(credentials.refresh);
744
+ });
627
745
  });
628
746
 
629
747
  it('clears the tokens from boundedStorage', () => {
@@ -632,25 +750,22 @@ describe('webex-core', () => {
632
750
 
633
751
  webex.trigger('change:config');
634
752
  const st = makeToken(webex, {
635
- access_token: 'ST'
753
+ access_token: 'ST',
636
754
  });
637
755
 
638
756
  const t1 = makeToken(webex, {
639
757
  access_token: 'AT1',
640
- scope: 'scope1'
758
+ scope: 'scope1',
641
759
  });
642
760
 
643
761
  const t2 = makeToken(webex, {
644
762
  access_token: 'AT2',
645
- scope: 'scope2'
763
+ scope: 'scope2',
646
764
  });
647
765
 
648
766
  credentials.set({
649
767
  supertoken: st,
650
- userTokens: [
651
- t1,
652
- t2
653
- ]
768
+ userTokens: [t1, t2],
654
769
  });
655
770
 
656
771
  return new Promise((resolve) => {
@@ -665,19 +780,24 @@ describe('webex-core', () => {
665
780
  return credentials.invalidate();
666
781
  })
667
782
  .then(() => promiseTick(500))
668
- .then(() => new Promise((resolve) => {
669
- setTimeout(resolve, 1);
670
- clock.tick(1000);
671
- }))
783
+ .then(
784
+ () =>
785
+ new Promise((resolve) => {
786
+ setTimeout(resolve, 1);
787
+ clock.tick(1000);
788
+ })
789
+ )
672
790
  .then(() => promiseTick(500))
673
- .then(() => new Promise((resolve) => {
674
- setTimeout(resolve, 1);
675
- clock.tick(1000);
676
- }))
791
+ .then(
792
+ () =>
793
+ new Promise((resolve) => {
794
+ setTimeout(resolve, 1);
795
+ clock.tick(1000);
796
+ })
797
+ )
677
798
  .then(() => assert.isRejected(webex.boundedStorage.get('Credentials', '@'), /NotFound/));
678
799
  });
679
800
 
680
-
681
801
  it('does not induce any token refreshes');
682
802
 
683
803
  it('prevents #getUserToken() from being invoked', () => {
@@ -687,67 +807,77 @@ describe('webex-core', () => {
687
807
  webex.trigger('change:config');
688
808
  const st = makeToken(webex, {
689
809
  access_token: 'ST',
690
- refresh_token: 'RT'
810
+ refresh_token: 'RT',
691
811
  });
692
812
 
693
813
  const t1 = makeToken(webex, {
694
814
  access_token: 'AT1',
695
- scope: 'scope1'
815
+ scope: 'scope1',
696
816
  });
697
817
 
698
818
  credentials.set({
699
819
  supertoken: st,
700
- userTokens: [
701
- t1
702
- ]
820
+ userTokens: [t1],
703
821
  });
704
822
 
705
- return credentials.invalidate()
706
- .then(() => assert.isRejected(credentials.getUserToken(), /Current state cannot produce an access token/));
823
+ return credentials
824
+ .invalidate()
825
+ .then(() =>
826
+ assert.isRejected(
827
+ credentials.getUserToken(),
828
+ /Current state cannot produce an access token/
829
+ )
830
+ );
707
831
  });
708
832
  });
709
833
 
710
834
  describe('#refresh()', () => {
711
835
  it('refreshes and downscopes the supertoken, and revokes previous tokens', () => {
712
- const webex = new MockWebex();
836
+ const webex = new MockWebex({
837
+ children: {
838
+ metrics: Metrics,
839
+ },
840
+ });
713
841
  const credentials = new Credentials(undefined, {parent: webex});
714
842
 
715
843
  webex.trigger('change:config');
716
844
  const st = makeToken(webex, {
717
845
  access_token: 'ST',
718
- refresh_token: 'RT'
846
+ refresh_token: 'RT',
847
+ scope: 'scope1 scope2',
719
848
  });
720
849
 
721
850
  const st2 = makeToken(webex, {
722
851
  access_token: 'ST2',
723
- refresh_token: 'RT2'
852
+ refresh_token: 'RT2',
853
+ scope: 'scope1 scope2',
724
854
  });
725
855
 
726
856
  const t1 = makeToken(webex, {
727
857
  access_token: 'AT1',
728
- scope: 'scope1'
858
+ scope: 'scope1',
729
859
  });
730
860
 
731
861
  const t2 = makeToken(webex, {
732
862
  access_token: 'AT2',
733
- scope: 'scope2'
863
+ scope: 'scope2',
734
864
  });
735
865
 
736
866
  sinon.stub(st2, 'downscope').returns(Promise.resolve(t2));
737
867
  sinon.stub(st, 'refresh').returns(Promise.resolve(st2));
738
868
  sinon.stub(t1, 'revoke').returns(Promise.resolve());
739
869
  sinon.spy(credentials, 'scheduleRefresh');
870
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
740
871
 
741
872
  credentials.set({
742
873
  supertoken: st,
743
- userTokens: [
744
- t1
745
- ]
874
+ userTokens: [t1],
746
875
  });
747
876
 
748
877
  assert.equal(credentials.userTokens.get(t1.scope), t1);
749
878
 
750
- return credentials.refresh()
879
+ return credentials
880
+ .refresh()
751
881
  .then(() => assert.called(st.refresh))
752
882
  .then(() => assert.calledWith(st2.downscope, 'scope1'))
753
883
  .then(() => assert.called(t1.revoke))
@@ -757,45 +887,50 @@ describe('webex-core', () => {
757
887
  });
758
888
 
759
889
  it('refreshes and downscopes the supertoken even if revocation of previous token fails', () => {
760
- const webex = new MockWebex();
890
+ const webex = new MockWebex({
891
+ children: {
892
+ metrics: Metrics,
893
+ },
894
+ });
761
895
  const credentials = new Credentials(undefined, {parent: webex});
762
896
 
763
897
  webex.trigger('change:config');
764
898
  const st = makeToken(webex, {
765
899
  access_token: 'ST',
766
- refresh_token: 'RT'
900
+ refresh_token: 'RT',
767
901
  });
768
902
 
769
903
  const st2 = makeToken(webex, {
770
904
  access_token: 'ST2',
771
- refresh_token: 'RT2'
905
+ refresh_token: 'RT2',
906
+ scope: 'scope1 scope2',
772
907
  });
773
908
 
774
909
  const t1 = makeToken(webex, {
775
910
  access_token: 'AT1',
776
- scope: 'scope1'
911
+ scope: 'scope1',
777
912
  });
778
913
 
779
914
  const t2 = makeToken(webex, {
780
915
  access_token: 'AT2',
781
- scope: 'scope2'
916
+ scope: 'scope2',
782
917
  });
783
918
 
784
919
  sinon.stub(st2, 'downscope').returns(Promise.resolve(t2));
785
920
  sinon.stub(st, 'refresh').returns(Promise.resolve(st2));
786
921
  sinon.stub(t1, 'revoke').returns(Promise.reject());
787
922
  sinon.spy(credentials, 'scheduleRefresh');
923
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
788
924
 
789
925
  credentials.set({
790
926
  supertoken: st,
791
- userTokens: [
792
- t1
793
- ]
927
+ userTokens: [t1],
794
928
  });
795
929
 
796
930
  assert.equal(credentials.userTokens.get(t1.scope), t1);
797
931
 
798
- return credentials.refresh()
932
+ return credentials
933
+ .refresh()
799
934
  .then(() => assert.called(st.refresh))
800
935
  .then(() => assert.calledWith(st2.downscope, 'scope1'))
801
936
  .then(() => assert.called(t1.revoke))
@@ -807,74 +942,72 @@ describe('webex-core', () => {
807
942
  it('removes and revokes all child tokens', () => {
808
943
  const webex = new MockWebex({
809
944
  children: {
810
- logger: Logger
811
- }
945
+ logger: Logger,
946
+ metrics: Metrics,
947
+ },
812
948
  });
813
949
  const credentials = new Credentials(undefined, {parent: webex});
814
950
 
815
951
  webex.trigger('change:config');
816
952
  const st = makeToken(webex, {
817
953
  access_token: 'ST',
818
- refresh_token: 'RT'
954
+ refresh_token: 'RT',
955
+ scope: '',
819
956
  });
820
957
 
821
958
  sinon.stub(st, 'refresh').returns(Promise.resolve(makeToken(webex, {access_token: 'ST2'})));
959
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
822
960
 
823
961
  const t1 = makeToken(webex, {
824
962
  access_token: 'AT1',
825
- scope: 'scope1'
963
+ scope: 'scope1',
826
964
  });
827
965
 
828
966
  credentials.set({
829
967
  supertoken: st,
830
- userTokens: [
831
- t1
832
- ]
968
+ userTokens: [t1],
833
969
  });
834
970
 
835
- return credentials.refresh()
836
- .then(() => assert.called(st.refresh));
971
+ return credentials.refresh().then(() => assert.called(st.refresh));
837
972
  });
838
973
 
839
974
  it('allows #getUserToken() to be revoked, but #getUserToken() promises will not resolve until the suport token has been refreshed', () => {
840
- const webex = new MockWebex();
975
+ const webex = new MockWebex({children: {metrics: Metrics}});
841
976
  const credentials = new Credentials(undefined, {parent: webex});
842
977
 
843
978
  webex.trigger('change:config');
844
979
  const st1 = makeToken(webex, {
845
980
  access_token: 'ST1',
846
- refresh_token: 'RT1'
981
+ refresh_token: 'RT1',
847
982
  });
848
983
 
849
984
  const st2 = makeToken(webex, {
850
985
  access_token: 'ST2',
851
- refresh_token: 'RT1'
986
+ refresh_token: 'RT1',
852
987
  });
853
988
 
854
989
  const t1 = makeToken(webex, {
855
990
  access_token: 'AT1',
856
- scope: 'scope1'
991
+ scope: 'scope1',
857
992
  });
858
993
 
859
994
  const t2 = makeToken(webex, {
860
995
  access_token: 'AT2',
861
- scope: 'scope1'
996
+ scope: 'scope1',
862
997
  });
863
998
 
864
999
  sinon.stub(st1, 'refresh').returns(Promise.resolve(st2));
865
1000
  sinon.stub(st2, 'downscope').returns(Promise.resolve(t2));
1001
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
866
1002
 
867
1003
  credentials.set({
868
1004
  supertoken: st1,
869
- userTokens: [
870
- t1
871
- ]
1005
+ userTokens: [t1],
872
1006
  });
873
1007
 
874
1008
  credentials.refresh();
875
1009
 
876
- return credentials.getUserToken('scope1')
877
- .then((result) => assert.deepEqual(result, t2));
1010
+ return credentials.getUserToken('scope1').then((result) => assert.deepEqual(result, t2));
878
1011
  });
879
1012
 
880
1013
  it('emits InvalidRequestError when the refresh token and access token expire', () => {
@@ -884,42 +1017,99 @@ describe('webex-core', () => {
884
1017
  webex.trigger('change:config');
885
1018
  const st = makeToken(webex, {
886
1019
  access_token: 'ST',
887
- refresh_token: 'RT'
1020
+ refresh_token: 'RT',
888
1021
  });
889
1022
 
890
1023
  const t1 = makeToken(webex, {
891
1024
  access_token: 'AT1',
892
- scope: 'scope1'
1025
+ scope: 'scope1',
893
1026
  });
894
1027
 
895
1028
  const res = {
896
1029
  body: {
897
1030
  error: 'invalid_request',
898
- error_description: 'The refresh token provided is expired, revoked, malformed, or invalid.',
899
- trackingID: 'test123'
900
- }
1031
+ error_description:
1032
+ 'The refresh token provided is expired, revoked, malformed, or invalid.',
1033
+ trackingID: 'test123',
1034
+ },
901
1035
  };
902
1036
 
903
1037
  const ErrorConstructor = grantErrors.select(res.body.error);
904
1038
 
905
- sinon.stub(st, 'refresh').returns(Promise.reject(new ErrorConstructor('InvalidRequestError')));
1039
+ sinon
1040
+ .stub(st, 'refresh')
1041
+ .returns(Promise.reject(new ErrorConstructor('InvalidRequestError')));
906
1042
  sinon.stub(credentials, 'unset').returns(Promise.resolve());
907
1043
  const triggerSpy = sinon.spy(webex, 'trigger');
908
1044
 
909
1045
  credentials.set({
910
1046
  supertoken: st,
911
- userTokens: [
912
- t1
913
- ]
1047
+ userTokens: [t1],
914
1048
  });
915
1049
 
916
- return credentials.refresh()
1050
+ return credentials
1051
+ .refresh()
917
1052
  .then(() => assert.called(st.refresh))
918
1053
  .catch(() => {
919
1054
  assert.called(credentials.unset);
920
1055
  assert.calledWith(triggerSpy, sinon.match('client:InvalidRequestError'));
921
1056
  });
922
1057
  });
1058
+
1059
+ it('exclude invalid scopes from user token, log and call metrics when fetched supertoken scope mismatch with the configured scope', () => {
1060
+ const webex = new MockWebex({
1061
+ children: {
1062
+ logger: Logger,
1063
+ metrics: Metrics,
1064
+ },
1065
+ });
1066
+ const credentials = new Credentials(undefined, {parent: webex});
1067
+
1068
+ webex.trigger('change:config');
1069
+ const st = makeToken(webex, {
1070
+ access_token: 'ST',
1071
+ refresh_token: 'RT',
1072
+ });
1073
+
1074
+ const st2 = makeToken(webex, {
1075
+ access_token: 'ST2',
1076
+ refresh_token: 'RT2',
1077
+ scope: 'scope1',
1078
+ });
1079
+
1080
+ const userToken = makeToken(webex, {
1081
+ access_token: 'AT1',
1082
+ scope: 'scope1 invalidScope1',
1083
+ });
1084
+
1085
+ credentials.set({
1086
+ supertoken: st,
1087
+ userTokens: [userToken],
1088
+ });
1089
+ const invalidScopes = 'invalidScope1 invalidScope2';
1090
+ credentials.config.scope = `scope1 ${invalidScopes}`;
1091
+
1092
+ sinon.stub(st2, 'downscope').returns(Promise.resolve());
1093
+ sinon.stub(st, 'refresh').returns(Promise.resolve(st2));
1094
+ sinon.spy(credentials, 'downscope');
1095
+ sinon.spy(credentials, 'scheduleRefresh');
1096
+
1097
+ sinon.stub(credentials.logger, 'warn').callsFake(() => {});
1098
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
1099
+
1100
+ return credentials.refresh().then(() => {
1101
+ assert.calledWith(
1102
+ credentials.logger.warn,
1103
+ `credentials: "${invalidScopes}" scope(s) are invalid because not listed in the supertoken, they will be excluded from user token requests.`
1104
+ );
1105
+ assert.calledWith(
1106
+ webex.internal.metrics.submitClientMetrics,
1107
+ 'JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH',
1108
+ {fields: {invalidScopes}}
1109
+ );
1110
+ assert.calledWith(credentials.downscope, 'scope1');
1111
+ });
1112
+ });
923
1113
  });
924
1114
 
925
1115
  describe('#scheduleRefresh()', () => {
@@ -930,16 +1120,16 @@ describe('webex-core', () => {
930
1120
  webex.trigger('change:config');
931
1121
  const st = makeToken(webex, {
932
1122
  access_token: 'ST',
933
- refresh_token: 'RT'
1123
+ refresh_token: 'RT',
934
1124
  });
935
1125
 
936
1126
  const st2 = makeToken(webex, {
937
1127
  access_token: 'ST2',
938
- refresh_token: 'RT2'
1128
+ refresh_token: 'RT2',
939
1129
  });
940
1130
 
941
1131
  credentials.set({
942
- supertoken: st
1132
+ supertoken: st,
943
1133
  });
944
1134
 
945
1135
  sinon.stub(credentials, 'refresh').returns(Promise.resolve(st2));
@@ -956,16 +1146,16 @@ describe('webex-core', () => {
956
1146
  webex.trigger('change:config');
957
1147
  const st = makeToken(webex, {
958
1148
  access_token: 'ST',
959
- refresh_token: 'RT'
1149
+ refresh_token: 'RT',
960
1150
  });
961
1151
 
962
1152
  const st2 = makeToken(webex, {
963
1153
  access_token: 'ST2',
964
- refresh_token: 'RT2'
1154
+ refresh_token: 'RT2',
965
1155
  });
966
1156
 
967
1157
  credentials.set({
968
- supertoken: st
1158
+ supertoken: st,
969
1159
  });
970
1160
 
971
1161
  sinon.stub(credentials, 'refresh').returns(Promise.resolve(st2));