@webex/internal-plugin-encryption 1.161.0 → 2.2.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.
@@ -273,7 +273,7 @@ var Encryption = _webexCore.WebexPlugin.extend({
273
273
  }));
274
274
  });
275
275
  },
276
- version: "1.161.0"
276
+ version: "2.2.0"
277
277
  });
278
278
  /**
279
279
  * JSON.stringify replacer that ensures private key data is serialized.
package/dist/kms.js CHANGED
@@ -46,6 +46,8 @@ var _nodeKms = require("node-kms");
46
46
 
47
47
  var _nodeJose = _interopRequireDefault(require("node-jose"));
48
48
 
49
+ var _uuid = _interopRequireDefault(require("uuid"));
50
+
49
51
  var _kmsBatcher = _interopRequireWildcard(require("./kms-batcher"));
50
52
 
51
53
  var _kmsCertificateValidation = _interopRequireWildcard(require("./kms-certificate-validation"));
@@ -318,11 +320,193 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
318
320
  return _promise.default.all(res.keys.map(_this6.asKey));
319
321
  });
320
322
  },
321
- fetchKey: function fetchKey(_ref8) {
323
+
324
+ /**
325
+ * @typedef {Object} FetchPublicKeyResponse
326
+ * @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)
327
+ * @property {UUID} requestId this is should be unique, used for debug.
328
+ * @property {string} publicKey
329
+ */
330
+
331
+ /**
332
+ * get public key from kms
333
+ * @param {Object} options
334
+ * @param {UUID} options.assignedOrgId the orgId
335
+ * @returns {Promise.<FetchPublicKeyResponse>} response of get public key api
336
+ */
337
+ fetchPublicKey: function fetchPublicKey(_ref8) {
322
338
  var _this7 = this;
323
339
 
324
- var uri = _ref8.uri,
325
- onBehalfOf = _ref8.onBehalfOf;
340
+ var assignedOrgId = _ref8.assignedOrgId;
341
+ this.logger.info('kms: fetch public key for byok');
342
+ return this.request({
343
+ method: 'retrieve',
344
+ uri: '/publicKey',
345
+ assignedOrgId: assignedOrgId
346
+ }).then(function (res) {
347
+ _this7.logger.info('kms: received public key');
348
+
349
+ return res.publicKey;
350
+ });
351
+ },
352
+
353
+ /**
354
+ * @typedef {Object} UploadCmkResponse
355
+ * @property {number} status
356
+ * @property {UUID} requestId
357
+ * @property {string} uri
358
+ * @property {string} keysState
359
+ */
360
+
361
+ /**
362
+ * upload master key for one org.
363
+ * @param {Object} options
364
+ * @param {UUID} options.assignedOrgId the orgId
365
+ * @param {string} options.customerMasterKey the master key
366
+ * @returns {Promise.<UploadCmkResponse>} response of upload CMK api
367
+ */
368
+ uploadCustomerMasterKey: function uploadCustomerMasterKey(_ref9) {
369
+ var _this8 = this;
370
+
371
+ var assignedOrgId = _ref9.assignedOrgId,
372
+ customerMasterKey = _ref9.customerMasterKey;
373
+ this.logger.info('kms: upload customer master key for byok');
374
+ return this.request({
375
+ method: 'create',
376
+ uri: '/cmk',
377
+ assignedOrgId: assignedOrgId,
378
+ customerMasterKey: customerMasterKey,
379
+ requestId: _uuid.default.v4()
380
+ }).then(function (res) {
381
+ _this8.logger.info('kms: finish to upload customer master key');
382
+
383
+ return res;
384
+ });
385
+ },
386
+
387
+ /**
388
+ * get all customer master keys for one org.
389
+ * @param {Object} options
390
+ * @param {UUID} options.assignedOrgId the orgId
391
+ * @returns {Promise.<ActivateCmkResponse>} response of list CMKs api
392
+ */
393
+ listAllCustomerMasterKey: function listAllCustomerMasterKey(_ref10) {
394
+ var _this9 = this;
395
+
396
+ var assignedOrgId = _ref10.assignedOrgId;
397
+ this.logger.info('kms: get all customer master keys for byok');
398
+ return this.request({
399
+ method: 'retrieve',
400
+ uri: '/cmk',
401
+ assignedOrgId: assignedOrgId,
402
+ requestId: _uuid.default.v4()
403
+ }).then(function (res) {
404
+ _this9.logger.info('kms: finish to get all customer master keys');
405
+
406
+ return res;
407
+ });
408
+ },
409
+
410
+ /**
411
+ * @typedef {Object} ActivateCmkResponse
412
+ * @property {number} status
413
+ * @property {UUID} requestId
414
+ * @property {Array<CMK>} customerMasterKeys
415
+ */
416
+
417
+ /**
418
+ *
419
+ * @typedef {Object} CMK
420
+ * @property {string} usageState
421
+ * @property {UUID} assignedOrgId
422
+ * @property {string} uri
423
+ * @property {string} source
424
+ * @property {Date | undefined} stateUpdatedOn
425
+ * @property {Date | undefined} rotation
426
+ */
427
+
428
+ /**
429
+ * change one customer master key state for one org.
430
+ * delete pending key, then the keyState should be 'removedclean';
431
+ * active pending key, then the keyState should be 'active';
432
+ *
433
+ * @param {Object} options
434
+ * @param {string} options.keyId the id of one customer master key, it should be a url
435
+ * @param {string} options.keyState one of the following: PENDING, RECOVERING,ACTIVE,REVOKED,DEACTIVATED,REENCRYPTING,RETIRED,DELETED,DISABLED,REMOVEDCLEAN,REMOVEDDIRTY;
436
+ * @param {UUID} options.assignedOrgId the orgId
437
+ * @returns {Promise.<ActivateCmkResponse>} response of list CMKs api
438
+ */
439
+ changeCustomerMasterKeyState: function changeCustomerMasterKeyState(_ref11) {
440
+ var _this10 = this;
441
+
442
+ var keyId = _ref11.keyId,
443
+ keyState = _ref11.keyState,
444
+ assignedOrgId = _ref11.assignedOrgId;
445
+ this.logger.info('kms: change one customer master key state for byok');
446
+ return this.request({
447
+ method: 'update',
448
+ uri: keyId,
449
+ keyState: keyState,
450
+ assignedOrgId: assignedOrgId,
451
+ requestId: _uuid.default.v4()
452
+ }).then(function (res) {
453
+ _this10.logger.info('kms: finish to change the customer master key state to {}', keyState);
454
+
455
+ return res;
456
+ });
457
+ },
458
+
459
+ /**
460
+ * this is for test case. it will delete all CMKs, no matter what their status is. This is mainly for test purpose
461
+ * @param {Object} options
462
+ * @param {UUID} options.assignedOrgId the orgId
463
+ * @returns {Promise.<{status, requestId}>}
464
+ */
465
+ deleteAllCustomerMasterKeys: function deleteAllCustomerMasterKeys(_ref12) {
466
+ var _this11 = this;
467
+
468
+ var assignedOrgId = _ref12.assignedOrgId;
469
+ this.logger.info('kms: delete all customer master keys at the same time');
470
+ return this.request({
471
+ method: 'delete',
472
+ uri: '/cmk',
473
+ assignedOrgId: assignedOrgId,
474
+ requestId: _uuid.default.v4()
475
+ }).then(function (res) {
476
+ _this11.logger.info('kms: finish to delete all customer master keys');
477
+
478
+ return res;
479
+ });
480
+ },
481
+
482
+ /**
483
+ * return to use global master key for one org.
484
+ * @param {Object} options
485
+ * @param {UUID} options.assignedOrgId the orgId
486
+ * @returns {Promise.<ActivateCmkResponse>} response of activate CMK api
487
+ */
488
+ useGlobalMasterKey: function useGlobalMasterKey(_ref13) {
489
+ var _this12 = this;
490
+
491
+ var assignedOrgId = _ref13.assignedOrgId;
492
+ this.logger.info('kms: return to use global master key');
493
+ return this.request({
494
+ method: 'update',
495
+ uri: 'default',
496
+ keyState: 'ACTIVE',
497
+ assignedOrgId: assignedOrgId,
498
+ requestId: _uuid.default.v4()
499
+ }).then(function (res) {
500
+ _this12.logger.info('kms: finish to return to global master key');
501
+
502
+ return res;
503
+ });
504
+ },
505
+ fetchKey: function fetchKey(_ref14) {
506
+ var _this13 = this;
507
+
508
+ var uri = _ref14.uri,
509
+ onBehalfOf = _ref14.onBehalfOf;
326
510
 
327
511
  /* istanbul ignore if */
328
512
  if (!uri) {
@@ -336,9 +520,9 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
336
520
  }, {
337
521
  onBehalfOf: onBehalfOf
338
522
  }).then(function (res) {
339
- _this7.logger.info('kms: fetched key');
523
+ _this13.logger.info('kms: fetched key');
340
524
 
341
- return _this7.asKey(res.key);
525
+ return _this13.asKey(res.key);
342
526
  });
343
527
  },
344
528
 
@@ -372,17 +556,17 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
372
556
  * @returns {Promise<KMS.Request>}
373
557
  */
