@icure/api 6.4.0 → 7.0.0-beta.1
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/IccDeviceApi.d.ts +1 -1
- package/icc-api/api/IccDeviceApi.js.map +1 -1
- package/icc-api/api/IccDoctemplateApi.js.map +1 -1
- package/icc-api/api/IccDocumentTemplateApi.js.map +1 -1
- package/icc-api/api/IccHcpartyApi.d.ts +1 -1
- package/icc-api/api/IccHcpartyApi.js.map +1 -1
- package/icc-api/api/IccPatientApi.d.ts +1 -1
- package/icc-api/api/IccPatientApi.js.map +1 -1
- package/icc-api/model/MaintenanceTask.d.ts +6 -5
- package/icc-api/model/MaintenanceTask.js +5 -0
- package/icc-api/model/MaintenanceTask.js.map +1 -1
- package/icc-api/model/User.d.ts +23 -1
- package/icc-api/model/User.js +21 -0
- package/icc-api/model/User.js.map +1 -1
- package/icc-api/model/models.d.ts +14 -0
- package/icc-api/model/models.js.map +1 -1
- package/icc-x-api/crypto/AES.d.ts +2 -0
- package/icc-x-api/crypto/AES.js +12 -0
- package/icc-x-api/crypto/AES.js.map +1 -1
- package/icc-x-api/crypto/BaseExchangeKeysManager.d.ts +122 -0
- package/icc-x-api/crypto/BaseExchangeKeysManager.js +356 -0
- package/icc-x-api/crypto/BaseExchangeKeysManager.js.map +1 -0
- package/icc-x-api/crypto/ConfidentialEntities.d.ts +58 -0
- package/icc-x-api/crypto/ConfidentialEntities.js +99 -0
- package/icc-x-api/crypto/ConfidentialEntities.js.map +1 -0
- package/icc-x-api/crypto/CryptoPrimitives.d.ts +31 -0
- package/icc-x-api/crypto/CryptoPrimitives.js +55 -0
- package/icc-x-api/crypto/CryptoPrimitives.js.map +1 -0
- package/icc-x-api/crypto/CryptoStrategies.d.ts +82 -0
- package/icc-x-api/crypto/CryptoStrategies.js +3 -0
- package/icc-x-api/crypto/CryptoStrategies.js.map +1 -0
- package/icc-x-api/crypto/EntitiesEncryption.d.ts +254 -0
- package/icc-x-api/crypto/EntitiesEncryption.js +700 -0
- package/icc-x-api/crypto/EntitiesEncryption.js.map +1 -0
- package/icc-x-api/crypto/ExchangeKeysManager.d.ts +56 -0
- package/icc-x-api/crypto/ExchangeKeysManager.js +147 -0
- package/icc-x-api/crypto/ExchangeKeysManager.js.map +1 -0
- package/icc-x-api/crypto/KeyManager.d.ts +103 -0
- package/icc-x-api/crypto/KeyManager.js +288 -0
- package/icc-x-api/crypto/KeyManager.js.map +1 -0
- package/icc-x-api/crypto/KeyRecovery.d.ts +34 -0
- package/icc-x-api/crypto/KeyRecovery.js +253 -0
- package/icc-x-api/crypto/KeyRecovery.js.map +1 -0
- package/icc-x-api/crypto/LegacyCryptoStrategies.d.ts +28 -0
- package/icc-x-api/crypto/LegacyCryptoStrategies.js +22 -0
- package/icc-x-api/crypto/LegacyCryptoStrategies.js.map +1 -0
- package/icc-x-api/crypto/RSA.d.ts +19 -20
- package/icc-x-api/crypto/RSA.js +30 -1
- package/icc-x-api/crypto/RSA.js.map +1 -1
- package/icc-x-api/crypto/ShamirKeysManager.d.ts +43 -0
- package/icc-x-api/crypto/ShamirKeysManager.js +150 -0
- package/icc-x-api/crypto/ShamirKeysManager.js.map +1 -0
- package/icc-x-api/crypto/ShareMetadataBehaviour.d.ts +19 -0
- package/icc-x-api/crypto/ShareMetadataBehaviour.js +24 -0
- package/icc-x-api/crypto/ShareMetadataBehaviour.js.map +1 -0
- package/icc-x-api/crypto/TransferKeysManager.d.ts +29 -0
- package/icc-x-api/crypto/TransferKeysManager.js +121 -0
- package/icc-x-api/crypto/TransferKeysManager.js.map +1 -0
- package/icc-x-api/crypto/utils.d.ts +46 -0
- package/icc-x-api/crypto/utils.js +128 -0
- package/icc-x-api/crypto/utils.js.map +1 -1
- package/icc-x-api/filters/ContactByHcPartyTagCodeDateFilter.d.ts +11 -0
- package/icc-x-api/filters/ContactByHcPartyTagCodeDateFilter.js +11 -0
- package/icc-x-api/filters/ContactByHcPartyTagCodeDateFilter.js.map +1 -1
- package/icc-x-api/filters/DeviceByHcPartyFilter.d.ts +11 -0
- package/icc-x-api/filters/DeviceByHcPartyFilter.js +11 -0
- package/icc-x-api/filters/DeviceByHcPartyFilter.js.map +1 -1
- package/icc-x-api/filters/DeviceByIdsFilter.d.ts +11 -0
- package/icc-x-api/filters/DeviceByIdsFilter.js +11 -0
- package/icc-x-api/filters/DeviceByIdsFilter.js.map +1 -1
- package/icc-x-api/filters/HealthElementByHcPartySecretForeignKeysFilter.d.ts +11 -0
- package/icc-x-api/filters/HealthElementByHcPartySecretForeignKeysFilter.js +11 -0
- package/icc-x-api/filters/HealthElementByHcPartySecretForeignKeysFilter.js.map +1 -1
- package/icc-x-api/icc-accesslog-x-api.d.ts +49 -4
- package/icc-x-api/icc-accesslog-x-api.js +112 -102
- package/icc-x-api/icc-accesslog-x-api.js.map +1 -1
- package/icc-x-api/icc-calendar-item-x-api.d.ts +53 -5
- package/icc-x-api/icc-calendar-item-x-api.js +112 -100
- package/icc-x-api/icc-calendar-item-x-api.js.map +1 -1
- package/icc-x-api/icc-classification-x-api.d.ts +45 -2
- package/icc-x-api/icc-classification-x-api.js +89 -41
- package/icc-x-api/icc-classification-x-api.js.map +1 -1
- package/icc-x-api/icc-contact-x-api.d.ts +57 -19
- package/icc-x-api/icc-contact-x-api.js +149 -154
- package/icc-x-api/icc-contact-x-api.js.map +1 -1
- package/icc-x-api/icc-crypto-x-api.d.ts +266 -366
- package/icc-x-api/icc-crypto-x-api.js +416 -1327
- package/icc-x-api/icc-crypto-x-api.js.map +1 -1
- package/icc-x-api/icc-data-owner-x-api.d.ts +110 -11
- package/icc-x-api/icc-data-owner-x-api.js +188 -14
- package/icc-x-api/icc-data-owner-x-api.js.map +1 -1
- package/icc-x-api/icc-doctemplate-x-api.js +3 -3
- package/icc-x-api/icc-doctemplate-x-api.js.map +1 -1
- package/icc-x-api/icc-document-x-api.d.ts +76 -5
- package/icc-x-api/icc-document-x-api.js +137 -59
- package/icc-x-api/icc-document-x-api.js.map +1 -1
- package/icc-x-api/icc-form-x-api.d.ts +47 -7
- package/icc-x-api/icc-form-x-api.js +85 -86
- package/icc-x-api/icc-form-x-api.js.map +1 -1
- package/icc-x-api/icc-hcparty-x-api.d.ts +1 -1
- package/icc-x-api/icc-hcparty-x-api.js +1 -1
- package/icc-x-api/icc-hcparty-x-api.js.map +1 -1
- package/icc-x-api/icc-helement-x-api.d.ts +50 -3
- package/icc-x-api/icc-helement-x-api.js +101 -118
- package/icc-x-api/icc-helement-x-api.js.map +1 -1
- package/icc-x-api/icc-icure-maintenance-x-api.d.ts +31 -0
- package/icc-x-api/icc-icure-maintenance-x-api.js +124 -0
- package/icc-x-api/icc-icure-maintenance-x-api.js.map +1 -0
- package/icc-x-api/icc-invoice-x-api.d.ts +45 -5
- package/icc-x-api/icc-invoice-x-api.js +89 -64
- package/icc-x-api/icc-invoice-x-api.js.map +1 -1
- package/icc-x-api/icc-maintenance-task-x-api.d.ts +38 -6
- package/icc-x-api/icc-maintenance-task-x-api.js +73 -102
- package/icc-x-api/icc-maintenance-task-x-api.js.map +1 -1
- package/icc-x-api/icc-message-x-api.d.ts +55 -2
- package/icc-x-api/icc-message-x-api.js +92 -33
- package/icc-x-api/icc-message-x-api.js.map +1 -1
- package/icc-x-api/icc-patient-x-api.d.ts +67 -7
- package/icc-x-api/icc-patient-x-api.js +409 -473
- package/icc-x-api/icc-patient-x-api.js.map +1 -1
- package/icc-x-api/icc-receipt-x-api.d.ts +49 -5
- package/icc-x-api/icc-receipt-x-api.js +85 -47
- package/icc-x-api/icc-receipt-x-api.js.map +1 -1
- package/icc-x-api/icc-time-table-x-api.d.ts +34 -10
- package/icc-x-api/icc-time-table-x-api.js +61 -18
- package/icc-x-api/icc-time-table-x-api.js.map +1 -1
- package/icc-x-api/index.d.ts +30 -1
- package/icc-x-api/index.js +112 -49
- package/icc-x-api/index.js.map +1 -1
- package/icc-x-api/maintenance/KeyPairUpdateRequest.d.ts +35 -0
- package/icc-x-api/maintenance/KeyPairUpdateRequest.js +54 -0
- package/icc-x-api/maintenance/KeyPairUpdateRequest.js.map +1 -0
- package/icc-x-api/storage/DefaultStorageEntryKeysFactory.d.ts +9 -0
- package/icc-x-api/storage/DefaultStorageEntryKeysFactory.js +23 -0
- package/icc-x-api/storage/DefaultStorageEntryKeysFactory.js.map +1 -0
- package/icc-x-api/storage/IcureStorageFacade.d.ts +55 -0
- package/icc-x-api/storage/IcureStorageFacade.js +95 -0
- package/icc-x-api/storage/IcureStorageFacade.js.map +1 -0
- package/icc-x-api/storage/StorageEntryKeysFactory.d.ts +31 -0
- package/icc-x-api/storage/StorageEntryKeysFactory.js +3 -0
- package/icc-x-api/storage/StorageEntryKeysFactory.js.map +1 -0
- package/icc-x-api/utils/collection-utils.d.ts +8 -0
- package/icc-x-api/utils/collection-utils.js +26 -0
- package/icc-x-api/utils/collection-utils.js.map +1 -0
- package/icc-x-api/utils/crypto-utils.d.ts +8 -1
- package/icc-x-api/utils/crypto-utils.js +19 -3
- package/icc-x-api/utils/crypto-utils.js.map +1 -1
- package/icc-x-api/utils/graph-utils.d.ts +45 -0
- package/icc-x-api/utils/graph-utils.js +203 -0
- package/icc-x-api/utils/graph-utils.js.map +1 -0
- package/icc-x-api/utils/lru-temporised-async-cache.d.ts +27 -0
- package/icc-x-api/utils/lru-temporised-async-cache.js +120 -0
- package/icc-x-api/utils/lru-temporised-async-cache.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,150 @@
|
|
|
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.ShamirKeysManager = void 0;
|
|
13
|
+
const utils_1 = require("../utils");
|
|
14
|
+
/**
|
|
15
|
+
* Allows to create or update shamir split keys.
|
|
16
|
+
*/
|
|
17
|
+
class ShamirKeysManager {
|
|
18
|
+
constructor(primitives, dataOwnerApi, keyManager, exchangeKeysManager) {
|
|
19
|
+
this.primitives = primitives;
|
|
20
|
+
this.dataOwnerApi = dataOwnerApi;
|
|
21
|
+
this.keyManager = keyManager;
|
|
22
|
+
this.exchangeKeysManager = exchangeKeysManager;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get information on existing private keys splits for the provided data owner. For each private key of the provided data owner which has been
|
|
26
|
+
* split using the Shamir sharing algorithm gives the list of the notaries (other data owners) which hold a copy of the key part.
|
|
27
|
+
* @param dataOwner a data owner
|
|
28
|
+
* @return the existing splits for the current data owner as a publicKeyFingerprint -> notariesIds object
|
|
29
|
+
*/
|
|
30
|
+
getExistingSplitsInfo(dataOwner) {
|
|
31
|
+
var _a, _b;
|
|
32
|
+
const legacyPartitionDelegates = Object.keys((_a = dataOwner.privateKeyShamirPartitions) !== null && _a !== void 0 ? _a : {});
|
|
33
|
+
if (legacyPartitionDelegates.length > 0) {
|
|
34
|
+
const fp = (_b = dataOwner.publicKey) === null || _b === void 0 ? void 0 : _b.slice(-32);
|
|
35
|
+
if (!fp) {
|
|
36
|
+
console.error('Invalid data owner: the owner has legacy key partitions but no legacy key.');
|
|
37
|
+
}
|
|
38
|
+
else
|
|
39
|
+
return { [fp]: legacyPartitionDelegates };
|
|
40
|
+
}
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Creates, updates or deletes shamir splits for keys of the current data owner. Any request to update the splits for a specific key will completely
|
|
45
|
+
* replace any existing data on that split (all previous notaries will be ignored).
|
|
46
|
+
* Note: currently you can only split the legacy key pair.
|
|
47
|
+
* @param keySplitsToUpdate the fingerprints of key pairs which will have updated/new splits and the details on how to create the updated splits.
|
|
48
|
+
* @param keySplitsToDelete the fingerprints or hex-encoded spki public keys which will not be shared anymore.
|
|
49
|
+
* @throws if the parameters refer to non-existing or unavailable keys, have split creation details, or if they request to delete a non-existing
|
|
50
|
+
* split.
|
|
51
|
+
*/
|
|
52
|
+
updateSelfSplits(keySplitsToUpdate, keySplitsToDelete) {
|
|
53
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
+
const self = yield this.dataOwnerApi.getCurrentDataOwner();
|
|
55
|
+
const toUpdateSet = new Set(Object.keys(keySplitsToUpdate).map((x) => x.slice(-32)));
|
|
56
|
+
const toDeleteSet = new Set(keySplitsToDelete.slice(-32));
|
|
57
|
+
const intersection = Array.from(toDeleteSet).filter((x) => toUpdateSet.has(x));
|
|
58
|
+
const existingSplits = new Set(Object.keys(this.getExistingSplitsInfo(self.dataOwner)));
|
|
59
|
+
const allKeys = this.keyManager.getDecryptionKeys();
|
|
60
|
+
if (toDeleteSet.size !== keySplitsToDelete.length || toUpdateSet.size !== Object.keys(keySplitsToUpdate).length || intersection.length > 0)
|
|
61
|
+
throw new Error(`Duplicate keys in input:\nkeySplitsToUpdate: ${keySplitsToUpdate}\nkeySplitsToDelete: ${keySplitsToDelete}`);
|
|
62
|
+
Object.entries(keySplitsToUpdate).forEach(([key, params]) => this.validateShamirParams(key, params));
|
|
63
|
+
if (!Array.from(existingSplits).every((x) => existingSplits.has(x))) {
|
|
64
|
+
throw new Error(`Requested to delete non-existing split.\nexistingSplits: ${Array.from(existingSplits)}\ntoDelete:${Array.from(toDeleteSet)}`);
|
|
65
|
+
}
|
|
66
|
+
if (Array.from(toUpdateSet).some((x) => !allKeys[x])) {
|
|
67
|
+
throw new Error(`Private key is not available for some of the requested key split updates. ${keySplitsToUpdate}`);
|
|
68
|
+
}
|
|
69
|
+
const delegatesKeys = {};
|
|
70
|
+
let updatedSelf = self;
|
|
71
|
+
for (const delegateId of new Set(Object.values(keySplitsToUpdate).flatMap((x) => x.notariesIds))) {
|
|
72
|
+
const res = yield this.exchangeKeysManager.getOrCreateEncryptionExchangeKeysTo(delegateId);
|
|
73
|
+
delegatesKeys[delegateId] = res.keys[0];
|
|
74
|
+
if (res.updatedDelegator) {
|
|
75
|
+
updatedSelf = res.updatedDelegator;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
for (const [key, params] of Object.entries(keySplitsToUpdate)) {
|
|
79
|
+
updatedSelf = yield this.updateKeySplit(updatedSelf, key.slice(-32), params.notariesIds, params.minShares, delegatesKeys, allKeys);
|
|
80
|
+
}
|
|
81
|
+
for (const keyFp of toDeleteSet) {
|
|
82
|
+
updatedSelf = this.deleteKeySplit(updatedSelf, keyFp);
|
|
83
|
+
}
|
|
84
|
+
return yield this.dataOwnerApi.updateDataOwner(updatedSelf);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/*TODO
|
|
88
|
+
* Get suggested recovery keys: analyse transfer keys and shamir to get keys which should be shared with shamir for optimal recovery.
|
|
89
|
+
*/
|
|
90
|
+
validateShamirParams(key, params) {
|
|
91
|
+
if (params.notariesIds.length > 0) {
|
|
92
|
+
if (params.minShares > params.notariesIds.length) {
|
|
93
|
+
throw new Error(`Invalid parameters for key ${key}: min shares can't be greater than the number of delegates. ${params}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else
|
|
97
|
+
throw new Error(`Invalid parameters for key ${key}: must have at least one delegate. ${params}`);
|
|
98
|
+
}
|
|
99
|
+
deleteKeySplit(dataOwner, keyFp) {
|
|
100
|
+
var _a;
|
|
101
|
+
if (keyFp !== ((_a = dataOwner.dataOwner.publicKey) === null || _a === void 0 ? void 0 : _a.slice(-32))) {
|
|
102
|
+
throw new Error('Currently it is possible to use shamir splits only for the legacy public key');
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
type: dataOwner.type,
|
|
106
|
+
dataOwner: Object.assign(Object.assign({}, dataOwner.dataOwner), { privateKeyShamirPartitions: {} }),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
updateKeySplit(dataOwner, keyFp, delegateIds, minShares, delegatesKeys, allKeys) {
|
|
110
|
+
var _a;
|
|
111
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
112
|
+
if (keyFp !== ((_a = dataOwner.dataOwner.publicKey) === null || _a === void 0 ? void 0 : _a.slice(-32))) {
|
|
113
|
+
throw new Error('Currently it is possible to use shamir splits only for the legacy public key');
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
type: dataOwner.type,
|
|
117
|
+
dataOwner: Object.assign(Object.assign({}, dataOwner.dataOwner), { privateKeyShamirPartitions: yield this.createPartitionsFor(allKeys[keyFp], delegateIds, minShares, delegatesKeys) }),
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
createPartitionsFor(keyPair, delegateIds, minShares, delegatesKeys) {
|
|
122
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
123
|
+
const exportedKey = yield this.primitives.RSA.exportKey(keyPair.privateKey, 'pkcs8');
|
|
124
|
+
if (delegateIds.length == 1) {
|
|
125
|
+
return yield this.encryptShares([exportedKey], delegateIds, delegatesKeys);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
const exportedKeysHex = (0, utils_1.ua2hex)(exportedKey);
|
|
129
|
+
const stringShares = this.primitives.shamir.share(exportedKeysHex, delegateIds.length, minShares);
|
|
130
|
+
const paddedStringShares = stringShares.map((x) => `f${x}`); // Shares are uneven length, apart from that they are perfect hexes
|
|
131
|
+
for (const share of paddedStringShares) {
|
|
132
|
+
if (!/^(?:[0-9a-f][0-9a-f])+$/g.test(share))
|
|
133
|
+
throw new Error('Unexpected result of shamir split: padded shares should be a valid hex value');
|
|
134
|
+
if (share !== (0, utils_1.ua2hex)((0, utils_1.hex2ua)(share)))
|
|
135
|
+
throw new Error('Unexpected result with encoding-decoding share');
|
|
136
|
+
}
|
|
137
|
+
return yield this.encryptShares(paddedStringShares.map((x) => (0, utils_1.hex2ua)(x)), delegateIds, delegatesKeys);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
encryptShares(shares, delegateIds, delegatesKeys) {
|
|
142
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
143
|
+
return delegateIds.reduce((acc, delegateId, index) => __awaiter(this, void 0, void 0, function* () {
|
|
144
|
+
return (Object.assign(Object.assign({}, (yield acc)), { [delegateId]: (0, utils_1.ua2hex)(yield this.primitives.AES.encrypt(delegatesKeys[delegateId], shares[index])) }));
|
|
145
|
+
}), Promise.resolve({}));
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
exports.ShamirKeysManager = ShamirKeysManager;
|
|
150
|
+
//# sourceMappingURL=ShamirKeysManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShamirKeysManager.js","sourceRoot":"","sources":["../../../icc-x-api/crypto/ShamirKeysManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { DataOwner, DataOwnerWithType, IccDataOwnerXApi } from '../icc-data-owner-x-api'\nimport { KeyManager } from './KeyManager'\nimport { ExchangeKeysManager } from './ExchangeKeysManager'\nimport { CryptoPrimitives } from './CryptoPrimitives'\nimport { KeyPair } from './RSA'\nimport { hex2ua, ua2hex } from '../utils'\n\n/**\n * Allows to create or update shamir split keys.\n */\nexport class ShamirKeysManager {\n private readonly primitives: CryptoPrimitives\n private readonly dataOwnerApi: IccDataOwnerXApi\n private readonly keyManager: KeyManager\n private readonly exchangeKeysManager: ExchangeKeysManager\n\n constructor(primitives: CryptoPrimitives, dataOwnerApi: IccDataOwnerXApi, keyManager: KeyManager, exchangeKeysManager: ExchangeKeysManager) {\n this.primitives = primitives\n this.dataOwnerApi = dataOwnerApi\n this.keyManager = keyManager\n this.exchangeKeysManager = exchangeKeysManager\n }\n\n /**\n * Get information on existing private keys splits for the provided data owner. For each private key of the provided data owner which has been\n * split using the Shamir sharing algorithm gives the list of the notaries (other data owners) which hold a copy of the key part.\n * @param dataOwner a data owner\n * @return the existing splits for the current data owner as a publicKeyFingerprint -> notariesIds object\n */\n getExistingSplitsInfo(dataOwner: DataOwner): { [keyPairFingerprint: string]: string[] } {\n const legacyPartitionDelegates = Object.keys(dataOwner.privateKeyShamirPartitions ?? {})\n if (legacyPartitionDelegates.length > 0) {\n const fp = dataOwner.publicKey?.slice(-32)\n if (!fp) {\n console.error('Invalid data owner: the owner has legacy key partitions but no legacy key.')\n } else return { [fp]: legacyPartitionDelegates }\n }\n return {}\n }\n\n /**\n * Creates, updates or deletes shamir splits for keys of the current data owner. Any request to update the splits for a specific key will completely\n * replace any existing data on that split (all previous notaries will be ignored).\n * Note: currently you can only split the legacy key pair.\n * @param keySplitsToUpdate the fingerprints of key pairs which will have updated/new splits and the details on how to create the updated splits.\n * @param keySplitsToDelete the fingerprints or hex-encoded spki public keys which will not be shared anymore.\n * @throws if the parameters refer to non-existing or unavailable keys, have split creation details, or if they request to delete a non-existing\n * split.\n */\n async updateSelfSplits(\n keySplitsToUpdate: { [publicKeyHexOrFp: string]: { notariesIds: string[]; minShares: number } },\n keySplitsToDelete: string[]\n ): Promise<DataOwnerWithType> {\n const self = await this.dataOwnerApi.getCurrentDataOwner()\n const toUpdateSet = new Set(Object.keys(keySplitsToUpdate).map((x) => x.slice(-32)))\n const toDeleteSet = new Set(keySplitsToDelete.slice(-32))\n const intersection = Array.from(toDeleteSet).filter((x) => toUpdateSet.has(x))\n const existingSplits = new Set(Object.keys(this.getExistingSplitsInfo(self.dataOwner)))\n const allKeys = this.keyManager.getDecryptionKeys()\n if (toDeleteSet.size !== keySplitsToDelete.length || toUpdateSet.size !== Object.keys(keySplitsToUpdate).length || intersection.length > 0)\n throw new Error(`Duplicate keys in input:\\nkeySplitsToUpdate: ${keySplitsToUpdate}\\nkeySplitsToDelete: ${keySplitsToDelete}`)\n Object.entries(keySplitsToUpdate).forEach(([key, params]) => this.validateShamirParams(key, params))\n if (!Array.from(existingSplits).every((x) => existingSplits.has(x))) {\n throw new Error(`Requested to delete non-existing split.\\nexistingSplits: ${Array.from(existingSplits)}\\ntoDelete:${Array.from(toDeleteSet)}`)\n }\n if (Array.from(toUpdateSet).some((x) => !allKeys[x])) {\n throw new Error(`Private key is not available for some of the requested key split updates. ${keySplitsToUpdate}`)\n }\n const delegatesKeys: { [delegateId: string]: CryptoKey } = {}\n let updatedSelf = self\n for (const delegateId of new Set(Object.values(keySplitsToUpdate).flatMap((x) => x.notariesIds))) {\n const res = await this.exchangeKeysManager.getOrCreateEncryptionExchangeKeysTo(delegateId)\n delegatesKeys[delegateId] = res.keys[0]\n if (res.updatedDelegator) {\n updatedSelf = res.updatedDelegator\n }\n }\n for (const [key, params] of Object.entries(keySplitsToUpdate)) {\n updatedSelf = await this.updateKeySplit(updatedSelf, key.slice(-32), params.notariesIds, params.minShares, delegatesKeys, allKeys)\n }\n for (const keyFp of toDeleteSet) {\n updatedSelf = this.deleteKeySplit(updatedSelf, keyFp)\n }\n return await this.dataOwnerApi.updateDataOwner(updatedSelf)\n }\n\n /*TODO\n * Get suggested recovery keys: analyse transfer keys and shamir to get keys which should be shared with shamir for optimal recovery.\n */\n\n private validateShamirParams(key: string, params: { notariesIds: string[]; minShares: number }) {\n if (params.notariesIds.length > 0) {\n if (params.minShares > params.notariesIds.length) {\n throw new Error(`Invalid parameters for key ${key}: min shares can't be greater than the number of delegates. ${params}`)\n }\n } else throw new Error(`Invalid parameters for key ${key}: must have at least one delegate. ${params}`)\n }\n\n private deleteKeySplit(dataOwner: DataOwnerWithType, keyFp: string): DataOwnerWithType {\n if (keyFp !== dataOwner.dataOwner.publicKey?.slice(-32)) {\n throw new Error('Currently it is possible to use shamir splits only for the legacy public key')\n }\n return {\n type: dataOwner.type,\n dataOwner: {\n ...dataOwner.dataOwner,\n privateKeyShamirPartitions: {},\n },\n }\n }\n\n private async updateKeySplit(\n dataOwner: DataOwnerWithType,\n keyFp: string,\n delegateIds: string[],\n minShares: number,\n delegatesKeys: { [p: string]: CryptoKey },\n allKeys: { [p: string]: KeyPair<CryptoKey> }\n ): Promise<DataOwnerWithType> {\n if (keyFp !== dataOwner.dataOwner.publicKey?.slice(-32)) {\n throw new Error('Currently it is possible to use shamir splits only for the legacy public key')\n }\n return {\n type: dataOwner.type,\n dataOwner: {\n ...dataOwner.dataOwner,\n privateKeyShamirPartitions: await this.createPartitionsFor(allKeys[keyFp], delegateIds, minShares, delegatesKeys),\n },\n }\n }\n\n private async createPartitionsFor(\n keyPair: KeyPair<CryptoKey>,\n delegateIds: string[],\n minShares: number,\n delegatesKeys: { [p: string]: CryptoKey }\n ): Promise<{ [delegateId: string]: string }> {\n const exportedKey = await this.primitives.RSA.exportKey(keyPair.privateKey, 'pkcs8')\n if (delegateIds.length == 1) {\n return await this.encryptShares([exportedKey], delegateIds, delegatesKeys)\n } else {\n const exportedKeysHex = ua2hex(exportedKey)\n const stringShares = this.primitives.shamir.share(exportedKeysHex, delegateIds.length, minShares)\n const paddedStringShares = stringShares.map((x) => `f${x}`) // Shares are uneven length, apart from that they are perfect hexes\n for (const share of paddedStringShares) {\n if (!/^(?:[0-9a-f][0-9a-f])+$/g.test(share)) throw new Error('Unexpected result of shamir split: padded shares should be a valid hex value')\n if (share !== ua2hex(hex2ua(share))) throw new Error('Unexpected result with encoding-decoding share')\n }\n return await this.encryptShares(\n paddedStringShares.map((x) => hex2ua(x)),\n delegateIds,\n delegatesKeys\n )\n }\n }\n\n private async encryptShares(\n shares: ArrayBuffer[],\n delegateIds: string[],\n delegatesKeys: { [p: string]: CryptoKey }\n ): Promise<{ [delegateId: string]: string }> {\n return delegateIds.reduce(\n async (acc, delegateId, index) => ({\n ...(await acc),\n [delegateId]: ua2hex(await this.primitives.AES.encrypt(delegatesKeys[delegateId], shares[index])),\n }),\n Promise.resolve({} as { [delegateId: string]: string })\n )\n }\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Specifies a behaviour for the sharing of encryption keys or owning entity ids in the extended apis 'share' methods.
|
|
3
|
+
*/
|
|
4
|
+
export declare enum ShareMetadataBehaviour {
|
|
5
|
+
/**
|
|
6
|
+
* The method must share the metadata with the delegate. If this is not possible, because for example the current user has no access to this kind of
|
|
7
|
+
* metadata, the method will throw an error.
|
|
8
|
+
*/
|
|
9
|
+
REQUIRED = "REQUIRED",
|
|
10
|
+
/**
|
|
11
|
+
* The method must share the metadata with the delegate if available. If this is not possible, because for example the current user has no access to
|
|
12
|
+
* this kind of metadata, the method will simply not share this metadata.
|
|
13
|
+
*/
|
|
14
|
+
IF_AVAILABLE = "IF_AVAILABLE",
|
|
15
|
+
/**
|
|
16
|
+
* The method must not share the metadata with the delegate, even if the current data owner can access it.
|
|
17
|
+
*/
|
|
18
|
+
NEVER = "NEVER"
|
|
19
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ShareMetadataBehaviour = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Specifies a behaviour for the sharing of encryption keys or owning entity ids in the extended apis 'share' methods.
|
|
6
|
+
*/
|
|
7
|
+
var ShareMetadataBehaviour;
|
|
8
|
+
(function (ShareMetadataBehaviour) {
|
|
9
|
+
/**
|
|
10
|
+
* The method must share the metadata with the delegate. If this is not possible, because for example the current user has no access to this kind of
|
|
11
|
+
* metadata, the method will throw an error.
|
|
12
|
+
*/
|
|
13
|
+
ShareMetadataBehaviour["REQUIRED"] = "REQUIRED";
|
|
14
|
+
/**
|
|
15
|
+
* The method must share the metadata with the delegate if available. If this is not possible, because for example the current user has no access to
|
|
16
|
+
* this kind of metadata, the method will simply not share this metadata.
|
|
17
|
+
*/
|
|
18
|
+
ShareMetadataBehaviour["IF_AVAILABLE"] = "IF_AVAILABLE";
|
|
19
|
+
/**
|
|
20
|
+
* The method must not share the metadata with the delegate, even if the current data owner can access it.
|
|
21
|
+
*/
|
|
22
|
+
ShareMetadataBehaviour["NEVER"] = "NEVER";
|
|
23
|
+
})(ShareMetadataBehaviour = exports.ShareMetadataBehaviour || (exports.ShareMetadataBehaviour = {}));
|
|
24
|
+
//# sourceMappingURL=ShareMetadataBehaviour.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShareMetadataBehaviour.js","sourceRoot":"","sources":["../../../icc-x-api/crypto/ShareMetadataBehaviour.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,IAAY,sBAeX;AAfD,WAAY,sBAAsB;IAChC;;;OAGG;IACH,+CAAqB,CAAA;IACrB;;;OAGG;IACH,uDAA6B,CAAA;IAC7B;;OAEG;IACH,yCAAe,CAAA;AACjB,CAAC,EAfW,sBAAsB,GAAtB,8BAAsB,KAAtB,8BAAsB,QAejC","sourcesContent":["/**\n * Specifies a behaviour for the sharing of encryption keys or owning entity ids in the extended apis 'share' methods.\n */\nexport enum ShareMetadataBehaviour {\n /**\n * The method must share the metadata with the delegate. If this is not possible, because for example the current user has no access to this kind of\n * metadata, the method will throw an error.\n */\n REQUIRED = 'REQUIRED',\n /**\n * The method must share the metadata with the delegate if available. If this is not possible, because for example the current user has no access to\n * this kind of metadata, the method will simply not share this metadata.\n */\n IF_AVAILABLE = 'IF_AVAILABLE',\n /**\n * The method must not share the metadata with the delegate, even if the current data owner can access it.\n */\n NEVER = 'NEVER',\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BaseExchangeKeysManager } from './BaseExchangeKeysManager';
|
|
2
|
+
import { DataOwnerWithType, IccDataOwnerXApi } from '../icc-data-owner-x-api';
|
|
3
|
+
import { KeyManager } from './KeyManager';
|
|
4
|
+
import { CryptoPrimitives } from './CryptoPrimitives';
|
|
5
|
+
import { IcureStorageFacade } from '../storage/IcureStorageFacade';
|
|
6
|
+
/**
|
|
7
|
+
* @internal this class is intended only for internal use and may be changed without notice.
|
|
8
|
+
* Allows to create new transfer keys.
|
|
9
|
+
*/
|
|
10
|
+
export declare class TransferKeysManager {
|
|
11
|
+
private readonly primitives;
|
|
12
|
+
private readonly baseExchangeKeysManager;
|
|
13
|
+
private readonly dataOwnerApi;
|
|
14
|
+
private readonly keyManager;
|
|
15
|
+
private readonly icureStorage;
|
|
16
|
+
constructor(primitives: CryptoPrimitives, baseExchangeKeysManager: BaseExchangeKeysManager, dataOwnerApi: IccDataOwnerXApi, keyManager: KeyManager, icureStorage: IcureStorageFacade);
|
|
17
|
+
/**
|
|
18
|
+
* Analyses the transfer keys graph and creates new transfer keys which allow to improve data accessibility from other devices.
|
|
19
|
+
* For security reasons transfer keys will only be created between keys verified by the user, but this will be done ignoring any existing edges from
|
|
20
|
+
* unverified keys to verified keys.
|
|
21
|
+
* @param self the current data owner.
|
|
22
|
+
* @return the updated data owner.
|
|
23
|
+
*/
|
|
24
|
+
updateTransferKeys(self: DataOwnerWithType): Promise<void>;
|
|
25
|
+
private encryptTransferKey;
|
|
26
|
+
private transferKeysCandidatesFp;
|
|
27
|
+
private transferTargetVerifiedKey;
|
|
28
|
+
private getNewVerifiedTransferKeysEdges;
|
|
29
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
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.TransferKeysManager = void 0;
|
|
13
|
+
const utils_1 = require("../utils");
|
|
14
|
+
const graph_utils_1 = require("../utils/graph-utils");
|
|
15
|
+
const utils_2 = require("./utils");
|
|
16
|
+
/**
|
|
17
|
+
* @internal this class is intended only for internal use and may be changed without notice.
|
|
18
|
+
* Allows to create new transfer keys.
|
|
19
|
+
*/
|
|
20
|
+
class TransferKeysManager {
|
|
21
|
+
constructor(primitives, baseExchangeKeysManager, dataOwnerApi, keyManager, icureStorage) {
|
|
22
|
+
this.primitives = primitives;
|
|
23
|
+
this.baseExchangeKeysManager = baseExchangeKeysManager;
|
|
24
|
+
this.dataOwnerApi = dataOwnerApi;
|
|
25
|
+
this.keyManager = keyManager;
|
|
26
|
+
this.icureStorage = icureStorage;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Analyses the transfer keys graph and creates new transfer keys which allow to improve data accessibility from other devices.
|
|
30
|
+
* For security reasons transfer keys will only be created between keys verified by the user, but this will be done ignoring any existing edges from
|
|
31
|
+
* unverified keys to verified keys.
|
|
32
|
+
* @param self the current data owner.
|
|
33
|
+
* @return the updated data owner.
|
|
34
|
+
*/
|
|
35
|
+
updateTransferKeys(self) {
|
|
36
|
+
var _a;
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
const newEdges = yield this.getNewVerifiedTransferKeysEdges(self);
|
|
39
|
+
if (!newEdges)
|
|
40
|
+
return;
|
|
41
|
+
const selfId = yield this.dataOwnerApi.getCurrentDataOwnerId();
|
|
42
|
+
const fpToPublicKey = (0, utils_2.fingerprintToPublicKeysMapOf)(self.dataOwner);
|
|
43
|
+
const newExchangeKeyPublicKeys = newEdges.sources.map((fp) => fpToPublicKey[fp]);
|
|
44
|
+
const { key: exchangeKey, updatedDelegator: updatedSelf } = yield this.baseExchangeKeysManager.createOrUpdateEncryptedExchangeKeyTo(selfId, newEdges.target, yield (0, utils_2.loadPublicKeys)(this.primitives.RSA, newExchangeKeyPublicKeys));
|
|
45
|
+
// note: createEncryptedExchangeKeyFor may update self
|
|
46
|
+
const encryptedTransferKey = yield this.encryptTransferKey(newEdges.target, exchangeKey);
|
|
47
|
+
const newTransferKeys = newEdges.sources.reduce((acc, candidateFp) => {
|
|
48
|
+
var _a;
|
|
49
|
+
const existingKeys = Object.assign({}, ((_a = acc[candidateFp]) !== null && _a !== void 0 ? _a : {}));
|
|
50
|
+
existingKeys[newEdges.targetFp] = encryptedTransferKey;
|
|
51
|
+
acc[candidateFp] = existingKeys;
|
|
52
|
+
return acc;
|
|
53
|
+
}, Object.assign({}, ((_a = updatedSelf.dataOwner.transferKeys) !== null && _a !== void 0 ? _a : {})));
|
|
54
|
+
yield this.dataOwnerApi.updateDataOwner({
|
|
55
|
+
type: updatedSelf.type,
|
|
56
|
+
dataOwner: Object.assign(Object.assign({}, updatedSelf.dataOwner), { transferKeys: newTransferKeys }),
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
// encrypts a transfer key in pkcs8 format using an exchange key, returns the hex representation
|
|
61
|
+
encryptTransferKey(transferKey, exchangeKey) {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
const exportedKey = yield this.primitives.RSA.exportKey(transferKey.privateKey, 'pkcs8');
|
|
64
|
+
return (0, utils_1.ua2hex)(yield this.primitives.AES.encrypt(exchangeKey, exportedKey));
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
// all public keys would go to the stored keys -> no need for specifying the key.
|
|
68
|
+
// Result only includes the acyclic label, not the full group
|
|
69
|
+
transferKeysCandidatesFp(keyToFp, graph) {
|
|
70
|
+
return Object.entries((0, graph_utils_1.reachSetsAcyclic)(graph.acyclicGraph))
|
|
71
|
+
.filter(([from, reachable]) => from != keyToFp && !reachable.has(keyToFp))
|
|
72
|
+
.map((x) => x[0]);
|
|
73
|
+
}
|
|
74
|
+
transferTargetVerifiedKey(keyManager) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
return keyManager.getSelfVerifiedKeys()[0];
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
// Decides the best edges considering the verified public keys.
|
|
80
|
+
getNewVerifiedTransferKeysEdges(self) {
|
|
81
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
const verifiedKeysFpSet = new Set(this.keyManager.getSelfVerifiedKeys().map((x) => x.fingerprint));
|
|
83
|
+
Object.entries(yield this.icureStorage.loadSelfVerifiedKeys(self.dataOwner.id)).forEach(([key, verified]) => {
|
|
84
|
+
if (verified)
|
|
85
|
+
verifiedKeysFpSet.add(key.slice(-32));
|
|
86
|
+
});
|
|
87
|
+
if (verifiedKeysFpSet.size == 0)
|
|
88
|
+
return undefined;
|
|
89
|
+
const graph = (0, utils_2.transferKeysFpGraphOf)(self.dataOwner);
|
|
90
|
+
// 1. Choose a key available in this device which should be reachable from all other verified keys
|
|
91
|
+
const { fingerprint: targetKeyFp, pair: targetKey } = yield this.transferTargetVerifiedKey(this.keyManager);
|
|
92
|
+
// 2. Find groups which can't reach the existing target keys
|
|
93
|
+
const candidatesFp = this.transferKeysCandidatesFp(targetKeyFp, graph);
|
|
94
|
+
// 3. Keep only groups which contain at least a verified candidate
|
|
95
|
+
const verifiedGroupCandidates = candidatesFp.filter((candidate) => graph.acyclicLabelToGroup[candidate].some((candidateGroupMember) => verifiedKeysFpSet.has(candidateGroupMember)));
|
|
96
|
+
const verifiedCandidatesSet = new Set(verifiedGroupCandidates);
|
|
97
|
+
if (verifiedCandidatesSet.size == 0)
|
|
98
|
+
return undefined;
|
|
99
|
+
// 4. Drop all candidates which can already reach another candidate group: it is sufficient to create a transfer key from that group.
|
|
100
|
+
const reachSets = (0, graph_utils_1.reachSetsAcyclic)(graph.acyclicGraph);
|
|
101
|
+
const optimizedCandidates = verifiedGroupCandidates.filter((candidate) => Array.from(reachSets[candidate]).every((reachableNode) => !verifiedCandidatesSet.has(reachableNode)));
|
|
102
|
+
if (optimizedCandidates.length == 0)
|
|
103
|
+
throw new Error('Check failed: at least one candidate should survive optimization');
|
|
104
|
+
// 5. Transfer keys could also be faked: to make sure we are not giving access to unauthorised people we remap the candidates to a verified public
|
|
105
|
+
// keys
|
|
106
|
+
const verifiedOptimizedCandidates = optimizedCandidates.map((candidate) => {
|
|
107
|
+
const res = graph.acyclicLabelToGroup[candidate].find((groupMemberFp) => verifiedKeysFpSet.has(groupMemberFp));
|
|
108
|
+
if (!res)
|
|
109
|
+
throw new Error('Check failed: optimized candidates groups should have at least a verified member');
|
|
110
|
+
return res;
|
|
111
|
+
});
|
|
112
|
+
return {
|
|
113
|
+
sources: verifiedOptimizedCandidates,
|
|
114
|
+
target: targetKey,
|
|
115
|
+
targetFp: targetKeyFp,
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
exports.TransferKeysManager = TransferKeysManager;
|
|
121
|
+
//# sourceMappingURL=TransferKeysManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TransferKeysManager.js","sourceRoot":"","sources":["../../../icc-x-api/crypto/TransferKeysManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyPair } from './RSA'\nimport { BaseExchangeKeysManager } from './BaseExchangeKeysManager'\nimport { DataOwnerWithType, IccDataOwnerXApi } from '../icc-data-owner-x-api'\nimport { ua2hex } from '../utils'\nimport { KeyManager } from './KeyManager'\nimport { reachSetsAcyclic, StronglyConnectedGraph } from '../utils/graph-utils'\nimport { fingerprintToPublicKeysMapOf, loadPublicKeys, transferKeysFpGraphOf } from './utils'\nimport { CryptoPrimitives } from './CryptoPrimitives'\nimport { IcureStorageFacade } from '../storage/IcureStorageFacade'\n\n/**\n * @internal this class is intended only for internal use and may be changed without notice.\n * Allows to create new transfer keys.\n */\nexport class TransferKeysManager {\n private readonly primitives: CryptoPrimitives\n private readonly baseExchangeKeysManager: BaseExchangeKeysManager\n private readonly dataOwnerApi: IccDataOwnerXApi\n private readonly keyManager: KeyManager\n private readonly icureStorage: IcureStorageFacade\n\n constructor(\n primitives: CryptoPrimitives,\n baseExchangeKeysManager: BaseExchangeKeysManager,\n dataOwnerApi: IccDataOwnerXApi,\n keyManager: KeyManager,\n icureStorage: IcureStorageFacade\n ) {\n this.primitives = primitives\n this.baseExchangeKeysManager = baseExchangeKeysManager\n this.dataOwnerApi = dataOwnerApi\n this.keyManager = keyManager\n this.icureStorage = icureStorage\n }\n\n /**\n * Analyses the transfer keys graph and creates new transfer keys which allow to improve data accessibility from other devices.\n * For security reasons transfer keys will only be created between keys verified by the user, but this will be done ignoring any existing edges from\n * unverified keys to verified keys.\n * @param self the current data owner.\n * @return the updated data owner.\n */\n async updateTransferKeys(self: DataOwnerWithType): Promise<void> {\n const newEdges = await this.getNewVerifiedTransferKeysEdges(self)\n if (!newEdges) return\n const selfId = await this.dataOwnerApi.getCurrentDataOwnerId()\n const fpToPublicKey = fingerprintToPublicKeysMapOf(self.dataOwner)\n const newExchangeKeyPublicKeys = newEdges.sources.map((fp) => fpToPublicKey[fp])\n const { key: exchangeKey, updatedDelegator: updatedSelf } = await this.baseExchangeKeysManager.createOrUpdateEncryptedExchangeKeyTo(\n selfId,\n newEdges.target,\n await loadPublicKeys(this.primitives.RSA, newExchangeKeyPublicKeys)\n )\n // note: createEncryptedExchangeKeyFor may update self\n const encryptedTransferKey = await this.encryptTransferKey(newEdges.target, exchangeKey)\n const newTransferKeys = newEdges.sources.reduce(\n (acc, candidateFp) => {\n const existingKeys = { ...(acc[candidateFp] ?? {}) }\n existingKeys[newEdges.targetFp] = encryptedTransferKey\n acc[candidateFp] = existingKeys\n return acc\n },\n { ...(updatedSelf.dataOwner.transferKeys ?? {}) }\n )\n await this.dataOwnerApi.updateDataOwner({\n type: updatedSelf.type,\n dataOwner: {\n ...updatedSelf.dataOwner,\n transferKeys: newTransferKeys,\n },\n })\n }\n\n // encrypts a transfer key in pkcs8 format using an exchange key, returns the hex representation\n private async encryptTransferKey(transferKey: KeyPair<CryptoKey>, exchangeKey: CryptoKey): Promise<string> {\n const exportedKey = await this.primitives.RSA.exportKey(transferKey.privateKey, 'pkcs8')\n return ua2hex(await this.primitives.AES.encrypt(exchangeKey, exportedKey))\n }\n\n // all public keys would go to the stored keys -> no need for specifying the key.\n // Result only includes the acyclic label, not the full group\n private transferKeysCandidatesFp(keyToFp: string, graph: StronglyConnectedGraph): string[] {\n return Object.entries(reachSetsAcyclic(graph.acyclicGraph))\n .filter(([from, reachable]) => from != keyToFp && !reachable.has(keyToFp))\n .map((x) => x[0])\n }\n\n private async transferTargetVerifiedKey(keyManager: KeyManager): Promise<{ fingerprint: string; pair: KeyPair<CryptoKey> }> {\n return keyManager.getSelfVerifiedKeys()[0]\n }\n\n // Decides the best edges considering the verified public keys.\n private async getNewVerifiedTransferKeysEdges(self: DataOwnerWithType): Promise<\n | undefined\n | {\n sources: string[]\n target: KeyPair<CryptoKey>\n targetFp: string\n }\n > {\n const verifiedKeysFpSet = new Set(this.keyManager.getSelfVerifiedKeys().map((x) => x.fingerprint))\n Object.entries(await this.icureStorage.loadSelfVerifiedKeys(self.dataOwner.id!)).forEach(([key, verified]) => {\n if (verified) verifiedKeysFpSet.add(key.slice(-32))\n })\n if (verifiedKeysFpSet.size == 0) return undefined\n const graph = transferKeysFpGraphOf(self.dataOwner)\n // 1. Choose a key available in this device which should be reachable from all other verified keys\n const { fingerprint: targetKeyFp, pair: targetKey } = await this.transferTargetVerifiedKey(this.keyManager)\n // 2. Find groups which can't reach the existing target keys\n const candidatesFp = this.transferKeysCandidatesFp(targetKeyFp, graph)\n // 3. Keep only groups which contain at least a verified candidate\n const verifiedGroupCandidates = candidatesFp.filter((candidate) =>\n graph.acyclicLabelToGroup[candidate].some((candidateGroupMember) => verifiedKeysFpSet.has(candidateGroupMember))\n )\n const verifiedCandidatesSet = new Set(verifiedGroupCandidates)\n if (verifiedCandidatesSet.size == 0) return undefined\n // 4. Drop all candidates which can already reach another candidate group: it is sufficient to create a transfer key from that group.\n const reachSets = reachSetsAcyclic(graph.acyclicGraph)\n const optimizedCandidates = verifiedGroupCandidates.filter((candidate) =>\n Array.from(reachSets[candidate]).every((reachableNode) => !verifiedCandidatesSet.has(reachableNode))\n )\n if (optimizedCandidates.length == 0) throw new Error('Check failed: at least one candidate should survive optimization')\n // 5. Transfer keys could also be faked: to make sure we are not giving access to unauthorised people we remap the candidates to a verified public\n // keys\n const verifiedOptimizedCandidates = optimizedCandidates.map((candidate) => {\n const res = graph.acyclicLabelToGroup[candidate].find((groupMemberFp) => verifiedKeysFpSet.has(groupMemberFp))\n if (!res) throw new Error('Check failed: optimized candidates groups should have at least a verified member')\n return res\n })\n return {\n sources: verifiedOptimizedCandidates,\n target: targetKey,\n targetFp: targetKeyFp,\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { StronglyConnectedGraph } from '../utils/graph-utils';
|
|
2
|
+
import { DataOwner, DataOwnerWithType, IccDataOwnerXApi } from '../icc-data-owner-x-api';
|
|
3
|
+
import { RSAUtils } from './RSA';
|
|
4
|
+
import { EntitiesEncryption } from './EntitiesEncryption';
|
|
5
|
+
import { CryptoPrimitives } from './CryptoPrimitives';
|
|
6
|
+
import { EncryptedEntityStub } from '../../icc-api/model/models';
|
|
7
|
+
/**
|
|
8
|
+
* @internal this function is meant only for internal use and may be changed without notice.
|
|
9
|
+
* Get the public keys of a data owner, same as {@link dataOwnerApi.getHexPublicKeysOf}.
|
|
10
|
+
* @param dataOwner
|
|
11
|
+
*/
|
|
12
|
+
export declare function hexPublicKeysOf(dataOwner: DataOwner): Set<string>;
|
|
13
|
+
/**
|
|
14
|
+
* @internal this function is meant only for internal use and may be changed without notice.
|
|
15
|
+
* Get the transfer key graph for a data owner. Node names are the public key fingerprints of the data owner's keys, and an edge represents a key
|
|
16
|
+
* which can be retrieved from another key using the transfer keys.
|
|
17
|
+
* @param dataOwner a data owner.
|
|
18
|
+
* @return a graph representing the possible key recovery paths using transfer keys for hte provided data owner.
|
|
19
|
+
*/
|
|
20
|
+
export declare function transferKeysFpGraphOf(dataOwner: DataOwner): StronglyConnectedGraph;
|
|
21
|
+
/**
|
|
22
|
+
* @internal this function is meant only for internal use and may be changed without notice.
|
|
23
|
+
* Get a map for converting public keys fingerprint to full public keys for the provided data owner.
|
|
24
|
+
* @param dataOwner a data owner.
|
|
25
|
+
* @return a map to convert fingerprints of the data owner into full public keys.
|
|
26
|
+
*/
|
|
27
|
+
export declare function fingerprintToPublicKeysMapOf(dataOwner: DataOwner): {
|
|
28
|
+
[fp: string]: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* @internal this function is meant only for internal use and may be changed without notice.
|
|
32
|
+
* Load many public keys in spki format.
|
|
33
|
+
* @param rsa the rsa service
|
|
34
|
+
* @param publicKeysSpkiHex public keys in spki format, hex encoded.
|
|
35
|
+
* @return public keys as crypto keys by their fingerprint.
|
|
36
|
+
*/
|
|
37
|
+
export declare function loadPublicKeys(rsa: RSAUtils, publicKeysSpkiHex: string[]): Promise<{
|
|
38
|
+
[publicKeyFingerprint: string]: CryptoKey;
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* @internal This method is intended only for internal use and may be changed without notice.
|
|
42
|
+
* Creates a delegation for the current data owner if the data owner is an encrypted entity and there is no delegation to himself.
|
|
43
|
+
* @return the updated self.
|
|
44
|
+
*/
|
|
45
|
+
export declare function ensureDelegationForSelf(dataOwnerApi: IccDataOwnerXApi, entitiesEncryption: EntitiesEncryption, cryptoPrimitives: CryptoPrimitives): Promise<DataOwnerWithType>;
|
|
46
|
+
export declare function encryptedStubEquals(a: EncryptedEntityStub, b: EncryptedEntityStub): boolean;
|
|
@@ -1,2 +1,130 @@
|
|
|
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.encryptedStubEquals = exports.ensureDelegationForSelf = exports.loadPublicKeys = exports.fingerprintToPublicKeysMapOf = exports.transferKeysFpGraphOf = exports.hexPublicKeysOf = void 0;
|
|
13
|
+
// Uses fp as node names
|
|
14
|
+
const graph_utils_1 = require("../utils/graph-utils");
|
|
15
|
+
const icc_data_owner_x_api_1 = require("../icc-data-owner-x-api");
|
|
16
|
+
const utils_1 = require("../utils");
|
|
17
|
+
const collection_utils_1 = require("../utils/collection-utils");
|
|
18
|
+
/**
|
|
19
|
+
* @internal this function is meant only for internal use and may be changed without notice.
|
|
20
|
+
* Get the public keys of a data owner, same as {@link dataOwnerApi.getHexPublicKeysOf}.
|
|
21
|
+
* @param dataOwner
|
|
22
|
+
*/
|
|
23
|
+
function hexPublicKeysOf(dataOwner) {
|
|
24
|
+
var _a;
|
|
25
|
+
return new Set([dataOwner.publicKey, ...Object.keys((_a = dataOwner.aesExchangeKeys) !== null && _a !== void 0 ? _a : {})].filter((pubKey) => !!pubKey));
|
|
26
|
+
}
|
|
27
|
+
exports.hexPublicKeysOf = hexPublicKeysOf;
|
|
28
|
+
/**
|
|
29
|
+
* @internal this function is meant only for internal use and may be changed without notice.
|
|
30
|
+
* Get the transfer key graph for a data owner. Node names are the public key fingerprints of the data owner's keys, and an edge represents a key
|
|
31
|
+
* which can be retrieved from another key using the transfer keys.
|
|
32
|
+
* @param dataOwner a data owner.
|
|
33
|
+
* @return a graph representing the possible key recovery paths using transfer keys for hte provided data owner.
|
|
34
|
+
*/
|
|
35
|
+
function transferKeysFpGraphOf(dataOwner) {
|
|
36
|
+
var _a;
|
|
37
|
+
const publicKeys = Array.from(hexPublicKeysOf(dataOwner));
|
|
38
|
+
const edges = [];
|
|
39
|
+
Object.entries((_a = dataOwner.transferKeys) !== null && _a !== void 0 ? _a : {}).forEach(([from, tos]) => {
|
|
40
|
+
Object.keys(tos).forEach((to) => {
|
|
41
|
+
edges.push([from.slice(-32), to.slice(-32)]);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
return (0, graph_utils_1.acyclic)((0, graph_utils_1.graphFromEdges)(edges, publicKeys.map((x) => x.slice(-32))));
|
|
45
|
+
}
|
|
46
|
+
exports.transferKeysFpGraphOf = transferKeysFpGraphOf;
|
|
47
|
+
/**
|
|
48
|
+
* @internal this function is meant only for internal use and may be changed without notice.
|
|
49
|
+
* Get a map for converting public keys fingerprint to full public keys for the provided data owner.
|
|
50
|
+
* @param dataOwner a data owner.
|
|
51
|
+
* @return a map to convert fingerprints of the data owner into full public keys.
|
|
52
|
+
*/
|
|
53
|
+
function fingerprintToPublicKeysMapOf(dataOwner) {
|
|
54
|
+
const publicKeys = Array.from(hexPublicKeysOf(dataOwner));
|
|
55
|
+
const res = {};
|
|
56
|
+
publicKeys.forEach((pk) => {
|
|
57
|
+
res[pk.slice(-32)] = pk;
|
|
58
|
+
});
|
|
59
|
+
return res;
|
|
60
|
+
}
|
|
61
|
+
exports.fingerprintToPublicKeysMapOf = fingerprintToPublicKeysMapOf;
|
|
62
|
+
/**
|
|
63
|
+
* @internal this function is meant only for internal use and may be changed without notice.
|
|
64
|
+
* Load many public keys in spki format.
|
|
65
|
+
* @param rsa the rsa service
|
|
66
|
+
* @param publicKeysSpkiHex public keys in spki format, hex encoded.
|
|
67
|
+
* @return public keys as crypto keys by their fingerprint.
|
|
68
|
+
*/
|
|
69
|
+
function loadPublicKeys(rsa, publicKeysSpkiHex) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
return Object.fromEntries(yield Promise.all(publicKeysSpkiHex.map((x) => __awaiter(this, void 0, void 0, function* () { return [x.slice(-32), yield rsa.importKey('spki', (0, utils_1.hex2ua)(x), ['encrypt'])]; }))));
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
exports.loadPublicKeys = loadPublicKeys;
|
|
75
|
+
/**
|
|
76
|
+
* @internal This method is intended only for internal use and may be changed without notice.
|
|
77
|
+
* Creates a delegation for the current data owner if the data owner is an encrypted entity and there is no delegation to himself.
|
|
78
|
+
* @return the updated self.
|
|
79
|
+
*/
|
|
80
|
+
function ensureDelegationForSelf(dataOwnerApi, entitiesEncryption, cryptoPrimitives) {
|
|
81
|
+
var _a, _b;
|
|
82
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
83
|
+
const self = yield dataOwnerApi.getCurrentDataOwner();
|
|
84
|
+
if (self.type === icc_data_owner_x_api_1.DataOwnerTypeEnum.Patient) {
|
|
85
|
+
const patient = self.dataOwner;
|
|
86
|
+
const availableSecretIds = yield entitiesEncryption.secretIdsOf(patient);
|
|
87
|
+
if (availableSecretIds.length) {
|
|
88
|
+
return self;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const updatedPatient = Object.entries((_a = patient.encryptionKeys) !== null && _a !== void 0 ? _a : {}).length || Object.entries((_b = patient.delegations) !== null && _b !== void 0 ? _b : {}).length
|
|
92
|
+
? yield entitiesEncryption.entityWithExtendedEncryptedMetadata(
|
|
93
|
+
// If there is already something initialise only a new delegation to self
|
|
94
|
+
patient, patient.id, [cryptoPrimitives.randomUuid()], [], []) // else initialise also encryption keys
|
|
95
|
+
: yield entitiesEncryption.entityWithInitialisedEncryptedMetadata(patient, undefined, undefined, true).then((x) => x.updatedEntity);
|
|
96
|
+
return yield dataOwnerApi.updateDataOwner({
|
|
97
|
+
dataOwner: updatedPatient,
|
|
98
|
+
type: icc_data_owner_x_api_1.DataOwnerTypeEnum.Patient,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
return self;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
exports.ensureDelegationForSelf = ensureDelegationForSelf;
|
|
108
|
+
function encryptedStubEquals(a, b) {
|
|
109
|
+
if (!delegationLikeEquality(a.delegations, b.delegations))
|
|
110
|
+
return false;
|
|
111
|
+
if (!delegationLikeEquality(a.encryptionKeys, b.encryptionKeys))
|
|
112
|
+
return false;
|
|
113
|
+
if (!delegationLikeEquality(a.cryptedForeignKeys, b.cryptedForeignKeys))
|
|
114
|
+
return false;
|
|
115
|
+
if (!(0, collection_utils_1.setEquals)(new Set(a.secretForeignKeys), new Set(b.secretForeignKeys)))
|
|
116
|
+
return false;
|
|
117
|
+
return a.encryptedSelf === b.encryptedSelf;
|
|
118
|
+
}
|
|
119
|
+
exports.encryptedStubEquals = encryptedStubEquals;
|
|
120
|
+
function delegationLikeEquality(a, b) {
|
|
121
|
+
if (!(0, collection_utils_1.setEquals)(new Set(Object.keys(a !== null && a !== void 0 ? a : {})), new Set(Object.keys(b !== null && b !== void 0 ? b : {}))))
|
|
122
|
+
return false;
|
|
123
|
+
for (const [k, aDelegations] of Object.entries(a !== null && a !== void 0 ? a : {})) {
|
|
124
|
+
const bDelegations = (b !== null && b !== void 0 ? b : {})[k];
|
|
125
|
+
if (!aDelegations.every((da) => !!bDelegations.find((db) => da.key === db.key && da.delegatedTo === db.delegatedTo && da.owner === db.owner && (0, collection_utils_1.setEquals)(new Set(da.tags), new Set(db.tags)))))
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
2
130
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../icc-x-api/crypto/utils.ts"],"names":[],"mappings":"","sourcesContent":[""]}
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../icc-x-api/crypto/utils.ts"],"names":[],"mappings":"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","sourcesContent":["// Uses fp as node names\nimport { acyclic, graphFromEdges, StronglyConnectedGraph } from '../utils/graph-utils'\nimport { DataOwner, DataOwnerTypeEnum, DataOwnerWithType, IccDataOwnerXApi } from '../icc-data-owner-x-api'\nimport { RSAUtils } from './RSA'\nimport { hex2ua } from '../utils'\nimport { HealthcareParty } from '../../icc-api/model/HealthcareParty'\nimport { Patient } from '../../icc-api/model/Patient'\nimport { Device } from '../../icc-api/model/Device'\nimport { EntitiesEncryption } from './EntitiesEncryption'\nimport { CryptoPrimitives } from './CryptoPrimitives'\nimport { Delegation, EncryptedEntityStub } from '../../icc-api/model/models'\nimport { setEquals } from '../utils/collection-utils'\n\n/**\n * @internal this function is meant only for internal use and may be changed without notice.\n * Get the public keys of a data owner, same as {@link dataOwnerApi.getHexPublicKeysOf}.\n * @param dataOwner\n */\nexport function hexPublicKeysOf(dataOwner: DataOwner) {\n return new Set([dataOwner.publicKey, ...Object.keys(dataOwner.aesExchangeKeys ?? {})].filter((pubKey) => !!pubKey) as string[])\n}\n\n/**\n * @internal this function is meant only for internal use and may be changed without notice.\n * Get the transfer key graph for a data owner. Node names are the public key fingerprints of the data owner's keys, and an edge represents a key\n * which can be retrieved from another key using the transfer keys.\n * @param dataOwner a data owner.\n * @return a graph representing the possible key recovery paths using transfer keys for hte provided data owner.\n */\nexport function transferKeysFpGraphOf(dataOwner: DataOwner): StronglyConnectedGraph {\n const publicKeys = Array.from(hexPublicKeysOf(dataOwner))\n const edges: [string, string][] = []\n Object.entries(dataOwner.transferKeys ?? {}).forEach(([from, tos]) => {\n Object.keys(tos).forEach((to) => {\n edges.push([from.slice(-32), to.slice(-32)])\n })\n })\n return acyclic(\n graphFromEdges(\n edges,\n publicKeys.map((x) => x.slice(-32))\n )\n )\n}\n\n/**\n * @internal this function is meant only for internal use and may be changed without notice.\n * Get a map for converting public keys fingerprint to full public keys for the provided data owner.\n * @param dataOwner a data owner.\n * @return a map to convert fingerprints of the data owner into full public keys.\n */\nexport function fingerprintToPublicKeysMapOf(dataOwner: DataOwner): { [fp: string]: string } {\n const publicKeys = Array.from(hexPublicKeysOf(dataOwner))\n const res: { [fp: string]: string } = {}\n publicKeys.forEach((pk) => {\n res[pk.slice(-32)] = pk\n })\n return res\n}\n\n/**\n * @internal this function is meant only for internal use and may be changed without notice.\n * Load many public keys in spki format.\n * @param rsa the rsa service\n * @param publicKeysSpkiHex public keys in spki format, hex encoded.\n * @return public keys as crypto keys by their fingerprint.\n */\nexport async function loadPublicKeys(rsa: RSAUtils, publicKeysSpkiHex: string[]): Promise<{ [publicKeyFingerprint: string]: CryptoKey }> {\n return Object.fromEntries(\n await Promise.all(publicKeysSpkiHex.map(async (x) => [x.slice(-32), await rsa.importKey('spki', hex2ua(x), ['encrypt'])]))\n )\n}\n\n/**\n * @internal This method is intended only for internal use and may be changed without notice.\n * Creates a delegation for the current data owner if the data owner is an encrypted entity and there is no delegation to himself.\n * @return the updated self.\n */\nexport async function ensureDelegationForSelf(\n dataOwnerApi: IccDataOwnerXApi,\n entitiesEncryption: EntitiesEncryption,\n cryptoPrimitives: CryptoPrimitives\n): Promise<DataOwnerWithType> {\n const self = await dataOwnerApi.getCurrentDataOwner()\n if (self.type === DataOwnerTypeEnum.Patient) {\n const patient: Patient & DataOwner = self.dataOwner\n const availableSecretIds = await entitiesEncryption.secretIdsOf(patient)\n if (availableSecretIds.length) {\n return self\n } else {\n const updatedPatient =\n Object.entries(patient.encryptionKeys ?? {}).length || Object.entries(patient.delegations ?? {}).length\n ? await entitiesEncryption.entityWithExtendedEncryptedMetadata(\n // If there is already something initialise only a new delegation to self\n patient,\n patient.id!,\n [cryptoPrimitives.randomUuid()],\n [],\n []\n ) // else initialise also encryption keys\n : await entitiesEncryption.entityWithInitialisedEncryptedMetadata(patient, undefined, undefined, true).then((x) => x.updatedEntity)\n return await dataOwnerApi.updateDataOwner({\n dataOwner: updatedPatient,\n type: DataOwnerTypeEnum.Patient,\n })\n }\n } else {\n return self\n }\n}\n\nexport function encryptedStubEquals(a: EncryptedEntityStub, b: EncryptedEntityStub): boolean {\n if (!delegationLikeEquality(a.delegations, b.delegations)) return false\n if (!delegationLikeEquality(a.encryptionKeys, b.encryptionKeys)) return false\n if (!delegationLikeEquality(a.cryptedForeignKeys, b.cryptedForeignKeys)) return false\n if (!setEquals(new Set(a.secretForeignKeys), new Set(b.secretForeignKeys))) return false\n return a.encryptedSelf === b.encryptedSelf\n}\n\nfunction delegationLikeEquality(a: { [s: string]: Delegation[] } | undefined, b: { [s: string]: Delegation[] } | undefined): boolean {\n if (!setEquals(new Set(Object.keys(a ?? {})), new Set(Object.keys(b ?? {})))) return false\n for (const [k, aDelegations] of Object.entries(a ?? {})) {\n const bDelegations = (b ?? {})[k]\n if (\n !aDelegations.every(\n (da) =>\n !!bDelegations.find(\n (db) => da.key === db.key && da.delegatedTo === db.delegatedTo && da.owner === db.owner && setEquals(new Set(da.tags), new Set(db.tags))\n )\n )\n )\n return false\n }\n return true\n}\n"]}
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* iCure Data Stack API Documentation
|
|
3
|
+
* The iCure Data Stack Application API is the native interface to iCure. This version is obsolete, please use v2.
|
|
4
|
+
*
|
|
5
|
+
* OpenAPI spec version: v1
|
|
6
|
+
*
|
|
7
|
+
*
|
|
8
|
+
* NOTE: This class is auto generated by the swagger code generator program.
|
|
9
|
+
* https://github.com/swagger-api/swagger-codegen.git
|
|
10
|
+
* Do not edit the class manually.
|
|
11
|
+
*/
|
|
1
12
|
import { AbstractFilterContact } from '../../icc-api/model/AbstractFilterContact';
|
|
2
13
|
export declare class ContactByHcPartyTagCodeDateFilter extends AbstractFilterContact {
|
|
3
14
|
$type: string;
|