@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
@@ -12,33 +12,32 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.initialiseExchangeDataManagerForCurrentDataOwner = void 0;
13
13
  const utils_1 = require("./utils");
14
14
  const utils_2 = require("../utils");
15
- const lru_temporised_async_cache_1 = require("../utils/lru-temporised-async-cache");
16
- const EntityWithDelegationTypeName_1 = require("../utils/EntityWithDelegationTypeName");
17
15
  const CryptoActorStub_1 = require("../../icc-api/model/CryptoActorStub");
18
16
  const RSA_1 = require("./RSA");
17
+ const async_mutex_1 = require("async-mutex");
18
+ const simple_lru_cache_1 = require("../utils/simple-lru-cache");
19
19
  /**
20
20
  * @internal this function is for internal use only and may be changed without notice.
21
21
  * Initialises and returns the exchange data manager which is most appropriate for the current data owner.
22
22
  */
23
- function initialiseExchangeDataManagerForCurrentDataOwner(base, encryptionKeys, signatureKeys, accessControlSecret, cryptoStrategies, dataOwnerApi, primitives, useParentKeys, optionalParameters = {}) {
23
+ function initialiseExchangeDataManagerForCurrentDataOwner(base, encryptionKeys, accessControlSecret, cryptoStrategies, dataOwnerApi, primitives, useParentKeys, optionalParameters = {}) {
24
24
  return __awaiter(this, void 0, void 0, function* () {
25
25
  const currentOwner = CryptoActorStub_1.CryptoActorStubWithType.fromDataOwner(yield dataOwnerApi.getCurrentDataOwner());
26
26
  if (cryptoStrategies.dataOwnerRequiresAnonymousDelegation(currentOwner)) {
27
- const res = new FullyCachedExchangeDataManager(base, encryptionKeys, signatureKeys, accessControlSecret, cryptoStrategies, dataOwnerApi, primitives, useParentKeys);
27
+ const res = new FullyCachedExchangeDataManager(base, encryptionKeys, accessControlSecret, cryptoStrategies, dataOwnerApi, primitives, useParentKeys);
28
28
  yield res.clearOrRepopulateCache();
29
29
  return res;
30
30
  }
31
31
  else {
32
- return new LimitedLruCacheExchangeDataManager(base, encryptionKeys, signatureKeys, accessControlSecret, cryptoStrategies, dataOwnerApi, primitives, useParentKeys, optionalParameters);
32
+ return new LimitedLruCacheExchangeDataManager(base, encryptionKeys, accessControlSecret, cryptoStrategies, dataOwnerApi, primitives, useParentKeys, optionalParameters);
33
33
  }
34
34
  });
35
35
  }
36
36
  exports.initialiseExchangeDataManagerForCurrentDataOwner = initialiseExchangeDataManagerForCurrentDataOwner;
37
37
  class AbstractExchangeDataManager {
38
- constructor(base, encryptionKeys, signatureKeys, accessControlSecret, cryptoStrategies, dataOwnerApi, primitives, useParentKeys) {
38
+ constructor(base, encryptionKeys, accessControlSecret, cryptoStrategies, dataOwnerApi, primitives, useParentKeys) {
39
39
  this.base = base;
40
40
  this.encryptionKeys = encryptionKeys;
41
- this.signatureKeys = signatureKeys;
42
41
  this.accessControlSecret = accessControlSecret;
43
42
  this.cryptoStrategies = cryptoStrategies;
44
43
  this.dataOwnerApi = dataOwnerApi;
@@ -48,6 +47,7 @@ class AbstractExchangeDataManager {
48
47
  decryptData(data) {
49
48
  return __awaiter(this, void 0, void 0, function* () {
50
49
  const decryptionKeys = this.encryptionKeys.getDecryptionKeys();
50
+ const encryptionKeys = Object.fromEntries(this.encryptionKeys.getSelfVerifiedKeys().map((x) => [x.fingerprint, x.pair.privateKey]));
51
51
  const decryptedExchangeKey = (yield this.base.tryDecryptExchangeKeys([data], decryptionKeys)).successfulDecryptions[0];
52
52
  if (!decryptedExchangeKey)
53
53
  return undefined;
@@ -65,14 +65,15 @@ class AbstractExchangeDataManager {
65
65
  decryptedAccessControlSecret,
66
66
  decryptedExchangeKey,
67
67
  decryptedSharedSignatureKey,
68
- }, (fp) => this.signatureKeys.getSignatureVerificationKey(fp), true),
68
+ }, encryptionKeys, true),
69
69
  };
70
70
  });
71
71
  }
72
72
  createNewExchangeData(delegateId, options) {
73
73
  return __awaiter(this, void 0, void 0, function* () {
74
74
  const encryptionKeys = {};
75
- this.encryptionKeys.getSelfVerifiedKeys().forEach(({ fingerprint, pair }) => {
75
+ const selfVerifiedKeys = this.encryptionKeys.getSelfVerifiedKeys();
76
+ selfVerifiedKeys.forEach(({ fingerprint, pair }) => {
76
77
  encryptionKeys[fingerprint] = pair.publicKey;
77
78
  });
78
79
  if (delegateId != (yield this.dataOwnerApi.getCurrentDataOwnerId())) {
@@ -104,8 +105,7 @@ class AbstractExchangeDataManager {
104
105
  throw new Error('Illegal state: verified keys should contain only keys for OAPE-SHA1 or OAPE-SHA256.');
105
106
  }
106
107
  }
107
- const signatureKey = yield this.signatureKeys.getOrCreateSignatureKeyPair();
108
- const newData = yield this.base.createExchangeData(delegateId, { [signatureKey.fingerprint]: signatureKey.keyPair.privateKey }, encryptionKeys, options.newDataId ? { id: options.newDataId } : {});
108
+ const newData = yield this.base.createExchangeData(delegateId, Object.fromEntries(selfVerifiedKeys.map((x) => [x.fingerprint, x.pair.privateKey])), encryptionKeys, options.newDataId ? { id: options.newDataId } : {});
109
109
  return {
110
110
  exchangeData: newData.exchangeData,
111
111
  accessControlSecret: newData.accessControlSecret,
@@ -122,7 +122,6 @@ class AbstractExchangeDataManager {
122
122
  if (!newKeyHashVersion)
123
123
  throw new Error(`Public key not found for data owner ${otherDataOwner}`);
124
124
  const importedNewKey = yield this.primitives.RSA.importKey('spki', (0, utils_2.hex2ua)(newDataOwnerPublicKey), ['encrypt'], newKeyHashVersion);
125
- const signatureKey = yield this.signatureKeys.getOrCreateSignatureKeyPair();
126
125
  const decryptionKeys = this.encryptionKeys.getDecryptionKeys();
127
126
  const allExchangeDataToUpdate = self == otherDataOwner
128
127
  ? yield this.base.getExchangeDataByDelegatorDelegatePair(self, self)
@@ -143,13 +142,13 @@ class AbstractExchangeDataManager {
143
142
  clearOrRepopulateCache() {
144
143
  throw new Error('Implemented by concrete class');
145
144
  }
146
- getOrCreateEncryptionDataTo(delegateId, entityType, entitySecretForeignKeys, allowCreationWithoutDelegateKey) {
145
+ getOrCreateEncryptionDataTo(delegateId, allowCreationWithoutDelegateKey) {
147
146
  throw new Error('Implemented by concrete class');
148
147
  }
149
- getCachedDecryptionDataKeyByAccessControlHash(hashes, entityType, entitySecretForeignKeys) {
148
+ getCachedDecryptionDataKeyByAccessControlHash(hashes) {
150
149
  throw new Error('Implemented by concrete class');
151
150
  }
152
- getDecryptionDataKeyById(id, entityType, entitySecretForeignKeys, retrieveIfNotCached) {
151
+ getDecryptionDataKeyByIds(ids, retrieveIfNotCached) {
153
152
  throw new Error('Implemented by concrete class');
154
153
  }
155
154
  getAccessControlKeysValue(entityType) {
@@ -162,7 +161,8 @@ class AbstractExchangeDataManager {
162
161
  class FullyCachedExchangeDataManager extends AbstractExchangeDataManager {
163
162
  constructor() {
164
163
  super(...arguments);
165
- this.caches = Promise.resolve({ dataById: {}, hashToId: new Map(), delegateToVerifiedEncryptionDataId: {}, entityTypeToAccessControlKeysValue: {} });
164
+ this.caches = Promise.resolve({ dataById: {}, hashToId: {}, delegateToVerifiedEncryptionDataId: {}, entityTypeToAccessControlKeysValue: {} });
165
+ this.createExchangeDataMutex = new async_mutex_1.Mutex();
166
166
  }
167
167
  clearOrRepopulateCache() {
168
168
  return __awaiter(this, void 0, void 0, function* () {
@@ -170,11 +170,11 @@ class FullyCachedExchangeDataManager extends AbstractExchangeDataManager {
170
170
  yield this.caches;
171
171
  });
172
172
  }
173
- getCachedDecryptionDataKeyByAccessControlHash(hashes, entityType, entitySecretForeignKeys) {
173
+ getCachedDecryptionDataKeyByAccessControlHash(hashes) {
174
174
  return __awaiter(this, void 0, void 0, function* () {
175
175
  function retrieveByHashesFromCaches(caches) {
176
176
  return hashes.reduce((res, hash) => {
177
- const id = caches.hashToId.get(hash);
177
+ const id = caches.hashToId[hash];
178
178
  if (id) {
179
179
  const cached = caches.dataById[id];
180
180
  if (cached === null || cached === void 0 ? void 0 : cached.decrypted) {
@@ -188,25 +188,10 @@ class FullyCachedExchangeDataManager extends AbstractExchangeDataManager {
188
188
  return res;
189
189
  }, {});
190
190
  }
191
- const retrievedFromHashesCache = retrieveByHashesFromCaches(yield this.caches);
192
- if (Object.keys(retrievedFromHashesCache).length) {
193
- return retrievedFromHashesCache;
194
- }
195
- else {
196
- this.caches = this.caches.then((caches) => __awaiter(this, void 0, void 0, function* () {
197
- for (const currData of Object.values(caches.dataById)) {
198
- if (currData.decrypted) {
199
- const currDataHashes = yield this.accessControlSecret.secureDelegationKeysFor(currData.decrypted.accessControlSecret, entityType, entitySecretForeignKeys);
200
- currDataHashes.forEach((hash) => caches.hashToId.set(hash, currData.exchangeData.id));
201
- }
202
- }
203
- return caches;
204
- }));
205
- return retrieveByHashesFromCaches(yield this.caches);
206
- }
191
+ return retrieveByHashesFromCaches(yield this.caches);
207
192
  });
208
193
  }
209
- getOrCreateEncryptionDataTo(delegateId, entityType, entitySecretForeignKeys, allowCreationWithoutDelegateKey) {
194
+ getCachedEncryptionDataTo(delegateId) {
210
195
  return __awaiter(this, void 0, void 0, function* () {
211
196
  const caches = yield this.caches;
212
197
  const dataId = caches.delegateToVerifiedEncryptionDataId[delegateId];
@@ -218,48 +203,60 @@ class FullyCachedExchangeDataManager extends AbstractExchangeDataManager {
218
203
  exchangeKey: cached.decrypted.exchangeKey,
219
204
  };
220
205
  }
221
- // TODO this could technically allow for 2 concurrent exchange data creations, needs fix
222
- const created = yield this.createNewExchangeData(delegateId, { allowNoDelegateKeys: allowCreationWithoutDelegateKey });
223
- this.cacheData(created.exchangeData, true, { accessControlSecret: created.accessControlSecret, exchangeKey: created.exchangeKey, verified: true }, entityType, entitySecretForeignKeys);
224
- return created;
206
+ else {
207
+ return undefined;
208
+ }
225
209
  });
226
210
  }
227
- getDecryptionDataKeyById(id, entityType, entitySecretForeignKeys, retrieveIfNotCached) {
211
+ getOrCreateEncryptionDataTo(delegateId, allowCreationWithoutDelegateKey) {
212
+ return __awaiter(this, void 0, void 0, function* () {
213
+ const initialCached = yield this.getCachedEncryptionDataTo(delegateId);
214
+ if (initialCached)
215
+ return initialCached;
216
+ const release = yield this.createExchangeDataMutex.acquire();
217
+ try {
218
+ const cachedAfterMutex = yield this.getCachedEncryptionDataTo(delegateId);
219
+ if (cachedAfterMutex)
220
+ return cachedAfterMutex;
221
+ const created = yield this.createNewExchangeData(delegateId, { allowNoDelegateKeys: allowCreationWithoutDelegateKey });
222
+ this.cacheData(created.exchangeData, true, {
223
+ accessControlSecret: created.accessControlSecret,
224
+ exchangeKey: created.exchangeKey,
225
+ verified: true,
226
+ });
227
+ return created;
228
+ }
229
+ finally {
230
+ release();
231
+ }
232
+ });
233
+ }
234
+ getDecryptionDataKeyByIds(ids, retrieveIfNotCached) {
228
235
  var _a, _b;
229
236
  return __awaiter(this, void 0, void 0, function* () {
230
237
  const caches = yield this.caches;
231
- const cachedData = caches.dataById[id];
232
- if (cachedData) {
233
- return {
234
- exchangeData: cachedData.exchangeData,
235
- exchangeKey: (_a = cachedData.decrypted) === null || _a === void 0 ? void 0 : _a.exchangeKey,
236
- accessControlSecret: (_b = cachedData.decrypted) === null || _b === void 0 ? void 0 : _b.accessControlSecret,
237
- };
238
- }
239
- else if (retrieveIfNotCached) {
240
- const data = yield this.base.getExchangeDataById(id);
241
- if (!data)
242
- throw new Error(`Could not find exchange data with id ${id}`);
243
- const decrypted = yield this.decryptData(data);
244
- this.cacheData(data, false, decrypted, entityType, entitySecretForeignKeys);
245
- return { exchangeData: data, exchangeKey: decrypted === null || decrypted === void 0 ? void 0 : decrypted.exchangeKey, accessControlSecret: decrypted === null || decrypted === void 0 ? void 0 : decrypted.accessControlSecret };
238
+ const res = {};
239
+ for (const id of ids) {
240
+ const data = caches.dataById[id];
241
+ if (data) {
242
+ res[id] = {
243
+ exchangeData: data.exchangeData,
244
+ exchangeKey: (_a = data.decrypted) === null || _a === void 0 ? void 0 : _a.exchangeKey,
245
+ accessControlSecret: (_b = data.decrypted) === null || _b === void 0 ? void 0 : _b.accessControlSecret,
246
+ };
247
+ }
246
248
  }
247
- else
248
- return undefined;
249
+ return res;
249
250
  });
250
251
  }
251
- cacheData(exchangeData, isNewData, decrypted, entityType, entitySecretForeignKeys) {
252
+ cacheData(exchangeData, isNewData, decrypted) {
252
253
  this.caches = this.caches.then((caches) => __awaiter(this, void 0, void 0, function* () {
253
254
  caches.dataById[exchangeData.id] = { exchangeData, decrypted };
254
255
  if (decrypted) {
255
- // Usage of sfks in secure delegation key should be configurable: it is not necessary for all users and it has some performance impact
256
- // `secureDelegationKeysFor` is currently ignoring the sfks
257
- if (entityType && entitySecretForeignKeys) {
258
- const hashes = yield this.accessControlSecret.secureDelegationKeysFor(decrypted.accessControlSecret, entityType, entitySecretForeignKeys);
259
- hashes.forEach((hash) => {
260
- caches.hashToId.set(hash, exchangeData.id);
261
- });
262
- }
256
+ const hashes = yield this.accessControlSecret.allSecureDelegationKeysFor(decrypted.accessControlSecret);
257
+ hashes.forEach((hash) => {
258
+ caches.hashToId[hash] = exchangeData.id;
259
+ });
263
260
  if (decrypted.verified) {
264
261
  caches.delegateToVerifiedEncryptionDataId[exchangeData.delegate] = exchangeData.id;
265
262
  }
@@ -275,7 +272,7 @@ class FullyCachedExchangeDataManager extends AbstractExchangeDataManager {
275
272
  if (!allData)
276
273
  throw new Error('Impossible to use fully cached exchange data manager for current data owner.');
277
274
  const dataById = {};
278
- const hashToId = new Map();
275
+ const hashToId = {};
279
276
  const delegateToVerifiedEncryptionDataId = {};
280
277
  for (const currData of allData) {
281
278
  const currDecrypted = yield this.decryptData(currData);
@@ -283,6 +280,11 @@ class FullyCachedExchangeDataManager extends AbstractExchangeDataManager {
283
280
  if (currDecrypted === null || currDecrypted === void 0 ? void 0 : currDecrypted.verified) {
284
281
  delegateToVerifiedEncryptionDataId[currData.delegate] = currData.id;
285
282
  }
283
+ if (currDecrypted === null || currDecrypted === void 0 ? void 0 : currDecrypted.accessControlSecret) {
284
+ for (const h of yield this.accessControlSecret.allSecureDelegationKeysFor(currDecrypted.accessControlSecret)) {
285
+ hashToId[h] = currData.id;
286
+ }
287
+ }
286
288
  }
287
289
  const entityTypeToAccessControlKeysValue = {};
288
290
  return { dataById, hashToId, delegateToVerifiedEncryptionDataId, entityTypeToAccessControlKeysValue };
@@ -307,217 +309,190 @@ class FullyCachedExchangeDataManager extends AbstractExchangeDataManager {
307
309
  const res = [];
308
310
  for (const accessControlSecret of accessControlSecrets) {
309
311
  // Usage of sfks in secure delegation key should be configurable: it is not necessary for all users and it has some performance impact
310
- res.push(yield this.accessControlSecret.secureDelegationKeyFor(accessControlSecret, entityType, undefined));
312
+ res.push(yield this.accessControlSecret.secureDelegationKeyFor(accessControlSecret, entityType));
311
313
  }
312
314
  return res;
313
315
  });
314
316
  }
315
317
  }
316
318
  class LimitedLruCacheExchangeDataManager extends AbstractExchangeDataManager {
317
- constructor(base, encryptionKeys, signatureKeys, accessControlSecret, cryptoStrategies, dataOwnerApi, primitives, useParentKeys, optionalParameters) {
319
+ constructor(base, encryptionKeys, accessControlSecret, cryptoStrategies, dataOwnerApi, primitives, useParentKeys, optionalParameters) {
318
320
  var _a;
319
- super(base, encryptionKeys, signatureKeys, accessControlSecret, cryptoStrategies, dataOwnerApi, primitives, useParentKeys);
321
+ super(base, encryptionKeys, accessControlSecret, cryptoStrategies, dataOwnerApi, primitives, useParentKeys);
322
+ this.idToData = new simple_lru_cache_1.SimpleLruCache();
320
323
  this.hashToId = new Map();
321
324
  this.delegateToVerifiedEncryptionDataId = new Map();
322
- this.idToDataCache = new lru_temporised_async_cache_1.LruTemporisedAsyncCache((_a = optionalParameters.lruCacheSize) !== null && _a !== void 0 ? _a : 2000, () => -1);
325
+ this.cacheMutex = new async_mutex_1.Mutex();
326
+ this.maxCachedExchangeData = (_a = optionalParameters.lruCacheSize) !== null && _a !== void 0 ? _a : 2000;
323
327
  }
324
328
  clearOrRepopulateCache() {
325
329
  return __awaiter(this, void 0, void 0, function* () {
326
- this.idToDataCache.clear(false);
330
+ this.idToData.clear();
327
331
  this.hashToId.clear();
328
332
  this.delegateToVerifiedEncryptionDataId.clear();
329
333
  });
330
334
  }
331
- getCachedDecryptionDataKeyByAccessControlHash(hashes, entityType, entitySecretForeignKeys) {
335
+ getCachedDecryptionDataKeyByAccessControlHash(hashes) {
332
336
  return __awaiter(this, void 0, void 0, function* () {
333
- const res = {};
334
- for (const hash of hashes) {
335
- const dataId = this.hashToId.get(hash);
336
- if (dataId) {
337
- const retrieved = yield this.idToDataCache.get(dataId, () => {
338
- throw new Error(`Data with id ${dataId} should have been already cached.`);
339
- });
340
- if (retrieved.decrypted) {
341
- res[hash] = {
342
- exchangeData: retrieved.exchangeData,
343
- exchangeKey: retrieved.decrypted.exchangeKey,
344
- accessControlSecret: retrieved.decrypted.accessControlSecret,
345
- };
337
+ const release = yield this.cacheMutex.acquire();
338
+ try {
339
+ const res = {};
340
+ for (const hash of hashes) {
341
+ const dataId = this.hashToId.get(hash);
342
+ if (dataId) {
343
+ const retrieved = this.idToData.getCached(dataId);
344
+ if (!retrieved)
345
+ throw new Error(`Data with id ${dataId} should have been already cached.`);
346
+ if (retrieved.decrypted) {
347
+ res[hash] = {
348
+ exchangeData: retrieved.exchangeData,
349
+ exchangeKey: retrieved.decrypted.exchangeKey,
350
+ accessControlSecret: retrieved.decrypted.accessControlSecret,
351
+ };
352
+ }
346
353
  }
347
354
  }
355
+ return res;
348
356
  }
349
- return res;
350
- });
351
- }
352
- secureDelegationKeysForAllEntitiesNoSfkAndSpecificEntitySfksPairs(accessControlSecret, entityType, entitySecretForeignKeys) {
353
- return __awaiter(this, void 0, void 0, function* () {
354
- const noSfkDelegationKeys = yield Promise.all([...EntityWithDelegationTypeName_1.entityWithDelegationTypeNames].map((t) => this.accessControlSecret.secureDelegationKeyFor(accessControlSecret, t, undefined)));
355
- if (entityType && (entitySecretForeignKeys === null || entitySecretForeignKeys === void 0 ? void 0 : entitySecretForeignKeys.length)) {
356
- // Usage of sfks in secure delegation key should be configurable: it is not necessary for all users and it has some performance impact
357
- // `secureDelegationKeysFor` is currently ignoring the sfks
358
- return [
359
- ...noSfkDelegationKeys,
360
- ...(yield this.accessControlSecret.secureDelegationKeysFor(accessControlSecret, entityType, entitySecretForeignKeys)),
361
- ];
362
- }
363
- else {
364
- return noSfkDelegationKeys;
357
+ finally {
358
+ release();
365
359
  }
366
360
  });
367
361
  }
368
- getDecryptionDataKeyById(id, entityType, entitySecretForeignKeys, retrieveIfNotCached) {
362
+ getDecryptionDataKeyByIds(ids, retrieveIfNotCached) {
369
363
  var _a, _b;
370
364
  return __awaiter(this, void 0, void 0, function* () {
371
- const cached = yield this.idToDataCache.getIfCachedJob(id);
372
- if (cached) {
373
- const updated = yield this.idToDataCache.get(id, (prevData) => __awaiter(this, void 0, void 0, function* () {
374
- const toUpdate = prevData !== null && prevData !== void 0 ? prevData : cached.item;
375
- if (toUpdate.decrypted) {
376
- // Usage of sfks in secure delegation key should be configurable: it is not necessary for all users, and it has some performance impact
377
- // `secureDelegationKeysFor` is currently ignoring the sfks
378
- if (entityType && entitySecretForeignKeys) {
379
- const hashes = yield this.accessControlSecret.secureDelegationKeysFor(toUpdate.decrypted.accessControlSecret, entityType, entitySecretForeignKeys);
380
- hashes.forEach((hash) => {
381
- this.hashToId.set(hash, toUpdate.exchangeData.id);
382
- });
383
- toUpdate.hashes.push(...hashes);
384
- }
365
+ const release = yield this.cacheMutex.acquire();
366
+ try {
367
+ const res = {};
368
+ const uncached = [];
369
+ for (const id of ids) {
370
+ const cached = this.idToData.getCached(id);
371
+ if (cached) {
372
+ res[id] = {
373
+ exchangeKey: (_a = cached.decrypted) === null || _a === void 0 ? void 0 : _a.exchangeKey,
374
+ accessControlSecret: (_b = cached.decrypted) === null || _b === void 0 ? void 0 : _b.accessControlSecret,
375
+ exchangeData: cached.exchangeData,
376
+ };
385
377
  }
386
- return { item: toUpdate, onEviction: (b) => this.doOnEvictionJob(b, toUpdate) };
387
- }), () => true);
388
- return {
389
- exchangeData: updated.exchangeData,
390
- exchangeKey: (_a = updated.decrypted) === null || _a === void 0 ? void 0 : _a.exchangeKey,
391
- accessControlSecret: (_b = updated.decrypted) === null || _b === void 0 ? void 0 : _b.accessControlSecret,
392
- };
393
- }
394
- else if (retrieveIfNotCached) {
395
- return yield this.idToDataCache
396
- .get(id, () => __awaiter(this, void 0, void 0, function* () {
397
- return this.cacheJob(() => __awaiter(this, void 0, void 0, function* () {
398
- const data = yield this.base.getExchangeDataById(id);
399
- if (!data)
400
- throw new Error(`Could not find exchange data with id ${id}`);
378
+ else if (retrieveIfNotCached) {
379
+ uncached.push(id);
380
+ }
381
+ }
382
+ if (uncached.length > 0) {
383
+ const retrieved = yield this.base.getExchangeDataByIds(uncached);
384
+ for (const data of retrieved) {
401
385
  const decrypted = yield this.decryptData(data);
402
386
  if (decrypted) {
403
- const hashes = yield this.secureDelegationKeysForAllEntitiesNoSfkAndSpecificEntitySfksPairs(decrypted.accessControlSecret, entityType, entitySecretForeignKeys);
404
- return { exchangeData: data, hashes, decrypted, verified: decrypted.verified };
387
+ const hashes = yield this.accessControlSecret.allSecureDelegationKeysFor(decrypted.accessControlSecret);
388
+ this.addToCache({ exchangeData: data, hashes, decrypted });
405
389
  }
406
390
  else {
407
- return { exchangeData: data, hashes: [], verified: false };
391
+ this.addToCache({ exchangeData: data, hashes: [] });
408
392
  }
409
- }));
410
- }))
411
- .then((x) => { var _a, _b; return ({ exchangeData: x.exchangeData, exchangeKey: (_a = x.decrypted) === null || _a === void 0 ? void 0 : _a.exchangeKey, accessControlSecret: (_b = x.decrypted) === null || _b === void 0 ? void 0 : _b.accessControlSecret }); });
393
+ res[data.id] = {
394
+ exchangeKey: decrypted === null || decrypted === void 0 ? void 0 : decrypted.exchangeKey,
395
+ accessControlSecret: decrypted === null || decrypted === void 0 ? void 0 : decrypted.accessControlSecret,
396
+ exchangeData: data,
397
+ };
398
+ }
399
+ }
400
+ return res;
401
+ }
402
+ finally {
403
+ release();
412
404
  }
413
- else
414
- return undefined;
415
405
  });
416
406
  }
417
- getOrCreateEncryptionDataTo(delegateId, entityType, entitySecretForeignKeys, allowCreationWithoutDelegateKey) {
407
+ getOrCreateEncryptionDataTo(delegateId, allowCreationWithoutDelegateKey) {
418
408
  return __awaiter(this, void 0, void 0, function* () {
419
- let existingId = this.delegateToVerifiedEncryptionDataId.get(delegateId);
420
- if (!existingId) {
421
- yield this.populateCacheToDelegate(delegateId, entityType, entitySecretForeignKeys);
422
- existingId = this.delegateToVerifiedEncryptionDataId.get(delegateId);
423
- }
424
- if (existingId) {
425
- const cached = yield this.idToDataCache.getIfCachedJob(existingId);
426
- if (!cached)
427
- throw new Error(`Illegal state: data with id ${existingId} should have been in cache`);
428
- if (cached.item.decrypted) {
429
- return {
430
- exchangeData: cached.item.exchangeData,
431
- exchangeKey: cached.item.decrypted.exchangeKey,
432
- accessControlSecret: cached.item.decrypted.accessControlSecret,
433
- };
409
+ const release = yield this.cacheMutex.acquire();
410
+ try {
411
+ let existingId = this.delegateToVerifiedEncryptionDataId.get(delegateId);
412
+ if (!existingId) {
413
+ yield this.populateCacheToDelegate(delegateId);
414
+ existingId = this.delegateToVerifiedEncryptionDataId.get(delegateId);
434
415
  }
435
- else
436
- throw new Error(`Illegal state: cached verified data should be decrypted.`);
437
- }
438
- else {
439
- const newDataId = this.primitives.randomUuid();
440
- this.delegateToVerifiedEncryptionDataId.set(delegateId, newDataId);
441
- const createdAndCachedData = yield this.idToDataCache.get(newDataId, () => this.cacheJob(() => __awaiter(this, void 0, void 0, function* () {
442
- try {
443
- const created = yield this.createNewExchangeData(delegateId, { newDataId, allowNoDelegateKeys: allowCreationWithoutDelegateKey });
444
- const hashes = yield this.secureDelegationKeysForAllEntitiesNoSfkAndSpecificEntitySfksPairs(created.accessControlSecret, entityType, entitySecretForeignKeys);
416
+ if (existingId) {
417
+ const cached = this.idToData.getCached(existingId);
418
+ if (!cached)
419
+ throw new Error(`Illegal state: data with id ${existingId} should have been in cache`);
420
+ if (cached.decrypted) {
445
421
  return {
446
- exchangeData: created.exchangeData,
447
- decrypted: {
448
- accessControlSecret: created.accessControlSecret,
449
- exchangeKey: created.exchangeKey,
450
- verified: true,
451
- },
452
- hashes,
422
+ exchangeData: cached.exchangeData,
423
+ exchangeKey: cached.decrypted.exchangeKey,
424
+ accessControlSecret: cached.decrypted.accessControlSecret,
453
425
  };
454
426
  }
455
- catch (e) {
456
- this.delegateToVerifiedEncryptionDataId.delete(delegateId);
457
- throw e;
458
- }
459
- })));
460
- if (!createdAndCachedData)
461
- throw new Error('Data should have been successfully created');
462
- return {
463
- exchangeData: createdAndCachedData.exchangeData,
464
- exchangeKey: createdAndCachedData.decrypted.exchangeKey,
465
- accessControlSecret: createdAndCachedData.decrypted.accessControlSecret,
466
- };
427
+ else
428
+ throw new Error(`Illegal state: cached verified data should be decrypted.`);
429
+ }
430
+ else {
431
+ const created = yield this.createNewExchangeData(delegateId, {
432
+ allowNoDelegateKeys: allowCreationWithoutDelegateKey,
433
+ });
434
+ const hashes = yield this.accessControlSecret.allSecureDelegationKeysFor(created.accessControlSecret);
435
+ const data = {
436
+ exchangeData: created.exchangeData,
437
+ decrypted: {
438
+ accessControlSecret: created.accessControlSecret,
439
+ exchangeKey: created.exchangeKey,
440
+ verified: true,
441
+ },
442
+ hashes,
443
+ };
444
+ this.addToCache(data);
445
+ return {
446
+ exchangeData: data.exchangeData,
447
+ exchangeKey: data.decrypted.exchangeKey,
448
+ accessControlSecret: data.decrypted.accessControlSecret,
449
+ };
450
+ }
451
+ }
452
+ finally {
453
+ release();
467
454
  }
468
455
  });
469
456
  }
470
457
  // Loads and adds to the cache all exchange data from the current data owner to the given delegate. Allows to check if there is already data from
471
458
  // the current data owner to the delegate which is good for encryption.
472
- populateCacheToDelegate(delegateId, entityType, entitySecretForeignKeys) {
459
+ populateCacheToDelegate(delegateId) {
473
460
  return __awaiter(this, void 0, void 0, function* () {
474
461
  const dataToDelegate = yield this.base.getExchangeDataByDelegatorDelegatePair(yield this.dataOwnerApi.getCurrentDataOwnerId(), delegateId);
475
- yield Promise.all(dataToDelegate.map((data) => __awaiter(this, void 0, void 0, function* () {
476
- yield this.idToDataCache.get(data.id, () => this.cacheJob(() => __awaiter(this, void 0, void 0, function* () {
477
- const decrypted = yield this.decryptData(data);
478
- if (decrypted) {
479
- const hashes = yield this.secureDelegationKeysForAllEntitiesNoSfkAndSpecificEntitySfksPairs(decrypted.accessControlSecret, entityType, entitySecretForeignKeys);
480
- return { exchangeData: data, hashes, decrypted };
481
- }
482
- else {
483
- return { exchangeData: data, hashes: [] };
484
- }
485
- })));
486
- })));
462
+ for (const data of dataToDelegate) {
463
+ const decrypted = yield this.decryptData(data);
464
+ if (decrypted) {
465
+ const hashes = yield this.accessControlSecret.allSecureDelegationKeysFor(decrypted.accessControlSecret);
466
+ this.addToCache({ exchangeData: data, hashes, decrypted });
467
+ }
468
+ else {
469
+ this.addToCache({ exchangeData: data, hashes: [] });
470
+ }
471
+ }
487
472
  });
488
473
  }
489
- cacheJob(retrieveDecryptedDataInfo) {
474
+ addToCache(data) {
490
475
  var _a;
491
- return __awaiter(this, void 0, void 0, function* () {
492
- const info = yield retrieveDecryptedDataInfo();
493
- info.hashes.forEach((hash) => this.hashToId.set(hash, info === null || info === void 0 ? void 0 : info.exchangeData.id));
494
- if ((_a = info.decrypted) === null || _a === void 0 ? void 0 : _a.verified)
495
- this.delegateToVerifiedEncryptionDataId.set(info.exchangeData.delegate, info.exchangeData.id);
496
- const item = {
497
- exchangeData: info.exchangeData,
498
- hashes: info.hashes,
499
- decrypted: info.decrypted,
500
- };
501
- return {
502
- item,
503
- onEviction: (b) => this.doOnEvictionJob(b, item),
504
- };
505
- });
476
+ if (this.idToData.size >= this.maxCachedExchangeData) {
477
+ this.evictOneEntry();
478
+ }
479
+ data.hashes.forEach((hash) => this.hashToId.set(hash, data.exchangeData.id));
480
+ if (((_a = data.decrypted) === null || _a === void 0 ? void 0 : _a.verified) && !this.delegateToVerifiedEncryptionDataId.has(data.exchangeData.delegate)) {
481
+ this.delegateToVerifiedEncryptionDataId.set(data.exchangeData.delegate, data.exchangeData.id);
482
+ }
483
+ this.idToData.set(data.exchangeData.id, data);
506
484
  }
507
- doOnEvictionJob(isReplacement, item) {
508
- return __awaiter(this, void 0, void 0, function* () {
509
- if (!isReplacement) {
510
- item.hashes.forEach((hash) => this.hashToId.delete(hash));
511
- if (this.delegateToVerifiedEncryptionDataId.get(item.exchangeData.delegate) === item.exchangeData.id) {
512
- this.delegateToVerifiedEncryptionDataId.delete(item.exchangeData.delegate);
513
- }
514
- }
515
- });
485
+ evictOneEntry() {
486
+ const evicted = this.idToData.evictLeastRecentlyUsed();
487
+ evicted.hashes.forEach((hash) => this.hashToId.delete(hash));
488
+ if (this.delegateToVerifiedEncryptionDataId.get(evicted.exchangeData.delegate) === evicted.exchangeData.id) {
489
+ this.delegateToVerifiedEncryptionDataId.delete(evicted.exchangeData.delegate);
490
+ }
516
491
  }
517
- getAccessControlKeysValue(entityType) {
492
+ getAccessControlKeysValue() {
518
493
  return Promise.resolve(undefined);
519
494
  }
520
- getAllDelegationKeys(entityType) {
495
+ getAllDelegationKeys() {
521
496
  return Promise.resolve(undefined);
522
497
  }
523
498
  }