374
558
  prepareRequest: function prepareRequest(payload, onBehalfOf) {
375
- var _this8 = this;
559
+ var _this14 = this;
376
560
 
377
561
  var isECDHRequest = payload.method === 'create' && payload.uri.includes('/ecdhe');
378
562
  return _promise.default.resolve(isECDHRequest ? partialContexts.get(this) : this._getContext()).then(function (context) {
379
- _this8.logger.info("kms: wrapping ".concat(isECDHRequest ? 'ephemeral key' : 'kms', " request"));
563
+ _this14.logger.info("kms: wrapping ".concat(isECDHRequest ? 'ephemeral key' : 'kms', " request"));
380
564
 
381
565
  var req = new _nodeKms.Request(payload);
382
566
  var requestContext = context;
383
567
 
384
568
  if (onBehalfOf) {
385
- requestContext = _this8._contextOnBehalfOf(context, onBehalfOf);
569
+ requestContext = _this14._contextOnBehalfOf(context, onBehalfOf);
386
570
  }
387
571
 
388
572
  return req.wrap(requestContext, {
@@ -390,7 +574,7 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
390
574
  }).then(function () {
391
575
  /* istanbul ignore else */
392
576
  if (process.env.NODE_ENV !== 'production') {
393
- _this8.logger.info('kms: request payload', _util.default.inspect((0, _omit2.default)(JSON.parse((0, _stringify.default)(req)), 'wrapped'), {
577
+ _this14.logger.info('kms: request payload', _util.default.inspect((0, _omit2.default)(JSON.parse((0, _stringify.default)(req)), 'wrapped'), {
394
578
  depth: null
395
579
  }));
396
580
  }
@@ -406,21 +590,21 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
406
590
  * @returns {Promise<Object>}
407
591
  */
408
592
  processKmsMessageEvent: function processKmsMessageEvent(event) {
409
- var _this9 = this;
593
+ var _this15 = this;
410
594
 
411
595
  this.logger.info('kms: received kms message');
412
596
  return _promise.default.all(event.encryption.kmsMessages.map(function (kmsMessage, index) {
413
- return _this9._isECDHEMessage(kmsMessage).then(function (isECDHMessage) {
414
- _this9.logger.info("kms: received ".concat(isECDHMessage ? 'ecdhe' : 'normal', " message"));
597
+ return _this15._isECDHEMessage(kmsMessage).then(function (isECDHMessage) {
598
+ _this15.logger.info("kms: received ".concat(isECDHMessage ? 'ecdhe' : 'normal', " message"));
415
599
 
416
600
  var res = new _nodeKms.Response(kmsMessage);
417
- return _promise.default.resolve(isECDHMessage ? partialContexts.get(_this9) : contexts.get(_this9)) // eslint-disable-next-line max-nested-callbacks
601
+ return _promise.default.resolve(isECDHMessage ? partialContexts.get(_this15) : contexts.get(_this15)) // eslint-disable-next-line max-nested-callbacks
418
602
  .then(function (context) {
419
603
  return res.unwrap(context);
420
604
  }) // eslint-disable-next-line max-nested-callbacks
421
605
  .then(function () {
422
606
  if (process.env.NODE_ENV !== 'production') {
423
- _this9.logger.info('kms: response payload', _util.default.inspect((0, _omit2.default)(JSON.parse((0, _stringify.default)(res)), 'wrapped'), {
607
+ _this15.logger.info('kms: response payload', _util.default.inspect((0, _omit2.default)(JSON.parse((0, _stringify.default)(res)), 'wrapped'), {
424
608
  depth: null
425
609
  }));
426
610
  }
@@ -433,9 +617,9 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
433
617
  });
434
618
  });
435
619
  })).then(function () {
436
- return _this9.batcher.processKmsMessageEvent(event);
620
+ return _this15.batcher.processKmsMessageEvent(event);
437
621
  }).catch(function (reason) {
438
- _this9.logger.error('kms: decrypt failed', reason.stack);
622
+ _this15.logger.error('kms: decrypt failed', reason.stack);
439
623
 
440
624
  return _promise.default.reject(reason);
441
625
  }).then(function () {
@@ -484,34 +668,34 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
484
668
  * @returns {Promise<Object>}
485
669
  */
486
670
  request: function request(payload) {
487
- var _this10 = this;
671
+ var _this16 = this;
488
672
 
489
- var _ref9 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
490
- timeout = _ref9.timeout,
491
- onBehalfOf = _ref9.onBehalfOf;
673
+ var _ref15 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
674
+ timeout = _ref15.timeout,
675
+ onBehalfOf = _ref15.onBehalfOf;
492
676
 
493
677
  timeout = timeout || this.config.kmsInitialTimeout; // Note: this should only happen when we're using the async kms batcher;
494
678
  // once we implement the sync batcher, this'll need to be smarter.
495
679
 
496
680
  return this.webex.internal.mercury.connect().then(function () {
497
- return _this10.prepareRequest(payload, onBehalfOf);
681
+ return _this16.prepareRequest(payload, onBehalfOf);
498
682
  }).then(function (req) {
499
683
  req[_kmsBatcher.TIMEOUT_SYMBOL] = timeout;
500
- return _this10.batcher.request(req);
684
+ return _this16.batcher.request(req);
501
685
  }) // High complexity is due to attempt at test mode resiliency
502
686
  // eslint-disable-next-line complexity
503
687
  .catch(function (reason) {
504
688
  if (process.env.NODE_ENV === 'test' && (reason.status === 403 || reason.statusCode === 403) && reason.message.match(/Failed to resolve authorization token in KmsMessage request for user/)) {
505
- _this10.logger.warn('kms: rerequested key due to test-mode kms auth failure');
689
+ _this16.logger.warn('kms: rerequested key due to test-mode kms auth failure');
506
690
 
507
- return _this10.request(payload, {
691
+ return _this16.request(payload, {
508
692
  onBehalfOf: onBehalfOf
509
693
  });
510
694
  } // KMS Error. Notify the user
511
695
 
512
696
 
513
697
  if (reason instanceof _kmsCertificateValidation.KMSError) {
514
- _this10.webex.trigger('client:InvalidRequestError');
698
+ _this16.webex.trigger('client:InvalidRequestError');
515
699
 
516
700
  return _promise.default.reject(reason);
517
701
  } // Ideally, most or all of the code below would go in kms-batcher, but
@@ -523,14 +707,14 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
523
707
  /* istanbul ignore else */
524
708
  if (process.env.NODE_ENV !== 'production') {
525
709
  /* istanbul ignore next: reason.stack vs stack difficult to control in test */
526
- _this10.logger.info('kms: request error', reason.stack || reason);
710
+ _this16.logger.info('kms: request error', reason.stack || reason);
527
711
  }
528
712
 
529
713
  consoleDebug("timeout ".concat(timeout));
530
714
  timeout *= 2;
531
715
 
532
- if (timeout >= _this10.config.ecdhMaxTimeout) {
533
- _this10.logger.info('kms: exceeded maximum KMS request retries');
716
+ if (timeout >= _this16.config.ecdhMaxTimeout) {
717
+ _this16.logger.info('kms: exceeded maximum KMS request retries');
534
718
 
535
719
  return _promise.default.reject(reason);
536
720
  } // Peek ahead to make sure we don't reset the timeout if the next timeout
@@ -539,20 +723,20 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
539
723
 
540
724
  var nextTimeout = timeout * 2;
541
725
 
542
- if (timeout >= _this10.config.kmsMaxTimeout && nextTimeout < _this10.config.ecdhMaxTimeout) {
543
- _this10.logger.info('kms: exceeded maximum KMS request retries; negotiating new ecdh key');
726
+ if (timeout >= _this16.config.kmsMaxTimeout && nextTimeout < _this16.config.ecdhMaxTimeout) {
727
+ _this16.logger.info('kms: exceeded maximum KMS request retries; negotiating new ecdh key');
544
728
  /* istanbul ignore else */
545
729
 
546
730
 
547
731
  if (process.env.NODE_ENV !== 'production') {
548
- _this10.logger.info('kms: timeout/maxtimeout', timeout, _this10.config.kmsMaxTimeout);
732
+ _this16.logger.info('kms: timeout/maxtimeout', timeout, _this16.config.kmsMaxTimeout);
549
733
  }
550
734
 
551
- contexts.delete(_this10);
735
+ contexts.delete(_this16);
552
736
  timeout = 0;
553
737
  }
554
738
 
555
- return _this10.request(payload, {
739
+ return _this16.request(payload, {
556
740
  timeout: timeout,
557
741
  onBehalfOf: onBehalfOf
558
742
  });
@@ -578,7 +762,7 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
578
762
  * @returns {Promise<Object>}
579
763
  */
580
764
  _getContext: function _getContext() {
581
- var _this11 = this;
765
+ var _this17 = this;
582
766
 
583
767
  var promise = contexts.get(this);
584
768
 
@@ -588,15 +772,15 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
588
772
  promise.then(function (context) {
589
773
  var expiresIn = context.ephemeralKey.expirationDate - (0, _now.default)() - 30000;
590
774
  (0, _commonTimers.safeSetTimeout)(function () {
591
- return contexts.delete(_this11);
775
+ return contexts.delete(_this17);
592
776
  }, expiresIn);
593
777
  });
594
778
  }
595
779
 
596
- return _promise.default.all([promise, this._getAuthorization()]).then(function (_ref10) {
597
- var _ref11 = (0, _slicedToArray2.default)(_ref10, 2),
598
- context = _ref11[0],
599
- authorization = _ref11[1];
780
+ return _promise.default.all([promise, this._getAuthorization()]).then(function (_ref16) {
781
+ var _ref17 = (0, _slicedToArray2.default)(_ref16, 2),
782
+ context = _ref17[0],
783
+ authorization = _ref17[1];
600
784
 
601
785
  context.clientInfo.credential.bearer = authorization;
602
786
  return context;
@@ -609,8 +793,8 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
609
793
  */
610
794
  _getKMSCluster: function _getKMSCluster() {
611
795
  this.logger.info('kms: retrieving KMS cluster');
612
- return this._getKMSDetails().then(function (_ref12) {
613
- var kmsCluster = _ref12.kmsCluster;
796
+ return this._getKMSDetails().then(function (_ref18) {
797
+ var kmsCluster = _ref18.kmsCluster;
614
798
  return kmsCluster;
615
799
  });
616
800
  },
@@ -620,7 +804,7 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
620
804
  * @returns {Promise<Object>}
621
805
  */
622
806
  _getKMSDetails: function _getKMSDetails() {
623
- var _this12 = this;
807
+ var _this18 = this;
624
808
 
625
809
  var details = kmsDetails.get(this);
626
810
 
@@ -630,13 +814,13 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
630
814
  service: 'encryption',
631
815
  resource: "/kms/".concat(this.webex.internal.device.userId)
632
816
  }).then(function (res) {
633
- _this12.logger.info('kms: fetched KMS details');
817
+ _this18.logger.info('kms: fetched KMS details');
634
818
 
635
819
  var body = res.body;
636
820
  body.rsaPublicKey = JSON.parse(body.rsaPublicKey);
637
821
  return body;
638
822
  }).catch(function (reason) {
639
- _this12.logger.error('kms: failed to fetch KMS details', reason);
823
+ _this18.logger.error('kms: failed to fetch KMS details', reason);
640
824
 
641
825
  return _promise.default.reject(reason);
642
826
  });
@@ -652,8 +836,8 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
652
836
  */
653
837
  _getKMSStaticPubKey: function _getKMSStaticPubKey() {
654
838
  this.logger.info('kms: retrieving KMS static public key');
655
- return this._getKMSDetails().then(function (_ref13) {
656
- var rsaPublicKey = _ref13.rsaPublicKey;
839
+ return this._getKMSDetails().then(function (_ref19) {
840
+ var rsaPublicKey = _ref19.rsaPublicKey;
657
841
  return rsaPublicKey;
658
842
  });
659
843
  },
@@ -663,19 +847,19 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
663
847
  * @returns {Promise<Object>}
664
848
  */
665
849
  _prepareContext: function _prepareContext() {
666
- var _this13 = this;
850
+ var _this19 = this;
667
851
 
668
852
  this.logger.info('kms: creating context');
669
853
  var context = new _nodeKms.Context();
670
- return _promise.default.all([this._getKMSStaticPubKey().then((0, _kmsCertificateValidation.default)(this.config.caroots)), this._getAuthorization()]).then(function (_ref14) {
671
- var _ref15 = (0, _slicedToArray2.default)(_ref14, 2),
672
- kmsStaticPubKey = _ref15[0],
673
- authorization = _ref15[1];
854
+ return _promise.default.all([this._getKMSStaticPubKey().then((0, _kmsCertificateValidation.default)(this.config.caroots)), this._getAuthorization()]).then(function (_ref20) {
855
+ var _ref21 = (0, _slicedToArray2.default)(_ref20, 2),
856
+ kmsStaticPubKey = _ref21[0],
857
+ authorization = _ref21[1];
674
858
 
675
859
  context.clientInfo = {
676
- clientId: _this13.webex.internal.device.url,
860
+ clientId: _this19.webex.internal.device.url,
677
861
  credential: {
678
- userId: _this13.webex.internal.device.userId,
862
+ userId: _this19.webex.internal.device.userId,
679
863
  bearer: authorization
680
864
  }
681
865
  };
@@ -683,38 +867,38 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
683
867
  key: kmsStaticPubKey
684
868
  };
685
869
 
686
- _this13.logger.info('kms: creating local ephemeral key');
870
+ _this19.logger.info('kms: creating local ephemeral key');
687
871
 
688
872
  return context.createECDHKey();
689
873
  }).then(function (localECDHKey) {
690
874
  context.ephemeralKey = localECDHKey;
691
- partialContexts.set(_this13, context);
692
- return _promise.default.all([localECDHKey.asKey(), _this13._getKMSCluster()]);
693
- }).then(function (_ref16) {
694
- var _ref17 = (0, _slicedToArray2.default)(_ref16, 2),
695
- localECDHKey = _ref17[0],
696
- cluster = _ref17[1];
875
+ partialContexts.set(_this19, context);
876
+ return _promise.default.all([localECDHKey.asKey(), _this19._getKMSCluster()]);
877
+ }).then(function (_ref22) {
878
+ var _ref23 = (0, _slicedToArray2.default)(_ref22, 2),
879
+ localECDHKey = _ref23[0],
880
+ cluster = _ref23[1];
697
881
 
698
- _this13.logger.info('kms: submitting ephemeral key request');
882
+ _this19.logger.info('kms: submitting ephemeral key request');
699
883
 
700
- return _this13.request({
884
+ return _this19.request({
701
885
  uri: "".concat(cluster, "/ecdhe"),
702
886
  method: 'create',
703
887
  jwk: localECDHKey.toJSON()
704
888
  });
705
889
  }).then(function (res) {
706
- _this13.logger.info('kms: deriving final ephemeral key');
890
+ _this19.logger.info('kms: deriving final ephemeral key');
707
891
 
708
892
  return context.deriveEphemeralKey(res.key);
709
893
  }).then(function (key) {
710
894
  context.ephemeralKey = key;
711
- partialContexts.delete(_this13);
895
+ partialContexts.delete(_this19);
712
896
 
713
- _this13.logger.info('kms: derived final ephemeral key');
897
+ _this19.logger.info('kms: derived final ephemeral key');
714
898
 
715
899
  return context;
716
900
  }).catch(function (reason) {
717
- _this13.logger.error('kms: failed to negotiate ephemeral key', reason);
901
+ _this19.logger.error('kms: failed to negotiate ephemeral key', reason);
718
902
 
719
903
  return _promise.default.reject(reason);
720
904
  });
@@ -747,7 +931,7 @@ var KMS = _webexCore.WebexPlugin.extend((_dec = (0, _common.oneFlight)({
747
931
  context.ephemeralKey = originalContext.ephemeralKey;
748
932
  return context;
749
933
  },
750
- version: "1.161.0"
934
+ version: "2.2.0"
751
935
  }, ((0, _applyDecoratedDescriptor2.default)(_obj, "fetchKey", [_dec], (0, _getOwnPropertyDescriptor.default)(_obj, "fetchKey"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "_getContext", [_common.oneFlight], (0, _getOwnPropertyDescriptor.default)(_obj, "_getContext"), _obj)), _obj)));
752
936
 
753
937
  var _default = KMS;
package/dist/kms.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"names":["contexts","kmsDetails","partialContexts","consoleDebug","require","KMS","WebexPlugin","extend","keyFactory","uri","onBehalfOf","namespace","children","batcher","KMSBatcher","bindKey","kro","kroUri","key","keyUri","logger","info","reject","Error","request","method","resourceUri","then","res","createResource","userIds","keyUris","keys","reduce","uris","k","push","length","resource","addAuthorization","authIds","concat","authorizations","listAuthorizations","removeAuthorization","authId","userId","querystring","stringify","createUnboundKeys","count","all","map","asKey","fetchKey","ping","jose","JWK","jwk","prepareRequest","payload","isECDHRequest","includes","resolve","get","_getContext","context","req","Request","requestContext","_contextOnBehalfOf","wrap","serverKey","process","env","NODE_ENV","util","inspect","JSON","parse","depth","processKmsMessageEvent","event","encryption","kmsMessages","kmsMessage","index","_isECDHEMessage","isECDHMessage","Response","unwrap","catch","reason","error","stack","decryptKmsMessage","body","_getKMSStaticPubKey","kmsStaticPubKey","fields","split","header","base64url","decode","kid","timeout","config","kmsInitialTimeout","webex","internal","mercury","connect","TIMEOUT_SYMBOL","status","statusCode","message","match","warn","KMSError","trigger","ecdhMaxTimeout","nextTimeout","kmsMaxTimeout","delete","_getAuthorization","credentials","getUserToken","token","access_token","promise","_prepareContext","set","expiresIn","ephemeralKey","expirationDate","authorization","clientInfo","credential","bearer","_getKMSCluster","_getKMSDetails","kmsCluster","details","service","device","rsaPublicKey","Context","caroots","clientId","url","serverInfo","createECDHKey","localECDHKey","cluster","toJSON","deriveEphemeralKey","originalContext","oneFlight"],"sources":["kms.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport querystring from 'querystring';\nimport util from 'util';\n\nimport {safeSetTimeout} from '@webex/common-timers';\nimport {oneFlight} from '@webex/common';\nimport {WebexPlugin} from '@webex/webex-core';\nimport {Context, Request, Response} from 'node-kms';\nimport jose from 'node-jose';\nimport {omit} from 'lodash';\n\nimport KMSBatcher, {TIMEOUT_SYMBOL} from './kms-batcher';\nimport validateKMS, {KMSError} from './kms-certificate-validation';\n\nconst contexts = new WeakMap();\nconst kmsDetails = new WeakMap();\nconst partialContexts = new WeakMap();\n\nconst consoleDebug = require('debug')('kms');\n\n/**\n * @class\n */\nconst KMS = WebexPlugin.extend({\n namespace: 'Encryption',\n\n children: {\n batcher: KMSBatcher\n },\n\n /**\n * Binds a key to a resource\n * @param {Object} options\n * @param {KMSResourceObject} options.kro\n * @param {string} options.kroUri\n * @param {Key} options.key\n * @param {string} options.keyUri\n * @returns {Promise<Key>}\n */\n bindKey({\n kro, kroUri, key, keyUri\n }) {\n kroUri = kroUri || kro.uri;\n keyUri = keyUri || key.uri;\n\n this.logger.info('kms: binding key to resource');\n\n /* istanbul ignore if */\n if (!kroUri) {\n return Promise.reject(new Error('`kro` or `kroUri` is required'));\n }\n\n /* istanbul ignore if */\n if (!keyUri) {\n return Promise.reject(new Error('`key` or `keyUri` is required'));\n }\n\n return this.request({\n method: 'update',\n resourceUri: kroUri,\n uri: keyUri\n })\n .then((res) => {\n this.logger.info('kms: bound key to resource');\n\n return res.key;\n });\n },\n\n /**\n * Creates a new KMS Resource\n * @param {Object} options\n * @param {Array<string>} options.userIds\n * @param {Array<string>} options.keyUris\n * @param {Key} options.key\n * @param {Array<Keys>} options.keys\n * @returns {Promise<KMSResourceObject>}\n */\n createResource({\n userIds, keyUris, key, keys\n }) {\n keyUris = keyUris || [];\n /* istanbul ignore if */\n if (keys) {\n keyUris = keys.reduce((uris, k) => {\n uris.push(k.uri);\n\n return uris;\n }, keyUris);\n }\n\n /* istanbul ignore else */\n if (key) {\n keyUris.push(key.uri);\n }\n\n /* istanbul ignore if */\n if (keyUris.length === 0) {\n return Promise.reject(new Error('Cannot create KMS Resource without at least one keyUri'));\n }\n\n this.logger.info('kms: creating resource');\n\n return this.request({\n method: 'create',\n uri: '/resources',\n userIds,\n keyUris\n })\n .then((res) => {\n this.logger.info('kms: created resource');\n\n return res.resource;\n });\n },\n\n /**\n * Authorizes a user or KRO to a KRO\n * @param {Object} options\n * @param {Array<string>} options.userIds\n * @param {Array<string>} options.authIds interchangable with userIds\n * @param {KMSResourceObject} options.kro the target kro\n * @param {string} options.kroUri\n * @returns {Promise<KMSAuthorizationObject>}\n */\n addAuthorization({\n userIds, authIds, kro, kroUri\n }) {\n userIds = userIds || [];\n kroUri = kroUri || kro.uri;\n\n if (authIds) {\n userIds = userIds.concat(authIds);\n }\n\n /* istanbul ignore if */\n if (userIds.length === 0) {\n return Promise.reject(new Error('Cannot add authorization without userIds or authIds'));\n }\n\n /* istanbul ignore if */\n if (!kroUri) {\n return Promise.reject(new Error('`kro` or `kroUri` is required'));\n }\n\n this.logger.info('kms: adding authorization to kms resource');\n\n return this.request({\n method: 'create',\n uri: '/authorizations',\n resourceUri: kroUri,\n userIds\n })\n .then((res) => {\n this.logger.info('kms: added authorization');\n\n return res.authorizations;\n });\n },\n\n /**\n * Retrieve a list of users that have been authorized to the KRO\n * @param {Object} options\n * @param {KMSResourceObject} options.kro the target kro\n * @param {string} options.kroUri\n * @returns {Array<authId>}\n */\n listAuthorizations({kro, kroUri}) {\n kroUri = kroUri || kro.uri;\n /* istanbul ignore if */\n if (!kroUri) {\n return Promise.reject(new Error('`kro` or `kroUri` is required'));\n }\n\n return this.request({\n method: 'retrieve',\n uri: `${kroUri}/authorizations`\n })\n .then((res) => {\n this.logger.info('kms: retrieved authorization list');\n\n return res.authorizations;\n });\n },\n\n /**\n * Deauthorizes a user or KRO from a KRO\n * @param {Object} options\n * @param {string} options.userId\n * @param {string} options.authId interchangable with userIds\n * @param {KMSResourceObject} options.kro the target kro\n * @param {string} options.kroUri\n * @returns {Promise<KMSAuthorizationObject>}\n */\n removeAuthorization({\n authId, userId, kro, kroUri\n }) {\n authId = authId || userId;\n kroUri = kroUri || kro.uri;\n\n /* istanbul ignore if */\n if (!authId) {\n return Promise.reject(new Error('Cannot remove authorization without authId'));\n }\n\n /* istanbul ignore if */\n if (!kroUri) {\n return Promise.reject(new Error('`kro` or `kroUri` is required'));\n }\n\n this.logger.info('kms: removing authorization from kms resource');\n\n return this.request({\n method: 'delete',\n uri: `${kroUri}/authorizations?${querystring.stringify({authId})}`\n })\n .then((res) => {\n this.logger.info('kms: removed authorization');\n\n return res.authorizations;\n });\n },\n\n /**\n * Requests `count` unbound keys from the kms\n * @param {Object} options\n * @param {Number} options.count\n * @returns {Array<Key>}\n */\n createUnboundKeys({count}) {\n this.logger.info(`kms: request ${count} unbound keys`);\n\n /* istanbul ignore if */\n if (!count) {\n return Promise.reject(new Error('`options.count` is required'));\n }\n\n return this.request({\n method: 'create',\n uri: '/keys',\n count\n })\n .then((res) => {\n this.logger.info('kms: received unbound keys');\n\n return Promise.all(res.keys.map(this.asKey));\n });\n },\n\n /**\n * Fetches the specified key from the kms\n * @param {Object} options\n * @param {string} options.uri\n * @param {string} options.onBehalfOf The id of a user, upon whose behalf, the key is to be retrieved or undefined if retrieval is for the active user\n * @returns {Promise<Key>}\n */\n // Ideally, this would be done via the kms batcher, but other than request id,\n // there isn't any other userful key in a kms response to match it to a\n // request. as such, we need the batcher to group requests, but one flight to\n // make sure we don't make the same request multiple times.\n @oneFlight({\n keyFactory: ({uri, onBehalfOf}) => `${uri}/${onBehalfOf}`\n })\n fetchKey({uri, onBehalfOf}) {\n /* istanbul ignore if */\n if (!uri) {\n return Promise.reject(new Error('`options.uri` is required'));\n }\n\n this.logger.info('kms: fetching key');\n\n return this.request({\n method: 'retrieve',\n uri\n }, {onBehalfOf})\n .then((res) => {\n this.logger.info('kms: fetched key');\n\n return this.asKey(res.key);\n });\n },\n\n /**\n * Pings the kms. Mostly for testing\n * @returns {Promise}\n */\n ping() {\n return this.request({\n method: 'update',\n uri: '/ping'\n });\n },\n\n /**\n * Ensures a key obect is Key instance\n * @param {Object} key\n * @returns {Promise<Key>}\n */\n asKey(key) {\n return jose.JWK.asKey(key.jwk)\n .then((jwk) => {\n key.jwk = jwk;\n\n return key;\n });\n },\n\n /**\n * Adds appropriate metadata to the KMS request\n * @param {Object} payload\n * @param {Object} onBehalfOf Optional parameter to prepare the request on behalf of another user\n * @returns {Promise<KMS.Request>}\n */\n prepareRequest(payload, onBehalfOf) {\n const isECDHRequest = payload.method === 'create' && payload.uri.includes('/ecdhe');\n\n return Promise.resolve(isECDHRequest ? partialContexts.get(this) : this._getContext())\n .then((context) => {\n this.logger.info(`kms: wrapping ${isECDHRequest ? 'ephemeral key' : 'kms'} request`);\n const req = new Request(payload);\n let requestContext = context;\n\n if (onBehalfOf) {\n requestContext = this._contextOnBehalfOf(context, onBehalfOf);\n }\n\n return req.wrap(requestContext, {serverKey: isECDHRequest})\n .then(() => {\n /* istanbul ignore else */\n if (process.env.NODE_ENV !== 'production') {\n this.logger.info('kms: request payload', util.inspect(omit(JSON.parse(JSON.stringify(req)), 'wrapped'), {depth: null}));\n }\n\n return req;\n });\n });\n },\n\n /**\n * Accepts a kms message event, decrypts it, and passes it to the batcher\n * @param {Object} event\n * @returns {Promise<Object>}\n */\n processKmsMessageEvent(event) {\n this.logger.info('kms: received kms message');\n\n return Promise.all(event.encryption.kmsMessages.map((kmsMessage, index) => this._isECDHEMessage(kmsMessage)\n .then((isECDHMessage) => {\n this.logger.info(`kms: received ${isECDHMessage ? 'ecdhe' : 'normal'} message`);\n const res = new Response(kmsMessage);\n\n return Promise.resolve(isECDHMessage ? partialContexts.get(this) : contexts.get(this))\n // eslint-disable-next-line max-nested-callbacks\n .then((context) => res.unwrap(context))\n // eslint-disable-next-line max-nested-callbacks\n .then(() => {\n if (process.env.NODE_ENV !== 'production') {\n this.logger.info('kms: response payload', util.inspect(omit(JSON.parse(JSON.stringify(res)), 'wrapped'), {depth: null}));\n }\n })\n // eslint-disable-next-line max-nested-callbacks\n .then(() => { event.encryption.kmsMessages[index] = res; })\n // eslint-disable-next-line max-nested-callbacks\n .then(() => res);\n })))\n .then(() => this.batcher.processKmsMessageEvent(event))\n .catch((reason) => {\n this.logger.error('kms: decrypt failed', reason.stack);\n\n return Promise.reject(reason);\n })\n .then(() => event);\n },\n\n /**\n * Decrypts a kms message\n * @param {Object} kmsMessage\n * @returns {Promise<Object>}\n */\n decryptKmsMessage(kmsMessage) {\n const res = new Response(kmsMessage);\n\n return contexts.get(this)\n .then((context) => res.unwrap(context))\n .then(() => res.body);\n },\n\n /**\n * Determines if the kms message is an ecdhe message or a normal message\n * @param {Object} kmsMessage\n * @returns {Promise<boolean>}\n */\n _isECDHEMessage(kmsMessage) {\n return this._getKMSStaticPubKey()\n .then((kmsStaticPubKey) => {\n const fields = kmsMessage.split('.');\n\n if (fields.length !== 3) {\n return false;\n }\n\n const header = JSON.parse(jose.util.base64url.decode(fields[0]));\n\n return header.kid === kmsStaticPubKey.kid;\n });\n },\n\n /**\n * Sends a request to the kms\n * @param {Object} payload\n * @param {Object} options\n * @param {Number} options.timeout (internal)\n * @param {string} options.onBehalfOf Run the request on behalf of another user (UUID), used in compliance scenarios\n * @returns {Promise<Object>}\n */\n request(payload, {timeout, onBehalfOf} = {}) {\n timeout = timeout || this.config.kmsInitialTimeout;\n\n // Note: this should only happen when we're using the async kms batcher;\n // once we implement the sync batcher, this'll need to be smarter.\n return this.webex.internal.mercury.connect()\n .then(() => this.prepareRequest(payload, onBehalfOf))\n .then((req) => {\n req[TIMEOUT_SYMBOL] = timeout;\n\n return this.batcher.request(req);\n })\n // High complexity is due to attempt at test mode resiliency\n // eslint-disable-next-line complexity\n .catch((reason) => {\n if (process.env.NODE_ENV === 'test' && (reason.status === 403 || reason.statusCode === 403) && reason.message.match(/Failed to resolve authorization token in KmsMessage request for user/)) {\n this.logger.warn('kms: rerequested key due to test-mode kms auth failure');\n\n return this.request(payload, {onBehalfOf});\n }\n\n // KMS Error. Notify the user\n if (reason instanceof KMSError) {\n this.webex.trigger('client:InvalidRequestError');\n\n return Promise.reject(reason);\n }\n\n // Ideally, most or all of the code below would go in kms-batcher, but\n // but batching needs at least one more round of refactoring for that to\n // work.\n if (!reason.statusCode && !reason.status) {\n /* istanbul ignore else */\n if (process.env.NODE_ENV !== 'production') {\n /* istanbul ignore next: reason.stack vs stack difficult to control in test */\n this.logger.info('kms: request error', reason.stack || reason);\n }\n\n consoleDebug(`timeout ${timeout}`);\n timeout *= 2;\n\n if (timeout >= this.config.ecdhMaxTimeout) {\n this.logger.info('kms: exceeded maximum KMS request retries');\n\n return Promise.reject(reason);\n }\n\n // Peek ahead to make sure we don't reset the timeout if the next timeout\n // will exceed the maximum timeout for renegotiating ECDH keys.\n const nextTimeout = timeout * 2;\n\n if (timeout >= this.config.kmsMaxTimeout && nextTimeout < this.config.ecdhMaxTimeout) {\n this.logger.info('kms: exceeded maximum KMS request retries; negotiating new ecdh key');\n\n /* istanbul ignore else */\n if (process.env.NODE_ENV !== 'production') {\n this.logger.info('kms: timeout/maxtimeout', timeout, this.config.kmsMaxTimeout);\n }\n\n contexts.delete(this);\n timeout = 0;\n }\n\n return this.request(payload, {timeout, onBehalfOf});\n }\n\n return Promise.reject(reason);\n });\n },\n\n /**\n * @private\n * @returns {Promise<string>}\n */\n _getAuthorization() {\n return this.webex.credentials.getUserToken('spark:kms')\n .then((token) => token.access_token);\n },\n\n @oneFlight\n /**\n * @private\n * @param {String} onBehalfOf create context on behalf of another user, undefined when this is not necessary\n * @returns {Promise<Object>}\n */\n _getContext() {\n let promise = contexts.get(this);\n\n if (!promise) {\n promise = this._prepareContext();\n contexts.set(this, promise);\n promise.then((context) => {\n const expiresIn = context.ephemeralKey.expirationDate - Date.now() - 30000;\n\n safeSetTimeout(() => contexts.delete(this), expiresIn);\n });\n }\n\n return Promise.all([\n promise,\n this._getAuthorization()\n ])\n .then(([context, authorization]) => {\n context.clientInfo.credential.bearer = authorization;\n\n return context;\n });\n },\n\n /**\n * @private\n * @returns {Promise<Object>}\n */\n _getKMSCluster() {\n this.logger.info('kms: retrieving KMS cluster');\n\n return this._getKMSDetails()\n .then(({kmsCluster}) => kmsCluster);\n },\n\n /**\n * @private\n * @returns {Promise<Object>}\n */\n _getKMSDetails() {\n let details = kmsDetails.get(this);\n\n if (!details) {\n this.logger.info('kms: fetching KMS details');\n details = this.webex.request({\n service: 'encryption',\n resource: `/kms/${this.webex.internal.device.userId}`\n })\n .then((res) => {\n this.logger.info('kms: fetched KMS details');\n const {body} = res;\n\n body.rsaPublicKey = JSON.parse(body.rsaPublicKey);\n\n return body;\n })\n .catch((reason) => {\n this.logger.error('kms: failed to fetch KMS details', reason);\n\n return Promise.reject(reason);\n });\n\n kmsDetails.set(this, details);\n }\n\n return details;\n },\n\n /**\n * @private\n * @returns {Promise<Object>}\n */\n _getKMSStaticPubKey() {\n this.logger.info('kms: retrieving KMS static public key');\n\n return this._getKMSDetails()\n .then(({rsaPublicKey}) => rsaPublicKey);\n },\n\n /**\n * @private\n * @returns {Promise<Object>}\n */\n _prepareContext() {\n this.logger.info('kms: creating context');\n const context = new Context();\n\n return Promise.all([\n this._getKMSStaticPubKey().then(validateKMS(this.config.caroots)),\n this._getAuthorization()\n ])\n .then(([kmsStaticPubKey, authorization]) => {\n context.clientInfo = {\n clientId: this.webex.internal.device.url,\n credential: {\n userId: this.webex.internal.device.userId,\n bearer: authorization\n }\n };\n\n context.serverInfo = {\n key: kmsStaticPubKey\n };\n\n this.logger.info('kms: creating local ephemeral key');\n\n return context.createECDHKey();\n })\n .then((localECDHKey) => {\n context.ephemeralKey = localECDHKey;\n partialContexts.set(this, context);\n\n return Promise.all([localECDHKey.asKey(), this._getKMSCluster()]);\n })\n .then(([localECDHKey, cluster]) => {\n this.logger.info('kms: submitting ephemeral key request');\n\n return this.request({\n uri: `${cluster}/ecdhe`,\n method: 'create',\n jwk: localECDHKey.toJSON()\n });\n })\n .then((res) => {\n this.logger.info('kms: deriving final ephemeral key');\n\n return context.deriveEphemeralKey(res.key);\n })\n .then((key) => {\n context.ephemeralKey = key;\n partialContexts.delete(this);\n this.logger.info('kms: derived final ephemeral key');\n\n return context;\n })\n .catch((reason) => {\n this.logger.error('kms: failed to negotiate ephemeral key', reason);\n\n return Promise.reject(reason);\n });\n },\n\n /**\n * KMS 'retrieve' requests can be made on behalf of another user. This is useful\n * for scenarios such as eDiscovery. i.e. Where an authorized compliance officer is\n * entitled to retrieve content generated by any organisational user.\n * As the KMSContext is cached, updating it will affect separate requests. Hence when\n * making a request onBehalfOf another user create a new context for just this request.\n * However this context will be 'light' as it only needs to change one field.\n * @param {Object} originalContext - The base context to 'copy'\n * @param {String} onBehalfOf - The user specified in the new context\n * @returns {Context} A 'copy' of the existing context with a new user specified\n * @private\n */\n _contextOnBehalfOf(originalContext, onBehalfOf) {\n const context = new Context();\n\n context.clientInfo = context.clientInfo = {\n clientId: originalContext.clientInfo.clientId,\n credential: {\n userId: onBehalfOf,\n onBehalfOf, // Supports running onBehalfOf self. i.e. A CO which calls onBehalfOf with CO.id.\n bearer: originalContext.clientInfo.credential.bearer\n }\n };\n context.serverInfo = originalContext.serverInfo;\n context.ephemeralKey = originalContext.ephemeralKey;\n\n return context;\n }\n});\n\nexport default KMS;\n"],"mappings":"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"}
1
+ {"version":3,"names":["contexts","kmsDetails","partialContexts","consoleDebug","require","KMS","WebexPlugin","extend","keyFactory","uri","onBehalfOf","namespace","children","batcher","KMSBatcher","bindKey","kro","kroUri","key","keyUri","logger","info","reject","Error","request","method","resourceUri","then","res","createResource","userIds","keyUris","keys","reduce","uris","k","push","length","resource","addAuthorization","authIds","concat","authorizations","listAuthorizations","removeAuthorization","authId","userId","querystring","stringify","createUnboundKeys","count","all","map","asKey","fetchPublicKey","assignedOrgId","publicKey","uploadCustomerMasterKey","customerMasterKey","requestId","uuid","v4","listAllCustomerMasterKey","changeCustomerMasterKeyState","keyId","keyState","deleteAllCustomerMasterKeys","useGlobalMasterKey","fetchKey","ping","jose","JWK","jwk","prepareRequest","payload","isECDHRequest","includes","resolve","get","_getContext","context","req","Request","requestContext","_contextOnBehalfOf","wrap","serverKey","process","env","NODE_ENV","util","inspect","JSON","parse","depth","processKmsMessageEvent","event","encryption","kmsMessages","kmsMessage","index","_isECDHEMessage","isECDHMessage","Response","unwrap","catch","reason","error","stack","decryptKmsMessage","body","_getKMSStaticPubKey","kmsStaticPubKey","fields","split","header","base64url","decode","kid","timeout","config","kmsInitialTimeout","webex","internal","mercury","connect","TIMEOUT_SYMBOL","status","statusCode","message","match","warn","KMSError","trigger","ecdhMaxTimeout","nextTimeout","kmsMaxTimeout","delete","_getAuthorization","credentials","getUserToken","token","access_token","promise","_prepareContext","set","expiresIn","ephemeralKey","expirationDate","authorization","clientInfo","credential","bearer","_getKMSCluster","_getKMSDetails","kmsCluster","details","service","device","rsaPublicKey","Context","caroots","clientId","url","serverInfo","createECDHKey","localECDHKey","cluster","toJSON","deriveEphemeralKey","originalContext","oneFlight"],"sources":["kms.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport querystring from 'querystring';\nimport util from 'util';\n\nimport {safeSetTimeout} from '@webex/common-timers';\nimport {oneFlight} from '@webex/common';\nimport {WebexPlugin} from '@webex/webex-core';\nimport {Context, Request, Response} from 'node-kms';\nimport jose from 'node-jose';\nimport {omit} from 'lodash';\nimport uuid from 'uuid';\n\nimport KMSBatcher, {TIMEOUT_SYMBOL} from './kms-batcher';\nimport validateKMS, {KMSError} from './kms-certificate-validation';\n\nconst contexts = new WeakMap();\nconst kmsDetails = new WeakMap();\nconst partialContexts = new WeakMap();\n\nconst consoleDebug = require('debug')('kms');\n\n/**\n * @class\n */\nconst KMS = WebexPlugin.extend({\n namespace: 'Encryption',\n\n children: {\n batcher: KMSBatcher\n },\n\n /**\n * Binds a key to a resource\n * @param {Object} options\n * @param {KMSResourceObject} options.kro\n * @param {string} options.kroUri\n * @param {Key} options.key\n * @param {string} options.keyUri\n * @returns {Promise<Key>}\n */\n bindKey({\n kro, kroUri, key, keyUri\n }) {\n kroUri = kroUri || kro.uri;\n keyUri = keyUri || key.uri;\n\n this.logger.info('kms: binding key to resource');\n\n /* istanbul ignore if */\n if (!kroUri) {\n return Promise.reject(new Error('`kro` or `kroUri` is required'));\n }\n\n /* istanbul ignore if */\n if (!keyUri) {\n return Promise.reject(new Error('`key` or `keyUri` is required'));\n }\n\n return this.request({\n method: 'update',\n resourceUri: kroUri,\n uri: keyUri\n })\n .then((res) => {\n this.logger.info('kms: bound key to resource');\n\n return res.key;\n });\n },\n\n /**\n * Creates a new KMS Resource\n * @param {Object} options\n * @param {Array<string>} options.userIds\n * @param {Array<string>} options.keyUris\n * @param {Key} options.key\n * @param {Array<Keys>} options.keys\n * @returns {Promise<KMSResourceObject>}\n */\n createResource({\n userIds, keyUris, key, keys\n }) {\n keyUris = keyUris || [];\n /* istanbul ignore if */\n if (keys) {\n keyUris = keys.reduce((uris, k) => {\n uris.push(k.uri);\n\n return uris;\n }, keyUris);\n }\n\n /* istanbul ignore else */\n if (key) {\n keyUris.push(key.uri);\n }\n\n /* istanbul ignore if */\n if (keyUris.length === 0) {\n return Promise.reject(new Error('Cannot create KMS Resource without at least one keyUri'));\n }\n\n this.logger.info('kms: creating resource');\n\n return this.request({\n method: 'create',\n uri: '/resources',\n userIds,\n keyUris\n })\n .then((res) => {\n this.logger.info('kms: created resource');\n\n return res.resource;\n });\n },\n\n /**\n * Authorizes a user or KRO to a KRO\n * @param {Object} options\n * @param {Array<string>} options.userIds\n * @param {Array<string>} options.authIds interchangable with userIds\n * @param {KMSResourceObject} options.kro the target kro\n * @param {string} options.kroUri\n * @returns {Promise<KMSAuthorizationObject>}\n */\n addAuthorization({\n userIds, authIds, kro, kroUri\n }) {\n userIds = userIds || [];\n kroUri = kroUri || kro.uri;\n\n if (authIds) {\n userIds = userIds.concat(authIds);\n }\n\n /* istanbul ignore if */\n if (userIds.length === 0) {\n return Promise.reject(new Error('Cannot add authorization without userIds or authIds'));\n }\n\n /* istanbul ignore if */\n if (!kroUri) {\n return Promise.reject(new Error('`kro` or `kroUri` is required'));\n }\n\n this.logger.info('kms: adding authorization to kms resource');\n\n return this.request({\n method: 'create',\n uri: '/authorizations',\n resourceUri: kroUri,\n userIds\n })\n .then((res) => {\n this.logger.info('kms: added authorization');\n\n return res.authorizations;\n });\n },\n\n /**\n * Retrieve a list of users that have been authorized to the KRO\n * @param {Object} options\n * @param {KMSResourceObject} options.kro the target kro\n * @param {string} options.kroUri\n * @returns {Array<authId>}\n */\n listAuthorizations({kro, kroUri}) {\n kroUri = kroUri || kro.uri;\n /* istanbul ignore if */\n if (!kroUri) {\n return Promise.reject(new Error('`kro` or `kroUri` is required'));\n }\n\n return this.request({\n method: 'retrieve',\n uri: `${kroUri}/authorizations`\n })\n .then((res) => {\n this.logger.info('kms: retrieved authorization list');\n\n return res.authorizations;\n });\n },\n\n /**\n * Deauthorizes a user or KRO from a KRO\n * @param {Object} options\n * @param {string} options.userId\n * @param {string} options.authId interchangable with userIds\n * @param {KMSResourceObject} options.kro the target kro\n * @param {string} options.kroUri\n * @returns {Promise<KMSAuthorizationObject>}\n */\n removeAuthorization({\n authId, userId, kro, kroUri\n }) {\n authId = authId || userId;\n kroUri = kroUri || kro.uri;\n\n /* istanbul ignore if */\n if (!authId) {\n return Promise.reject(new Error('Cannot remove authorization without authId'));\n }\n\n /* istanbul ignore if */\n if (!kroUri) {\n return Promise.reject(new Error('`kro` or `kroUri` is required'));\n }\n\n this.logger.info('kms: removing authorization from kms resource');\n\n return this.request({\n method: 'delete',\n uri: `${kroUri}/authorizations?${querystring.stringify({authId})}`\n })\n .then((res) => {\n this.logger.info('kms: removed authorization');\n\n return res.authorizations;\n });\n },\n\n /**\n * Requests `count` unbound keys from the kms\n * @param {Object} options\n * @param {Number} options.count\n * @returns {Array<Key>}\n */\n createUnboundKeys({count}) {\n this.logger.info(`kms: request ${count} unbound keys`);\n\n /* istanbul ignore if */\n if (!count) {\n return Promise.reject(new Error('`options.count` is required'));\n }\n\n return this.request({\n method: 'create',\n uri: '/keys',\n count\n })\n .then((res) => {\n this.logger.info('kms: received unbound keys');\n\n return Promise.all(res.keys.map(this.asKey));\n });\n },\n\n /**\n * @typedef {Object} FetchPublicKeyResponse\n * @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)\n * @property {UUID} requestId this is should be unique, used for debug.\n * @property {string} publicKey\n */\n /**\n * get public key from kms\n * @param {Object} options\n * @param {UUID} options.assignedOrgId the orgId\n * @returns {Promise.<FetchPublicKeyResponse>} response of get public key api\n */\n fetchPublicKey({assignedOrgId}) {\n this.logger.info('kms: fetch public key for byok');\n\n return this.request({\n method: 'retrieve',\n uri: '/publicKey',\n assignedOrgId\n })\n .then((res) => {\n this.logger.info('kms: received public key');\n\n return res.publicKey;\n });\n },\n\n /**\n * @typedef {Object} UploadCmkResponse\n * @property {number} status\n * @property {UUID} requestId\n * @property {string} uri\n * @property {string} keysState\n */\n /**\n * upload master key for one org.\n * @param {Object} options\n * @param {UUID} options.assignedOrgId the orgId\n * @param {string} options.customerMasterKey the master key\n * @returns {Promise.<UploadCmkResponse>} response of upload CMK api\n */\n uploadCustomerMasterKey({assignedOrgId, customerMasterKey}) {\n this.logger.info('kms: upload customer master key for byok');\n\n return this.request({\n method: 'create',\n uri: '/cmk',\n assignedOrgId,\n customerMasterKey,\n requestId: uuid.v4()\n }).then((res) => {\n this.logger.info('kms: finish to upload customer master key');\n\n return res;\n });\n },\n\n /**\n * get all customer master keys for one org.\n * @param {Object} options\n * @param {UUID} options.assignedOrgId the orgId\n * @returns {Promise.<ActivateCmkResponse>} response of list CMKs api\n */\n listAllCustomerMasterKey({assignedOrgId}) {\n this.logger.info('kms: get all customer master keys for byok');\n\n return this.request({\n method: 'retrieve',\n uri: '/cmk',\n assignedOrgId,\n requestId: uuid.v4()\n }).then((res) => {\n this.logger.info('kms: finish to get all customer master keys');\n\n return res;\n });\n },\n\n /**\n * @typedef {Object} ActivateCmkResponse\n * @property {number} status\n * @property {UUID} requestId\n * @property {Array<CMK>} customerMasterKeys\n */\n /**\n *\n * @typedef {Object} CMK\n * @property {string} usageState\n * @property {UUID} assignedOrgId\n * @property {string} uri\n * @property {string} source\n * @property {Date | undefined} stateUpdatedOn\n * @property {Date | undefined} rotation\n */\n /**\n * change one customer master key state for one org.\n * delete pending key, then the keyState should be 'removedclean';\n * active pending key, then the keyState should be 'active';\n *\n * @param {Object} options\n * @param {string} options.keyId the id of one customer master key, it should be a url\n * @param {string} options.keyState one of the following: PENDING, RECOVERING,ACTIVE,REVOKED,DEACTIVATED,REENCRYPTING,RETIRED,DELETED,DISABLED,REMOVEDCLEAN,REMOVEDDIRTY;\n * @param {UUID} options.assignedOrgId the orgId\n * @returns {Promise.<ActivateCmkResponse>} response of list CMKs api\n */\n changeCustomerMasterKeyState({keyId, keyState, assignedOrgId}) {\n this.logger.info('kms: change one customer master key state for byok');\n\n return this.request({\n method: 'update',\n uri: keyId,\n keyState,\n assignedOrgId,\n requestId: uuid.v4()\n }).then((res) => {\n this.logger.info('kms: finish to change the customer master key state to {}', keyState);\n\n return res;\n });\n },\n\n /**\n * this is for test case. it will delete all CMKs, no matter what their status is. This is mainly for test purpose\n * @param {Object} options\n * @param {UUID} options.assignedOrgId the orgId\n * @returns {Promise.<{status, requestId}>}\n */\n deleteAllCustomerMasterKeys({assignedOrgId}) {\n this.logger.info('kms: delete all customer master keys at the same time');\n\n return this.request({\n method: 'delete',\n uri: '/cmk',\n assignedOrgId,\n requestId: uuid.v4()\n }).then((res) => {\n this.logger.info('kms: finish to delete all customer master keys');\n\n return res;\n });\n },\n\n /**\n * return to use global master key for one org.\n * @param {Object} options\n * @param {UUID} options.assignedOrgId the orgId\n * @returns {Promise.<ActivateCmkResponse>} response of activate CMK api\n */\n useGlobalMasterKey({assignedOrgId}) {\n this.logger.info('kms: return to use global master key');\n\n return this.request({\n method: 'update',\n uri: 'default',\n keyState: 'ACTIVE',\n assignedOrgId,\n requestId: uuid.v4()\n }).then((res) => {\n this.logger.info('kms: finish to return to global master key');\n\n return res;\n });\n },\n\n /**\n * Fetches the specified key from the kms\n * @param {Object} options\n * @param {string} options.uri\n * @param {string} options.onBehalfOf The id of a user, upon whose behalf, the key is to be retrieved or undefined if retrieval is for the active user\n * @returns {Promise<Key>}\n */\n // Ideally, this would be done via the kms batcher, but other than request id,\n // there isn't any other userful key in a kms response to match it to a\n // request. as such, we need the batcher to group requests, but one flight to\n // make sure we don't make the same request multiple times.\n @oneFlight({\n keyFactory: ({uri, onBehalfOf}) => `${uri}/${onBehalfOf}`\n })\n fetchKey({uri, onBehalfOf}) {\n /* istanbul ignore if */\n if (!uri) {\n return Promise.reject(new Error('`options.uri` is required'));\n }\n\n this.logger.info('kms: fetching key');\n\n return this.request({\n method: 'retrieve',\n uri\n }, {onBehalfOf})\n .then((res) => {\n this.logger.info('kms: fetched key');\n\n return this.asKey(res.key);\n });\n },\n\n /**\n * Pings the kms. Mostly for testing\n * @returns {Promise}\n */\n ping() {\n return this.request({\n method: 'update',\n uri: '/ping'\n });\n },\n\n /**\n * Ensures a key obect is Key instance\n * @param {Object} key\n * @returns {Promise<Key>}\n */\n asKey(key) {\n return jose.JWK.asKey(key.jwk)\n .then((jwk) => {\n key.jwk = jwk;\n\n return key;\n });\n },\n\n /**\n * Adds appropriate metadata to the KMS request\n * @param {Object} payload\n * @param {Object} onBehalfOf Optional parameter to prepare the request on behalf of another user\n * @returns {Promise<KMS.Request>}\n */\n prepareRequest(payload, onBehalfOf) {\n const isECDHRequest = payload.method === 'create' && payload.uri.includes('/ecdhe');\n\n return Promise.resolve(isECDHRequest ? partialContexts.get(this) : this._getContext())\n .then((context) => {\n this.logger.info(`kms: wrapping ${isECDHRequest ? 'ephemeral key' : 'kms'} request`);\n const req = new Request(payload);\n let requestContext = context;\n\n if (onBehalfOf) {\n requestContext = this._contextOnBehalfOf(context, onBehalfOf);\n }\n\n return req.wrap(requestContext, {serverKey: isECDHRequest})\n .then(() => {\n /* istanbul ignore else */\n if (process.env.NODE_ENV !== 'production') {\n this.logger.info('kms: request payload', util.inspect(omit(JSON.parse(JSON.stringify(req)), 'wrapped'), {depth: null}));\n }\n\n return req;\n });\n });\n },\n\n /**\n * Accepts a kms message event, decrypts it, and passes it to the batcher\n * @param {Object} event\n * @returns {Promise<Object>}\n */\n processKmsMessageEvent(event) {\n this.logger.info('kms: received kms message');\n\n return Promise.all(event.encryption.kmsMessages.map((kmsMessage, index) => this._isECDHEMessage(kmsMessage)\n .then((isECDHMessage) => {\n this.logger.info(`kms: received ${isECDHMessage ? 'ecdhe' : 'normal'} message`);\n const res = new Response(kmsMessage);\n\n return Promise.resolve(isECDHMessage ? partialContexts.get(this) : contexts.get(this))\n // eslint-disable-next-line max-nested-callbacks\n .then((context) => res.unwrap(context))\n // eslint-disable-next-line max-nested-callbacks\n .then(() => {\n if (process.env.NODE_ENV !== 'production') {\n this.logger.info('kms: response payload', util.inspect(omit(JSON.parse(JSON.stringify(res)), 'wrapped'), {depth: null}));\n }\n })\n // eslint-disable-next-line max-nested-callbacks\n .then(() => { event.encryption.kmsMessages[index] = res; })\n // eslint-disable-next-line max-nested-callbacks\n .then(() => res);\n })))\n .then(() => this.batcher.processKmsMessageEvent(event))\n .catch((reason) => {\n this.logger.error('kms: decrypt failed', reason.stack);\n\n return Promise.reject(reason);\n })\n .then(() => event);\n },\n\n /**\n * Decrypts a kms message\n * @param {Object} kmsMessage\n * @returns {Promise<Object>}\n */\n decryptKmsMessage(kmsMessage) {\n const res = new Response(kmsMessage);\n\n return contexts.get(this)\n .then((context) => res.unwrap(context))\n .then(() => res.body);\n },\n\n /**\n * Determines if the kms message is an ecdhe message or a normal message\n * @param {Object} kmsMessage\n * @returns {Promise<boolean>}\n */\n _isECDHEMessage(kmsMessage) {\n return this._getKMSStaticPubKey()\n .then((kmsStaticPubKey) => {\n const fields = kmsMessage.split('.');\n\n if (fields.length !== 3) {\n return false;\n }\n\n const header = JSON.parse(jose.util.base64url.decode(fields[0]));\n\n return header.kid === kmsStaticPubKey.kid;\n });\n },\n\n /**\n * Sends a request to the kms\n * @param {Object} payload\n * @param {Object} options\n * @param {Number} options.timeout (internal)\n * @param {string} options.onBehalfOf Run the request on behalf of another user (UUID), used in compliance scenarios\n * @returns {Promise<Object>}\n */\n request(payload, {timeout, onBehalfOf} = {}) {\n timeout = timeout || this.config.kmsInitialTimeout;\n\n // Note: this should only happen when we're using the async kms batcher;\n // once we implement the sync batcher, this'll need to be smarter.\n return this.webex.internal.mercury.connect()\n .then(() => this.prepareRequest(payload, onBehalfOf))\n .then((req) => {\n req[TIMEOUT_SYMBOL] = timeout;\n\n return this.batcher.request(req);\n })\n // High complexity is due to attempt at test mode resiliency\n // eslint-disable-next-line complexity\n .catch((reason) => {\n if (process.env.NODE_ENV === 'test' && (reason.status === 403 || reason.statusCode === 403) && reason.message.match(/Failed to resolve authorization token in KmsMessage request for user/)) {\n this.logger.warn('kms: rerequested key due to test-mode kms auth failure');\n\n return this.request(payload, {onBehalfOf});\n }\n\n // KMS Error. Notify the user\n if (reason instanceof KMSError) {\n this.webex.trigger('client:InvalidRequestError');\n\n return Promise.reject(reason);\n }\n\n // Ideally, most or all of the code below would go in kms-batcher, but\n // but batching needs at least one more round of refactoring for that to\n // work.\n if (!reason.statusCode && !reason.status) {\n /* istanbul ignore else */\n if (process.env.NODE_ENV !== 'production') {\n /* istanbul ignore next: reason.stack vs stack difficult to control in test */\n this.logger.info('kms: request error', reason.stack || reason);\n }\n\n consoleDebug(`timeout ${timeout}`);\n timeout *= 2;\n\n if (timeout >= this.config.ecdhMaxTimeout) {\n this.logger.info('kms: exceeded maximum KMS request retries');\n\n return Promise.reject(reason);\n }\n\n // Peek ahead to make sure we don't reset the timeout if the next timeout\n // will exceed the maximum timeout for renegotiating ECDH keys.\n const nextTimeout = timeout * 2;\n\n if (timeout >= this.config.kmsMaxTimeout && nextTimeout < this.config.ecdhMaxTimeout) {\n this.logger.info('kms: exceeded maximum KMS request retries; negotiating new ecdh key');\n\n /* istanbul ignore else */\n if (process.env.NODE_ENV !== 'production') {\n this.logger.info('kms: timeout/maxtimeout', timeout, this.config.kmsMaxTimeout);\n }\n\n contexts.delete(this);\n timeout = 0;\n }\n\n return this.request(payload, {timeout, onBehalfOf});\n }\n\n return Promise.reject(reason);\n });\n },\n\n /**\n * @private\n * @returns {Promise<string>}\n */\n _getAuthorization() {\n return this.webex.credentials.getUserToken('spark:kms')\n .then((token) => token.access_token);\n },\n\n @oneFlight\n /**\n * @private\n * @param {String} onBehalfOf create context on behalf of another user, undefined when this is not necessary\n * @returns {Promise<Object>}\n */\n _getContext() {\n let promise = contexts.get(this);\n\n if (!promise) {\n promise = this._prepareContext();\n contexts.set(this, promise);\n promise.then((context) => {\n const expiresIn = context.ephemeralKey.expirationDate - Date.now() - 30000;\n\n safeSetTimeout(() => contexts.delete(this), expiresIn);\n });\n }\n\n return Promise.all([\n promise,\n this._getAuthorization()\n ])\n .then(([context, authorization]) => {\n context.clientInfo.credential.bearer = authorization;\n\n return context;\n });\n },\n\n /**\n * @private\n * @returns {Promise<Object>}\n */\n _getKMSCluster() {\n this.logger.info('kms: retrieving KMS cluster');\n\n return this._getKMSDetails()\n .then(({kmsCluster}) => kmsCluster);\n },\n\n /**\n * @private\n * @returns {Promise<Object>}\n */\n _getKMSDetails() {\n let details = kmsDetails.get(this);\n\n if (!details) {\n this.logger.info('kms: fetching KMS details');\n details = this.webex.request({\n service: 'encryption',\n resource: `/kms/${this.webex.internal.device.userId}`\n })\n .then((res) => {\n this.logger.info('kms: fetched KMS details');\n const {body} = res;\n\n body.rsaPublicKey = JSON.parse(body.rsaPublicKey);\n\n return body;\n })\n .catch((reason) => {\n this.logger.error('kms: failed to fetch KMS details', reason);\n\n return Promise.reject(reason);\n });\n\n kmsDetails.set(this, details);\n }\n\n return details;\n },\n\n /**\n * @private\n * @returns {Promise<Object>}\n */\n _getKMSStaticPubKey() {\n this.logger.info('kms: retrieving KMS static public key');\n\n return this._getKMSDetails()\n .then(({rsaPublicKey}) => rsaPublicKey);\n },\n\n /**\n * @private\n * @returns {Promise<Object>}\n */\n _prepareContext() {\n this.logger.info('kms: creating context');\n const context = new Context();\n\n return Promise.all([\n this._getKMSStaticPubKey().then(validateKMS(this.config.caroots)),\n this._getAuthorization()\n ])\n .then(([kmsStaticPubKey, authorization]) => {\n context.clientInfo = {\n clientId: this.webex.internal.device.url,\n credential: {\n userId: this.webex.internal.device.userId,\n bearer: authorization\n }\n };\n\n context.serverInfo = {\n key: kmsStaticPubKey\n };\n\n this.logger.info('kms: creating local ephemeral key');\n\n return context.createECDHKey();\n })\n .then((localECDHKey) => {\n context.ephemeralKey = localECDHKey;\n partialContexts.set(this, context);\n\n return Promise.all([localECDHKey.asKey(), this._getKMSCluster()]);\n })\n .then(([localECDHKey, cluster]) => {\n this.logger.info('kms: submitting ephemeral key request');\n\n return this.request({\n uri: `${cluster}/ecdhe`,\n method: 'create',\n jwk: localECDHKey.toJSON()\n });\n })\n .then((res) => {\n this.logger.info('kms: deriving final ephemeral key');\n\n return context.deriveEphemeralKey(res.key);\n })\n .then((key) => {\n context.ephemeralKey = key;\n partialContexts.delete(this);\n this.logger.info('kms: derived final ephemeral key');\n\n return context;\n })\n .catch((reason) => {\n this.logger.error('kms: failed to negotiate ephemeral key', reason);\n\n return Promise.reject(reason);\n });\n },\n\n /**\n * KMS 'retrieve' requests can be made on behalf of another user. This is useful\n * for scenarios such as eDiscovery. i.e. Where an authorized compliance officer is\n * entitled to retrieve content generated by any organisational user.\n * As the KMSContext is cached, updating it will affect separate requests. Hence when\n * making a request onBehalfOf another user create a new context for just this request.\n * However this context will be 'light' as it only needs to change one field.\n * @param {Object} originalContext - The base context to 'copy'\n * @param {String} onBehalfOf - The user specified in the new context\n * @returns {Context} A 'copy' of the existing context with a new user specified\n * @private\n */\n _contextOnBehalfOf(originalContext, onBehalfOf) {\n const context = new Context();\n\n context.clientInfo = context.clientInfo = {\n clientId: originalContext.clientInfo.clientId,\n credential: {\n userId: onBehalfOf,\n onBehalfOf, // Supports running onBehalfOf self. i.e. A CO which calls onBehalfOf with CO.id.\n bearer: originalContext.clientInfo.credential.bearer\n }\n };\n context.serverInfo = originalContext.serverInfo;\n context.ephemeralKey = originalContext.ephemeralKey;\n\n return context;\n }\n});\n\nexport default KMS;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/internal-plugin-encryption",
3
- "version": "1.161.0",
3
+ "version": "2.2.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "author": "Ian W. Remmel <iremmel@cisco.com>",
@@ -22,21 +22,22 @@
22
22
  "dependencies": {
23
23
  "@babel/runtime-corejs2": "^7.14.8",
24
24
  "lodash": "^4.17.21",
25
- "@webex/webex-core": "1.161.0",
26
- "@webex/common": "1.161.0",
25
+ "@webex/webex-core": "2.2.0",
26
+ "@webex/common": "2.2.0",
27
27
  "node-jose": "^2.0.0",
28
28
  "node-scr": "^0.3.0",
29
- "@webex/common-timers": "1.161.0",
29
+ "@webex/common-timers": "2.2.0",
30
30
  "node-kms": "^0.4.0",
31
+ "uuid": "^3.3.2",
31
32
  "valid-url": "^1.0.9",
32
33
  "asn1js": "^2.0.26",
33
34
  "pkijs": "^2.1.84",
34
35
  "isomorphic-webcrypto": "^2.3.8",
35
36
  "safe-buffer": "^5.2.0",
36
37
  "debug": "^3.2.6",
37
- "@webex/internal-plugin-device": "1.161.0",
38
- "@webex/internal-plugin-mercury": "1.161.0",
39
- "@webex/http-core": "1.161.0",
38
+ "@webex/internal-plugin-device": "2.2.0",
39
+ "@webex/internal-plugin-mercury": "2.2.0",
40
+ "@webex/http-core": "2.2.0",
40
41
  "envify": "^4.1.0"
41
42
  }
42
43
  }
package/src/kms.js CHANGED
@@ -11,6 +11,7 @@ import {WebexPlugin} from '@webex/webex-core';
11
11
  import {Context, Request, Response} from 'node-kms';
12
12
  import jose from 'node-jose';
13
13
  import {omit} from 'lodash';
14
+ import uuid from 'uuid';
14
15
 
15
16
  import KMSBatcher, {TIMEOUT_SYMBOL} from './kms-batcher';
16
17
  import validateKMS, {KMSError} from './kms-certificate-validation';
@@ -250,6 +251,170 @@ const KMS = WebexPlugin.extend({
250
251
  });
251
252
  },
252
253
 
254
+ /**
255
+ * @typedef {Object} FetchPublicKeyResponse
256
+ * @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)
257
+ * @property {UUID} requestId this is should be unique, used for debug.
258
+ * @property {string} publicKey
259
+ */
260
+ /**
261
+ * get public key from kms
262
+ * @param {Object} options
263
+ * @param {UUID} options.assignedOrgId the orgId
264
+ * @returns {Promise.<FetchPublicKeyResponse>} response of get public key api
265
+ */
266
+ fetchPublicKey({assignedOrgId}) {
267
+ this.logger.info('kms: fetch public key for byok');
268
+
269
+ return this.request({
270
+ method: 'retrieve',
271
+ uri: '/publicKey',
272
+ assignedOrgId
273
+ })
274
+ .then((res) => {
275
+ this.logger.info('kms: received public key');
276
+
277
+ return res.publicKey;
278
+ });
279
+ },
280
+
281
+ /**
282
+ * @typedef {Object} UploadCmkResponse
283
+ * @property {number} status
284
+ * @property {UUID} requestId
285
+ * @property {string} uri
286
+ * @property {string} keysState
287
+ */
288
+ /**
289
+ * upload master key for one org.
290
+ * @param {Object} options
291
+ * @param {UUID} options.assignedOrgId the orgId
292
+ * @param {string} options.customerMasterKey the master key
293
+ * @returns {Promise.<UploadCmkResponse>} response of upload CMK api
294
+ */
295
+ uploadCustomerMasterKey({assignedOrgId, customerMasterKey}) {
296
+ this.logger.info('kms: upload customer master key for byok');
297
+
298
+ return this.request({
299
+ method: 'create',
300
+ uri: '/cmk',
301
+ assignedOrgId,
302
+ customerMasterKey,
303
+ requestId: uuid.v4()
304
+ }).then((res) => {
305
+ this.logger.info('kms: finish to upload customer master key');
306
+
307
+ return res;
308
+ });
309
+ },
310
+
311
+ /**
312
+ * get all customer master keys for one org.
313
+ * @param {Object} options
314
+ * @param {UUID} options.assignedOrgId the orgId
315
+ * @returns {Promise.<ActivateCmkResponse>} response of list CMKs api
316
+ */
317
+ listAllCustomerMasterKey({assignedOrgId}) {
318
+ this.logger.info('kms: get all customer master keys for byok');
319
+
320
+ return this.request({
321
+ method: 'retrieve',
322
+ uri: '/cmk',
323
+ assignedOrgId,
324
+ requestId: uuid.v4()
325
+ }).then((res) => {
326
+ this.logger.info('kms: finish to get all customer master keys');
327
+
328
+ return res;
329
+ });
330
+ },
331
+
332
+ /**
333
+ * @typedef {Object} ActivateCmkResponse
334
+ * @property {number} status
335
+ * @property {UUID} requestId
336
+ * @property {Array<CMK>} customerMasterKeys
337
+ */
338
+ /**
339
+ *
340
+ * @typedef {Object} CMK
341
+ * @property {string} usageState
342
+ * @property {UUID} assignedOrgId
343
+ * @property {string} uri
344
+ * @property {string} source
345
+ * @property {Date | undefined} stateUpdatedOn
346
+ * @property {Date | undefined} rotation
347
+ */
348
+ /**
349
+ * change one customer master key state for one org.
350
+ * delete pending key, then the keyState should be 'removedclean';
351
+ * active pending key, then the keyState should be 'active';
352
+ *
353
+ * @param {Object} options
354
+ * @param {string} options.keyId the id of one customer master key, it should be a url
355
+ * @param {string} options.keyState one of the following: PENDING, RECOVERING,ACTIVE,REVOKED,DEACTIVATED,REENCRYPTING,RETIRED,DELETED,DISABLED,REMOVEDCLEAN,REMOVEDDIRTY;
356
+ * @param {UUID} options.assignedOrgId the orgId
357
+ * @returns {Promise.<ActivateCmkResponse>} response of list CMKs api
358
+ */
359
+ changeCustomerMasterKeyState({keyId, keyState, assignedOrgId}) {
360
+ this.logger.info('kms: change one customer master key state for byok');
361
+
362
+ return this.request({
363
+ method: 'update',
364
+ uri: keyId,
365
+ keyState,
366
+ assignedOrgId,
367
+ requestId: uuid.v4()
368
+ }).then((res) => {
369
+ this.logger.info('kms: finish to change the customer master key state to {}', keyState);
370
+
371
+ return res;
372
+ });
373
+ },
374
+
375
+ /**
376
+ * this is for test case. it will delete all CMKs, no matter what their status is. This is mainly for test purpose
377
+ * @param {Object} options
378
+ * @param {UUID} options.assignedOrgId the orgId
379
+ * @returns {Promise.<{status, requestId}>}
380
+ */
381
+ deleteAllCustomerMasterKeys({assignedOrgId}) {
382
+ this.logger.info('kms: delete all customer master keys at the same time');
383
+
384
+ return this.request({
385
+ method: 'delete',
386
+ uri: '/cmk',
387
+ assignedOrgId,
388
+ requestId: uuid.v4()
389
+ }).then((res) => {
390
+ this.logger.info('kms: finish to delete all customer master keys');
391
+
392
+ return res;
393
+ });
394
+ },
395
+
396
+ /**
397
+ * return to use global master key for one org.
398
+ * @param {Object} options
399
+ * @param {UUID} options.assignedOrgId the orgId
400
+ * @returns {Promise.<ActivateCmkResponse>} response of activate CMK api
401
+ */
402
+ useGlobalMasterKey({assignedOrgId}) {
403
+ this.logger.info('kms: return to use global master key');
404
+
405
+ return this.request({
406
+ method: 'update',
407
+ uri: 'default',
408
+ keyState: 'ACTIVE',
409
+ assignedOrgId,
410
+ requestId: uuid.v4()
411
+ }).then((res) => {
412
+ this.logger.info('kms: finish to return to global master key');
413
+
414
+ return res;
415
+ });
416
+ },
417
+
253
418
  /**
254
419
  * Fetches the specified key from the kms
255
420
  * @param {Object} options
@@ -1,3 +1,4 @@
1
+ /* eslint-env browser */
1
2
  /*!
2
3
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
4
  */
@@ -9,6 +10,7 @@ import sinon from 'sinon';
9
10
  import WebexCore from '@webex/webex-core';
10
11
  import testUsers from '@webex/test-helper-test-users';
11
12
  import uuid from 'uuid';
13
+ import {skipInBrowser} from '@webex/test-helper-mocha';
12
14
 
13
15
  const debug = require('debug')('kms');
14
16
 
@@ -17,7 +19,30 @@ describe('Encryption', function () {
17
19
  describe('KMS', () => {
18
20
  let mccoy, webex, spock;
19
21
 
20
- before('create test user', () => testUsers.create({count: 2})
22
+ function str2ab(str) {
23
+ const buf = new ArrayBuffer(str.length);
24
+ const bufView = new Uint8Array(buf);
25
+
26
+ for (let i = 0, strLen = str.length; i < strLen; i += 1) {
27
+ bufView[i] = str.charCodeAt(i);
28
+ }
29
+
30
+ return buf;
31
+ }
32
+
33
+ function arrayBufferToBase64(buffer) {
34
+ let binary = '';
35
+ const bytes = new Uint8Array(buffer);
36
+ const len = bytes.byteLength;
37
+
38
+ for (let i = 0; i < len; i += 1) {
39
+ binary += String.fromCharCode(bytes[i]);
40
+ }
41
+
42
+ return window.btoa(binary);
43
+ }
44
+
45
+ before('create test user', () => testUsers.create({count: 2, config: {roles: [{name: 'id_full_admin'}]}})
21
46
  .then((users) => {
22
47
  spock = users[0];
23
48
  webex = new WebexCore({
@@ -314,6 +339,65 @@ describe('Encryption', function () {
314
339
  }));
315
340
  });
316
341
 
342
+ describe('upload customer master key', () => {
343
+ let uploadedkeyId;
344
+
345
+ /* eslint-disable no-unused-expressions */
346
+ skipInBrowser(it)('upload customer master key', () => (webex.internal.encryption.kms.deleteAllCustomerMasterKeys({assignedOrgId: spock.orgId})
347
+ .then(() => webex.internal.encryption.kms.fetchPublicKey({assignedOrgId: spock.orgId}))
348
+ .then((publicKey) => {
349
+ assert.isNotEmpty(publicKey);
350
+ const pemHeader = '-----BEGIN PUBLIC KEY-----';
351
+ const pemFooter = '-----END PUBLIC KEY-----';
352
+ const publicContent = publicKey.substring(pemHeader.length, publicKey.length - pemFooter.length);
353
+ const binaryDerString = window.atob(publicContent);
354
+ // convert from a binary string to an ArrayBuffer
355
+ const binaryDer = str2ab(binaryDerString);
356
+
357
+ return window.crypto.subtle.importKey(
358
+ 'spki',
359
+ binaryDer,
360
+ {
361
+ name: 'RSA-OAEP',
362
+ hash: 'SHA-256'
363
+ },
364
+ true,
365
+ ['encrypt']
366
+ );
367
+ })
368
+ .then((publicKey) => {
369
+ const buf = window.crypto.getRandomValues(new Uint8Array(16));
370
+
371
+ return window.crypto.subtle.encrypt(
372
+ {
373
+ name: 'RSA-OAEP'
374
+ },
375
+ publicKey,
376
+ buf
377
+ );
378
+ })
379
+ .then((encryptedData) => webex.internal.encryption.kms.uploadCustomerMasterKey({assignedOrgId: spock.orgId, customerMasterKey: arrayBufferToBase64(encryptedData)}))
380
+ .then((uploadRes) => {
381
+ uploadedkeyId = uploadRes.customerMasterKeys[0].uri;
382
+
383
+ return webex.internal.encryption.kms.listAllCustomerMasterKey({assignedOrgId: spock.orgId});
384
+ })
385
+ .then((listCmksRes) => {
386
+ const cmks = listCmksRes.customerMasterKeys;
387
+ const uploadedCmk = cmks.find((cmk) => cmk.uri === uploadedkeyId);
388
+
389
+ expect(uploadedCmk).to.not.be.null;
390
+
391
+ return webex.internal.encryption.kms.changeCustomerMasterKeyState({keyId: uploadedkeyId, keyState: 'ACTIVE', assignedOrgId: spock.orgId});
392
+ })
393
+ .then((activeRes) => {
394
+ expect(activeRes.customerMasterKeys[0].usageState).to.have.string('ACTIVE');
395
+
396
+ // return webex.internal.encryption.kms.useGlobalMasterKey({assignedOrgId: spock.orgId});
397
+ return webex.internal.encryption.kms.deleteAllCustomerMasterKeys({assignedOrgId: spock.orgId});
398
+ })));
399
+ });
400
+
317
401
  describe('#fetchKey()', () => {
318
402
  let key;
319
403