@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.
Files changed (42) hide show
  1. package/.eslintrc.js +6 -6
  2. package/README.md +42 -42
  3. package/babel.config.js +3 -3
  4. package/dist/config.js +21 -21
  5. package/dist/config.js.map +1 -1
  6. package/dist/encryption.js +57 -57
  7. package/dist/encryption.js.map +1 -1
  8. package/dist/ensure-buffer.browser.js +7 -7
  9. package/dist/ensure-buffer.browser.js.map +1 -1
  10. package/dist/ensure-buffer.js +7 -7
  11. package/dist/ensure-buffer.js.map +1 -1
  12. package/dist/index.js +2 -2
  13. package/dist/index.js.map +1 -1
  14. package/dist/kms-batcher.js +38 -38
  15. package/dist/kms-batcher.js.map +1 -1
  16. package/dist/kms-certificate-validation.js +50 -50
  17. package/dist/kms-certificate-validation.js.map +1 -1
  18. package/dist/kms-dry-error-interceptor.js +15 -15
  19. package/dist/kms-dry-error-interceptor.js.map +1 -1
  20. package/dist/kms-errors.js +16 -16
  21. package/dist/kms-errors.js.map +1 -1
  22. package/dist/kms.js +171 -171
  23. package/dist/kms.js.map +1 -1
  24. package/jest.config.js +3 -3
  25. package/package.json +20 -19
  26. package/process +1 -1
  27. package/src/config.js +50 -50
  28. package/src/encryption.js +257 -257
  29. package/src/ensure-buffer.browser.js +37 -37
  30. package/src/ensure-buffer.js +20 -20
  31. package/src/index.js +159 -159
  32. package/src/kms-batcher.js +158 -158
  33. package/src/kms-certificate-validation.js +232 -232
  34. package/src/kms-dry-error-interceptor.js +65 -65
  35. package/src/kms-errors.js +147 -147
  36. package/src/kms.js +848 -848
  37. package/test/integration/spec/encryption.js +448 -448
  38. package/test/integration/spec/kms.js +800 -800
  39. package/test/integration/spec/payload-transfom.js +97 -97
  40. package/test/unit/spec/encryption.js +82 -82
  41. package/test/unit/spec/kms-certificate-validation.js +165 -165
  42. package/test/unit/spec/kms.js +103 -103
