@webex/internal-plugin-encryption 3.0.0-beta.8 → 3.0.0-bnr.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -3
- package/dist/config.js +0 -9
- package/dist/config.js.map +1 -1
- package/dist/encryption.js +9 -60
- package/dist/encryption.js.map +1 -1
- package/dist/ensure-buffer.browser.js +0 -12
- package/dist/ensure-buffer.browser.js.map +1 -1
- package/dist/ensure-buffer.js +5 -12
- package/dist/ensure-buffer.js.map +1 -1
- package/dist/index.js +7 -33
- package/dist/index.js.map +1 -1
- package/dist/kms-batcher.js +6 -30
- package/dist/kms-batcher.js.map +1 -1
- package/dist/kms-certificate-validation.js +20 -88
- package/dist/kms-certificate-validation.js.map +1 -1
- package/dist/kms-dry-error-interceptor.js +1 -23
- package/dist/kms-dry-error-interceptor.js.map +1 -1
- package/dist/kms-errors.js +3 -50
- package/dist/kms-errors.js.map +1 -1
- package/dist/kms.js +74 -213
- package/dist/kms.js.map +1 -1
- package/dist/types/config.d.ts +16 -0
- package/dist/types/encryption.d.ts +2 -0
- package/dist/types/ensure-buffer.browser.d.ts +10 -0
- package/dist/types/ensure-buffer.d.ts +7 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/kms-batcher.d.ts +6 -0
- package/dist/types/kms-certificate-validation.d.ts +24 -0
- package/dist/types/kms-dry-error-interceptor.d.ts +25 -0
- package/dist/types/kms-errors.d.ts +33 -0
- package/dist/types/kms.d.ts +5 -0
- package/package.json +15 -15
- package/src/config.js +3 -3
- package/src/encryption.js +66 -56
- package/src/ensure-buffer.browser.js +0 -1
- package/src/ensure-buffer.js +5 -5
- package/src/index.js +120 -96
- package/src/kms-batcher.js +50 -44
- package/src/kms-certificate-validation.js +45 -47
- package/src/kms-dry-error-interceptor.js +8 -4
- package/src/kms-errors.js +19 -16
- package/src/kms.js +210 -206
- package/test/integration/spec/encryption.js +311 -230
- package/test/integration/spec/kms.js +532 -404
- package/test/integration/spec/payload-transfom.js +69 -69
- package/test/unit/spec/encryption.js +16 -13
- package/test/unit/spec/kms-certificate-validation.js +41 -32
package/src/kms.js
CHANGED
|
@@ -29,7 +29,7 @@ const KMS = WebexPlugin.extend({
|
|
|
29
29
|
namespace: 'Encryption',
|
|
30
30
|
|
|
31
31
|
children: {
|
|
32
|
-
batcher: KMSBatcher
|
|
32
|
+
batcher: KMSBatcher,
|
|
33
33
|
},
|
|
34
34
|
|
|
35
35
|
/**
|
|
@@ -41,9 +41,7 @@ const KMS = WebexPlugin.extend({
|
|
|
41
41
|
* @param {string} options.keyUri
|
|
42
42
|
* @returns {Promise<Key>}
|
|
43
43
|
*/
|
|
44
|
-
bindKey({
|
|
45
|
-
kro, kroUri, key, keyUri
|
|
46
|
-
}) {
|
|
44
|
+
bindKey({kro, kroUri, key, keyUri}) {
|
|
47
45
|
kroUri = kroUri || kro.uri;
|
|
48
46
|
keyUri = keyUri || key.uri;
|
|
49
47
|
|
|
@@ -62,13 +60,12 @@ const KMS = WebexPlugin.extend({
|
|
|
62
60
|
return this.request({
|
|
63
61
|
method: 'update',
|
|
64
62
|
resourceUri: kroUri,
|
|
65
|
-
uri: keyUri
|
|
66
|
-
})
|
|
67
|
-
.
|
|
68
|
-
this.logger.info('kms: bound key to resource');
|
|
63
|
+
uri: keyUri,
|
|
64
|
+
}).then((res) => {
|
|
65
|
+
this.logger.info('kms: bound key to resource');
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
return res.key;
|
|
68
|
+
});
|
|
72
69
|
},
|
|
73
70
|
|
|
74
71
|
/**
|
|
@@ -80,9 +77,7 @@ const KMS = WebexPlugin.extend({
|
|
|
80
77
|
* @param {Array<Keys>} options.keys
|
|
81
78
|
* @returns {Promise<KMSResourceObject>}
|
|
82
79
|
*/
|
|
83
|
-
createResource({
|
|
84
|
-
userIds, keyUris, key, keys
|
|
85
|
-
}) {
|
|
80
|
+
createResource({userIds, keyUris, key, keys}) {
|
|
86
81
|
keyUris = keyUris || [];
|
|
87
82
|
/* istanbul ignore if */
|
|
88
83
|
if (keys) {
|
|
@@ -109,13 +104,12 @@ const KMS = WebexPlugin.extend({
|
|
|
109
104
|
method: 'create',
|
|
110
105
|
uri: '/resources',
|
|
111
106
|
userIds,
|
|
112
|
-
keyUris
|
|
113
|
-
})
|
|
114
|
-
.
|
|
115
|
-
this.logger.info('kms: created resource');
|
|
107
|
+
keyUris,
|
|
108
|
+
}).then((res) => {
|
|
109
|
+
this.logger.info('kms: created resource');
|
|
116
110
|
|
|
117
|
-
|
|
118
|
-
|
|
111
|
+
return res.resource;
|
|
112
|
+
});
|
|
119
113
|
},
|
|
120
114
|
|
|
121
115
|
/**
|
|
@@ -127,9 +121,7 @@ const KMS = WebexPlugin.extend({
|
|
|
127
121
|
* @param {string} options.kroUri
|
|
128
122
|
* @returns {Promise<KMSAuthorizationObject>}
|
|
129
123
|
*/
|
|
130
|
-
addAuthorization({
|
|
131
|
-
userIds, authIds, kro, kroUri
|
|
132
|
-
}) {
|
|
124
|
+
addAuthorization({userIds, authIds, kro, kroUri}) {
|
|
133
125
|
userIds = userIds || [];
|
|
134
126
|
kroUri = kroUri || kro.uri;
|
|
135
127
|
|
|
@@ -153,13 +145,12 @@ const KMS = WebexPlugin.extend({
|
|
|
153
145
|
method: 'create',
|
|
154
146
|
uri: '/authorizations',
|
|
155
147
|
resourceUri: kroUri,
|
|
156
|
-
userIds
|
|
157
|
-
})
|
|
158
|
-
.
|
|
159
|
-
this.logger.info('kms: added authorization');
|
|
148
|
+
userIds,
|
|
149
|
+
}).then((res) => {
|
|
150
|
+
this.logger.info('kms: added authorization');
|
|
160
151
|
|
|
161
|
-
|
|
162
|
-
|
|
152
|
+
return res.authorizations;
|
|
153
|
+
});
|
|
163
154
|
},
|
|
164
155
|
|
|
165
156
|
/**
|
|
@@ -178,13 +169,12 @@ const KMS = WebexPlugin.extend({
|
|
|
178
169
|
|
|
179
170
|
return this.request({
|
|
180
171
|
method: 'retrieve',
|
|
181
|
-
uri: `${kroUri}/authorizations
|
|
182
|
-
})
|
|
183
|
-
.
|
|
184
|
-
this.logger.info('kms: retrieved authorization list');
|
|
172
|
+
uri: `${kroUri}/authorizations`,
|
|
173
|
+
}).then((res) => {
|
|
174
|
+
this.logger.info('kms: retrieved authorization list');
|
|
185
175
|
|
|
186
|
-
|
|
187
|
-
|
|
176
|
+
return res.authorizations;
|
|
177
|
+
});
|
|
188
178
|
},
|
|
189
179
|
|
|
190
180
|
/**
|
|
@@ -196,9 +186,7 @@ const KMS = WebexPlugin.extend({
|
|
|
196
186
|
* @param {string} options.kroUri
|
|
197
187
|
* @returns {Promise<KMSAuthorizationObject>}
|
|
198
188
|
*/
|
|
199
|
-
removeAuthorization({
|
|
200
|
-
authId, userId, kro, kroUri
|
|
201
|
-
}) {
|
|
189
|
+
removeAuthorization({authId, userId, kro, kroUri}) {
|
|
202
190
|
authId = authId || userId;
|
|
203
191
|
kroUri = kroUri || kro.uri;
|
|
204
192
|
|
|
@@ -216,13 +204,12 @@ const KMS = WebexPlugin.extend({
|
|
|
216
204
|
|
|
217
205
|
return this.request({
|
|
218
206
|
method: 'delete',
|
|
219
|
-
uri: `${kroUri}/authorizations?${querystring.stringify({authId})}
|
|
220
|
-
})
|
|
221
|
-
.
|
|
222
|
-
this.logger.info('kms: removed authorization');
|
|
207
|
+
uri: `${kroUri}/authorizations?${querystring.stringify({authId})}`,
|
|
208
|
+
}).then((res) => {
|
|
209
|
+
this.logger.info('kms: removed authorization');
|
|
223
210
|
|
|
224
|
-
|
|
225
|
-
|
|
211
|
+
return res.authorizations;
|
|
212
|
+
});
|
|
226
213
|
},
|
|
227
214
|
|
|
228
215
|
/**
|
|
@@ -242,21 +229,20 @@ const KMS = WebexPlugin.extend({
|
|
|
242
229
|
return this.request({
|
|
243
230
|
method: 'create',
|
|
244
231
|
uri: '/keys',
|
|
245
|
-
count
|
|
246
|
-
})
|
|
247
|
-
.
|
|
248
|
-
this.logger.info('kms: received unbound keys');
|
|
232
|
+
count,
|
|
233
|
+
}).then((res) => {
|
|
234
|
+
this.logger.info('kms: received unbound keys');
|
|
249
235
|
|
|
250
|
-
|
|
251
|
-
|
|
236
|
+
return Promise.all(res.keys.map(this.asKey));
|
|
237
|
+
});
|
|
252
238
|
},
|
|
253
239
|
|
|
254
240
|
/**
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
241
|
+
* @typedef {Object} FetchPublicKeyResponse
|
|
242
|
+
* @property {number} status 200,400(Bad Request: Request payload missing info),404(Not Found: HSM Public Key not found),501(Not Implemented: This KMS does not support BYOK),502(Bad Gateway: KMS could not communicate with HSM)
|
|
243
|
+
* @property {UUID} requestId this is should be unique, used for debug.
|
|
244
|
+
* @property {string} publicKey
|
|
245
|
+
*/
|
|
260
246
|
/**
|
|
261
247
|
* get public key from kms
|
|
262
248
|
* @param {Object} options
|
|
@@ -269,22 +255,21 @@ const KMS = WebexPlugin.extend({
|
|
|
269
255
|
return this.request({
|
|
270
256
|
method: 'retrieve',
|
|
271
257
|
uri: '/publicKey',
|
|
272
|
-
assignedOrgId
|
|
273
|
-
})
|
|
274
|
-
.
|
|
275
|
-
this.logger.info('kms: received public key');
|
|
258
|
+
assignedOrgId,
|
|
259
|
+
}).then((res) => {
|
|
260
|
+
this.logger.info('kms: received public key');
|
|
276
261
|
|
|
277
|
-
|
|
278
|
-
|
|
262
|
+
return res.publicKey;
|
|
263
|
+
});
|
|
279
264
|
},
|
|
280
265
|
|
|
281
266
|
/**
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
267
|
+
* @typedef {Object} UploadCmkResponse
|
|
268
|
+
* @property {number} status
|
|
269
|
+
* @property {UUID} requestId
|
|
270
|
+
* @property {string} uri
|
|
271
|
+
* @property {string} keysState
|
|
272
|
+
*/
|
|
288
273
|
/**
|
|
289
274
|
* upload master key for one org.
|
|
290
275
|
* @param {Object} options
|
|
@@ -300,7 +285,7 @@ const KMS = WebexPlugin.extend({
|
|
|
300
285
|
uri: '/cmk',
|
|
301
286
|
assignedOrgId,
|
|
302
287
|
customerMasterKey,
|
|
303
|
-
requestId: uuid.v4()
|
|
288
|
+
requestId: uuid.v4(),
|
|
304
289
|
}).then((res) => {
|
|
305
290
|
this.logger.info('kms: finish to upload customer master key');
|
|
306
291
|
|
|
@@ -321,7 +306,7 @@ const KMS = WebexPlugin.extend({
|
|
|
321
306
|
method: 'retrieve',
|
|
322
307
|
uri: '/cmk',
|
|
323
308
|
assignedOrgId,
|
|
324
|
-
requestId: uuid.v4()
|
|
309
|
+
requestId: uuid.v4(),
|
|
325
310
|
}).then((res) => {
|
|
326
311
|
this.logger.info('kms: finish to get all customer master keys');
|
|
327
312
|
|
|
@@ -330,11 +315,11 @@ const KMS = WebexPlugin.extend({
|
|
|
330
315
|
},
|
|
331
316
|
|
|
332
317
|
/**
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
318
|
+
* @typedef {Object} ActivateCmkResponse
|
|
319
|
+
* @property {number} status
|
|
320
|
+
* @property {UUID} requestId
|
|
321
|
+
* @property {Array<CMK>} customerMasterKeys
|
|
322
|
+
*/
|
|
338
323
|
/**
|
|
339
324
|
*
|
|
340
325
|
* @typedef {Object} CMK
|
|
@@ -364,7 +349,7 @@ const KMS = WebexPlugin.extend({
|
|
|
364
349
|
uri: keyId,
|
|
365
350
|
keyState,
|
|
366
351
|
assignedOrgId,
|
|
367
|
-
requestId: uuid.v4()
|
|
352
|
+
requestId: uuid.v4(),
|
|
368
353
|
}).then((res) => {
|
|
369
354
|
this.logger.info('kms: finish to change the customer master key state to {}', keyState);
|
|
370
355
|
|
|
@@ -385,7 +370,7 @@ const KMS = WebexPlugin.extend({
|
|
|
385
370
|
method: 'delete',
|
|
386
371
|
uri: '/cmk',
|
|
387
372
|
assignedOrgId,
|
|
388
|
-
requestId: uuid.v4()
|
|
373
|
+
requestId: uuid.v4(),
|
|
389
374
|
}).then((res) => {
|
|
390
375
|
this.logger.info('kms: finish to delete all customer master keys');
|
|
391
376
|
|
|
@@ -407,7 +392,7 @@ const KMS = WebexPlugin.extend({
|
|
|
407
392
|
uri: 'default',
|
|
408
393
|
keyState: 'ACTIVE',
|
|
409
394
|
assignedOrgId,
|
|
410
|
-
requestId: uuid.v4()
|
|
395
|
+
requestId: uuid.v4(),
|
|
411
396
|
}).then((res) => {
|
|
412
397
|
this.logger.info('kms: finish to return to global master key');
|
|
413
398
|
|
|
@@ -427,7 +412,7 @@ const KMS = WebexPlugin.extend({
|
|
|
427
412
|
// request. as such, we need the batcher to group requests, but one flight to
|
|
428
413
|
// make sure we don't make the same request multiple times.
|
|
429
414
|
@oneFlight({
|
|
430
|
-
keyFactory: ({uri, onBehalfOf}) => `${uri}/${onBehalfOf}
|
|
415
|
+
keyFactory: ({uri, onBehalfOf}) => `${uri}/${onBehalfOf}`,
|
|
431
416
|
})
|
|
432
417
|
fetchKey({uri, onBehalfOf}) {
|
|
433
418
|
/* istanbul ignore if */
|
|
@@ -437,15 +422,17 @@ const KMS = WebexPlugin.extend({
|
|
|
437
422
|
|
|
438
423
|
this.logger.info('kms: fetching key');
|
|
439
424
|
|
|
440
|
-
return this.request(
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
425
|
+
return this.request(
|
|
426
|
+
{
|
|
427
|
+
method: 'retrieve',
|
|
428
|
+
uri,
|
|
429
|
+
},
|
|
430
|
+
{onBehalfOf}
|
|
431
|
+
).then((res) => {
|
|
432
|
+
this.logger.info('kms: fetched key');
|
|
446
433
|
|
|
447
|
-
|
|
448
|
-
|
|
434
|
+
return this.asKey(res.key);
|
|
435
|
+
});
|
|
449
436
|
},
|
|
450
437
|
|
|
451
438
|
/**
|
|
@@ -455,7 +442,7 @@ const KMS = WebexPlugin.extend({
|
|
|
455
442
|
ping() {
|
|
456
443
|
return this.request({
|
|
457
444
|
method: 'update',
|
|
458
|
-
uri: '/ping'
|
|
445
|
+
uri: '/ping',
|
|
459
446
|
});
|
|
460
447
|
},
|
|
461
448
|
|
|
@@ -465,12 +452,11 @@ const KMS = WebexPlugin.extend({
|
|
|
465
452
|
* @returns {Promise<Key>}
|
|
466
453
|
*/
|
|
467
454
|
asKey(key) {
|
|
468
|
-
return jose.JWK.asKey(key.jwk)
|
|
469
|
-
.
|
|
470
|
-
key.jwk = jwk;
|
|
455
|
+
return jose.JWK.asKey(key.jwk).then((jwk) => {
|
|
456
|
+
key.jwk = jwk;
|
|
471
457
|
|
|
472
|
-
|
|
473
|
-
|
|
458
|
+
return key;
|
|
459
|
+
});
|
|
474
460
|
},
|
|
475
461
|
|
|
476
462
|
/**
|
|
@@ -482,8 +468,8 @@ const KMS = WebexPlugin.extend({
|
|
|
482
468
|
prepareRequest(payload, onBehalfOf) {
|
|
483
469
|
const isECDHRequest = payload.method === 'create' && payload.uri.includes('/ecdhe');
|
|
484
470
|
|
|
485
|
-
return Promise.resolve(isECDHRequest ? partialContexts.get(this) : this._getContext())
|
|
486
|
-
|
|
471
|
+
return Promise.resolve(isECDHRequest ? partialContexts.get(this) : this._getContext()).then(
|
|
472
|
+
(context) => {
|
|
487
473
|
this.logger.info(`kms: wrapping ${isECDHRequest ? 'ephemeral key' : 'kms'} request`);
|
|
488
474
|
const req = new Request(payload);
|
|
489
475
|
let requestContext = context;
|
|
@@ -492,16 +478,19 @@ const KMS = WebexPlugin.extend({
|
|
|
492
478
|
requestContext = this._contextOnBehalfOf(context, onBehalfOf);
|
|
493
479
|
}
|
|
494
480
|
|
|
495
|
-
return req.wrap(requestContext, {serverKey: isECDHRequest})
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
481
|
+
return req.wrap(requestContext, {serverKey: isECDHRequest}).then(() => {
|
|
482
|
+
/* istanbul ignore else */
|
|
483
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
484
|
+
this.logger.info(
|
|
485
|
+
'kms: request payload',
|
|
486
|
+
util.inspect(omit(JSON.parse(JSON.stringify(req)), 'wrapped'), {depth: null})
|
|
487
|
+
);
|
|
488
|
+
}
|
|
501
489
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
}
|
|
490
|
+
return req;
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
);
|
|
505
494
|
},
|
|
506
495
|
|
|
507
496
|
/**
|
|
@@ -512,25 +501,35 @@ const KMS = WebexPlugin.extend({
|
|
|
512
501
|
processKmsMessageEvent(event) {
|
|
513
502
|
this.logger.info('kms: received kms message');
|
|
514
503
|
|
|
515
|
-
return Promise.all(
|
|
516
|
-
.
|
|
517
|
-
this.
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
504
|
+
return Promise.all(
|
|
505
|
+
event.encryption.kmsMessages.map((kmsMessage, index) =>
|
|
506
|
+
this._isECDHEMessage(kmsMessage).then((isECDHMessage) => {
|
|
507
|
+
this.logger.info(`kms: received ${isECDHMessage ? 'ecdhe' : 'normal'} message`);
|
|
508
|
+
const res = new Response(kmsMessage);
|
|
509
|
+
|
|
510
|
+
return (
|
|
511
|
+
Promise.resolve(isECDHMessage ? partialContexts.get(this) : contexts.get(this))
|
|
512
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
513
|
+
.then((context) => res.unwrap(context))
|
|
514
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
515
|
+
.then(() => {
|
|
516
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
517
|
+
this.logger.info(
|
|
518
|
+
'kms: response payload',
|
|
519
|
+
util.inspect(omit(JSON.parse(JSON.stringify(res)), 'wrapped'), {depth: null})
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
})
|
|
523
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
524
|
+
.then(() => {
|
|
525
|
+
event.encryption.kmsMessages[index] = res;
|
|
526
|
+
})
|
|
527
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
528
|
+
.then(() => res)
|
|
529
|
+
);
|
|
530
|
+
})
|
|
531
|
+
)
|
|
532
|
+
)
|
|
534
533
|
.then(() => this.batcher.processKmsMessageEvent(event))
|
|
535
534
|
.catch((reason) => {
|
|
536
535
|
this.logger.error('kms: decrypt failed', reason.stack);
|
|
@@ -548,7 +547,8 @@ const KMS = WebexPlugin.extend({
|
|
|
548
547
|
decryptKmsMessage(kmsMessage) {
|
|
549
548
|
const res = new Response(kmsMessage);
|
|
550
549
|
|
|
551
|
-
return contexts
|
|
550
|
+
return contexts
|
|
551
|
+
.get(this)
|
|
552
552
|
.then((context) => res.unwrap(context))
|
|
553
553
|
.then(() => res.body);
|
|
554
554
|
},
|
|
@@ -559,18 +559,17 @@ const KMS = WebexPlugin.extend({
|
|
|
559
559
|
* @returns {Promise<boolean>}
|
|
560
560
|
*/
|
|
561
561
|
_isECDHEMessage(kmsMessage) {
|
|
562
|
-
return this._getKMSStaticPubKey()
|
|
563
|
-
.
|
|
564
|
-
const fields = kmsMessage.split('.');
|
|
562
|
+
return this._getKMSStaticPubKey().then((kmsStaticPubKey) => {
|
|
563
|
+
const fields = kmsMessage.split('.');
|
|
565
564
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
565
|
+
if (fields.length !== 3) {
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
569
568
|
|
|
570
|
-
|
|
569
|
+
const header = JSON.parse(jose.util.base64url.decode(fields[0]));
|
|
571
570
|
|
|
572
|
-
|
|
573
|
-
|
|
571
|
+
return header.kid === kmsStaticPubKey.kid;
|
|
572
|
+
});
|
|
574
573
|
},
|
|
575
574
|
|
|
576
575
|
/**
|
|
@@ -586,69 +585,80 @@ const KMS = WebexPlugin.extend({
|
|
|
586
585
|
|
|
587
586
|
// Note: this should only happen when we're using the async kms batcher;
|
|
588
587
|
// once we implement the sync batcher, this'll need to be smarter.
|
|
589
|
-
return
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
588
|
+
return (
|
|
589
|
+
this.webex.internal.mercury
|
|
590
|
+
.connect()
|
|
591
|
+
.then(() => this.prepareRequest(payload, onBehalfOf))
|
|
592
|
+
.then((req) => {
|
|
593
|
+
req[TIMEOUT_SYMBOL] = timeout;
|
|
594
|
+
|
|
595
|
+
return this.batcher.request(req);
|
|
596
|
+
})
|
|
597
|
+
// High complexity is due to attempt at test mode resiliency
|
|
598
|
+
// eslint-disable-next-line complexity
|
|
599
|
+
.catch((reason) => {
|
|
600
|
+
if (
|
|
601
|
+
process.env.NODE_ENV === 'test' &&
|
|
602
|
+
(reason.status === 403 || reason.statusCode === 403) &&
|
|
603
|
+
reason.message.match(
|
|
604
|
+
/Failed to resolve authorization token in KmsMessage request for user/
|
|
605
|
+
)
|
|
606
|
+
) {
|
|
607
|
+
this.logger.warn('kms: rerequested key due to test-mode kms auth failure');
|
|
608
|
+
|
|
609
|
+
return this.request(payload, {onBehalfOf});
|
|
610
|
+
}
|
|
601
611
|
|
|
602
|
-
|
|
603
|
-
|
|
612
|
+
// KMS Error. Notify the user
|
|
613
|
+
if (reason instanceof KMSError) {
|
|
614
|
+
this.webex.trigger('client:InvalidRequestError');
|
|
604
615
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
this.webex.trigger('client:InvalidRequestError');
|
|
616
|
+
return Promise.reject(reason);
|
|
617
|
+
}
|
|
608
618
|
|
|
609
|
-
|
|
610
|
-
|
|
619
|
+
// Ideally, most or all of the code below would go in kms-batcher, but
|
|
620
|
+
// but batching needs at least one more round of refactoring for that to
|
|
621
|
+
// work.
|
|
622
|
+
if (!reason.statusCode && !reason.status) {
|
|
623
|
+
/* istanbul ignore else */
|
|
624
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
625
|
+
/* istanbul ignore next: reason.stack vs stack difficult to control in test */
|
|
626
|
+
this.logger.info('kms: request error', reason.stack || reason);
|
|
627
|
+
}
|
|
611
628
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
// work.
|
|
615
|
-
if (!reason.statusCode && !reason.status) {
|
|
616
|
-
/* istanbul ignore else */
|
|
617
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
618
|
-
/* istanbul ignore next: reason.stack vs stack difficult to control in test */
|
|
619
|
-
this.logger.info('kms: request error', reason.stack || reason);
|
|
620
|
-
}
|
|
629
|
+
consoleDebug(`timeout ${timeout}`);
|
|
630
|
+
timeout *= 2;
|
|
621
631
|
|
|
622
|
-
|
|
623
|
-
|
|
632
|
+
if (timeout >= this.config.ecdhMaxTimeout) {
|
|
633
|
+
this.logger.info('kms: exceeded maximum KMS request retries');
|
|
624
634
|
|
|
625
|
-
|
|
626
|
-
|
|
635
|
+
return Promise.reject(reason);
|
|
636
|
+
}
|
|
627
637
|
|
|
628
|
-
|
|
629
|
-
|
|
638
|
+
// Peek ahead to make sure we don't reset the timeout if the next timeout
|
|
639
|
+
// will exceed the maximum timeout for renegotiating ECDH keys.
|
|
640
|
+
const nextTimeout = timeout * 2;
|
|
630
641
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
642
|
+
if (timeout >= this.config.kmsMaxTimeout && nextTimeout < this.config.ecdhMaxTimeout) {
|
|
643
|
+
this.logger.info(
|
|
644
|
+
'kms: exceeded maximum KMS request retries; negotiating new ecdh key'
|
|
645
|
+
);
|
|
634
646
|
|
|
635
|
-
|
|
636
|
-
|
|
647
|
+
/* istanbul ignore else */
|
|
648
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
649
|
+
this.logger.info('kms: timeout/maxtimeout', timeout, this.config.kmsMaxTimeout);
|
|
650
|
+
}
|
|
637
651
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
this.logger.info('kms: timeout/maxtimeout', timeout, this.config.kmsMaxTimeout);
|
|
652
|
+
contexts.delete(this);
|
|
653
|
+
timeout = 0;
|
|
641
654
|
}
|
|
642
655
|
|
|
643
|
-
|
|
644
|
-
timeout = 0;
|
|
656
|
+
return this.request(payload, {timeout, onBehalfOf});
|
|
645
657
|
}
|
|
646
658
|
|
|
647
|
-
return
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
return Promise.reject(reason);
|
|
651
|
-
});
|
|
659
|
+
return Promise.reject(reason);
|
|
660
|
+
})
|
|
661
|
+
);
|
|
652
662
|
},
|
|
653
663
|
|
|
654
664
|
/**
|
|
@@ -656,8 +666,7 @@ const KMS = WebexPlugin.extend({
|
|
|
656
666
|
* @returns {Promise<string>}
|
|
657
667
|
*/
|
|
658
668
|
_getAuthorization() {
|
|
659
|
-
return this.webex.credentials.getUserToken('spark:kms')
|
|
660
|
-
.then((token) => token.access_token);
|
|
669
|
+
return this.webex.credentials.getUserToken('spark:kms').then((token) => token.access_token);
|
|
661
670
|
},
|
|
662
671
|
|
|
663
672
|
@oneFlight
|
|
@@ -679,15 +688,11 @@ const KMS = WebexPlugin.extend({
|
|
|
679
688
|
});
|
|
680
689
|
}
|
|
681
690
|
|
|
682
|
-
return Promise.all([
|
|
683
|
-
|
|
684
|
-
this._getAuthorization()
|
|
685
|
-
])
|
|
686
|
-
.then(([context, authorization]) => {
|
|
687
|
-
context.clientInfo.credential.bearer = authorization;
|
|
691
|
+
return Promise.all([promise, this._getAuthorization()]).then(([context, authorization]) => {
|
|
692
|
+
context.clientInfo.credential.bearer = authorization;
|
|
688
693
|
|
|
689
|
-
|
|
690
|
-
|
|
694
|
+
return context;
|
|
695
|
+
});
|
|
691
696
|
},
|
|
692
697
|
|
|
693
698
|
/**
|
|
@@ -697,8 +702,7 @@ const KMS = WebexPlugin.extend({
|
|
|
697
702
|
_getKMSCluster() {
|
|
698
703
|
this.logger.info('kms: retrieving KMS cluster');
|
|
699
704
|
|
|
700
|
-
return this._getKMSDetails()
|
|
701
|
-
.then(({kmsCluster}) => kmsCluster);
|
|
705
|
+
return this._getKMSDetails().then(({kmsCluster}) => kmsCluster);
|
|
702
706
|
},
|
|
703
707
|
|
|
704
708
|
/**
|
|
@@ -710,10 +714,11 @@ const KMS = WebexPlugin.extend({
|
|
|
710
714
|
|
|
711
715
|
if (!details) {
|
|
712
716
|
this.logger.info('kms: fetching KMS details');
|
|
713
|
-
details = this.webex
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
+
details = this.webex
|
|
718
|
+
.request({
|
|
719
|
+
service: 'encryption',
|
|
720
|
+
resource: `/kms/${this.webex.internal.device.userId}`,
|
|
721
|
+
})
|
|
717
722
|
.then((res) => {
|
|
718
723
|
this.logger.info('kms: fetched KMS details');
|
|
719
724
|
const {body} = res;
|
|
@@ -741,8 +746,7 @@ const KMS = WebexPlugin.extend({
|
|
|
741
746
|
_getKMSStaticPubKey() {
|
|
742
747
|
this.logger.info('kms: retrieving KMS static public key');
|
|
743
748
|
|
|
744
|
-
return this._getKMSDetails()
|
|
745
|
-
.then(({rsaPublicKey}) => rsaPublicKey);
|
|
749
|
+
return this._getKMSDetails().then(({rsaPublicKey}) => rsaPublicKey);
|
|
746
750
|
},
|
|
747
751
|
|
|
748
752
|
/**
|
|
@@ -755,19 +759,19 @@ const KMS = WebexPlugin.extend({
|
|
|
755
759
|
|
|
756
760
|
return Promise.all([
|
|
757
761
|
this._getKMSStaticPubKey().then(validateKMS(this.config.caroots)),
|
|
758
|
-
this._getAuthorization()
|
|
762
|
+
this._getAuthorization(),
|
|
759
763
|
])
|
|
760
764
|
.then(([kmsStaticPubKey, authorization]) => {
|
|
761
765
|
context.clientInfo = {
|
|
762
766
|
clientId: this.webex.internal.device.url,
|
|
763
767
|
credential: {
|
|
764
768
|
userId: this.webex.internal.device.userId,
|
|
765
|
-
bearer: authorization
|
|
766
|
-
}
|
|
769
|
+
bearer: authorization,
|
|
770
|
+
},
|
|
767
771
|
};
|
|
768
772
|
|
|
769
773
|
context.serverInfo = {
|
|
770
|
-
key: kmsStaticPubKey
|
|
774
|
+
key: kmsStaticPubKey,
|
|
771
775
|
};
|
|
772
776
|
|
|
773
777
|
this.logger.info('kms: creating local ephemeral key');
|
|
@@ -786,7 +790,7 @@ const KMS = WebexPlugin.extend({
|
|
|
786
790
|
return this.request({
|
|
787
791
|
uri: `${cluster}/ecdhe`,
|
|
788
792
|
method: 'create',
|
|
789
|
-
jwk: localECDHKey.toJSON()
|
|
793
|
+
jwk: localECDHKey.toJSON(),
|
|
790
794
|
});
|
|
791
795
|
})
|
|
792
796
|
.then((res) => {
|
|
@@ -828,14 +832,14 @@ const KMS = WebexPlugin.extend({
|
|
|
828
832
|
credential: {
|
|
829
833
|
userId: onBehalfOf,
|
|
830
834
|
onBehalfOf, // Supports running onBehalfOf self. i.e. A CO which calls onBehalfOf with CO.id.
|
|
831
|
-
bearer: originalContext.clientInfo.credential.bearer
|
|
832
|
-
}
|
|
835
|
+
bearer: originalContext.clientInfo.credential.bearer,
|
|
836
|
+
},
|
|
833
837
|
};
|
|
834
838
|
context.serverInfo = originalContext.serverInfo;
|
|
835
839
|
context.ephemeralKey = originalContext.ephemeralKey;
|
|
836
840
|
|
|
837
841
|
return context;
|
|
838
|
-
}
|
|
842
|
+
},
|
|
839
843
|
});
|
|
840
844
|
|
|
841
845
|
export default KMS;
|