@icure/api 8.0.0-RC.6 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/icc-api/api/IccAccesslogApi.d.ts +3 -7
- package/icc-api/api/IccAccesslogApi.js +2 -2
- package/icc-api/api/IccAccesslogApi.js.map +1 -1
- package/icc-api/api/IccAgendaApi.d.ts +1 -1
- package/icc-api/api/IccAgendaApi.js +2 -2
- package/icc-api/api/IccAgendaApi.js.map +1 -1
- package/icc-api/api/IccAnonymousAccessApi.d.ts +10 -0
- package/icc-api/api/IccAnonymousAccessApi.js +33 -0
- package/icc-api/api/IccAnonymousAccessApi.js.map +1 -1
- package/icc-api/api/IccApplicationsettingsApi.d.ts +1 -1
- package/icc-api/api/IccApplicationsettingsApi.js +2 -2
- package/icc-api/api/IccApplicationsettingsApi.js.map +1 -1
- package/icc-api/api/IccArticleApi.d.ts +1 -1
- package/icc-api/api/IccArticleApi.js +2 -2
- package/icc-api/api/IccArticleApi.js.map +1 -1
- package/icc-api/api/IccAuthApi.d.ts +4 -2
- package/icc-api/api/IccAuthApi.js +11 -4
- package/icc-api/api/IccAuthApi.js.map +1 -1
- package/icc-api/api/IccCalendarItemApi.d.ts +4 -12
- package/icc-api/api/IccCalendarItemApi.js +2 -2
- package/icc-api/api/IccCalendarItemApi.js.map +1 -1
- package/icc-api/api/IccCalendarItemTypeApi.d.ts +1 -1
- package/icc-api/api/IccCalendarItemTypeApi.js +2 -2
- package/icc-api/api/IccCalendarItemTypeApi.js.map +1 -1
- package/icc-api/api/IccClassificationApi.d.ts +4 -12
- package/icc-api/api/IccClassificationApi.js +2 -2
- package/icc-api/api/IccClassificationApi.js.map +1 -1
- package/icc-api/api/IccClassificationTemplateApi.d.ts +1 -1
- package/icc-api/api/IccClassificationTemplateApi.js +2 -2
- package/icc-api/api/IccClassificationTemplateApi.js.map +1 -1
- package/icc-api/api/IccCodeApi.d.ts +1 -1
- package/icc-api/api/IccCodeApi.js +2 -2
- package/icc-api/api/IccCodeApi.js.map +1 -1
- package/icc-api/api/IccContactApi.d.ts +3 -11
- package/icc-api/api/IccContactApi.js.map +1 -1
- package/icc-api/api/IccDataownerApi.d.ts +1 -1
- package/icc-api/api/IccDataownerApi.js +2 -2
- package/icc-api/api/IccDataownerApi.js.map +1 -1
- package/icc-api/api/IccDeviceApi.d.ts +1 -1
- package/icc-api/api/IccDeviceApi.js +2 -2
- package/icc-api/api/IccDeviceApi.js.map +1 -1
- package/icc-api/api/IccDoctemplateApi.d.ts +1 -1
- package/icc-api/api/IccDoctemplateApi.js +2 -2
- package/icc-api/api/IccDoctemplateApi.js.map +1 -1
- package/icc-api/api/IccDocumentApi.d.ts +3 -7
- package/icc-api/api/IccDocumentApi.js +2 -2
- package/icc-api/api/IccDocumentApi.js.map +1 -1
- package/icc-api/api/IccEntityrefApi.d.ts +1 -1
- package/icc-api/api/IccEntityrefApi.js +2 -2
- package/icc-api/api/IccEntityrefApi.js.map +1 -1
- package/icc-api/api/IccEntitytemplateApi.d.ts +1 -1
- package/icc-api/api/IccEntitytemplateApi.js +2 -2
- package/icc-api/api/IccEntitytemplateApi.js.map +1 -1
- package/icc-api/api/IccFormApi.d.ts +4 -12
- package/icc-api/api/IccFormApi.js +2 -2
- package/icc-api/api/IccFormApi.js.map +1 -1
- package/icc-api/api/IccFrontendmigrationApi.d.ts +1 -1
- package/icc-api/api/IccFrontendmigrationApi.js +2 -2
- package/icc-api/api/IccFrontendmigrationApi.js.map +1 -1
- package/icc-api/api/IccGroupApi.d.ts +1 -1
- package/icc-api/api/IccGroupApi.js +2 -2
- package/icc-api/api/IccGroupApi.js.map +1 -1
- package/icc-api/api/IccHcpartyApi.d.ts +1 -1
- package/icc-api/api/IccHcpartyApi.js +2 -2
- package/icc-api/api/IccHcpartyApi.js.map +1 -1
- package/icc-api/api/IccHelementApi.d.ts +4 -12
- package/icc-api/api/IccHelementApi.js +2 -2
- package/icc-api/api/IccHelementApi.js.map +1 -1
- package/icc-api/api/IccIcureApi.d.ts +1 -1
- package/icc-api/api/IccIcureApi.js +2 -2
- package/icc-api/api/IccIcureApi.js.map +1 -1
- package/icc-api/api/IccInsuranceApi.d.ts +1 -1
- package/icc-api/api/IccInsuranceApi.js +2 -2
- package/icc-api/api/IccInsuranceApi.js.map +1 -1
- package/icc-api/api/IccInvoiceApi.d.ts +4 -12
- package/icc-api/api/IccInvoiceApi.js +2 -2
- package/icc-api/api/IccInvoiceApi.js.map +1 -1
- package/icc-api/api/IccKeywordApi.d.ts +1 -1
- package/icc-api/api/IccKeywordApi.js +2 -2
- package/icc-api/api/IccKeywordApi.js.map +1 -1
- package/icc-api/api/IccMaintenanceTaskApi.d.ts +3 -7
- package/icc-api/api/IccMaintenanceTaskApi.js +2 -2
- package/icc-api/api/IccMaintenanceTaskApi.js.map +1 -1
- package/icc-api/api/IccMedexApi.d.ts +1 -1
- package/icc-api/api/IccMedexApi.js +2 -2
- package/icc-api/api/IccMedexApi.js.map +1 -1
- package/icc-api/api/IccMedicallocationApi.d.ts +1 -1
- package/icc-api/api/IccMedicallocationApi.js +2 -2
- package/icc-api/api/IccMedicallocationApi.js.map +1 -1
- package/icc-api/api/IccMessageApi.d.ts +3 -7
- package/icc-api/api/IccMessageApi.js +2 -2
- package/icc-api/api/IccMessageApi.js.map +1 -1
- package/icc-api/api/IccPatientApi.d.ts +3 -7
- package/icc-api/api/IccPatientApi.js +2 -2
- package/icc-api/api/IccPatientApi.js.map +1 -1
- package/icc-api/api/IccPermissionApi.d.ts +1 -1
- package/icc-api/api/IccPermissionApi.js +2 -2
- package/icc-api/api/IccPermissionApi.js.map +1 -1
- package/icc-api/api/IccPlaceApi.d.ts +1 -1
- package/icc-api/api/IccPlaceApi.js +2 -2
- package/icc-api/api/IccPlaceApi.js.map +1 -1
- package/icc-api/api/IccReceiptApi.d.ts +3 -7
- package/icc-api/api/IccReceiptApi.js +2 -2
- package/icc-api/api/IccReceiptApi.js.map +1 -1
- package/icc-api/api/IccReplicationApi.d.ts +1 -1
- package/icc-api/api/IccReplicationApi.js +2 -2
- package/icc-api/api/IccReplicationApi.js.map +1 -1
- package/icc-api/api/IccRoleApi.d.ts +1 -1
- package/icc-api/api/IccRoleApi.js +2 -2
- package/icc-api/api/IccRoleApi.js.map +1 -1
- package/icc-api/api/IccTarificationApi.d.ts +1 -1
- package/icc-api/api/IccTarificationApi.js +2 -2
- package/icc-api/api/IccTarificationApi.js.map +1 -1
- package/icc-api/api/IccTimeTableApi.d.ts +3 -7
- package/icc-api/api/IccTimeTableApi.js +2 -2
- package/icc-api/api/IccTimeTableApi.js.map +1 -1
- package/icc-api/api/IccTopicApi.d.ts +3 -7
- package/icc-api/api/IccTopicApi.js +2 -2
- package/icc-api/api/IccTopicApi.js.map +1 -1
- package/icc-api/api/IccUserApi.d.ts +16 -1
- package/icc-api/api/IccUserApi.js +46 -2
- package/icc-api/api/IccUserApi.js.map +1 -1
- package/icc-api/api/XHR.d.ts +1 -1
- package/icc-api/api/XHR.js +4 -3
- package/icc-api/api/XHR.js.map +1 -1
- package/icc-api/api/internal/IccExchangeDataMapApi.d.ts +0 -3
- package/icc-api/api/internal/IccExchangeDataMapApi.js +0 -31
- package/icc-api/api/internal/IccExchangeDataMapApi.js.map +1 -1
- package/icc-api/api/internal/IccSecureDelegationKeyMapApi.d.ts +2 -6
- package/icc-api/api/internal/IccSecureDelegationKeyMapApi.js.map +1 -1
- package/icc-api/model/MedicalLocation.d.ts +3 -0
- package/icc-api/model/MedicalLocation.js.map +1 -1
- package/icc-api/model/PaginatedListMedicalLocation.d.ts +20 -0
- package/icc-api/model/PaginatedListMedicalLocation.js +10 -0
- package/icc-api/model/PaginatedListMedicalLocation.js.map +1 -0
- package/icc-api/model/requests/BulkShareOrUpdateMetadataParams.d.ts +12 -0
- package/icc-api/model/requests/BulkShareOrUpdateMetadataParams.js +3 -0
- package/icc-api/model/requests/BulkShareOrUpdateMetadataParams.js.map +1 -0
- package/icc-x-api/auth/AuthService.d.ts +2 -1
- package/icc-x-api/auth/AuthService.js.map +1 -1
- package/icc-x-api/auth/AuthenticationProvider.d.ts +1 -1
- package/icc-x-api/auth/AuthenticationProvider.js +1 -1
- package/icc-x-api/auth/AuthenticationProvider.js.map +1 -1
- package/icc-x-api/auth/EnsembleAuthService.d.ts +1 -1
- package/icc-x-api/auth/EnsembleAuthService.js +2 -2
- package/icc-x-api/auth/EnsembleAuthService.js.map +1 -1
- package/icc-x-api/auth/JwtAuthService.d.ts +0 -2
- package/icc-x-api/auth/JwtAuthService.js +3 -15
- package/icc-x-api/auth/JwtAuthService.js.map +1 -1
- package/icc-x-api/auth/JwtBridgedAuthService.js +1 -1
- package/icc-x-api/auth/JwtBridgedAuthService.js.map +1 -1
- package/icc-x-api/auth/JwtUtils.d.ts +10 -0
- package/icc-x-api/auth/JwtUtils.js +31 -0
- package/icc-x-api/auth/JwtUtils.js.map +1 -0
- package/icc-x-api/auth/SmartAuthProvider.d.ts +132 -0
- package/icc-x-api/auth/SmartAuthProvider.js +419 -0
- package/icc-x-api/auth/SmartAuthProvider.js.map +1 -0
- package/icc-x-api/crypto/BaseExchangeDataManager.d.ts +20 -0
- package/icc-x-api/crypto/BaseExchangeDataManager.js +32 -2
- package/icc-x-api/crypto/BaseExchangeDataManager.js.map +1 -1
- package/icc-x-api/crypto/ConfidentialEntities.d.ts +2 -6
- package/icc-x-api/crypto/ConfidentialEntities.js.map +1 -1
- package/icc-x-api/crypto/CryptoStrategies.d.ts +3 -1
- package/icc-x-api/crypto/CryptoStrategies.js.map +1 -1
- package/icc-x-api/crypto/ExchangeDataManager.d.ts +3 -1
- package/icc-x-api/crypto/ExchangeDataManager.js +36 -22
- package/icc-x-api/crypto/ExchangeDataManager.js.map +1 -1
- package/icc-x-api/crypto/ExchangeDataMapManager.d.ts +0 -5
- package/icc-x-api/crypto/ExchangeDataMapManager.js +0 -11
- package/icc-x-api/crypto/ExchangeDataMapManager.js.map +1 -1
- package/icc-x-api/crypto/ExtendedApisUtils.d.ts +4 -16
- package/icc-x-api/crypto/ExtendedApisUtils.js.map +1 -1
- package/icc-x-api/crypto/ExtendedApisUtilsImpl.d.ts +4 -16
- package/icc-x-api/crypto/ExtendedApisUtilsImpl.js +12 -3
- package/icc-x-api/crypto/ExtendedApisUtilsImpl.js.map +1 -1
- package/icc-x-api/crypto/KeyPairRecoverer.d.ts +34 -0
- package/icc-x-api/crypto/KeyPairRecoverer.js +32 -0
- package/icc-x-api/crypto/KeyPairRecoverer.js.map +1 -0
- package/icc-x-api/crypto/RecoveryDataEncryption.d.ts +85 -0
- package/icc-x-api/crypto/RecoveryDataEncryption.js +171 -0
- package/icc-x-api/crypto/RecoveryDataEncryption.js.map +1 -0
- package/icc-x-api/crypto/SecureDelegationsManager.js +2 -2
- package/icc-x-api/crypto/SecureDelegationsManager.js.map +1 -1
- package/icc-x-api/crypto/ShamirKeysManager.js +1 -1
- package/icc-x-api/crypto/ShamirKeysManager.js.map +1 -1
- package/icc-x-api/crypto/UserEncryptionKeysManager.d.ts +4 -1
- package/icc-x-api/crypto/UserEncryptionKeysManager.js +4 -3
- package/icc-x-api/crypto/UserEncryptionKeysManager.js.map +1 -1
- package/icc-x-api/icc-bekmehr-x-api.d.ts +1 -0
- package/icc-x-api/icc-bekmehr-x-api.js +37 -36
- package/icc-x-api/icc-bekmehr-x-api.js.map +1 -1
- package/icc-x-api/icc-contact-x-api.js +15 -12
- package/icc-x-api/icc-contact-x-api.js.map +1 -1
- package/icc-x-api/icc-crypto-x-api.d.ts +1 -0
- package/icc-x-api/icc-crypto-x-api.js.map +1 -1
- package/icc-x-api/icc-maintenance-task-x-api.d.ts +1 -1
- package/icc-x-api/icc-maintenance-task-x-api.js.map +1 -1
- package/icc-x-api/icc-patient-x-api.d.ts +18 -0
- package/icc-x-api/icc-patient-x-api.js +29 -0
- package/icc-x-api/icc-patient-x-api.js.map +1 -1
- package/icc-x-api/icc-recovery-x-api.d.ts +127 -0
- package/icc-x-api/icc-recovery-x-api.js +217 -0
- package/icc-x-api/icc-recovery-x-api.js.map +1 -1
- package/icc-x-api/icc-user-x-api.js +15 -2
- package/icc-x-api/icc-user-x-api.js.map +1 -1
- package/icc-x-api/index.d.ts +46 -2
- package/icc-x-api/index.js +44 -11
- package/icc-x-api/index.js.map +1 -1
- package/icc-x-api/utils/collection-utils.d.ts +14 -1
- package/icc-x-api/utils/collection-utils.js +49 -3
- package/icc-x-api/utils/collection-utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,219 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.IccRecoveryXApi = exports.RecoveryDataUseFailureReason = void 0;
|
|
13
|
+
const utils_1 = require("./utils");
|
|
14
|
+
const RecoveryData_1 = require("../icc-api/model/internal/RecoveryData");
|
|
15
|
+
var RecoveryDataEncryption_1 = require("./crypto/RecoveryDataEncryption");
|
|
16
|
+
Object.defineProperty(exports, "RecoveryDataUseFailureReason", { enumerable: true, get: function () { return RecoveryDataEncryption_1.RecoveryDataUseFailureReason; } });
|
|
17
|
+
class IccRecoveryXApi {
|
|
18
|
+
constructor(baseRecoveryApi, recoveryDataEncryption, keyManager, dataOwnerApi, primitives, exchangeData) {
|
|
19
|
+
this.baseRecoveryApi = baseRecoveryApi;
|
|
20
|
+
this.recoveryDataEncryption = recoveryDataEncryption;
|
|
21
|
+
this.keyManager = keyManager;
|
|
22
|
+
this.dataOwnerApi = dataOwnerApi;
|
|
23
|
+
this.primitives = primitives;
|
|
24
|
+
this.exchangeData = exchangeData;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create recovery data for the logged user and stores it encrypted on the iCure server. This allows the user that created
|
|
28
|
+
* it to recover all the currently available keypairs at a later time by just providing the string returned by this method to the
|
|
29
|
+
* {@link recoverKeyPairs} method.
|
|
30
|
+
*
|
|
31
|
+
* You can also provide an expiration time for the recovery data (through `options.lifetimeSeconds`). If you do so, the recovery dat
|
|
32
|
+
* a will be deleted automatically after that amount seconds has passed. If you don't provide an expiration time, the recovery data
|
|
33
|
+
* will be available until it is explicitly deleted.
|
|
34
|
+
*
|
|
35
|
+
* This could be used to:
|
|
36
|
+
* - Provide some sort of one-use "recovery codes" to the user, which he can use to recover his keypair if he loses
|
|
37
|
+
* his device. In this case you should not put any expiration time on the recovery data.
|
|
38
|
+
* - Provide a way for the user to easily "copy" the key from one device to another. In this case you should put a
|
|
39
|
+
* short expiration time on the recovery data (a few minutes), so that it will automatically be deleted if it is
|
|
40
|
+
* not used after all.
|
|
41
|
+
*
|
|
42
|
+
* # Important
|
|
43
|
+
*
|
|
44
|
+
* A malicious user that can login as the creator of the recovery data or that can access directly the database
|
|
45
|
+
* containing the recovery data will be able to get the private key of the data owner from the recovery key returned
|
|
46
|
+
* by this method. Therefore, the resulting recovery key must be kept secret, just like a private key.
|
|
47
|
+
*
|
|
48
|
+
* @param options optional parameters:
|
|
49
|
+
* - `includeParentsKeys` if true, the recovery data will also contain any available keypairs for parents data owners.
|
|
50
|
+
* - `lifetimeSeconds` the amount of seconds the recovery data will be available. If not provided, the recovery data will be available until it is
|
|
51
|
+
* explicitly deleted.
|
|
52
|
+
* @return an hexadecimal string that is the `recoveryKey` which will allow the user to recover his keypair later or
|
|
53
|
+
* from another device. This value must be kept secret from other users. You can use this value with {@link recoverKeyPairs}
|
|
54
|
+
*/
|
|
55
|
+
createRecoveryInfoForAvailableKeyPairs(options = {}) {
|
|
56
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
+
const selfId = yield this.dataOwnerApi.getCurrentDataOwnerId();
|
|
58
|
+
const allAvailableKeys = yield this.keyManager.getCurrentUserHierarchyAvailableKeypairs();
|
|
59
|
+
let dataOwnersToInclude;
|
|
60
|
+
if (options.includeParentsKeys) {
|
|
61
|
+
dataOwnersToInclude = [allAvailableKeys.self, ...allAvailableKeys.parents];
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
dataOwnersToInclude = [allAvailableKeys.self];
|
|
65
|
+
}
|
|
66
|
+
const keyPairsToSave = {};
|
|
67
|
+
for (const { dataOwnerId, keys } of dataOwnersToInclude) {
|
|
68
|
+
const dataOwner = yield this.dataOwnerApi.getDataOwner(dataOwnerId);
|
|
69
|
+
const sha1Keys = new Set(this.dataOwnerApi.getHexPublicKeysWithSha1Of(dataOwner.dataOwner));
|
|
70
|
+
const sha256Keys = new Set(this.dataOwnerApi.getHexPublicKeysWithSha256Of(dataOwner.dataOwner));
|
|
71
|
+
const pairs = [];
|
|
72
|
+
for (const { pair, verified } of keys) {
|
|
73
|
+
if (verified) {
|
|
74
|
+
const pubKeyHex = (0, utils_1.ua2hex)(yield this.primitives.RSA.exportKey(pair.publicKey, 'spki'));
|
|
75
|
+
if (sha256Keys.has(pubKeyHex)) {
|
|
76
|
+
pairs.push({ pair, algorithm: 'sha-256' });
|
|
77
|
+
}
|
|
78
|
+
else if (sha1Keys.has(pubKeyHex)) {
|
|
79
|
+
pairs.push({ pair, algorithm: 'sha-1' });
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
console.warn(`Found stored key ${pubKeyHex} for data owner ${dataOwnerId} which is not saved in the data owner. Ignoring.`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
keyPairsToSave[dataOwnerId] = pairs;
|
|
87
|
+
}
|
|
88
|
+
return yield this.recoveryDataEncryption.createAndSaveKeyPairsRecoveryDataFor(selfId, keyPairsToSave, options.lifetimeSeconds);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Equivalent to {@link KeyPairRecoverer.recoverWithRecoveryKey}
|
|
93
|
+
*/
|
|
94
|
+
recoverKeyPairs(recoveryKey, autoDelete) {
|
|
95
|
+
return this.recoveryDataEncryption.getAndDecryptKeyPairsRecoveryData(recoveryKey, autoDelete);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Create recovery data that allows the delegate {@link delegateId} recover the content of exchange data from the
|
|
99
|
+
* current data owner to the delegate.
|
|
100
|
+
*
|
|
101
|
+
* This can be useful in the following situations:
|
|
102
|
+
* - A user lost access to his old keypair and is asking for access back to his data. This is similar to the
|
|
103
|
+
* give-access-back mechanism, except that instead of having to verify the public key of the delegate as in the
|
|
104
|
+
* give-access-back, the delegator has to provide the recovery key to the delegate: the delegator has to properly
|
|
105
|
+
* identify the delegate instead of validating that the public key belongs to the delegate.
|
|
106
|
+
* - A patient is not yet registered in the system and therefore has no keypair, but the doctor wants to already share
|
|
107
|
+
* some data with them. The doctor can create some placeholder exchange data, encrypted only with his own key
|
|
108
|
+
* through the {@link IccPatientXApi.forceInitialiseExchangeDataToNewlyInvitedPatient} method, then create recovery data
|
|
109
|
+
* for it and share the recovery key with the patient. The moment the patient logs in and creates his keypair he
|
|
110
|
+
* will use the {@link recoverExchangeData} method to "complete" the placeholder exchange data.
|
|
111
|
+
*
|
|
112
|
+
* @param delegateId id of the delegate that needs access to his exchange data from the current data owner. This can't
|
|
113
|
+
* be the id of the current data owner (you should instead recover the keypair).
|
|
114
|
+
* @param options optional parameters:
|
|
115
|
+
* - `lifetimeSeconds` the amount of seconds the recovery data will be available. If not provided, the recovery data will be available until it is
|
|
116
|
+
* explicitly deleted.
|
|
117
|
+
* @return an hexadecimal string that is the `recoveryKey` which will allow the delegate to gain access to the exchange data.
|
|
118
|
+
* This value must be kept secret from users other than the current data owner and the delegate.
|
|
119
|
+
* You can use this value with {@link recoverExchangeData}
|
|
120
|
+
*/
|
|
121
|
+
createExchangeDataRecoveryInfo(delegateId, options = {}) {
|
|
122
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
123
|
+
const exchangeDataToDelegate = yield this.exchangeData.base.getExchangeDataByDelegatorDelegatePair(yield this.dataOwnerApi.getCurrentDataOwnerId(), delegateId);
|
|
124
|
+
const decryptionKeys = this.keyManager.getDecryptionKeys();
|
|
125
|
+
const decryptedInformation = [];
|
|
126
|
+
for (const exchangeData of exchangeDataToDelegate) {
|
|
127
|
+
const decryptedData = yield this.exchangeData.base.tryRawDecryptExchangeData(exchangeData, decryptionKeys);
|
|
128
|
+
if (decryptedData !== undefined) {
|
|
129
|
+
decryptedInformation.push(Object.assign(Object.assign({}, decryptedData), { exchangeDataId: exchangeData.id }));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return this.recoveryDataEncryption.createAndSaveExchangeDataRecoveryData(delegateId, decryptedInformation, options.lifetimeSeconds);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Recover the content of exchange data from the delegator that created the recovery data at the provided.
|
|
137
|
+
* {@link recoveryKey} to the current delegate. This will enable the current user to access the exchange data with
|
|
138
|
+
* any of his private keys available on the device from which this method was called.
|
|
139
|
+
* The exchange data will be automatically deleted from the server after the process completes successfully.
|
|
140
|
+
*
|
|
141
|
+
* @param recoveryKey the result of a call to {@link createExchangeDataRecoveryInfo} by a delegator.
|
|
142
|
+
* @return null on success or a failure reason if the recovery data could not be used to perform the operation.
|
|
143
|
+
* @throws If the recovery data is valid but the process fails for other reasons.
|
|
144
|
+
*/
|
|
145
|
+
recoverExchangeData(recoveryKey) {
|
|
146
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
147
|
+
const selfEncryptionKeys = Object.fromEntries(this.keyManager.getSelfVerifiedKeys().map((k) => [k.fingerprint, k.pair.publicKey]));
|
|
148
|
+
const recoveredExchangeData = yield this.recoveryDataEncryption.getAndDecryptExchangeDataRecoveryData(recoveryKey);
|
|
149
|
+
if ('failure' in recoveredExchangeData) {
|
|
150
|
+
return recoveredExchangeData.failure;
|
|
151
|
+
}
|
|
152
|
+
for (const exchangeDataInfo of recoveredExchangeData.success) {
|
|
153
|
+
const retrievedData = yield this.exchangeData.base.getExchangeDataById(exchangeDataInfo.exchangeDataId);
|
|
154
|
+
if (!retrievedData) {
|
|
155
|
+
console.warn(`Could not recover exchange data with id ${exchangeDataInfo.exchangeDataId} as it was not found. Ignoring`);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
yield this.exchangeData.base.updateExchangeDataWithRawDecryptedContent(retrievedData, selfEncryptionKeys, exchangeDataInfo.rawExchangeKey, exchangeDataInfo.rawAccessControlSecret, exchangeDataInfo.rawSharedSignatureKey);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
yield this.baseRecoveryApi.deleteRecoveryData(yield this.recoveryDataEncryption.recoveryKeyToId(recoveryKey)).catch((e) => {
|
|
162
|
+
console.warn(`Could not delete recovery data with id ${recoveryKey} after successful recovery: ${e}. Ignoring.`);
|
|
163
|
+
});
|
|
164
|
+
yield this.exchangeData.clearOrRepopulateCache();
|
|
165
|
+
return null;
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Deletes the recovery information associated to a certain recovery key. You can use this method with the recovery key for any kind of data,
|
|
170
|
+
* regardless of how you obtained the recovery key (from the {@link createRecoveryInfoForAvailableKeyPairs} or from the
|
|
171
|
+
* {@link createExchangeDataRecoveryInfo} methods).
|
|
172
|
+
* If there is no data associated to the provided recovery key, this method will do nothing.
|
|
173
|
+
* @param recoveryKey the recovery key associated to the recovery information to delete.
|
|
174
|
+
*/
|
|
175
|
+
deleteRecoveryInfo(recoveryKey) {
|
|
176
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
177
|
+
yield this.baseRecoveryApi.deleteRecoveryData(yield this.recoveryDataEncryption.recoveryKeyToId(recoveryKey));
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Deletes the recovery information associated to a certain data owner, regardless of type.
|
|
182
|
+
* @param dataOwnerId the data owner for which to delete the recovery data.
|
|
183
|
+
* @return the number of deleted recovery information.
|
|
184
|
+
*/
|
|
185
|
+
deleteAllRecoveryInfoFor(dataOwnerId) {
|
|
186
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
187
|
+
return this.getCountFromDeleteAllRes(yield this.baseRecoveryApi.deleteAllRecoveryDataForRecipient(dataOwnerId));
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Deletes all key pair recovery information for a certain data owner.
|
|
192
|
+
* @param dataOwnerId the data owner for which to delete the key pair recovery information.
|
|
193
|
+
* @return the number of deleted key pair recovery information.
|
|
194
|
+
*/
|
|
195
|
+
deleteAllKeyPairRecoveryInfoFor(dataOwnerId) {
|
|
196
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
197
|
+
return this.getCountFromDeleteAllRes(yield this.baseRecoveryApi.deleteAllRecoveryDataOfTypeForRecipient(RecoveryData_1.RecoveryData.Type.KEYPAIR_RECOVERY, dataOwnerId));
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Deletes all exchange data recovery information for a certain data owner.
|
|
202
|
+
* @param dataOwnerId the data owner for which to delete the exchange data recovery information.
|
|
203
|
+
* @return the number of deleted exchange data recovery information.
|
|
204
|
+
*/
|
|
205
|
+
deleteAllExchangeDataRecoveryInfoFor(dataOwnerId) {
|
|
206
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
207
|
+
return this.getCountFromDeleteAllRes(yield this.baseRecoveryApi.deleteAllRecoveryDataOfTypeForRecipient(RecoveryData_1.RecoveryData.Type.EXCHANGE_KEY_RECOVERY, dataOwnerId));
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
getCountFromDeleteAllRes(deleteAllRes) {
|
|
211
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
212
|
+
if (deleteAllRes.numberValue !== undefined)
|
|
213
|
+
return deleteAllRes.numberValue;
|
|
214
|
+
throw new Error(`Unexpected result from delete method: ${JSON.stringify(deleteAllRes)}`);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
exports.IccRecoveryXApi = IccRecoveryXApi;
|
|
2
219
|
//# sourceMappingURL=icc-recovery-x-api.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icc-recovery-x-api.js","sourceRoot":"","sources":["../../icc-x-api/icc-recovery-x-api.ts"],"names":[],"mappings":"","sourcesContent":[""]}
|
|
1
|
+
{"version":3,"file":"icc-recovery-x-api.js","sourceRoot":"","sources":["../../icc-x-api/icc-recovery-x-api.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyPair, ShaVersion } from './crypto/RSA'\nimport { RecoveryDataEncryption, RecoveryDataUseFailureReason } from './crypto/RecoveryDataEncryption'\nimport { IccRecoveryDataApi } from '../icc-api/api/internal/IccRecoveryDataApi'\nimport { UserEncryptionKeysManager } from './crypto/UserEncryptionKeysManager'\nimport { IccDataOwnerXApi } from './icc-data-owner-x-api'\nimport { CryptoPrimitives } from './crypto/CryptoPrimitives'\nimport { ua2hex } from './utils'\nimport { Content } from '../icc-api/model/Content'\nimport { RecoveryData } from '../icc-api/model/internal/RecoveryData'\nimport { ExchangeDataManager } from './crypto/ExchangeDataManager'\n\nexport { RecoveryDataUseFailureReason } from './crypto/RecoveryDataEncryption'\n\nexport class IccRecoveryXApi {\n constructor(\n private readonly baseRecoveryApi: IccRecoveryDataApi,\n private readonly recoveryDataEncryption: RecoveryDataEncryption,\n private readonly keyManager: UserEncryptionKeysManager,\n private readonly dataOwnerApi: IccDataOwnerXApi,\n private readonly primitives: CryptoPrimitives,\n private readonly exchangeData: ExchangeDataManager\n ) {}\n\n /**\n * Create recovery data for the logged user and stores it encrypted on the iCure server. This allows the user that created\n * it to recover all the currently available keypairs at a later time by just providing the string returned by this method to the\n * {@link recoverKeyPairs} method.\n *\n * You can also provide an expiration time for the recovery data (through `options.lifetimeSeconds`). If you do so, the recovery dat\n * a will be deleted automatically after that amount seconds has passed. If you don't provide an expiration time, the recovery data\n * will be available until it is explicitly deleted.\n *\n * This could be used to:\n * - Provide some sort of one-use \"recovery codes\" to the user, which he can use to recover his keypair if he loses\n * his device. In this case you should not put any expiration time on the recovery data.\n * - Provide a way for the user to easily \"copy\" the key from one device to another. In this case you should put a\n * short expiration time on the recovery data (a few minutes), so that it will automatically be deleted if it is\n * not used after all.\n *\n * # Important\n *\n * A malicious user that can login as the creator of the recovery data or that can access directly the database\n * containing the recovery data will be able to get the private key of the data owner from the recovery key returned\n * by this method. Therefore, the resulting recovery key must be kept secret, just like a private key.\n *\n * @param options optional parameters:\n * - `includeParentsKeys` if true, the recovery data will also contain any available keypairs for parents data owners.\n * - `lifetimeSeconds` the amount of seconds the recovery data will be available. If not provided, the recovery data will be available until it is\n * explicitly deleted.\n * @return an hexadecimal string that is the `recoveryKey` which will allow the user to recover his keypair later or\n * from another device. This value must be kept secret from other users. You can use this value with {@link recoverKeyPairs}\n */\n async createRecoveryInfoForAvailableKeyPairs(options: { includeParentsKeys?: boolean; lifetimeSeconds?: number } = {}): Promise<string> {\n const selfId = await this.dataOwnerApi.getCurrentDataOwnerId()\n const allAvailableKeys = await this.keyManager.getCurrentUserHierarchyAvailableKeypairs()\n let dataOwnersToInclude: { dataOwnerId: string; keys: { pair: KeyPair<CryptoKey>; verified: boolean }[] }[]\n if (options.includeParentsKeys) {\n dataOwnersToInclude = [allAvailableKeys.self, ...allAvailableKeys.parents]\n } else {\n dataOwnersToInclude = [allAvailableKeys.self]\n }\n const keyPairsToSave: { [delegateId: string]: { pair: KeyPair<CryptoKey>; algorithm: ShaVersion }[] } = {}\n for (const { dataOwnerId, keys } of dataOwnersToInclude) {\n const dataOwner = await this.dataOwnerApi.getDataOwner(dataOwnerId)\n const sha1Keys = new Set(this.dataOwnerApi.getHexPublicKeysWithSha1Of(dataOwner.dataOwner))\n const sha256Keys = new Set(this.dataOwnerApi.getHexPublicKeysWithSha256Of(dataOwner.dataOwner))\n const pairs: { pair: KeyPair<CryptoKey>; algorithm: ShaVersion }[] = []\n for (const { pair, verified } of keys) {\n if (verified) {\n const pubKeyHex = ua2hex(await this.primitives.RSA.exportKey(pair.publicKey, 'spki'))\n if (sha256Keys.has(pubKeyHex)) {\n pairs.push({ pair, algorithm: 'sha-256' })\n } else if (sha1Keys.has(pubKeyHex)) {\n pairs.push({ pair, algorithm: 'sha-1' })\n } else {\n console.warn(`Found stored key ${pubKeyHex} for data owner ${dataOwnerId} which is not saved in the data owner. Ignoring.`)\n }\n }\n }\n keyPairsToSave[dataOwnerId] = pairs\n }\n return await this.recoveryDataEncryption.createAndSaveKeyPairsRecoveryDataFor(selfId, keyPairsToSave, options.lifetimeSeconds)\n }\n\n /**\n * Equivalent to {@link KeyPairRecoverer.recoverWithRecoveryKey}\n */\n recoverKeyPairs(\n recoveryKey: string,\n autoDelete: boolean\n ): Promise<{ success: { [dataOwnerId: string]: { [publicKeySpki: string]: KeyPair<CryptoKey> } } } | { failure: RecoveryDataUseFailureReason }> {\n return this.recoveryDataEncryption.getAndDecryptKeyPairsRecoveryData(recoveryKey, autoDelete)\n }\n\n /**\n * Create recovery data that allows the delegate {@link delegateId} recover the content of exchange data from the\n * current data owner to the delegate.\n *\n * This can be useful in the following situations:\n * - A user lost access to his old keypair and is asking for access back to his data. This is similar to the\n * give-access-back mechanism, except that instead of having to verify the public key of the delegate as in the\n * give-access-back, the delegator has to provide the recovery key to the delegate: the delegator has to properly\n * identify the delegate instead of validating that the public key belongs to the delegate.\n * - A patient is not yet registered in the system and therefore has no keypair, but the doctor wants to already share\n * some data with them. The doctor can create some placeholder exchange data, encrypted only with his own key\n * through the {@link IccPatientXApi.forceInitialiseExchangeDataToNewlyInvitedPatient} method, then create recovery data\n * for it and share the recovery key with the patient. The moment the patient logs in and creates his keypair he\n * will use the {@link recoverExchangeData} method to \"complete\" the placeholder exchange data.\n *\n * @param delegateId id of the delegate that needs access to his exchange data from the current data owner. This can't\n * be the id of the current data owner (you should instead recover the keypair).\n * @param options optional parameters:\n * - `lifetimeSeconds` the amount of seconds the recovery data will be available. If not provided, the recovery data will be available until it is\n * explicitly deleted.\n * @return an hexadecimal string that is the `recoveryKey` which will allow the delegate to gain access to the exchange data.\n * This value must be kept secret from users other than the current data owner and the delegate.\n * You can use this value with {@link recoverExchangeData}\n */\n async createExchangeDataRecoveryInfo(delegateId: string, options: { lifetimeSeconds?: number } = {}): Promise<string> {\n const exchangeDataToDelegate = await this.exchangeData.base.getExchangeDataByDelegatorDelegatePair(\n await this.dataOwnerApi.getCurrentDataOwnerId(),\n delegateId\n )\n const decryptionKeys = this.keyManager.getDecryptionKeys()\n const decryptedInformation: {\n exchangeDataId: string\n rawExchangeKey: ArrayBuffer\n rawAccessControlSecret: ArrayBuffer\n rawSharedSignatureKey: ArrayBuffer\n }[] = []\n for (const exchangeData of exchangeDataToDelegate) {\n const decryptedData = await this.exchangeData.base.tryRawDecryptExchangeData(exchangeData, decryptionKeys)\n if (decryptedData !== undefined) {\n decryptedInformation.push({ ...decryptedData, exchangeDataId: exchangeData.id! })\n }\n }\n return this.recoveryDataEncryption.createAndSaveExchangeDataRecoveryData(delegateId, decryptedInformation, options.lifetimeSeconds)\n }\n\n /**\n * Recover the content of exchange data from the delegator that created the recovery data at the provided.\n * {@link recoveryKey} to the current delegate. This will enable the current user to access the exchange data with\n * any of his private keys available on the device from which this method was called.\n * The exchange data will be automatically deleted from the server after the process completes successfully.\n *\n * @param recoveryKey the result of a call to {@link createExchangeDataRecoveryInfo} by a delegator.\n * @return null on success or a failure reason if the recovery data could not be used to perform the operation.\n * @throws If the recovery data is valid but the process fails for other reasons.\n */\n async recoverExchangeData(recoveryKey: string): Promise<RecoveryDataUseFailureReason | null> {\n const selfEncryptionKeys = Object.fromEntries(this.keyManager.getSelfVerifiedKeys().map((k) => [k.fingerprint, k.pair.publicKey]))\n const recoveredExchangeData = await this.recoveryDataEncryption.getAndDecryptExchangeDataRecoveryData(recoveryKey)\n if ('failure' in recoveredExchangeData) {\n return recoveredExchangeData.failure\n }\n for (const exchangeDataInfo of recoveredExchangeData.success) {\n const retrievedData = await this.exchangeData.base.getExchangeDataById(exchangeDataInfo.exchangeDataId)\n if (!retrievedData) {\n console.warn(`Could not recover exchange data with id ${exchangeDataInfo.exchangeDataId} as it was not found. Ignoring`)\n } else {\n await this.exchangeData.base.updateExchangeDataWithRawDecryptedContent(\n retrievedData,\n selfEncryptionKeys,\n exchangeDataInfo.rawExchangeKey,\n exchangeDataInfo.rawAccessControlSecret,\n exchangeDataInfo.rawSharedSignatureKey\n )\n }\n }\n await this.baseRecoveryApi.deleteRecoveryData(await this.recoveryDataEncryption.recoveryKeyToId(recoveryKey)).catch((e) => {\n console.warn(`Could not delete recovery data with id ${recoveryKey} after successful recovery: ${e}. Ignoring.`)\n })\n await this.exchangeData.clearOrRepopulateCache()\n return null\n }\n\n /**\n * Deletes the recovery information associated to a certain recovery key. You can use this method with the recovery key for any kind of data,\n * regardless of how you obtained the recovery key (from the {@link createRecoveryInfoForAvailableKeyPairs} or from the\n * {@link createExchangeDataRecoveryInfo} methods).\n * If there is no data associated to the provided recovery key, this method will do nothing.\n * @param recoveryKey the recovery key associated to the recovery information to delete.\n */\n async deleteRecoveryInfo(recoveryKey: string): Promise<void> {\n await this.baseRecoveryApi.deleteRecoveryData(await this.recoveryDataEncryption.recoveryKeyToId(recoveryKey))\n }\n\n /**\n * Deletes the recovery information associated to a certain data owner, regardless of type.\n * @param dataOwnerId the data owner for which to delete the recovery data.\n * @return the number of deleted recovery information.\n */\n async deleteAllRecoveryInfoFor(dataOwnerId: string): Promise<number> {\n return this.getCountFromDeleteAllRes(await this.baseRecoveryApi.deleteAllRecoveryDataForRecipient(dataOwnerId))\n }\n\n /**\n * Deletes all key pair recovery information for a certain data owner.\n * @param dataOwnerId the data owner for which to delete the key pair recovery information.\n * @return the number of deleted key pair recovery information.\n */\n async deleteAllKeyPairRecoveryInfoFor(dataOwnerId: string): Promise<number> {\n return this.getCountFromDeleteAllRes(\n await this.baseRecoveryApi.deleteAllRecoveryDataOfTypeForRecipient(RecoveryData.Type.KEYPAIR_RECOVERY, dataOwnerId)\n )\n }\n\n /**\n * Deletes all exchange data recovery information for a certain data owner.\n * @param dataOwnerId the data owner for which to delete the exchange data recovery information.\n * @return the number of deleted exchange data recovery information.\n */\n async deleteAllExchangeDataRecoveryInfoFor(dataOwnerId: string): Promise<number> {\n return this.getCountFromDeleteAllRes(\n await this.baseRecoveryApi.deleteAllRecoveryDataOfTypeForRecipient(RecoveryData.Type.EXCHANGE_KEY_RECOVERY, dataOwnerId)\n )\n }\n\n private async getCountFromDeleteAllRes(deleteAllRes: Content): Promise<number> {\n if (deleteAllRes.numberValue !== undefined) return deleteAllRes.numberValue\n throw new Error(`Unexpected result from delete method: ${JSON.stringify(deleteAllRes)}`)\n }\n}\n"]}
|
|
@@ -14,6 +14,7 @@ const IccUserApi_1 = require("../icc-api/api/IccUserApi");
|
|
|
14
14
|
const AuthenticationProvider_1 = require("./auth/AuthenticationProvider");
|
|
15
15
|
const Connection_1 = require("../icc-api/model/Connection");
|
|
16
16
|
const utils_1 = require("./utils");
|
|
17
|
+
const collection_utils_1 = require("./utils/collection-utils");
|
|
17
18
|
class IccUserXApi extends IccUserApi_1.IccUserApi {
|
|
18
19
|
constructor(host, headers, authenticationProvider = new AuthenticationProvider_1.NoAuthenticationProvider(), authApi, fetchImpl = typeof window !== 'undefined'
|
|
19
20
|
? window.fetch
|
|
@@ -33,12 +34,24 @@ class IccUserXApi extends IccUserApi_1.IccUserApi {
|
|
|
33
34
|
}
|
|
34
35
|
modifyUser(body) {
|
|
35
36
|
const _super = Object.create(null, {
|
|
36
|
-
modifyUser: { get: () => super.modifyUser }
|
|
37
|
+
modifyUser: { get: () => super.modifyUser },
|
|
38
|
+
getCurrentUser: { get: () => super.getCurrentUser }
|
|
37
39
|
});
|
|
38
40
|
return __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
//If we do not load the current user, we cannot know if the modification is on the current user
|
|
42
|
+
yield this.getCurrentUser();
|
|
39
43
|
if (this.cachedCurrentUser && (yield this.cachedCurrentUser).id === (body === null || body === void 0 ? void 0 : body.id)) {
|
|
40
44
|
try {
|
|
41
|
-
const modifiedUser = yield _super.modifyUser.call(this, body)
|
|
45
|
+
const modifiedUser = yield _super.modifyUser.call(this, body).catch((e) => __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
//It is
|
|
47
|
+
if (e.statusCode === 409) {
|
|
48
|
+
let userInDb = yield _super.getCurrentUser.call(this);
|
|
49
|
+
if ((0, collection_utils_1.objectEquals)((yield this.cachedCurrentUser), userInDb, ['authenticationTokens', 'rev'])) {
|
|
50
|
+
return yield _super.modifyUser.call(this, Object.assign(Object.assign({}, body), { rev: userInDb.rev, authenticationTokens: userInDb.authenticationTokens }));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
throw e;
|
|
54
|
+
}));
|
|
42
55
|
this.cachedCurrentUser = Promise.resolve(modifiedUser);
|
|
43
56
|
return modifiedUser;
|
|
44
57
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icc-user-x-api.js","sourceRoot":"","sources":["../../icc-x-api/icc-user-x-api.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,0DAAsD;AACtD,0EAAgG;AAGhG,4DAAwE;AACxE,mCAAsE;
|
|
1
|
+
{"version":3,"file":"icc-user-x-api.js","sourceRoot":"","sources":["../../icc-x-api/icc-user-x-api.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,0DAAsD;AACtD,0EAAgG;AAGhG,4DAAwE;AACxE,mCAAsE;AAEtE,+DAAuD;AAEvD,MAAa,WAAY,SAAQ,uBAAU;IAIzC,YACE,IAAY,EACZ,OAAkC,EAClC,yBAAiD,IAAI,iDAAwB,EAAE,EAC9D,OAAmB,EACpC,YAA2E,OAAO,MAAM,KAAK,WAAW;QACtG,CAAC,CAAC,MAAM,CAAC,KAAK;QACd,CAAC,CAAC,OAAO,IAAI,KAAK,WAAW;YAC7B,CAAC,CAAC,IAAI,CAAC,KAAK;YACZ,CAAC,CAAC,KAAK;QAET,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,sBAAsB,EAAE,SAAS,CAAC,CAAA;QAPtC,YAAO,GAAP,OAAO,CAAY;QAQpC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;IAC5B,CAAC;IAED,cAAc,CAAC,cAAuB,KAAK;;QACzC,IAAI,WAAW;YAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC,CAAA;;YACpE,OAAO,MAAA,IAAI,CAAC,iBAAiB,mCAAI,CAAC,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC,CAAA;IACzF,CAAC;IAEK,UAAU,CAAC,IAAW;;;;;;YAC1B,+FAA+F;YAC/F,MAAM,IAAI,CAAC,cAAc,EAAE,CAAA;YAC3B,IAAI,IAAI,CAAC,iBAAiB,IAAI,CAAC,MAAM,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,MAAK,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,EAAE,CAAA,EAAE;gBAC5E,IAAI;oBACF,MAAM,YAAY,GAAG,MAAM,OAAM,UAAU,YAAC,IAAI,EAAE,KAAK,CAAC,CAAO,CAAC,EAAE,EAAE;wBAClE,OAAO;wBACP,IAAI,CAAC,CAAC,UAAU,KAAK,GAAG,EAAE;4BACxB,IAAI,QAAQ,GAAG,MAAM,OAAM,cAAc,WAAE,CAAA;4BAC3C,IAAI,IAAA,+BAAY,EAAC,CAAC,MAAM,IAAI,CAAC,iBAAiB,CAAE,EAAE,QAAQ,EAAE,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC,EAAE;gCAC5F,OAAO,MAAM,OAAM,UAAU,4CAAM,IAAI,KAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,oBAAoB,EAAE,QAAQ,CAAC,oBAAoB,IAAG,CAAA;6BACnH;yBACF;wBACD,MAAM,CAAC,CAAA;oBACT,CAAC,CAAA,CAAC,CAAA;oBACF,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;oBACtD,OAAO,YAAY,CAAA;iBACpB;gBAAC,OAAO,CAAC,EAAE;oBACV,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAA;oBAClC,MAAM,CAAC,CAAA;iBACR;aACF;;gBAAM,OAAO,OAAM,UAAU,YAAC,IAAI,EAAC;QACtC,CAAC;KAAA;IAEK,qBAAqB,CACzB,UAA8C,EAC9C,MAAwC,EACxC,UAAyC,EACzC,UAA+B,EAAE;;YAEjC,MAAM,EAAE,GAAG,MAAM,IAAA,+BAAuB,EAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;YAClH,OAAO,IAAI,2BAAc,CAAC,EAAE,CAAC,CAAA;QAC/B,CAAC;KAAA;CACF;AAzDD,kCAyDC","sourcesContent":["import { IccUserApi } from '../icc-api/api/IccUserApi'\nimport { AuthenticationProvider, NoAuthenticationProvider } from './auth/AuthenticationProvider'\nimport { AbstractFilter } from './filters/filters'\nimport { User } from '../icc-api/model/User'\nimport { Connection, ConnectionImpl } from '../icc-api/model/Connection'\nimport { subscribeToEntityEvents, SubscriptionOptions } from './utils'\nimport { IccAuthApi } from '../icc-api'\nimport { objectEquals } from './utils/collection-utils'\n\nexport class IccUserXApi extends IccUserApi {\n fetchImpl: (input: RequestInfo, init?: RequestInit) => Promise<Response>\n private cachedCurrentUser: Promise<User> | undefined\n\n constructor(\n host: string,\n headers: { [key: string]: string },\n authenticationProvider: AuthenticationProvider = new NoAuthenticationProvider(),\n private readonly authApi: IccAuthApi,\n fetchImpl: (input: RequestInfo, init?: RequestInit) => Promise<Response> = typeof window !== 'undefined'\n ? window.fetch\n : typeof self !== 'undefined'\n ? self.fetch\n : fetch\n ) {\n super(host, headers, authenticationProvider, fetchImpl)\n this.fetchImpl = fetchImpl\n }\n\n getCurrentUser(bypassCache: boolean = false): Promise<User> {\n if (bypassCache) return (this.cachedCurrentUser = super.getCurrentUser())\n else return this.cachedCurrentUser ?? (this.cachedCurrentUser = super.getCurrentUser())\n }\n\n async modifyUser(body?: User): Promise<User> {\n //If we do not load the current user, we cannot know if the modification is on the current user\n await this.getCurrentUser()\n if (this.cachedCurrentUser && (await this.cachedCurrentUser).id === body?.id) {\n try {\n const modifiedUser = await super.modifyUser(body).catch(async (e) => {\n //It is\n if (e.statusCode === 409) {\n let userInDb = await super.getCurrentUser()\n if (objectEquals((await this.cachedCurrentUser)!, userInDb, ['authenticationTokens', 'rev'])) {\n return await super.modifyUser({ ...body, rev: userInDb.rev, authenticationTokens: userInDb.authenticationTokens })\n }\n }\n throw e\n })\n this.cachedCurrentUser = Promise.resolve(modifiedUser)\n return modifiedUser\n } catch (e) {\n this.cachedCurrentUser = undefined\n throw e\n }\n } else return super.modifyUser(body)\n }\n\n async subscribeToUserEvents(\n eventTypes: ('CREATE' | 'UPDATE' | 'DELETE')[],\n filter: AbstractFilter<User> | undefined,\n eventFired: (user: User) => Promise<void>,\n options: SubscriptionOptions = {}\n ): Promise<Connection> {\n const rs = await subscribeToEntityEvents(this.host, this.authApi, 'User', eventTypes, filter, eventFired, options)\n return new ConnectionImpl(rs)\n }\n}\n"]}
|
package/icc-x-api/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IccAgendaApi, IccAnonymousAccessApi, IccApplicationsettingsApi, IccArticleApi, IccAuthApi, IccBeefactApi, IccBeresultexportApi, IccBeresultimportApi, IccBesamv2Api, IccCalendarItemTypeApi, IccClassificationTemplateApi, IccEntityrefApi, IccEntitytemplateApi, IccFrontendmigrationApi, IccGroupApi, IccIcureApi, IccInsuranceApi, IccKeywordApi, IccMedexApi, IccMedicallocationApi, IccPermissionApi, IccPlaceApi, IccPubsubApi, IccReplicationApi, IccTarificationApi, IccTmpApi } from '../icc-api';
|
|
1
|
+
import { IccAgendaApi, IccAnonymousAccessApi, IccApplicationsettingsApi, IccArticleApi, IccAuthApi, IccBeefactApi, IccBeresultexportApi, IccBeresultimportApi, IccBesamv2Api, IccCalendarItemTypeApi, IccClassificationTemplateApi, IccEntityrefApi, IccEntitytemplateApi, IccFrontendmigrationApi, IccGroupApi, IccIcureApi, IccInsuranceApi, IccKeywordApi, IccMedexApi, IccMedicallocationApi, IccPermissionApi, IccPlaceApi, IccPubsubApi, IccReplicationApi, IccTarificationApi, IccTmpApi, OAuthThirdParty } from '../icc-api';
|
|
2
2
|
import { IccUserXApi } from './icc-user-x-api';
|
|
3
3
|
import { IccCryptoXApi } from './icc-crypto-x-api';
|
|
4
4
|
import { IccContactXApi } from './icc-contact-x-api';
|
|
@@ -29,6 +29,8 @@ import { IccDoctemplateXApi } from './icc-doctemplate-x-api';
|
|
|
29
29
|
import { UserGroup } from '../icc-api/model/UserGroup';
|
|
30
30
|
import { IccTopicXApi } from './icc-topic-x-api';
|
|
31
31
|
import { IccRoleApi } from '../icc-api/api/IccRoleApi';
|
|
32
|
+
import { AuthSecretProvider } from './auth/SmartAuthProvider';
|
|
33
|
+
import { IccRecoveryXApi } from './icc-recovery-x-api';
|
|
32
34
|
export * from './icc-accesslog-x-api';
|
|
33
35
|
export * from './icc-bekmehr-x-api';
|
|
34
36
|
export * from './icc-calendar-item-x-api';
|
|
@@ -113,6 +115,7 @@ export interface Apis extends BasicApis {
|
|
|
113
115
|
readonly tmpApi: IccTmpApi;
|
|
114
116
|
readonly topicApi: IccTopicXApi;
|
|
115
117
|
readonly roleApi: IccRoleApi;
|
|
118
|
+
readonly recoveryApi: IccRecoveryXApi;
|
|
116
119
|
}
|
|
117
120
|
/**
|
|
118
121
|
* Allows to customise the behaviour of the iCure API by providing various optional parameters.
|
|
@@ -352,6 +355,44 @@ export type AuthenticationDetails = {
|
|
|
352
355
|
thirdPartyTokens: {
|
|
353
356
|
[thirdParty: string]: string;
|
|
354
357
|
};
|
|
358
|
+
} | SmartAuthenticationDetails;
|
|
359
|
+
/**
|
|
360
|
+
* Allows to perform authentication through an {@link AuthSecretProvider}.
|
|
361
|
+
*
|
|
362
|
+
* The iCure SDK can authenticate to the backend using different kinds of secrets, such as passwords, long-lived authentication tokens, and
|
|
363
|
+
* short-lived authentication tokens generated through the message gateway. iCure associates to each kind of secret a certain security level, and for
|
|
364
|
+
* some sensitive operations, depending on the configurations of the user and his group, some operations may require a secret of a certain security
|
|
365
|
+
* level. For example, with the default configurations, in order to change his own email the user can't have logged in with a long-lived token, but he
|
|
366
|
+
* needs to provide his current password or a short-lived token.
|
|
367
|
+
*
|
|
368
|
+
* By using this authentication option, the iCure SDK will automatically request and cache the secret from the {@link AuthSecretProvider} only when
|
|
369
|
+
* needed, which should help to minimise the interaction with the user.
|
|
370
|
+
*
|
|
371
|
+
* Another advantage of using this authentication option over others is that in case all the cached tokens and secrets were to expire while performing
|
|
372
|
+
* a request, instead of having the request fail the SDK will ask for a new secret from the {@link SmartAuthProvider} and the request will
|
|
373
|
+
* automatically be retried with the new secret.
|
|
374
|
+
*
|
|
375
|
+
* You must provide the following information:
|
|
376
|
+
* - username: any kind of value that can identify the user (userId, groupId/userId, username, email, ...). More generic identifiers, valid
|
|
377
|
+
* on multiple groups, allow for simpler group switching by using {@link IcureApi.switchGroup}.
|
|
378
|
+
* - secretProvider: the secret provider to use for authentication. Will handle interaction with the gui.
|
|
379
|
+
*
|
|
380
|
+
* You can also provide the following optional information, which may allow to reduce the requests for secrets initially:
|
|
381
|
+
* - initialSecret: an initial secret (password, token, ...) that will be used to get new authentication tokens as needed. If it is expired it will be ignored.
|
|
382
|
+
* - initialAuthToken: an initial authentication token used on each request. If it is expired it will be ignored.
|
|
383
|
+
* - initialRefreshToken: an initial refresh token used to get new authentication tokens as needed. If it is expired it will be ignored.
|
|
384
|
+
*/
|
|
385
|
+
export type SmartAuthenticationDetails = {
|
|
386
|
+
username: string;
|
|
387
|
+
secretProvider: AuthSecretProvider;
|
|
388
|
+
initialSecret?: {
|
|
389
|
+
plainSecret: string;
|
|
390
|
+
} | {
|
|
391
|
+
oauthToken: string;
|
|
392
|
+
oauthType: OAuthThirdParty;
|
|
393
|
+
};
|
|
394
|
+
initialAuthToken?: string;
|
|
395
|
+
initialRefreshToken?: string;
|
|
355
396
|
};
|
|
356
397
|
/**
|
|
357
398
|
* Main entry point for the iCure API. Provides entity-specific sub-apis and some general methods which are not related to a specific entity.
|
|
@@ -361,9 +402,12 @@ export interface IcureApi extends Apis {
|
|
|
361
402
|
* Get the information on groups that the current user can access and the current group that this api instance is working on.
|
|
362
403
|
* Note that the values you will get for `availableGroups` may differ from the values you would get if you call {@link IccUserApi.getMatchingUsers}
|
|
363
404
|
* on {@link Apis.userApi}, since the latter is specialised on the specific instance of the user in `currentGroup`.
|
|
405
|
+
* - `currentGroup`: the group that this api instance is working on, or undefined if the backend environment is not multi-group.
|
|
406
|
+
* - `availableGroups`: the list of groups that the current user can access with the provided secret. Empty if the backend environment is not
|
|
407
|
+
* multi-group.
|
|
364
408
|
*/
|
|
365
409
|
getGroupsInfo(): Promise<{
|
|
366
|
-
currentGroup: UserGroup;
|
|
410
|
+
currentGroup: UserGroup | undefined;
|
|
367
411
|
availableGroups: UserGroup[];
|
|
368
412
|
}>;
|
|
369
413
|
/**
|
package/icc-x-api/index.js
CHANGED
|
@@ -79,6 +79,11 @@ const IccRoleApi_1 = require("../icc-api/api/IccRoleApi");
|
|
|
79
79
|
const DataOwnerTypeEnum_1 = require("../icc-api/model/DataOwnerTypeEnum");
|
|
80
80
|
const DelegationsDeAnonymization_1 = require("./crypto/DelegationsDeAnonymization");
|
|
81
81
|
const JwtBridgedAuthService_1 = require("./auth/JwtBridgedAuthService");
|
|
82
|
+
const SmartAuthProvider_1 = require("./auth/SmartAuthProvider");
|
|
83
|
+
const KeyPairRecoverer_1 = require("./crypto/KeyPairRecoverer");
|
|
84
|
+
const IccRecoveryDataApi_1 = require("../icc-api/api/internal/IccRecoveryDataApi");
|
|
85
|
+
const RecoveryDataEncryption_1 = require("./crypto/RecoveryDataEncryption");
|
|
86
|
+
const icc_recovery_x_api_1 = require("./icc-recovery-x-api");
|
|
82
87
|
__exportStar(require("./icc-accesslog-x-api"), exports);
|
|
83
88
|
__exportStar(require("./icc-bekmehr-x-api"), exports);
|
|
84
89
|
__exportStar(require("./icc-calendar-item-x-api"), exports);
|
|
@@ -156,17 +161,24 @@ var IcureApi;
|
|
|
156
161
|
: typeof self !== 'undefined'
|
|
157
162
|
? self.fetch
|
|
158
163
|
: fetch, options = {}) {
|
|
164
|
+
var _a;
|
|
159
165
|
return __awaiter(this, void 0, void 0, function* () {
|
|
160
166
|
const params = new IcureApiOptions.WithDefaults(options);
|
|
161
167
|
let grouplessAuthenticationProvider = yield getAuthenticationProvider(host, authenticationOptions, params.headers, fetchImpl);
|
|
168
|
+
// TODO if this uses a smart auth provider the groupless auth provider does not share the secret cache with the group specific one.
|
|
162
169
|
const grouplessUserApi = new icc_api_1.IccUserApi(host, params.headers, grouplessAuthenticationProvider, fetchImpl);
|
|
163
|
-
const matches = yield grouplessUserApi
|
|
164
|
-
const chosenGroupId = matches.length > 1 ? yield
|
|
170
|
+
const matches = yield getMatchesOrEmpty(grouplessUserApi);
|
|
171
|
+
const chosenGroupId = matches.length > 1 && !!options.groupSelector ? yield options.groupSelector(matches) : (_a = matches[0]) === null || _a === void 0 ? void 0 : _a.groupId;
|
|
172
|
+
const groupSpecificAuthenticationProviderInfo = matches.length > 1 && chosenGroupId
|
|
173
|
+
? yield grouplessAuthenticationProvider.switchGroup(chosenGroupId, matches)
|
|
174
|
+
: { switchedProvider: grouplessAuthenticationProvider, isGroupLocked: false };
|
|
165
175
|
/*TODO
|
|
166
176
|
* On new very new users switching the authentication provider to a specific group may fail and block the user for too many requests. This is
|
|
167
177
|
* probably linked to replication of the user in the fallback database.
|
|
168
178
|
*/
|
|
169
|
-
const groupSpecificAuthenticationProvider = matches.length > 1
|
|
179
|
+
const groupSpecificAuthenticationProvider = matches.length > 1 && chosenGroupId
|
|
180
|
+
? yield grouplessAuthenticationProvider.switchGroup(chosenGroupId, matches)
|
|
181
|
+
: grouplessAuthenticationProvider;
|
|
170
182
|
const cryptoInitInfo = yield initialiseCryptoWithProvider(host, fetchImpl, groupSpecificAuthenticationProvider, params, cryptoStrategies, crypto);
|
|
171
183
|
return new IcureApiImpl(cryptoInitInfo, host, groupSpecificAuthenticationProvider, fetch, grouplessUserApi, matches, matches.find((match) => match.groupId === chosenGroupId), params, cryptoStrategies);
|
|
172
184
|
});
|
|
@@ -177,13 +189,7 @@ function getAuthenticationProvider(host, authenticationOptions, headers, fetchIm
|
|
|
177
189
|
return __awaiter(this, void 0, void 0, function* () {
|
|
178
190
|
let authenticationProvider;
|
|
179
191
|
if ('getIcureTokens' in authenticationOptions && 'switchGroup' in authenticationOptions && 'getAuthService' in authenticationOptions) {
|
|
180
|
-
|
|
181
|
-
if (!!tokens && !!tokens.token && !!tokens.refreshToken) {
|
|
182
|
-
authenticationProvider = new AuthenticationProvider_1.JwtAuthenticationProvider(new icc_api_1.IccAuthApi(host, headers, new AuthenticationProvider_1.NoAuthenticationProvider(), fetchImpl), undefined, undefined, undefined, tokens);
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
authenticationProvider = authenticationOptions;
|
|
186
|
-
}
|
|
192
|
+
authenticationProvider = authenticationOptions;
|
|
187
193
|
}
|
|
188
194
|
else if ('icureTokens' in authenticationOptions && !!authenticationOptions.icureTokens) {
|
|
189
195
|
authenticationProvider = new AuthenticationProvider_1.JwtAuthenticationProvider(new icc_api_1.IccAuthApi(host, headers, new AuthenticationProvider_1.NoAuthenticationProvider(), fetchImpl), undefined, undefined, undefined, authenticationOptions.icureTokens);
|
|
@@ -197,6 +203,13 @@ function getAuthenticationProvider(host, authenticationOptions, headers, fetchIm
|
|
|
197
203
|
else if ('thirdPartyTokens' in authenticationOptions && !!authenticationOptions.thirdPartyTokens) {
|
|
198
204
|
authenticationProvider = new AuthenticationProvider_1.JwtAuthenticationProvider(new icc_api_1.IccAuthApi(host, headers, new AuthenticationProvider_1.NoAuthenticationProvider(), fetchImpl), undefined, undefined, new JwtBridgedAuthService_1.JwtBridgedAuthService(new icc_api_1.IccAuthApi(host, headers, new AuthenticationProvider_1.NoAuthenticationProvider(), fetchImpl), undefined, undefined, authenticationOptions.thirdPartyTokens));
|
|
199
205
|
}
|
|
206
|
+
else if ('username' in authenticationOptions && 'secretProvider' in authenticationOptions) {
|
|
207
|
+
authenticationProvider = SmartAuthProvider_1.SmartAuthProvider.initialise(new icc_api_1.IccAuthApi(host, headers, new AuthenticationProvider_1.NoAuthenticationProvider(), fetchImpl), authenticationOptions.username, authenticationOptions.secretProvider, {
|
|
208
|
+
initialSecret: authenticationOptions.initialSecret,
|
|
209
|
+
initialAuthToken: authenticationOptions.initialAuthToken,
|
|
210
|
+
initialRefreshToken: authenticationOptions.initialRefreshToken,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
200
213
|
else {
|
|
201
214
|
throw new Error('Invalid authentication options provided');
|
|
202
215
|
}
|
|
@@ -229,13 +242,16 @@ function initialiseCryptoWithProvider(host, fetchImpl, groupSpecificAuthenticati
|
|
|
229
242
|
const basePatientApi = new icc_api_1.IccPatientApi(host, updatedHeaders, groupSpecificAuthenticationProvider, fetchImpl);
|
|
230
243
|
const dataOwnerApi = new icc_data_owner_x_api_1.IccDataOwnerXApi(host, updatedHeaders, groupSpecificAuthenticationProvider, fetchImpl);
|
|
231
244
|
const exchangeDataApi = new IccExchangeDataApi_1.IccExchangeDataApi(host, updatedHeaders, groupSpecificAuthenticationProvider, fetchImpl);
|
|
245
|
+
const baseRecoveryDataApi = new IccRecoveryDataApi_1.IccRecoveryDataApi(host, updatedHeaders, groupSpecificAuthenticationProvider, fetchImpl);
|
|
232
246
|
// Crypto initialisation
|
|
233
247
|
const icureStorage = new IcureStorageFacade_1.IcureStorageFacade(params.keyStorage, params.storage, params.entryKeysFactory);
|
|
234
248
|
const cryptoPrimitives = new CryptoPrimitives_1.CryptoPrimitives(crypto);
|
|
235
249
|
const baseExchangeKeysManager = new BaseExchangeKeysManager_1.BaseExchangeKeysManager(cryptoPrimitives, dataOwnerApi, healthcarePartyApi, basePatientApi, deviceApi);
|
|
236
250
|
const baseExchangeDataManager = new BaseExchangeDataManager_1.BaseExchangeDataManager(exchangeDataApi, dataOwnerApi, cryptoPrimitives, dataOwnerRequiresAnonymousDelegation);
|
|
237
251
|
const keyRecovery = new KeyRecovery_1.KeyRecovery(cryptoPrimitives, dataOwnerApi, baseExchangeKeysManager, baseExchangeDataManager);
|
|
238
|
-
const
|
|
252
|
+
const recoveryDataEncryption = new RecoveryDataEncryption_1.RecoveryDataEncryption(cryptoPrimitives, baseRecoveryDataApi);
|
|
253
|
+
const keyPairRecoverer = new KeyPairRecoverer_1.KeyPairRecoverer(recoveryDataEncryption);
|
|
254
|
+
const userEncryptionKeysManager = new UserEncryptionKeysManager_1.UserEncryptionKeysManager(cryptoPrimitives, dataOwnerApi, icureStorage, keyRecovery, cryptoStrategies, !params.disableParentKeysInitialisation, keyPairRecoverer);
|
|
239
255
|
const userSignatureKeysManager = new UserSignatureKeysManager_1.UserSignatureKeysManager(icureStorage, dataOwnerApi, cryptoPrimitives);
|
|
240
256
|
const newKey = yield userEncryptionKeysManager.initialiseKeys();
|
|
241
257
|
yield new TransferKeysManager_1.TransferKeysManager(cryptoPrimitives, baseExchangeDataManager, dataOwnerApi, userEncryptionKeysManager, userSignatureKeysManager, icureStorage).updateTransferKeys(yield dataOwnerApi.getCurrentDataOwnerStub());
|
|
@@ -268,6 +284,7 @@ function initialiseCryptoWithProvider(host, fetchImpl, groupSpecificAuthenticati
|
|
|
268
284
|
icureMaintenanceTaskApi,
|
|
269
285
|
headers: updatedHeaders,
|
|
270
286
|
dataOwnerRequiresAnonymousDelegation,
|
|
287
|
+
recoveryApi: new icc_recovery_x_api_1.IccRecoveryXApi(baseRecoveryDataApi, recoveryDataEncryption, userEncryptionKeysManager, dataOwnerApi, cryptoPrimitives, exchangeDataManager),
|
|
271
288
|
};
|
|
272
289
|
});
|
|
273
290
|
}
|
|
@@ -283,6 +300,9 @@ class IcureApiImpl {
|
|
|
283
300
|
this.cryptoStrategies = cryptoStrategies;
|
|
284
301
|
this.latestGroupsRequest = Promise.resolve(latestMatches);
|
|
285
302
|
}
|
|
303
|
+
get recoveryApi() {
|
|
304
|
+
return this.cryptoInitInfos.recoveryApi;
|
|
305
|
+
}
|
|
286
306
|
get authApi() {
|
|
287
307
|
var _a;
|
|
288
308
|
return ((_a = this._authApi) !== null && _a !== void 0 ? _a : (this._authApi = new icc_api_1.IccAuthApi(this.host, this.cryptoInitInfos.headers, this.groupSpecificAuthenticationProvider, this.fetch)));
|
|
@@ -529,4 +549,17 @@ const BasicApis = function (host, authenticationOptions, crypto = typeof window
|
|
|
529
549
|
});
|
|
530
550
|
};
|
|
531
551
|
exports.BasicApis = BasicApis;
|
|
552
|
+
function getMatchesOrEmpty(userApi) {
|
|
553
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
554
|
+
try {
|
|
555
|
+
return yield userApi.getMatchingUsers();
|
|
556
|
+
}
|
|
557
|
+
catch (err) {
|
|
558
|
+
if (err instanceof Error && 'statusCode' in err && err.statusCode === 404)
|
|
559
|
+
return Promise.resolve([]);
|
|
560
|
+
else
|
|
561
|
+
return Promise.reject(err);
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
}
|
|
532
565
|
//# sourceMappingURL=index.js.map
|