@icure/api 5.0.23 → 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.
- package/icc-x-api/filters/HealthcarePartyByTagCodeFilter.d.ts +21 -0
- package/icc-x-api/filters/HealthcarePartyByTagCodeFilter.js +24 -0
- package/icc-x-api/filters/HealthcarePartyByTagCodeFilter.js.map +1 -0
- package/icc-x-api/filters/PatientByHcPartyGenderEducationProfession.js.map +1 -1
- package/icc-x-api/filters/filters.d.ts +1 -0
- package/icc-x-api/filters/filters.js +1 -0
- package/icc-x-api/filters/filters.js.map +1 -1
- package/icc-x-api/icc-accesslog-x-api.d.ts +1 -1
- package/icc-x-api/icc-accesslog-x-api.js.map +1 -1
- package/icc-x-api/icc-calendar-item-x-api.d.ts +1 -1
- package/icc-x-api/icc-calendar-item-x-api.js.map +1 -1
- package/icc-x-api/icc-crypto-x-api.d.ts +23 -0
- package/icc-x-api/icc-crypto-x-api.js +156 -20
- package/icc-x-api/icc-crypto-x-api.js.map +1 -1
- package/icc-x-api/icc-data-owner-x-api.js.map +1 -1
- package/icc-x-api/icc-patient-x-api.d.ts +1 -1
- package/icc-x-api/icc-patient-x-api.js +26 -29
- package/icc-x-api/icc-patient-x-api.js.map +1 -1
- package/icc-x-api/icc-user-x-api.js.map +1 -1
- package/icc-x-api/index.js +1 -1
- package/icc-x-api/index.js.map +1 -1
- package/icc-x-api/utils/functional-util.d.ts +1 -0
- package/icc-x-api/utils/functional-util.js +19 -1
- package/icc-x-api/utils/functional-util.js.map +1 -1
- package/package.json +1 -1
|
@@ -879,7 +879,8 @@ class IccCryptoXApi {
|
|
|
879
879
|
extractKeysFromDelegationsForHcpHierarchy(
|
|
880
880
|
//TODO suggested name: getSecretIdsOfHcpAndParentsFromGenericDelegations
|
|
881
881
|
dataOwnerId, objectId, delegations) {
|
|
882
|
-
return this.getDataOwner(dataOwnerId)
|
|
882
|
+
return this.getDataOwner(dataOwnerId)
|
|
883
|
+
.then(({ dataOwner: hcp }) => (delegations[dataOwnerId] && delegations[dataOwnerId].length
|
|
883
884
|
? this.getDecryptedAesExchangeKeysOfDelegateAndParentsFromGenericDelegations(dataOwnerId, delegations, false).then((decryptedAndImportedAesHcPartyKeys) => {
|
|
884
885
|
const collatedAesKeysFromDelegatorToHcpartyId = {};
|
|
885
886
|
decryptedAndImportedAesHcPartyKeys.forEach((k) => {
|
|
@@ -889,11 +890,74 @@ class IccCryptoXApi {
|
|
|
889
890
|
});
|
|
890
891
|
return this.decryptKeyInDelegationLikes(delegations[dataOwnerId], collatedAesKeysFromDelegatorToHcpartyId, objectId);
|
|
891
892
|
})
|
|
892
|
-
: Promise.resolve([]))
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
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* () {
|
|
901
|
+
var _a;
|
|
902
|
+
const parentExtractedKeys = hcp.parentId
|
|
903
|
+
? yield this.extractKeysFromDelegationsForHcpHierarchy(hcp.parentId, objectId, delegations)
|
|
904
|
+
: { extractedKeys: [], hcpartyId: undefined };
|
|
905
|
+
return { extractedKeys: extractedKeys.concat(parentExtractedKeys.extractedKeys), hcpartyId: (_a = parentExtractedKeys.hcpartyId) !== null && _a !== void 0 ? _a : dataOwnerId };
|
|
906
|
+
})))
|
|
907
|
+
.catch((e) => {
|
|
908
|
+
console.error(`Dataowner with id ${dataOwnerId} cannot be resolved`);
|
|
909
|
+
throw e;
|
|
910
|
+
});
|
|
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
|
+
});
|
|
897
961
|
}
|
|
898
962
|
/**
|
|
899
963
|
* Gets an array of generic secret IDs decrypted from a list of generic delegations (SPKs, CFKs, EKs) `delegationsArray`
|
|
@@ -990,7 +1054,7 @@ class IccCryptoXApi {
|
|
|
990
1054
|
}
|
|
991
1055
|
const publicKey = this.getPublicKeyFromPrivateKey(privateKey, dataOwner);
|
|
992
1056
|
const keyPair = yield this._RSA.importKeyPair('jwk', privateKey, 'jwk', (0, utils_1.spkiToJwk)((0, binary_utils_1.hex2ua)(publicKey)));
|
|
993
|
-
this.rsaKeyPairs[
|
|
1057
|
+
this.rsaKeyPairs[publicKey.slice(-32)] = keyPair;
|
|
994
1058
|
const exportedKeyPair = yield this._RSA.exportKeys(keyPair, 'jwk', 'jwk');
|
|
995
1059
|
return this.storeKeyPair(`${healthcarePartyId}.${publicKey.slice(-32)}`, exportedKeyPair);
|
|
996
1060
|
});
|
|
@@ -1210,6 +1274,66 @@ class IccCryptoXApi {
|
|
|
1210
1274
|
}
|
|
1211
1275
|
});
|
|
1212
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
|
+
}
|
|
1213
1337
|
addNewKeyPairForOwnerId(maintenanceTasksApi, user, ownerId, generateTransferKey = true) {
|
|
1214
1338
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1215
1339
|
return this.addNewKeyPairForOwner(maintenanceTasksApi, user, yield this.getDataOwner(ownerId), generateTransferKey);
|
|
@@ -1227,7 +1351,22 @@ class IccCryptoXApi {
|
|
|
1227
1351
|
}).then((dataOwnerWithUpdatedAesKeys) => generateTransferKey
|
|
1228
1352
|
? this.createOrUpdateTransferKeysFor(dataOwnerWithUpdatedAesKeys, gen, { pubKey: publicKey, privKey: privateKey })
|
|
1229
1353
|
: dataOwnerWithUpdatedAesKeys);
|
|
1230
|
-
const modifiedDataOwnerAndType = ownerType
|
|
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'
|
|
1231
1370
|
? yield (this.dataOwnerCache[ownerToUpdate.id] = this.hcpartyBaseApi
|
|
1232
1371
|
.modifyHealthcareParty(ownerToUpdate)
|
|
1233
1372
|
.then((x) => ({ type: 'hcp', dataOwner: x })))
|
|
@@ -1238,14 +1377,6 @@ class IccCryptoXApi {
|
|
|
1238
1377
|
: yield (this.dataOwnerCache[ownerToUpdate.id] = this.deviceBaseApi
|
|
1239
1378
|
.updateDevice(ownerToUpdate)
|
|
1240
1379
|
.then((x) => ({ type: 'device', dataOwner: x })));
|
|
1241
|
-
const sentMaintenanceTasks = yield this.sendMaintenanceTasks(maintenanceTasksApi, user, modifiedDataOwnerAndType.dataOwner, publicKey);
|
|
1242
|
-
return {
|
|
1243
|
-
dataOwner: sentMaintenanceTasks.length
|
|
1244
|
-
? yield this.retrieveDataOwnerInfoAfterPotentialUpdate(modifiedDataOwnerAndType.dataOwner)
|
|
1245
|
-
: modifiedDataOwnerAndType.dataOwner,
|
|
1246
|
-
publicKey: publicKeyHex,
|
|
1247
|
-
privateKey: (0, binary_utils_1.ua2hex)((yield this.RSA.exportKey(privateKey, 'pkcs8'))),
|
|
1248
|
-
};
|
|
1249
1380
|
});
|
|
1250
1381
|
}
|
|
1251
1382
|
createOrUpdateAesExchangeKeysFor(cdo, decryptedAesExchangeKey, keyToEncrypt) {
|
|
@@ -1278,11 +1409,16 @@ class IccCryptoXApi {
|
|
|
1278
1409
|
encryptAesKeyFor(aesKey, dataOwner, doNewPublicKey) {
|
|
1279
1410
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1280
1411
|
const dataOwnerAllPubKeys = [doNewPublicKey].concat(yield this.getDataOwnerPublicKeys(dataOwner));
|
|
1281
|
-
|
|
1282
|
-
|
|
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* () {
|
|
1283
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)));
|
|
1284
|
-
|
|
1285
|
-
|
|
1419
|
+
return encrAes;
|
|
1420
|
+
}));
|
|
1421
|
+
return { [dataOwner.id]: encryptedAesForDataOwner };
|
|
1286
1422
|
});
|
|
1287
1423
|
}
|
|
1288
1424
|
retrieveDataOwnerInfoAfterPotentialUpdate(dataOwnerToUpdate) {
|