@webex/internal-plugin-encryption 3.0.0-bnr.4 → 3.0.0-next.1
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/.eslintrc.js +6 -0
- package/babel.config.js +3 -0
- package/dist/config.js +1 -2
- package/dist/config.js.map +1 -1
- package/dist/constants.js +11 -0
- package/dist/constants.js.map +1 -0
- package/dist/encryption.js +23 -20
- package/dist/encryption.js.map +1 -1
- package/dist/ensure-buffer.browser.js.map +1 -1
- package/dist/ensure-buffer.js.map +1 -1
- package/dist/index.js +5 -7
- package/dist/index.js.map +1 -1
- package/dist/kms-batcher.js +3 -4
- package/dist/kms-batcher.js.map +1 -1
- package/dist/kms-certificate-validation.js +8 -10
- package/dist/kms-certificate-validation.js.map +1 -1
- package/dist/kms-dry-error-interceptor.js +4 -3
- package/dist/kms-dry-error-interceptor.js.map +1 -1
- package/dist/kms-errors.js +23 -8
- package/dist/kms-errors.js.map +1 -1
- package/dist/kms.js +25 -14
- package/dist/kms.js.map +1 -1
- package/jest.config.js +3 -0
- package/package.json +32 -16
- package/process +1 -0
- package/src/constants.js +3 -0
- package/src/encryption.js +30 -23
- package/src/kms-batcher.js +3 -1
- package/src/kms-certificate-validation.js +3 -3
- package/src/kms-errors.js +28 -0
- package/src/kms.js +9 -6
- package/test/integration/spec/encryption.js +2 -1
- package/test/integration/spec/kms.js +0 -1
- package/test/unit/spec/encryption.js +10 -10
- package/test/unit/spec/kms-certificate-validation.js +34 -1
- package/test/unit/spec/kms-errors.js +70 -0
- package/test/unit/spec/kms.js +103 -0
- package/dist/types/config.d.ts +0 -16
- package/dist/types/encryption.d.ts +0 -2
- package/dist/types/ensure-buffer.browser.d.ts +0 -10
- package/dist/types/ensure-buffer.d.ts +0 -7
- package/dist/types/index.d.ts +0 -3
- package/dist/types/kms-batcher.d.ts +0 -6
- package/dist/types/kms-certificate-validation.d.ts +0 -24
- package/dist/types/kms-dry-error-interceptor.d.ts +0 -25
- package/dist/types/kms-errors.d.ts +0 -33
- package/dist/types/kms.d.ts +0 -5
package/package.json
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webex/internal-plugin-encryption",
|
|
3
|
-
"version": "3.0.0-bnr.4",
|
|
4
3
|
"description": "",
|
|
5
4
|
"license": "MIT",
|
|
6
5
|
"main": "dist/index.js",
|
|
@@ -24,22 +23,28 @@
|
|
|
24
23
|
]
|
|
25
24
|
},
|
|
26
25
|
"devDependencies": {
|
|
27
|
-
"@
|
|
28
|
-
"@webex/
|
|
29
|
-
"@webex/
|
|
30
|
-
"@webex/
|
|
31
|
-
"@webex/
|
|
26
|
+
"@babel/core": "^7.17.10",
|
|
27
|
+
"@webex/babel-config-legacy": "0.0.0",
|
|
28
|
+
"@webex/eslint-config-legacy": "0.0.0",
|
|
29
|
+
"@webex/jest-config-legacy": "0.0.0",
|
|
30
|
+
"@webex/legacy-tools": "0.0.0",
|
|
31
|
+
"@webex/test-helper-chai": "3.0.0-next.1",
|
|
32
|
+
"@webex/test-helper-make-local-url": "3.0.0-next.1",
|
|
33
|
+
"@webex/test-helper-mocha": "3.0.0-next.1",
|
|
34
|
+
"@webex/test-helper-mock-webex": "3.0.0-next.1",
|
|
35
|
+
"@webex/test-helper-test-users": "3.0.0-next.1",
|
|
36
|
+
"eslint": "^8.24.0",
|
|
37
|
+
"prettier": "^2.7.1",
|
|
32
38
|
"sinon": "^9.2.4"
|
|
33
39
|
},
|
|
34
40
|
"dependencies": {
|
|
35
|
-
"@webex/common": "
|
|
36
|
-
"@webex/common-timers": "
|
|
37
|
-
"@webex/http-core": "
|
|
38
|
-
"@webex/internal-plugin-device": "
|
|
39
|
-
"@webex/internal-plugin-
|
|
40
|
-
"@webex/
|
|
41
|
-
"@webex/
|
|
42
|
-
"@webex/webex-core": "workspace:^",
|
|
41
|
+
"@webex/common": "3.0.0-next.1",
|
|
42
|
+
"@webex/common-timers": "3.0.0-next.1",
|
|
43
|
+
"@webex/http-core": "3.0.0-next.1",
|
|
44
|
+
"@webex/internal-plugin-device": "3.0.0-next.1",
|
|
45
|
+
"@webex/internal-plugin-mercury": "3.0.0-next.1",
|
|
46
|
+
"@webex/test-helper-file": "3.0.0-next.1",
|
|
47
|
+
"@webex/webex-core": "3.0.0-next.1",
|
|
43
48
|
"asn1js": "^2.0.26",
|
|
44
49
|
"debug": "^4.3.4",
|
|
45
50
|
"isomorphic-webcrypto": "^2.3.8",
|
|
@@ -51,5 +56,16 @@
|
|
|
51
56
|
"safe-buffer": "^5.2.0",
|
|
52
57
|
"uuid": "^3.3.2",
|
|
53
58
|
"valid-url": "^1.0.9"
|
|
54
|
-
}
|
|
55
|
-
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "yarn build:src",
|
|
62
|
+
"build:src": "webex-legacy-tools build -dest \"./dist\" -src \"./src\" -js -ts -maps",
|
|
63
|
+
"deploy:npm": "yarn npm publish",
|
|
64
|
+
"test": "yarn test:style && yarn test:unit && yarn test:integration && yarn test:browser",
|
|
65
|
+
"test:browser": "webex-legacy-tools test --integration --runner karma",
|
|
66
|
+
"test:integration": "webex-legacy-tools test --integration --runner mocha",
|
|
67
|
+
"test:style": "eslint ./src/**/*.*",
|
|
68
|
+
"test:unit": "webex-legacy-tools test --unit --runner jest"
|
|
69
|
+
},
|
|
70
|
+
"version": "3.0.0-next.1"
|
|
71
|
+
}
|
package/process
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = {browser: true};
|
package/src/constants.js
ADDED
package/src/encryption.js
CHANGED
|
@@ -67,19 +67,19 @@ const Encryption = WebexPlugin.extend({
|
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* Validate and initiate a Download request for requested file
|
|
70
|
-
*
|
|
70
|
+
* @param {Object} fileUrl - Plaintext
|
|
71
71
|
* @param {Object} scr - Plaintext
|
|
72
72
|
* @param {Object} options - optional parameters to download a file
|
|
73
73
|
* @returns {promise}
|
|
74
74
|
*/
|
|
75
|
-
download(scr, options) {
|
|
75
|
+
download(fileUrl, scr, options) {
|
|
76
76
|
/* istanbul ignore if */
|
|
77
|
-
if (!scr
|
|
78
|
-
return Promise.reject(new Error('`scr
|
|
77
|
+
if (!fileUrl || !scr) {
|
|
78
|
+
return Promise.reject(new Error('`scr` and `fileUrl` are required'));
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
const shunt = new EventEmitter();
|
|
82
|
-
const promise = this._fetchDownloadUrl(
|
|
82
|
+
const promise = this._fetchDownloadUrl(fileUrl, options)
|
|
83
83
|
.then((uri) => {
|
|
84
84
|
// eslint-disable-next-line no-shadow
|
|
85
85
|
const options = {
|
|
@@ -103,26 +103,25 @@ const Encryption = WebexPlugin.extend({
|
|
|
103
103
|
|
|
104
104
|
/**
|
|
105
105
|
* Fetch Download URL for the requested file
|
|
106
|
-
*
|
|
107
|
-
* @param {Object} scr - Plaintext
|
|
106
|
+
* @param {Object} fileUrl - Plaintext
|
|
108
107
|
* @param {Object} options - optional parameters to download a file
|
|
109
108
|
* @returns {promise} url of the downloadable file
|
|
110
109
|
*/
|
|
111
|
-
_fetchDownloadUrl(
|
|
110
|
+
_fetchDownloadUrl(fileUrl, options) {
|
|
112
111
|
this.logger.info('encryption: retrieving download url for encrypted file');
|
|
113
112
|
|
|
114
|
-
if (process.env.NODE_ENV !== 'production' &&
|
|
113
|
+
if (process.env.NODE_ENV !== 'production' && fileUrl.includes('localhost')) {
|
|
115
114
|
this.logger.info(
|
|
116
115
|
'encryption: bypassing webex files because this looks to be a test file on localhost'
|
|
117
116
|
);
|
|
118
117
|
|
|
119
|
-
return Promise.resolve(
|
|
118
|
+
return Promise.resolve(fileUrl);
|
|
120
119
|
}
|
|
121
120
|
|
|
122
121
|
const inputBody = {
|
|
123
|
-
endpoints: [
|
|
122
|
+
endpoints: [fileUrl],
|
|
124
123
|
};
|
|
125
|
-
const endpointUrl = url.parse(
|
|
124
|
+
const endpointUrl = url.parse(fileUrl);
|
|
126
125
|
|
|
127
126
|
// hardcode the url to use 'https' and the file service '/v1/download/endpoints' api
|
|
128
127
|
endpointUrl.protocol = 'https';
|
|
@@ -137,21 +136,29 @@ const Encryption = WebexPlugin.extend({
|
|
|
137
136
|
allow: options.params.allow,
|
|
138
137
|
}
|
|
139
138
|
: inputBody,
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
})
|
|
140
|
+
.then((res) => {
|
|
141
|
+
// eslint-disable-next-line no-shadow
|
|
142
|
+
const url = res.body.endpoints[fileUrl];
|
|
143
|
+
|
|
144
|
+
if (!url) {
|
|
145
|
+
this.logger.warn(
|
|
146
|
+
'encryption: could not determine download url for `fileUrl`; attempting to download `fileUrl` directly'
|
|
147
|
+
);
|
|
143
148
|
|
|
144
|
-
|
|
149
|
+
return fileUrl;
|
|
150
|
+
}
|
|
151
|
+
this.logger.info('encryption: retrieved download url for encrypted file');
|
|
152
|
+
|
|
153
|
+
return url;
|
|
154
|
+
})
|
|
155
|
+
.catch((err) => {
|
|
145
156
|
this.logger.warn(
|
|
146
|
-
|
|
157
|
+
`encryption: ${err} could not determine download url for ${fileUrl}; attempting to download ${fileUrl} directly`
|
|
147
158
|
);
|
|
148
159
|
|
|
149
|
-
return
|
|
150
|
-
}
|
|
151
|
-
this.logger.info('encryption: retrieved download url for encrypted file');
|
|
152
|
-
|
|
153
|
-
return url;
|
|
154
|
-
});
|
|
160
|
+
return fileUrl;
|
|
161
|
+
});
|
|
155
162
|
},
|
|
156
163
|
|
|
157
164
|
encryptBinary(file) {
|
package/src/kms-batcher.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import {safeSetTimeout} from '@webex/common-timers';
|
|
6
6
|
import {Batcher} from '@webex/webex-core';
|
|
7
7
|
|
|
8
|
-
import {KmsError, KmsTimeoutError} from './kms-errors';
|
|
8
|
+
import {KmsError, KmsTimeoutError, handleKmsKeyRevokedEncryptionFailure} from './kms-errors';
|
|
9
9
|
|
|
10
10
|
export const TIMEOUT_SYMBOL = Symbol('TIMEOUT_SYMBOL');
|
|
11
11
|
|
|
@@ -133,6 +133,8 @@ const KmsBatcher = Batcher.extend({
|
|
|
133
133
|
* @returns {Promise}
|
|
134
134
|
*/
|
|
135
135
|
handleItemFailure(item, reason) {
|
|
136
|
+
handleKmsKeyRevokedEncryptionFailure(item, this.webex);
|
|
137
|
+
|
|
136
138
|
return this.getDeferredForResponse(item).then((defer) => {
|
|
137
139
|
defer.reject(reason || new KmsError(item.body));
|
|
138
140
|
});
|
|
@@ -29,7 +29,7 @@ const VALID_KID_PROTOCOL = 'kms:';
|
|
|
29
29
|
|
|
30
30
|
const X509_COMMON_NAME_KEY = '2.5.4.3';
|
|
31
31
|
|
|
32
|
-
const X509_SUBJECT_ALT_NAME_KEY = '2.5.29.17';
|
|
32
|
+
export const X509_SUBJECT_ALT_NAME_KEY = '2.5.29.17';
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Customize Error so the SDK knows to quit retrying and notify
|
|
@@ -101,7 +101,7 @@ const validateKidHeader = ({kid}) => {
|
|
|
101
101
|
* @throws {KMSError} if unable to validate certificate against KMS credentials
|
|
102
102
|
* @returns {void}
|
|
103
103
|
*/
|
|
104
|
-
const validateCommonName = ([certificate], {kid}) => {
|
|
104
|
+
export const validateCommonName = ([certificate], {kid}) => {
|
|
105
105
|
const kidHostname = parseUrl(kid).hostname;
|
|
106
106
|
let validationSuccessful = false;
|
|
107
107
|
|
|
@@ -112,7 +112,7 @@ const validateCommonName = ([certificate], {kid}) => {
|
|
|
112
112
|
const {altNames} = extension.parsedValue;
|
|
113
113
|
|
|
114
114
|
for (const entry of altNames) {
|
|
115
|
-
const san = entry.value;
|
|
115
|
+
const san = entry.value.toLowerCase();
|
|
116
116
|
|
|
117
117
|
validationSuccessful = san === kidHostname;
|
|
118
118
|
if (validationSuccessful) {
|
package/src/kms-errors.js
CHANGED
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
import {Exception} from '@webex/common';
|
|
6
6
|
import {WebexHttpError} from '@webex/webex-core';
|
|
7
7
|
|
|
8
|
+
import {
|
|
9
|
+
KMS_KEY_REVOKE_ERROR_CODES,
|
|
10
|
+
KMS_KEY_REVOKE_FAILURE,
|
|
11
|
+
KMS_KEY_REVOKE_ERROR_STATUS,
|
|
12
|
+
} from './constants';
|
|
13
|
+
|
|
8
14
|
/**
|
|
9
15
|
* Error class for KMS errors
|
|
10
16
|
*/
|
|
@@ -50,6 +56,14 @@ export class KmsError extends Exception {
|
|
|
50
56
|
message += `\nKMS_REQUEST_ID: ${body.requestId}`;
|
|
51
57
|
}
|
|
52
58
|
|
|
59
|
+
if (body.statusCode) {
|
|
60
|
+
message += `\nKMS_STATUS_CODE: ${body.statusCode}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (body.errorCode) {
|
|
64
|
+
message += `\nKMS_ErrorCode: ${body.errorCode}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
53
67
|
return message;
|
|
54
68
|
}
|
|
55
69
|
}
|
|
@@ -137,3 +151,17 @@ export class DryError extends WebexHttpError {
|
|
|
137
151
|
return message;
|
|
138
152
|
}
|
|
139
153
|
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Function triggers an event when specific encryption failures are received.
|
|
157
|
+
*/
|
|
158
|
+
|
|
159
|
+
// eslint-disable-next-line consistent-return
|
|
160
|
+
export const handleKmsKeyRevokedEncryptionFailure = (item, webex) => {
|
|
161
|
+
if (
|
|
162
|
+
item.status === KMS_KEY_REVOKE_ERROR_STATUS &&
|
|
163
|
+
KMS_KEY_REVOKE_ERROR_CODES.includes(item.body.errorCode)
|
|
164
|
+
) {
|
|
165
|
+
webex.internal.encryption.trigger(KMS_KEY_REVOKE_FAILURE);
|
|
166
|
+
}
|
|
167
|
+
};
|
package/src/kms.js
CHANGED
|
@@ -275,14 +275,15 @@ const KMS = WebexPlugin.extend({
|
|
|
275
275
|
* @param {Object} options
|
|
276
276
|
* @param {UUID} options.assignedOrgId the orgId
|
|
277
277
|
* @param {string} options.customerMasterKey the master key
|
|
278
|
+
* @param {boolean} options.awsKms enable amazon aws keys
|
|
278
279
|
* @returns {Promise.<UploadCmkResponse>} response of upload CMK api
|
|
279
280
|
*/
|
|
280
|
-
uploadCustomerMasterKey({assignedOrgId, customerMasterKey}) {
|
|
281
|
+
uploadCustomerMasterKey({assignedOrgId, customerMasterKey, awsKms = false}) {
|
|
281
282
|
this.logger.info('kms: upload customer master key for byok');
|
|
282
283
|
|
|
283
284
|
return this.request({
|
|
284
285
|
method: 'create',
|
|
285
|
-
uri: '/cmk',
|
|
286
|
+
uri: awsKms ? '/awsKmsCmk' : '/cmk',
|
|
286
287
|
assignedOrgId,
|
|
287
288
|
customerMasterKey,
|
|
288
289
|
requestId: uuid.v4(),
|
|
@@ -297,14 +298,15 @@ const KMS = WebexPlugin.extend({
|
|
|
297
298
|
* get all customer master keys for one org.
|
|
298
299
|
* @param {Object} options
|
|
299
300
|
* @param {UUID} options.assignedOrgId the orgId
|
|
301
|
+
* @param {boolean} options.awsKms enable amazon aws keys
|
|
300
302
|
* @returns {Promise.<ActivateCmkResponse>} response of list CMKs api
|
|
301
303
|
*/
|
|
302
|
-
listAllCustomerMasterKey({assignedOrgId}) {
|
|
304
|
+
listAllCustomerMasterKey({assignedOrgId, awsKms = false}) {
|
|
303
305
|
this.logger.info('kms: get all customer master keys for byok');
|
|
304
306
|
|
|
305
307
|
return this.request({
|
|
306
308
|
method: 'retrieve',
|
|
307
|
-
uri: '/cmk',
|
|
309
|
+
uri: awsKms ? '/awsKmsCmk' : '/cmk',
|
|
308
310
|
assignedOrgId,
|
|
309
311
|
requestId: uuid.v4(),
|
|
310
312
|
}).then((res) => {
|
|
@@ -361,14 +363,15 @@ const KMS = WebexPlugin.extend({
|
|
|
361
363
|
* this is for test case. it will delete all CMKs, no matter what their status is. This is mainly for test purpose
|
|
362
364
|
* @param {Object} options
|
|
363
365
|
* @param {UUID} options.assignedOrgId the orgId
|
|
366
|
+
* @param {boolean} options.awsKms enable amazon aws keys
|
|
364
367
|
* @returns {Promise.<{status, requestId}>}
|
|
365
368
|
*/
|
|
366
|
-
deleteAllCustomerMasterKeys({assignedOrgId}) {
|
|
369
|
+
deleteAllCustomerMasterKeys({assignedOrgId, awsKms = false}) {
|
|
367
370
|
this.logger.info('kms: delete all customer master keys at the same time');
|
|
368
371
|
|
|
369
372
|
return this.request({
|
|
370
373
|
method: 'delete',
|
|
371
|
-
uri: '/cmk',
|
|
374
|
+
uri: awsKms ? '/awsKmsCmk' : '/cmk',
|
|
372
375
|
assignedOrgId,
|
|
373
376
|
requestId: uuid.v4(),
|
|
374
377
|
}).then((res) => {
|
|
@@ -158,7 +158,8 @@ describe('Encryption', function () {
|
|
|
158
158
|
}));
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
// SPARK-413317
|
|
162
|
+
describe.skip('#download()', () => {
|
|
162
163
|
it('downloads and decrypts an encrypted file', () =>
|
|
163
164
|
webex.internal.encryption
|
|
164
165
|
.encryptBinary(FILE)
|
|
@@ -425,7 +425,6 @@ describe('Encryption', function () {
|
|
|
425
425
|
describe('upload customer master key', () => {
|
|
426
426
|
let uploadedkeyId;
|
|
427
427
|
|
|
428
|
-
/* eslint-disable no-unused-expressions */
|
|
429
428
|
skipInBrowser(it)('upload customer master key', () =>
|
|
430
429
|
webex.internal.encryption.kms
|
|
431
430
|
.deleteAllCustomerMasterKeys({assignedOrgId: spock.orgId})
|
|
@@ -22,18 +22,18 @@ describe('internal-plugin-encryption', () => {
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
describe('check _fetchDownloadUrl()', () => {
|
|
25
|
-
const
|
|
25
|
+
const fileArray = [
|
|
26
26
|
{
|
|
27
|
-
|
|
27
|
+
url: 'https://files-api-intb1.ciscospark.com/v1/spaces/a0cba376-fc05-4b88-af4b-cfffa7465f9a/contents/1d3931e7-9e31-46bc-8084-d766a8f72c99/versions/5fa9caf87a98410aae49e0173856a974/bytes',
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
|
-
|
|
30
|
+
url: 'https://files-api-intb2.ciscospark.com/v1/spaces/a0cba376-fc05-4b88-af4b-cfffa7465f9a/contents/1d3931e7-9e31-46bc-8084-d766a8f72c99/versions/5fa9caf87a98410aae49e0173856a974/bytes',
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
|
|
33
|
+
url: 'https://www.test-api.com/v1/spaces/test-path-name-space/contents/test-path-name-contents/versions/test-version/bytes',
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
|
-
|
|
36
|
+
url: 'http://www.test-api.com/v1/spaces/test-path-name-space/contents/test-path-name-contents/versions/test-version/bytes',
|
|
37
37
|
},
|
|
38
38
|
];
|
|
39
39
|
const options = undefined;
|
|
@@ -44,7 +44,7 @@ describe('internal-plugin-encryption', () => {
|
|
|
44
44
|
|
|
45
45
|
spyStub = sinon.stub(webex.internal.encryption, 'request').callsFake(returnStub);
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
fileArray.forEach((file) => webex.internal.encryption._fetchDownloadUrl(file.url, options));
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
it('verifying file service uris', () => {
|
|
@@ -68,10 +68,10 @@ describe('internal-plugin-encryption', () => {
|
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
it('verifying endpoints', () => {
|
|
71
|
-
assert.equal(spyStub.args[0][0].body.endpoints[0],
|
|
72
|
-
assert.equal(spyStub.args[1][0].body.endpoints[0],
|
|
73
|
-
assert.equal(spyStub.args[2][0].body.endpoints[0],
|
|
74
|
-
assert.equal(spyStub.args[3][0].body.endpoints[0],
|
|
71
|
+
assert.equal(spyStub.args[0][0].body.endpoints[0], fileArray[0].url);
|
|
72
|
+
assert.equal(spyStub.args[1][0].body.endpoints[0], fileArray[1].url);
|
|
73
|
+
assert.equal(spyStub.args[2][0].body.endpoints[0], fileArray[2].url);
|
|
74
|
+
assert.equal(spyStub.args[3][0].body.endpoints[0], fileArray[3].url);
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
afterEach(() => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {assert} from '@webex/test-helper-chai';
|
|
2
2
|
|
|
3
|
-
import validateCert, {KMSError} from '../../../src/kms-certificate-validation';
|
|
3
|
+
import validateCert, {KMSError, validateCommonName, X509_SUBJECT_ALT_NAME_KEY} from '../../../src/kms-certificate-validation';
|
|
4
4
|
|
|
5
5
|
const caroots = [
|
|
6
6
|
'MIID6TCCAtGgAwIBAgIURmBu688C9oUIJXlykr1J3fi5H4kwDQYJKoZIhvcNAQELBQAwgYMxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhDb2xvcmFkbzEPMA0GA1UEBwwGRGVudmVyMRAwDgYDVQQKDAdFeGFtcGxlMR8wHQYDVQQDDBZodHRwczovL2NhLmV4YW1wbGUuY29tMR0wGwYJKoZIhvcNAQkBFg5jYUBleGFtcGxlLmNvbTAeFw0yMDAyMDYyMDIyMDhaFw00MDAyMDEyMDIyMDhaMIGDMQswCQYDVQQGEwJVUzERMA8GA1UECAwIQ29sb3JhZG8xDzANBgNVBAcMBkRlbnZlcjEQMA4GA1UECgwHRXhhbXBsZTEfMB0GA1UEAwwWaHR0cHM6Ly9jYS5leGFtcGxlLmNvbTEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7TaDWldwjU65y4fnNDIuNu4dZi3bZvaN9nJ3A8D9pwFcNx3DL5cPpafAkJuE/2ZBrsZxJWKwXLQFuNE9V3XVslv0OPgEZVfY5AKuPhVezRqEqsCdUgODMkJat6PE02r0NZRFpBiRCThh0wY5u/tiTiPgjHwEPhBEyLgcJ6FOWLn9wBsS4SvBzfppYGL5GW1G0eN9yORnKKgqkgyf0x8FvTMyVSjtkhcI/kA/8061sl4DFG6sefQmAOVvH7tp7YmN+jpQ7cOKQtjOpZS6Gp22u7LEI0/qb5n2QvjjcUQM81mN6CZ8nciWXRgjBhdAJJhmyMvcx8rnVb6vtU26fCaetAgMBAAGjUzBRMB0GA1UdDgQWBBRZiCyKaTYL94gwhxzktYg32qMOYjAfBgNVHSMEGDAWgBRZiCyKaTYL94gwhxzktYg32qMOYjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQATa2QkTGcj8IPjItnvg23ihlRjHdFHn6lB7uYPhcDurwRlBrlC2/OB44P3dHB9tEPbV4unoF9ftEKO3nNY3HUDcPrQwRqkPftlYYr4/6z/jnmNBRgiDICVaiTZNlX54fLiPsSAbIymPWLLLNtq17vjVEcfGUXhi/F+EkN/uXZ4yH6RK0YjBRwPV9cfziz1YsF2WVYVYtQErf+NTjnYR5S4Ba2kEqhI5j7mNhiafPNODaOchHcaRMvfWcBhlHt+atwNyPxNr4NP+cDjAWg0I8xAUdbZGQiRJecjkctolLHsfZXj+ulEv3eaKw7gSo3Aekexw8aZS7soy+VM1fzmLopw',
|
|
@@ -163,3 +163,36 @@ describe('internal-plugin-encryption', () => {
|
|
|
163
163
|
});
|
|
164
164
|
});
|
|
165
165
|
});
|
|
166
|
+
|
|
167
|
+
describe('validateCommonName', () => {
|
|
168
|
+
|
|
169
|
+
const checkValidate = (SAN, kidHostname) => {
|
|
170
|
+
validateCommonName(
|
|
171
|
+
[
|
|
172
|
+
{
|
|
173
|
+
extensions: [
|
|
174
|
+
{
|
|
175
|
+
extnID: X509_SUBJECT_ALT_NAME_KEY,
|
|
176
|
+
parsedValue: {
|
|
177
|
+
altNames: [{value: 'Example.com'}],
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
{kid: 'https://Example.com'}
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
it('handles mixed case SAN', () => {
|
|
188
|
+
checkValidate('Example.com', 'https://Example.com');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('handles different case SAN', () => {
|
|
192
|
+
checkValidate('ExAmpLe.cOm', 'https://example.com');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('handles different case kid hostname', () => {
|
|
196
|
+
checkValidate('example.com', 'https://ExAmpLe.cOm');
|
|
197
|
+
});
|
|
198
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {assert} from '@webex/test-helper-chai';
|
|
2
|
+
import {handleKmsKeyRevokedEncryptionFailure} from '../../../src/kms-errors'
|
|
3
|
+
import sinon from 'sinon';
|
|
4
|
+
|
|
5
|
+
describe('handleKmsKeyRevokedEncryptionFailure', () => {
|
|
6
|
+
|
|
7
|
+
it('triggers `event:kms:key:revoke:encryption:failure` event when correct error code is detected', () => {
|
|
8
|
+
const webex = {
|
|
9
|
+
internal: {
|
|
10
|
+
encryption: {
|
|
11
|
+
trigger: sinon.spy()
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const item = {
|
|
17
|
+
status: 405,
|
|
18
|
+
body: {
|
|
19
|
+
errorCode: 405005,
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
handleKmsKeyRevokedEncryptionFailure(item, webex);
|
|
24
|
+
|
|
25
|
+
assert.calledOnce(webex.internal.encryption.trigger);
|
|
26
|
+
assert.calledWithExactly(webex.internal.encryption.trigger, `event:kms:key:revoke:encryption:failure`);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('does not trigger `event:kms:key:revoke:encryption:failure` event when correct status but wrong error code is detected', () => {
|
|
30
|
+
const webex = {
|
|
31
|
+
internal: {
|
|
32
|
+
encryption: {
|
|
33
|
+
trigger: sinon.spy()
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const item = {
|
|
39
|
+
status: 405,
|
|
40
|
+
body: {
|
|
41
|
+
errorCode: 405009,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
handleKmsKeyRevokedEncryptionFailure(item, webex);
|
|
46
|
+
|
|
47
|
+
assert.notCalled(webex.internal.encryption.trigger);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('does not trigger `event:kms:key:revoke:encryption:failure` event when wrong status but correct error code is detected', () => {
|
|
51
|
+
const webex = {
|
|
52
|
+
internal: {
|
|
53
|
+
encryption: {
|
|
54
|
+
trigger: sinon.spy()
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const item = {
|
|
60
|
+
status: 403,
|
|
61
|
+
body: {
|
|
62
|
+
errorCode: 405005,
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
handleKmsKeyRevokedEncryptionFailure(item, webex);
|
|
67
|
+
|
|
68
|
+
assert.notCalled(webex.internal.encryption.trigger);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
/* eslint-disable no-underscore-dangle */
|
|
5
|
+
import Url from 'url';
|
|
6
|
+
|
|
7
|
+
import {assert} from '@webex/test-helper-chai';
|
|
8
|
+
import MockWebex from '@webex/test-helper-mock-webex';
|
|
9
|
+
import sinon from 'sinon';
|
|
10
|
+
import Encryption from '@webex/internal-plugin-encryption';
|
|
11
|
+
import {KmsError} from '../../../dist/kms-errors';
|
|
12
|
+
|
|
13
|
+
describe('internal-plugin-encryption', () => {
|
|
14
|
+
describe('kms', () => {
|
|
15
|
+
let webex;
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
webex = new MockWebex({
|
|
19
|
+
children: {
|
|
20
|
+
encryption: Encryption,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('key management', () => {
|
|
26
|
+
const options = undefined;
|
|
27
|
+
let spyStub;
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
const returnStub = (obj) => Promise.resolve(obj);
|
|
31
|
+
|
|
32
|
+
spyStub = sinon.stub(webex.internal.encryption.kms, 'request').callsFake(returnStub);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
spyStub.resetHistory();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('listAllCustomerMasterKey', async () => {
|
|
40
|
+
await webex.internal.encryption.kms.listAllCustomerMasterKey({
|
|
41
|
+
assignedOrgId: 'xx-sds-assdf',
|
|
42
|
+
awsKms: false,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
await webex.internal.encryption.kms.listAllCustomerMasterKey({
|
|
46
|
+
assignedOrgId: 'xx-sds-assdf',
|
|
47
|
+
awsKms: true,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
assert.equal(spyStub.args[0][0].uri, '/cmk');
|
|
51
|
+
assert.equal(spyStub.args[1][0].uri, '/awsKmsCmk');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('uploadCustomerMasterKey', async () => {
|
|
55
|
+
await webex.internal.encryption.kms.uploadCustomerMasterKey({
|
|
56
|
+
assignedOrgId: 'xx-sds-assdf',
|
|
57
|
+
awsKms: false,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
await webex.internal.encryption.kms.uploadCustomerMasterKey({
|
|
61
|
+
assignedOrgId: 'xx-sds-assdf',
|
|
62
|
+
awsKms: true,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
assert.equal(spyStub.args[0][0].uri, '/cmk');
|
|
66
|
+
assert.equal(spyStub.args[1][0].uri, '/awsKmsCmk');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('deleteAllCustomerMasterKeys', async () => {
|
|
70
|
+
await webex.internal.encryption.kms.deleteAllCustomerMasterKeys({
|
|
71
|
+
assignedOrgId: 'xx-sds-assdf',
|
|
72
|
+
awsKms: false,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await webex.internal.encryption.kms.deleteAllCustomerMasterKeys({
|
|
76
|
+
assignedOrgId: 'xx-sds-assdf',
|
|
77
|
+
awsKms: true,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
assert.equal(spyStub.args[0][0].uri, '/cmk');
|
|
81
|
+
assert.equal(spyStub.args[1][0].uri, '/awsKmsCmk');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('KMS error', () => {
|
|
86
|
+
it('KMSError', async () => {
|
|
87
|
+
const error = new KmsError({
|
|
88
|
+
status: 404,
|
|
89
|
+
errorCode: 30005,
|
|
90
|
+
reason: 'cannot fetch keys',
|
|
91
|
+
requestId: '3434343',
|
|
92
|
+
});
|
|
93
|
+
assert.equal(
|
|
94
|
+
error.toString(),
|
|
95
|
+
'KmsError: cannot fetch keys\n' +
|
|
96
|
+
'KMS_RESPONSE_STATUS: 404\n' +
|
|
97
|
+
'KMS_REQUEST_ID: 3434343\n' +
|
|
98
|
+
'KMS_ErrorCode: 30005'
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
});
|
package/dist/types/config.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
declare namespace _default {
|
|
2
|
-
namespace encryption {
|
|
3
|
-
namespace joseOptions {
|
|
4
|
-
const compact: boolean;
|
|
5
|
-
const contentAlg: string;
|
|
6
|
-
const protect: string;
|
|
7
|
-
}
|
|
8
|
-
const kmsInitialTimeout: number;
|
|
9
|
-
const kmsMaxTimeout: number;
|
|
10
|
-
const ecdhMaxTimeout: number;
|
|
11
|
-
const batcherWait: number;
|
|
12
|
-
const batcherMaxCalls: number;
|
|
13
|
-
const batcherMaxWait: number;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
export default _default;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Ensures the provider buffer is, indeed, an ArrayBuffer; converts File and
|
|
6
|
-
* Blob objects to ArrayBuffers.
|
|
7
|
-
* @param {mixed} buffer
|
|
8
|
-
* @returns {Promise<ArrayBuffer>}
|
|
9
|
-
*/
|
|
10
|
-
export default function ensureBuffer(buffer: mixed): Promise<ArrayBuffer>;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ensures the provider Buffer is, indeed, a Buffer; sometimes, they seem to be
|
|
3
|
-
* byte-arrays instead of proper Buffer objects.
|
|
4
|
-
* @param {mixed} buffer
|
|
5
|
-
* @returns {Promise<Buffer>}
|
|
6
|
-
*/
|
|
7
|
-
export default function ensureBuffer(buffer: mixed): Promise<Buffer>;
|
package/dist/types/index.d.ts
DELETED