@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.
Files changed (131) hide show
  1. package/icc-api/api/internal/IccExchangeDataApi.d.ts +2 -0
  2. package/icc-api/api/internal/IccExchangeDataApi.js +10 -0
  3. package/icc-api/api/internal/IccExchangeDataApi.js.map +1 -1
  4. package/icc-api/iccApi.d.ts +0 -1
  5. package/icc-api/iccApi.js +0 -1
  6. package/icc-api/iccApi.js.map +1 -1
  7. package/icc-api/index.d.ts +0 -1
  8. package/icc-api/index.js +0 -1
  9. package/icc-api/index.js.map +1 -1
  10. package/icc-x-api/crypto/AccessControlSecretUtils.d.ts +4 -13
  11. package/icc-x-api/crypto/AccessControlSecretUtils.js +19 -29
  12. package/icc-x-api/crypto/AccessControlSecretUtils.js.map +1 -1
  13. package/icc-x-api/crypto/BaseExchangeDataManager.d.ts +8 -3
  14. package/icc-x-api/crypto/BaseExchangeDataManager.js +45 -10
  15. package/icc-x-api/crypto/BaseExchangeDataManager.js.map +1 -1
  16. package/icc-x-api/crypto/BaseExchangeKeysManager.d.ts +2 -3
  17. package/icc-x-api/crypto/BaseExchangeKeysManager.js +17 -20
  18. package/icc-x-api/crypto/BaseExchangeKeysManager.js.map +1 -1
  19. package/icc-x-api/crypto/CryptoPrimitives.d.ts +2 -0
  20. package/icc-x-api/crypto/CryptoPrimitives.js +3 -0
  21. package/icc-x-api/crypto/CryptoPrimitives.js.map +1 -1
  22. package/icc-x-api/crypto/DelegationsDeAnonymization.d.ts +3 -3
  23. package/icc-x-api/crypto/DelegationsDeAnonymization.js +7 -7
  24. package/icc-x-api/crypto/DelegationsDeAnonymization.js.map +1 -1
  25. package/icc-x-api/crypto/ExchangeDataManager.d.ts +19 -29
  26. package/icc-x-api/crypto/ExchangeDataManager.js +200 -225
  27. package/icc-x-api/crypto/ExchangeDataManager.js.map +1 -1
  28. package/icc-x-api/crypto/ExchangeDataMapManager.js +6 -4
  29. package/icc-x-api/crypto/ExchangeDataMapManager.js.map +1 -1
  30. package/icc-x-api/crypto/ExchangeKeysManager.d.ts +4 -16
  31. package/icc-x-api/crypto/ExchangeKeysManager.js +44 -41
  32. package/icc-x-api/crypto/ExchangeKeysManager.js.map +1 -1
  33. package/icc-x-api/crypto/ExtendedApisUtils.d.ts +47 -25
  34. package/icc-x-api/crypto/ExtendedApisUtils.js.map +1 -1
  35. package/icc-x-api/crypto/ExtendedApisUtilsImpl.d.ts +19 -18
  36. package/icc-x-api/crypto/ExtendedApisUtilsImpl.js +213 -134
  37. package/icc-x-api/crypto/ExtendedApisUtilsImpl.js.map +1 -1
  38. package/icc-x-api/crypto/HMACUtils.d.ts +2 -2
  39. package/icc-x-api/crypto/HMACUtils.js +3 -4
  40. package/icc-x-api/crypto/HMACUtils.js.map +1 -1
  41. package/icc-x-api/crypto/NativeCryptoPrimitivesBridge.d.ts +1 -0
  42. package/icc-x-api/crypto/NativeCryptoPrimitivesBridge.js +5 -0
  43. package/icc-x-api/crypto/NativeCryptoPrimitivesBridge.js.map +1 -1
  44. package/icc-x-api/crypto/SecureDelegationsManager.d.ts +0 -1
  45. package/icc-x-api/crypto/SecureDelegationsManager.js +17 -49
  46. package/icc-x-api/crypto/SecureDelegationsManager.js.map +1 -1
  47. package/icc-x-api/crypto/SecurityMetadataDecryptor.d.ts +59 -90
  48. package/icc-x-api/crypto/SecurityMetadataDecryptor.js +470 -56
  49. package/icc-x-api/crypto/SecurityMetadataDecryptor.js.map +1 -1
  50. package/icc-x-api/crypto/ShamirKeysManager.js +1 -1
  51. package/icc-x-api/crypto/ShamirKeysManager.js.map +1 -1
  52. package/icc-x-api/crypto/TransferKeysManager.d.ts +1 -3
  53. package/icc-x-api/crypto/TransferKeysManager.js +2 -4
  54. package/icc-x-api/crypto/TransferKeysManager.js.map +1 -1
  55. package/icc-x-api/icc-accesslog-x-api.d.ts +2 -2
  56. package/icc-x-api/icc-accesslog-x-api.js +7 -3
  57. package/icc-x-api/icc-accesslog-x-api.js.map +1 -1
  58. package/icc-x-api/icc-calendar-item-x-api.js +4 -2
  59. package/icc-x-api/icc-calendar-item-x-api.js.map +1 -1
  60. package/icc-x-api/icc-contact-x-api.d.ts +0 -1
  61. package/icc-x-api/icc-contact-x-api.js +33 -48
  62. package/icc-x-api/icc-contact-x-api.js.map +1 -1
  63. package/icc-x-api/icc-crypto-x-api.js +1 -1
  64. package/icc-x-api/icc-crypto-x-api.js.map +1 -1
  65. package/icc-x-api/icc-document-x-api.d.ts +2 -2
  66. package/icc-x-api/icc-document-x-api.js +45 -42
  67. package/icc-x-api/icc-document-x-api.js.map +1 -1
  68. package/icc-x-api/icc-form-x-api.js +3 -1
  69. package/icc-x-api/icc-form-x-api.js.map +1 -1
  70. package/icc-x-api/icc-helement-x-api.js +4 -4
  71. package/icc-x-api/icc-helement-x-api.js.map +1 -1
  72. package/icc-x-api/icc-maintenance-task-x-api.js +4 -2
  73. package/icc-x-api/icc-maintenance-task-x-api.js.map +1 -1
  74. package/icc-x-api/icc-message-x-api.js +4 -2
  75. package/icc-x-api/icc-message-x-api.js.map +1 -1
  76. package/icc-x-api/icc-patient-x-api.js +5 -7
  77. package/icc-x-api/icc-patient-x-api.js.map +1 -1
  78. package/icc-x-api/icc-topic-x-api.js +2 -2
  79. package/icc-x-api/icc-topic-x-api.js.map +1 -1
  80. package/icc-x-api/index.d.ts +6 -2
  81. package/icc-x-api/index.js +16 -20
  82. package/icc-x-api/index.js.map +1 -1
  83. package/icc-x-api/utils/crypto-utils.d.ts +6 -4
  84. package/icc-x-api/utils/crypto-utils.js +27 -6
  85. package/icc-x-api/utils/crypto-utils.js.map +1 -1
  86. package/icc-x-api/utils/simple-lru-cache.d.ts +19 -0
  87. package/icc-x-api/utils/simple-lru-cache.js +90 -0
  88. package/icc-x-api/utils/simple-lru-cache.js.map +1 -0
  89. package/package.json +4 -2
  90. package/test/icc-x-api/crud/entities-crud-test-interface.js +0 -8
  91. package/test/icc-x-api/crud/entities-crud-test-interface.js.map +1 -1
  92. package/test/icc-x-api/crypto/exchange-data-manager-test.js +75 -93
  93. package/test/icc-x-api/crypto/exchange-data-manager-test.js.map +1 -1
  94. package/test/icc-x-api/crypto/legacy-metadata-migration-test.js.map +1 -1
  95. package/test/icc-x-api/crypto/secure-delegations-manager-test.js +28 -16
  96. package/test/icc-x-api/crypto/secure-delegations-manager-test.js.map +1 -1
  97. package/test/utils/FakeEncryptionKeysManager.d.ts +1 -0
  98. package/test/utils/FakeEncryptionKeysManager.js +11 -0
  99. package/test/utils/FakeEncryptionKeysManager.js.map +1 -1
  100. package/test/utils/FakeExchangeDataApi.d.ts +4 -2
  101. package/test/utils/FakeExchangeDataApi.js +24 -6
  102. package/test/utils/FakeExchangeDataApi.js.map +1 -1
  103. package/test/utils/FakeExchangeDataManager.d.ts +10 -10
  104. package/test/utils/FakeExchangeDataManager.js +12 -22
  105. package/test/utils/FakeExchangeDataManager.js.map +1 -1
  106. package/test/utils/TestApi.js +1 -0
  107. package/test/utils/TestApi.js.map +1 -1
  108. package/icc-api/api/IccArticleApi.d.ts +0 -72
  109. package/icc-api/api/IccArticleApi.js +0 -149
  110. package/icc-api/api/IccArticleApi.js.map +0 -1
  111. package/icc-x-api/crypto/LegacyDelegationSecurityMetadataDecryptor.d.ts +0 -33
  112. package/icc-x-api/crypto/LegacyDelegationSecurityMetadataDecryptor.js +0 -141
  113. package/icc-x-api/crypto/LegacyDelegationSecurityMetadataDecryptor.js.map +0 -1
  114. package/icc-x-api/crypto/SecureDelegationsSecurityMetadataDecryptor.d.ts +0 -46
  115. package/icc-x-api/crypto/SecureDelegationsSecurityMetadataDecryptor.js +0 -312
  116. package/icc-x-api/crypto/SecureDelegationsSecurityMetadataDecryptor.js.map +0 -1
  117. package/icc-x-api/crypto/UserSignatureKeysManager.d.ts +0 -26
  118. package/icc-x-api/crypto/UserSignatureKeysManager.js +0 -78
  119. package/icc-x-api/crypto/UserSignatureKeysManager.js.map +0 -1
  120. package/test/icc-x-api/crypto/secure-delegations-metadata-decryptor-test.d.ts +0 -1
  121. package/test/icc-x-api/crypto/secure-delegations-metadata-decryptor-test.js +0 -393
  122. package/test/icc-x-api/crypto/secure-delegations-metadata-decryptor-test.js.map +0 -1
  123. package/test/icc-x-api/crypto/security-metadata-decryptor-chain-test.d.ts +0 -1
  124. package/test/icc-x-api/crypto/security-metadata-decryptor-chain-test.js +0 -213
  125. package/test/icc-x-api/crypto/security-metadata-decryptor-chain-test.js.map +0 -1
  126. package/test/icc-x-api/crypto/signature-keys-manager-test.d.ts +0 -1
  127. package/test/icc-x-api/crypto/signature-keys-manager-test.js +0 -44
  128. package/test/icc-x-api/crypto/signature-keys-manager-test.js.map +0 -1
  129. package/test/utils/FakeSignatureKeysManager.d.ts +0 -16
  130. package/test/utils/FakeSignatureKeysManager.js +0 -54
  131. 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, legacyDelMetadataDecryptor, secDelMetadataDecryptor, secureDelegationsManager, userApi, useParentKeys) {
28
+ constructor(primitives, dataOwnerApi, securityMetadataDecryptor, secureDelegationsManager, userApi, useParentKeys) {
30
29
  this.primitives = primitives;
31
30
  this.dataOwnerApi = dataOwnerApi;
32
- this.legacyDelMetadataDecryptor = legacyDelMetadataDecryptor;
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(entity, dataOwnerId, (entityWithType, hierarchy) => this.allSecurityMetadataDecryptor.decryptEncryptionKeysOf(entityWithType, hierarchy));
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(entity, (entityWithType, hierarchy) => this.allSecurityMetadataDecryptor.decryptEncryptionKeysOf(entityWithType, hierarchy));
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(entity, dataOwnerId, (entityWithType, hierarchy) => this.allSecurityMetadataDecryptor.decryptSecretIdsOf(entityWithType, hierarchy));
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(entity, (entityWithType, hierarchy) => this.allSecurityMetadataDecryptor.decryptSecretIdsOf(entityWithType, hierarchy));
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(entity, dataOwnerId, (entityWithType, hierarchy) => this.allSecurityMetadataDecryptor.decryptOwningEntityIdsOf(entityWithType, hierarchy));
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(entity, (entityWithType, hierarchy) => this.allSecurityMetadataDecryptor.decryptOwningEntityIdsOf(entityWithType, hierarchy));
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.allSecurityMetadataDecryptor.getEntityAccessLevel(entity, yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds())) ===
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.secDelMetadataDecryptor.getDelegationMemberDetails(entityWithType);
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 (0, collection_utils_1.asyncGeneratorToArray)(this.legacyDelMetadataDecryptor.decryptSecretIdsOf(entity, hierarchy));
255
- const legacyEncryptionKeys = yield (0, collection_utils_1.asyncGeneratorToArray)(this.legacyDelMetadataDecryptor.decryptEncryptionKeysOf(entity, hierarchy));
256
- const legacyOwningEntityIds = yield (0, collection_utils_1.asyncGeneratorToArray)(this.legacyDelMetadataDecryptor.decryptOwningEntityIdsOf(entity, hierarchy));
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.legacyDelMetadataDecryptor.getEntityAccessLevel(entity, subHierarchy);
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 (0, collection_utils_1.asyncGeneratorToArray)(this.secDelMetadataDecryptor.decryptSecretIdsOf(entity, [currMemberId]))).map((x) => x.decrypted));
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 (0, collection_utils_1.asyncGeneratorToArray)(this.secDelMetadataDecryptor.decryptEncryptionKeysOf(entity, [currMemberId]))).map((x) => x.decrypted));
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 (0, collection_utils_1.asyncGeneratorToArray)(this.secDelMetadataDecryptor.decryptOwningEntityIdsOf(entity, [currMemberId]))).map((x) => x.decrypted));
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 && currMemberId === selfId && !(yield this.secDelMetadataDecryptor.getEntityAccessLevel(entity, subHierarchy));
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
- let latest = yield decryptedKeys.next();
324
- while (!latest.done) {
325
- if (!triedKeys.has(latest.value.decrypted)) {
326
- triedKeys.add(latest.value.decrypted);
327
- try {
328
- const decrypted = yield this.primitives.AES.decryptWithRawKey(latest.value.decrypted, content);
329
- if (!validator || (yield validator(decrypted)))
330
- return { data: decrypted, wasDecrypted: true };
331
- }
332
- catch (e) {
333
- console.warn(`Error while decrypting with raw key ${latest.value}: ${e}`);
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
- latest = yield decryptedKeys.next();
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 dataOwnerIds = this.useParentKeys
349
- ? yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds()
350
- : [yield this.dataOwnerApi.getCurrentDataOwnerId()];
351
- const decryptedKeys = this.allSecurityMetadataDecryptor.decryptEncryptionKeysOf({ entity: updatedEntity !== null && updatedEntity !== void 0 ? updatedEntity : entity, type }, dataOwnerIds);
352
- let latest = yield decryptedKeys.next();
353
- while (!latest.done) {
354
- try {
355
- return { encryptedData: yield this.primitives.AES.encryptWithRawKey(latest.value.decrypted, content), updatedEntity: updatedEntity };
356
- }
357
- catch (e) {
358
- console.warn(`Error while encrypting with raw key ${latest.value}: ${e}`);
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
- latest = yield decryptedKeys.next();
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
- decryptEntity(entity, entityType, constructor) {
370
+ tryDecryptEntities(entities, entityType, constructor) {
371
+ var _a;
366
372
  return __awaiter(this, void 0, void 0, function* () {
367
- if (!entity.encryptedSelf)
368
- return { entity, decrypted: true };
369
- const encryptionKeys = yield this.decryptAndImportAllDecryptionKeys({ entity: entity, type: entityType });
370
- if (!encryptionKeys.length)
371
- return { entity, decrypted: false };
372
- return {
373
- entity: constructor(yield (0, utils_1.decryptObject)(entity, (encrypted) => __awaiter(this, void 0, void 0, function* () {
374
- var _a;
375
- return (_a = (yield this.tryDecryptJson(encryptionKeys, encrypted, false))) !== null && _a !== void 0 ? _a : {};
376
- }))),
377
- decrypted: true,
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 = (_a = (yield this.primitives.AES.decrypt(key.key, encrypted, key.raw))) !== null && _a !== void 0 ? _a : encrypted;
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 undefined;
416
+ return null;
392
417
  });
393
418
  }
394
- tryEncryptEntity(entity, entityType, fieldsToEncrypt, encodeBinaryData, requireEncryption, constructor) {
419
+ tryEncryptEntities(entities, entityType, fieldsToEncrypt, encodeBinaryData, requireEncryption, constructor) {
420
+ var _a;
395
421
  return __awaiter(this, void 0, void 0, function* () {
396
- const entityWithInitialisedEncryptionKeys = yield this.ensureEncryptionKeysInitialised(entity, entityType);
397
- const updatedEntity = entityWithInitialisedEncryptionKeys ? entityWithInitialisedEncryptionKeys : entity;
398
- const encryptionKey = yield this.tryImportFirstValidKey({ entity, type: entityType });
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
- else if (requireEncryption) {
413
- throw new Error(`No key found for encryption of entity ${entity}`);
414
- }
415
- else {
416
- yield (0, utils_1.encryptObject)(entity, (obj) => __awaiter(this, void 0, void 0, function* () {
417
- const hasNonEmptyValues = Object.values(obj).some((v) => v !== undefined && (typeof v !== 'object' || (Array.isArray(v) && v.length > 0) || Object.keys(v).length > 0));
418
- if (hasNonEmptyValues) {
419
- throw new Error(`Impossible to modify encrypted content of an entity if no encryption key is known.\nEntity: ${JSON.stringify(entity)}\nTo encrypt: ${JSON.stringify(obj)}`);
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
- return Promise.resolve(new ArrayBuffer(1));
422
- }), fieldsToEncrypt, 'entity');
423
- return entity;
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.allSecurityMetadataDecryptor.hasAnyEncryptionKeys(entity))
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(entity, decryptedDataGeneratorProvider) {
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
- const decryptedData = yield (0, collection_utils_1.asyncGeneratorToArray)(decryptedDataGeneratorProvider(entity, canDecryptOwnerIds));
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(entity, dataOwnerId, decryptedDataGeneratorProvider) {
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 (0, collection_utils_1.asyncGeneratorToArray)(decryptedDataGeneratorProvider(entity, hierarchy));
468
- return this.deduplicate(decryptedData.map((x) => x.decrypted));
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
- decryptAndImportAllDecryptionKeys(entity) {
524
+ doIncrementallyDecryptingKeys(entity, entityType, action) {
485
525
  return __awaiter(this, void 0, void 0, function* () {
486
- const keys = this.allSecurityMetadataDecryptor.hasAnyEncryptionKeys(entity.entity)
487
- ? yield this.encryptionKeysOf(entity)
488
- : this.deduplicate(yield (0, collection_utils_1.asyncGeneratorToArray)(this.legacyDelMetadataDecryptor.decryptSecretIdsOf(entity, yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds())).then((secretIdsInfo) => secretIdsInfo.map(({ decrypted }) => decrypted)));
489
- const res = [];
490
- for (const key of keys) {
491
- const imported = yield this.tryImportKey(key);
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
- tryImportFirstValidKey(entity) {
535
+ doManyIncrementallyDecryptingKeys(entities, entitiesType, action) {
507
536
  return __awaiter(this, void 0, void 0, function* () {
508
- const dataOwnerIds = this.useParentKeys
509
- ? yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds()
510
- : [yield this.dataOwnerApi.getCurrentDataOwnerId()];
511
- const generator = this.allSecurityMetadataDecryptor.decryptEncryptionKeysOf(entity, dataOwnerIds);
512
- let latest = yield generator.next();
513
- while (!latest.done) {
514
- const imported = yield this.tryImportKey(latest.value.decrypted);
515
- if (imported)
516
- return { key: imported, raw: latest.value.decrypted };
517
- latest = yield generator.next();
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
- return undefined;
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) {