@webex/internal-plugin-conversation 2.59.1 → 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 (48) hide show
  1. package/.eslintrc.js +6 -6
  2. package/README.md +47 -47
  3. package/babel.config.js +3 -3
  4. package/dist/activities.js +4 -4
  5. package/dist/activities.js.map +1 -1
  6. package/dist/activity-thread-ordering.js +34 -34
  7. package/dist/activity-thread-ordering.js.map +1 -1
  8. package/dist/config.js +12 -12
  9. package/dist/config.js.map +1 -1
  10. package/dist/constants.js.map +1 -1
  11. package/dist/conversation.js +474 -474
  12. package/dist/conversation.js.map +1 -1
  13. package/dist/convo-error.js +4 -4
  14. package/dist/convo-error.js.map +1 -1
  15. package/dist/decryption-transforms.js +155 -155
  16. package/dist/decryption-transforms.js.map +1 -1
  17. package/dist/encryption-transforms.js.map +1 -1
  18. package/dist/index.js +2 -2
  19. package/dist/index.js.map +1 -1
  20. package/dist/share-activity.js +57 -57
  21. package/dist/share-activity.js.map +1 -1
  22. package/dist/to-array.js +7 -7
  23. package/dist/to-array.js.map +1 -1
  24. package/jest.config.js +3 -3
  25. package/package.json +21 -20
  26. package/process +1 -1
  27. package/src/activities.js +157 -157
  28. package/src/activity-thread-ordering.js +283 -283
  29. package/src/activity-threading.md +282 -282
  30. package/src/config.js +37 -37
  31. package/src/constants.js +3 -3
  32. package/src/conversation.js +2535 -2535
  33. package/src/convo-error.js +15 -15
  34. package/src/decryption-transforms.js +541 -541
  35. package/src/encryption-transforms.js +345 -345
  36. package/src/index.js +327 -327
  37. package/src/share-activity.js +436 -436
  38. package/src/to-array.js +29 -29
  39. package/test/integration/spec/create.js +290 -290
  40. package/test/integration/spec/encryption.js +333 -333
  41. package/test/integration/spec/get.js +1255 -1255
  42. package/test/integration/spec/mercury.js +94 -94
  43. package/test/integration/spec/share.js +537 -537
  44. package/test/integration/spec/verbs.js +1041 -1041
  45. package/test/unit/spec/conversation.js +823 -823
  46. package/test/unit/spec/decrypt-transforms.js +460 -460
  47. package/test/unit/spec/encryption-transforms.js +93 -93
  48. package/test/unit/spec/share-activity.js +178 -178
