@icure/api 8.0.64 → 8.0.66
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/icc-api/api/internal/IccExchangeDataApi.d.ts +2 -0
- package/icc-api/api/internal/IccExchangeDataApi.js +10 -0
- package/icc-api/api/internal/IccExchangeDataApi.js.map +1 -1
- package/icc-api/iccApi.d.ts +0 -1
- package/icc-api/iccApi.js +0 -1
- package/icc-api/iccApi.js.map +1 -1
- package/icc-api/index.d.ts +0 -1
- package/icc-api/index.js +0 -1
- package/icc-api/index.js.map +1 -1
- package/icc-x-api/crypto/AccessControlSecretUtils.d.ts +4 -13
- package/icc-x-api/crypto/AccessControlSecretUtils.js +19 -29
- package/icc-x-api/crypto/AccessControlSecretUtils.js.map +1 -1
- package/icc-x-api/crypto/BaseExchangeDataManager.d.ts +8 -3
- package/icc-x-api/crypto/BaseExchangeDataManager.js +45 -10
- package/icc-x-api/crypto/BaseExchangeDataManager.js.map +1 -1
- package/icc-x-api/crypto/BaseExchangeKeysManager.d.ts +2 -3
- package/icc-x-api/crypto/BaseExchangeKeysManager.js +17 -20
- package/icc-x-api/crypto/BaseExchangeKeysManager.js.map +1 -1
- package/icc-x-api/crypto/CryptoPrimitives.d.ts +2 -0
- package/icc-x-api/crypto/CryptoPrimitives.js +3 -0
- package/icc-x-api/crypto/CryptoPrimitives.js.map +1 -1
- package/icc-x-api/crypto/DelegationsDeAnonymization.d.ts +3 -3
- package/icc-x-api/crypto/DelegationsDeAnonymization.js +7 -7
- package/icc-x-api/crypto/DelegationsDeAnonymization.js.map +1 -1
- package/icc-x-api/crypto/ExchangeDataManager.d.ts +19 -29
- package/icc-x-api/crypto/ExchangeDataManager.js +200 -225
- package/icc-x-api/crypto/ExchangeDataManager.js.map +1 -1
- package/icc-x-api/crypto/ExchangeDataMapManager.js +6 -4
- package/icc-x-api/crypto/ExchangeDataMapManager.js.map +1 -1
- package/icc-x-api/crypto/ExchangeKeysManager.d.ts +4 -16
- package/icc-x-api/crypto/ExchangeKeysManager.js +44 -41
- package/icc-x-api/crypto/ExchangeKeysManager.js.map +1 -1
- package/icc-x-api/crypto/ExtendedApisUtils.d.ts +47 -25
- package/icc-x-api/crypto/ExtendedApisUtils.js.map +1 -1
- package/icc-x-api/crypto/ExtendedApisUtilsImpl.d.ts +19 -18
- package/icc-x-api/crypto/ExtendedApisUtilsImpl.js +213 -134
- package/icc-x-api/crypto/ExtendedApisUtilsImpl.js.map +1 -1
- package/icc-x-api/crypto/HMACUtils.d.ts +2 -2
- package/icc-x-api/crypto/HMACUtils.js +3 -4
- package/icc-x-api/crypto/HMACUtils.js.map +1 -1
- package/icc-x-api/crypto/NativeCryptoPrimitivesBridge.d.ts +1 -0
- package/icc-x-api/crypto/NativeCryptoPrimitivesBridge.js +5 -0
- package/icc-x-api/crypto/NativeCryptoPrimitivesBridge.js.map +1 -1
- package/icc-x-api/crypto/SecureDelegationsManager.d.ts +0 -1
- package/icc-x-api/crypto/SecureDelegationsManager.js +17 -49
- package/icc-x-api/crypto/SecureDelegationsManager.js.map +1 -1
- package/icc-x-api/crypto/SecurityMetadataDecryptor.d.ts +59 -90
- package/icc-x-api/crypto/SecurityMetadataDecryptor.js +470 -56
- package/icc-x-api/crypto/SecurityMetadataDecryptor.js.map +1 -1
- package/icc-x-api/crypto/ShamirKeysManager.js +1 -1
- package/icc-x-api/crypto/ShamirKeysManager.js.map +1 -1
- package/icc-x-api/crypto/TransferKeysManager.d.ts +1 -3
- package/icc-x-api/crypto/TransferKeysManager.js +2 -4
- package/icc-x-api/crypto/TransferKeysManager.js.map +1 -1
- package/icc-x-api/icc-accesslog-x-api.d.ts +2 -2
- package/icc-x-api/icc-accesslog-x-api.js +7 -3
- package/icc-x-api/icc-accesslog-x-api.js.map +1 -1
- package/icc-x-api/icc-calendar-item-x-api.js +4 -2
- package/icc-x-api/icc-calendar-item-x-api.js.map +1 -1
- package/icc-x-api/icc-contact-x-api.d.ts +0 -1
- package/icc-x-api/icc-contact-x-api.js +33 -48
- package/icc-x-api/icc-contact-x-api.js.map +1 -1
- package/icc-x-api/icc-crypto-x-api.js +1 -1
- package/icc-x-api/icc-crypto-x-api.js.map +1 -1
- package/icc-x-api/icc-document-x-api.d.ts +2 -2
- package/icc-x-api/icc-document-x-api.js +45 -42
- package/icc-x-api/icc-document-x-api.js.map +1 -1
- package/icc-x-api/icc-form-x-api.js +3 -1
- package/icc-x-api/icc-form-x-api.js.map +1 -1
- package/icc-x-api/icc-helement-x-api.js +4 -4
- package/icc-x-api/icc-helement-x-api.js.map +1 -1
- package/icc-x-api/icc-maintenance-task-x-api.js +4 -2
- package/icc-x-api/icc-maintenance-task-x-api.js.map +1 -1
- package/icc-x-api/icc-message-x-api.js +4 -2
- package/icc-x-api/icc-message-x-api.js.map +1 -1
- package/icc-x-api/icc-patient-x-api.js +5 -7
- package/icc-x-api/icc-patient-x-api.js.map +1 -1
- package/icc-x-api/icc-topic-x-api.js +2 -2
- package/icc-x-api/icc-topic-x-api.js.map +1 -1
- package/icc-x-api/index.d.ts +6 -2
- package/icc-x-api/index.js +16 -20
- package/icc-x-api/index.js.map +1 -1
- package/icc-x-api/utils/crypto-utils.d.ts +6 -4
- package/icc-x-api/utils/crypto-utils.js +27 -6
- package/icc-x-api/utils/crypto-utils.js.map +1 -1
- package/icc-x-api/utils/simple-lru-cache.d.ts +19 -0
- package/icc-x-api/utils/simple-lru-cache.js +90 -0
- package/icc-x-api/utils/simple-lru-cache.js.map +1 -0
- package/package.json +4 -2
- package/test/icc-x-api/crud/entities-crud-test-interface.js +0 -8
- package/test/icc-x-api/crud/entities-crud-test-interface.js.map +1 -1
- package/test/icc-x-api/crypto/exchange-data-manager-test.js +75 -93
- package/test/icc-x-api/crypto/exchange-data-manager-test.js.map +1 -1
- package/test/icc-x-api/crypto/legacy-metadata-migration-test.js.map +1 -1
- package/test/icc-x-api/crypto/secure-delegations-manager-test.js +28 -16
- package/test/icc-x-api/crypto/secure-delegations-manager-test.js.map +1 -1
- package/test/utils/FakeEncryptionKeysManager.d.ts +1 -0
- package/test/utils/FakeEncryptionKeysManager.js +11 -0
- package/test/utils/FakeEncryptionKeysManager.js.map +1 -1
- package/test/utils/FakeExchangeDataApi.d.ts +4 -2
- package/test/utils/FakeExchangeDataApi.js +24 -6
- package/test/utils/FakeExchangeDataApi.js.map +1 -1
- package/test/utils/FakeExchangeDataManager.d.ts +10 -10
- package/test/utils/FakeExchangeDataManager.js +12 -22
- package/test/utils/FakeExchangeDataManager.js.map +1 -1
- package/test/utils/TestApi.js +1 -0
- package/test/utils/TestApi.js.map +1 -1
- package/icc-api/api/IccArticleApi.d.ts +0 -72
- package/icc-api/api/IccArticleApi.js +0 -149
- package/icc-api/api/IccArticleApi.js.map +0 -1
- package/icc-x-api/crypto/LegacyDelegationSecurityMetadataDecryptor.d.ts +0 -33
- package/icc-x-api/crypto/LegacyDelegationSecurityMetadataDecryptor.js +0 -141
- package/icc-x-api/crypto/LegacyDelegationSecurityMetadataDecryptor.js.map +0 -1
- package/icc-x-api/crypto/SecureDelegationsSecurityMetadataDecryptor.d.ts +0 -46
- package/icc-x-api/crypto/SecureDelegationsSecurityMetadataDecryptor.js +0 -312
- package/icc-x-api/crypto/SecureDelegationsSecurityMetadataDecryptor.js.map +0 -1
- package/icc-x-api/crypto/UserSignatureKeysManager.d.ts +0 -26
- package/icc-x-api/crypto/UserSignatureKeysManager.js +0 -78
- package/icc-x-api/crypto/UserSignatureKeysManager.js.map +0 -1
- package/test/icc-x-api/crypto/secure-delegations-metadata-decryptor-test.d.ts +0 -1
- package/test/icc-x-api/crypto/secure-delegations-metadata-decryptor-test.js +0 -393
- package/test/icc-x-api/crypto/secure-delegations-metadata-decryptor-test.js.map +0 -1
- package/test/icc-x-api/crypto/security-metadata-decryptor-chain-test.d.ts +0 -1
- package/test/icc-x-api/crypto/security-metadata-decryptor-chain-test.js +0 -213
- package/test/icc-x-api/crypto/security-metadata-decryptor-chain-test.js.map +0 -1
- package/test/icc-x-api/crypto/signature-keys-manager-test.d.ts +0 -1
- package/test/icc-x-api/crypto/signature-keys-manager-test.js +0 -44
- package/test/icc-x-api/crypto/signature-keys-manager-test.js.map +0 -1
- package/test/utils/FakeSignatureKeysManager.d.ts +0 -16
- package/test/utils/FakeSignatureKeysManager.js +0 -54
- package/test/utils/FakeSignatureKeysManager.js.map +0 -1
|
@@ -11,7 +11,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.ExtendedApisUtilsImpl = void 0;
|
|
13
13
|
const utils_1 = require("../utils");
|
|
14
|
-
const collection_utils_1 = require("../utils/collection-utils");
|
|
15
14
|
const SecurityMetadataDecryptor_1 = require("./SecurityMetadataDecryptor");
|
|
16
15
|
const SecureDelegation_1 = require("../../icc-api/model/SecureDelegation");
|
|
17
16
|
const EntityShareRequest_1 = require("../../icc-api/model/requests/EntityShareRequest");
|
|
@@ -26,49 +25,47 @@ var AccessLevelEnum = SecureDelegation_1.SecureDelegation.AccessLevelEnum;
|
|
|
26
25
|
* Methods to support extended apis.
|
|
27
26
|
*/
|
|
28
27
|
class ExtendedApisUtilsImpl {
|
|
29
|
-
constructor(primitives, dataOwnerApi,
|
|
28
|
+
constructor(primitives, dataOwnerApi, securityMetadataDecryptor, secureDelegationsManager, userApi, useParentKeys) {
|
|
30
29
|
this.primitives = primitives;
|
|
31
30
|
this.dataOwnerApi = dataOwnerApi;
|
|
32
|
-
this.
|
|
33
|
-
this.secDelMetadataDecryptor = secDelMetadataDecryptor;
|
|
31
|
+
this.securityMetadataDecryptor = securityMetadataDecryptor;
|
|
34
32
|
this.secureDelegationsManager = secureDelegationsManager;
|
|
35
33
|
this.userApi = userApi;
|
|
36
34
|
this.useParentKeys = useParentKeys;
|
|
37
|
-
this.allSecurityMetadataDecryptor = new SecurityMetadataDecryptor_1.SecurityMetadataDecryptorChain([legacyDelMetadataDecryptor, secDelMetadataDecryptor]);
|
|
38
35
|
}
|
|
39
36
|
encryptionKeysOf(entity, dataOwnerId) {
|
|
40
37
|
return __awaiter(this, void 0, void 0, function* () {
|
|
41
|
-
return yield this.decryptAndMergeHierarchy(
|
|
38
|
+
return yield this.decryptAndMergeHierarchy(dataOwnerId, (hierarchy) => this.securityMetadataDecryptor.decryptAll(entity.entity, hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.EncryptionKey));
|
|
42
39
|
});
|
|
43
40
|
}
|
|
44
41
|
encryptionKeysForHcpHierarchyOf(entity) {
|
|
45
42
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
-
return this.decryptHierarchy(
|
|
43
|
+
return this.decryptHierarchy((hierarchy) => this.securityMetadataDecryptor.decryptAll(entity.entity, hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.EncryptionKey));
|
|
47
44
|
});
|
|
48
45
|
}
|
|
49
46
|
secretIdsOf(entity, dataOwnerId) {
|
|
50
47
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
-
return yield this.decryptAndMergeHierarchy(
|
|
48
|
+
return yield this.decryptAndMergeHierarchy(dataOwnerId, (hierarchy) => this.securityMetadataDecryptor.decryptAll(entity.entity, hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.SecretId));
|
|
52
49
|
});
|
|
53
50
|
}
|
|
54
51
|
secretIdsForHcpHierarchyOf(entity) {
|
|
55
52
|
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
-
return this.decryptHierarchy(
|
|
53
|
+
return this.decryptHierarchy((hierarchy) => this.securityMetadataDecryptor.decryptAll(entity.entity, hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.SecretId));
|
|
57
54
|
});
|
|
58
55
|
}
|
|
59
56
|
owningEntityIdsOf(entity, dataOwnerId) {
|
|
60
57
|
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
-
return yield this.decryptAndMergeHierarchy(
|
|
58
|
+
return yield this.decryptAndMergeHierarchy(dataOwnerId, (hierarchy) => this.securityMetadataDecryptor.decryptAll(entity.entity, hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.OwningEntityId));
|
|
62
59
|
});
|
|
63
60
|
}
|
|
64
61
|
owningEntityIdsForHcpHierarchyOf(entity) {
|
|
65
62
|
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
-
return this.decryptHierarchy(
|
|
63
|
+
return this.decryptHierarchy((hierarchy) => this.securityMetadataDecryptor.decryptAll(entity.entity, hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.OwningEntityId));
|
|
67
64
|
});
|
|
68
65
|
}
|
|
69
66
|
hasWriteAccess(entity) {
|
|
70
67
|
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
-
return ((yield this.
|
|
68
|
+
return ((yield this.securityMetadataDecryptor.getEntityAccessLevel(entity.entity, yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds())) ===
|
|
72
69
|
AccessLevel.WRITE);
|
|
73
70
|
});
|
|
74
71
|
}
|
|
@@ -186,7 +183,7 @@ class ExtendedApisUtilsImpl {
|
|
|
186
183
|
}
|
|
187
184
|
}
|
|
188
185
|
if (Object.keys(currentRequests).length > 0) {
|
|
189
|
-
const existingDelegationMembersDetails = yield this.
|
|
186
|
+
const existingDelegationMembersDetails = yield this.securityMetadataDecryptor.getDelegationMemberDetails(entityWithType);
|
|
190
187
|
const accessibleMembers = new Set(this.useParentKeys ? yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds() : [yield this.dataOwnerApi.getCurrentDataOwnerId()]);
|
|
191
188
|
const potentialParentDelegations = Object.entries(existingDelegationMembersDetails).flatMap(([k, members]) => {
|
|
192
189
|
if ((!!members.delegate && accessibleMembers.has(members.delegate)) || (!!members.delegator && accessibleMembers.has(members.delegator))) {
|
|
@@ -251,9 +248,9 @@ class ExtendedApisUtilsImpl {
|
|
|
251
248
|
const hierarchy = this.useParentKeys
|
|
252
249
|
? yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds()
|
|
253
250
|
: [yield this.dataOwnerApi.getCurrentDataOwnerId()];
|
|
254
|
-
const legacySecretIds = yield
|
|
255
|
-
const legacyEncryptionKeys = yield
|
|
256
|
-
const legacyOwningEntityIds = yield
|
|
251
|
+
const legacySecretIds = yield this.securityMetadataDecryptor.decryptAllLegacyDelegations(entity.entity, hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.SecretId);
|
|
252
|
+
const legacyEncryptionKeys = yield this.securityMetadataDecryptor.decryptAllLegacyDelegations(entity.entity, hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.EncryptionKey);
|
|
253
|
+
const legacyOwningEntityIds = yield this.securityMetadataDecryptor.decryptAllLegacyDelegations(entity.entity, hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.OwningEntityId);
|
|
257
254
|
const res = {};
|
|
258
255
|
const selfId = yield this.dataOwnerApi.getCurrentDataOwnerId();
|
|
259
256
|
for (const hierarchyMember of hierarchy) {
|
|
@@ -273,7 +270,7 @@ class ExtendedApisUtilsImpl {
|
|
|
273
270
|
const subHierarchySet = new Set(subHierarchy);
|
|
274
271
|
const legacyAccess = selfId === entity.entity.id && currMemberId === selfId
|
|
275
272
|
? AccessLevel.WRITE
|
|
276
|
-
: yield this.
|
|
273
|
+
: yield this.securityMetadataDecryptor.getEntityLegacyDelegationAccessLevel(entity.entity, subHierarchy);
|
|
277
274
|
if (!legacyAccess)
|
|
278
275
|
return undefined;
|
|
279
276
|
const selfLegacySecretIds = legacySecretIds.filter((x) => x.dataOwnersWithAccess.some((d) => subHierarchySet.has(d))).map((x) => x.decrypted);
|
|
@@ -287,18 +284,20 @@ class ExtendedApisUtilsImpl {
|
|
|
287
284
|
let missingEncryptionKeys = [];
|
|
288
285
|
let missingOwningEntityIds = [];
|
|
289
286
|
if (selfLegacySecretIds.length > 0) {
|
|
290
|
-
const currentSecretIds = new Set((yield
|
|
287
|
+
const currentSecretIds = new Set((yield this.securityMetadataDecryptor.decryptAllSecureDelegations(entity.entity, [currMemberId], SecurityMetadataDecryptor_1.SecurityMetadataType.SecretId)).map((x) => x.decrypted));
|
|
291
288
|
missingSecretIds = selfLegacySecretIds.filter((x) => !currentSecretIds.has(x));
|
|
292
289
|
}
|
|
293
290
|
if (selfLegacyEncryptionKeys.length > 0) {
|
|
294
|
-
const currentEncryptionKeys = new Set((yield
|
|
291
|
+
const currentEncryptionKeys = new Set((yield this.securityMetadataDecryptor.decryptAllSecureDelegations(entity.entity, [currMemberId], SecurityMetadataDecryptor_1.SecurityMetadataType.EncryptionKey)).map((x) => x.decrypted));
|
|
295
292
|
missingEncryptionKeys = selfLegacyEncryptionKeys.filter((x) => !currentEncryptionKeys.has(x));
|
|
296
293
|
}
|
|
297
294
|
if (selfLegacyOwningEntityIds.length > 0) {
|
|
298
|
-
const currentOwningEntityIds = new Set((yield
|
|
295
|
+
const currentOwningEntityIds = new Set((yield this.securityMetadataDecryptor.decryptAllSecureDelegations(entity.entity, [currMemberId], SecurityMetadataDecryptor_1.SecurityMetadataType.OwningEntityId)).map((x) => x.decrypted));
|
|
299
296
|
missingOwningEntityIds = selfLegacyOwningEntityIds.filter((x) => !currentOwningEntityIds.has(x));
|
|
300
297
|
}
|
|
301
|
-
const mustCreateRootDelegation = selfId === entity.entity.id &&
|
|
298
|
+
const mustCreateRootDelegation = selfId === entity.entity.id &&
|
|
299
|
+
currMemberId === selfId &&
|
|
300
|
+
!(yield this.securityMetadataDecryptor.getEntitySecureDelegationAccessLevel(entity.entity, subHierarchy));
|
|
302
301
|
if (missingSecretIds.length > 0 || missingEncryptionKeys.length > 0 || missingOwningEntityIds.length > 0 || mustCreateRootDelegation) {
|
|
303
302
|
let requestedPermissions;
|
|
304
303
|
if (currMemberId === selfId) {
|
|
@@ -315,27 +314,29 @@ class ExtendedApisUtilsImpl {
|
|
|
315
314
|
}
|
|
316
315
|
tryDecryptDataOf(entity, content, validator) {
|
|
317
316
|
return __awaiter(this, void 0, void 0, function* () {
|
|
318
|
-
const dataOwnerIds = this.useParentKeys
|
|
319
|
-
? yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds()
|
|
320
|
-
: [yield this.dataOwnerApi.getCurrentDataOwnerId()];
|
|
321
|
-
const decryptedKeys = this.allSecurityMetadataDecryptor.decryptEncryptionKeysOf(entity, dataOwnerIds);
|
|
322
317
|
const triedKeys = new Set();
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
318
|
+
const result = yield this.doIncrementallyDecryptingKeys(entity.entity, entity.type, (e, t, keys) => __awaiter(this, void 0, void 0, function* () {
|
|
319
|
+
for (const k of keys) {
|
|
320
|
+
if (!triedKeys.has(k.raw)) {
|
|
321
|
+
triedKeys.add(k.raw);
|
|
322
|
+
try {
|
|
323
|
+
const decrypted = yield this.primitives.AES.decrypt(k.key, content);
|
|
324
|
+
if (!validator || (yield validator(decrypted)))
|
|
325
|
+
return { success: decrypted };
|
|
326
|
+
}
|
|
327
|
+
catch (e) {
|
|
328
|
+
console.warn(`Error while attempting to decrypt attachment of ${entity.entity.id} with raw key ${k.raw}: ${e}`);
|
|
329
|
+
}
|
|
334
330
|
}
|
|
335
331
|
}
|
|
336
|
-
|
|
332
|
+
return null;
|
|
333
|
+
}));
|
|
334
|
+
if (result != null) {
|
|
335
|
+
return { data: result.success, wasDecrypted: true };
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
return { data: content, wasDecrypted: false };
|
|
337
339
|
}
|
|
338
|
-
return { data: content, wasDecrypted: false };
|
|
339
340
|
});
|
|
340
341
|
}
|
|
341
342
|
encryptDataOf(entity, type, content, saveEntity) {
|
|
@@ -345,89 +346,131 @@ class ExtendedApisUtilsImpl {
|
|
|
345
346
|
if (!!ensureInitialisedKeysResult) {
|
|
346
347
|
updatedEntity = yield saveEntity(ensureInitialisedKeysResult);
|
|
347
348
|
}
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
349
|
+
const encrypted = yield this.doIncrementallyDecryptingKeys(entity, type, (e, t, keys) => __awaiter(this, void 0, void 0, function* () {
|
|
350
|
+
for (const k of keys) {
|
|
351
|
+
try {
|
|
352
|
+
return {
|
|
353
|
+
success: {
|
|
354
|
+
encryptedData: yield this.primitives.AES.encrypt(k.key, content),
|
|
355
|
+
updatedEntity: updatedEntity,
|
|
356
|
+
},
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
catch (e) {
|
|
360
|
+
console.warn(`Error while encrypting with raw key ${k.raw}: ${e}`);
|
|
361
|
+
}
|
|
359
362
|
}
|
|
360
|
-
|
|
361
|
-
}
|
|
363
|
+
return null;
|
|
364
|
+
}));
|
|
365
|
+
if (encrypted != null)
|
|
366
|
+
return encrypted.success;
|
|
362
367
|
throw new Error(`Could not extract any valid encryption keys for entity ${JSON.stringify(entity)}.`);
|
|
363
368
|
});
|
|
364
369
|
}
|
|
365
|
-
|
|
370
|
+
tryDecryptEntities(entities, entityType, constructor) {
|
|
371
|
+
var _a;
|
|
366
372
|
return __awaiter(this, void 0, void 0, function* () {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
373
|
+
const nothingToDecryptResults = new Map();
|
|
374
|
+
for (const entity of entities) {
|
|
375
|
+
const nothingToDecrypt = yield (0, utils_1.decryptObject)(entity, (encrypted) => __awaiter(this, void 0, void 0, function* () {
|
|
376
|
+
return null;
|
|
377
|
+
}));
|
|
378
|
+
if (nothingToDecrypt != null) {
|
|
379
|
+
nothingToDecryptResults.set(entity.id, constructor(nothingToDecrypt));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const actuallyDecryptedResults = yield this.doManyIncrementallyDecryptingKeys(entities.filter((e) => !nothingToDecryptResults.has(e.id)), entityType, (entity, t, keys) => __awaiter(this, void 0, void 0, function* () {
|
|
383
|
+
// The decrypt object will try all keys on each of the sub-objects; this is intentional because even though it
|
|
384
|
+
// shouldn't happen, but it is still possible that some entity could be accidentally merged badly and the merged
|
|
385
|
+
// entity has multiple encryptedSelf (on different sub-entities) that use different keys.
|
|
386
|
+
const decrypted = yield (0, utils_1.decryptObject)(entity, (encrypted) => this.tryDecryptJson(keys, encrypted, false));
|
|
387
|
+
if (decrypted != null) {
|
|
388
|
+
return { success: constructor(decrypted) };
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
}));
|
|
394
|
+
const res = [];
|
|
395
|
+
for (const entity of entities) {
|
|
396
|
+
const decrypted = (_a = actuallyDecryptedResults.get(entity.id)) !== null && _a !== void 0 ? _a : nothingToDecryptResults.get(entity.id);
|
|
397
|
+
if (!decrypted) {
|
|
398
|
+
res.push({ entity: entity, decrypted: false });
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
res.push({ entity: decrypted, decrypted: true });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return res;
|
|
379
405
|
});
|
|
380
406
|
}
|
|
381
407
|
tryDecryptJson(potentialKeys, encrypted, truncateTrailingDecryptedNulls) {
|
|
382
|
-
var _a;
|
|
383
408
|
return __awaiter(this, void 0, void 0, function* () {
|
|
384
409
|
for (const key of potentialKeys) {
|
|
385
410
|
try {
|
|
386
|
-
const decrypted =
|
|
411
|
+
const decrypted = yield this.primitives.AES.decrypt(key.key, encrypted, key.raw);
|
|
387
412
|
return JSON.parse((0, utils_1.ua2utf8)(truncateTrailingDecryptedNulls ? (0, utils_1.truncateTrailingNulls)(new Uint8Array(decrypted)) : decrypted));
|
|
388
413
|
}
|
|
389
414
|
catch (e) { }
|
|
390
415
|
}
|
|
391
|
-
return
|
|
416
|
+
return null;
|
|
392
417
|
});
|
|
393
418
|
}
|
|
394
|
-
|
|
419
|
+
tryEncryptEntities(entities, entityType, fieldsToEncrypt, encodeBinaryData, requireEncryption, constructor) {
|
|
420
|
+
var _a;
|
|
395
421
|
return __awaiter(this, void 0, void 0, function* () {
|
|
396
|
-
const
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
if (!!encryptionKey) {
|
|
400
|
-
return constructor(yield (0, utils_1.encryptObject)(updatedEntity, (obj) => {
|
|
401
|
-
// TODO should encoding of binary data should probably be applied to everything?
|
|
402
|
-
const json = encodeBinaryData
|
|
403
|
-
? JSON.stringify(obj, (k, v) => {
|
|
404
|
-
return v instanceof ArrayBuffer || ArrayBuffer.isView(v)
|
|
405
|
-
? (0, utils_1.b2a)(new Uint8Array(v).reduce((d, b) => d + String.fromCharCode(b), ''))
|
|
406
|
-
: v;
|
|
407
|
-
})
|
|
408
|
-
: JSON.stringify(obj);
|
|
409
|
-
return this.primitives.AES.encrypt(encryptionKey.key, (0, utils_1.utf8_2ua)(json), encryptionKey.raw);
|
|
410
|
-
}, fieldsToEncrypt, entityType));
|
|
422
|
+
const entitiesWithInitialisedEncryptionKeys = [];
|
|
423
|
+
for (const entity of entities) {
|
|
424
|
+
entitiesWithInitialisedEncryptionKeys.push((_a = (yield this.ensureEncryptionKeysInitialised(entity, entityType))) !== null && _a !== void 0 ? _a : entity);
|
|
411
425
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
426
|
+
const results = yield this.doManyIncrementallyDecryptingKeys(entitiesWithInitialisedEncryptionKeys, entityType, (e, t, keys) => __awaiter(this, void 0, void 0, function* () {
|
|
427
|
+
for (const k of keys) {
|
|
428
|
+
try {
|
|
429
|
+
const encrypted = yield (0, utils_1.encryptObject)(e, (obj) => {
|
|
430
|
+
// TODO encoding of binary data should probably be applied to everything?
|
|
431
|
+
const json = encodeBinaryData
|
|
432
|
+
? JSON.stringify(obj, (k, v) => {
|
|
433
|
+
return v instanceof ArrayBuffer || ArrayBuffer.isView(v)
|
|
434
|
+
? (0, utils_1.b2a)(new Uint8Array(v).reduce((d, b) => d + String.fromCharCode(b), ''))
|
|
435
|
+
: v;
|
|
436
|
+
})
|
|
437
|
+
: JSON.stringify(obj);
|
|
438
|
+
return this.primitives.AES.encrypt(k.key, (0, utils_1.utf8_2ua)(json), k.raw);
|
|
439
|
+
}, fieldsToEncrypt, entityType);
|
|
440
|
+
return { success: constructor(encrypted) };
|
|
420
441
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
442
|
+
catch (e) {
|
|
443
|
+
console.warn(`Error while encrypting with raw key ${k.raw}: ${e}`);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return null;
|
|
447
|
+
}));
|
|
448
|
+
if (results.size != entitiesWithInitialisedEncryptionKeys.length) {
|
|
449
|
+
if (requireEncryption) {
|
|
450
|
+
throw new Error(`Could not encrypt entities ${entitiesWithInitialisedEncryptionKeys.flatMap((e) => (results.has(e.id) ? [] : [e.id]))}`);
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
for (const e of entitiesWithInitialisedEncryptionKeys) {
|
|
454
|
+
if (!results.has(e.id)) {
|
|
455
|
+
yield (0, utils_1.encryptObject)(e, (obj) => __awaiter(this, void 0, void 0, function* () {
|
|
456
|
+
const hasNonEmptyValues = Object.values(obj).some((v) => v !== undefined && (typeof v !== 'object' || (Array.isArray(v) && v.length > 0) || Object.keys(v).length > 0));
|
|
457
|
+
if (hasNonEmptyValues) {
|
|
458
|
+
throw new Error(`Impossible to modify encrypted content of an entity if no encryption key is known.\nEntity: ${JSON.stringify(e)}\nTo encrypt: ${JSON.stringify(obj)}`);
|
|
459
|
+
}
|
|
460
|
+
return Promise.resolve(new ArrayBuffer(1));
|
|
461
|
+
}), fieldsToEncrypt, 'entity');
|
|
462
|
+
results.set(e.id, e);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
424
466
|
}
|
|
467
|
+
return entitiesWithInitialisedEncryptionKeys.map((e) => results.get(e.id));
|
|
425
468
|
});
|
|
426
469
|
}
|
|
427
470
|
ensureEncryptionKeysInitialised(entity, entityType) {
|
|
428
471
|
var _a, _b, _c;
|
|
429
472
|
return __awaiter(this, void 0, void 0, function* () {
|
|
430
|
-
if (this.
|
|
473
|
+
if (this.securityMetadataDecryptor.hasAnyEncryptionKeys(entity))
|
|
431
474
|
return undefined;
|
|
432
475
|
if (!entity.rev) {
|
|
433
476
|
throw new Error('New encrypted entity is lacking encryption metadata. ' +
|
|
@@ -445,27 +488,24 @@ class ExtendedApisUtilsImpl {
|
|
|
445
488
|
return yield this.secureDelegationsManager.entityWithInitialisedEncryptedMetadata(Object.assign(Object.assign({}, entity), { secretForeignKeys: (_c = entity.secretForeignKeys) !== null && _c !== void 0 ? _c : [] }), entityType, [], [], [yield this.primitives.AES.generateCryptoKey(true)], usersWithAccessToNewKey);
|
|
446
489
|
});
|
|
447
490
|
}
|
|
448
|
-
decryptHierarchy(
|
|
491
|
+
decryptHierarchy(decryptedDataProvider) {
|
|
449
492
|
return __awaiter(this, void 0, void 0, function* () {
|
|
450
493
|
const canDecryptOwnerIds = this.useParentKeys
|
|
451
494
|
? yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds()
|
|
452
495
|
: [yield this.dataOwnerApi.getCurrentDataOwnerId()];
|
|
453
|
-
|
|
454
|
-
return canDecryptOwnerIds.map((ownerId) => {
|
|
455
|
-
const extracted = this.deduplicate(decryptedData.filter((x) => x.dataOwnersWithAccess.some((o) => o === ownerId)).map((x) => x.decrypted));
|
|
456
|
-
return { ownerId, extracted };
|
|
457
|
-
});
|
|
496
|
+
return yield decryptedDataProvider(canDecryptOwnerIds);
|
|
458
497
|
});
|
|
459
498
|
}
|
|
460
|
-
decryptAndMergeHierarchy(
|
|
499
|
+
decryptAndMergeHierarchy(dataOwnerId, decryptedDataProvider) {
|
|
461
500
|
return __awaiter(this, void 0, void 0, function* () {
|
|
462
501
|
const hierarchy = this.useParentKeys
|
|
463
502
|
? dataOwnerId
|
|
464
503
|
? yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIdsFrom(dataOwnerId)
|
|
465
504
|
: yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds()
|
|
466
505
|
: [dataOwnerId !== null && dataOwnerId !== void 0 ? dataOwnerId : (yield this.dataOwnerApi.getCurrentDataOwnerId())];
|
|
467
|
-
const decryptedData = yield (
|
|
468
|
-
|
|
506
|
+
const decryptedData = yield decryptedDataProvider(hierarchy);
|
|
507
|
+
const merged = decryptedData.flatMap((x) => x.extracted);
|
|
508
|
+
return this.deduplicate(merged);
|
|
469
509
|
});
|
|
470
510
|
}
|
|
471
511
|
tryImportKey(key) {
|
|
@@ -481,42 +521,81 @@ class ExtendedApisUtilsImpl {
|
|
|
481
521
|
}
|
|
482
522
|
});
|
|
483
523
|
}
|
|
484
|
-
|
|
524
|
+
doIncrementallyDecryptingKeys(entity, entityType, action) {
|
|
485
525
|
return __awaiter(this, void 0, void 0, function* () {
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
if (imported)
|
|
493
|
-
res.push({ key: imported, raw: key });
|
|
526
|
+
const res = yield this.doManyIncrementallyDecryptingKeys([entity], entityType, (e, t, ks) => action(e, t, ks));
|
|
527
|
+
if (res.has(entity.id)) {
|
|
528
|
+
return { success: res.get(entity.id) };
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
return null;
|
|
494
532
|
}
|
|
495
|
-
return res;
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
|
-
decryptAndImportAnyEncryptionKey(entity) {
|
|
499
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
500
|
-
const res = yield this.tryImportFirstValidKey(entity);
|
|
501
|
-
if (!res)
|
|
502
|
-
throw new Error(`Could not find any valid key for entity ${entity.entity.id} (${entity.type}).`);
|
|
503
|
-
return res;
|
|
504
533
|
});
|
|
505
534
|
}
|
|
506
|
-
|
|
535
|
+
doManyIncrementallyDecryptingKeys(entities, entitiesType, action) {
|
|
507
536
|
return __awaiter(this, void 0, void 0, function* () {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
537
|
+
if (entities.length == 0)
|
|
538
|
+
return new Map();
|
|
539
|
+
if (new Set(entities.map((e) => e.id)).size != entities.length) {
|
|
540
|
+
throw new Error(`Duplicate entries in entities ${entities.map((x) => x.id)}`);
|
|
541
|
+
}
|
|
542
|
+
const hierarchy = yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds();
|
|
543
|
+
const allExtractedKeysForEntities = Object.fromEntries(entities.map((x) => [x.id, new Set()]));
|
|
544
|
+
const newlyExtractedKeysForEntities = Object.fromEntries(entities.map((x) => [x.id, new Set()]));
|
|
545
|
+
const results = new Map();
|
|
546
|
+
const remainingEntitiesById = Object.fromEntries(entities.map((x) => [x.id, x]));
|
|
547
|
+
const importedKeysByRaw = new Map();
|
|
548
|
+
const primitives = this.primitives;
|
|
549
|
+
function updateExtractedKeysAndDoActionIfNecessary(newKeys, forceUpdateOnEntitiesWithNewExtractedKeys) {
|
|
550
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
551
|
+
for (const [entityId, keys] of Object.entries(newKeys)) {
|
|
552
|
+
const newlyExtractedSet = newlyExtractedKeysForEntities[entityId];
|
|
553
|
+
const alreadyExtractedSet = allExtractedKeysForEntities[entityId];
|
|
554
|
+
for (const k of keys) {
|
|
555
|
+
if (!alreadyExtractedSet.has(k)) {
|
|
556
|
+
newlyExtractedSet.add(k);
|
|
557
|
+
if (!importedKeysByRaw.has(k)) {
|
|
558
|
+
importedKeysByRaw.set(k, yield primitives.AES.importKey('raw', (0, utils_1.hex2ua)(k)));
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (forceUpdateOnEntitiesWithNewExtractedKeys ||
|
|
564
|
+
Object.keys(remainingEntitiesById).every((eId) => newlyExtractedKeysForEntities[eId].size > 0)) {
|
|
565
|
+
for (const entity of Object.values(remainingEntitiesById)) {
|
|
566
|
+
const currId = entity.id;
|
|
567
|
+
const currNewlyExtracted = newlyExtractedKeysForEntities[currId];
|
|
568
|
+
if (currNewlyExtracted.size > 0) {
|
|
569
|
+
const currAllExtracted = allExtractedKeysForEntities[currId];
|
|
570
|
+
currNewlyExtracted.forEach((k) => currAllExtracted.add(k));
|
|
571
|
+
currNewlyExtracted.clear();
|
|
572
|
+
const actionResult = yield action(entity, entitiesType, [...currAllExtracted].map((raw) => ({
|
|
573
|
+
raw: raw,
|
|
574
|
+
key: importedKeysByRaw.get(raw),
|
|
575
|
+
})));
|
|
576
|
+
if (actionResult != null) {
|
|
577
|
+
delete remainingEntitiesById[currId];
|
|
578
|
+
results.set(currId, actionResult.success);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
});
|
|
518
584
|
}
|
|
519
|
-
|
|
585
|
+
yield updateExtractedKeysAndDoActionIfNecessary(yield this.securityMetadataDecryptor.decryptLegacyDelegations(Object.values(remainingEntitiesById), hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.EncryptionKey), false);
|
|
586
|
+
if (Object.keys(remainingEntitiesById).length == 0)
|
|
587
|
+
return results;
|
|
588
|
+
yield updateExtractedKeysAndDoActionIfNecessary(yield this.securityMetadataDecryptor.decryptSecureDelegationsUsingCache(Object.values(remainingEntitiesById), hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.EncryptionKey), false);
|
|
589
|
+
if (Object.keys(remainingEntitiesById).length == 0)
|
|
590
|
+
return results;
|
|
591
|
+
yield updateExtractedKeysAndDoActionIfNecessary(yield this.securityMetadataDecryptor.decryptSecureDelegationsUsingKnownExchangeData(Object.values(remainingEntitiesById), hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.EncryptionKey), false);
|
|
592
|
+
if (Object.keys(remainingEntitiesById).length == 0)
|
|
593
|
+
return results;
|
|
594
|
+
yield updateExtractedKeysAndDoActionIfNecessary(yield this.securityMetadataDecryptor.decryptSecureDelegationsUsingExchangeDataMap(Object.values(remainingEntitiesById), hierarchy, SecurityMetadataDecryptor_1.SecurityMetadataType.EncryptionKey), false);
|
|
595
|
+
if (Object.keys(remainingEntitiesById).length == 0)
|
|
596
|
+
return results;
|
|
597
|
+
yield updateExtractedKeysAndDoActionIfNecessary({}, true);
|
|
598
|
+
return results;
|
|
520
599
|
});
|
|
521
600
|
}
|
|
522
601
|
deduplicate(values) {
|