@webex/internal-plugin-encryption 3.0.0-beta.4 → 3.0.0-beta.400
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -3
- package/dist/config.js +0 -9
- package/dist/config.js.map +1 -1
- package/dist/constants.js +14 -0
- package/dist/constants.js.map +1 -0
- package/dist/encryption.js +25 -74
- 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 +7 -30
- package/dist/kms-batcher.js.map +1 -1
- package/dist/kms-certificate-validation.js +24 -90
- 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 +21 -51
- package/dist/kms-errors.js.map +1 -1
- package/dist/kms.js +88 -218
- package/dist/kms.js.map +1 -1
- package/package.json +15 -15
- package/src/config.js +3 -3
- package/src/constants.js +3 -0
- package/src/encryption.js +74 -57
- 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 +53 -45
- package/src/kms-certificate-validation.js +48 -50
- package/src/kms-dry-error-interceptor.js +8 -4
- package/src/kms-errors.js +47 -16
- package/src/kms.js +219 -212
- package/test/integration/spec/encryption.js +313 -231
- package/test/integration/spec/kms.js +532 -405
- package/test/integration/spec/payload-transfom.js +69 -69
- package/test/unit/spec/encryption.js +21 -18
- package/test/unit/spec/kms-certificate-validation.js +76 -34
- package/test/unit/spec/kms-errors.js +70 -0
- package/test/unit/spec/kms.js +103 -0
|
@@ -1,67 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _Reflect$construct = require("@babel/runtime-corejs2/core-js/reflect/construct");
|
|
4
|
-
|
|
5
4
|
var _Array$from = require("@babel/runtime-corejs2/core-js/array/from");
|
|
6
|
-
|
|
7
5
|
var _Symbol = require("@babel/runtime-corejs2/core-js/symbol");
|
|
8
|
-
|
|
9
6
|
var _Symbol$iterator = require("@babel/runtime-corejs2/core-js/symbol/iterator");
|
|
10
|
-
|
|
11
7
|
var _Array$isArray = require("@babel/runtime-corejs2/core-js/array/is-array");
|
|
12
|
-
|
|
13
8
|
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
14
|
-
|
|
15
9
|
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
16
|
-
|
|
17
10
|
_Object$defineProperty(exports, "__esModule", {
|
|
18
11
|
value: true
|
|
19
12
|
});
|
|
20
|
-
|
|
21
|
-
exports.default = exports.KMSError = void 0;
|
|
22
|
-
|
|
13
|
+
exports.validateCommonName = exports.default = exports.X509_SUBJECT_ALT_NAME_KEY = exports.KMSError = void 0;
|
|
23
14
|
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
|
|
24
|
-
|
|
25
15
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/slicedToArray"));
|
|
26
|
-
|
|
27
16
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
|
|
28
|
-
|
|
29
17
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
|
|
30
|
-
|
|
31
18
|
var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/inherits"));
|
|
32
|
-
|
|
33
19
|
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/possibleConstructorReturn"));
|
|
34
|
-
|
|
35
20
|
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/getPrototypeOf"));
|
|
36
|
-
|
|
37
21
|
var _wrapNativeSuper2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/wrapNativeSuper"));
|
|
38
|
-
|
|
39
22
|
var _isArray2 = _interopRequireDefault(require("lodash/isArray"));
|
|
40
|
-
|
|
41
23
|
var _url = require("url");
|
|
42
|
-
|
|
43
24
|
var _validUrl = require("valid-url");
|
|
44
|
-
|
|
45
25
|
var _asn1js = require("asn1js");
|
|
46
|
-
|
|
47
26
|
var _pkijs = require("pkijs");
|
|
48
|
-
|
|
49
27
|
var _nodeJose = _interopRequireDefault(require("node-jose"));
|
|
50
|
-
|
|
51
28
|
var _isomorphicWebcrypto = _interopRequireDefault(require("isomorphic-webcrypto"));
|
|
52
|
-
|
|
53
29
|
var _safeBuffer = require("safe-buffer");
|
|
54
|
-
|
|
55
30
|
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof _Symbol !== "undefined" && o[_Symbol$iterator] || o["@@iterator"]; if (!it) { if (_Array$isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
56
|
-
|
|
57
31
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return _Array$from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
58
|
-
|
|
59
|
-
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
60
|
-
|
|
32
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
61
33
|
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = _Reflect$construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
|
|
62
|
-
|
|
63
34
|
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !_Reflect$construct) return false; if (_Reflect$construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
64
|
-
|
|
65
35
|
(0, _pkijs.setEngine)('newEngine', _isomorphicWebcrypto.default, new _pkijs.CryptoEngine({
|
|
66
36
|
name: '',
|
|
67
37
|
crypto: _isomorphicWebcrypto.default,
|
|
@@ -71,57 +41,50 @@ var VALID_KTY = 'RSA';
|
|
|
71
41
|
var VALID_KID_PROTOCOL = 'kms:';
|
|
72
42
|
var X509_COMMON_NAME_KEY = '2.5.4.3';
|
|
73
43
|
var X509_SUBJECT_ALT_NAME_KEY = '2.5.29.17';
|
|
44
|
+
|
|
74
45
|
/**
|
|
75
46
|
* Customize Error so the SDK knows to quit retrying and notify
|
|
76
47
|
* the user
|
|
77
48
|
*/
|
|
78
|
-
|
|
49
|
+
exports.X509_SUBJECT_ALT_NAME_KEY = X509_SUBJECT_ALT_NAME_KEY;
|
|
79
50
|
var KMSError = /*#__PURE__*/function (_Error) {
|
|
80
51
|
(0, _inherits2.default)(KMSError, _Error);
|
|
81
|
-
|
|
82
52
|
var _super = _createSuper(KMSError);
|
|
83
|
-
|
|
84
53
|
/**
|
|
85
54
|
* add kmsError field to notify
|
|
86
55
|
* @param {string} message
|
|
87
56
|
*/
|
|
88
57
|
function KMSError(message) {
|
|
89
58
|
var _this;
|
|
90
|
-
|
|
91
59
|
(0, _classCallCheck2.default)(this, KMSError);
|
|
92
60
|
_this = _super.call(this, message);
|
|
93
61
|
_this.kmsError = true;
|
|
94
62
|
return _this;
|
|
95
63
|
}
|
|
96
|
-
|
|
97
64
|
return (0, _createClass2.default)(KMSError);
|
|
98
65
|
}( /*#__PURE__*/(0, _wrapNativeSuper2.default)(Error));
|
|
99
|
-
|
|
100
66
|
exports.KMSError = KMSError;
|
|
101
|
-
|
|
102
67
|
var throwError = function throwError(err) {
|
|
103
68
|
throw new KMSError("INVALID KMS: ".concat(err));
|
|
104
69
|
};
|
|
70
|
+
|
|
105
71
|
/**
|
|
106
72
|
* Converts the PEM string to a pkijs certificate object
|
|
107
73
|
* @param {string} pem PEM representation of a certificate
|
|
108
74
|
* @returns {Certificate} pkijs object of the certificate
|
|
109
75
|
*/
|
|
110
|
-
|
|
111
|
-
|
|
112
76
|
var decodeCert = function decodeCert(pem) {
|
|
113
77
|
if (typeof pem !== 'string') {
|
|
114
78
|
throwError('certificate needs to be a string');
|
|
115
79
|
}
|
|
116
|
-
|
|
117
80
|
var der = _safeBuffer.Buffer.from(pem, 'base64');
|
|
118
|
-
|
|
119
81
|
var ber = new Uint8Array(der).buffer;
|
|
120
82
|
var asn1 = (0, _asn1js.fromBER)(ber);
|
|
121
83
|
return new _pkijs.Certificate({
|
|
122
84
|
schema: asn1.result
|
|
123
85
|
});
|
|
124
86
|
};
|
|
87
|
+
|
|
125
88
|
/**
|
|
126
89
|
* Validate the 'kty' property of the KMS credentials
|
|
127
90
|
* @param {Object} JWT KMS credentials
|
|
@@ -129,27 +92,22 @@ var decodeCert = function decodeCert(pem) {
|
|
|
129
92
|
* @throws {KMSError} if kty is not a valid type
|
|
130
93
|
* @returns {void}
|
|
131
94
|
*/
|
|
132
|
-
|
|
133
|
-
|
|
134
95
|
var validateKtyHeader = function validateKtyHeader(_ref) {
|
|
135
96
|
var kty = _ref.kty;
|
|
136
|
-
|
|
137
97
|
if (kty !== VALID_KTY) {
|
|
138
98
|
throwError("'kty' header must be '".concat(VALID_KTY, "'"));
|
|
139
99
|
}
|
|
140
100
|
};
|
|
141
|
-
|
|
142
101
|
var validateKidHeader = function validateKidHeader(_ref2) {
|
|
143
102
|
var kid = _ref2.kid;
|
|
144
|
-
|
|
145
103
|
if (!(0, _validUrl.isUri)(kid)) {
|
|
146
|
-
throwError('
|
|
104
|
+
throwError("'kid' is not a valid URI");
|
|
147
105
|
}
|
|
148
|
-
|
|
149
106
|
if ((0, _url.parse)(kid).protocol !== VALID_KID_PROTOCOL) {
|
|
150
107
|
throwError("'kid' protocol must be '".concat(VALID_KID_PROTOCOL, "'"));
|
|
151
108
|
}
|
|
152
109
|
};
|
|
110
|
+
|
|
153
111
|
/**
|
|
154
112
|
* Checks the first certificate matches the 'kid' in the JWT.
|
|
155
113
|
* It first checks the Subject Alternative Name then it checks
|
|
@@ -160,37 +118,28 @@ var validateKidHeader = function validateKidHeader(_ref2) {
|
|
|
160
118
|
* @throws {KMSError} if unable to validate certificate against KMS credentials
|
|
161
119
|
* @returns {void}
|
|
162
120
|
*/
|
|
163
|
-
|
|
164
|
-
|
|
165
121
|
var validateCommonName = function validateCommonName(_ref3, _ref4) {
|
|
166
122
|
var _ref5 = (0, _slicedToArray2.default)(_ref3, 1),
|
|
167
|
-
|
|
168
|
-
|
|
123
|
+
certificate = _ref5[0];
|
|
169
124
|
var kid = _ref4.kid;
|
|
170
125
|
var kidHostname = (0, _url.parse)(kid).hostname;
|
|
171
126
|
var validationSuccessful = false;
|
|
172
|
-
|
|
173
127
|
if (certificate.extensions) {
|
|
174
128
|
// Subject Alt Names are in here
|
|
175
129
|
var _iterator = _createForOfIteratorHelper(certificate.extensions),
|
|
176
|
-
|
|
177
|
-
|
|
130
|
+
_step;
|
|
178
131
|
try {
|
|
179
132
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
180
133
|
var extension = _step.value;
|
|
181
|
-
|
|
182
134
|
if (extension.extnID === X509_SUBJECT_ALT_NAME_KEY) {
|
|
183
135
|
var altNames = extension.parsedValue.altNames;
|
|
184
|
-
|
|
185
136
|
var _iterator2 = _createForOfIteratorHelper(altNames),
|
|
186
|
-
|
|
187
|
-
|
|
137
|
+
_step2;
|
|
188
138
|
try {
|
|
189
139
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
190
140
|
var entry = _step2.value;
|
|
191
|
-
var san = entry.value;
|
|
141
|
+
var san = entry.value.toLowerCase();
|
|
192
142
|
validationSuccessful = san === kidHostname;
|
|
193
|
-
|
|
194
143
|
if (validationSuccessful) {
|
|
195
144
|
break;
|
|
196
145
|
}
|
|
@@ -200,7 +149,6 @@ var validateCommonName = function validateCommonName(_ref3, _ref4) {
|
|
|
200
149
|
} finally {
|
|
201
150
|
_iterator2.f();
|
|
202
151
|
}
|
|
203
|
-
|
|
204
152
|
if (validationSuccessful) {
|
|
205
153
|
break;
|
|
206
154
|
}
|
|
@@ -212,22 +160,17 @@ var validateCommonName = function validateCommonName(_ref3, _ref4) {
|
|
|
212
160
|
_iterator.f();
|
|
213
161
|
}
|
|
214
162
|
}
|
|
215
|
-
|
|
216
163
|
if (!validationSuccessful) {
|
|
217
164
|
// Didn't match kid in the Subject Alt Names, checking the Common Name
|
|
218
165
|
var subjectAttributes = certificate.subject.typesAndValues;
|
|
219
|
-
|
|
220
166
|
var _iterator3 = _createForOfIteratorHelper(subjectAttributes),
|
|
221
|
-
|
|
222
|
-
|
|
167
|
+
_step3;
|
|
223
168
|
try {
|
|
224
169
|
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
225
170
|
var attribute = _step3.value;
|
|
226
|
-
|
|
227
171
|
if (attribute.type === X509_COMMON_NAME_KEY) {
|
|
228
172
|
var commonName = attribute.value.valueBlock.value;
|
|
229
173
|
validationSuccessful = commonName === kidHostname;
|
|
230
|
-
|
|
231
174
|
if (validationSuccessful) {
|
|
232
175
|
break;
|
|
233
176
|
}
|
|
@@ -239,11 +182,11 @@ var validateCommonName = function validateCommonName(_ref3, _ref4) {
|
|
|
239
182
|
_iterator3.f();
|
|
240
183
|
}
|
|
241
184
|
}
|
|
242
|
-
|
|
243
185
|
if (!validationSuccessful) {
|
|
244
|
-
throwError(
|
|
186
|
+
throwError("hostname of the 1st certificate does not match 'kid'");
|
|
245
187
|
}
|
|
246
188
|
};
|
|
189
|
+
|
|
247
190
|
/**
|
|
248
191
|
* Validate the first KMS certificate against the information
|
|
249
192
|
* provided in the JWT
|
|
@@ -254,14 +197,12 @@ var validateCommonName = function validateCommonName(_ref3, _ref4) {
|
|
|
254
197
|
* @throws {KMSError} if e or n doesn't match the first certificate
|
|
255
198
|
* @returns {void}
|
|
256
199
|
*/
|
|
257
|
-
|
|
258
|
-
|
|
200
|
+
exports.validateCommonName = validateCommonName;
|
|
259
201
|
var validatePublicCertificate = function validatePublicCertificate(_ref6, _ref7) {
|
|
260
202
|
var _ref8 = (0, _slicedToArray2.default)(_ref6, 1),
|
|
261
|
-
|
|
262
|
-
|
|
203
|
+
certificate = _ref8[0];
|
|
263
204
|
var publicExponent = _ref7.e,
|
|
264
|
-
|
|
205
|
+
modulus = _ref7.n;
|
|
265
206
|
var encode = _nodeJose.default.util.base64url.encode;
|
|
266
207
|
var publicKey = certificate.subjectPublicKeyInfo.subjectPublicKey;
|
|
267
208
|
var asn1PublicCert = (0, _asn1js.fromBER)(publicKey.valueBlock.valueHex);
|
|
@@ -270,15 +211,14 @@ var validatePublicCertificate = function validatePublicCertificate(_ref6, _ref7)
|
|
|
270
211
|
});
|
|
271
212
|
var publicExponentHex = publicCert.publicExponent.valueBlock.valueHex;
|
|
272
213
|
var modulusHex = publicCert.modulus.valueBlock.valueHex;
|
|
273
|
-
|
|
274
214
|
if (publicExponent !== encode(publicExponentHex)) {
|
|
275
215
|
throwError('Public exponent is invalid');
|
|
276
216
|
}
|
|
277
|
-
|
|
278
217
|
if (modulus !== encode(modulusHex)) {
|
|
279
218
|
throwError('Modulus is invalid');
|
|
280
219
|
}
|
|
281
220
|
};
|
|
221
|
+
|
|
282
222
|
/**
|
|
283
223
|
* Validates the list of certificates against the CAs provided
|
|
284
224
|
* @param {certificate[]} certificates list of certificates provided
|
|
@@ -287,8 +227,6 @@ var validatePublicCertificate = function validatePublicCertificate(_ref6, _ref7)
|
|
|
287
227
|
* validate the KMS's certificates
|
|
288
228
|
* @returns {Promise} rejects if unable to validate the certificates
|
|
289
229
|
*/
|
|
290
|
-
|
|
291
|
-
|
|
292
230
|
var validateCertificatesSignature = function validateCertificatesSignature(certificates) {
|
|
293
231
|
var caroots = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
294
232
|
var certificateEngine = new _pkijs.CertificateChainValidationEngine({
|
|
@@ -297,14 +235,14 @@ var validateCertificatesSignature = function validateCertificatesSignature(certi
|
|
|
297
235
|
});
|
|
298
236
|
return certificateEngine.verify().then(function (_ref9) {
|
|
299
237
|
var result = _ref9.result,
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
238
|
+
resultCode = _ref9.resultCode,
|
|
239
|
+
resultMessage = _ref9.resultMessage;
|
|
303
240
|
if (!result) {
|
|
304
241
|
throwError("Certificate Validation failed [".concat(resultCode, "]: ").concat(resultMessage));
|
|
305
242
|
}
|
|
306
243
|
});
|
|
307
244
|
};
|
|
245
|
+
|
|
308
246
|
/**
|
|
309
247
|
* Validates the information provided by the KMS. This is a curried function.
|
|
310
248
|
* The first function takes the caroots param and returns a second function.
|
|
@@ -315,23 +253,20 @@ var validateCertificatesSignature = function validateCertificatesSignature(certi
|
|
|
315
253
|
* validate the KMS
|
|
316
254
|
* @returns {Promise} when resolved will return the jwt
|
|
317
255
|
*/
|
|
318
|
-
|
|
319
|
-
|
|
320
256
|
var validateKMS = function validateKMS(caroots) {
|
|
321
257
|
return function () {
|
|
322
258
|
var jwt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
323
259
|
return _promise.default.resolve().then(function () {
|
|
324
260
|
validateKtyHeader(jwt);
|
|
325
261
|
validateKidHeader(jwt);
|
|
326
|
-
|
|
327
262
|
if (!((0, _isArray2.default)(jwt.x5c) && jwt.x5c.length > 0)) {
|
|
328
263
|
throwError('JWK does not contain a list of certificates');
|
|
329
264
|
}
|
|
330
|
-
|
|
331
265
|
var certificates = jwt.x5c.map(decodeCert);
|
|
332
266
|
validateCommonName(certificates, jwt);
|
|
333
|
-
validatePublicCertificate(certificates, jwt);
|
|
267
|
+
validatePublicCertificate(certificates, jwt);
|
|
334
268
|
|
|
269
|
+
// Skip validating signatures if no CA roots were provided
|
|
335
270
|
var promise = caroots ? validateCertificatesSignature(certificates, caroots) : _promise.default.resolve();
|
|
336
271
|
return promise.then(function () {
|
|
337
272
|
return jwt;
|
|
@@ -339,7 +274,6 @@ var validateKMS = function validateKMS(caroots) {
|
|
|
339
274
|
});
|
|
340
275
|
};
|
|
341
276
|
};
|
|
342
|
-
|
|
343
277
|
var _default = validateKMS;
|
|
344
278
|
exports.default = _default;
|
|
345
279
|
//# sourceMappingURL=kms-certificate-validation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["setEngine","crypto","CryptoEngine","name","subtle","VALID_KTY","VALID_KID_PROTOCOL","X509_COMMON_NAME_KEY","X509_SUBJECT_ALT_NAME_KEY","KMSError","message","kmsError","Error","throwError","err","decodeCert","pem","der","Buffer","from","ber","Uint8Array","buffer","asn1","fromBER","Certificate","schema","result","validateKtyHeader","kty","validateKidHeader","kid","isUri","parseUrl","protocol","validateCommonName","certificate","kidHostname","hostname","validationSuccessful","extensions","extension","extnID","altNames","parsedValue","entry","san","value","subjectAttributes","subject","typesAndValues","attribute","type","commonName","valueBlock","validatePublicCertificate","publicExponent","e","modulus","n","encode","jose","util","base64url","publicKey","subjectPublicKeyInfo","subjectPublicKey","asn1PublicCert","valueHex","publicCert","RSAPublicKey","publicExponentHex","modulusHex","validateCertificatesSignature","certificates","caroots","certificateEngine","CertificateChainValidationEngine","trustedCerts","map","certs","verify","then","resultCode","resultMessage","validateKMS","jwt","resolve","x5c","length","promise"],"sources":["kms-certificate-validation.js"],"sourcesContent":["import {parse as parseUrl} from 'url';\n\nimport {isUri} from 'valid-url';\nimport {fromBER} from 'asn1js';\nimport {\n Certificate,\n RSAPublicKey,\n CertificateChainValidationEngine,\n CryptoEngine,\n setEngine\n} from 'pkijs';\nimport {isArray} from 'lodash';\nimport jose from 'node-jose';\nimport crypto from 'isomorphic-webcrypto';\nimport {Buffer} from 'safe-buffer';\n\nsetEngine(\n 'newEngine',\n crypto,\n new CryptoEngine({\n name: '',\n crypto,\n subtle: crypto.subtle\n })\n);\n\nconst VALID_KTY = 'RSA';\nconst VALID_KID_PROTOCOL = 'kms:';\n\nconst X509_COMMON_NAME_KEY = '2.5.4.3';\n\nconst X509_SUBJECT_ALT_NAME_KEY = '2.5.29.17';\n\n/**\n * Customize Error so the SDK knows to quit retrying and notify\n * the user\n */\nexport class KMSError extends Error {\n /**\n * add kmsError field to notify\n * @param {string} message\n */\n constructor(message) {\n super(message);\n this.kmsError = true;\n }\n}\n\nconst throwError = (err) => {\n throw new KMSError(`INVALID KMS: ${err}`);\n};\n\n/**\n * Converts the PEM string to a pkijs certificate object\n * @param {string} pem PEM representation of a certificate\n * @returns {Certificate} pkijs object of the certificate\n */\nconst decodeCert = (pem) => {\n if (typeof pem !== 'string') {\n throwError('certificate needs to be a string');\n }\n\n const der = Buffer.from(pem, 'base64');\n const ber = new Uint8Array(der).buffer;\n\n const asn1 = fromBER(ber);\n\n return new Certificate({schema: asn1.result});\n};\n\n/**\n * Validate the 'kty' property of the KMS credentials\n * @param {Object} JWT KMS credentials\n * @param {string} JWT.kty type of certificate\n * @throws {KMSError} if kty is not a valid type\n * @returns {void}\n */\nconst validateKtyHeader = ({kty}) => {\n if (kty !== VALID_KTY) {\n throwError(`'kty' header must be '${VALID_KTY}'`);\n }\n};\n\nconst validateKidHeader = ({kid}) => {\n if (!isUri(kid)) {\n throwError('\\'kid\\' is not a valid URI');\n }\n\n if (parseUrl(kid).protocol !== VALID_KID_PROTOCOL) {\n throwError(`'kid' protocol must be '${VALID_KID_PROTOCOL}'`);\n }\n};\n\n/**\n * Checks the first certificate matches the 'kid' in the JWT.\n * It first checks the Subject Alternative Name then it checks\n * the Common Name\n * @param {Certificate} certificate represents the KMS\n * @param {Object} JWT KMS credentials\n * @param {string} JWT.kid the uri of the KMS\n * @throws {KMSError} if unable to validate certificate against KMS credentials\n * @returns {void}\n */\nconst validateCommonName = ([certificate], {kid}) => {\n const kidHostname = parseUrl(kid).hostname;\n let validationSuccessful = false;\n\n if (certificate.extensions) {\n // Subject Alt Names are in here\n for (const extension of certificate.extensions) {\n if (extension.extnID === X509_SUBJECT_ALT_NAME_KEY) {\n const {altNames} = extension.parsedValue;\n\n for (const entry of altNames) {\n const san = entry.value;\n\n validationSuccessful = san === kidHostname;\n if (validationSuccessful) {\n break;\n }\n }\n\n if (validationSuccessful) {\n break;\n }\n }\n }\n }\n\n if (!validationSuccessful) {\n // Didn't match kid in the Subject Alt Names, checking the Common Name\n const subjectAttributes = certificate.subject.typesAndValues;\n\n for (const attribute of subjectAttributes) {\n if (attribute.type === X509_COMMON_NAME_KEY) {\n const commonName = attribute.value.valueBlock.value;\n\n validationSuccessful = commonName === kidHostname;\n if (validationSuccessful) {\n break;\n }\n }\n }\n }\n\n if (!validationSuccessful) {\n throwError('hostname of the 1st certificate does not match \\'kid\\'');\n }\n};\n\n/**\n * Validate the first KMS certificate against the information\n * provided in the JWT\n * @param {Certificate} certificate first certificate the identifies the KMS\n * @param {Object} JWT credentials of the KMS\n * @param {string} JWT.e Public exponent of the first certificate\n * @param {string} KWT.n Modulus of the first certificate\n * @throws {KMSError} if e or n doesn't match the first certificate\n * @returns {void}\n */\nconst validatePublicCertificate =\n ([certificate], {e: publicExponent, n: modulus}) => {\n const {encode} = jose.util.base64url;\n\n const publicKey = certificate.subjectPublicKeyInfo.subjectPublicKey;\n const asn1PublicCert = fromBER(publicKey.valueBlock.valueHex);\n const publicCert = new RSAPublicKey({schema: asn1PublicCert.result});\n const publicExponentHex = publicCert.publicExponent.valueBlock.valueHex;\n const modulusHex = publicCert.modulus.valueBlock.valueHex;\n\n if (publicExponent !== encode(publicExponentHex)) {\n throwError('Public exponent is invalid');\n }\n if (modulus !== encode(modulusHex)) {\n throwError('Modulus is invalid');\n }\n };\n\n/**\n * Validates the list of certificates against the CAs provided\n * @param {certificate[]} certificates list of certificates provided\n * by the KMS to certify itself\n * @param {string[]} [caroots=[]] list of Certificate Authorities used to\n * validate the KMS's certificates\n * @returns {Promise} rejects if unable to validate the certificates\n */\nconst validateCertificatesSignature = (certificates, caroots = []) => {\n const certificateEngine = new CertificateChainValidationEngine({\n trustedCerts: caroots.map(decodeCert),\n certs: certificates\n });\n\n return certificateEngine.verify()\n .then(({result, resultCode, resultMessage}) => {\n if (!result) {\n throwError(\n `Certificate Validation failed [${resultCode}]: ${resultMessage}`\n );\n }\n });\n};\n\n/**\n * Validates the information provided by the KMS. This is a curried function.\n * The first function takes the caroots param and returns a second function.\n * The second function takes the credentials of the KMS and validates it\n * @param {string[]} caroots PEM encoded certificates that will be used\n * as Certificate Authorities\n * @param {Object} jwt Object containing the fields necessary to\n * validate the KMS\n * @returns {Promise} when resolved will return the jwt\n */\nconst validateKMS = (caroots) => (jwt = {}) => Promise.resolve()\n .then(() => {\n validateKtyHeader(jwt);\n validateKidHeader(jwt);\n\n if (!(isArray(jwt.x5c) && jwt.x5c.length > 0)) {\n throwError('JWK does not contain a list of certificates');\n }\n const certificates = jwt.x5c.map(decodeCert);\n\n validateCommonName(certificates, jwt);\n validatePublicCertificate(certificates, jwt);\n\n // Skip validating signatures if no CA roots were provided\n const promise = caroots ?\n validateCertificatesSignature(certificates, caroots) : Promise.resolve();\n\n return promise\n .then(() => jwt);\n });\n\nexport default validateKMS;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["setEngine","crypto","CryptoEngine","name","subtle","VALID_KTY","VALID_KID_PROTOCOL","X509_COMMON_NAME_KEY","X509_SUBJECT_ALT_NAME_KEY","KMSError","message","kmsError","Error","throwError","err","decodeCert","pem","der","Buffer","from","ber","Uint8Array","buffer","asn1","fromBER","Certificate","schema","result","validateKtyHeader","kty","validateKidHeader","kid","isUri","parseUrl","protocol","validateCommonName","certificate","kidHostname","hostname","validationSuccessful","extensions","extension","extnID","altNames","parsedValue","entry","san","value","toLowerCase","subjectAttributes","subject","typesAndValues","attribute","type","commonName","valueBlock","validatePublicCertificate","publicExponent","e","modulus","n","encode","jose","util","base64url","publicKey","subjectPublicKeyInfo","subjectPublicKey","asn1PublicCert","valueHex","publicCert","RSAPublicKey","publicExponentHex","modulusHex","validateCertificatesSignature","certificates","caroots","certificateEngine","CertificateChainValidationEngine","trustedCerts","map","certs","verify","then","resultCode","resultMessage","validateKMS","jwt","resolve","x5c","length","promise"],"sources":["kms-certificate-validation.js"],"sourcesContent":["import {parse as parseUrl} from 'url';\n\nimport {isUri} from 'valid-url';\nimport {fromBER} from 'asn1js';\nimport {\n Certificate,\n RSAPublicKey,\n CertificateChainValidationEngine,\n CryptoEngine,\n setEngine,\n} from 'pkijs';\nimport {isArray} from 'lodash';\nimport jose from 'node-jose';\nimport crypto from 'isomorphic-webcrypto';\nimport {Buffer} from 'safe-buffer';\n\nsetEngine(\n 'newEngine',\n crypto,\n new CryptoEngine({\n name: '',\n crypto,\n subtle: crypto.subtle,\n })\n);\n\nconst VALID_KTY = 'RSA';\nconst VALID_KID_PROTOCOL = 'kms:';\n\nconst X509_COMMON_NAME_KEY = '2.5.4.3';\n\nexport const X509_SUBJECT_ALT_NAME_KEY = '2.5.29.17';\n\n/**\n * Customize Error so the SDK knows to quit retrying and notify\n * the user\n */\nexport class KMSError extends Error {\n /**\n * add kmsError field to notify\n * @param {string} message\n */\n constructor(message) {\n super(message);\n this.kmsError = true;\n }\n}\n\nconst throwError = (err) => {\n throw new KMSError(`INVALID KMS: ${err}`);\n};\n\n/**\n * Converts the PEM string to a pkijs certificate object\n * @param {string} pem PEM representation of a certificate\n * @returns {Certificate} pkijs object of the certificate\n */\nconst decodeCert = (pem) => {\n if (typeof pem !== 'string') {\n throwError('certificate needs to be a string');\n }\n\n const der = Buffer.from(pem, 'base64');\n const ber = new Uint8Array(der).buffer;\n\n const asn1 = fromBER(ber);\n\n return new Certificate({schema: asn1.result});\n};\n\n/**\n * Validate the 'kty' property of the KMS credentials\n * @param {Object} JWT KMS credentials\n * @param {string} JWT.kty type of certificate\n * @throws {KMSError} if kty is not a valid type\n * @returns {void}\n */\nconst validateKtyHeader = ({kty}) => {\n if (kty !== VALID_KTY) {\n throwError(`'kty' header must be '${VALID_KTY}'`);\n }\n};\n\nconst validateKidHeader = ({kid}) => {\n if (!isUri(kid)) {\n throwError(\"'kid' is not a valid URI\");\n }\n\n if (parseUrl(kid).protocol !== VALID_KID_PROTOCOL) {\n throwError(`'kid' protocol must be '${VALID_KID_PROTOCOL}'`);\n }\n};\n\n/**\n * Checks the first certificate matches the 'kid' in the JWT.\n * It first checks the Subject Alternative Name then it checks\n * the Common Name\n * @param {Certificate} certificate represents the KMS\n * @param {Object} JWT KMS credentials\n * @param {string} JWT.kid the uri of the KMS\n * @throws {KMSError} if unable to validate certificate against KMS credentials\n * @returns {void}\n */\nexport const validateCommonName = ([certificate], {kid}) => {\n const kidHostname = parseUrl(kid).hostname;\n let validationSuccessful = false;\n\n if (certificate.extensions) {\n // Subject Alt Names are in here\n for (const extension of certificate.extensions) {\n if (extension.extnID === X509_SUBJECT_ALT_NAME_KEY) {\n const {altNames} = extension.parsedValue;\n\n for (const entry of altNames) {\n const san = entry.value.toLowerCase();\n\n validationSuccessful = san === kidHostname;\n if (validationSuccessful) {\n break;\n }\n }\n\n if (validationSuccessful) {\n break;\n }\n }\n }\n }\n\n if (!validationSuccessful) {\n // Didn't match kid in the Subject Alt Names, checking the Common Name\n const subjectAttributes = certificate.subject.typesAndValues;\n\n for (const attribute of subjectAttributes) {\n if (attribute.type === X509_COMMON_NAME_KEY) {\n const commonName = attribute.value.valueBlock.value;\n\n validationSuccessful = commonName === kidHostname;\n if (validationSuccessful) {\n break;\n }\n }\n }\n }\n\n if (!validationSuccessful) {\n throwError(\"hostname of the 1st certificate does not match 'kid'\");\n }\n};\n\n/**\n * Validate the first KMS certificate against the information\n * provided in the JWT\n * @param {Certificate} certificate first certificate the identifies the KMS\n * @param {Object} JWT credentials of the KMS\n * @param {string} JWT.e Public exponent of the first certificate\n * @param {string} KWT.n Modulus of the first certificate\n * @throws {KMSError} if e or n doesn't match the first certificate\n * @returns {void}\n */\nconst validatePublicCertificate = ([certificate], {e: publicExponent, n: modulus}) => {\n const {encode} = jose.util.base64url;\n\n const publicKey = certificate.subjectPublicKeyInfo.subjectPublicKey;\n const asn1PublicCert = fromBER(publicKey.valueBlock.valueHex);\n const publicCert = new RSAPublicKey({schema: asn1PublicCert.result});\n const publicExponentHex = publicCert.publicExponent.valueBlock.valueHex;\n const modulusHex = publicCert.modulus.valueBlock.valueHex;\n\n if (publicExponent !== encode(publicExponentHex)) {\n throwError('Public exponent is invalid');\n }\n if (modulus !== encode(modulusHex)) {\n throwError('Modulus is invalid');\n }\n};\n\n/**\n * Validates the list of certificates against the CAs provided\n * @param {certificate[]} certificates list of certificates provided\n * by the KMS to certify itself\n * @param {string[]} [caroots=[]] list of Certificate Authorities used to\n * validate the KMS's certificates\n * @returns {Promise} rejects if unable to validate the certificates\n */\nconst validateCertificatesSignature = (certificates, caroots = []) => {\n const certificateEngine = new CertificateChainValidationEngine({\n trustedCerts: caroots.map(decodeCert),\n certs: certificates,\n });\n\n return certificateEngine.verify().then(({result, resultCode, resultMessage}) => {\n if (!result) {\n throwError(`Certificate Validation failed [${resultCode}]: ${resultMessage}`);\n }\n });\n};\n\n/**\n * Validates the information provided by the KMS. This is a curried function.\n * The first function takes the caroots param and returns a second function.\n * The second function takes the credentials of the KMS and validates it\n * @param {string[]} caroots PEM encoded certificates that will be used\n * as Certificate Authorities\n * @param {Object} jwt Object containing the fields necessary to\n * validate the KMS\n * @returns {Promise} when resolved will return the jwt\n */\nconst validateKMS =\n (caroots) =>\n (jwt = {}) =>\n Promise.resolve().then(() => {\n validateKtyHeader(jwt);\n validateKidHeader(jwt);\n\n if (!(isArray(jwt.x5c) && jwt.x5c.length > 0)) {\n throwError('JWK does not contain a list of certificates');\n }\n const certificates = jwt.x5c.map(decodeCert);\n\n validateCommonName(certificates, jwt);\n validatePublicCertificate(certificates, jwt);\n\n // Skip validating signatures if no CA roots were provided\n const promise = caroots\n ? validateCertificatesSignature(certificates, caroots)\n : Promise.resolve();\n\n return promise.then(() => jwt);\n });\n\nexport default validateKMS;\n"],"mappings":"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"}
|
|
@@ -1,37 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _Reflect$construct = require("@babel/runtime-corejs2/core-js/reflect/construct");
|
|
4
|
-
|
|
5
4
|
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
6
|
-
|
|
7
5
|
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
8
|
-
|
|
9
6
|
_Object$defineProperty(exports, "__esModule", {
|
|
10
7
|
value: true
|
|
11
8
|
});
|
|
12
|
-
|
|
13
9
|
exports.default = void 0;
|
|
14
|
-
|
|
15
10
|
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
|
|
16
|
-
|
|
17
11
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
|
|
18
|
-
|
|
19
12
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
|
|
20
|
-
|
|
21
13
|
var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/inherits"));
|
|
22
|
-
|
|
23
14
|
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/possibleConstructorReturn"));
|
|
24
|
-
|
|
25
15
|
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/getPrototypeOf"));
|
|
26
|
-
|
|
27
16
|
var _httpCore = require("@webex/http-core");
|
|
28
|
-
|
|
29
17
|
var _kmsErrors = require("./kms-errors");
|
|
30
|
-
|
|
31
18
|
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = _Reflect$construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
|
|
32
|
-
|
|
33
19
|
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !_Reflect$construct) return false; if (_Reflect$construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
34
|
-
|
|
35
20
|
/**
|
|
36
21
|
* Interceptor (only to be used in test mode) intended to replay requests that
|
|
37
22
|
* fail as a result of the test-user incompatibility in KMS.
|
|
@@ -39,14 +24,11 @@ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !_R
|
|
|
39
24
|
*/
|
|
40
25
|
var KmsDryErrorInterceptor = /*#__PURE__*/function (_Interceptor) {
|
|
41
26
|
(0, _inherits2.default)(KmsDryErrorInterceptor, _Interceptor);
|
|
42
|
-
|
|
43
27
|
var _super = _createSuper(KmsDryErrorInterceptor);
|
|
44
|
-
|
|
45
28
|
function KmsDryErrorInterceptor() {
|
|
46
29
|
(0, _classCallCheck2.default)(this, KmsDryErrorInterceptor);
|
|
47
30
|
return _super.apply(this, arguments);
|
|
48
31
|
}
|
|
49
|
-
|
|
50
32
|
(0, _createClass2.default)(KmsDryErrorInterceptor, [{
|
|
51
33
|
key: "onResponseError",
|
|
52
34
|
value:
|
|
@@ -61,16 +43,15 @@ var KmsDryErrorInterceptor = /*#__PURE__*/function (_Interceptor) {
|
|
|
61
43
|
this.webex.logger.error(reason);
|
|
62
44
|
return this.replay(options, reason);
|
|
63
45
|
}
|
|
64
|
-
|
|
65
46
|
return _promise.default.reject(reason);
|
|
66
47
|
}
|
|
48
|
+
|
|
67
49
|
/**
|
|
68
50
|
* Replays the request
|
|
69
51
|
* @param {Object} options
|
|
70
52
|
* @param {DryError} reason
|
|
71
53
|
* @returns {Object}
|
|
72
54
|
*/
|
|
73
|
-
|
|
74
55
|
}, {
|
|
75
56
|
key: "replay",
|
|
76
57
|
value: function replay(options, reason) {
|
|
@@ -79,12 +60,10 @@ var KmsDryErrorInterceptor = /*#__PURE__*/function (_Interceptor) {
|
|
|
79
60
|
} else {
|
|
80
61
|
options.replayCount = 1;
|
|
81
62
|
}
|
|
82
|
-
|
|
83
63
|
if (options.replayCount > this.webex.config.maxAuthenticationReplays) {
|
|
84
64
|
this.webex.logger.error("kms: failed after ".concat(this.webex.config.maxAuthenticationReplays, " replay attempts"));
|
|
85
65
|
return _promise.default.reject(reason);
|
|
86
66
|
}
|
|
87
|
-
|
|
88
67
|
this.webex.logger.info("kms: replaying request ".concat(options.replayCount, " time"));
|
|
89
68
|
return this.webex.request(options);
|
|
90
69
|
}
|
|
@@ -102,6 +81,5 @@ var KmsDryErrorInterceptor = /*#__PURE__*/function (_Interceptor) {
|
|
|
102
81
|
}]);
|
|
103
82
|
return KmsDryErrorInterceptor;
|
|
104
83
|
}(_httpCore.Interceptor);
|
|
105
|
-
|
|
106
84
|
exports.default = KmsDryErrorInterceptor;
|
|
107
85
|
//# sourceMappingURL=kms-dry-error-interceptor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["KmsDryErrorInterceptor","options","reason","DryError","message","match","webex","logger","error","replay","reject","replayCount","config","maxAuthenticationReplays","info","request","Interceptor"],"sources":["kms-dry-error-interceptor.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport {Interceptor} from '@webex/http-core';\n\nimport {DryError} from './kms-errors';\n/**\n * Interceptor (only to be used in test mode) intended to replay requests that\n * fail as a result of the test-user incompatibility in KMS.\n * @class\n */\nexport default class KmsDryErrorInterceptor extends Interceptor {\n /**\n * @returns {KmsDryErrorInterceptor}\n */\n static create() {\n return new KmsDryErrorInterceptor({webex: this});\n }\n\n /**\n * @param {Object} options\n * @param {Exception} reason\n * @returns {Promise}\n */\n onResponseError(options, reason) {\n if (reason instanceof DryError
|
|
1
|
+
{"version":3,"names":["KmsDryErrorInterceptor","options","reason","DryError","message","match","webex","logger","error","replay","reject","replayCount","config","maxAuthenticationReplays","info","request","Interceptor"],"sources":["kms-dry-error-interceptor.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport {Interceptor} from '@webex/http-core';\n\nimport {DryError} from './kms-errors';\n/**\n * Interceptor (only to be used in test mode) intended to replay requests that\n * fail as a result of the test-user incompatibility in KMS.\n * @class\n */\nexport default class KmsDryErrorInterceptor extends Interceptor {\n /**\n * @returns {KmsDryErrorInterceptor}\n */\n static create() {\n return new KmsDryErrorInterceptor({webex: this});\n }\n\n /**\n * @param {Object} options\n * @param {Exception} reason\n * @returns {Promise}\n */\n onResponseError(options, reason) {\n if (\n reason instanceof DryError &&\n reason.message.match(/Failed to resolve authorization token in KmsMessage request for user/)\n ) {\n this.webex.logger.error('DRY Request Failed due to kms/test-user flakiness');\n this.webex.logger.error(reason);\n\n return this.replay(options, reason);\n }\n\n return Promise.reject(reason);\n }\n\n /**\n * Replays the request\n * @param {Object} options\n * @param {DryError} reason\n * @returns {Object}\n */\n replay(options, reason) {\n if (options.replayCount) {\n options.replayCount += 1;\n } else {\n options.replayCount = 1;\n }\n\n if (options.replayCount > this.webex.config.maxAuthenticationReplays) {\n this.webex.logger.error(\n `kms: failed after ${this.webex.config.maxAuthenticationReplays} replay attempts`\n );\n\n return Promise.reject(reason);\n }\n\n this.webex.logger.info(`kms: replaying request ${options.replayCount} time`);\n\n return this.webex.request(options);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAIA;AAEA;AAAsC;AAAA;AACtC;AACA;AACA;AACA;AACA;AAJA,IAKqBA,sBAAsB;EAAA;EAAA;EAAA;IAAA;IAAA;EAAA;EAAA;IAAA;IAAA;IAQzC;AACF;AACA;AACA;AACA;IACE,yBAAgBC,OAAO,EAAEC,MAAM,EAAE;MAC/B,IACEA,MAAM,YAAYC,mBAAQ,IAC1BD,MAAM,CAACE,OAAO,CAACC,KAAK,CAAC,sEAAsE,CAAC,EAC5F;QACA,IAAI,CAACC,KAAK,CAACC,MAAM,CAACC,KAAK,CAAC,mDAAmD,CAAC;QAC5E,IAAI,CAACF,KAAK,CAACC,MAAM,CAACC,KAAK,CAACN,MAAM,CAAC;QAE/B,OAAO,IAAI,CAACO,MAAM,CAACR,OAAO,EAAEC,MAAM,CAAC;MACrC;MAEA,OAAO,iBAAQQ,MAAM,CAACR,MAAM,CAAC;IAC/B;;IAEA;AACF;AACA;AACA;AACA;AACA;EALE;IAAA;IAAA,OAMA,gBAAOD,OAAO,EAAEC,MAAM,EAAE;MACtB,IAAID,OAAO,CAACU,WAAW,EAAE;QACvBV,OAAO,CAACU,WAAW,IAAI,CAAC;MAC1B,CAAC,MAAM;QACLV,OAAO,CAACU,WAAW,GAAG,CAAC;MACzB;MAEA,IAAIV,OAAO,CAACU,WAAW,GAAG,IAAI,CAACL,KAAK,CAACM,MAAM,CAACC,wBAAwB,EAAE;QACpE,IAAI,CAACP,KAAK,CAACC,MAAM,CAACC,KAAK,6BACA,IAAI,CAACF,KAAK,CAACM,MAAM,CAACC,wBAAwB,sBAChE;QAED,OAAO,iBAAQH,MAAM,CAACR,MAAM,CAAC;MAC/B;MAEA,IAAI,CAACI,KAAK,CAACC,MAAM,CAACO,IAAI,kCAA2Bb,OAAO,CAACU,WAAW,WAAQ;MAE5E,OAAO,IAAI,CAACL,KAAK,CAACS,OAAO,CAACd,OAAO,CAAC;IACpC;EAAC;IAAA;IAAA;IAlDD;AACF;AACA;IACE,kBAAgB;MACd,OAAO,IAAID,sBAAsB,CAAC;QAACM,KAAK,EAAE;MAAI,CAAC,CAAC;IAClD;EAAC;EAAA;AAAA,EANiDU,qBAAW;AAAA"}
|