@icure/api 6.2.0 → 6.3.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/model/Document.d.ts +8 -8
- package/icc-api/model/Document.js.map +1 -1
- package/icc-api/model/Measure.d.ts +1 -1
- package/icc-api/model/Measure.js.map +1 -1
- package/icc-api/model/Medication.d.ts +4 -0
- package/icc-api/model/Medication.js.map +1 -1
- package/icc-api/model/Patient.d.ts +4 -0
- package/icc-api/model/Patient.js.map +1 -1
- package/icc-api/model/PermissionItem.d.ts +3 -1
- package/icc-api/model/PermissionItem.js +2 -0
- package/icc-api/model/PermissionItem.js.map +1 -1
- package/icc-api/model/TimeTableItem.d.ts +1 -0
- package/icc-api/model/TimeTableItem.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 +14 -23
- package/icc-x-api/icc-crypto-x-api.js.map +1 -1
- package/icc-x-api/icc-patient-x-api.d.ts +6 -0
- package/icc-x-api/icc-patient-x-api.js +61 -38
- package/icc-x-api/icc-patient-x-api.js.map +1 -1
- package/package.json +1 -1
|
@@ -45,6 +45,10 @@ export declare class IccPatientXApi extends IccPatientApi {
|
|
|
45
45
|
getPatient(patientId: string): never;
|
|
46
46
|
getPatientRaw(patientId: string): Promise<models.Patient | any>;
|
|
47
47
|
getPatientWithUser(user: models.User, patientId: string): Promise<models.Patient | any>;
|
|
48
|
+
getPotentiallyEncryptedPatientWithUser(user: models.User, patientId: string): Promise<{
|
|
49
|
+
patient: models.Patient;
|
|
50
|
+
decrypted: boolean;
|
|
51
|
+
}>;
|
|
48
52
|
getPatients(body?: models.ListOfIds): never;
|
|
49
53
|
getPatientsWithUser(user: models.User, body?: models.ListOfIds): Promise<Array<models.Patient> | any>;
|
|
50
54
|
listDeletedPatients(startDate?: number, endDate?: number, desc?: boolean, startDocumentId?: string, limit?: number): never;
|
|
@@ -69,7 +73,9 @@ export declare class IccPatientXApi extends IccPatientApi {
|
|
|
69
73
|
modifyPatientReferral(patientId: string, referralId: string, start?: number, end?: number): never;
|
|
70
74
|
modifyPatientReferralWithUser(user: models.User, patientId: string, referralId: string, start?: number, end?: number): Promise<models.Patient | any>;
|
|
71
75
|
encrypt(user: models.User, pats: Array<models.Patient>): Promise<Array<models.Patient>>;
|
|
76
|
+
private tryEncrypt;
|
|
72
77
|
decrypt(user: models.User, patients: Array<models.Patient>, fillDelegations?: boolean): Promise<Array<models.Patient>>;
|
|
78
|
+
private tryDecryptOrReturnOriginal;
|
|
73
79
|
/** By default, an encryptionKey will be added for every hcp in the autoDelegations of the provided user.
|
|
74
80
|
* In optional field additionalDelegateIds, you can ask the method to create encryptionKeys for additional hcps */
|
|
75
81
|
initEncryptionKeys(user: models.User, pat: models.Patient, additionalDelegateIds?: string[]): Promise<models.Patient>;
|
|
@@ -79,13 +79,23 @@ class IccPatientXApi extends icc_api_1.IccPatientApi {
|
|
|
79
79
|
}
|
|
80
80
|
initDelegationsAndEncryptionKeys(patient, user, secretForeignKey = undefined, delegates = []) {
|
|
81
81
|
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
function updatePatientWithDataOwnerIfSame(dataOwner) {
|
|
83
|
+
if (dataOwner.id === patient.id) {
|
|
84
|
+
_.extend(patient, {
|
|
85
|
+
rev: dataOwner.rev,
|
|
86
|
+
publicKey: dataOwner.publicKey,
|
|
87
|
+
aesExchangeKeys: dataOwner.aesExchangeKeys,
|
|
88
|
+
hcPartyKeys: dataOwner.hcPartyKeys
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
82
92
|
const dataOwnerId = this.dataOwnerApi.getDataOwnerOf(user);
|
|
83
93
|
const dels = yield this.crypto.initObjectDelegations(patient, null, dataOwnerId, null);
|
|
94
|
+
updatePatientWithDataOwnerIfSame(dels.owner);
|
|
84
95
|
const eks = yield this.crypto.initEncryptionKeys(patient, dataOwnerId);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
});
|
|
96
|
+
updatePatientWithDataOwnerIfSame(eks.modifiedOwner);
|
|
97
|
+
patient.delegations = dels.delegations;
|
|
98
|
+
patient.encryptionKeys = eks.encryptionKeys;
|
|
89
99
|
let promise = Promise.resolve(patient);
|
|
90
100
|
_.uniq(delegates.concat(user.autoDelegations ? (user.autoDelegations.all || []).concat(user.autoDelegations.medicalInformation || []) : [])).forEach((delegateId) => (promise = promise.then((patient) => this.crypto.addDelegationsAndEncryptionKeys(null, patient, dataOwnerId, delegateId, dels.secretId, eks.secretId).catch((e) => {
|
|
91
101
|
console.log(e);
|
|
@@ -183,7 +193,13 @@ class IccPatientXApi extends icc_api_1.IccPatientApi {
|
|
|
183
193
|
getPatientWithUser(user, patientId) {
|
|
184
194
|
return super
|
|
185
195
|
.getPatient(patientId)
|
|
186
|
-
.then((p) => this.
|
|
196
|
+
.then((p) => this.tryDecryptOrReturnOriginal(user, [p], false))
|
|
197
|
+
.then((pats) => pats[0].patient);
|
|
198
|
+
}
|
|
199
|
+
getPotentiallyEncryptedPatientWithUser(user, patientId) {
|
|
200
|
+
return super
|
|
201
|
+
.getPatient(patientId)
|
|
202
|
+
.then((p) => this.tryDecryptOrReturnOriginal(user, [p], false))
|
|
187
203
|
.then((pats) => pats[0]);
|
|
188
204
|
}
|
|
189
205
|
getPatients(body) {
|
|
@@ -261,7 +277,7 @@ class IccPatientXApi extends icc_api_1.IccPatientApi {
|
|
|
261
277
|
}
|
|
262
278
|
modifyPatientWithUser(user, body) {
|
|
263
279
|
return body
|
|
264
|
-
? this.
|
|
280
|
+
? this.tryEncrypt(user, [_.cloneDeep(this.completeNames(body))], false)
|
|
265
281
|
.then((pats) => super.modifyPatient(pats[0]))
|
|
266
282
|
.then((p) => this.decrypt(user, [p]))
|
|
267
283
|
.then((pats) => {
|
|
@@ -285,36 +301,43 @@ class IccPatientXApi extends icc_api_1.IccPatientApi {
|
|
|
285
301
|
});
|
|
286
302
|
}
|
|
287
303
|
encrypt(user, pats) {
|
|
304
|
+
return this.tryEncrypt(user, pats, true);
|
|
305
|
+
}
|
|
306
|
+
tryEncrypt(user, pats, requireAccessibleKey) {
|
|
288
307
|
const dataOwnerId = this.dataOwnerApi.getDataOwnerOf(user);
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
return seks;
|
|
308
|
+
return Promise.all(pats.map((p) => __awaiter(this, void 0, void 0, function* () {
|
|
309
|
+
const patientWithInitialisedEks = (p.encryptionKeys && Object.values(p.encryptionKeys).some((v) => !!v.length)
|
|
310
|
+
? p
|
|
311
|
+
: yield this.initEncryptionKeys(user, p));
|
|
312
|
+
const seks = yield this.crypto.extractKeysFromDelegationsForHcpHierarchy(dataOwnerId, patientWithInitialisedEks.id, patientWithInitialisedEks.encryptionKeys).catch((e) => { console.error(e); throw e; });
|
|
313
|
+
if (seks.extractedKeys.length) {
|
|
314
|
+
const key = yield this.crypto.AES.importKey('raw', (0, binary_utils_1.hex2ua)(seks.extractedKeys[0].replace(/-/g, '')));
|
|
315
|
+
return (0, utils_1.crypt)(patientWithInitialisedEks, (obj) => this.crypto.AES.encrypt(key, (0, binary_utils_1.utf8_2ua)(JSON.stringify(obj, (k, v) => {
|
|
316
|
+
return v instanceof ArrayBuffer || v instanceof Uint8Array
|
|
317
|
+
? (0, binary_utils_1.b2a)(new Uint8Array(v).reduce((d, b) => d + String.fromCharCode(b), ''))
|
|
318
|
+
: v;
|
|
319
|
+
}))), this.encryptedKeys);
|
|
302
320
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
throw e;
|
|
321
|
+
else if (requireAccessibleKey) {
|
|
322
|
+
throw new Error(`Current data owner can't access any key of patient ${p.id}.`);
|
|
306
323
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
324
|
+
else {
|
|
325
|
+
const cryptedCopyWithRandomKey = yield (0, utils_1.crypt)(_.cloneDeep(patientWithInitialisedEks), (obj) => __awaiter(this, void 0, void 0, function* () { return Promise.resolve(new ArrayBuffer(1)); }), this.encryptedKeys);
|
|
326
|
+
if (!_.isEqual(_.omitBy(Object.assign(Object.assign({}, cryptedCopyWithRandomKey), { encryptedSelf: undefined }), _.isNil), _.omitBy(Object.assign(Object.assign({}, patientWithInitialisedEks), { encryptedSelf: undefined }), _.isNil))) {
|
|
327
|
+
throw Error("You can't modify encrypted data of a patient if you don't have access to his encryption key.");
|
|
328
|
+
}
|
|
329
|
+
return patientWithInitialisedEks;
|
|
330
|
+
}
|
|
331
|
+
})));
|
|
314
332
|
}
|
|
333
|
+
// If patient can't be decrypted returns patient with encrypted data.
|
|
315
334
|
decrypt(user, patients, fillDelegations = true) {
|
|
316
|
-
|
|
317
|
-
|
|
335
|
+
return this.tryDecryptOrReturnOriginal(user, patients, fillDelegations).then((ps) => ps.map((p) => p.patient));
|
|
336
|
+
}
|
|
337
|
+
tryDecryptOrReturnOriginal(user, patients, fillDelegations = true) {
|
|
338
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
339
|
+
const dataOwnerId = this.dataOwnerApi.getDataOwnerOf(user);
|
|
340
|
+
const ids = yield (user.healthcarePartyId ? this.hcpartyApi.getHealthcarePartyHierarchyIds(user.healthcarePartyId) : Promise.resolve([dataOwnerId]));
|
|
318
341
|
//First check that we have no dangling delegation
|
|
319
342
|
const patsWithMissingDelegations = patients.filter((p) => p.delegations &&
|
|
320
343
|
ids.some((id) => p.delegations[id] && !p.delegations[id].length) &&
|
|
@@ -330,10 +353,9 @@ class IccPatientXApi extends icc_api_1.IccPatientApi {
|
|
|
330
353
|
return Promise.all(patients
|
|
331
354
|
.map((p) => acc[p.id] || p)
|
|
332
355
|
.map((p) => __awaiter(this, void 0, void 0, function* () {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
return ((_b = (yield decP)) !== null && _b !== void 0 ? _b : (p.encryptedSelf
|
|
356
|
+
const decryptedPatient = yield ids.reduce((decP, hcpId) => __awaiter(this, void 0, void 0, function* () {
|
|
357
|
+
var _a;
|
|
358
|
+
return ((_a = (yield decP)) !== null && _a !== void 0 ? _a : (p.encryptedSelf
|
|
337
359
|
? yield this.crypto
|
|
338
360
|
.extractKeysFromDelegationsForHcpHierarchy(hcpId, p.id, _.size(p.encryptionKeys) ? p.encryptionKeys : p.delegations)
|
|
339
361
|
.then(({ extractedKeys: sfks }) => {
|
|
@@ -362,9 +384,10 @@ class IccPatientXApi extends icc_api_1.IccPatientApi {
|
|
|
362
384
|
}));
|
|
363
385
|
})
|
|
364
386
|
: p));
|
|
365
|
-
}), Promise.resolve(undefined))
|
|
387
|
+
}), Promise.resolve(undefined));
|
|
388
|
+
return decryptedPatient ? { patient: decryptedPatient, decrypted: true } : { patient: p, decrypted: false };
|
|
366
389
|
})));
|
|
367
|
-
})
|
|
390
|
+
});
|
|
368
391
|
}
|
|
369
392
|
/** By default, an encryptionKey will be added for every hcp in the autoDelegations of the provided user.
|
|
370
393
|
* In optional field additionalDelegateIds, you can ask the method to create encryptionKeys for additional hcps */
|
|
@@ -372,7 +395,7 @@ class IccPatientXApi extends icc_api_1.IccPatientApi {
|
|
|
372
395
|
const dataOwnerId = this.dataOwnerApi.getDataOwnerOf(user);
|
|
373
396
|
const userAutoDelegations = user.autoDelegations ? (user.autoDelegations.all || []).concat(user.autoDelegations.medicalInformation || []) : [];
|
|
374
397
|
return this.crypto.initEncryptionKeys(pat, dataOwnerId).then((eks) => {
|
|
375
|
-
let promise = Promise.resolve(_.extend(pat, {
|
|
398
|
+
let promise = Promise.resolve(_.extend(pat.id === eks.modifiedOwner.id ? eks.modifiedOwner : pat, {
|
|
376
399
|
encryptionKeys: eks.encryptionKeys,
|
|
377
400
|
}));
|
|
378
401
|
new Set([...userAutoDelegations, ...(additionalDelegateIds || [])]).forEach((delegateId) => (promise = promise.then((patient) => this.crypto
|