@icure/api 5.0.24 → 5.0.25

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.
@@ -890,7 +890,14 @@ class IccCryptoXApi {
890
890
  });
891
891
  return this.decryptKeyInDelegationLikes(delegations[dataOwnerId], collatedAesKeysFromDelegatorToHcpartyId, objectId);
892
892
  })
893
- : Promise.resolve([])).then((extractedKeys) => __awaiter(this, void 0, void 0, function* () {
893
+ : Promise.resolve([]))
894
+ .then((extractedKeys) => __awaiter(this, void 0, void 0, function* () {
895
+ if (extractedKeys.length == 0) {
896
+ return yield this._extractDelegationsKeysUsingDataOwnerDelegateAesExchangeKeys(hcp, delegations, objectId);
897
+ }
898
+ return extractedKeys;
899
+ }))
900
+ .then((extractedKeys) => __awaiter(this, void 0, void 0, function* () {
894
901
  var _a;
895
902
  const parentExtractedKeys = hcp.parentId
896
903
  ? yield this.extractKeysFromDelegationsForHcpHierarchy(hcp.parentId, objectId, delegations)
@@ -902,6 +909,56 @@ class IccCryptoXApi {
902
909
  throw e;
903
910
  });
904
911
  }
912
+ /**
913
+ * This method covers the use case when a DataOwner found back access to its data, and needs to use the delegations of its delegates instead
914
+ * of its own ones
915
+ *
916
+ * @param dataOwner The current data owner from whom we want to decrypt the aesExchangeKeys
917
+ * @param delegations The object delegations to decrypt
918
+ * @param objectId The object to decrypt id
919
+ * @private
920
+ */
921
+ _extractDelegationsKeysUsingDataOwnerDelegateAesExchangeKeys(dataOwner, delegations, objectId) {
922
+ return __awaiter(this, void 0, void 0, function* () {
923
+ // Find other keys through aesExchangeKeys
924
+ const dataOwnerPubKeys = yield this.getPublicKeys();
925
+ const keysToDecrypt = (0, utils_1.fold)(Object.entries(dataOwner.aesExchangeKeys), {}, (acc, [pub, aesForPub]) => {
926
+ Object.entries(aesForPub).forEach(([delegateId, aesKeys]) => {
927
+ if (delegateId != dataOwner.id) {
928
+ const aesAcc = {};
929
+ Object.entries(aesKeys)
930
+ .filter(([encrPubKey]) => dataOwnerPubKeys.some((pubKey) => pubKey.slice(-32) == encrPubKey))
931
+ .forEach(([pubKeyFingerprint, aesEncr]) => {
932
+ aesAcc[pubKeyFingerprint] = aesEncr;
933
+ });
934
+ if (acc[delegateId] == undefined) {
935
+ acc[delegateId] = {};
936
+ }
937
+ acc[delegateId][pub] = aesAcc;
938
+ }
939
+ });
940
+ return acc;
941
+ });
942
+ const decryptedAndImportedAesHcPartyKeys = yield (0, utils_1.foldAsync)(Object.entries(keysToDecrypt), [], (delKeysAcc, [delegateId, keysForDelegate]) => __awaiter(this, void 0, void 0, function* () {
943
+ try {
944
+ delKeysAcc.push(yield this.decryptAnyAesExchangeKeyForOwner(keysForDelegate, dataOwner.id, dataOwner.id, delegateId, dataOwnerPubKeys));
945
+ }
946
+ catch (e) {
947
+ console.log(`Could not decrypt aesExchangeKeys for delegate ${delegateId}`);
948
+ }
949
+ return delKeysAcc;
950
+ }));
951
+ const collatedAesKeysFromDelegatorToHcpartyId = decryptedAndImportedAesHcPartyKeys.reduce((map, k) => { var _a; return (Object.assign(Object.assign({}, map), { [k.delegatorId]: ((_a = map[k.delegatorId]) !== null && _a !== void 0 ? _a : []).concat([k]) })); }, {});
952
+ const delegateIdsWithNewExtractedAesKeys = Object.keys(keysToDecrypt);
953
+ const delegationsToDecrypt = (0, utils_1.fold)(Object.entries(delegations), [], (acc, [delegateId, del]) => {
954
+ if (delegateIdsWithNewExtractedAesKeys.find((id) => id == delegateId) != undefined) {
955
+ acc.push(...delegations[delegateId]);
956
+ }
957
+ return acc;
958
+ });
959
+ return this.decryptKeyInDelegationLikes(delegationsToDecrypt, collatedAesKeysFromDelegatorToHcpartyId, objectId);
960
+ });
961
+ }
905
962
  /**
906
963
  * Gets an array of generic secret IDs decrypted from a list of generic delegations (SPKs, CFKs, EKs) `delegationsArray`
907
964
  * If a particular generic delegation thows an exception when decrypted, the return value for it's secret ID will be 'false' and a message is logged to console
@@ -997,7 +1054,7 @@ class IccCryptoXApi {
997
1054
  }
998
1055
  const publicKey = this.getPublicKeyFromPrivateKey(privateKey, dataOwner);
999
1056
  const keyPair = yield this._RSA.importKeyPair('jwk', privateKey, 'jwk', (0, utils_1.spkiToJwk)((0, binary_utils_1.hex2ua)(publicKey)));
1000
- this.rsaKeyPairs[healthcarePartyId] = keyPair;
1057
+ this.rsaKeyPairs[publicKey.slice(-32)] = keyPair;
1001
1058
  const exportedKeyPair = yield this._RSA.exportKeys(keyPair, 'jwk', 'jwk');
1002
1059
  return this.storeKeyPair(`${healthcarePartyId}.${publicKey.slice(-32)}`, exportedKeyPair);
1003
1060
  });
@@ -1217,6 +1274,66 @@ class IccCryptoXApi {
1217
1274
  }
1218
1275
  });
1219
1276
  }
1277
+ /**
1278
+ * When a user lost his keys, people to whom he shared information may call this method to give access back to him, re-encrypting their common
1279
+ * AES key using the new user public key.
1280
+ *
1281
+ * @param delegateUser Delegate Data Owner User, in charge of giving access back to the person who previously gave him some access
1282
+ * @param ownerId Id of the data owner to which we would like to give access back
1283
+ * @param ownerNewPublicKey New Data Owner Public Key we want to use to re-encrypt previously created AES key
1284
+ *
1285
+ * @return The DataOwner, updated by the delegateUser to add the new encrypted AES Key using the new provided public key
1286
+ */
1287
+ giveAccessBackTo(delegateUser, ownerId, ownerNewPublicKey) {
1288
+ var _a, _b, _c, _d;
1289
+ return __awaiter(this, void 0, void 0, function* () {
1290
+ const delegateId = (_b = (_a = delegateUser.healthcarePartyId) !== null && _a !== void 0 ? _a : delegateUser.patientId) !== null && _b !== void 0 ? _b : delegateUser.deviceId;
1291
+ if (!delegateId) {
1292
+ throw new Error(`DelegateUser ${delegateUser.id} must be a data Owner`);
1293
+ }
1294
+ const delegatePublicKeys = yield this.getPublicKeys();
1295
+ const newPubKeyCryptoKey = yield this._RSA.importKey('jwk', (0, utils_1.spkiToJwk)((0, binary_utils_1.hex2ua)(ownerNewPublicKey)), ['encrypt']);
1296
+ const dataOwnerToUpdate = yield this.getDataOwner(ownerId);
1297
+ const newAesExchangeKeys = yield (0, utils_1.foldAsync)(Object.entries((_c = dataOwnerToUpdate.dataOwner.aesExchangeKeys) !== null && _c !== void 0 ? _c : {}), (_d = dataOwnerToUpdate.dataOwner.aesExchangeKeys) !== null && _d !== void 0 ? _d : {}, (pubAcc, [pubKey, newAesExcKeys]) => __awaiter(this, void 0, void 0, function* () {
1298
+ var _e;
1299
+ const existingKeys = (_e = pubAcc[pubKey]) !== null && _e !== void 0 ? _e : {};
1300
+ pubAcc[pubKey] = yield (0, utils_1.foldAsync)(Object.entries(newAesExcKeys), existingKeys, (delAcc, [delId, delKeys]) => __awaiter(this, void 0, void 0, function* () {
1301
+ if (delId == delegateId && pubKey != ownerNewPublicKey) {
1302
+ // Add the AES Key encrypted with the new public key in the aesExchangeKeys
1303
+ try {
1304
+ // First, we decrypt it using the delegate RSA Public Key
1305
+ const encrAesKeyInfo = yield this.decryptHcPartyKey(delegateId, dataOwnerToUpdate.dataOwner.id, delegateId, pubKey, delKeys, delegatePublicKeys).then((delegatorAndKeys) => __awaiter(this, void 0, void 0, function* () {
1306
+ // Then, we encrypt it using the owner new RSA Public Key (provided in argument)
1307
+ return yield this.encryptAesKeyOnlyForProvidedKeys(delegatorAndKeys === null || delegatorAndKeys === void 0 ? void 0 : delegatorAndKeys.rawKey, dataOwnerToUpdate, [newPubKeyCryptoKey])
1308
+ .then((encrAes) => Object.values(encrAes)[0])
1309
+ .then((encrAesInfo) => {
1310
+ return { pubKeyUsedToEncryptAes: Object.keys(encrAesInfo)[0], encryptedAes: Object.values(encrAesInfo)[0] };
1311
+ });
1312
+ }));
1313
+ delKeys[encrAesKeyInfo.pubKeyUsedToEncryptAes] = encrAesKeyInfo.encryptedAes;
1314
+ }
1315
+ catch (e) {
1316
+ console.log(`${delegateId} could not re-encrypt AES Key of ${dataOwnerToUpdate.dataOwner.id}`);
1317
+ }
1318
+ finally {
1319
+ delAcc[delId] = delKeys;
1320
+ }
1321
+ }
1322
+ else {
1323
+ // Otherwise, we don't transform the aesExchangeKeys for this delegate
1324
+ delAcc[delId] = delKeys;
1325
+ }
1326
+ return delAcc;
1327
+ }));
1328
+ return pubAcc;
1329
+ }));
1330
+ // After adding the potential new aesExchangeKeys, we save the updated data owner
1331
+ return this._saveDataOwner({
1332
+ type: dataOwnerToUpdate.type,
1333
+ dataOwner: Object.assign(Object.assign({}, dataOwnerToUpdate.dataOwner), { aesExchangeKeys: newAesExchangeKeys }),
1334
+ });
1335
+ });
1336
+ }
1220
1337
  addNewKeyPairForOwnerId(maintenanceTasksApi, user, ownerId, generateTransferKey = true) {
1221
1338
  return __awaiter(this, void 0, void 0, function* () {
1222
1339
  return this.addNewKeyPairForOwner(maintenanceTasksApi, user, yield this.getDataOwner(ownerId), generateTransferKey);
@@ -1234,7 +1351,22 @@ class IccCryptoXApi {
1234
1351
  }).then((dataOwnerWithUpdatedAesKeys) => generateTransferKey
1235
1352
  ? this.createOrUpdateTransferKeysFor(dataOwnerWithUpdatedAesKeys, gen, { pubKey: publicKey, privKey: privateKey })
1236
1353
  : dataOwnerWithUpdatedAesKeys);
1237
- const modifiedDataOwnerAndType = ownerType === 'hcp'
1354
+ const modifiedDataOwnerAndType = yield this._saveDataOwner({ type: ownerType, dataOwner: ownerToUpdate });
1355
+ const sentMaintenanceTasks = yield this.sendMaintenanceTasks(maintenanceTasksApi, user, modifiedDataOwnerAndType.dataOwner, publicKey);
1356
+ return {
1357
+ dataOwner: sentMaintenanceTasks.length
1358
+ ? yield this.retrieveDataOwnerInfoAfterPotentialUpdate(modifiedDataOwnerAndType.dataOwner)
1359
+ : modifiedDataOwnerAndType.dataOwner,
1360
+ publicKey: publicKeyHex,
1361
+ privateKey: (0, binary_utils_1.ua2hex)((yield this.RSA.exportKey(privateKey, 'pkcs8'))),
1362
+ };
1363
+ });
1364
+ }
1365
+ _saveDataOwner(dataOwner) {
1366
+ return __awaiter(this, void 0, void 0, function* () {
1367
+ const ownerType = dataOwner.type;
1368
+ const ownerToUpdate = dataOwner.dataOwner;
1369
+ return ownerType === 'hcp'
1238
1370
  ? yield (this.dataOwnerCache[ownerToUpdate.id] = this.hcpartyBaseApi
1239
1371
  .modifyHealthcareParty(ownerToUpdate)
1240
1372
  .then((x) => ({ type: 'hcp', dataOwner: x })))
@@ -1245,14 +1377,6 @@ class IccCryptoXApi {
1245
1377
  : yield (this.dataOwnerCache[ownerToUpdate.id] = this.deviceBaseApi
1246
1378
  .updateDevice(ownerToUpdate)
1247
1379
  .then((x) => ({ type: 'device', dataOwner: x })));
1248
- const sentMaintenanceTasks = yield this.sendMaintenanceTasks(maintenanceTasksApi, user, modifiedDataOwnerAndType.dataOwner, publicKey);
1249
- return {
1250
- dataOwner: sentMaintenanceTasks.length
1251
- ? yield this.retrieveDataOwnerInfoAfterPotentialUpdate(modifiedDataOwnerAndType.dataOwner)
1252
- : modifiedDataOwnerAndType.dataOwner,
1253
- publicKey: publicKeyHex,
1254
- privateKey: (0, binary_utils_1.ua2hex)((yield this.RSA.exportKey(privateKey, 'pkcs8'))),
1255
- };
1256
1380
  });
1257
1381
  }
1258
1382
  createOrUpdateAesExchangeKeysFor(cdo, decryptedAesExchangeKey, keyToEncrypt) {
@@ -1285,11 +1409,16 @@ class IccCryptoXApi {
1285
1409
  encryptAesKeyFor(aesKey, dataOwner, doNewPublicKey) {
1286
1410
  return __awaiter(this, void 0, void 0, function* () {
1287
1411
  const dataOwnerAllPubKeys = [doNewPublicKey].concat(yield this.getDataOwnerPublicKeys(dataOwner));
1288
- const encrAes = {};
1289
- for (const pubKey of dataOwnerAllPubKeys) {
1412
+ return this.encryptAesKeyOnlyForProvidedKeys(aesKey, dataOwner, dataOwnerAllPubKeys);
1413
+ });
1414
+ }
1415
+ encryptAesKeyOnlyForProvidedKeys(aesKey, dataOwner, dataOwnerPubKeys) {
1416
+ return __awaiter(this, void 0, void 0, function* () {
1417
+ const encryptedAesForDataOwner = yield (0, utils_1.foldAsync)(dataOwnerPubKeys, {}, (encrAes, pubKey) => __awaiter(this, void 0, void 0, function* () {
1290
1418
  encrAes[(0, binary_utils_1.ua2hex)(yield this.RSA.exportKey(pubKey, 'spki')).slice(-32)] = (0, binary_utils_1.ua2hex)(yield this._RSA.encrypt(pubKey, (0, binary_utils_1.hex2ua)(aesKey)));
1291
- }
1292
- return { [dataOwner.id]: encrAes };
1419
+ return encrAes;
1420
+ }));
1421
+ return { [dataOwner.id]: encryptedAesForDataOwner };
1293
1422
  });
1294
1423
  }
1295
1424
  retrieveDataOwnerInfoAfterPotentialUpdate(dataOwnerToUpdate) {