@@ -1,448 +1,448 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import '@webex/internal-plugin-encryption';
6
-
7
- import {isBuffer} from '@webex/common';
8
- import {assert, expect} from '@webex/test-helper-chai';
9
- import file from '@webex/test-helper-file';
10
- import sinon from 'sinon';
11
- import WebexCore from '@webex/webex-core';
12
- import testUsers from '@webex/test-helper-test-users';
13
- import makeLocalUrl from '@webex/test-helper-make-local-url';
14
-
15
- describe('Encryption', function () {
16
- this.timeout(30000);
17
-
18
- let key, user, webex;
19
-
20
- const PLAINTEXT =
21
- 'Admiral, if we go "by the book". like Lieutenant Saavik, hours could seem like days.';
22
- let FILE = makeLocalUrl('/sample-image-small-one.png');
23
-
24
- before('create test user', () =>
25
- testUsers.create({count: 1}).then((users) => {
26
- user = users[0];
27
- webex = new WebexCore({
28
- credentials: {
29
- authorization: user.token,
30
- },
31
- });
32
- assert.isTrue(webex.isAuthenticated || webex.canAuthorize);
33
- })
34
- );
35
-
36
- before('create unbound key', () =>
37
- webex.internal.encryption.kms.createUnboundKeys({count: 1}).then(([k]) => {
38
- key = k;
39
- })
40
- );
41
-
42
- before('fetch file fixture', () =>
43
- webex
44
- .request({
45
- uri: FILE,
46
- responseType: 'buffer',
47
- })
48
- .then((res) => {
49
- FILE = res.body;
50
- })
51
- );
52
-
53
- after(() => webex && webex.internal.mercury.disconnect());
54
-
55
- describe('#decryptBinary()', () => {
56
- it('decrypts a binary file', () =>
57
- webex.internal.encryption.encryptBinary(FILE).then(({scr, cdata}) => {
58
- scr.loc = 'file:///file.enc';
59
-
60
- return webex.internal.encryption
61
- .encryptScr(key, scr)
62
- .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
63
- .then((decryptedScr) => webex.internal.encryption.decryptBinary(decryptedScr, cdata))
64
- .then((f) => {
65
- assert.isTrue(isBuffer(f));
66
-
67
- return assert.equal(f.byteLength, FILE.byteLength);
68
- });
69
- }));
70
- });
71
-
72
- describe('#decryptScr()', () => {
73
- it('decrypts an scr', () =>
74
- webex.internal.encryption.encryptBinary(FILE).then(({scr}) => {
75
- scr.loc = 'file:///file.enc';
76
-
77
- return webex.internal.encryption
78
- .encryptScr(key, scr)
79
- .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
80
- .then((decryptedScr) => assert.deepEqual(decryptedScr, scr));
81
- }));
82
- });
83
-
84
- describe('#decryptText()', () => {
85
- it('decrypts text', () =>
86
- webex.internal.encryption
87
- .encryptText(key, PLAINTEXT)
88
- .then((ciphertext) => {
89
- assert.notEqual(ciphertext, PLAINTEXT);
90
-
91
- return webex.internal.encryption.decryptText(key, ciphertext);
92
- })
93
- .then((plaintext) => assert.equal(plaintext, PLAINTEXT)));
94
- });
95
-
96
- describe('#getKey()', () => {
97
- let fetchKeySpy, otherWebex, otherUser, storageGetSpy;
98
-
99
- before('create test user', () =>
100
- testUsers.create({count: 1}).then((users) => {
101
- otherUser = users[0];
102
- otherWebex = new WebexCore({
103
- credentials: {
104
- authorization: otherUser.token,
105
- },
106
- });
107
- assert.isTrue(otherWebex.canAuthorize);
108
- })
109
- );
110
-
111
- before('create kms resource', () =>
112
- webex.internal.encryption.kms.createResource({
113
- key,
114
- userIds: [webex.internal.device.userId, otherUser.id],
115
- })
116
- );
117
-
118
- after(() => otherWebex && otherWebex.internal.mercury.disconnect());
119
-
120
- beforeEach(() => {
121
- fetchKeySpy = sinon.spy(otherWebex.internal.encryption.kms, 'fetchKey');
122
- storageGetSpy = sinon.spy(otherWebex.internal.encryption.unboundedStorage, 'get');
123
- });
124
-
125
- afterEach(() => {
126
- fetchKeySpy.restore();
127
- storageGetSpy.restore();
128
- });
129
-
130
- it('shortcircuits if it receives a key instead of a keyUri', () =>
131
- webex.internal.encryption
132
- .getKey(key)
133
- // Reminder: If this starts failing after a node-jose upgrade, it probably
134
- // implies node-jose stopped shortcircuiting correctly.
135
- .then((k) => assert.equal(k, key)));
136
-
137
- it('attempts to retrieve the specified key from the local cache', () =>
138
- otherWebex.internal.encryption
139
- .getKey(key.uri)
140
- .then((k) => assert.calledWith(storageGetSpy, k.uri)));
141
-
142
- it('fetches the key from the kms', () =>
143
- otherWebex.internal.encryption.unboundedStorage
144
- .del(key.uri)
145
- .then(() => assert.notCalled(fetchKeySpy))
146
- .then(() => otherWebex.internal.encryption.getKey(key.uri))
147
- .then(() => assert.calledOnce(fetchKeySpy)));
148
-
149
- it('stores the newly retrieved key', () =>
150
- otherWebex.internal.encryption
151
- .getKey(key.uri)
152
- .then((k) => otherWebex.internal.encryption.unboundedStorage.get(k.uri))
153
- .then((str) => JSON.parse(str))
154
- .then((k2) => {
155
- assert.property(k2, 'jwk');
156
- assert.property(k2.jwk, 'k');
157
- assert.equal(key.jwk.kid, k2.jwk.kid);
158
- }));
159
- });
160
-
161
- describe('#download()', () => {
162
- it('downloads and decrypts an encrypted file', () =>
163
- webex.internal.encryption
164
- .encryptBinary(FILE)
165
- .then(({scr, cdata}) =>
166
- webex
167
- .request({
168
- method: 'POST',
169
- uri: makeLocalUrl('/files/upload'),
170
- body: cdata,
171
- })
172
- .then((res) => {
173
- scr.loc = makeLocalUrl(res.body.loc, {full: true});
174
-
175
- return webex.internal.encryption.encryptScr(key, scr);
176
- })
177
- )
178
- .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
179
- .then((scr) => webex.internal.encryption.download(scr))
180
- .then((f) =>
181
- file.isMatchingFile(f, FILE).then((result) => assert.deepEqual(result, true))
182
- ));
183
-
184
- it('downloads and decrypts an encrypted file with options param', () =>
185
- webex.internal.encryption
186
- .encryptBinary(FILE)
187
- .then(({scr, cdata}) =>
188
- webex
189
- .request({
190
- method: 'POST',
191
- uri: makeLocalUrl('/files/upload'),
192
- body: cdata,
193
- })
194
- .then((res) => {
195
- scr.loc = makeLocalUrl(res.body.loc, {full: true});
196
-
197
- return webex.internal.encryption.encryptScr(key, scr);
198
- })
199
- )
200
- .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
201
- .then((scr) => {
202
- const options = {
203
- params: {
204
- allow: 'none',
205
- },
206
- };
207
-
208
- return webex.internal.encryption.download(scr, options);
209
- })
210
- .then((f) => file.isMatchingFile(f, FILE))
211
- .then((result) => assert.deepEqual(result, true)));
212
-
213
- it('emits progress events', () => {
214
- const spy = sinon.spy();
215
-
216
- return webex.internal.encryption
217
- .encryptBinary(FILE)
218
- .then(({scr, cdata}) =>
219
- webex
220
- .request({
221
- method: 'POST',
222
- uri: makeLocalUrl('/files/upload'),
223
- body: cdata,
224
- })
225
- .then((res) => {
226
- scr.loc = makeLocalUrl(res.body.loc, {full: true});
227
-
228
- return webex.internal.encryption.encryptScr(key, scr);
229
- })
230
- )
231
- .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
232
- .then((scr) => webex.internal.encryption.download(scr).on('progress', spy))
233
- .then(() => assert.called(spy));
234
- });
235
-
236
- it('checks body of the API call /downloads/endpoints', () =>
237
- webex.internal.encryption
238
- .encryptBinary(FILE)
239
- .then(({scr, cdata}) =>
240
- webex
241
- .request({
242
- method: 'POST',
243
- uri: makeLocalUrl('/files/upload'),
244
- body: cdata,
245
- })
246
- .then((res) => {
247
- scr.loc = makeLocalUrl(res.body.loc, {full: true});
248
-
249
- return webex.internal.encryption.encryptScr(key, scr);
250
- })
251
- )
252
- .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
253
- .then((scr) => {
254
- const options = {
255
- params: {
256
- allow: ['unchecked', 'evaluating'],
257
- },
258
- };
259
-
260
- return webex.internal.encryption.download(scr, options);
261
- })
262
- .then((f) => file.isMatchingFile(f, FILE))
263
- .then((result) => assert.deepEqual(result, true)));
264
-
265
- it('checks _fetchDownloadUrl()', () =>
266
- webex.internal.encryption
267
- .encryptBinary(FILE)
268
- .then(({scr, cdata}) =>
269
- webex
270
- .request({
271
- method: 'POST',
272
- uri: makeLocalUrl('/files/upload'),
273
- body: cdata,
274
- })
275
- .then((res) => {
276
- scr.loc = makeLocalUrl(res.body.loc, {full: true});
277
-
278
- return webex.internal.encryption.encryptScr(key, scr);
279
- })
280
- )
281
- .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
282
- .then((scr) => {
283
- const options = {
284
- params: {
285
- allow: ['unchecked', 'evaluating'],
286
- },
287
- };
288
-
289
- return webex.internal.encryption._fetchDownloadUrl(scr, options);
290
- })
291
- .then((result) => assert.isString(result)));
292
- });
293
-
294
- describe('#encryptBinary()', () => {
295
- it('encrypts a binary file', () =>
296
- webex.internal.encryption.encryptBinary(FILE).then(({scr, cdata}) => {
297
- assert.property(scr, 'enc');
298
- assert.property(scr, 'key');
299
- assert.property(scr, 'iv');
300
-
301
- return assert.isBufferLike(cdata);
302
- }));
303
-
304
- // browserOnly(it)(`accepts an ArrayBuffer`);
305
- // browserOnly(it)(`accepts a Blob`);
306
- });
307
-
308
- describe('#encryptScr()', () => {
309
- it('encrypts an scr', () =>
310
- webex.internal.encryption
311
- .encryptBinary(FILE)
312
- .then(({scr}) => {
313
- scr.loc = 'file:///file.enc';
314
-
315
- return webex.internal.encryption.encryptScr(key, scr);
316
- })
317
- .then((cipherScr) => assert.isString(cipherScr)));
318
- });
319
-
320
- describe('#encryptText()', () => {
321
- it('encrypts text', () =>
322
- webex.internal.encryption
323
- .encryptText(key, PLAINTEXT)
324
- .then((ciphertext) => assert.notEqual(ciphertext, PLAINTEXT)));
325
- });
326
-
327
- describe('#onBehalfOf', () => {
328
- let complianceUser;
329
-
330
- before('create compliance officer test user', () =>
331
- testUsers
332
- .create({
333
- count: 1,
334
- config: {
335
- roles: [{name: 'spark.kms_orgagent'}],
336
- },
337
- })
338
- .then((users) => {
339
- complianceUser = users[0];
340
- complianceUser.webex = new WebexCore({
341
- credentials: {
342
- authorization: complianceUser.token,
343
- },
344
- });
345
- assert.isTrue(complianceUser.webex.canAuthorize);
346
- })
347
- );
348
-
349
- after(() => complianceUser && complianceUser.webex.internal.mercury.disconnect());
350
-
351
- it('decrypt text', () =>
352
- webex.internal.encryption
353
- .encryptText(key, PLAINTEXT)
354
- .then((ciphertext) => {
355
- assert.notEqual(ciphertext, PLAINTEXT);
356
-
357
- return complianceUser.webex.internal.encryption.decryptText(key, ciphertext, {
358
- onBehalfOf: user.id,
359
- });
360
- })
361
- .then((plaintext) => assert.equal(plaintext, PLAINTEXT)));
362
-
363
- it('encrypt and decrypt text', () =>
364
- complianceUser.webex.internal.encryption
365
- .encryptText(key, PLAINTEXT, {onBehalfOf: user.id})
366
- .then((ciphertext) => {
367
- assert.notEqual(ciphertext, PLAINTEXT);
368
-
369
- return complianceUser.webex.internal.encryption.decryptText(key, ciphertext, {
370
- onBehalfOf: user.id,
371
- });
372
- })
373
- .then((plaintext) => assert.equal(plaintext, PLAINTEXT)));
374
-
375
- it('decrypt scr', () =>
376
- webex.internal.encryption.encryptBinary(FILE).then(({scr}) => {
377
- scr.loc = 'file:///file.enc';
378
-
379
- return webex.internal.encryption
380
- .encryptScr(key, scr)
381
- .then((cipherScr) =>
382
- complianceUser.webex.internal.encryption.decryptScr(key, cipherScr, {
383
- onBehalfOf: user.id,
384
- })
385
- )
386
- .then((decryptedScr) => assert.deepEqual(decryptedScr, scr));
387
- }));
388
-
389
- it('decrypt scr', () =>
390
- webex.internal.encryption.encryptBinary(FILE).then(({scr}) => {
391
- scr.loc = 'file:///file.enc';
392
-
393
- return complianceUser.webex.internal.encryption
394
- .encryptScr(key, scr, {onBehalfOf: user.id})
395
- .then((cipherScr) =>
396
- complianceUser.webex.internal.encryption.decryptScr(key, cipherScr, {
397
- onBehalfOf: user.id,
398
- })
399
- )
400
- .then((decryptedScr) => assert.deepEqual(decryptedScr, scr));
401
- }));
402
-
403
- it('getKey', () =>
404
- complianceUser.webex.internal.encryption
405
- .getKey(key.uri, {onBehalfOf: user.id})
406
- .then((key2) => {
407
- assert.property(key2, 'uri');
408
- assert.property(key2, 'jwk');
409
- assert.notEqual(key2, key);
410
- assert.equal(key2.uri, key.uri);
411
- }));
412
-
413
- it('getKey forbidden as compliance officer does not have access', () =>
414
- complianceUser.webex.internal.encryption.getKey(key.uri).then(
415
- (value) => expect.fail(`Compliance officer has retrieved key without onBehalfOf: ${value}`),
416
- (error) => expect(error.body.status).to.equal(403)
417
- ));
418
-
419
- it('getKey forbidden as user does not have access', () =>
420
- complianceUser.webex.internal.encryption
421
- .getKey(key.uri, {onBehalfOf: '7851fe79-7c87-40cc-ac36-8b77b011b399'})
422
- .then(
423
- (value) =>
424
- expect.fail(
425
- `Should not be found as 7851fe79-7c87-40cc-ac36-8b77b011b399 does not have access ${value}`
426
- ),
427
- (error) => expect(error.body.status).to.equal(403)
428
- ));
429
-
430
- it('getKey onBehalfOf and then by compliance officer only', () =>
431
- complianceUser.webex.internal.encryption
432
- .getKey(key.uri, {onBehalfOf: user.id})
433
- .then((key2) => {
434
- assert.property(key2, 'uri');
435
- assert.property(key2, 'jwk');
436
- assert.notEqual(key2, key);
437
- assert.equal(key2.uri, key.uri);
438
- })
439
- .then(() => complianceUser.webex.internal.encryption.getKey(key.uri))
440
- .then(
441
- (value) =>
442
- expect.fail(
443
- `Compliance should no longer be able to retrieve key as onBehalfOf was not set: ${value}`
444
- ),
445
- (error) => expect(error.body.status).to.equal(403)
446
- ));
447
- });
448
- });
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import '@webex/internal-plugin-encryption';
6
+
7
+ import {isBuffer} from '@webex/common';
8
+ import {assert, expect} from '@webex/test-helper-chai';
9
+ import file from '@webex/test-helper-file';
10
+ import sinon from 'sinon';
11
+ import WebexCore from '@webex/webex-core';
12
+ import testUsers from '@webex/test-helper-test-users';
13
+ import makeLocalUrl from '@webex/test-helper-make-local-url';
14
+
15
+ describe('Encryption', function () {
16
+ this.timeout(30000);
17
+
18
+ let key, user, webex;
19
+
20
+ const PLAINTEXT =
21
+ 'Admiral, if we go "by the book". like Lieutenant Saavik, hours could seem like days.';
22
+ let FILE = makeLocalUrl('/sample-image-small-one.png');
23
+
24
+ before('create test user', () =>
25
+ testUsers.create({count: 1}).then((users) => {
26
+ user = users[0];
27
+ webex = new WebexCore({
28
+ credentials: {
29
+ authorization: user.token,
30
+ },
31
+ });
32
+ assert.isTrue(webex.isAuthenticated || webex.canAuthorize);
33
+ })
34
+ );
35
+
36
+ before('create unbound key', () =>
37
+ webex.internal.encryption.kms.createUnboundKeys({count: 1}).then(([k]) => {
38
+ key = k;
39
+ })
40
+ );
41
+
42
+ before('fetch file fixture', () =>
43
+ webex
44
+ .request({
45
+ uri: FILE,
46
+ responseType: 'buffer',
47
+ })
48
+ .then((res) => {
49
+ FILE = res.body;
50
+ })
51
+ );
52
+
53
+ after(() => webex && webex.internal.mercury.disconnect());
54
+
55
+ describe('#decryptBinary()', () => {
56
+ it('decrypts a binary file', () =>
57
+ webex.internal.encryption.encryptBinary(FILE).then(({scr, cdata}) => {
58
+ scr.loc = 'file:///file.enc';
59
+
60
+ return webex.internal.encryption
61
+ .encryptScr(key, scr)
62
+ .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
63
+ .then((decryptedScr) => webex.internal.encryption.decryptBinary(decryptedScr, cdata))
64
+ .then((f) => {
65
+ assert.isTrue(isBuffer(f));
66
+
67
+ return assert.equal(f.byteLength, FILE.byteLength);
68
+ });
69
+ }));
70
+ });
71
+
72
+ describe('#decryptScr()', () => {
73
+ it('decrypts an scr', () =>
74
+ webex.internal.encryption.encryptBinary(FILE).then(({scr}) => {
75
+ scr.loc = 'file:///file.enc';
76
+
77
+ return webex.internal.encryption
78
+ .encryptScr(key, scr)
79
+ .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
80
+ .then((decryptedScr) => assert.deepEqual(decryptedScr, scr));
81
+ }));
82
+ });
83
+
84
+ describe('#decryptText()', () => {
85
+ it('decrypts text', () =>
86
+ webex.internal.encryption
87
+ .encryptText(key, PLAINTEXT)
88
+ .then((ciphertext) => {
89
+ assert.notEqual(ciphertext, PLAINTEXT);
90
+
91
+ return webex.internal.encryption.decryptText(key, ciphertext);
92
+ })
93
+ .then((plaintext) => assert.equal(plaintext, PLAINTEXT)));
94
+ });
95
+
96
+ describe('#getKey()', () => {
97
+ let fetchKeySpy, otherWebex, otherUser, storageGetSpy;
98
+
99
+ before('create test user', () =>
100
+ testUsers.create({count: 1}).then((users) => {
101
+ otherUser = users[0];
102
+ otherWebex = new WebexCore({
103
+ credentials: {
104
+ authorization: otherUser.token,
105
+ },
106
+ });
107
+ assert.isTrue(otherWebex.canAuthorize);
108
+ })
109
+ );
110
+
111
+ before('create kms resource', () =>
112
+ webex.internal.encryption.kms.createResource({
113
+ key,
114
+ userIds: [webex.internal.device.userId, otherUser.id],
115
+ })
116
+ );
117
+
118
+ after(() => otherWebex && otherWebex.internal.mercury.disconnect());
119
+
120
+ beforeEach(() => {
121
+ fetchKeySpy = sinon.spy(otherWebex.internal.encryption.kms, 'fetchKey');
122
+ storageGetSpy = sinon.spy(otherWebex.internal.encryption.unboundedStorage, 'get');
123
+ });
124
+
125
+ afterEach(() => {
126
+ fetchKeySpy.restore();
127
+ storageGetSpy.restore();
128
+ });
129
+
130
+ it('shortcircuits if it receives a key instead of a keyUri', () =>
131
+ webex.internal.encryption
132
+ .getKey(key)
133
+ // Reminder: If this starts failing after a node-jose upgrade, it probably
134
+ // implies node-jose stopped shortcircuiting correctly.
135
+ .then((k) => assert.equal(k, key)));
136
+
137
+ it('attempts to retrieve the specified key from the local cache', () =>
138
+ otherWebex.internal.encryption
139
+ .getKey(key.uri)
140
+ .then((k) => assert.calledWith(storageGetSpy, k.uri)));
141
+
142
+ it('fetches the key from the kms', () =>
143
+ otherWebex.internal.encryption.unboundedStorage
144
+ .del(key.uri)
145
+ .then(() => assert.notCalled(fetchKeySpy))
146
+ .then(() => otherWebex.internal.encryption.getKey(key.uri))
147
+ .then(() => assert.calledOnce(fetchKeySpy)));
148
+
149
+ it('stores the newly retrieved key', () =>
150
+ otherWebex.internal.encryption
151
+ .getKey(key.uri)
152
+ .then((k) => otherWebex.internal.encryption.unboundedStorage.get(k.uri))
153
+ .then((str) => JSON.parse(str))
154
+ .then((k2) => {
155
+ assert.property(k2, 'jwk');
156
+ assert.property(k2.jwk, 'k');
157
+ assert.equal(key.jwk.kid, k2.jwk.kid);
158
+ }));
159
+ });
160
+
161
+ describe('#download()', () => {
162
+ it('downloads and decrypts an encrypted file', () =>
163
+ webex.internal.encryption
164
+ .encryptBinary(FILE)
165
+ .then(({scr, cdata}) =>
166
+ webex
167
+ .request({
168
+ method: 'POST',
169
+ uri: makeLocalUrl('/files/upload'),
170
+ body: cdata,
171
+ })
172
+ .then((res) => {
173
+ scr.loc = makeLocalUrl(res.body.loc, {full: true});
174
+
175
+ return webex.internal.encryption.encryptScr(key, scr);
176
+ })
177
+ )
178
+ .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
179
+ .then((scr) => webex.internal.encryption.download(scr))
180
+ .then((f) =>
181
+ file.isMatchingFile(f, FILE).then((result) => assert.deepEqual(result, true))
182
+ ));
183
+
184
+ it('downloads and decrypts an encrypted file with options param', () =>
185
+ webex.internal.encryption
186
+ .encryptBinary(FILE)
187
+ .then(({scr, cdata}) =>
188
+ webex
189
+ .request({
190
+ method: 'POST',
191
+ uri: makeLocalUrl('/files/upload'),
192
+ body: cdata,
193
+ })
194
+ .then((res) => {
195
+ scr.loc = makeLocalUrl(res.body.loc, {full: true});
196
+
197
+ return webex.internal.encryption.encryptScr(key, scr);
198
+ })
199
+ )
200
+ .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
201
+ .then((scr) => {
202
+ const options = {
203
+ params: {
204
+ allow: 'none',
205
+ },
206
+ };
207
+
208
+ return webex.internal.encryption.download(scr, options);
209
+ })
210
+ .then((f) => file.isMatchingFile(f, FILE))
211
+ .then((result) => assert.deepEqual(result, true)));
212
+
213
+ it('emits progress events', () => {
214
+ const spy = sinon.spy();
215
+
216
+ return webex.internal.encryption
217
+ .encryptBinary(FILE)
218
+ .then(({scr, cdata}) =>
219
+ webex
220
+ .request({
221
+ method: 'POST',
222
+ uri: makeLocalUrl('/files/upload'),
223
+ body: cdata,
224
+ })
225
+ .then((res) => {
226
+ scr.loc = makeLocalUrl(res.body.loc, {full: true});
227
+
228
+ return webex.internal.encryption.encryptScr(key, scr);
229
+ })
230
+ )
231
+ .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
232
+ .then((scr) => webex.internal.encryption.download(scr).on('progress', spy))
233
+ .then(() => assert.called(spy));
234
+ });
235
+
236
+ it('checks body of the API call /downloads/endpoints', () =>
237
+ webex.internal.encryption
238
+ .encryptBinary(FILE)
239
+ .then(({scr, cdata}) =>
240
+ webex
241
+ .request({
242
+ method: 'POST',
243
+ uri: makeLocalUrl('/files/upload'),
244
+ body: cdata,
245
+ })
246
+ .then((res) => {
247
+ scr.loc = makeLocalUrl(res.body.loc, {full: true});
248
+
249
+ return webex.internal.encryption.encryptScr(key, scr);
250
+ })
251
+ )
252
+ .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
253
+ .then((scr) => {
254
+ const options = {
255
+ params: {
256
+ allow: ['unchecked', 'evaluating'],
257
+ },
258
+ };
259
+
260
+ return webex.internal.encryption.download(scr, options);
261
+ })
262
+ .then((f) => file.isMatchingFile(f, FILE))
263
+ .then((result) => assert.deepEqual(result, true)));
264
+
265
+ it('checks _fetchDownloadUrl()', () =>
266
+ webex.internal.encryption
267
+ .encryptBinary(FILE)
268
+ .then(({scr, cdata}) =>
269
+ webex
270
+ .request({
271
+ method: 'POST',
272
+ uri: makeLocalUrl('/files/upload'),
273
+ body: cdata,
274
+ })
275
+ .then((res) => {
276
+ scr.loc = makeLocalUrl(res.body.loc, {full: true});
277
+
278
+ return webex.internal.encryption.encryptScr(key, scr);
279
+ })
280
+ )
281
+ .then((cipherScr) => webex.internal.encryption.decryptScr(key, cipherScr))
282
+ .then((scr) => {
283
+ const options = {
284
+ params: {
285
+ allow: ['unchecked', 'evaluating'],
286
+ },
287
+ };
288
+
289
+ return webex.internal.encryption._fetchDownloadUrl(scr, options);
290
+ })
291
+ .then((result) => assert.isString(result)));
292
+ });
293
+
294
+ describe('#encryptBinary()', () => {
295
+ it('encrypts a binary file', () =>
296
+ webex.internal.encryption.encryptBinary(FILE).then(({scr, cdata}) => {
297
+ assert.property(scr, 'enc');
298
+ assert.property(scr, 'key');
299
+ assert.property(scr, 'iv');
300
+
301
+ return assert.isBufferLike(cdata);
302
+ }));
303
+
304
+ // browserOnly(it)(`accepts an ArrayBuffer`);
305
+ // browserOnly(it)(`accepts a Blob`);
306
+ });
307
+
308
+ describe('#encryptScr()', () => {
309
+ it('encrypts an scr', () =>
310
+ webex.internal.encryption
311
+ .encryptBinary(FILE)
312
+ .then(({scr}) => {
313
+ scr.loc = 'file:///file.enc';
314
+
315
+ return webex.internal.encryption.encryptScr(key, scr);
316
+ })
317
+ .then((cipherScr) => assert.isString(cipherScr)));
318
+ });
319
+
320
+ describe('#encryptText()', () => {
321
+ it('encrypts text', () =>
322
+ webex.internal.encryption
323
+ .encryptText(key, PLAINTEXT)
324
+ .then((ciphertext) => assert.notEqual(ciphertext, PLAINTEXT)));
325
+ });
326
+
327
+ describe('#onBehalfOf', () => {
328
+ let complianceUser;
329
+
330
+ before('create compliance officer test user', () =>
331
+ testUsers
332
+ .create({
333
+ count: 1,
334
+ config: {
335
+ roles: [{name: 'spark.kms_orgagent'}],
336
+ },
337
+ })
338
+ .then((users) => {
339
+ complianceUser = users[0];
340
+ complianceUser.webex = new WebexCore({
341
+ credentials: {
342
+ authorization: complianceUser.token,
343
+ },
344
+ });
345
+ assert.isTrue(complianceUser.webex.canAuthorize);
346
+ })
347
+ );
348
+
349
+ after(() => complianceUser && complianceUser.webex.internal.mercury.disconnect());
350
+
351
+ it('decrypt text', () =>
352
+ webex.internal.encryption
353
+ .encryptText(key, PLAINTEXT)
354
+ .then((ciphertext) => {
355
+ assert.notEqual(ciphertext, PLAINTEXT);
356
+
357
+ return complianceUser.webex.internal.encryption.decryptText(key, ciphertext, {
358
+ onBehalfOf: user.id,
359
+ });
360
+ })
361
+ .then((plaintext) => assert.equal(plaintext, PLAINTEXT)));
362
+
363
+ it('encrypt and decrypt text', () =>
364
+ complianceUser.webex.internal.encryption
365
+ .encryptText(key, PLAINTEXT, {onBehalfOf: user.id})
366
+ .then((ciphertext) => {
367
+ assert.notEqual(ciphertext, PLAINTEXT);
368
+
369
+ return complianceUser.webex.internal.encryption.decryptText(key, ciphertext, {
370
+ onBehalfOf: user.id,
371
+ });
372
+ })
373
+ .then((plaintext) => assert.equal(plaintext, PLAINTEXT)));
374
+
375
+ it('decrypt scr', () =>
376
+ webex.internal.encryption.encryptBinary(FILE).then(({scr}) => {
377
+ scr.loc = 'file:///file.enc';
378
+
379
+ return webex.internal.encryption
380
+ .encryptScr(key, scr)
381
+ .then((cipherScr) =>
382
+ complianceUser.webex.internal.encryption.decryptScr(key, cipherScr, {
383
+ onBehalfOf: user.id,
384
+ })
385
+ )
386
+ .then((decryptedScr) => assert.deepEqual(decryptedScr, scr));
387
+ }));
388
+
389
+ it('decrypt scr', () =>
390
+ webex.internal.encryption.encryptBinary(FILE).then(({scr}) => {
391
+ scr.loc = 'file:///file.enc';
392
+
393
+ return complianceUser.webex.internal.encryption
394
+ .encryptScr(key, scr, {onBehalfOf: user.id})
395
+ .then((cipherScr) =>
396
+ complianceUser.webex.internal.encryption.decryptScr(key, cipherScr, {
397
+ onBehalfOf: user.id,
398
+ })
399
+ )
400
+ .then((decryptedScr) => assert.deepEqual(decryptedScr, scr));
401
+ }));
402
+
403
+ it('getKey', () =>
404
+ complianceUser.webex.internal.encryption
405
+ .getKey(key.uri, {onBehalfOf: user.id})
406
+ .then((key2) => {
407
+ assert.property(key2, 'uri');
408
+ assert.property(key2, 'jwk');
409
+ assert.notEqual(key2, key);
410
+ assert.equal(key2.uri, key.uri);
411
+ }));
412
+
413
+ it('getKey forbidden as compliance officer does not have access', () =>
414
+ complianceUser.webex.internal.encryption.getKey(key.uri).then(
415
+ (value) => expect.fail(`Compliance officer has retrieved key without onBehalfOf: ${value}`),
416
+ (error) => expect(error.body.status).to.equal(403)
417
+ ));
418
+
419
+ it('getKey forbidden as user does not have access', () =>
420
+ complianceUser.webex.internal.encryption
421
+ .getKey(key.uri, {onBehalfOf: '7851fe79-7c87-40cc-ac36-8b77b011b399'})
422
+ .then(
423
+ (value) =>
424
+ expect.fail(
425
+ `Should not be found as 7851fe79-7c87-40cc-ac36-8b77b011b399 does not have access ${value}`
426
+ ),
427
+ (error) => expect(error.body.status).to.equal(403)
428
+ ));
429
+
430
+ it('getKey onBehalfOf and then by compliance officer only', () =>
431
+ complianceUser.webex.internal.encryption
432
+ .getKey(key.uri, {onBehalfOf: user.id})
433
+ .then((key2) => {
434
+ assert.property(key2, 'uri');
435
+ assert.property(key2, 'jwk');
436
+ assert.notEqual(key2, key);
437
+ assert.equal(key2.uri, key.uri);
438
+ })
439
+ .then(() => complianceUser.webex.internal.encryption.getKey(key.uri))
440
+ .then(
441
+ (value) =>
442
+ expect.fail(
443
+ `Compliance should no longer be able to retrieve key as onBehalfOf was not set: ${value}`
444
+ ),
445
+ (error) => expect(error.body.status).to.equal(403)
446
+ ));
447
+ });
448
+ });