@webex/internal-plugin-task 0.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/README.md +77 -0
- package/babel.config.js +3 -0
- package/dist/config.js +14 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.js +10 -0
- package/dist/constants.js.map +1 -0
- package/dist/helpers/decrypt.helper.js +58 -0
- package/dist/helpers/decrypt.helper.js.map +1 -0
- package/dist/helpers/encrypt.helper.js +52 -0
- package/dist/helpers/encrypt.helper.js.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/task.js +225 -0
- package/dist/task.js.map +1 -0
- package/jest.config.js +3 -0
- package/package.json +56 -0
- package/process +1 -0
- package/src/config.js +7 -0
- package/src/constants.js +2 -0
- package/src/helpers/decrypt.helper.js +58 -0
- package/src/helpers/encrypt.helper.js +50 -0
- package/src/index.js +22 -0
- package/src/task.js +224 -0
- package/test/integration/spec/task.js +87 -0
- package/test/unit/spec/helpers/decrypt.helper.js +93 -0
- package/test/unit/spec/helpers/encrypt.helper.js +43 -0
- package/test/unit/spec/task.js +194 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decrypt text property - Note: this is backup solution for decryption, the better solution is to use interceptors and needs migration later
|
|
3
|
+
* @param {object} [ctx] context
|
|
4
|
+
* @param {string} [name] property name
|
|
5
|
+
* @param {string|object} [key] encryption key or key uri
|
|
6
|
+
* @param {object} [object] object which contains the property
|
|
7
|
+
* @returns {Promise} Resolves when decryption is complete
|
|
8
|
+
*/
|
|
9
|
+
const _decryptTextProp = (ctx, name, key, object) => {
|
|
10
|
+
if (!object[name]) {
|
|
11
|
+
return Promise.resolve();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return ctx.webex.internal.encryption
|
|
15
|
+
.decryptText(key.uri || key, object[name])
|
|
16
|
+
.then((plaintext) => {
|
|
17
|
+
object[name] = plaintext;
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const _decryptTaskFields = (ctx, item) => {
|
|
22
|
+
if (!item || !item.encryptionKeyUrl) {
|
|
23
|
+
return Promise.resolve();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return Promise.all([
|
|
27
|
+
_decryptTextProp(ctx, 'title', item.encryptionKeyUrl, item),
|
|
28
|
+
_decryptTextProp(ctx, 'notes', item.encryptionKeyUrl, item),
|
|
29
|
+
]);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const DecryptHelper = {
|
|
33
|
+
/**
|
|
34
|
+
* Decrypt task response
|
|
35
|
+
* @param {object} [ctx] context
|
|
36
|
+
* @param {object} [data] task response
|
|
37
|
+
* @returns {Promise} Resolves with decrypted response
|
|
38
|
+
* */
|
|
39
|
+
decryptTaskResponse: (ctx, data) => {
|
|
40
|
+
return _decryptTaskFields(ctx, data);
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Decrypt tasks response
|
|
45
|
+
* @param {object} [ctx] context
|
|
46
|
+
* @param {object} [data] tasks response
|
|
47
|
+
* @returns {Promise} Resolves with decrypted response
|
|
48
|
+
* */
|
|
49
|
+
decryptTasksResponse: (ctx, data) => {
|
|
50
|
+
if (!data || !data.items || data.items.length === 0) {
|
|
51
|
+
return Promise.resolve();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return Promise.all(data.items.map((task) => _decryptTaskFields(ctx, task)));
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default DecryptHelper;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {isArray} from 'lodash';
|
|
2
|
+
/**
|
|
3
|
+
* Encrypt text property of an object - Note: this is backup solution for encryption, the better solution is to use interceptors and needs migration later
|
|
4
|
+
* @param {object} [ctx] context
|
|
5
|
+
* @param {string} [name] property name
|
|
6
|
+
* @param {string|object} [key] encryption key or key uri
|
|
7
|
+
* @param {object} [object] object which contains the property
|
|
8
|
+
* @returns {Promise} Resolves when encryption is complete
|
|
9
|
+
*/
|
|
10
|
+
const _encryptTextProp = (ctx, name, key, object) => {
|
|
11
|
+
if (!object[name]) {
|
|
12
|
+
return Promise.resolve();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return ctx.webex.internal.encryption
|
|
16
|
+
.encryptText(key.uri || key, object[name])
|
|
17
|
+
.then((ciphertext) => {
|
|
18
|
+
object[name] = ciphertext;
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const EncryptHelper = {
|
|
23
|
+
/**
|
|
24
|
+
* Encrypt create / update task event request payload
|
|
25
|
+
* @param {object} [ctx] context
|
|
26
|
+
* @param {object} [data] task payload data
|
|
27
|
+
* @returns {Promise} Resolves with encrypted request payload
|
|
28
|
+
* */
|
|
29
|
+
encryptTaskRequest: (ctx, data) => {
|
|
30
|
+
if (data.encryptionKeyUrl) {
|
|
31
|
+
return Promise.all([
|
|
32
|
+
_encryptTextProp(ctx, 'title', data.encryptionKeyUrl, data),
|
|
33
|
+
_encryptTextProp(ctx, 'notes', data.encryptionKeyUrl, data),
|
|
34
|
+
]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return ctx.webex.internal.encryption.kms.createUnboundKeys({count: 1}).then((keys) => {
|
|
38
|
+
const key = isArray(keys) ? keys[0] : keys;
|
|
39
|
+
const encryptionKeyUrl = key.uri;
|
|
40
|
+
Object.assign(data, {encryptionKeyUrl});
|
|
41
|
+
|
|
42
|
+
return Promise.all([
|
|
43
|
+
_encryptTextProp(ctx, 'title', encryptionKeyUrl, data),
|
|
44
|
+
_encryptTextProp(ctx, 'notes', encryptionKeyUrl, data),
|
|
45
|
+
]);
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default EncryptHelper;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import '@webex/internal-plugin-device';
|
|
6
|
+
import '@webex/internal-plugin-encryption';
|
|
7
|
+
import '@webex/internal-plugin-conversation';
|
|
8
|
+
|
|
9
|
+
import {registerInternalPlugin} from '@webex/webex-core';
|
|
10
|
+
|
|
11
|
+
import Task from './task';
|
|
12
|
+
import config from './config';
|
|
13
|
+
|
|
14
|
+
registerInternalPlugin('task', Task, {
|
|
15
|
+
config,
|
|
16
|
+
payloadTransformer: {
|
|
17
|
+
predicates: [],
|
|
18
|
+
transforms: [],
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export {default} from './task';
|
package/src/task.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
import {WebexPlugin} from '@webex/webex-core';
|
|
5
|
+
|
|
6
|
+
import {TASK_REGISTERED, TASK_UNREGISTERED} from './constants';
|
|
7
|
+
|
|
8
|
+
import EncryptHelper from './helpers/encrypt.helper';
|
|
9
|
+
import DecryptHelper from './helpers/decrypt.helper';
|
|
10
|
+
|
|
11
|
+
const Task = WebexPlugin.extend({
|
|
12
|
+
namespace: 'Task',
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* registered value indicating events registration is successful
|
|
16
|
+
* @instance
|
|
17
|
+
* @type {Boolean}
|
|
18
|
+
* @memberof Task
|
|
19
|
+
*/
|
|
20
|
+
registered: false,
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* WebexPlugin initialize method. This triggers once Webex has completed its
|
|
24
|
+
* initialization workflow.
|
|
25
|
+
*
|
|
26
|
+
* If the plugin is meant to perform startup actions, place them in this
|
|
27
|
+
* `initialize()` method instead of the `constructor()` method.
|
|
28
|
+
* @returns {void}
|
|
29
|
+
*/
|
|
30
|
+
initialize() {
|
|
31
|
+
// Used to perform actions after webex is fully qualified and ready for
|
|
32
|
+
// operation.
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Explicitly sets up the Task plugin by registering
|
|
37
|
+
* the device, connecting to mercury, and listening for events.
|
|
38
|
+
* @returns {Promise}
|
|
39
|
+
* @public
|
|
40
|
+
* @memberof Task
|
|
41
|
+
*/
|
|
42
|
+
register() {
|
|
43
|
+
if (!this.webex.canAuthorize) {
|
|
44
|
+
this.logger.error('Task->register#ERROR, Unable to register, SDK cannot authorize');
|
|
45
|
+
|
|
46
|
+
return Promise.reject(new Error('SDK cannot authorize'));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (this.registered) {
|
|
50
|
+
this.logger.info('Task->register#INFO, task plugin already registered');
|
|
51
|
+
|
|
52
|
+
return Promise.resolve();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return this.webex.internal.device
|
|
56
|
+
.register()
|
|
57
|
+
.then(() => this.webex.internal.mercury.connect())
|
|
58
|
+
.then(() => {
|
|
59
|
+
this.listenForEvents();
|
|
60
|
+
this.trigger(TASK_REGISTERED);
|
|
61
|
+
this.registered = true;
|
|
62
|
+
})
|
|
63
|
+
.catch((error) => {
|
|
64
|
+
this.logger.error(`Task->register#ERROR, Unable to register, ${error.message}`);
|
|
65
|
+
|
|
66
|
+
return Promise.reject(error);
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Explicitly tears down the task plugin by stops listening to task events
|
|
72
|
+
*
|
|
73
|
+
* @returns {Promise}
|
|
74
|
+
* @public
|
|
75
|
+
* @memberof Task
|
|
76
|
+
*/
|
|
77
|
+
unregister() {
|
|
78
|
+
if (!this.registered) {
|
|
79
|
+
this.logger.info('Task->unregister#INFO, task plugin already unregistered');
|
|
80
|
+
|
|
81
|
+
return Promise.resolve();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.stopListeningForEvents();
|
|
85
|
+
this.trigger(TASK_UNREGISTERED);
|
|
86
|
+
this.registered = false;
|
|
87
|
+
|
|
88
|
+
return Promise.resolve();
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* registers for task events through mercury
|
|
93
|
+
* @returns {undefined}
|
|
94
|
+
* @private
|
|
95
|
+
*/
|
|
96
|
+
listenForEvents() {},
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* unregisteres all the task events from mercury
|
|
100
|
+
* @returns {undefined}
|
|
101
|
+
* @private
|
|
102
|
+
*/
|
|
103
|
+
stopListeningForEvents() {},
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Retrieves a collection of tasks based on the request parameters
|
|
107
|
+
* @param {Object} options
|
|
108
|
+
* @param {String} options.orderBy
|
|
109
|
+
* @param {Number} options.offset
|
|
110
|
+
* @param {Number} options.limit
|
|
111
|
+
* @returns {Promise} Resolves with an array of tasks
|
|
112
|
+
*/
|
|
113
|
+
listMyTasks(options) {
|
|
114
|
+
options = options || {};
|
|
115
|
+
|
|
116
|
+
return this.webex
|
|
117
|
+
.request({
|
|
118
|
+
method: 'GET',
|
|
119
|
+
service: 'raindrop',
|
|
120
|
+
resource: 'tasks',
|
|
121
|
+
qs: options || {},
|
|
122
|
+
})
|
|
123
|
+
.then((response) => {
|
|
124
|
+
return DecryptHelper.decryptTasksResponse(this, response.body).then(() => response);
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Retrieves a task based on the request parameters
|
|
130
|
+
* @param {String} id Task ID
|
|
131
|
+
* @returns {Promise} Resolves with an array of tasks
|
|
132
|
+
*/
|
|
133
|
+
getTask(id) {
|
|
134
|
+
return this.request({
|
|
135
|
+
method: 'GET',
|
|
136
|
+
service: 'raindrop',
|
|
137
|
+
resource: `tasks/${id}`,
|
|
138
|
+
}).then((response) => {
|
|
139
|
+
return DecryptHelper.decryptTaskResponse(this, response.body).then(() => response);
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Create task
|
|
145
|
+
* @param {object} [data] task payload data
|
|
146
|
+
* @returns {Promise} Resolves with creating task response
|
|
147
|
+
* */
|
|
148
|
+
createTask(data) {
|
|
149
|
+
return EncryptHelper.encryptTaskRequest(this, data).then(() =>
|
|
150
|
+
this.request({
|
|
151
|
+
method: 'POST',
|
|
152
|
+
service: 'raindrop',
|
|
153
|
+
body: data,
|
|
154
|
+
resource: 'tasks',
|
|
155
|
+
}).then((response) => {
|
|
156
|
+
return DecryptHelper.decryptTaskResponse(this, response.body).then(() => response);
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Update task
|
|
163
|
+
* @param {string} [id] task id
|
|
164
|
+
* @param {object} [data] task payload data
|
|
165
|
+
* @returns {Promise} Resolves with updating task response
|
|
166
|
+
* */
|
|
167
|
+
updateTask(id, data) {
|
|
168
|
+
return EncryptHelper.encryptTaskRequest(this, data).then(() =>
|
|
169
|
+
this.request({
|
|
170
|
+
method: 'PATCH',
|
|
171
|
+
service: 'raindrop',
|
|
172
|
+
body: data,
|
|
173
|
+
resource: `tasks/${id}`,
|
|
174
|
+
}).then((response) => {
|
|
175
|
+
return DecryptHelper.decryptTaskResponse(this, response.body).then(() => response);
|
|
176
|
+
})
|
|
177
|
+
);
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Delete task
|
|
182
|
+
* @param {string} [id] task id
|
|
183
|
+
* @returns {Promise} Resolves with deleting task response
|
|
184
|
+
* */
|
|
185
|
+
deleteTask(id) {
|
|
186
|
+
return this.request({
|
|
187
|
+
method: 'DELETE',
|
|
188
|
+
service: 'raindrop',
|
|
189
|
+
resource: `tasks/${id}`,
|
|
190
|
+
});
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Accept task
|
|
195
|
+
* @param {string} [id] task id
|
|
196
|
+
* @returns {Promise} Resolves with accepting task response
|
|
197
|
+
* */
|
|
198
|
+
acceptTask(id) {
|
|
199
|
+
return this.request({
|
|
200
|
+
method: 'POST',
|
|
201
|
+
service: 'raindrop',
|
|
202
|
+
resource: `tasks/${id}/accept`,
|
|
203
|
+
}).then((response) => {
|
|
204
|
+
return DecryptHelper.decryptTaskResponse(this, response.body).then(() => response);
|
|
205
|
+
});
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Reject task
|
|
210
|
+
* @param {string} [id] task id
|
|
211
|
+
* @returns {Promise} Resolves with rejecting task response
|
|
212
|
+
* */
|
|
213
|
+
rejectTask(id) {
|
|
214
|
+
return this.request({
|
|
215
|
+
method: 'POST',
|
|
216
|
+
service: 'raindrop',
|
|
217
|
+
resource: `tasks/${id}/reject`,
|
|
218
|
+
}).then((response) => {
|
|
219
|
+
return DecryptHelper.decryptTaskResponse(this, response.body).then(() => response);
|
|
220
|
+
});
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
export default Task;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {assert} from '@webex/test-helper-chai';
|
|
2
|
+
|
|
3
|
+
// mock testUsers
|
|
4
|
+
const testUsers = {
|
|
5
|
+
create: () => Promise.resolve([
|
|
6
|
+
{
|
|
7
|
+
token: 'fake-token',
|
|
8
|
+
webex: null
|
|
9
|
+
}
|
|
10
|
+
])
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// mock WebexCore
|
|
14
|
+
class MockTask {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.tasks = [];
|
|
17
|
+
this.id = 1;
|
|
18
|
+
}
|
|
19
|
+
createTask({title, notes}) {
|
|
20
|
+
const task = {id: String(this.id++), title, notes};
|
|
21
|
+
this.tasks.push(task);
|
|
22
|
+
return Promise.resolve({body: task});
|
|
23
|
+
}
|
|
24
|
+
getTask(id) {
|
|
25
|
+
const task = this.tasks.find(t => t.id === id);
|
|
26
|
+
return Promise.resolve(task);
|
|
27
|
+
}
|
|
28
|
+
listMyTasks() {
|
|
29
|
+
return Promise.resolve({body: {items: this.tasks}});
|
|
30
|
+
}
|
|
31
|
+
deleteTask(id) {
|
|
32
|
+
this.tasks = this.tasks.filter(t => t.id !== id);
|
|
33
|
+
return Promise.resolve();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class WebexCore {
|
|
38
|
+
constructor() {
|
|
39
|
+
this.internal = {
|
|
40
|
+
device: {},
|
|
41
|
+
encryption: {
|
|
42
|
+
kms: {
|
|
43
|
+
setDeviceInfo: () => {},
|
|
44
|
+
createUnboundKeys: async () => [{uri: 'kms://mock-key', jwk: {}}]
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
task: new MockTask()
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
describe('plugin-task', function () {
|
|
53
|
+
// this.timeout(60000);
|
|
54
|
+
describe('Task', () => {
|
|
55
|
+
let createdTask, spock;
|
|
56
|
+
|
|
57
|
+
beforeEach('create users', async () => {
|
|
58
|
+
[spock] = await testUsers.create({count: 1});
|
|
59
|
+
spock.webex = new WebexCore();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
beforeEach('populate data', async () => {
|
|
63
|
+
const t = await spock.webex.internal.task.createTask({
|
|
64
|
+
title: 'Task Title',
|
|
65
|
+
notes: 'Task Notes',
|
|
66
|
+
});
|
|
67
|
+
createdTask = t.body;
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
afterEach(async () => {
|
|
71
|
+
const res = await spock.webex.internal.task.listMyTasks();
|
|
72
|
+
await Promise.all(
|
|
73
|
+
res.body.items.map((task) =>
|
|
74
|
+
spock.webex.internal.task.deleteTask(task.id).catch((reason) => console.warn(reason))
|
|
75
|
+
)
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('#getTask()', () => {
|
|
80
|
+
it('fetch the task', async () => {
|
|
81
|
+
const task = await spock.webex.internal.task.getTask(createdTask.id);
|
|
82
|
+
assert.isObject(task);
|
|
83
|
+
assert.equal(task.id, createdTask.id);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import DecryptHelper from "@webex/internal-plugin-task/src/helpers/decrypt.helper";
|
|
2
|
+
|
|
3
|
+
describe("internal-plugin-task", () => {
|
|
4
|
+
describe("DecryptHelper", () => {
|
|
5
|
+
let ctx;
|
|
6
|
+
let encryptedTaskData;
|
|
7
|
+
let encryptedTasksData;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
ctx = {
|
|
11
|
+
webex: {
|
|
12
|
+
internal: {
|
|
13
|
+
encryption: {
|
|
14
|
+
decryptText: jest.fn()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
encryptedTaskData = {
|
|
21
|
+
"id": "abcdabcd-abcd-abcd-abcd-00000000",
|
|
22
|
+
"title": "Encrypted Task Title",
|
|
23
|
+
"notes": "Encrypted Task Notes",
|
|
24
|
+
"encryptionKeyUrl": "/keys/e5d3f747-6adf-432d-999c-6578e33953e3",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
encryptedTasksData = {
|
|
28
|
+
"offset": 0,
|
|
29
|
+
"limit": 100,
|
|
30
|
+
"hasMore": false,
|
|
31
|
+
"items": [
|
|
32
|
+
encryptedTaskData
|
|
33
|
+
]
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
jest.clearAllMocks();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("#decryptTaskResponse - should resolve with undefined if data is undefined", async () => {
|
|
42
|
+
const decryptedData = await DecryptHelper.decryptTaskResponse(ctx, undefined);
|
|
43
|
+
expect(decryptedData).toBeUndefined();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("#decryptTaskResponse - should resolve with undefined if data.encryptionKeyUrl is undefined", async () => {
|
|
47
|
+
encryptedTaskData.encryptionKeyUrl = undefined;
|
|
48
|
+
const decryptedData = await DecryptHelper.decryptTaskResponse(ctx, encryptedTaskData);
|
|
49
|
+
expect(decryptedData).toBeUndefined();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("#decryptTaskResponse - should replace encrypted data with decrypted data in response", () => {
|
|
53
|
+
it("should decrypt scheduler data response correctly", async () => {
|
|
54
|
+
const expectedCiphertext = "some decrypted text for testing";
|
|
55
|
+
ctx.webex.internal.encryption.decryptText.mockResolvedValue(expectedCiphertext);
|
|
56
|
+
|
|
57
|
+
await DecryptHelper.decryptTaskResponse(ctx, encryptedTaskData);
|
|
58
|
+
|
|
59
|
+
expect(encryptedTaskData.title).toBe(expectedCiphertext);
|
|
60
|
+
expect(encryptedTaskData.notes).toBe(expectedCiphertext);
|
|
61
|
+
expect(ctx.webex.internal.encryption.decryptText).toHaveBeenCalled();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("#decryptTasksResponse - should resolve with undefined if data is undefined", async () => {
|
|
66
|
+
const decryptedData = await DecryptHelper.decryptTasksResponse(ctx, undefined);
|
|
67
|
+
expect(decryptedData).toBeUndefined();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("#decryptTasksResponse - should resolve with undefined if data.items is undefined", async () => {
|
|
71
|
+
const decryptedData = await DecryptHelper.decryptTasksResponse(ctx, {});
|
|
72
|
+
expect(decryptedData).toBeUndefined();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("#decryptTasksResponse - should resolve with undefined if data.items is empty", async () => {
|
|
76
|
+
const decryptedData = await DecryptHelper.decryptTasksResponse(ctx, { items: [] });
|
|
77
|
+
expect(decryptedData).toBeUndefined();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe("#decryptTasksResponse - should replace encrypted data with decrypted data in response", () => {
|
|
81
|
+
it("should decrypt tasks data response correctly", async () => {
|
|
82
|
+
const expectedCiphertext = "some decrypted text for testing";
|
|
83
|
+
ctx.webex.internal.encryption.decryptText.mockResolvedValue(expectedCiphertext);
|
|
84
|
+
|
|
85
|
+
await DecryptHelper.decryptTasksResponse(ctx, encryptedTasksData);
|
|
86
|
+
|
|
87
|
+
expect(encryptedTasksData.items[0].title).toBe(expectedCiphertext);
|
|
88
|
+
expect(encryptedTasksData.items[0].notes).toBe(expectedCiphertext);
|
|
89
|
+
expect(ctx.webex.internal.encryption.decryptText).toHaveBeenCalled();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import EncryptHelper from '@webex/internal-plugin-task/src/helpers/encrypt.helper';
|
|
2
|
+
|
|
3
|
+
describe('internal-plugin-task', () => {
|
|
4
|
+
describe('encryptHelper', () => {
|
|
5
|
+
let ctx;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
ctx = {
|
|
9
|
+
webex: {
|
|
10
|
+
internal: {
|
|
11
|
+
encryption: {
|
|
12
|
+
encryptText: jest.fn(),
|
|
13
|
+
kms: {
|
|
14
|
+
createUnboundKeys: jest.fn().mockResolvedValue([{
|
|
15
|
+
uri: 'kmsKeyUri',
|
|
16
|
+
}]),
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
jest.clearAllMocks();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('#encryptTaskRequest with plain text fields', async () => {
|
|
29
|
+
const taskRequest = {
|
|
30
|
+
"title": "plain text title",
|
|
31
|
+
"notes": "plain text notes",
|
|
32
|
+
};
|
|
33
|
+
const expectedCiphertext = 'some encrpty data';
|
|
34
|
+
ctx.webex.internal.encryption.encryptText.mockResolvedValue(expectedCiphertext);
|
|
35
|
+
|
|
36
|
+
await EncryptHelper.encryptTaskRequest(ctx, taskRequest);
|
|
37
|
+
|
|
38
|
+
expect(taskRequest.title).toBe(expectedCiphertext);
|
|
39
|
+
expect(taskRequest.notes).toBe(expectedCiphertext);
|
|
40
|
+
expect(ctx.webex.internal.encryption.encryptText).toHaveBeenCalled();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
});
|