@webex/internal-plugin-encryption 2.59.2 → 2.59.3-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 -6
- package/README.md +42 -42
- package/babel.config.js +3 -3
- package/dist/config.js +21 -21
- package/dist/config.js.map +1 -1
- package/dist/encryption.js +57 -57
- package/dist/encryption.js.map +1 -1
- package/dist/ensure-buffer.browser.js +7 -7
- package/dist/ensure-buffer.browser.js.map +1 -1
- package/dist/ensure-buffer.js +7 -7
- package/dist/ensure-buffer.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/kms-batcher.js +38 -38
- package/dist/kms-batcher.js.map +1 -1
- package/dist/kms-certificate-validation.js +50 -50
- package/dist/kms-certificate-validation.js.map +1 -1
- package/dist/kms-dry-error-interceptor.js +15 -15
- package/dist/kms-dry-error-interceptor.js.map +1 -1
- package/dist/kms-errors.js +16 -16
- package/dist/kms-errors.js.map +1 -1
- package/dist/kms.js +171 -171
- package/dist/kms.js.map +1 -1
- package/jest.config.js +3 -3
- package/package.json +20 -19
- package/process +1 -1
- package/src/config.js +50 -50
- package/src/encryption.js +257 -257
- package/src/ensure-buffer.browser.js +37 -37
- package/src/ensure-buffer.js +20 -20
- package/src/index.js +159 -159
- package/src/kms-batcher.js +158 -158
- package/src/kms-certificate-validation.js +232 -232
- package/src/kms-dry-error-interceptor.js +65 -65
- package/src/kms-errors.js +147 -147
- package/src/kms.js +848 -848
- package/test/integration/spec/encryption.js +448 -448
- package/test/integration/spec/kms.js +800 -800
- package/test/integration/spec/payload-transfom.js +97 -97
- package/test/unit/spec/encryption.js +82 -82
- package/test/unit/spec/kms-certificate-validation.js +165 -165
- package/test/unit/spec/kms.js +103 -103
package/src/encryption.js
CHANGED
|
@@ -1,257 +1,257 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {EventEmitter} from 'events';
|
|
6
|
-
import url from 'url';
|
|
7
|
-
|
|
8
|
-
import {WebexPlugin} from '@webex/webex-core';
|
|
9
|
-
import {proxyEvents, tap, transferEvents} from '@webex/common';
|
|
10
|
-
import jose from 'node-jose';
|
|
11
|
-
import SCR from 'node-scr';
|
|
12
|
-
|
|
13
|
-
import ensureBuffer from './ensure-buffer';
|
|
14
|
-
import KMS from './kms';
|
|
15
|
-
|
|
16
|
-
const Encryption = WebexPlugin.extend({
|
|
17
|
-
children: {
|
|
18
|
-
kms: KMS,
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
namespace: 'Encryption',
|
|
22
|
-
|
|
23
|
-
processKmsMessageEvent(event) {
|
|
24
|
-
return this.kms.processKmsMessageEvent(event);
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
decryptBinary(scr, buffer) {
|
|
28
|
-
return ensureBuffer(buffer).then((b) => {
|
|
29
|
-
/* istanbul ignore if */
|
|
30
|
-
if (buffer.length === 0 || buffer.byteLength === 0) {
|
|
31
|
-
return Promise.reject(new Error('Attempted to decrypt zero-length buffer'));
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return scr.decrypt(b);
|
|
35
|
-
});
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Decrypt a SCR (Secure Content Resource) using the supplied key uri.
|
|
40
|
-
*
|
|
41
|
-
* @param {string} key - The uri of a key stored in KMS
|
|
42
|
-
* @param {Object} cipherScr - An encrypted SCR
|
|
43
|
-
* @param {Object} options
|
|
44
|
-
* @param {string} options.onBehalfOf - Fetch the KMS key on behalf of another user (using the user's UUID), active user requires the 'spark.kms_orgagent' role
|
|
45
|
-
* @returns {Object} Decrypted SCR
|
|
46
|
-
*/
|
|
47
|
-
decryptScr(key, cipherScr, options) {
|
|
48
|
-
return this.getKey(key, options).then((k) => SCR.fromJWE(k.jwk, cipherScr));
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Decrypt text using the supplied key uri.
|
|
53
|
-
*
|
|
54
|
-
* @param {string} key - The uri of a key stored in KMS
|
|
55
|
-
* @param {string} ciphertext - Encrypted text
|
|
56
|
-
* @param {Object} options
|
|
57
|
-
* @param {string} options.onBehalfOf - Fetch the KMS key on behalf of another user (using the user's UUID), active user requires the 'spark.kms_orgagent' role
|
|
58
|
-
* @returns {string} Decrypted plaintext
|
|
59
|
-
*/
|
|
60
|
-
decryptText(key, ciphertext, options) {
|
|
61
|
-
return this.getKey(key, options).then((k) =>
|
|
62
|
-
jose.JWE.createDecrypt(k.jwk)
|
|
63
|
-
.decrypt(ciphertext)
|
|
64
|
-
.then((result) => result.plaintext.toString())
|
|
65
|
-
);
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Validate and initiate a Download request for requested file
|
|
70
|
-
*
|
|
71
|
-
* @param {Object} scr - Plaintext
|
|
72
|
-
* @param {Object} options - optional parameters to download a file
|
|
73
|
-
* @returns {promise}
|
|
74
|
-
*/
|
|
75
|
-
download(scr, options) {
|
|
76
|
-
/* istanbul ignore if */
|
|
77
|
-
if (!scr.loc) {
|
|
78
|
-
return Promise.reject(new Error('`scr.loc` is required'));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const shunt = new EventEmitter();
|
|
82
|
-
const promise = this._fetchDownloadUrl(scr, options)
|
|
83
|
-
.then((uri) => {
|
|
84
|
-
// eslint-disable-next-line no-shadow
|
|
85
|
-
const options = {
|
|
86
|
-
method: 'GET',
|
|
87
|
-
uri,
|
|
88
|
-
responseType: 'buffer',
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const ret = this.request(options);
|
|
92
|
-
|
|
93
|
-
transferEvents('progress', options.download, shunt);
|
|
94
|
-
|
|
95
|
-
return ret;
|
|
96
|
-
})
|
|
97
|
-
.then((res) => this.decryptBinary(scr, res.body));
|
|
98
|
-
|
|
99
|
-
proxyEvents(shunt, promise);
|
|
100
|
-
|
|
101
|
-
return promise;
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Fetch Download URL for the requested file
|
|
106
|
-
*
|
|
107
|
-
* @param {Object} scr - Plaintext
|
|
108
|
-
* @param {Object} options - optional parameters to download a file
|
|
109
|
-
* @returns {promise} url of the downloadable file
|
|
110
|
-
*/
|
|
111
|
-
_fetchDownloadUrl(scr, options) {
|
|
112
|
-
this.logger.info('encryption: retrieving download url for encrypted file');
|
|
113
|
-
|
|
114
|
-
if (process.env.NODE_ENV !== 'production' && scr.loc.includes('localhost')) {
|
|
115
|
-
this.logger.info(
|
|
116
|
-
'encryption: bypassing webex files because this looks to be a test file on localhost'
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
return Promise.resolve(scr.loc);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const inputBody = {
|
|
123
|
-
endpoints: [scr.loc],
|
|
124
|
-
};
|
|
125
|
-
const endpointUrl = url.parse(scr.loc);
|
|
126
|
-
|
|
127
|
-
// hardcode the url to use 'https' and the file service '/v1/download/endpoints' api
|
|
128
|
-
endpointUrl.protocol = 'https';
|
|
129
|
-
endpointUrl.pathname = '/v1/download/endpoints';
|
|
130
|
-
|
|
131
|
-
return this.request({
|
|
132
|
-
method: 'POST',
|
|
133
|
-
uri: url.format(endpointUrl),
|
|
134
|
-
body: options
|
|
135
|
-
? {
|
|
136
|
-
...inputBody,
|
|
137
|
-
allow: options.params.allow,
|
|
138
|
-
}
|
|
139
|
-
: inputBody,
|
|
140
|
-
}).then((res) => {
|
|
141
|
-
// eslint-disable-next-line no-shadow
|
|
142
|
-
const url = res.body.endpoints[scr.loc];
|
|
143
|
-
|
|
144
|
-
if (!url) {
|
|
145
|
-
this.logger.warn(
|
|
146
|
-
'encryption: could not determine download url for `scr.loc`; attempting to download `scr.loc` directly'
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
return scr.loc;
|
|
150
|
-
}
|
|
151
|
-
this.logger.info('encryption: retrieved download url for encrypted file');
|
|
152
|
-
|
|
153
|
-
return url;
|
|
154
|
-
});
|
|
155
|
-
},
|
|
156
|
-
|
|
157
|
-
encryptBinary(file) {
|
|
158
|
-
return ensureBuffer(file).then((buffer) =>
|
|
159
|
-
SCR.create().then((scr) =>
|
|
160
|
-
scr
|
|
161
|
-
.encrypt(buffer)
|
|
162
|
-
.then(ensureBuffer)
|
|
163
|
-
// eslint-disable-next-line max-nested-callbacks
|
|
164
|
-
.then((cdata) => ({scr, cdata}))
|
|
165
|
-
)
|
|
166
|
-
);
|
|
167
|
-
},
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Encrypt a SCR (Secure Content Resource) using the supplied key uri.
|
|
171
|
-
*
|
|
172
|
-
* @param {string} key - The uri of a key stored in KMS
|
|
173
|
-
* @param {Object} scr - Plaintext
|
|
174
|
-
* @param {Object} options
|
|
175
|
-
* @param {string} options.onBehalfOf - Fetch the KMS key on behalf of another user (using the user's UUID), active user requires the 'spark.kms_orgagent' role
|
|
176
|
-
* @returns {string} Encrypted SCR
|
|
177
|
-
*/
|
|
178
|
-
encryptScr(key, scr, options) {
|
|
179
|
-
/* istanbul ignore if */
|
|
180
|
-
if (!scr.loc) {
|
|
181
|
-
return Promise.reject(new Error('Cannot encrypt `scr` without first setting `loc`'));
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return this.getKey(key, options).then((k) => scr.toJWE(k.jwk));
|
|
185
|
-
},
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Encrypt plaintext using the supplied key uri.
|
|
189
|
-
*
|
|
190
|
-
* @param {string} key - The uri of a key stored in KMS
|
|
191
|
-
* @param {string} plaintext
|
|
192
|
-
* @param {Object} options
|
|
193
|
-
* @param {string} options.onBehalfOf - Fetch the KMS key on behalf of another user (using the user's UUID), active user requires the 'spark.kms_orgagent' role
|
|
194
|
-
* @returns {string} Encrypted text
|
|
195
|
-
*/
|
|
196
|
-
encryptText(key, plaintext, options) {
|
|
197
|
-
return this.getKey(key, options).then((k) =>
|
|
198
|
-
jose.JWE.createEncrypt(this.config.joseOptions, {
|
|
199
|
-
key: k.jwk,
|
|
200
|
-
header: {
|
|
201
|
-
alg: 'dir',
|
|
202
|
-
},
|
|
203
|
-
reference: null,
|
|
204
|
-
}).final(plaintext, 'utf8')
|
|
205
|
-
);
|
|
206
|
-
},
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Fetch the key associated with the supplied KMS uri.
|
|
210
|
-
*
|
|
211
|
-
* @param {string} uri - The uri of a key stored in KMS
|
|
212
|
-
* @param {Object} options
|
|
213
|
-
* @param {string} options.onBehalfOf - Fetch the KMS key on behalf of another user (using the user's UUID), active user requires the 'spark.kms_orgagent' role
|
|
214
|
-
* @returns {string} Key
|
|
215
|
-
*/
|
|
216
|
-
getKey(uri, {onBehalfOf} = {}) {
|
|
217
|
-
if (uri.jwk) {
|
|
218
|
-
return this.kms.asKey(uri);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
let storageKey = uri;
|
|
222
|
-
|
|
223
|
-
if (onBehalfOf) {
|
|
224
|
-
storageKey += `/onBehalfOf/${onBehalfOf}`;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return this.unboundedStorage
|
|
228
|
-
.get(storageKey)
|
|
229
|
-
.then((keyString) => JSON.parse(keyString))
|
|
230
|
-
.then((keyObject) => this.kms.asKey(keyObject))
|
|
231
|
-
.catch(() =>
|
|
232
|
-
this.kms
|
|
233
|
-
.fetchKey({uri, onBehalfOf})
|
|
234
|
-
.then(tap((key) => this.unboundedStorage.put(storageKey, JSON.stringify(key, replacer))))
|
|
235
|
-
);
|
|
236
|
-
},
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* JSON.stringify replacer that ensures private key data is serialized.
|
|
241
|
-
* @param {string} k
|
|
242
|
-
* @param {mixed} v
|
|
243
|
-
* @returns {mixed}
|
|
244
|
-
*/
|
|
245
|
-
function replacer(k, v) {
|
|
246
|
-
if (k === 'jwk') {
|
|
247
|
-
// note: this[k] and v may be different representations of the same value
|
|
248
|
-
// eslint-disable-next-line no-invalid-this
|
|
249
|
-
const json = this[k].toJSON(true);
|
|
250
|
-
|
|
251
|
-
return json;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return v;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
export default Encryption;
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {EventEmitter} from 'events';
|
|
6
|
+
import url from 'url';
|
|
7
|
+
|
|
8
|
+
import {WebexPlugin} from '@webex/webex-core';
|
|
9
|
+
import {proxyEvents, tap, transferEvents} from '@webex/common';
|
|
10
|
+
import jose from 'node-jose';
|
|
11
|
+
import SCR from 'node-scr';
|
|
12
|
+
|
|
13
|
+
import ensureBuffer from './ensure-buffer';
|
|
14
|
+
import KMS from './kms';
|
|
15
|
+
|
|
16
|
+
const Encryption = WebexPlugin.extend({
|
|
17
|
+
children: {
|
|
18
|
+
kms: KMS,
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
namespace: 'Encryption',
|
|
22
|
+
|
|
23
|
+
processKmsMessageEvent(event) {
|
|
24
|
+
return this.kms.processKmsMessageEvent(event);
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
decryptBinary(scr, buffer) {
|
|
28
|
+
return ensureBuffer(buffer).then((b) => {
|
|
29
|
+
/* istanbul ignore if */
|
|
30
|
+
if (buffer.length === 0 || buffer.byteLength === 0) {
|
|
31
|
+
return Promise.reject(new Error('Attempted to decrypt zero-length buffer'));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return scr.decrypt(b);
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Decrypt a SCR (Secure Content Resource) using the supplied key uri.
|
|
40
|
+
*
|
|
41
|
+
* @param {string} key - The uri of a key stored in KMS
|
|
42
|
+
* @param {Object} cipherScr - An encrypted SCR
|
|
43
|
+
* @param {Object} options
|
|
44
|
+
* @param {string} options.onBehalfOf - Fetch the KMS key on behalf of another user (using the user's UUID), active user requires the 'spark.kms_orgagent' role
|
|
45
|
+
* @returns {Object} Decrypted SCR
|
|
46
|
+
*/
|
|
47
|
+
decryptScr(key, cipherScr, options) {
|
|
48
|
+
return this.getKey(key, options).then((k) => SCR.fromJWE(k.jwk, cipherScr));
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Decrypt text using the supplied key uri.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} key - The uri of a key stored in KMS
|
|
55
|
+
* @param {string} ciphertext - Encrypted text
|
|
56
|
+
* @param {Object} options
|
|
57
|
+
* @param {string} options.onBehalfOf - Fetch the KMS key on behalf of another user (using the user's UUID), active user requires the 'spark.kms_orgagent' role
|
|
58
|
+
* @returns {string} Decrypted plaintext
|
|
59
|
+
*/
|
|
60
|
+
decryptText(key, ciphertext, options) {
|
|
61
|
+
return this.getKey(key, options).then((k) =>
|
|
62
|
+
jose.JWE.createDecrypt(k.jwk)
|
|
63
|
+
.decrypt(ciphertext)
|
|
64
|
+
.then((result) => result.plaintext.toString())
|
|
65
|
+
);
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Validate and initiate a Download request for requested file
|
|
70
|
+
*
|
|
71
|
+
* @param {Object} scr - Plaintext
|
|
72
|
+
* @param {Object} options - optional parameters to download a file
|
|
73
|
+
* @returns {promise}
|
|
74
|
+
*/
|
|
75
|
+
download(scr, options) {
|
|
76
|
+
/* istanbul ignore if */
|
|
77
|
+
if (!scr.loc) {
|
|
78
|
+
return Promise.reject(new Error('`scr.loc` is required'));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const shunt = new EventEmitter();
|
|
82
|
+
const promise = this._fetchDownloadUrl(scr, options)
|
|
83
|
+
.then((uri) => {
|
|
84
|
+
// eslint-disable-next-line no-shadow
|
|
85
|
+
const options = {
|
|
86
|
+
method: 'GET',
|
|
87
|
+
uri,
|
|
88
|
+
responseType: 'buffer',
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const ret = this.request(options);
|
|
92
|
+
|
|
93
|
+
transferEvents('progress', options.download, shunt);
|
|
94
|
+
|
|
95
|
+
return ret;
|
|
96
|
+
})
|
|
97
|
+
.then((res) => this.decryptBinary(scr, res.body));
|
|
98
|
+
|
|
99
|
+
proxyEvents(shunt, promise);
|
|
100
|
+
|
|
101
|
+
return promise;
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Fetch Download URL for the requested file
|
|
106
|
+
*
|
|
107
|
+
* @param {Object} scr - Plaintext
|
|
108
|
+
* @param {Object} options - optional parameters to download a file
|
|
109
|
+
* @returns {promise} url of the downloadable file
|
|
110
|
+
*/
|
|
111
|
+
_fetchDownloadUrl(scr, options) {
|
|
112
|
+
this.logger.info('encryption: retrieving download url for encrypted file');
|
|
113
|
+
|
|
114
|
+
if (process.env.NODE_ENV !== 'production' && scr.loc.includes('localhost')) {
|
|
115
|
+
this.logger.info(
|
|
116
|
+
'encryption: bypassing webex files because this looks to be a test file on localhost'
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
return Promise.resolve(scr.loc);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const inputBody = {
|
|
123
|
+
endpoints: [scr.loc],
|
|
124
|
+
};
|
|
125
|
+
const endpointUrl = url.parse(scr.loc);
|
|
126
|
+
|
|
127
|
+
// hardcode the url to use 'https' and the file service '/v1/download/endpoints' api
|
|
128
|
+
endpointUrl.protocol = 'https';
|
|
129
|
+
endpointUrl.pathname = '/v1/download/endpoints';
|
|
130
|
+
|
|
131
|
+
return this.request({
|
|
132
|
+
method: 'POST',
|
|
133
|
+
uri: url.format(endpointUrl),
|
|
134
|
+
body: options
|
|
135
|
+
? {
|
|
136
|
+
...inputBody,
|
|
137
|
+
allow: options.params.allow,
|
|
138
|
+
}
|
|
139
|
+
: inputBody,
|
|
140
|
+
}).then((res) => {
|
|
141
|
+
// eslint-disable-next-line no-shadow
|
|
142
|
+
const url = res.body.endpoints[scr.loc];
|
|
143
|
+
|
|
144
|
+
if (!url) {
|
|
145
|
+
this.logger.warn(
|
|
146
|
+
'encryption: could not determine download url for `scr.loc`; attempting to download `scr.loc` directly'
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
return scr.loc;
|
|
150
|
+
}
|
|
151
|
+
this.logger.info('encryption: retrieved download url for encrypted file');
|
|
152
|
+
|
|
153
|
+
return url;
|
|
154
|
+
});
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
encryptBinary(file) {
|
|
158
|
+
return ensureBuffer(file).then((buffer) =>
|
|
159
|
+
SCR.create().then((scr) =>
|
|
160
|
+
scr
|
|
161
|
+
.encrypt(buffer)
|
|
162
|
+
.then(ensureBuffer)
|
|
163
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
164
|
+
.then((cdata) => ({scr, cdata}))
|
|
165
|
+
)
|
|
166
|
+
);
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Encrypt a SCR (Secure Content Resource) using the supplied key uri.
|
|
171
|
+
*
|
|
172
|
+
* @param {string} key - The uri of a key stored in KMS
|
|
173
|
+
* @param {Object} scr - Plaintext
|
|
174
|
+
* @param {Object} options
|
|
175
|
+
* @param {string} options.onBehalfOf - Fetch the KMS key on behalf of another user (using the user's UUID), active user requires the 'spark.kms_orgagent' role
|
|
176
|
+
* @returns {string} Encrypted SCR
|
|
177
|
+
*/
|
|
178
|
+
encryptScr(key, scr, options) {
|
|
179
|
+
/* istanbul ignore if */
|
|
180
|
+
if (!scr.loc) {
|
|
181
|
+
return Promise.reject(new Error('Cannot encrypt `scr` without first setting `loc`'));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return this.getKey(key, options).then((k) => scr.toJWE(k.jwk));
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Encrypt plaintext using the supplied key uri.
|
|
189
|
+
*
|
|
190
|
+
* @param {string} key - The uri of a key stored in KMS
|
|
191
|
+
* @param {string} plaintext
|
|
192
|
+
* @param {Object} options
|
|
193
|
+
* @param {string} options.onBehalfOf - Fetch the KMS key on behalf of another user (using the user's UUID), active user requires the 'spark.kms_orgagent' role
|
|
194
|
+
* @returns {string} Encrypted text
|
|
195
|
+
*/
|
|
196
|
+
encryptText(key, plaintext, options) {
|
|
197
|
+
return this.getKey(key, options).then((k) =>
|
|
198
|
+
jose.JWE.createEncrypt(this.config.joseOptions, {
|
|
199
|
+
key: k.jwk,
|
|
200
|
+
header: {
|
|
201
|
+
alg: 'dir',
|
|
202
|
+
},
|
|
203
|
+
reference: null,
|
|
204
|
+
}).final(plaintext, 'utf8')
|
|
205
|
+
);
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Fetch the key associated with the supplied KMS uri.
|
|
210
|
+
*
|
|
211
|
+
* @param {string} uri - The uri of a key stored in KMS
|
|
212
|
+
* @param {Object} options
|
|
213
|
+
* @param {string} options.onBehalfOf - Fetch the KMS key on behalf of another user (using the user's UUID), active user requires the 'spark.kms_orgagent' role
|
|
214
|
+
* @returns {string} Key
|
|
215
|
+
*/
|
|
216
|
+
getKey(uri, {onBehalfOf} = {}) {
|
|
217
|
+
if (uri.jwk) {
|
|
218
|
+
return this.kms.asKey(uri);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
let storageKey = uri;
|
|
222
|
+
|
|
223
|
+
if (onBehalfOf) {
|
|
224
|
+
storageKey += `/onBehalfOf/${onBehalfOf}`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return this.unboundedStorage
|
|
228
|
+
.get(storageKey)
|
|
229
|
+
.then((keyString) => JSON.parse(keyString))
|
|
230
|
+
.then((keyObject) => this.kms.asKey(keyObject))
|
|
231
|
+
.catch(() =>
|
|
232
|
+
this.kms
|
|
233
|
+
.fetchKey({uri, onBehalfOf})
|
|
234
|
+
.then(tap((key) => this.unboundedStorage.put(storageKey, JSON.stringify(key, replacer))))
|
|
235
|
+
);
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* JSON.stringify replacer that ensures private key data is serialized.
|
|
241
|
+
* @param {string} k
|
|
242
|
+
* @param {mixed} v
|
|
243
|
+
* @returns {mixed}
|
|
244
|
+
*/
|
|
245
|
+
function replacer(k, v) {
|
|
246
|
+
if (k === 'jwk') {
|
|
247
|
+
// note: this[k] and v may be different representations of the same value
|
|
248
|
+
// eslint-disable-next-line no-invalid-this
|
|
249
|
+
const json = this[k].toJSON(true);
|
|
250
|
+
|
|
251
|
+
return json;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return v;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export default Encryption;
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/* eslint-env: browser */
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Ensures the provider buffer is, indeed, an ArrayBuffer; converts File and
|
|
9
|
-
* Blob objects to ArrayBuffers.
|
|
10
|
-
* @param {mixed} buffer
|
|
11
|
-
* @returns {Promise<ArrayBuffer>}
|
|
12
|
-
*/
|
|
13
|
-
export default function ensureBuffer(buffer) {
|
|
14
|
-
if (buffer instanceof ArrayBuffer) {
|
|
15
|
-
return Promise.resolve(buffer);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (buffer.toArrayBuffer) {
|
|
19
|
-
return Promise.resolve(buffer.toArrayBuffer());
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (buffer.buffer) {
|
|
23
|
-
return Promise.resolve(buffer.buffer);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return new Promise((resolve, reject) => {
|
|
27
|
-
const fr = new FileReader();
|
|
28
|
-
|
|
29
|
-
fr.onload = function onload() {
|
|
30
|
-
resolve(new Uint8Array(this.result));
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
fr.onerror = reject;
|
|
34
|
-
|
|
35
|
-
fr.readAsArrayBuffer(buffer);
|
|
36
|
-
});
|
|
37
|
-
}
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/* eslint-env: browser */
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Ensures the provider buffer is, indeed, an ArrayBuffer; converts File and
|
|
9
|
+
* Blob objects to ArrayBuffers.
|
|
10
|
+
* @param {mixed} buffer
|
|
11
|
+
* @returns {Promise<ArrayBuffer>}
|
|
12
|
+
*/
|
|
13
|
+
export default function ensureBuffer(buffer) {
|
|
14
|
+
if (buffer instanceof ArrayBuffer) {
|
|
15
|
+
return Promise.resolve(buffer);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (buffer.toArrayBuffer) {
|
|
19
|
+
return Promise.resolve(buffer.toArrayBuffer());
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (buffer.buffer) {
|
|
23
|
+
return Promise.resolve(buffer.buffer);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
const fr = new FileReader();
|
|
28
|
+
|
|
29
|
+
fr.onload = function onload() {
|
|
30
|
+
resolve(new Uint8Array(this.result));
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
fr.onerror = reject;
|
|
34
|
+
|
|
35
|
+
fr.readAsArrayBuffer(buffer);
|
|
36
|
+
});
|
|
37
|
+
}
|
package/src/ensure-buffer.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {isBuffer} from '@webex/common';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Ensures the provider Buffer is, indeed, a Buffer; sometimes, they seem to be
|
|
9
|
-
* byte-arrays instead of proper Buffer objects.
|
|
10
|
-
* @param {mixed} buffer
|
|
11
|
-
* @returns {Promise<Buffer>}
|
|
12
|
-
*/
|
|
13
|
-
export default function ensureBuffer(buffer) {
|
|
14
|
-
/* istanbul ignore if */
|
|
15
|
-
if (!isBuffer(buffer)) {
|
|
16
|
-
return Promise.reject(new Error('`buffer` must be a buffer'));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return Promise.resolve(buffer);
|
|
20
|
-
}
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {isBuffer} from '@webex/common';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Ensures the provider Buffer is, indeed, a Buffer; sometimes, they seem to be
|
|
9
|
+
* byte-arrays instead of proper Buffer objects.
|
|
10
|
+
* @param {mixed} buffer
|
|
11
|
+
* @returns {Promise<Buffer>}
|
|
12
|
+
*/
|
|
13
|
+
export default function ensureBuffer(buffer) {
|
|
14
|
+
/* istanbul ignore if */
|
|
15
|
+
if (!isBuffer(buffer)) {
|
|
16
|
+
return Promise.reject(new Error('`buffer` must be a buffer'));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return Promise.resolve(buffer);
|
|
20
|
+
}
|