@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.
Files changed (154) hide show
  1. package/icc-api/api/IccDeviceApi.d.ts +1 -1
  2. package/icc-api/api/IccDeviceApi.js.map +1 -1
  3. package/icc-api/api/IccDoctemplateApi.js.map +1 -1
  4. package/icc-api/api/IccDocumentTemplateApi.js.map +1 -1
  5. package/icc-api/api/IccHcpartyApi.d.ts +1 -1
  6. package/icc-api/api/IccHcpartyApi.js.map +1 -1
  7. package/icc-api/api/IccPatientApi.d.ts +1 -1
  8. package/icc-api/api/IccPatientApi.js.map +1 -1
  9. package/icc-api/model/MaintenanceTask.d.ts +6 -5
  10. package/icc-api/model/MaintenanceTask.js +5 -0
  11. package/icc-api/model/MaintenanceTask.js.map +1 -1
  12. package/icc-api/model/User.d.ts +23 -1
  13. package/icc-api/model/User.js +21 -0
  14. package/icc-api/model/User.js.map +1 -1
  15. package/icc-api/model/models.d.ts +14 -0
  16. package/icc-api/model/models.js.map +1 -1
  17. package/icc-x-api/crypto/AES.d.ts +2 -0
  18. package/icc-x-api/crypto/AES.js +12 -0
  19. package/icc-x-api/crypto/AES.js.map +1 -1
  20. package/icc-x-api/crypto/BaseExchangeKeysManager.d.ts +122 -0
  21. package/icc-x-api/crypto/BaseExchangeKeysManager.js +356 -0
  22. package/icc-x-api/crypto/BaseExchangeKeysManager.js.map +1 -0
  23. package/icc-x-api/crypto/ConfidentialEntities.d.ts +58 -0
  24. package/icc-x-api/crypto/ConfidentialEntities.js +99 -0
  25. package/icc-x-api/crypto/ConfidentialEntities.js.map +1 -0
  26. package/icc-x-api/crypto/CryptoPrimitives.d.ts +31 -0
  27. package/icc-x-api/crypto/CryptoPrimitives.js +55 -0
  28. package/icc-x-api/crypto/CryptoPrimitives.js.map +1 -0
  29. package/icc-x-api/crypto/CryptoStrategies.d.ts +82 -0
  30. package/icc-x-api/crypto/CryptoStrategies.js +3 -0
  31. package/icc-x-api/crypto/CryptoStrategies.js.map +1 -0
  32. package/icc-x-api/crypto/EntitiesEncryption.d.ts +254 -0
  33. package/icc-x-api/crypto/EntitiesEncryption.js +700 -0
  34. package/icc-x-api/crypto/EntitiesEncryption.js.map +1 -0
  35. package/icc-x-api/crypto/ExchangeKeysManager.d.ts +56 -0
  36. package/icc-x-api/crypto/ExchangeKeysManager.js +147 -0
  37. package/icc-x-api/crypto/ExchangeKeysManager.js.map +1 -0
  38. package/icc-x-api/crypto/KeyManager.d.ts +103 -0
  39. package/icc-x-api/crypto/KeyManager.js +288 -0
  40. package/icc-x-api/crypto/KeyManager.js.map +1 -0
  41. package/icc-x-api/crypto/KeyRecovery.d.ts +34 -0
  42. package/icc-x-api/crypto/KeyRecovery.js +253 -0
  43. package/icc-x-api/crypto/KeyRecovery.js.map +1 -0
  44. package/icc-x-api/crypto/LegacyCryptoStrategies.d.ts +28 -0
  45. package/icc-x-api/crypto/LegacyCryptoStrategies.js +22 -0
  46. package/icc-x-api/crypto/LegacyCryptoStrategies.js.map +1 -0
  47. package/icc-x-api/crypto/RSA.d.ts +19 -20
  48. package/icc-x-api/crypto/RSA.js +30 -1
  49. package/icc-x-api/crypto/RSA.js.map +1 -1
  50. package/icc-x-api/crypto/ShamirKeysManager.d.ts +43 -0
  51. package/icc-x-api/crypto/ShamirKeysManager.js +150 -0
  52. package/icc-x-api/crypto/ShamirKeysManager.js.map +1 -0
  53. package/icc-x-api/crypto/ShareMetadataBehaviour.d.ts +19 -0
  54. package/icc-x-api/crypto/ShareMetadataBehaviour.js +24 -0
  55. package/icc-x-api/crypto/ShareMetadataBehaviour.js.map +1 -0
  56. package/icc-x-api/crypto/TransferKeysManager.d.ts +29 -0
  57. package/icc-x-api/crypto/TransferKeysManager.js +121 -0
  58. package/icc-x-api/crypto/TransferKeysManager.js.map +1 -0
  59. package/icc-x-api/crypto/utils.d.ts +46 -0
  60. package/icc-x-api/crypto/utils.js +128 -0
  61. package/icc-x-api/crypto/utils.js.map +1 -1
  62. package/icc-x-api/filters/ContactByHcPartyTagCodeDateFilter.d.ts +11 -0
  63. package/icc-x-api/filters/ContactByHcPartyTagCodeDateFilter.js +11 -0
  64. package/icc-x-api/filters/ContactByHcPartyTagCodeDateFilter.js.map +1 -1
  65. package/icc-x-api/filters/DeviceByHcPartyFilter.d.ts +11 -0
  66. package/icc-x-api/filters/DeviceByHcPartyFilter.js +11 -0
  67. package/icc-x-api/filters/DeviceByHcPartyFilter.js.map +1 -1
  68. package/icc-x-api/filters/DeviceByIdsFilter.d.ts +11 -0
  69. package/icc-x-api/filters/DeviceByIdsFilter.js +11 -0
  70. package/icc-x-api/filters/DeviceByIdsFilter.js.map +1 -1
  71. package/icc-x-api/filters/HealthElementByHcPartySecretForeignKeysFilter.d.ts +11 -0
  72. package/icc-x-api/filters/HealthElementByHcPartySecretForeignKeysFilter.js +11 -0
  73. package/icc-x-api/filters/HealthElementByHcPartySecretForeignKeysFilter.js.map +1 -1
  74. package/icc-x-api/icc-accesslog-x-api.d.ts +49 -4
  75. package/icc-x-api/icc-accesslog-x-api.js +112 -102
  76. package/icc-x-api/icc-accesslog-x-api.js.map +1 -1
  77. package/icc-x-api/icc-calendar-item-x-api.d.ts +53 -5
  78. package/icc-x-api/icc-calendar-item-x-api.js +112 -100
  79. package/icc-x-api/icc-calendar-item-x-api.js.map +1 -1
  80. package/icc-x-api/icc-classification-x-api.d.ts +45 -2
  81. package/icc-x-api/icc-classification-x-api.js +89 -41
  82. package/icc-x-api/icc-classification-x-api.js.map +1 -1
  83. package/icc-x-api/icc-contact-x-api.d.ts +57 -19
  84. package/icc-x-api/icc-contact-x-api.js +149 -154
  85. package/icc-x-api/icc-contact-x-api.js.map +1 -1
  86. package/icc-x-api/icc-crypto-x-api.d.ts +266 -366
  87. package/icc-x-api/icc-crypto-x-api.js +416 -1327
  88. package/icc-x-api/icc-crypto-x-api.js.map +1 -1
  89. package/icc-x-api/icc-data-owner-x-api.d.ts +110 -11
  90. package/icc-x-api/icc-data-owner-x-api.js +188 -14
  91. package/icc-x-api/icc-data-owner-x-api.js.map +1 -1
  92. package/icc-x-api/icc-doctemplate-x-api.js +3 -3
  93. package/icc-x-api/icc-doctemplate-x-api.js.map +1 -1
  94. package/icc-x-api/icc-document-x-api.d.ts +76 -5
  95. package/icc-x-api/icc-document-x-api.js +137 -59
  96. package/icc-x-api/icc-document-x-api.js.map +1 -1
  97. package/icc-x-api/icc-form-x-api.d.ts +47 -7
  98. package/icc-x-api/icc-form-x-api.js +85 -86
  99. package/icc-x-api/icc-form-x-api.js.map +1 -1
  100. package/icc-x-api/icc-hcparty-x-api.d.ts +1 -1
  101. package/icc-x-api/icc-hcparty-x-api.js +1 -1
  102. package/icc-x-api/icc-hcparty-x-api.js.map +1 -1
  103. package/icc-x-api/icc-helement-x-api.d.ts +50 -3
  104. package/icc-x-api/icc-helement-x-api.js +101 -118
  105. package/icc-x-api/icc-helement-x-api.js.map +1 -1
  106. package/icc-x-api/icc-icure-maintenance-x-api.d.ts +31 -0
  107. package/icc-x-api/icc-icure-maintenance-x-api.js +124 -0
  108. package/icc-x-api/icc-icure-maintenance-x-api.js.map +1 -0
  109. package/icc-x-api/icc-invoice-x-api.d.ts +45 -5
  110. package/icc-x-api/icc-invoice-x-api.js +89 -64
  111. package/icc-x-api/icc-invoice-x-api.js.map +1 -1
  112. package/icc-x-api/icc-maintenance-task-x-api.d.ts +38 -6
  113. package/icc-x-api/icc-maintenance-task-x-api.js +73 -102
  114. package/icc-x-api/icc-maintenance-task-x-api.js.map +1 -1
  115. package/icc-x-api/icc-message-x-api.d.ts +55 -2
  116. package/icc-x-api/icc-message-x-api.js +92 -33
  117. package/icc-x-api/icc-message-x-api.js.map +1 -1
  118. package/icc-x-api/icc-patient-x-api.d.ts +67 -7
  119. package/icc-x-api/icc-patient-x-api.js +409 -473
  120. package/icc-x-api/icc-patient-x-api.js.map +1 -1
  121. package/icc-x-api/icc-receipt-x-api.d.ts +49 -5
  122. package/icc-x-api/icc-receipt-x-api.js +85 -47
  123. package/icc-x-api/icc-receipt-x-api.js.map +1 -1
  124. package/icc-x-api/icc-time-table-x-api.d.ts +34 -10
  125. package/icc-x-api/icc-time-table-x-api.js +61 -18
  126. package/icc-x-api/icc-time-table-x-api.js.map +1 -1
  127. package/icc-x-api/index.d.ts +30 -1
  128. package/icc-x-api/index.js +112 -49
  129. package/icc-x-api/index.js.map +1 -1
  130. package/icc-x-api/maintenance/KeyPairUpdateRequest.d.ts +35 -0
  131. package/icc-x-api/maintenance/KeyPairUpdateRequest.js +54 -0
  132. package/icc-x-api/maintenance/KeyPairUpdateRequest.js.map +1 -0
  133. package/icc-x-api/storage/DefaultStorageEntryKeysFactory.d.ts +9 -0
  134. package/icc-x-api/storage/DefaultStorageEntryKeysFactory.js +23 -0
  135. package/icc-x-api/storage/DefaultStorageEntryKeysFactory.js.map +1 -0
  136. package/icc-x-api/storage/IcureStorageFacade.d.ts +55 -0
  137. package/icc-x-api/storage/IcureStorageFacade.js +95 -0
  138. package/icc-x-api/storage/IcureStorageFacade.js.map +1 -0
  139. package/icc-x-api/storage/StorageEntryKeysFactory.d.ts +31 -0
  140. package/icc-x-api/storage/StorageEntryKeysFactory.js +3 -0
  141. package/icc-x-api/storage/StorageEntryKeysFactory.js.map +1 -0
  142. package/icc-x-api/utils/collection-utils.d.ts +8 -0
  143. package/icc-x-api/utils/collection-utils.js +26 -0
  144. package/icc-x-api/utils/collection-utils.js.map +1 -0
  145. package/icc-x-api/utils/crypto-utils.d.ts +8 -1
  146. package/icc-x-api/utils/crypto-utils.js +19 -3
  147. package/icc-x-api/utils/crypto-utils.js.map +1 -1
  148. package/icc-x-api/utils/graph-utils.d.ts +45 -0
  149. package/icc-x-api/utils/graph-utils.js +203 -0
  150. package/icc-x-api/utils/graph-utils.js.map +1 -0
  151. package/icc-x-api/utils/lru-temporised-async-cache.d.ts +27 -0
  152. package/icc-x-api/utils/lru-temporised-async-cache.js +120 -0
  153. package/icc-x-api/utils/lru-temporised-async-cache.js.map +1 -0
  154. package/package.json +1 -1