@@ -1,345 +1,345 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import {capitalize, curry, get, has, isArray} from 'lodash';
6
-
7
- import toArray from './to-array';
8
-
9
- const KEY = Symbol('KEY');
10
-
11
- const encryptTextProp = curry((name, ctx, key, object) =>
12
- ctx.transform('encryptTextProp', name, key, object)
13
- );
14
-
15
- const encryptJsonProp = curry((name, ctx, key, object) =>
16
- ctx.transform('encryptJsonProp', name, key, object)
17
- );
18
-
19
- // eslint-disable-next-line import/prefer-default-export
20
- export const transforms = toArray('outbound', {
21
- encryptObject(ctx, key, object) {
22
- if (!object) {
23
- object = key;
24
- key = undefined;
25
- }
26
-
27
- if (!object) {
28
- return Promise.resolve();
29
- }
30
-
31
- if (!object.objectType) {
32
- return Promise.resolve();
33
- }
34
-
35
- if (key === false) {
36
- return Promise.resolve();
37
- }
38
-
39
- return ctx.transform(`encrypt${capitalize(object.objectType)}`, key, object);
40
- },
41
-
42
- encryptReaction2(ctx, key, reaction2) {
43
- return ctx.transform('encryptPropDisplayName', key, reaction2);
44
- },
45
-
46
- encryptConversation(ctx, key, conversation) {
47
- if (key === false) {
48
- return Promise.resolve();
49
- }
50
-
51
- return Promise.resolve(
52
- key || ctx.webex.internal.encryption.kms.createUnboundKeys({count: 1})
53
- ).then((keys) => {
54
- const k = isArray(keys) ? keys[0] : keys;
55
-
56
- if (
57
- has(conversation, 'kmsMessage.keyUris') &&
58
- !conversation.kmsMessage.keyUris.includes(k.uri)
59
- ) {
60
- conversation.kmsMessage.keyUris.push(k.uri);
61
- }
62
-
63
- return Promise.all([
64
- // too many implicit returns on the same line is difficult to interpret
65
- // eslint-disable-next-line arrow-body-style
66
- has(conversation, 'activities.items') &&
67
- conversation.activities.items.reduce((p, activity) => {
68
- // eslint-disable-next-line max-nested-callbacks
69
- return p.then(() => ctx.transform('encryptObject', k, activity));
70
- }, Promise.resolve()),
71
- ctx.transform('encryptPropDisplayName', k, conversation),
72
- ]).then(() => {
73
- conversation.encryptionKeyUrl = k.uri || k;
74
- // we only want to set the defaultActivityEncryptionKeyUrl if we've
75
- // bound a new key
76
- if (!key) {
77
- conversation.defaultActivityEncryptionKeyUrl =
78
- conversation.defaultActivityEncryptionKeyUrl || k.uri || k;
79
- }
80
- });
81
- });
82
- },
83
-
84
- encryptActivity(ctx, key, activity) {
85
- // Activity is already encrypted
86
- if (activity.encryptionKeyUrl || activity.object?.created === 'True') {
87
- return Promise.resolve();
88
- }
89
-
90
- return ctx.transform(`encrypt${capitalize(activity.verb)}Activity`, key, activity).then(() => {
91
- key = key || activity[KEY];
92
-
93
- return ctx.transform('prepareActivityKmsMessage', key, activity);
94
- });
95
- },
96
-
97
- encryptVerbActivity(ctx, key, activity) {
98
- return ctx
99
- .transform('maybeEncryptTarget', key, activity)
100
- .then(() => {
101
- key = key || activity[KEY];
102
- })
103
- .then(() => ctx.transform('encryptObject', key, activity.object));
104
- },
105
-
106
- maybeEncryptTarget(ctx, key, activity) {
107
- // This isn't quite right; if we just go by key, we have no guarantee that
108
- // we have a proper KRO available for add activities
109
- if (key) {
110
- return Promise.resolve();
111
- }
112
-
113
- if (
114
- has(activity, 'target.defaultActivityEncryptionKeyUrl') &&
115
- activity.target.defaultActivityEncryptionKeyUrl &&
116
- has(activity, 'target.kmsResourceObjectUrl')
117
- ) {
118
- activity[KEY] = key || activity.target.defaultActivityEncryptionKeyUrl;
119
-
120
- return Promise.resolve();
121
- }
122
-
123
- const conversationUrl = activity.target && activity.target.url;
124
-
125
- if (!conversationUrl) {
126
- return Promise.reject(
127
- new Error(
128
- "Cannot determine encryption key for activity's conversation; no key url or conversation url provided"
129
- )
130
- );
131
- }
132
-
133
- return ctx.webex.internal.conversation.get({url: conversationUrl}).then((conversation) => {
134
- if (!conversation.defaultActivityEncryptionKeyUrl) {
135
- return ctx.webex.internal.conversation.updateKey(conversation).then((updateKeyActivity) => {
136
- if (updateKeyActivity.kmsMessage.resource) {
137
- activity.target.kmsResourceObjectUrl = updateKeyActivity.kmsMessage.resource.uri;
138
- }
139
- activity[KEY] = activity.target.defaultActivityEncryptionKeyUrl =
140
- updateKeyActivity.object.defaultActivityEncryptionKeyUrl;
141
- });
142
- }
143
-
144
- if (!activity.target.defaultActivityEncryptionKeyUrl) {
145
- ctx.webex.logger.warn(
146
- 'plugin-conversation: downloaded conversation to determine its defaultActivityEncryptionKeyUrl; make sure to pass all encryption related properties when calling Webex.conversation methods.'
147
- );
148
- }
149
-
150
- if (!activity.target.kmsResourceObjectUrl) {
151
- ctx.webex.logger.warn(
152
- 'plugin-conversation: downloaded conversation to determine its kmsResourceObjectUrl; make sure to pass all encryption related properties when calling Webex.conversation methods.'
153
- );
154
- }
155
-
156
- activity[KEY] = activity.target.defaultActivityEncryptionKeyUrl =
157
- conversation.defaultActivityEncryptionKeyUrl;
158
- activity.target.kmsResourceObjectUrl = conversation.kmsResourceObjectUrl;
159
-
160
- return Promise.resolve();
161
- });
162
- },
163
-
164
- prepareActivityKmsMessage(ctx, key, activity) {
165
- if (activity.kmsMessage) {
166
- if (!key && activity.verb === 'delete') {
167
- key = get(activity, 'target.defaultActivityEncryptionKeyUrl');
168
- }
169
-
170
- if (
171
- !key &&
172
- activity.verb === 'updateKey' &&
173
- has(activity, 'object.defaultActivityEncryptionKeyUrl')
174
- ) {
175
- key = get(activity, 'object.defaultActivityEncryptionKeyUrl');
176
- }
177
-
178
- if (
179
- !key &&
180
- activity.verb === 'leave' &&
181
- has(activity, 'target.defaultActivityEncryptionKeyUrl')
182
- ) {
183
- key = get(activity, 'target.defaultActivityEncryptionKeyUrl');
184
- }
185
-
186
- if (key) {
187
- const kro = activity.target.kmsResourceObjectUrl;
188
-
189
- ['uri', 'resourceUri'].forEach((k) => {
190
- if (activity.kmsMessage[k] && !kro && activity.kmsMessage[k].includes('<KRO>')) {
191
- throw new Error('encrypter: cannot determine kro');
192
- }
193
-
194
- if (activity.kmsMessage[k]) {
195
- activity.kmsMessage[k] = activity.kmsMessage[k].replace('<KRO>', kro);
196
- // key may be a key or a key url
197
- activity.kmsMessage[k] = activity.kmsMessage[k].replace('<KEYURL>', key.keyUrl || key);
198
- }
199
- });
200
- }
201
- // If we made it this far and still don't have an encryption key, assume
202
- // this is a conversation that is not encrypted and we're performing an
203
- // action that should not encrypt it (e.g. `leave`)
204
- else {
205
- Reflect.deleteProperty(activity, 'kmsMessage');
206
- }
207
- }
208
- },
209
-
210
- encryptVerbActivityWithKey: {
211
- direction: 'outbound',
212
- fn(ctx, key, activity) {
213
- return ctx.transform('encryptVerbActivity', key, activity).then(() => {
214
- key = key || activity[KEY];
215
- activity.encryptionKeyUrl = key.uri || key;
216
- });
217
- },
218
- },
219
-
220
- encryptAddActivity: {
221
- direction: 'outbound',
222
- fn(ctx, key, activity) {
223
- if (has(activity, 'object.objectType') && activity.object.objectType === 'reaction2') {
224
- return ctx.transform('encryptVerbActivityWithKey', key, activity);
225
- }
226
-
227
- return ctx.transform('encryptVerbActivity', key, activity);
228
- },
229
- },
230
-
231
- encryptAssignActivity: {
232
- direction: 'outbound',
233
- alias: 'encryptVerbActivityWithKey',
234
- },
235
-
236
- encryptCreateActivity: {
237
- direction: 'outbound',
238
- alias: 'encryptVerbActivity',
239
- },
240
-
241
- encryptPostActivity: {
242
- direction: 'outbound',
243
- alias: 'encryptVerbActivityWithKey',
244
- },
245
-
246
- encryptShareActivity: {
247
- direction: 'outbound',
248
- alias: 'encryptVerbActivityWithKey',
249
- },
250
-
251
- encryptCardactionActivity: {
252
- direction: 'outbound',
253
- alias: 'encryptVerbActivityWithKey',
254
- },
255
-
256
- encryptUpdateActivity: {
257
- direction: 'outbound',
258
- alias: 'encryptVerbActivityWithKey',
259
- },
260
-
261
- encryptUpdateKeyActivity: {
262
- direction: 'outbound',
263
- alias: 'encryptVerbActivity',
264
- },
265
-
266
- encryptComment(ctx, key, comment) {
267
- return Promise.all([
268
- ctx.transform('encryptPropDisplayName', key, comment),
269
- ctx.transform('encryptPropContent', key, comment),
270
- ]);
271
- },
272
-
273
- encryptContent(ctx, key, content) {
274
- const promises = content.files.items.map((item) => ctx.transform('encryptObject', key, item));
275
-
276
- promises.push(ctx.transform('encryptPropContent', key, content));
277
- promises.push(ctx.transform('encryptPropDisplayName', key, content));
278
-
279
- return Promise.all(promises);
280
- },
281
-
282
- encryptFile(ctx, key, file) {
283
- if (file.image && !file.image.scr) {
284
- return Promise.reject(new Error('`file.image` must have an `scr`'));
285
- }
286
-
287
- return Promise.all([
288
- ctx.transform('encryptPropScr', key, file),
289
- ctx.transform('encryptPropDisplayName', key, file),
290
- ctx.transform('encryptPropContent', key, file),
291
- file.image && ctx.transform('encryptPropScr', key, file.image),
292
- ]);
293
- },
294
-
295
- encryptSubmit(ctx, key, submit) {
296
- return ctx.transform('encryptPropInputs', key, submit);
297
- },
298
-
299
- // TODO is this used for anything other than the now-removed stickies service?
300
- encryptImageURI(ctx, key, imageURI) {
301
- return ctx.transform('encryptPropLocation', key, imageURI);
302
- },
303
-
304
- encryptPropContent: encryptTextProp('content'),
305
-
306
- encryptPropDisplayName: encryptTextProp('displayName'),
307
-
308
- encryptPropInputs: encryptJsonProp('inputs'),
309
-
310
- encryptPropLocation: encryptTextProp('location'),
311
-
312
- encryptPropScr(ctx, key, object) {
313
- if (!object.scr) {
314
- return Promise.resolve();
315
- }
316
-
317
- return ctx.webex.internal.encryption.encryptScr(key, object.scr).then((scr) => {
318
- object.scr = scr;
319
- });
320
- },
321
-
322
- encryptJsonProp(ctx, name, key, object) {
323
- if (!object[name]) {
324
- return Promise.resolve();
325
- }
326
-
327
- return ctx.webex.internal.encryption
328
- .encryptText(key.uri || key, JSON.stringify(object[name]))
329
- .then((ciphertext) => {
330
- object[name] = ciphertext;
331
- });
332
- },
333
-
334
- encryptTextProp(ctx, name, key, object) {
335
- if (!object[name]) {
336
- return Promise.resolve();
337
- }
338
-
339
- return ctx.webex.internal.encryption
340
- .encryptText(key.uri || key, object[name])
341
- .then((ciphertext) => {
342
- object[name] = ciphertext;
343
- });
344
- },
345
- });
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {capitalize, curry, get, has, isArray} from 'lodash';
6
+
7
+ import toArray from './to-array';
8
+
9
+ const KEY = Symbol('KEY');
10
+
11
+ const encryptTextProp = curry((name, ctx, key, object) =>
12
+ ctx.transform('encryptTextProp', name, key, object)
13
+ );
14
+
15
+ const encryptJsonProp = curry((name, ctx, key, object) =>
16
+ ctx.transform('encryptJsonProp', name, key, object)
17
+ );
18
+
19
+ // eslint-disable-next-line import/prefer-default-export
20
+ export const transforms = toArray('outbound', {
21
+ encryptObject(ctx, key, object) {
22
+ if (!object) {
23
+ object = key;
24
+ key = undefined;
25
+ }
26
+
27
+ if (!object) {
28
+ return Promise.resolve();
29
+ }
30
+
31
+ if (!object.objectType) {
32
+ return Promise.resolve();
33
+ }
34
+
35
+ if (key === false) {
36
+ return Promise.resolve();
37
+ }
38
+
39
+ return ctx.transform(`encrypt${capitalize(object.objectType)}`, key, object);
40
+ },
41
+
42
+ encryptReaction2(ctx, key, reaction2) {
43
+ return ctx.transform('encryptPropDisplayName', key, reaction2);
44
+ },
45
+
46
+ encryptConversation(ctx, key, conversation) {
47
+ if (key === false) {
48
+ return Promise.resolve();
49
+ }
50
+
51
+ return Promise.resolve(
52
+ key || ctx.webex.internal.encryption.kms.createUnboundKeys({count: 1})
53
+ ).then((keys) => {
54
+ const k = isArray(keys) ? keys[0] : keys;
55
+
56
+ if (
57
+ has(conversation, 'kmsMessage.keyUris') &&
58
+ !conversation.kmsMessage.keyUris.includes(k.uri)
59
+ ) {
60
+ conversation.kmsMessage.keyUris.push(k.uri);
61
+ }
62
+
63
+ return Promise.all([
64
+ // too many implicit returns on the same line is difficult to interpret
65
+ // eslint-disable-next-line arrow-body-style
66
+ has(conversation, 'activities.items') &&
67
+ conversation.activities.items.reduce((p, activity) => {
68
+ // eslint-disable-next-line max-nested-callbacks
69
+ return p.then(() => ctx.transform('encryptObject', k, activity));
70
+ }, Promise.resolve()),
71
+ ctx.transform('encryptPropDisplayName', k, conversation),
72
+ ]).then(() => {
73
+ conversation.encryptionKeyUrl = k.uri || k;
74
+ // we only want to set the defaultActivityEncryptionKeyUrl if we've
75
+ // bound a new key
76
+ if (!key) {
77
+ conversation.defaultActivityEncryptionKeyUrl =
78
+ conversation.defaultActivityEncryptionKeyUrl || k.uri || k;
79
+ }
80
+ });
81
+ });
82
+ },
83
+
84
+ encryptActivity(ctx, key, activity) {
85
+ // Activity is already encrypted
86
+ if (activity.encryptionKeyUrl || activity.object?.created === 'True') {
87
+ return Promise.resolve();
88
+ }
89
+
90
+ return ctx.transform(`encrypt${capitalize(activity.verb)}Activity`, key, activity).then(() => {
91
+ key = key || activity[KEY];
92
+
93
+ return ctx.transform('prepareActivityKmsMessage', key, activity);
94
+ });
95
+ },
96
+
97
+ encryptVerbActivity(ctx, key, activity) {
98
+ return ctx
99
+ .transform('maybeEncryptTarget', key, activity)
100
+ .then(() => {
101
+ key = key || activity[KEY];
102
+ })
103
+ .then(() => ctx.transform('encryptObject', key, activity.object));
104
+ },
105
+
106
+ maybeEncryptTarget(ctx, key, activity) {
107
+ // This isn't quite right; if we just go by key, we have no guarantee that
108
+ // we have a proper KRO available for add activities
109
+ if (key) {
110
+ return Promise.resolve();
111
+ }
112
+
113
+ if (
114
+ has(activity, 'target.defaultActivityEncryptionKeyUrl') &&
115
+ activity.target.defaultActivityEncryptionKeyUrl &&
116
+ has(activity, 'target.kmsResourceObjectUrl')
117
+ ) {
118
+ activity[KEY] = key || activity.target.defaultActivityEncryptionKeyUrl;
119
+
120
+ return Promise.resolve();
121
+ }
122
+
123
+ const conversationUrl = activity.target && activity.target.url;
124
+
125
+ if (!conversationUrl) {
126
+ return Promise.reject(
127
+ new Error(
128
+ "Cannot determine encryption key for activity's conversation; no key url or conversation url provided"
129
+ )
130
+ );
131
+ }
132
+
133
+ return ctx.webex.internal.conversation.get({url: conversationUrl}).then((conversation) => {
134
+ if (!conversation.defaultActivityEncryptionKeyUrl) {
135
+ return ctx.webex.internal.conversation.updateKey(conversation).then((updateKeyActivity) => {
136
+ if (updateKeyActivity.kmsMessage.resource) {
137
+ activity.target.kmsResourceObjectUrl = updateKeyActivity.kmsMessage.resource.uri;
138
+ }
139
+ activity[KEY] = activity.target.defaultActivityEncryptionKeyUrl =
140
+ updateKeyActivity.object.defaultActivityEncryptionKeyUrl;
141
+ });
142
+ }
143
+
144
+ if (!activity.target.defaultActivityEncryptionKeyUrl) {
145
+ ctx.webex.logger.warn(
146
+ 'plugin-conversation: downloaded conversation to determine its defaultActivityEncryptionKeyUrl; make sure to pass all encryption related properties when calling Webex.conversation methods.'
147
+ );
148
+ }
149
+
150
+ if (!activity.target.kmsResourceObjectUrl) {
151
+ ctx.webex.logger.warn(
152
+ 'plugin-conversation: downloaded conversation to determine its kmsResourceObjectUrl; make sure to pass all encryption related properties when calling Webex.conversation methods.'
153
+ );
154
+ }
155
+
156
+ activity[KEY] = activity.target.defaultActivityEncryptionKeyUrl =
157
+ conversation.defaultActivityEncryptionKeyUrl;
158
+ activity.target.kmsResourceObjectUrl = conversation.kmsResourceObjectUrl;
159
+
160
+ return Promise.resolve();
161
+ });
162
+ },
163
+
164
+ prepareActivityKmsMessage(ctx, key, activity) {
165
+ if (activity.kmsMessage) {
166
+ if (!key && activity.verb === 'delete') {
167
+ key = get(activity, 'target.defaultActivityEncryptionKeyUrl');
168
+ }
169
+
170
+ if (
171
+ !key &&
172
+ activity.verb === 'updateKey' &&
173
+ has(activity, 'object.defaultActivityEncryptionKeyUrl')
174
+ ) {
175
+ key = get(activity, 'object.defaultActivityEncryptionKeyUrl');
176
+ }
177
+
178
+ if (
179
+ !key &&
180
+ activity.verb === 'leave' &&
181
+ has(activity, 'target.defaultActivityEncryptionKeyUrl')
182
+ ) {
183
+ key = get(activity, 'target.defaultActivityEncryptionKeyUrl');
184
+ }
185
+
186
+ if (key) {
187
+ const kro = activity.target.kmsResourceObjectUrl;
188
+
189
+ ['uri', 'resourceUri'].forEach((k) => {
190
+ if (activity.kmsMessage[k] && !kro && activity.kmsMessage[k].includes('<KRO>')) {
191
+ throw new Error('encrypter: cannot determine kro');
192
+ }
193
+
194
+ if (activity.kmsMessage[k]) {
195
+ activity.kmsMessage[k] = activity.kmsMessage[k].replace('<KRO>', kro);
196
+ // key may be a key or a key url
197
+ activity.kmsMessage[k] = activity.kmsMessage[k].replace('<KEYURL>', key.keyUrl || key);
198
+ }
199
+ });
200
+ }
201
+ // If we made it this far and still don't have an encryption key, assume
202
+ // this is a conversation that is not encrypted and we're performing an
203
+ // action that should not encrypt it (e.g. `leave`)
204
+ else {
205
+ Reflect.deleteProperty(activity, 'kmsMessage');
206
+ }
207
+ }
208
+ },
209
+
210
+ encryptVerbActivityWithKey: {
211
+ direction: 'outbound',
212
+ fn(ctx, key, activity) {
213
+ return ctx.transform('encryptVerbActivity', key, activity).then(() => {
214
+ key = key || activity[KEY];
215
+ activity.encryptionKeyUrl = key.uri || key;
216
+ });
217
+ },
218
+ },
219
+
220
+ encryptAddActivity: {
221
+ direction: 'outbound',
222
+ fn(ctx, key, activity) {
223
+ if (has(activity, 'object.objectType') && activity.object.objectType === 'reaction2') {
224
+ return ctx.transform('encryptVerbActivityWithKey', key, activity);
225
+ }
226
+
227
+ return ctx.transform('encryptVerbActivity', key, activity);
228
+ },
229
+ },
230
+
231
+ encryptAssignActivity: {
232
+ direction: 'outbound',
233
+ alias: 'encryptVerbActivityWithKey',
234
+ },
235
+
236
+ encryptCreateActivity: {
237
+ direction: 'outbound',
238
+ alias: 'encryptVerbActivity',
239
+ },
240
+
241
+ encryptPostActivity: {
242
+ direction: 'outbound',
243
+ alias: 'encryptVerbActivityWithKey',
244
+ },
245
+
246
+ encryptShareActivity: {
247
+ direction: 'outbound',
248
+ alias: 'encryptVerbActivityWithKey',
249
+ },
250
+
251
+ encryptCardactionActivity: {
252
+ direction: 'outbound',
253
+ alias: 'encryptVerbActivityWithKey',
254
+ },
255
+
256
+ encryptUpdateActivity: {
257
+ direction: 'outbound',
258
+ alias: 'encryptVerbActivityWithKey',
259
+ },
260
+
261
+ encryptUpdateKeyActivity: {
262
+ direction: 'outbound',
263
+ alias: 'encryptVerbActivity',
264
+ },
265
+
266
+ encryptComment(ctx, key, comment) {
267
+ return Promise.all([
268
+ ctx.transform('encryptPropDisplayName', key, comment),
269
+ ctx.transform('encryptPropContent', key, comment),
270
+ ]);
271
+ },
272
+
273
+ encryptContent(ctx, key, content) {
274
+ const promises = content.files.items.map((item) => ctx.transform('encryptObject', key, item));
275
+
276
+ promises.push(ctx.transform('encryptPropContent', key, content));
277
+ promises.push(ctx.transform('encryptPropDisplayName', key, content));
278
+
279
+ return Promise.all(promises);
280
+ },
281
+
282
+ encryptFile(ctx, key, file) {
283
+ if (file.image && !file.image.scr) {
284
+ return Promise.reject(new Error('`file.image` must have an `scr`'));
285
+ }
286
+
287
+ return Promise.all([
288
+ ctx.transform('encryptPropScr', key, file),
289
+ ctx.transform('encryptPropDisplayName', key, file),
290
+ ctx.transform('encryptPropContent', key, file),
291
+ file.image && ctx.transform('encryptPropScr', key, file.image),
292
+ ]);
293
+ },
294
+
295
+ encryptSubmit(ctx, key, submit) {
296
+ return ctx.transform('encryptPropInputs', key, submit);
297
+ },
298
+
299
+ // TODO is this used for anything other than the now-removed stickies service?
300
+ encryptImageURI(ctx, key, imageURI) {
301
+ return ctx.transform('encryptPropLocation', key, imageURI);
302
+ },
303
+
304
+ encryptPropContent: encryptTextProp('content'),
305
+
306
+ encryptPropDisplayName: encryptTextProp('displayName'),
307
+
308
+ encryptPropInputs: encryptJsonProp('inputs'),
309
+
310
+ encryptPropLocation: encryptTextProp('location'),
311
+
312
+ encryptPropScr(ctx, key, object) {
313
+ if (!object.scr) {
314
+ return Promise.resolve();
315
+ }
316
+
317
+ return ctx.webex.internal.encryption.encryptScr(key, object.scr).then((scr) => {
318
+ object.scr = scr;
319
+ });
320
+ },
321
+
322
+ encryptJsonProp(ctx, name, key, object) {
323
+ if (!object[name]) {
324
+ return Promise.resolve();
325
+ }
326
+
327
+ return ctx.webex.internal.encryption
328
+ .encryptText(key.uri || key, JSON.stringify(object[name]))
329
+ .then((ciphertext) => {
330
+ object[name] = ciphertext;
331
+ });
332
+ },
333
+
334
+ encryptTextProp(ctx, name, key, object) {
335
+ if (!object[name]) {
336
+ return Promise.resolve();
337
+ }
338
+
339
+ return ctx.webex.internal.encryption
340
+ .encryptText(key.uri || key, object[name])
341
+ .then((ciphertext) => {
342
+ object[name] = ciphertext;
343
+ });
344
+ },
345
+ });