@verii/agentdb-cli 1.0.0-pre.1752076816

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.
@@ -0,0 +1,292 @@
1
+ const { buildMongoConnection } = require('@verii/tests-helpers');
2
+ const { ObjectId } = require('mongodb');
3
+ const { decryptCollection, encryptCollection } = require('@verii/crypto');
4
+ const { initMongoClient } = require('../src/helpers/init-mongo-client');
5
+ const {
6
+ reencryptCollectionField,
7
+ } = require('../src/rotate-key/reencrypt-collection-field');
8
+ const { reencrypt } = require('../src/rotate-key/reencrypt');
9
+
10
+ const decryptedKey = 'TEST-KEY';
11
+ const decryptedFoo = 'TEST-FOO';
12
+ const decryptedTenant = 'TEST-TENANT';
13
+ const oldKey = '11111111111111111111111111111';
14
+ const newKey = '22222222222222222222222222222';
15
+
16
+ const persistKeyFactory =
17
+ (db) =>
18
+ async (encryptionKey = oldKey) => {
19
+ const result = await db.collection('keys').insertOne({
20
+ purposes: ['DLT_TRANSACTIONS'],
21
+ algorithm: 'SECP256K1',
22
+ encoding: 'hex',
23
+ kidFragment: '#eth-account-key-1',
24
+ key: encryptCollection(decryptedKey, encryptionKey),
25
+ tenantId: new ObjectId(),
26
+ createdAt: new Date(),
27
+ updatedAt: new Date(),
28
+ });
29
+
30
+ return db.collection('keys').findOne(result.insertedId);
31
+ };
32
+
33
+ const persistTenantFactory =
34
+ (db) =>
35
+ async (encryptionKey = oldKey) => {
36
+ const result = await db.collection('tenants').insertOne({
37
+ webhookAuth: {
38
+ type: 'bearer',
39
+ bearerToken: encryptCollection(decryptedTenant, encryptionKey),
40
+ },
41
+ createdAt: new Date(),
42
+ updatedAt: new Date(),
43
+ });
44
+
45
+ return db.collection('tenants').findOne(result.insertedId);
46
+ };
47
+
48
+ const persistFooFactory =
49
+ (db) =>
50
+ async (encryptionKey = oldKey) => {
51
+ const result = await db.collection('foos').insertOne({
52
+ foo: encryptCollection(decryptedFoo, encryptionKey),
53
+ bar: 'bar',
54
+ createdAt: new Date(),
55
+ updatedAt: new Date(),
56
+ });
57
+
58
+ return db.collection('foos').findOne(result.insertedId);
59
+ };
60
+
61
+ describe('rotate-key test suite', () => {
62
+ let client;
63
+ let db;
64
+ let persistKey;
65
+ let persistFoo;
66
+ let persistTenant;
67
+ let testOptions;
68
+
69
+ beforeAll(async () => {
70
+ client = await initMongoClient(
71
+ buildMongoConnection('test-credentialagent')
72
+ );
73
+ db = client.db();
74
+ persistKey = persistKeyFactory(db);
75
+ persistFoo = persistFooFactory(db);
76
+ persistTenant = persistTenantFactory(db);
77
+ });
78
+
79
+ afterAll(async () => {
80
+ await client.close();
81
+ });
82
+
83
+ beforeEach(async () => {
84
+ await db.collection('tenants').deleteMany({});
85
+ await db.collection('keys').deleteMany({});
86
+ await db.collection('foos').deleteMany({});
87
+ testOptions = {
88
+ collection: 'keys',
89
+ secretProp: 'key',
90
+ };
91
+ });
92
+
93
+ it('Should handle no entries ', async () => {
94
+ await reencryptCollectionField(
95
+ oldKey,
96
+ newKey,
97
+ testOptions.collection,
98
+ testOptions.secretProp,
99
+ { db, ...testOptions }
100
+ );
101
+ });
102
+
103
+ it('Should update encrypted key if old key is correct', async () => {
104
+ const key = await persistKey();
105
+ await reencryptCollectionField(
106
+ oldKey,
107
+ newKey,
108
+ testOptions.collection,
109
+ testOptions.secretProp,
110
+ { db, ...testOptions }
111
+ );
112
+ const updatedKey = await db.collection('keys').findOne(key._id);
113
+ expect(decryptCollection(updatedKey.key, newKey)).toEqual(decryptedKey);
114
+ });
115
+
116
+ it('Should not update database during dry run', async () => {
117
+ const key = await persistKey();
118
+ await reencryptCollectionField(
119
+ oldKey,
120
+ newKey,
121
+ testOptions.collection,
122
+ testOptions.secretProp,
123
+ {
124
+ db,
125
+ ...testOptions,
126
+ dryRun: true,
127
+ }
128
+ );
129
+ const updatedKey = await db.collection('keys').findOne(key._id);
130
+ expect(updatedKey.key).toEqual(key.key);
131
+ });
132
+
133
+ it('Should update encrypted foo if old key is correct', async () => {
134
+ const foo = await persistFoo();
135
+ testOptions = {
136
+ collection: 'foos',
137
+ secretProp: 'foo',
138
+ };
139
+
140
+ await reencryptCollectionField(
141
+ oldKey,
142
+ newKey,
143
+ testOptions.collection,
144
+ testOptions.secretProp,
145
+ { db, ...testOptions }
146
+ );
147
+
148
+ const updatedFoo = await db.collection('foos').findOne(foo._id);
149
+
150
+ expect(decryptCollection(updatedFoo.foo, newKey)).toEqual(decryptedFoo);
151
+ });
152
+
153
+ it('Should update encrypted nested field without rewriting whole object', async () => {
154
+ testOptions = {
155
+ collection: 'tenants',
156
+ secretProp: 'webhookAuth.bearerToken',
157
+ };
158
+
159
+ const tenant = await persistTenant();
160
+
161
+ await reencryptCollectionField(
162
+ oldKey,
163
+ newKey,
164
+ testOptions.collection,
165
+ testOptions.secretProp,
166
+ { db, ...testOptions }
167
+ );
168
+
169
+ const updatedTenant = await db.collection('tenants').findOne(tenant._id);
170
+ expect(
171
+ decryptCollection(updatedTenant.webhookAuth.bearerToken, newKey)
172
+ ).toEqual(decryptedTenant);
173
+
174
+ expect(updatedTenant.webhookAuth).toEqual({
175
+ bearerToken: expect.any(String),
176
+ type: 'bearer',
177
+ });
178
+ });
179
+
180
+ it('Should fail if old key is incorrect', async () => {
181
+ await persistKey();
182
+ const exec = () =>
183
+ reencryptCollectionField(
184
+ 'WRONG-KEY',
185
+ newKey,
186
+ testOptions.collection,
187
+ testOptions.secretProp,
188
+ { db, ...testOptions }
189
+ );
190
+ await expect(exec).rejects.toThrowError(
191
+ 'Unsupported state or unable to authenticate data'
192
+ );
193
+ });
194
+
195
+ it('Should run additional reencryptCollectionField with default params', async () => {
196
+ const key = await persistKey();
197
+ const tenant = await persistTenant();
198
+
199
+ await reencrypt(oldKey, newKey, undefined, undefined, { db });
200
+
201
+ const updatedTenant = await db.collection('tenants').findOne(tenant._id);
202
+ const updatedKey = await db.collection('keys').findOne(key._id);
203
+
204
+ expect(decryptCollection(updatedKey.key, newKey)).toEqual(decryptedKey);
205
+
206
+ expect(
207
+ decryptCollection(updatedTenant.webhookAuth.bearerToken, newKey)
208
+ ).toEqual(decryptedTenant);
209
+
210
+ expect(updatedTenant.webhookAuth).toEqual({
211
+ bearerToken: expect.any(String),
212
+ type: 'bearer',
213
+ });
214
+ });
215
+
216
+ describe('Reencrypt test suite', () => {
217
+ it('Should run reencryptCollectionField on keys and tenants', async () => {
218
+ const tenant = await persistTenant();
219
+ const key = await persistKey();
220
+
221
+ await reencrypt(oldKey, newKey, undefined, undefined, {
222
+ db,
223
+ });
224
+
225
+ const updatedTenant = await db.collection('tenants').findOne(tenant._id);
226
+ const updatedKey = await db.collection('keys').findOne(key._id);
227
+
228
+ expect(decryptCollection(updatedKey.key, newKey)).toEqual(decryptedKey);
229
+
230
+ expect(
231
+ decryptCollection(updatedTenant.webhookAuth.bearerToken, newKey)
232
+ ).toEqual(decryptedTenant);
233
+
234
+ expect(updatedTenant.webhookAuth).toEqual({
235
+ bearerToken: expect.any(String),
236
+ type: 'bearer',
237
+ });
238
+ });
239
+
240
+ it('Should run reencrypt only on tenants', async () => {
241
+ const tenant = await persistTenant();
242
+ const key = await persistKey();
243
+
244
+ await reencrypt(oldKey, newKey, 'tenants', 'webhookAuth.bearerToken', {
245
+ db,
246
+ });
247
+
248
+ const updatedTenant = await db.collection('tenants').findOne(tenant._id);
249
+ const sameKey = await db.collection('keys').findOne(key._id);
250
+
251
+ expect(decryptCollection(sameKey.key, oldKey)).toEqual(decryptedKey);
252
+
253
+ expect(
254
+ decryptCollection(updatedTenant.webhookAuth.bearerToken, newKey)
255
+ ).toEqual(decryptedTenant);
256
+ });
257
+
258
+ it('Should pass default options from reencrypt to reencryptCollectionField if collection was not provided', async () => {
259
+ const tenant = await persistTenant();
260
+ const key = await persistKey();
261
+
262
+ await reencrypt(oldKey, newKey, undefined, 'key', {
263
+ db,
264
+ });
265
+
266
+ const sameTenant = await db.collection('tenants').findOne(tenant._id);
267
+ const updatedKey = await db.collection('keys').findOne(key._id);
268
+
269
+ expect(decryptCollection(updatedKey.key, newKey)).toEqual(decryptedKey);
270
+ expect(
271
+ decryptCollection(sameTenant.webhookAuth.bearerToken, oldKey)
272
+ ).toEqual(decryptedTenant);
273
+ });
274
+
275
+ it('Should pass default options from reencrypt to reencryptCollectionField if secretProp was not provided', async () => {
276
+ const tenant = await persistTenant();
277
+ const key = await persistKey();
278
+
279
+ await reencrypt(oldKey, newKey, 'keys', undefined, {
280
+ db,
281
+ });
282
+
283
+ const sameTenant = await db.collection('tenants').findOne(tenant._id);
284
+ const updatedKey = await db.collection('keys').findOne(key._id);
285
+
286
+ expect(decryptCollection(updatedKey.key, newKey)).toEqual(decryptedKey);
287
+ expect(
288
+ decryptCollection(sameTenant.webhookAuth.bearerToken, oldKey)
289
+ ).toEqual(decryptedTenant);
290
+ });
291
+ });
292
+ });