@@ -0,0 +1,356 @@
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.BaseExchangeKeysManager = void 0;
13
+ const utils_1 = require("../utils");
14
+ const icc_data_owner_x_api_1 = require("../icc-data-owner-x-api");
15
+ /**
16
+ * @internal This class is meant only for internal use and may be changed without notice.
17
+ * Functions to create and get exchange keys.
18
+ * The methods of this api require to pass the appropriate keys for encryption/decryption manually.
19
+ */
20
+ class BaseExchangeKeysManager {
21
+ constructor(primitives, dataOwnerApi, hcpartyBaseApi, patientBaseApi, deviceBaseApi) {
22
+ this.generateKeyConcurrencyMap = {};
23
+ this.primitives = primitives;
24
+ this.dataOwnerApi = dataOwnerApi;
25
+ this.hcpartyBaseApi = hcpartyBaseApi;
26
+ this.patientBaseApi = patientBaseApi;
27
+ this.deviceBaseApi = deviceBaseApi;
28
+ }
29
+ /**
30
+ * Creates a new exchange key from the current data owner to a delegate, or updates an existing one allowing additional public keys to access it.
31
+ * @param delegateId the delegate data owner id.
32
+ * @param delegatorMainKeyPair main key pair for the delegator. The private key will be used for the decryption of the existing key in case of
33
+ * update, and the public key will be used as entry key of the aesExchangeKey map
34
+ * @param additionalPublicKeys all public keys of key pairs other than {@link delegatorMainKeyPair} that need to have access to the exchange key.
35
+ * Can be a mix of crypto keys and full hex-encoded spki format (no fingerprints).
36
+ * @return the exchange key for the delegator-delegate-delegatorKey triple (new or existing) and the updated delegator.
37
+ */
38
+ createOrUpdateEncryptedExchangeKeyTo(delegateId, delegatorMainKeyPair, additionalPublicKeys) {
39
+ return __awaiter(this, void 0, void 0, function* () {
40
+ const delegatorId = yield this.dataOwnerApi.getCurrentDataOwnerId();
41
+ return yield (0, utils_1.notConcurrent)(this.generateKeyConcurrencyMap, delegatorId, () => __awaiter(this, void 0, void 0, function* () {
42
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
43
+ const delegator = yield this.dataOwnerApi.getCurrentDataOwner();
44
+ const delegate = delegatorId === delegateId ? delegator : yield this.dataOwnerApi.getDataOwner(delegateId);
45
+ const mainDelegatorKeyPairPubHex = (0, utils_1.ua2hex)(yield this.primitives.RSA.exportKey(delegatorMainKeyPair.publicKey, 'spki'));
46
+ let exchangeKey = undefined;
47
+ const existingExchangeKey = (_d = (_c = (_b = (_a = delegator.dataOwner.aesExchangeKeys) === null || _a === void 0 ? void 0 : _a[mainDelegatorKeyPairPubHex]) === null || _b === void 0 ? void 0 : _b[delegateId]) === null || _c === void 0 ? void 0 : _c[mainDelegatorKeyPairPubHex.slice(-32)]) !== null && _d !== void 0 ? _d : (mainDelegatorKeyPairPubHex === delegator.dataOwner.publicKey ? (_f = (_e = delegator.dataOwner.hcPartyKeys) === null || _e === void 0 ? void 0 : _e[delegateId]) === null || _f === void 0 ? void 0 : _f[0] : undefined);
48
+ if (existingExchangeKey) {
49
+ exchangeKey = yield this.tryDecryptExchangeKeyWith(existingExchangeKey, delegatorMainKeyPair, undefined);
50
+ if (!exchangeKey)
51
+ throw new Error(`Failed to decrypt existing exchange key for update of ${mainDelegatorKeyPairPubHex.slice(-32)}@${delegatorId}->${delegateId}`);
52
+ const existingAesExchangeKey = (_h = (_g = delegator.dataOwner.aesExchangeKeys) === null || _g === void 0 ? void 0 : _g[mainDelegatorKeyPairPubHex]) === null || _h === void 0 ? void 0 : _h[delegateId];
53
+ if (existingAesExchangeKey) {
54
+ const existingPublicKeysSet = new Set(existingExchangeKey);
55
+ if (Object.keys(additionalPublicKeys).every((fp) => existingPublicKeysSet.has(fp)))
56
+ return {
57
+ updatedDelegator: delegator,
58
+ key: exchangeKey.key,
59
+ };
60
+ }
61
+ }
62
+ const allPublicKeys = Object.assign(Object.assign({}, additionalPublicKeys), { [mainDelegatorKeyPairPubHex.slice(-32)]: delegatorMainKeyPair.publicKey });
63
+ const encryptedKeyInfo = yield this.encryptExchangeKey(exchangeKey, allPublicKeys);
64
+ const updatedDataOwner = Object.assign(Object.assign({}, delegator.dataOwner), { aesExchangeKeys: yield this.updateExchangeKeys(delegator, delegate, mainDelegatorKeyPairPubHex, encryptedKeyInfo.encryptedExchangeKey), publicKey: (_j = delegator.dataOwner.publicKey) !== null && _j !== void 0 ? _j : mainDelegatorKeyPairPubHex });
65
+ if (delegator.dataOwner.publicKey === mainDelegatorKeyPairPubHex) {
66
+ updatedDataOwner.hcPartyKeys = this.updateLegacyExchangeKeys(delegator, delegate, encryptedKeyInfo.encryptedExchangeKey);
67
+ }
68
+ const updatedDelegator = yield this.dataOwnerApi.updateDataOwner({
69
+ type: delegator.type,
70
+ dataOwner: updatedDataOwner,
71
+ });
72
+ return {
73
+ key: encryptedKeyInfo.exchangeKey,
74
+ updatedDelegator,
75
+ };
76
+ }));
77
+ });
78
+ }
79
+ /**
80
+ * Updates the aes exchange keys between the current data owner and another data owner to allow the other data owner to access the exchange key
81
+ * using his new public key. Note that this will make existing exchange keys from the other data owner to the current data owner invalid for
82
+ * encryption.
83
+ * @param otherDataOwner the other data owner.
84
+ * @param newDataOwnerPublicKey a new public key of the other data owner.
85
+ * @param keyPairsByFingerprint all available key pairs to use for the decryption of existing aes exchange keys.
86
+ */
87
+ giveAccessBackTo(otherDataOwner, newDataOwnerPublicKey, keyPairsByFingerprint) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ const selfId = yield this.dataOwnerApi.getCurrentDataOwnerId();
90
+ const newPublicKey = yield this.primitives.RSA.importKey('spki', (0, utils_1.hex2ua)(newDataOwnerPublicKey), ['encrypt']);
91
+ yield this.extendForGiveAccessBackTo(selfId, otherDataOwner, newDataOwnerPublicKey.slice(-32), newPublicKey, keyPairsByFingerprint);
92
+ yield this.extendForGiveAccessBackTo(otherDataOwner, selfId, newDataOwnerPublicKey.slice(-32), newPublicKey, keyPairsByFingerprint);
93
+ });
94
+ }
95
+ /**
96
+ * Get the encrypted exchange keys for a delegator-delegate pair.
97
+ * @param delegatorId id of the delegator data owner.
98
+ * @param delegateId id of the delegate data owner.
99
+ * @return an array of exchange keys from the delegator to delegate where each key is encrypted with one or more public keys.
100
+ */
101
+ getEncryptedExchangeKeysFor(delegatorId, delegateId) {
102
+ var _a, _b, _c;
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ const delegator = yield this.dataOwnerApi.getDataOwner(delegatorId);
105
+ const res = Object.values((_a = delegator.dataOwner.aesExchangeKeys) !== null && _a !== void 0 ? _a : {}).flatMap((delegateToKey) => {
106
+ const encryptedKeyForDelegate = delegateToKey[delegateId];
107
+ if (encryptedKeyForDelegate) {
108
+ return [encryptedKeyForDelegate];
109
+ }
110
+ else {
111
+ return [];
112
+ }
113
+ });
114
+ const legacyDelegation = (_c = (_b = delegator.dataOwner.hcPartyKeys) === null || _b === void 0 ? void 0 : _b[delegateId]) === null || _c === void 0 ? void 0 : _c[1];
115
+ if (legacyDelegation)
116
+ res.push({ '': legacyDelegation });
117
+ return res;
118
+ });
119
+ }
120
+ /**
121
+ * Get all exchange keys where the provided data owner is involved either as the delegator or as the delegate.
122
+ * @param dataOwnerId id of a data owner.
123
+ * @param otherOwnerTypes only exchange keys between the current data owner and data owners of this type will be included in the result.
124
+ * @return all exchange keys involving the provided data owner. Note that there may be an overlap between some keys to and from the data owner.
125
+ */
126
+ getAllExchangeKeysWith(dataOwnerId, otherOwnerTypes) {
127
+ return __awaiter(this, void 0, void 0, function* () {
128
+ if (otherOwnerTypes.length === 0)
129
+ throw new Error('otherOwnerTypes must not be empty!');
130
+ const keysToOwner = yield Promise.all([
131
+ otherOwnerTypes.find((x) => x === icc_data_owner_x_api_1.DataOwnerTypeEnum.Hcp)
132
+ ? this.hcpartyBaseApi.getAesExchangeKeysForDelegate(dataOwnerId).catch(() => { })
133
+ : Promise.resolve({}),
134
+ otherOwnerTypes.find((x) => x === icc_data_owner_x_api_1.DataOwnerTypeEnum.Patient)
135
+ ? this.patientBaseApi.getPatientAesExchangeKeysForDelegate(dataOwnerId).catch(() => { })
136
+ : Promise.resolve({}),
137
+ otherOwnerTypes.find((x) => x === icc_data_owner_x_api_1.DataOwnerTypeEnum.Device)
138
+ ? this.deviceBaseApi.getDeviceAesExchangeKeysForDelegate(dataOwnerId).catch(() => { })
139
+ : Promise.resolve({}),
140
+ ]).then(([a, b, c]) => (Object.assign(Object.assign(Object.assign({}, a), b), c)));
141
+ const dataOwner = yield this.dataOwnerApi.getDataOwner(dataOwnerId);
142
+ const allOwnerKeys = yield this.combineLegacyHcpKeysWithAesExchangeKeys(dataOwner.dataOwner, undefined);
143
+ const filteredDelegates = new Set(yield Array.from(new Set(Object.values(allOwnerKeys).flatMap((x) => Object.keys(x)))).reduce((acc, ownerId) => __awaiter(this, void 0, void 0, function* () {
144
+ const awaitedAcc = yield acc;
145
+ if (ownerId === dataOwnerId) {
146
+ return [...awaitedAcc, ownerId];
147
+ }
148
+ else {
149
+ const dataOwnerType = (yield this.dataOwnerApi.getDataOwner(ownerId)).type;
150
+ if (otherOwnerTypes.some((x) => x === dataOwnerType)) {
151
+ return [...awaitedAcc, ownerId];
152
+ }
153
+ else
154
+ return awaitedAcc;
155
+ }
156
+ }), Promise.resolve([])));
157
+ const keysFromOwner = Object.fromEntries(Object.entries(allOwnerKeys)
158
+ .map(([delegatorPubKey, delegateToKeys]) => [
159
+ delegatorPubKey,
160
+ Object.fromEntries(Object.entries(delegateToKeys).filter(([delegateId]) => filteredDelegates.has(delegateId))),
161
+ ])
162
+ .filter(([, x]) => Object.keys(x).length > 0));
163
+ return { keysToOwner, keysFromOwner };
164
+ });
165
+ }
166
+ /**
167
+ * Attempts to decrypt many exchange keys using any of the provided key pairs.
168
+ * @param encryptedExchangeKeys an array of exchange keys where each key is encrypted with one or more public keys.
169
+ * @param keyPairsByFingerprint rsa key pairs to use for decryption.
170
+ * @return an array all successfully decrypted exchange keys and an array containing all exchange keys which could not be decrypted.
171
+ */
172
+ tryDecryptExchangeKeys(encryptedExchangeKeys, keyPairsByFingerprint) {
173
+ return __awaiter(this, void 0, void 0, function* () {
174
+ const raws = new Set();
175
+ const res = { successfulDecryptions: [], failedDecryptions: [] };
176
+ for (const encryptedExchangeKey of encryptedExchangeKeys) {
177
+ const decrypted = yield this.tryDecryptExchangeKey(encryptedExchangeKey, keyPairsByFingerprint);
178
+ if (decrypted !== undefined && !raws.has(decrypted.raw)) {
179
+ raws.add(decrypted.raw);
180
+ res.successfulDecryptions.push(decrypted.key);
181
+ }
182
+ else {
183
+ res.failedDecryptions.push(encryptedExchangeKey);
184
+ }
185
+ }
186
+ return res;
187
+ });
188
+ }
189
+ extendForGiveAccessBackTo(delegatorId, delegateId, newPublicKeyFp, newPublicKey, decryptionKeyPairsByFingerprint) {
190
+ return __awaiter(this, void 0, void 0, function* () {
191
+ yield (0, utils_1.notConcurrent)(this.generateKeyConcurrencyMap, delegatorId, () => __awaiter(this, void 0, void 0, function* () {
192
+ const delegator = yield this.dataOwnerApi.getDataOwner(delegatorId);
193
+ const delegate = yield this.dataOwnerApi.getDataOwner(delegateId);
194
+ let didUpdateSomeKey = false;
195
+ const combinedKeys = yield this.combineLegacyHcpKeysWithAesExchangeKeys(delegator.dataOwner, delegate.dataOwner);
196
+ const updatedExchangeKeys = {};
197
+ const newEncryptionKeys = { [newPublicKeyFp]: newPublicKey };
198
+ for (const [currDelegatorKey, currDelegatesToKeys] of Object.entries(combinedKeys)) {
199
+ const updatedDelegatesToKeys = {};
200
+ for (const [currDelegateId, currEncryptedKey] of Object.entries(currDelegatesToKeys)) {
201
+ if (delegateId !== currDelegateId || newPublicKeyFp in currEncryptedKey) {
202
+ updatedDelegatesToKeys[currDelegateId] = currEncryptedKey;
203
+ }
204
+ else {
205
+ const decrypted = yield this.tryDecryptExchangeKey(currEncryptedKey, decryptionKeyPairsByFingerprint);
206
+ if (decrypted) {
207
+ didUpdateSomeKey = true;
208
+ updatedDelegatesToKeys[currDelegateId] = Object.assign(Object.assign({}, currEncryptedKey), (yield this.encryptExchangeKey(decrypted, newEncryptionKeys)).encryptedExchangeKey);
209
+ }
210
+ else {
211
+ updatedDelegatesToKeys[currDelegateId] = currEncryptedKey;
212
+ }
213
+ }
214
+ }
215
+ updatedExchangeKeys[currDelegatorKey] = updatedDelegatesToKeys;
216
+ }
217
+ if (didUpdateSomeKey) {
218
+ yield this.dataOwnerApi.updateDataOwner({
219
+ type: delegator.type,
220
+ dataOwner: Object.assign(Object.assign({}, delegator.dataOwner), { aesExchangeKeys: updatedExchangeKeys }),
221
+ });
222
+ }
223
+ }));
224
+ });
225
+ }
226
+ /**
227
+ * Attempts to decrypt an exchange key using any of the provided key pairs.
228
+ * @param encryptedExchangeKey an encrypted exchange key, in the form publicKeyXyzFingerprint -> hex(exchangeKeyEncryptedByPrivateKeyXyz).
229
+ * @param keyPairsByFingerprint rsa key pairs to use for decryption.
230
+ * @return the decrypted exchange key, in raw and key format (to allow deduplication), or undefined if the key could not be decrypted using the
231
+ * provided keys.
232
+ */
233
+ tryDecryptExchangeKey(encryptedExchangeKey, keyPairsByFingerprint) {
234
+ return __awaiter(this, void 0, void 0, function* () {
235
+ for (const [entryKey, encrypted] of Object.entries(encryptedExchangeKey)) {
236
+ // Due to bugs in past version the entry may actually contain the full public key instead of just the fingerprint.
237
+ const fp = entryKey.slice(-32);
238
+ const keyPair = keyPairsByFingerprint[fp];
239
+ if (keyPair !== undefined) {
240
+ const res = yield this.tryDecryptExchangeKeyWith(encrypted, keyPair, fp);
241
+ if (res !== undefined)
242
+ return res;
243
+ }
244
+ }
245
+ const defaultEncryptedKey = encryptedExchangeKey[''];
246
+ if (defaultEncryptedKey !== undefined) {
247
+ for (const keyPair of Object.values(keyPairsByFingerprint)) {
248
+ // disable error logging, we are not sure keyPair is the correct key
249
+ const res = yield this.tryDecryptExchangeKeyWith(defaultEncryptedKey, keyPair, undefined);
250
+ if (res !== undefined)
251
+ return res;
252
+ }
253
+ }
254
+ return undefined;
255
+ });
256
+ }
257
+ /**
258
+ * Creates an encrypted exchange key for the provided public keys.
259
+ * @param exchangeKey the exchange key in raw and imported format. If undefined a new key will be automatically created.
260
+ * @param publicKeys additional public keys that will have access to the exchange key in spki format, hex-encoded.
261
+ * @return the exchangeKey and an object with the exchange key encrypted with each of the provided public keys, hex-encoded, by fingerprint.
262
+ */
263
+ encryptExchangeKey(exchangeKey, publicKeys) {
264
+ var _a;
265
+ return __awaiter(this, void 0, void 0, function* () {
266
+ const exchangeKeyCrypto = (_a = exchangeKey === null || exchangeKey === void 0 ? void 0 : exchangeKey.key) !== null && _a !== void 0 ? _a : (yield this.primitives.AES.generateCryptoKey(false));
267
+ const exchangeKeyBytes = exchangeKey !== undefined ? (0, utils_1.hex2ua)(exchangeKey.raw) : yield this.primitives.AES.exportKey(exchangeKeyCrypto, 'raw');
268
+ const encryptedExchangeKey = yield Object.entries(publicKeys).reduce((acc, [currKeyFp, currKey]) => __awaiter(this, void 0, void 0, function* () {
269
+ return (Object.assign(Object.assign({}, (yield acc)), { [currKeyFp]: (0, utils_1.ua2hex)(yield this.primitives.RSA.encrypt(currKey, new Uint8Array(exchangeKeyBytes))) }));
270
+ }), Promise.resolve({}));
271
+ return { exchangeKey: exchangeKeyCrypto, encryptedExchangeKey };
272
+ });
273
+ }
274
+ /**
275
+ * Attempts to decrypt an exchange key using the provided key pairs.
276
+ * If you are confident that the provided {@link keyPair} was used to encrypt {@link encryptedByOneKey} you should also provide {@link keyPairFp},
277
+ * so that if the decryption fail an error will be logged to console before returning undefined.
278
+ * @param encryptedByOneKey an exchange key which may be encrypted with {@link keyPair}.
279
+ * @param keyPair an rsa key pair.
280
+ * @param keyPairFp the fingerprint of the provided key pair or undefined to disable logging of error if the decryption failed.
281
+ * @return the decrypted exchange key, in raw and key format (to allow deduplication), or undefined if the key could not be decrypted using the
282
+ * provided key.
283
+ */
284
+ tryDecryptExchangeKeyWith(encryptedByOneKey, keyPair, keyPairFp // if undefined will not log errors, when we are not sure the key to be used is the provided key.
285
+ ) {
286
+ return __awaiter(this, void 0, void 0, function* () {
287
+ try {
288
+ const decrypted = yield this.primitives.RSA.decrypt(keyPair.privateKey, (0, utils_1.hex2ua)(encryptedByOneKey));
289
+ return { raw: (0, utils_1.ua2hex)(decrypted), key: yield this.primitives.AES.importKey('raw', decrypted) };
290
+ }
291
+ catch (e) {
292
+ if (keyPairFp) {
293
+ console.error(`Failed to decrypt or import exchange key ${encryptedByOneKey} using key with fingerprint ${keyPairFp}.`, e);
294
+ }
295
+ }
296
+ });
297
+ }
298
+ updateLegacyExchangeKeys(delegator, delegate, encryptedKeyMap) {
299
+ var _a;
300
+ const legacyEncryptedKeyDelegator = delegator.dataOwner.publicKey ? encryptedKeyMap[delegator.dataOwner.publicKey] : undefined;
301
+ const legacyEncryptedKeyDelegate = delegate.dataOwner.publicKey ? encryptedKeyMap[delegate.dataOwner.publicKey] : undefined;
302
+ if (legacyEncryptedKeyDelegator && legacyEncryptedKeyDelegate) {
303
+ return Object.assign(Object.assign({}, ((_a = delegator.dataOwner.hcPartyKeys) !== null && _a !== void 0 ? _a : {})), { [delegate.dataOwner.id]: [legacyEncryptedKeyDelegator, legacyEncryptedKeyDelegate] });
304
+ }
305
+ else
306
+ return delegator.dataOwner.hcPartyKeys;
307
+ }
308
+ updateExchangeKeys(delegator, delegate, mainDelegatorKeyPairPubHex, encryptedKeyMap) {
309
+ var _a, _b, _c;
310
+ return __awaiter(this, void 0, void 0, function* () {
311
+ const combinedAesExchangeKeys = yield this.combineLegacyHcpKeysWithAesExchangeKeys(delegator.dataOwner, delegate.dataOwner);
312
+ return this.fixAesExchangeKeyEntriesToFingerprints(Object.assign(Object.assign({}, combinedAesExchangeKeys), { [mainDelegatorKeyPairPubHex]: Object.assign(Object.assign({}, ((_a = combinedAesExchangeKeys[mainDelegatorKeyPairPubHex]) !== null && _a !== void 0 ? _a : {})), { [delegate.dataOwner.id]: Object.assign(Object.assign({}, ((_c = (_b = combinedAesExchangeKeys[mainDelegatorKeyPairPubHex]) === null || _b === void 0 ? void 0 : _b[delegate.dataOwner.id]) !== null && _c !== void 0 ? _c : {})), encryptedKeyMap) }) }));
313
+ });
314
+ }
315
+ // Copy all legacy hcp exchange keys into the new aes exchange keys
316
+ combineLegacyHcpKeysWithAesExchangeKeys(owner, delegate) {
317
+ var _a, _b, _c, _d, _e;
318
+ return __awaiter(this, void 0, void 0, function* () {
319
+ const ownerLegacyPublicKey = owner.publicKey;
320
+ if (ownerLegacyPublicKey && !((_a = owner.aesExchangeKeys) !== null && _a !== void 0 ? _a : {})[ownerLegacyPublicKey]) {
321
+ /*
322
+ * This condition would technically prevent new updates to the hcPartyKeys to be migrated to the aes exchange keys, but since I can only update
323
+ * data for self data owner and parent entities this is not an issue, because I will always be using the new api from now on and I won't have
324
+ * a situation where the legacy keys are updated but the aes exchange keys are not.
325
+ */
326
+ const unknownDataOwnerCounterPartIds = Object.keys((_b = owner.hcPartyKeys) !== null && _b !== void 0 ? _b : {}).filter((x) => x !== owner.id && x !== (delegate === null || delegate === void 0 ? void 0 : delegate.id));
327
+ const counterPartsById = [
328
+ owner,
329
+ ...(delegate ? [delegate] : []),
330
+ ...(yield Promise.all(unknownDataOwnerCounterPartIds.map((cpid) => __awaiter(this, void 0, void 0, function* () { return (yield this.dataOwnerApi.getDataOwner(cpid)).dataOwner; })))),
331
+ ].reduce((acc, dataOwner) => {
332
+ acc[dataOwner.id] = dataOwner;
333
+ return acc;
334
+ }, {});
335
+ return Object.assign({ [ownerLegacyPublicKey]: Object.entries((_c = owner.hcPartyKeys) !== null && _c !== void 0 ? _c : {}).reduce((acc, [hcpId, keys]) => {
336
+ var _a, _b, _c;
337
+ acc[hcpId] = { [ownerLegacyPublicKey.slice(-32)]: keys[0], [(_c = (_b = (_a = counterPartsById[hcpId]) === null || _a === void 0 ? void 0 : _a.publicKey) === null || _b === void 0 ? void 0 : _b.slice(-32)) !== null && _c !== void 0 ? _c : '']: keys[1] };
338
+ return acc;
339
+ }, {}) }, ((_d = owner.aesExchangeKeys) !== null && _d !== void 0 ? _d : {}));
340
+ }
341
+ else
342
+ return (_e = owner.aesExchangeKeys) !== null && _e !== void 0 ? _e : {};
343
+ });
344
+ }
345
+ fixAesExchangeKeyEntriesToFingerprints(aesExchangeKeys) {
346
+ return Object.fromEntries(Object.entries(aesExchangeKeys).map(([delegatorPubKey, allDelegates]) => [
347
+ delegatorPubKey,
348
+ Object.fromEntries(Object.entries(allDelegates).map(([delegateId, keyEntries]) => [
349
+ delegateId,
350
+ Object.fromEntries(Object.entries(keyEntries).map(([publicKey, encryptedValue]) => [publicKey.slice(-32), encryptedValue])),
351
+ ])),
352
+ ]));
353
+ }
354
+ }
355
+ exports.BaseExchangeKeysManager = BaseExchangeKeysManager;
356
+ //# sourceMappingURL=BaseExchangeKeysManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseExchangeKeysManager.js","sourceRoot":"","sources":["../../../icc-x-api/crypto/BaseExchangeKeysManager.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,oCAAwD;AACxD,kEAA2G;AAI3G;;;;GAIG;AACH,MAAa,uBAAuB;IAQlC,YACE,UAA4B,EAC5B,YAA8B,EAC9B,cAA6B,EAC7B,cAA6B,EAC7B,aAA2B;QAZZ,8BAAyB,GAAwC,EAAE,CAAA;QAclF,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAA;QAChC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAA;QACpC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAA;QACpC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA;IACpC,CAAC;IAED;;;;;;;;OAQG;IACG,oCAAoC,CACxC,UAAkB,EAClB,oBAAwC,EACxC,oBAA6D;;YAK7D,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,qBAAqB,EAAE,CAAA;YACnE,OAAO,MAAM,IAAA,qBAAa,EAAC,IAAI,CAAC,yBAAyB,EAAE,WAAW,EAAE,GAAS,EAAE;;gBACjF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,mBAAmB,EAAE,CAAA;gBAC/D,MAAM,QAAQ,GAAG,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,UAAU,CAAC,CAAA;gBAC1G,MAAM,0BAA0B,GAAG,IAAA,cAAM,EAAC,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,oBAAoB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;gBACtH,IAAI,WAAW,GAAgD,SAAS,CAAA;gBACxE,MAAM,mBAAmB,GACvB,MAAA,MAAA,MAAA,MAAA,SAAS,CAAC,SAAS,CAAC,eAAe,0CAAG,0BAA0B,CAAC,0CAAG,UAAU,CAAC,0CAAG,0BAA0B,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,mCACxH,CAAC,0BAA0B,KAAK,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,MAAA,MAAA,SAAS,CAAC,SAAS,CAAC,WAAW,0CAAG,UAAU,CAAC,0CAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;gBACjI,IAAI,mBAAmB,EAAE;oBACvB,WAAW,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,mBAAmB,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAA;oBACxG,IAAI,CAAC,WAAW;wBACd,MAAM,IAAI,KAAK,CACb,yDAAyD,0BAA0B,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,WAAW,KAAK,UAAU,EAAE,CAC/H,CAAA;oBACH,MAAM,sBAAsB,GAAG,MAAA,MAAA,SAAS,CAAC,SAAS,CAAC,eAAe,0CAAG,0BAA0B,CAAC,0CAAG,UAAU,CAAC,CAAA;oBAC9G,IAAI,sBAAsB,EAAE;wBAC1B,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,mBAAmB,CAAC,CAAA;wBAC1D,IAAI,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;4BAChF,OAAO;gCACL,gBAAgB,EAAE,SAAS;gCAC3B,GAAG,EAAE,WAAW,CAAC,GAAG;6BACrB,CAAA;qBACJ;iBACF;gBACD,MAAM,aAAa,mCACd,oBAAoB,KACvB,CAAC,0BAA0B,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,oBAAoB,CAAC,SAAS,GACxE,CAAA;gBACD,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,aAAa,CAAC,CAAA;gBAClF,MAAM,gBAAgB,mCACjB,SAAS,CAAC,SAAS,KACtB,eAAe,EAAE,MAAM,IAAI,CAAC,kBAAkB,CAAC,SAAS,EAAE,QAAQ,EAAE,0BAA0B,EAAE,gBAAgB,CAAC,oBAAoB,CAAC,EACtI,SAAS,EAAE,MAAA,SAAS,CAAC,SAAS,CAAC,SAAS,mCAAI,0BAA0B,GACvE,CAAA;gBACD,IAAI,SAAS,CAAC,SAAS,CAAC,SAAS,KAAK,0BAA0B,EAAE;oBAChE,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC,wBAAwB,CAAC,SAAS,EAAE,QAAQ,EAAE,gBAAgB,CAAC,oBAAoB,CAAC,CAAA;iBACzH;gBACD,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC;oBAC/D,IAAI,EAAE,SAAS,CAAC,IAAI;oBACpB,SAAS,EAAE,gBAAgB;iBAC5B,CAAC,CAAA;gBACF,OAAO;oBACL,GAAG,EAAE,gBAAgB,CAAC,WAAW;oBACjC,gBAAgB;iBACjB,CAAA;YACH,CAAC,CAAA,CAAC,CAAA;QACJ,CAAC;KAAA;IAED;;;;;;;OAOG;IACG,gBAAgB,CACpB,cAAsB,EACtB,qBAA6B,EAC7B,qBAA6E;;YAE7E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,qBAAqB,EAAE,CAAA;YAC9D,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,IAAA,cAAM,EAAC,qBAAqB,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAA;YAC5G,MAAM,IAAI,CAAC,yBAAyB,CAAC,MAAM,EAAE,cAAc,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,YAAY,EAAE,qBAAqB,CAAC,CAAA;YACnI,MAAM,IAAI,CAAC,yBAAyB,CAAC,cAAc,EAAE,MAAM,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,YAAY,EAAE,qBAAqB,CAAC,CAAA;QACrI,CAAC;KAAA;IAED;;;;;OAKG;IACG,2BAA2B,CAAC,WAAmB,EAAE,UAAkB;;;YACvE,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,WAAW,CAAC,CAAA;YACnE,MAAM,GAAG,GAAiD,MAAM,CAAC,MAAM,CAAC,MAAA,SAAS,CAAC,SAAS,CAAC,eAAe,mCAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,EAAE;gBAC3I,MAAM,uBAAuB,GAAG,aAAa,CAAC,UAAU,CAAC,CAAA;gBACzD,IAAI,uBAAuB,EAAE;oBAC3B,OAAO,CAAC,uBAAuB,CAAC,CAAA;iBACjC;qBAAM;oBACL,OAAO,EAAE,CAAA;iBACV;YACH,CAAC,CAAC,CAAA;YACF,MAAM,gBAAgB,GAAG,MAAA,MAAA,SAAS,CAAC,SAAS,CAAC,WAAW,0CAAG,UAAU,CAAC,0CAAG,CAAC,CAAC,CAAA;YAC3E,IAAI,gBAAgB;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAA;YACxD,OAAO,GAAG,CAAA;;KACX;IAED;;;;;OAKG;IACG,sBAAsB,CAC1B,WAAmB,EACnB,eAAoC;;YAKpC,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;YACvF,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBACpC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,wCAAiB,CAAC,GAAG,CAAC;oBACtD,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,6BAA6B,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;oBAChF,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBACvB,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,wCAAiB,CAAC,OAAO,CAAC;oBAC1D,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,oCAAoC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;oBACvF,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBACvB,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,wCAAiB,CAAC,MAAM,CAAC;oBACzD,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,mCAAmC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;oBACrF,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;aACxB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,8CAAK,CAAC,GAAK,CAAC,GAAK,CAAC,CAA0F,CAAA,CAAC,CAAA;YACrI,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,WAAW,CAAC,CAAA;YACnE,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,uCAAuC,CAAC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;YACvG,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAC/B,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAO,GAAG,EAAE,OAAO,EAAE,EAAE;gBAClH,MAAM,UAAU,GAAG,MAAM,GAAG,CAAA;gBAC5B,IAAI,OAAO,KAAK,WAAW,EAAE;oBAC3B,OAAO,CAAC,GAAG,UAAU,EAAE,OAAO,CAAC,CAAA;iBAChC;qBAAM;oBACL,MAAM,aAAa,GAAsB,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA;oBAC7F,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,aAAa,CAAC,EAAE;wBACpD,OAAO,CAAC,GAAG,UAAU,EAAE,OAAO,CAAC,CAAA;qBAChC;;wBAAM,OAAO,UAAU,CAAA;iBACzB;YACH,CAAC,CAAA,EAAE,OAAO,CAAC,OAAO,CAAC,EAAc,CAAC,CAAC,CACpC,CAAA;YACD,MAAM,aAAa,GAAG,MAAM,CAAC,WAAW,CACtC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;iBACzB,GAAG,CAAC,CAAC,CAAC,eAAe,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC;gBAC1C,eAAe;gBACf,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAwC,CAClI;aACF,CAAC;iBACD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAyD,CACxG,CAAA;YACD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,CAAA;QACvC,CAAC;KAAA;IAED;;;;;OAKG;IACG,sBAAsB,CAC1B,qBAAmE,EACnE,qBAA6E;;YAK7E,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;YAC9B,MAAM,GAAG,GAGL,EAAE,qBAAqB,EAAE,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE,CAAA;YACxD,KAAK,MAAM,oBAAoB,IAAI,qBAAqB,EAAE;gBACxD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,oBAAoB,EAAE,qBAAqB,CAAC,CAAA;gBAC/F,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE;oBACvD,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;oBACvB,GAAG,CAAC,qBAAqB,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;iBAC9C;qBAAM;oBACL,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;iBACjD;aACF;YACD,OAAO,GAAG,CAAA;QACZ,CAAC;KAAA;IAEa,yBAAyB,CACrC,WAAmB,EACnB,UAAkB,EAClB,cAAsB,EACtB,YAAuB,EACvB,+BAAuF;;YAEvF,MAAM,IAAA,qBAAa,EAAC,IAAI,CAAC,yBAAyB,EAAE,WAAW,EAAE,GAAS,EAAE;gBAC1E,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,WAAW,CAAC,CAAA;gBACnE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,UAAU,CAAC,CAAA;gBACjE,IAAI,gBAAgB,GAAG,KAAK,CAAA;gBAC5B,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,uCAAuC,CAAC,SAAS,CAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAA;gBAChH,MAAM,mBAAmB,GAAsF,EAAE,CAAA;gBACjH,MAAM,iBAAiB,GAAG,EAAE,CAAC,cAAc,CAAC,EAAE,YAAY,EAAE,CAAA;gBAC5D,KAAK,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE;oBAClF,MAAM,sBAAsB,GAA0D,EAAE,CAAA;oBACxF,KAAK,MAAM,CAAC,cAAc,EAAE,gBAAgB,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE;wBACpF,IAAI,UAAU,KAAK,cAAc,IAAI,cAAc,IAAI,gBAAgB,EAAE;4BACvE,sBAAsB,CAAC,cAAc,CAAC,GAAG,gBAAgB,CAAA;yBAC1D;6BAAM;4BACL,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,gBAAgB,EAAE,+BAA+B,CAAC,CAAA;4BACrG,IAAI,SAAS,EAAE;gCACb,gBAAgB,GAAG,IAAI,CAAA;gCACvB,sBAAsB,CAAC,cAAc,CAAC,mCACjC,gBAAgB,GAChB,CAAC,MAAM,IAAI,CAAC,kBAAkB,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAC,oBAAoB,CACtF,CAAA;6BACF;iCAAM;gCACL,sBAAsB,CAAC,cAAc,CAAC,GAAG,gBAAgB,CAAA;6BAC1D;yBACF;qBACF;oBACD,mBAAmB,CAAC,gBAAgB,CAAC,GAAG,sBAAsB,CAAA;iBAC/D;gBACD,IAAI,gBAAgB,EAAE;oBACpB,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC;wBACtC,IAAI,EAAE,SAAS,CAAC,IAAI;wBACpB,SAAS,kCACJ,SAAS,CAAC,SAAS,KACtB,eAAe,EAAE,mBAAmB,GACrC;qBACF,CAAC,CAAA;iBACH;YACH,CAAC,CAAA,CAAC,CAAA;QACJ,CAAC;KAAA;IAED;;;;;;OAMG;IACW,qBAAqB,CACjC,oBAAgE,EAChE,qBAA6E;;YAE7E,KAAK,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE;gBACxE,kHAAkH;gBAClH,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAA;gBAC9B,MAAM,OAAO,GAAG,qBAAqB,CAAC,EAAE,CAAC,CAAA;gBACzC,IAAI,OAAO,KAAK,SAAS,EAAE;oBACzB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;oBACxE,IAAI,GAAG,KAAK,SAAS;wBAAE,OAAO,GAAG,CAAA;iBAClC;aACF;YACD,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,EAAE,CAAC,CAAA;YACpD,IAAI,mBAAmB,KAAK,SAAS,EAAE;gBACrC,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,EAAE;oBAC1D,oEAAoE;oBACpE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,mBAAmB,EAAE,OAAO,EAAE,SAAS,CAAC,CAAA;oBACzF,IAAI,GAAG,KAAK,SAAS;wBAAE,OAAO,GAAG,CAAA;iBAClC;aACF;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;KAAA;IAED;;;;;OAKG;IACW,kBAAkB,CAC9B,WAAwD,EACxD,UAAmD;;;YAKnD,MAAM,iBAAiB,GAAG,MAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,GAAG,mCAAI,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAA;YAClG,MAAM,gBAAgB,GAAG,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,IAAA,cAAM,EAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAA;YAC5I,MAAM,oBAAoB,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,CAClE,CAAO,GAAG,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE;gBAAC,OAAA,iCAChC,CAAC,MAAM,GAAG,CAAC,KACd,CAAC,SAAS,CAAC,EAAE,IAAA,cAAM,EAAC,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC,IACjG,CAAA;cAAA,EACF,OAAO,CAAC,OAAO,CAAC,EAAoC,CAAC,CACtD,CAAA;YACD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,CAAA;;KAChE;IAED;;;;;;;;;OASG;IACW,yBAAyB,CACrC,iBAAyB,EACzB,OAA2B,EAC3B,SAA6B,CAAC,iGAAiG;;;YAE/H,IAAI;gBACF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,IAAA,cAAM,EAAC,iBAAiB,CAAC,CAAC,CAAA;gBAClG,OAAO,EAAE,GAAG,EAAE,IAAA,cAAM,EAAC,SAAS,CAAC,EAAE,GAAG,EAAE,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAA;aAC9F;YAAC,OAAO,CAAC,EAAE;gBACV,IAAI,SAAS,EAAE;oBACb,OAAO,CAAC,KAAK,CAAC,4CAA4C,iBAAiB,+BAA+B,SAAS,GAAG,EAAE,CAAC,CAAC,CAAA;iBAC3H;aACF;QACH,CAAC;KAAA;IAEO,wBAAwB,CAC9B,SAA4B,EAC5B,QAA2B,EAC3B,eAAyC;;QAEzC,MAAM,2BAA2B,GAAG,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC9H,MAAM,0BAA0B,GAAG,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC3H,IAAI,2BAA2B,IAAI,0BAA0B,EAAE;YAC7D,uCACK,CAAC,MAAA,SAAS,CAAC,SAAS,CAAC,WAAW,mCAAI,EAAE,CAAC,KAC1C,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAG,CAAC,EAAE,CAAC,2BAA2B,EAAE,0BAA0B,CAAC,IACpF;SACF;;YAAM,OAAO,SAAS,CAAC,SAAS,CAAC,WAAW,CAAA;IAC/C,CAAC;IAEa,kBAAkB,CAC9B,SAA4B,EAC5B,QAA2B,EAC3B,0BAAkC,EAClC,eAAyC;;;YAEzC,MAAM,uBAAuB,GAAG,MAAM,IAAI,CAAC,uCAAuC,CAAC,SAAS,CAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAA;YAC3H,OAAO,IAAI,CAAC,sCAAsC,iCAC7C,uBAAuB,KAC1B,CAAC,0BAA0B,CAAC,kCACvB,CAAC,MAAA,uBAAuB,CAAC,0BAA0B,CAAC,mCAAI,EAAE,CAAC,KAC9D,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAG,CAAC,kCACnB,CAAC,MAAA,MAAA,uBAAuB,CAAC,0BAA0B,CAAC,0CAAG,QAAQ,CAAC,SAAS,CAAC,EAAG,CAAC,mCAAI,EAAE,CAAC,GACrF,eAAe,QAGtB,CAAA;;KACH;IAED,mEAAmE;IACrD,uCAAuC,CACnD,KAAgB,EAChB,QAA+B;;;YAE/B,MAAM,oBAAoB,GAAG,KAAK,CAAC,SAAS,CAAA;YAC5C,IAAI,oBAAoB,IAAI,CAAC,CAAC,MAAA,KAAK,CAAC,eAAe,mCAAI,EAAE,CAAC,CAAC,oBAAoB,CAAC,EAAE;gBAChF;;;;mBAIG;gBACH,MAAM,8BAA8B,GAAG,MAAM,CAAC,IAAI,CAAC,MAAA,KAAK,CAAC,WAAW,mCAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,EAAE,IAAI,CAAC,MAAK,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,EAAE,CAAA,CAAC,CAAA;gBAC/H,MAAM,gBAAgB,GAAG;oBACvB,KAAK;oBACL,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC/B,GAAG,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,GAAG,CAAC,CAAO,IAAI,EAAE,EAAE,gDAAC,OAAA,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA,GAAA,CAAC,CAAC,CAAC;iBACnI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE;oBAC1B,GAAG,CAAC,SAAS,CAAC,EAAG,CAAC,GAAG,SAAS,CAAA;oBAC9B,OAAO,GAAG,CAAA;gBACZ,CAAC,EAAE,EAAiC,CAAC,CAAA;gBACrC,uBACE,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,MAAA,KAAK,CAAC,WAAW,mCAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE;;wBAC5F,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAA,MAAA,MAAA,gBAAgB,CAAC,KAAK,CAAC,0CAAE,SAAS,0CAAE,KAAK,CAAC,CAAC,EAAE,CAAC,mCAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;wBAC5H,OAAO,GAAG,CAAA;oBACZ,CAAC,EAAE,EAAiE,CAAC,IAClE,CAAC,MAAA,KAAK,CAAC,eAAe,mCAAI,EAAE,CAAC,EACjC;aACF;;gBAAM,OAAO,MAAA,KAAK,CAAC,eAAe,mCAAI,EAAE,CAAA;;KAC1C;IAEO,sCAAsC,CAAC,eAE9C;QACC,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,EAAE,YAAY,CAAC,EAAE,EAAE,CAAC;YACvE,eAAe;YACf,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC;gBAC7D,UAAU;gBACV,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;aAC5H,CAAC,CACH;SACF,CAAC,CACH,CAAA;IACH,CAAC;CACF;AAlaD,0DAkaC","sourcesContent":["import { KeyPair } from './RSA'\nimport { hex2ua, notConcurrent, ua2hex } from '../utils'\nimport { DataOwner, DataOwnerTypeEnum, DataOwnerWithType, IccDataOwnerXApi } from '../icc-data-owner-x-api'\nimport { CryptoPrimitives } from './CryptoPrimitives'\nimport { IccDeviceApi, IccHcpartyApi, IccPatientApi } from '../../icc-api'\n\n/**\n * @internal This class is meant only for internal use and may be changed without notice.\n * Functions to create and get exchange keys.\n * The methods of this api require to pass the appropriate keys for encryption/decryption manually.\n */\nexport class BaseExchangeKeysManager {\n private readonly generateKeyConcurrencyMap: { [key: string]: PromiseLike<any> } = {}\n private readonly primitives: CryptoPrimitives\n private readonly dataOwnerApi: IccDataOwnerXApi\n private readonly hcpartyBaseApi: IccHcpartyApi\n private readonly patientBaseApi: IccPatientApi\n private readonly deviceBaseApi: IccDeviceApi\n\n constructor(\n primitives: CryptoPrimitives,\n dataOwnerApi: IccDataOwnerXApi,\n hcpartyBaseApi: IccHcpartyApi,\n patientBaseApi: IccPatientApi,\n deviceBaseApi: IccDeviceApi\n ) {\n this.primitives = primitives\n this.dataOwnerApi = dataOwnerApi\n this.hcpartyBaseApi = hcpartyBaseApi\n this.patientBaseApi = patientBaseApi\n this.deviceBaseApi = deviceBaseApi\n }\n\n /**\n * Creates a new exchange key from the current data owner to a delegate, or updates an existing one allowing additional public keys to access it.\n * @param delegateId the delegate data owner id.\n * @param delegatorMainKeyPair main key pair for the delegator. The private key will be used for the decryption of the existing key in case of\n * update, and the public key will be used as entry key of the aesExchangeKey map\n * @param additionalPublicKeys all public keys of key pairs other than {@link delegatorMainKeyPair} that need to have access to the exchange key.\n * Can be a mix of crypto keys and full hex-encoded spki format (no fingerprints).\n * @return the exchange key for the delegator-delegate-delegatorKey triple (new or existing) and the updated delegator.\n */\n async createOrUpdateEncryptedExchangeKeyTo(\n delegateId: string,\n delegatorMainKeyPair: KeyPair<CryptoKey>,\n additionalPublicKeys: { [keyFingerprint: string]: CryptoKey }\n ): Promise<{\n updatedDelegator: DataOwnerWithType\n key: CryptoKey\n }> {\n const delegatorId = await this.dataOwnerApi.getCurrentDataOwnerId()\n return await notConcurrent(this.generateKeyConcurrencyMap, delegatorId, async () => {\n const delegator = await this.dataOwnerApi.getCurrentDataOwner()\n const delegate = delegatorId === delegateId ? delegator : await this.dataOwnerApi.getDataOwner(delegateId)\n const mainDelegatorKeyPairPubHex = ua2hex(await this.primitives.RSA.exportKey(delegatorMainKeyPair.publicKey, 'spki'))\n let exchangeKey: { raw: string; key: CryptoKey } | undefined = undefined\n const existingExchangeKey =\n delegator.dataOwner.aesExchangeKeys?.[mainDelegatorKeyPairPubHex]?.[delegateId]?.[mainDelegatorKeyPairPubHex.slice(-32)] ??\n (mainDelegatorKeyPairPubHex === delegator.dataOwner.publicKey ? delegator.dataOwner.hcPartyKeys?.[delegateId]?.[0] : undefined)\n if (existingExchangeKey) {\n exchangeKey = await this.tryDecryptExchangeKeyWith(existingExchangeKey, delegatorMainKeyPair, undefined)\n if (!exchangeKey)\n throw new Error(\n `Failed to decrypt existing exchange key for update of ${mainDelegatorKeyPairPubHex.slice(-32)}@${delegatorId}->${delegateId}`\n )\n const existingAesExchangeKey = delegator.dataOwner.aesExchangeKeys?.[mainDelegatorKeyPairPubHex]?.[delegateId]\n if (existingAesExchangeKey) {\n const existingPublicKeysSet = new Set(existingExchangeKey)\n if (Object.keys(additionalPublicKeys).every((fp) => existingPublicKeysSet.has(fp)))\n return {\n updatedDelegator: delegator,\n key: exchangeKey.key,\n }\n }\n }\n const allPublicKeys = {\n ...additionalPublicKeys,\n [mainDelegatorKeyPairPubHex.slice(-32)]: delegatorMainKeyPair.publicKey,\n }\n const encryptedKeyInfo = await this.encryptExchangeKey(exchangeKey, allPublicKeys)\n const updatedDataOwner: DataOwner = {\n ...delegator.dataOwner,\n aesExchangeKeys: await this.updateExchangeKeys(delegator, delegate, mainDelegatorKeyPairPubHex, encryptedKeyInfo.encryptedExchangeKey),\n publicKey: delegator.dataOwner.publicKey ?? mainDelegatorKeyPairPubHex,\n }\n if (delegator.dataOwner.publicKey === mainDelegatorKeyPairPubHex) {\n updatedDataOwner.hcPartyKeys = this.updateLegacyExchangeKeys(delegator, delegate, encryptedKeyInfo.encryptedExchangeKey)\n }\n const updatedDelegator = await this.dataOwnerApi.updateDataOwner({\n type: delegator.type,\n dataOwner: updatedDataOwner,\n })\n return {\n key: encryptedKeyInfo.exchangeKey,\n updatedDelegator,\n }\n })\n }\n\n /**\n * Updates the aes exchange keys between the current data owner and another data owner to allow the other data owner to access the exchange key\n * using his new public key. Note that this will make existing exchange keys from the other data owner to the current data owner invalid for\n * encryption.\n * @param otherDataOwner the other data owner.\n * @param newDataOwnerPublicKey a new public key of the other data owner.\n * @param keyPairsByFingerprint all available key pairs to use for the decryption of existing aes exchange keys.\n */\n async giveAccessBackTo(\n otherDataOwner: string,\n newDataOwnerPublicKey: string,\n keyPairsByFingerprint: { [publicKeyFingerprint: string]: KeyPair<CryptoKey> }\n ) {\n const selfId = await this.dataOwnerApi.getCurrentDataOwnerId()\n const newPublicKey = await this.primitives.RSA.importKey('spki', hex2ua(newDataOwnerPublicKey), ['encrypt'])\n await this.extendForGiveAccessBackTo(selfId, otherDataOwner, newDataOwnerPublicKey.slice(-32), newPublicKey, keyPairsByFingerprint)\n await this.extendForGiveAccessBackTo(otherDataOwner, selfId, newDataOwnerPublicKey.slice(-32), newPublicKey, keyPairsByFingerprint)\n }\n\n /**\n * Get the encrypted exchange keys for a delegator-delegate pair.\n * @param delegatorId id of the delegator data owner.\n * @param delegateId id of the delegate data owner.\n * @return an array of exchange keys from the delegator to delegate where each key is encrypted with one or more public keys.\n */\n async getEncryptedExchangeKeysFor(delegatorId: string, delegateId: string): Promise<{ [publicKeyFingerprint: string]: string }[]> {\n const delegator = await this.dataOwnerApi.getDataOwner(delegatorId)\n const res: { [publicKeyFingerprint: string]: string }[] = Object.values(delegator.dataOwner.aesExchangeKeys ?? {}).flatMap((delegateToKey) => {\n const encryptedKeyForDelegate = delegateToKey[delegateId]\n if (encryptedKeyForDelegate) {\n return [encryptedKeyForDelegate]\n } else {\n return []\n }\n })\n const legacyDelegation = delegator.dataOwner.hcPartyKeys?.[delegateId]?.[1]\n if (legacyDelegation) res.push({ '': legacyDelegation })\n return res\n }\n\n /**\n * Get all exchange keys where the provided data owner is involved either as the delegator or as the delegate.\n * @param dataOwnerId id of a data owner.\n * @param otherOwnerTypes only exchange keys between the current data owner and data owners of this type will be included in the result.\n * @return all exchange keys involving the provided data owner. Note that there may be an overlap between some keys to and from the data owner.\n */\n async getAllExchangeKeysWith(\n dataOwnerId: string,\n otherOwnerTypes: DataOwnerTypeEnum[]\n ): Promise<{\n keysToOwner: { [delegatorId: string]: { [delegatorFp: string]: { [entryFp: string]: string } } }\n keysFromOwner: { [delegatorFp: string]: { [delegateId: string]: { [entryFp: string]: string } } }\n }> {\n if (otherOwnerTypes.length === 0) throw new Error('otherOwnerTypes must not be empty!')\n const keysToOwner = await Promise.all([\n otherOwnerTypes.find((x) => x === DataOwnerTypeEnum.Hcp)\n ? this.hcpartyBaseApi.getAesExchangeKeysForDelegate(dataOwnerId).catch(() => {})\n : Promise.resolve({}),\n otherOwnerTypes.find((x) => x === DataOwnerTypeEnum.Patient)\n ? this.patientBaseApi.getPatientAesExchangeKeysForDelegate(dataOwnerId).catch(() => {})\n : Promise.resolve({}),\n otherOwnerTypes.find((x) => x === DataOwnerTypeEnum.Device)\n ? this.deviceBaseApi.getDeviceAesExchangeKeysForDelegate(dataOwnerId).catch(() => {})\n : Promise.resolve({}),\n ]).then(([a, b, c]) => ({ ...a, ...b, ...c } as { [delegatorId: string]: { [delegatorFp: string]: { [entryFp: string]: string } } }))\n const dataOwner = await this.dataOwnerApi.getDataOwner(dataOwnerId)\n const allOwnerKeys = await this.combineLegacyHcpKeysWithAesExchangeKeys(dataOwner.dataOwner, undefined)\n const filteredDelegates = new Set(\n await Array.from(new Set(Object.values(allOwnerKeys).flatMap((x) => Object.keys(x)))).reduce(async (acc, ownerId) => {\n const awaitedAcc = await acc\n if (ownerId === dataOwnerId) {\n return [...awaitedAcc, ownerId]\n } else {\n const dataOwnerType: DataOwnerTypeEnum = (await this.dataOwnerApi.getDataOwner(ownerId)).type\n if (otherOwnerTypes.some((x) => x === dataOwnerType)) {\n return [...awaitedAcc, ownerId]\n } else return awaitedAcc\n }\n }, Promise.resolve([] as string[]))\n )\n const keysFromOwner = Object.fromEntries(\n Object.entries(allOwnerKeys)\n .map(([delegatorPubKey, delegateToKeys]) => [\n delegatorPubKey,\n Object.fromEntries(\n Object.entries(delegateToKeys).filter(([delegateId]) => filteredDelegates.has(delegateId)) as [string, { [k: string]: string }][]\n ),\n ])\n .filter(([, x]) => Object.keys(x).length > 0) as [string, { [k: string]: { [k: string]: string } }][]\n )\n return { keysToOwner, keysFromOwner }\n }\n\n /**\n * Attempts to decrypt many exchange keys using any of the provided key pairs.\n * @param encryptedExchangeKeys an array of exchange keys where each key is encrypted with one or more public keys.\n * @param keyPairsByFingerprint rsa key pairs to use for decryption.\n * @return an array all successfully decrypted exchange keys and an array containing all exchange keys which could not be decrypted.\n */\n async tryDecryptExchangeKeys(\n encryptedExchangeKeys: { [publicKeyFingerprint: string]: string }[],\n keyPairsByFingerprint: { [publicKeyFingerprint: string]: KeyPair<CryptoKey> }\n ): Promise<{\n successfulDecryptions: CryptoKey[]\n failedDecryptions: { [publicKeyFingerprint: string]: string }[]\n }> {\n const raws = new Set<string>()\n const res: {\n successfulDecryptions: CryptoKey[]\n failedDecryptions: { [publicKeyFingerprint: string]: string }[]\n } = { successfulDecryptions: [], failedDecryptions: [] }\n for (const encryptedExchangeKey of encryptedExchangeKeys) {\n const decrypted = await this.tryDecryptExchangeKey(encryptedExchangeKey, keyPairsByFingerprint)\n if (decrypted !== undefined && !raws.has(decrypted.raw)) {\n raws.add(decrypted.raw)\n res.successfulDecryptions.push(decrypted.key)\n } else {\n res.failedDecryptions.push(encryptedExchangeKey)\n }\n }\n return res\n }\n\n private async extendForGiveAccessBackTo(\n delegatorId: string,\n delegateId: string,\n newPublicKeyFp: string,\n newPublicKey: CryptoKey,\n decryptionKeyPairsByFingerprint: { [publicKeyFingerprint: string]: KeyPair<CryptoKey> }\n ) {\n await notConcurrent(this.generateKeyConcurrencyMap, delegatorId, async () => {\n const delegator = await this.dataOwnerApi.getDataOwner(delegatorId)\n const delegate = await this.dataOwnerApi.getDataOwner(delegateId)\n let didUpdateSomeKey = false\n const combinedKeys = await this.combineLegacyHcpKeysWithAesExchangeKeys(delegator.dataOwner, delegate.dataOwner)\n const updatedExchangeKeys: { [delegatorKey: string]: { [delegateId: string]: { [keyFp: string]: string } } } = {}\n const newEncryptionKeys = { [newPublicKeyFp]: newPublicKey }\n for (const [currDelegatorKey, currDelegatesToKeys] of Object.entries(combinedKeys)) {\n const updatedDelegatesToKeys: { [delegateId: string]: { [keyFp: string]: string } } = {}\n for (const [currDelegateId, currEncryptedKey] of Object.entries(currDelegatesToKeys)) {\n if (delegateId !== currDelegateId || newPublicKeyFp in currEncryptedKey) {\n updatedDelegatesToKeys[currDelegateId] = currEncryptedKey\n } else {\n const decrypted = await this.tryDecryptExchangeKey(currEncryptedKey, decryptionKeyPairsByFingerprint)\n if (decrypted) {\n didUpdateSomeKey = true\n updatedDelegatesToKeys[currDelegateId] = {\n ...currEncryptedKey,\n ...(await this.encryptExchangeKey(decrypted, newEncryptionKeys)).encryptedExchangeKey,\n }\n } else {\n updatedDelegatesToKeys[currDelegateId] = currEncryptedKey\n }\n }\n }\n updatedExchangeKeys[currDelegatorKey] = updatedDelegatesToKeys\n }\n if (didUpdateSomeKey) {\n await this.dataOwnerApi.updateDataOwner({\n type: delegator.type,\n dataOwner: {\n ...delegator.dataOwner,\n aesExchangeKeys: updatedExchangeKeys,\n },\n })\n }\n })\n }\n\n /**\n * Attempts to decrypt an exchange key using any of the provided key pairs.\n * @param encryptedExchangeKey an encrypted exchange key, in the form publicKeyXyzFingerprint -> hex(exchangeKeyEncryptedByPrivateKeyXyz).\n * @param keyPairsByFingerprint rsa key pairs to use for decryption.\n * @return the decrypted exchange key, in raw and key format (to allow deduplication), or undefined if the key could not be decrypted using the\n * provided keys.\n */\n private async tryDecryptExchangeKey(\n encryptedExchangeKey: { [publicKeyFingerprint: string]: string },\n keyPairsByFingerprint: { [publicKeyFingerprint: string]: KeyPair<CryptoKey> }\n ): Promise<{ raw: string; key: CryptoKey } | undefined> {\n for (const [entryKey, encrypted] of Object.entries(encryptedExchangeKey)) {\n // Due to bugs in past version the entry may actually contain the full public key instead of just the fingerprint.\n const fp = entryKey.slice(-32)\n const keyPair = keyPairsByFingerprint[fp]\n if (keyPair !== undefined) {\n const res = await this.tryDecryptExchangeKeyWith(encrypted, keyPair, fp)\n if (res !== undefined) return res\n }\n }\n const defaultEncryptedKey = encryptedExchangeKey['']\n if (defaultEncryptedKey !== undefined) {\n for (const keyPair of Object.values(keyPairsByFingerprint)) {\n // disable error logging, we are not sure keyPair is the correct key\n const res = await this.tryDecryptExchangeKeyWith(defaultEncryptedKey, keyPair, undefined)\n if (res !== undefined) return res\n }\n }\n return undefined\n }\n\n /**\n * Creates an encrypted exchange key for the provided public keys.\n * @param exchangeKey the exchange key in raw and imported format. If undefined a new key will be automatically created.\n * @param publicKeys additional public keys that will have access to the exchange key in spki format, hex-encoded.\n * @return the exchangeKey and an object with the exchange key encrypted with each of the provided public keys, hex-encoded, by fingerprint.\n */\n private async encryptExchangeKey(\n exchangeKey: { raw: string; key: CryptoKey } | undefined,\n publicKeys: { [keyFingerprint: string]: CryptoKey }\n ): Promise<{\n exchangeKey: CryptoKey\n encryptedExchangeKey: { [pubKeyFp: string]: string }\n }> {\n const exchangeKeyCrypto = exchangeKey?.key ?? (await this.primitives.AES.generateCryptoKey(false))\n const exchangeKeyBytes = exchangeKey !== undefined ? hex2ua(exchangeKey.raw) : await this.primitives.AES.exportKey(exchangeKeyCrypto, 'raw')\n const encryptedExchangeKey = await Object.entries(publicKeys).reduce(\n async (acc, [currKeyFp, currKey]) => ({\n ...(await acc),\n [currKeyFp]: ua2hex(await this.primitives.RSA.encrypt(currKey, new Uint8Array(exchangeKeyBytes))),\n }),\n Promise.resolve({} as { [pubKeyFp: string]: string })\n )\n return { exchangeKey: exchangeKeyCrypto, encryptedExchangeKey }\n }\n\n /**\n * Attempts to decrypt an exchange key using the provided key pairs.\n * If you are confident that the provided {@link keyPair} was used to encrypt {@link encryptedByOneKey} you should also provide {@link keyPairFp},\n * so that if the decryption fail an error will be logged to console before returning undefined.\n * @param encryptedByOneKey an exchange key which may be encrypted with {@link keyPair}.\n * @param keyPair an rsa key pair.\n * @param keyPairFp the fingerprint of the provided key pair or undefined to disable logging of error if the decryption failed.\n * @return the decrypted exchange key, in raw and key format (to allow deduplication), or undefined if the key could not be decrypted using the\n * provided key.\n */\n private async tryDecryptExchangeKeyWith(\n encryptedByOneKey: string,\n keyPair: KeyPair<CryptoKey>,\n keyPairFp: string | undefined // if undefined will not log errors, when we are not sure the key to be used is the provided key.\n ): Promise<{ raw: string; key: CryptoKey } | undefined> {\n try {\n const decrypted = await this.primitives.RSA.decrypt(keyPair.privateKey, hex2ua(encryptedByOneKey))\n return { raw: ua2hex(decrypted), key: await this.primitives.AES.importKey('raw', decrypted) }\n } catch (e) {\n if (keyPairFp) {\n console.error(`Failed to decrypt or import exchange key ${encryptedByOneKey} using key with fingerprint ${keyPairFp}.`, e)\n }\n }\n }\n\n private updateLegacyExchangeKeys(\n delegator: DataOwnerWithType,\n delegate: DataOwnerWithType,\n encryptedKeyMap: { [fp: string]: string }\n ): { [delegateId: string]: string[] } | undefined {\n const legacyEncryptedKeyDelegator = delegator.dataOwner.publicKey ? encryptedKeyMap[delegator.dataOwner.publicKey] : undefined\n const legacyEncryptedKeyDelegate = delegate.dataOwner.publicKey ? encryptedKeyMap[delegate.dataOwner.publicKey] : undefined\n if (legacyEncryptedKeyDelegator && legacyEncryptedKeyDelegate) {\n return {\n ...(delegator.dataOwner.hcPartyKeys ?? {}),\n [delegate.dataOwner.id!]: [legacyEncryptedKeyDelegator, legacyEncryptedKeyDelegate],\n }\n } else return delegator.dataOwner.hcPartyKeys\n }\n\n private async updateExchangeKeys(\n delegator: DataOwnerWithType,\n delegate: DataOwnerWithType,\n mainDelegatorKeyPairPubHex: string,\n encryptedKeyMap: { [fp: string]: string }\n ): Promise<{ [ownerPublicKey: string]: { [delegateId: string]: { [fingerprint: string]: string } } }> {\n const combinedAesExchangeKeys = await this.combineLegacyHcpKeysWithAesExchangeKeys(delegator.dataOwner, delegate.dataOwner)\n return this.fixAesExchangeKeyEntriesToFingerprints({\n ...combinedAesExchangeKeys,\n [mainDelegatorKeyPairPubHex]: {\n ...(combinedAesExchangeKeys[mainDelegatorKeyPairPubHex] ?? {}),\n [delegate.dataOwner.id!]: {\n ...(combinedAesExchangeKeys[mainDelegatorKeyPairPubHex]?.[delegate.dataOwner.id!] ?? {}),\n ...encryptedKeyMap,\n },\n },\n })\n }\n\n // Copy all legacy hcp exchange keys into the new aes exchange keys\n private async combineLegacyHcpKeysWithAesExchangeKeys(\n owner: DataOwner,\n delegate: DataOwner | undefined\n ): Promise<{ [ownerPublicKey: string]: { [delegateId: string]: { [fingerprint: string]: string } } }> {\n const ownerLegacyPublicKey = owner.publicKey\n if (ownerLegacyPublicKey && !(owner.aesExchangeKeys ?? {})[ownerLegacyPublicKey]) {\n /*\n * This condition would technically prevent new updates to the hcPartyKeys to be migrated to the aes exchange keys, but since I can only update\n * data for self data owner and parent entities this is not an issue, because I will always be using the new api from now on and I won't have\n * a situation where the legacy keys are updated but the aes exchange keys are not.\n */\n const unknownDataOwnerCounterPartIds = Object.keys(owner.hcPartyKeys ?? {}).filter((x) => x !== owner.id && x !== delegate?.id)\n const counterPartsById = [\n owner,\n ...(delegate ? [delegate] : []),\n ...(await Promise.all(unknownDataOwnerCounterPartIds.map(async (cpid) => (await this.dataOwnerApi.getDataOwner(cpid)).dataOwner))),\n ].reduce((acc, dataOwner) => {\n acc[dataOwner.id!] = dataOwner\n return acc\n }, {} as { [id: string]: DataOwner })\n return {\n [ownerLegacyPublicKey]: Object.entries(owner.hcPartyKeys ?? {}).reduce((acc, [hcpId, keys]) => {\n acc[hcpId] = { [ownerLegacyPublicKey.slice(-32)]: keys[0], [counterPartsById[hcpId]?.publicKey?.slice(-32) ?? '']: keys[1] }\n return acc\n }, {} as { [delegateId: string]: { [fingerprint: string]: string } }),\n ...(owner.aesExchangeKeys ?? {}),\n }\n } else return owner.aesExchangeKeys ?? {}\n }\n\n private fixAesExchangeKeyEntriesToFingerprints(aesExchangeKeys: {\n [delegatorPubKey: string]: { [delegateId: string]: { [pubKeyFp: string]: string } }\n }): { [delegatorPubKey: string]: { [delegateId: string]: { [pubKeyFp: string]: string } } } {\n return Object.fromEntries(\n Object.entries(aesExchangeKeys).map(([delegatorPubKey, allDelegates]) => [\n delegatorPubKey,\n Object.fromEntries(\n Object.entries(allDelegates).map(([delegateId, keyEntries]) => [\n delegateId,\n Object.fromEntries(Object.entries(keyEntries).map(([publicKey, encryptedValue]) => [publicKey.slice(-32), encryptedValue])),\n ])\n ),\n ])\n )\n }\n}\n"]}
@@ -0,0 +1,58 @@
1
+ import { EncryptedEntity } from '../../icc-api/model/models';
2
+ import { EntitiesEncryption } from './EntitiesEncryption';
3
+ import { CryptoPrimitives } from './CryptoPrimitives';
4
+ import { IccDataOwnerXApi } from '../icc-data-owner-x-api';
5
+ /**
6
+ * This class helps to create confidential medical data in systems where multiple hcps share data with each other using parent hcps: while normally
7
+ * the hcps would share all data with other hcps part of the same "family" (e.g. an hospital) there are situations where the medical data is
8
+ * confidential and should only be known by the doctor which created the data. In these situations it is also important that the secret foreign key
9
+ * used in the confidential data is not known by other members of the hcp family, otherwise they may be able to draw some links between the medical
10
+ * data and the patient.
11
+ */
12
+ export declare class ConfidentialEntities {
13
+ private readonly entitiesEncryption;
14
+ private readonly primitives;
15
+ private readonly dataOwnerApi;
16
+ constructor(entitiesEncryption: EntitiesEncryption, primitives: CryptoPrimitives, dataOwnerApi: IccDataOwnerXApi);
17
+ /**
18
+ * Ensures that the current data owner has access to a confidential secret id for the provided entity: this is an id that is known to the data owner
19
+ * but is not known by any of his parents. If there is currently no confidential secret id for this entity the method returns a copy of the entity
20
+ * with a new confidential secret id for the current data owner (the entity in the database won't be updated), else this method returns undefined.
21
+ * New confidential secret ids will have an appropriate tag, but existing confidential secret ids may not necessarily have it.
22
+ * @param entity an entity which needs to have a confidential secret id for the current data owner
23
+ * @return undefined if the entity already had a confidential secret id for the current user, or the updated entity with the new confidential secret
24
+ * id.
25
+ */
26
+ entityWithInitialisedConfidentialSecretId<T extends EncryptedEntity>(entity: T): Promise<T | undefined>;
27
+ /**
28
+ * Get an existing confidential secret id of the provided entity for the provided data owner (current data owner by default). A confidential secret
29
+ * id is a secret id known by the data owner but not known by any of his parents: note however that children will know confidential secret ids.
30
+ * @param entity an entity for which you want to retrieve the confidential secret id.
31
+ * @param dataOwnerId (current data owner by default) a data owner for which you want to get a confidential secret id.
32
+ * @return the confidential secret id or undefined if there is no confidential secret id for the provided data owner.
33
+ */
34
+ getConfidentialSecretId(entity: EncryptedEntity, dataOwnerId?: string): Promise<string | undefined>;
35
+ /**
36
+ * Gets a secret id known by the topmost parent of the current data owner hierarchy. If there is multiple secret ids shared with the topmost parent
37
+ * there is no guarantee on which one will be chosen.
38
+ * @param entity an entity.
39
+ * @return a secret id known by the topmost parent of the current data owner hierarchy, or undefined if there is no secret id currently available
40
+ * for the topmost parent.
41
+ */
42
+ getAnySecretIdSharedWithParents(entity: EncryptedEntity): Promise<string | undefined>;
43
+ /**
44
+ * Get all existing confidential secret ids of the provided entity for the provided data owner (current data owner by default). A confidential secret
45
+ * id is a secret id known by the data owner but not known by any of his parents: note however that children will know confidential secret ids.
46
+ * @param entity an entity for which you want to retrieve the confidential secret id.
47
+ * @param dataOwnerId (current data owner by default) a data owner for which you want to get a confidential secret id.
48
+ * @return the confidential secret ids for the data owner (may be empty).
49
+ */
50
+ getConfidentialSecretIds(entity: EncryptedEntity, dataOwnerId?: string): Promise<string[]>;
51
+ /**
52
+ * Gets all secret ids known by the topmost parent of the current data owner hierarchy (or all secret ids known by the current data owner if he is
53
+ * not part of any data owner hierarchy).
54
+ * @param entity an entity.
55
+ * @return all secret ids known by the topmost parent of the current data owner hierarchy, may be empty.
56
+ */
57
+ getSecretIdsSharedWithParents(entity: EncryptedEntity): Promise<string[]>;
58
+ }
@@ -0,0 +1,99 @@
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.ConfidentialEntities = void 0;
13
+ /**
14
+ * This class helps to create confidential medical data in systems where multiple hcps share data with each other using parent hcps: while normally
15
+ * the hcps would share all data with other hcps part of the same "family" (e.g. an hospital) there are situations where the medical data is
16
+ * confidential and should only be known by the doctor which created the data. In these situations it is also important that the secret foreign key
17
+ * used in the confidential data is not known by other members of the hcp family, otherwise they may be able to draw some links between the medical
18
+ * data and the patient.
19
+ */
20
+ class ConfidentialEntities {
21
+ constructor(entitiesEncryption, primitives, dataOwnerApi) {
22
+ this.entitiesEncryption = entitiesEncryption;
23
+ this.primitives = primitives;
24
+ this.dataOwnerApi = dataOwnerApi;
25
+ }
26
+ /**
27
+ * Ensures that the current data owner has access to a confidential secret id for the provided entity: this is an id that is known to the data owner
28
+ * but is not known by any of his parents. If there is currently no confidential secret id for this entity the method returns a copy of the entity
29
+ * with a new confidential secret id for the current data owner (the entity in the database won't be updated), else this method returns undefined.
30
+ * New confidential secret ids will have an appropriate tag, but existing confidential secret ids may not necessarily have it.
31
+ * @param entity an entity which needs to have a confidential secret id for the current data owner
32
+ * @return undefined if the entity already had a confidential secret id for the current user, or the updated entity with the new confidential secret
33
+ * id.
34
+ */
35
+ entityWithInitialisedConfidentialSecretId(entity) {
36
+ return __awaiter(this, void 0, void 0, function* () {
37
+ if (yield this.getConfidentialSecretId(entity))
38
+ return undefined;
39
+ const confidentialSecretId = this.primitives.randomUuid();
40
+ return yield this.entitiesEncryption.entityWithExtendedEncryptedMetadata(entity, yield this.dataOwnerApi.getCurrentDataOwnerId(), [confidentialSecretId], [], [], ['confidential']);
41
+ });
42
+ }
43
+ /**
44
+ * Get an existing confidential secret id of the provided entity for the provided data owner (current data owner by default). A confidential secret
45
+ * id is a secret id known by the data owner but not known by any of his parents: note however that children will know confidential secret ids.
46
+ * @param entity an entity for which you want to retrieve the confidential secret id.
47
+ * @param dataOwnerId (current data owner by default) a data owner for which you want to get a confidential secret id.
48
+ * @return the confidential secret id or undefined if there is no confidential secret id for the provided data owner.
49
+ */
50
+ getConfidentialSecretId(entity, dataOwnerId) {
51
+ return __awaiter(this, void 0, void 0, function* () {
52
+ return this.getConfidentialSecretIds(entity, dataOwnerId).then((x) => x[0]);
53
+ });
54
+ }
55
+ /**
56
+ * Gets a secret id known by the topmost parent of the current data owner hierarchy. If there is multiple secret ids shared with the topmost parent
57
+ * there is no guarantee on which one will be chosen.
58
+ * @param entity an entity.
59
+ * @return a secret id known by the topmost parent of the current data owner hierarchy, or undefined if there is no secret id currently available
60
+ * for the topmost parent.
61
+ */
62
+ getAnySecretIdSharedWithParents(entity) {
63
+ return __awaiter(this, void 0, void 0, function* () {
64
+ return (yield this.getSecretIdsSharedWithParents(entity))[0];
65
+ });
66
+ }
67
+ /**
68
+ * Get all existing confidential secret ids of the provided entity for the provided data owner (current data owner by default). A confidential secret
69
+ * id is a secret id known by the data owner but not known by any of his parents: note however that children will know confidential secret ids.
70
+ * @param entity an entity for which you want to retrieve the confidential secret id.
71
+ * @param dataOwnerId (current data owner by default) a data owner for which you want to get a confidential secret id.
72
+ * @return the confidential secret ids for the data owner (may be empty).
73
+ */
74
+ getConfidentialSecretIds(entity, dataOwnerId) {
75
+ return __awaiter(this, void 0, void 0, function* () {
76
+ // TODO throw exception if any parent key is not available? if we are missing even only one single parent key we can't be sure it is confidential
77
+ const chosenDataOwnerId = dataOwnerId !== null && dataOwnerId !== void 0 ? dataOwnerId : (yield this.dataOwnerApi.getCurrentDataOwnerId());
78
+ const dataOwnerHierarchy = yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIdsFrom(chosenDataOwnerId);
79
+ const hierarchySecretIds = (yield this.entitiesEncryption.secretIdsForHcpHierarchyOf(entity)).filter((x) => dataOwnerHierarchy.includes(x.ownerId));
80
+ const keysForDataOwner = hierarchySecretIds.find((x) => x.ownerId === chosenDataOwnerId);
81
+ if (!keysForDataOwner)
82
+ return [];
83
+ return keysForDataOwner.extracted.filter((k) => !hierarchySecretIds.some((x) => x.ownerId !== chosenDataOwnerId && x.extracted.includes(k)));
84
+ });
85
+ }
86
+ /**
87
+ * Gets all secret ids known by the topmost parent of the current data owner hierarchy (or all secret ids known by the current data owner if he is
88
+ * not part of any data owner hierarchy).
89
+ * @param entity an entity.
90
+ * @return all secret ids known by the topmost parent of the current data owner hierarchy, may be empty.
91
+ */
92
+ getSecretIdsSharedWithParents(entity) {
93
+ return __awaiter(this, void 0, void 0, function* () {
94
+ return (yield this.entitiesEncryption.secretIdsForHcpHierarchyOf(entity))[0].extracted;
95
+ });
96
+ }
97
+ }
98
+ exports.ConfidentialEntities = ConfidentialEntities;
99
+ //# sourceMappingURL=ConfidentialEntities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfidentialEntities.js","sourceRoot":"","sources":["../../../icc-x-api/crypto/ConfidentialEntities.ts"],"names":[],"mappings":";;;;;;;;;;;;AAKA;;;;;;GAMG;AACH,MAAa,oBAAoB;IAC/B,YACmB,kBAAsC,EACtC,UAA4B,EAC5B,YAA8B;QAF9B,uBAAkB,GAAlB,kBAAkB,CAAoB;QACtC,eAAU,GAAV,UAAU,CAAkB;QAC5B,iBAAY,GAAZ,YAAY,CAAkB;IAC9C,CAAC;IAEJ;;;;;;;;OAQG;IACG,yCAAyC,CAA4B,MAAS;;YAClF,IAAI,MAAM,IAAI,CAAC,uBAAuB,CAAC,MAAM,CAAC;gBAAE,OAAO,SAAS,CAAA;YAChE,MAAM,oBAAoB,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAA;YACzD,OAAO,MAAM,IAAI,CAAC,kBAAkB,CAAC,mCAAmC,CACtE,MAAM,EACN,MAAM,IAAI,CAAC,YAAY,CAAC,qBAAqB,EAAE,EAC/C,CAAC,oBAAoB,CAAC,EACtB,EAAE,EACF,EAAE,EACF,CAAC,cAAc,CAAC,CACjB,CAAA;QACH,CAAC;KAAA;IAED;;;;;;OAMG;IACG,uBAAuB,CAAC,MAAuB,EAAE,WAAoB;;YACzE,OAAO,IAAI,CAAC,wBAAwB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC7E,CAAC;KAAA;IAED;;;;;;OAMG;IACG,+BAA+B,CAAC,MAAuB;;YAC3D,OAAO,CAAC,MAAM,IAAI,CAAC,6BAA6B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC9D,CAAC;KAAA;IAED;;;;;;OAMG;IACG,wBAAwB,CAAC,MAAuB,EAAE,WAAoB;;YAC1E,iJAAiJ;YACjJ,MAAM,iBAAiB,GAAG,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,qBAAqB,EAAE,CAAC,CAAA;YAC1F,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,mCAAmC,CAAC,iBAAiB,CAAC,CAAA;YACzG,MAAM,kBAAkB,GAAG,CAAC,MAAM,IAAI,CAAC,kBAAkB,CAAC,0BAA0B,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACzG,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CACvC,CAAA;YACD,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,iBAAiB,CAAC,CAAA;YAExF,IAAI,CAAC,gBAAgB;gBAAE,OAAO,EAAE,CAAA;YAChC,OAAO,gBAAgB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,iBAAiB,IAAI,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC9I,CAAC;KAAA;IAED;;;;;OAKG;IACG,6BAA6B,CAAC,MAAuB;;YACzD,OAAO,CAAC,MAAM,IAAI,CAAC,kBAAkB,CAAC,0BAA0B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACxF,CAAC;KAAA;CACF;AAhFD,oDAgFC","sourcesContent":["import { EncryptedEntity } from '../../icc-api/model/models'\nimport { EntitiesEncryption } from './EntitiesEncryption'\nimport { CryptoPrimitives } from './CryptoPrimitives'\nimport { IccDataOwnerXApi } from '../icc-data-owner-x-api'\n\n/**\n * This class helps to create confidential medical data in systems where multiple hcps share data with each other using parent hcps: while normally\n * the hcps would share all data with other hcps part of the same \"family\" (e.g. an hospital) there are situations where the medical data is\n * confidential and should only be known by the doctor which created the data. In these situations it is also important that the secret foreign key\n * used in the confidential data is not known by other members of the hcp family, otherwise they may be able to draw some links between the medical\n * data and the patient.\n */\nexport class ConfidentialEntities {\n constructor(\n private readonly entitiesEncryption: EntitiesEncryption,\n private readonly primitives: CryptoPrimitives,\n private readonly dataOwnerApi: IccDataOwnerXApi\n ) {}\n\n /**\n * Ensures that the current data owner has access to a confidential secret id for the provided entity: this is an id that is known to the data owner\n * but is not known by any of his parents. If there is currently no confidential secret id for this entity the method returns a copy of the entity\n * with a new confidential secret id for the current data owner (the entity in the database won't be updated), else this method returns undefined.\n * New confidential secret ids will have an appropriate tag, but existing confidential secret ids may not necessarily have it.\n * @param entity an entity which needs to have a confidential secret id for the current data owner\n * @return undefined if the entity already had a confidential secret id for the current user, or the updated entity with the new confidential secret\n * id.\n */\n async entityWithInitialisedConfidentialSecretId<T extends EncryptedEntity>(entity: T): Promise<T | undefined> {\n if (await this.getConfidentialSecretId(entity)) return undefined\n const confidentialSecretId = this.primitives.randomUuid()\n return await this.entitiesEncryption.entityWithExtendedEncryptedMetadata(\n entity,\n await this.dataOwnerApi.getCurrentDataOwnerId(),\n [confidentialSecretId],\n [],\n [],\n ['confidential']\n )\n }\n\n /**\n * Get an existing confidential secret id of the provided entity for the provided data owner (current data owner by default). A confidential secret\n * id is a secret id known by the data owner but not known by any of his parents: note however that children will know confidential secret ids.\n * @param entity an entity for which you want to retrieve the confidential secret id.\n * @param dataOwnerId (current data owner by default) a data owner for which you want to get a confidential secret id.\n * @return the confidential secret id or undefined if there is no confidential secret id for the provided data owner.\n */\n async getConfidentialSecretId(entity: EncryptedEntity, dataOwnerId?: string): Promise<string | undefined> {\n return this.getConfidentialSecretIds(entity, dataOwnerId).then((x) => x[0])\n }\n\n /**\n * Gets a secret id known by the topmost parent of the current data owner hierarchy. If there is multiple secret ids shared with the topmost parent\n * there is no guarantee on which one will be chosen.\n * @param entity an entity.\n * @return a secret id known by the topmost parent of the current data owner hierarchy, or undefined if there is no secret id currently available\n * for the topmost parent.\n */\n async getAnySecretIdSharedWithParents(entity: EncryptedEntity): Promise<string | undefined> {\n return (await this.getSecretIdsSharedWithParents(entity))[0]\n }\n\n /**\n * Get all existing confidential secret ids of the provided entity for the provided data owner (current data owner by default). A confidential secret\n * id is a secret id known by the data owner but not known by any of his parents: note however that children will know confidential secret ids.\n * @param entity an entity for which you want to retrieve the confidential secret id.\n * @param dataOwnerId (current data owner by default) a data owner for which you want to get a confidential secret id.\n * @return the confidential secret ids for the data owner (may be empty).\n */\n async getConfidentialSecretIds(entity: EncryptedEntity, dataOwnerId?: string): Promise<string[]> {\n // TODO throw exception if any parent key is not available? if we are missing even only one single parent key we can't be sure it is confidential\n const chosenDataOwnerId = dataOwnerId ?? (await this.dataOwnerApi.getCurrentDataOwnerId())\n const dataOwnerHierarchy = await this.dataOwnerApi.getCurrentDataOwnerHierarchyIdsFrom(chosenDataOwnerId)\n const hierarchySecretIds = (await this.entitiesEncryption.secretIdsForHcpHierarchyOf(entity)).filter((x) =>\n dataOwnerHierarchy.includes(x.ownerId)\n )\n const keysForDataOwner = hierarchySecretIds.find((x) => x.ownerId === chosenDataOwnerId)\n\n if (!keysForDataOwner) return []\n return keysForDataOwner.extracted.filter((k) => !hierarchySecretIds.some((x) => x.ownerId !== chosenDataOwnerId && x.extracted.includes(k)))\n }\n\n /**\n * Gets all secret ids known by the topmost parent of the current data owner hierarchy (or all secret ids known by the current data owner if he is\n * not part of any data owner hierarchy).\n * @param entity an entity.\n * @return all secret ids known by the topmost parent of the current data owner hierarchy, may be empty.\n */\n async getSecretIdsSharedWithParents(entity: EncryptedEntity): Promise<string[]> {\n return (await this.entitiesEncryption.secretIdsForHcpHierarchyOf(entity))[0].extracted\n }\n}\n"]}