@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,288 @@
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.KeyManager = void 0;
13
+ const utils_1 = require("../utils");
14
+ const utils_2 = require("./utils");
15
+ /**
16
+ * Allows to manage public and private keys for the current user and his parent hierarchy.
17
+ */
18
+ class KeyManager {
19
+ constructor(primitives, dataOwnerApi, icureStorage, keyRecovery, baseExchangeKeyManager, strategies) {
20
+ this.keysCache = undefined;
21
+ this.primitives = primitives;
22
+ this.icureStorage = icureStorage;
23
+ this.dataOwnerApi = dataOwnerApi;
24
+ this.keyRecovery = keyRecovery;
25
+ this.baseExchangeKeyManager = baseExchangeKeyManager;
26
+ this.strategies = strategies;
27
+ }
28
+ /**
29
+ * Get the public keys of available key pairs for the current user in hex-encoded spki representation (uses cached keys: no request is done to the
30
+ * server).
31
+ * By setting {@link verifiedOnly} to true only the public keys for verified key pairs will be returned: these will include only key pairs created
32
+ * on this device or which have been verified using {@link CryptoStrategies} on this device.
33
+ * @param verifiedOnly if true only the verified public keys will be returned.
34
+ * @return the spki representation of public keys of available keypairs for the current user.
35
+ */
36
+ getCurrentUserAvailablePublicKeysHex(verifiedOnly) {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ this.ensureInitialised();
39
+ let selectedData = Object.values(this.keysCache[this.selfId]);
40
+ if (verifiedOnly) {
41
+ selectedData = selectedData.filter((data) => data.isVerified || data.isDevice);
42
+ }
43
+ return yield Promise.all(selectedData.map((keyData) => __awaiter(this, void 0, void 0, function* () { return (0, utils_1.ua2hex)(yield this.primitives.RSA.exportKey(keyData.pair.publicKey, 'spki')); })));
44
+ });
45
+ }
46
+ /**
47
+ * Get the public keys of available key pairs for the current user and his parents in hex-encoded spki representation (uses cached keys: no request
48
+ * is done to the server).
49
+ * Note that this will also include unverified keys.
50
+ * @return the spki representation of public keys of available keypairs for the current user.
51
+ */
52
+ getCurrentUserHierarchyAvailablePublicKeysHex() {
53
+ return __awaiter(this, void 0, void 0, function* () {
54
+ return yield Promise.all(Object.values(this.keysCache)
55
+ .flatMap((pairsForParent) => Object.values(pairsForParent))
56
+ .map((keyPairData) => __awaiter(this, void 0, void 0, function* () { return (0, utils_1.ua2hex)(yield this.primitives.RSA.exportKey(keyPairData.pair.publicKey, 'spki')); })));
57
+ });
58
+ }
59
+ /**
60
+ * Get a key pair with the provided fingerprint if present.
61
+ * @param fingerprint a key-pair/public-key fingerprint
62
+ * @return the pair associated to the fingerprint and a boolean indicating if the pair is verified, if present, else undefined
63
+ */
64
+ getKeyPairForFingerprint(fingerprint) {
65
+ const foundVerified = this.getSelfVerifiedKeys().find((x) => x.fingerprint === fingerprint);
66
+ if (foundVerified)
67
+ return { pair: foundVerified.pair, verified: true };
68
+ const foundOther = this.getDecryptionKeys()[fingerprint];
69
+ if (foundOther)
70
+ return { pair: foundOther, verified: false };
71
+ return undefined;
72
+ }
73
+ /**
74
+ * @internal This method is intended for internal use only and may be changed without notice.
75
+ * Initializes all keys for the current data owner. This method needs to be called before any other method of this class can be used.
76
+ * @throws if the current user is not a data owner, or if there is no key and no new key could be created according to this manager crypt
77
+ * strategies.
78
+ * @return if a new key was created during initialisation the newly created key, else undefined.
79
+ */
80
+ initialiseKeys() {
81
+ return __awaiter(this, void 0, void 0, function* () {
82
+ const newKey = yield this.doLoadKeys((x) => this.strategies.recoverAndVerifySelfHierarchyKeys(x, this.primitives), (x) => this.strategies.generateNewKeyForDataOwner(x, this.primitives));
83
+ return newKey ? { newKeyPair: newKey.pair, newKeyFingerprint: newKey.fingerprint } : undefined;
84
+ });
85
+ }
86
+ /**
87
+ * @internal This method is intended for internal use only and may be changed without notice.
88
+ * Forces to reload keys for the current data owner. This could be useful if the data owner has logged in from another device in order to update the
89
+ * transfer keys.
90
+ * This method will complete only after keys have been reloaded successfully.
91
+ */
92
+ reloadKeys() {
93
+ return __awaiter(this, void 0, void 0, function* () {
94
+ yield this.doLoadKeys((x) => Promise.resolve(x.reduce((acc, { dataOwner }) => (Object.assign(Object.assign({}, acc), { [dataOwner.id]: { recoveredKeys: {}, keyAuthenticity: {} } })), {})), (x) => {
95
+ throw new Error("Can't create new keys at reload time: it should have already been created on initialisation");
96
+ });
97
+ });
98
+ }
99
+ /**
100
+ * @internal This method is intended for internal use only and may be changed without notice.
101
+ * Get all verified key pairs for the current data owner which can safely be used for encryption. This includes all key pairs created on the current
102
+ * device and all recovered key pairs which have been verified.
103
+ * The keys returned by this method will be in the following order:
104
+ * 1. Legacy key pair if it is verified
105
+ * 2. All device key pais, in alphabetical order according to the fingerprint
106
+ * 3. Other verified key pairs, in alphabetical order according to the fingerprint
107
+ * @return all verified keys, in order.
108
+ */
109
+ getSelfVerifiedKeys() {
110
+ var _a;
111
+ this.ensureInitialised();
112
+ const selfKeys = this.keysCache[this.selfId];
113
+ const allKeysEntries = Object.entries(selfKeys);
114
+ const legacyKeyFp = (_a = this.selfLegacyPublicKey) === null || _a === void 0 ? void 0 : _a.slice(-32);
115
+ const legacyKeyData = legacyKeyFp ? selfKeys[legacyKeyFp] : undefined;
116
+ const legacyEntry = (legacyKeyData === null || legacyKeyData === void 0 ? void 0 : legacyKeyData.isVerified) && legacyKeyFp ? [{ fingerprint: legacyKeyFp, pair: legacyKeyData.pair }] : [];
117
+ function filteredEntries(filterFunction) {
118
+ return allKeysEntries
119
+ .filter(([fp, data]) => filterFunction(fp, data) && fp !== legacyKeyFp)
120
+ .sort(([a], [b]) => {
121
+ // need to make sure that the comparison is independent of the locale, but the actual ordering is not that important
122
+ return a == b ? 0 : a > b ? 1 : -1;
123
+ })
124
+ .map(([fingerprint, { pair }]) => ({ fingerprint, pair }));
125
+ }
126
+ return [...legacyEntry, ...filteredEntries((_, data) => data.isDevice), ...filteredEntries((_, data) => !data.isDevice && data.isVerified)];
127
+ }
128
+ /**
129
+ * Get all verified keys for a member of the current data owner hierarchy in no particular order.
130
+ * @param dataOwner the current data owner or a member of his hierarchy.
131
+ * @throws if the provided data owner is not part of the current data owner hierarchy
132
+ */
133
+ getVerifiedPublicKeysFor(dataOwner) {
134
+ return __awaiter(this, void 0, void 0, function* () {
135
+ this.ensureInitialised();
136
+ const availableKeys = this.keysCache[dataOwner.id];
137
+ if (!availableKeys)
138
+ throw new Error(`Data owner ${dataOwner.id} is not part of the hierarchy of the current data owner ${this.selfId}`);
139
+ const availableVerifiedKeysFp = new Set(Object.entries(availableKeys).flatMap(([fp, info]) => (info.isVerified || info.isDevice ? [fp] : [])));
140
+ const otherVerifiedFp = new Set(Object.entries(yield this.icureStorage.loadSelfVerifiedKeys(dataOwner.id)).flatMap(([fp, verified]) => (verified ? [fp] : [])));
141
+ return Array.from(this.dataOwnerApi.getHexPublicKeysOf(dataOwner)).filter((key) => {
142
+ const fp = key.slice(-32);
143
+ return availableVerifiedKeysFp.has(fp) || otherVerifiedFp.has(fp);
144
+ });
145
+ });
146
+ }
147
+ /**
148
+ * @internal This method is intended for internal use only and may be changed without notice.
149
+ * Get all key pairs for the current data owner and his parents. These keys should be used only for decryption as they may have not been verified.
150
+ * @return all key pairs available for decryption.
151
+ */
152
+ getDecryptionKeys() {
153
+ this.ensureInitialised();
154
+ return Object.values(this.keysCache).reduce((acc, curr) => {
155
+ return Object.assign(Object.assign({}, acc), this.plainKeysByFingerprint(curr));
156
+ }, {});
157
+ }
158
+ doLoadKeys(keyRecovererAndVerifier, currentOwnerKeyGenerator) {
159
+ return __awaiter(this, void 0, void 0, function* () {
160
+ // Load all keys for self from key store
161
+ const hierarchy = yield this.dataOwnerApi.getCurrentDataOwnerHierarchy();
162
+ const self = hierarchy[hierarchy.length - 1];
163
+ this.selfId = self.dataOwner.id;
164
+ const keysData = [];
165
+ for (const dowt of hierarchy) {
166
+ const availableKeys = yield this.loadAndRecoverKeysFor(dowt);
167
+ const verifiedKeysMap = yield this.icureStorage.loadSelfVerifiedKeys(dowt.dataOwner.id);
168
+ const allPublicKeys = this.dataOwnerApi.getHexPublicKeysOf(dowt.dataOwner);
169
+ const fpToFullMap = (0, utils_2.fingerprintToPublicKeysMapOf)(dowt.dataOwner);
170
+ const unavailableKeys = Object.keys(availableKeys).flatMap((fp) => {
171
+ const fullPublicKey = fpToFullMap[fp];
172
+ return allPublicKeys.has(fullPublicKey) ? [] : [fullPublicKey];
173
+ });
174
+ const unknownKeys = Array.from(allPublicKeys).filter((x) => { var _a; return !(x.slice(-32) in verifiedKeysMap) && !(((_a = availableKeys === null || availableKeys === void 0 ? void 0 : availableKeys[x.slice(-32)]) === null || _a === void 0 ? void 0 : _a.isDevice) === true); });
175
+ keysData.push({ dowt, availableKeys, unavailableKeys, unknownKeys });
176
+ }
177
+ const recoveryAndVerificationResult = yield keyRecovererAndVerifier(keysData.map(({ dowt, unavailableKeys, unknownKeys }) => ({ dataOwner: dowt.dataOwner, unavailableKeys, unknownKeys })));
178
+ const keysCache = {};
179
+ for (const keyData of keysData) {
180
+ const currAuthenticity = this.ensureFingerprintKeys(recoveryAndVerificationResult[keyData.dowt.dataOwner.id].keyAuthenticity);
181
+ const currExternallyRecovered = this.ensureFingerprintKeys(recoveryAndVerificationResult[keyData.dowt.dataOwner.id].recoveredKeys);
182
+ for (const [fp, keyPair] of Object.entries(currExternallyRecovered)) {
183
+ const jwkPair = yield this.primitives.RSA.exportKeys(keyPair, 'jwk', 'jwk');
184
+ yield this.icureStorage.saveKey(keyData.dowt.dataOwner.id, fp, jwkPair, true);
185
+ }
186
+ const updatedVerifiedMap = yield this.icureStorage.saveSelfVerifiedKeys(keyData.dowt.dataOwner.id, [...Object.keys(currAuthenticity), ...Object.keys(currExternallyRecovered)].reduce((acc, currFp) => (Object.assign(Object.assign({}, acc), { [currFp]: currFp in currExternallyRecovered || currAuthenticity[currFp] })), {}));
187
+ const keysWithExternallyRecovered = Object.assign(Object.assign({}, keyData.availableKeys), Object.fromEntries(Object.entries(currExternallyRecovered).map(([k, v]) => [k, { pair: v, isDevice: false }])));
188
+ const additionallyRecovered = yield this.recoverAndCacheKeys(keyData.dowt, this.plainKeysByFingerprint(keysWithExternallyRecovered));
189
+ const keys = Object.assign(Object.assign({}, keysWithExternallyRecovered), Object.fromEntries(Object.entries(additionallyRecovered).map(([k, v]) => [k, { pair: v, isDevice: false }])));
190
+ keysCache[keyData.dowt.dataOwner.id] = this.verifyKeys(keys, updatedVerifiedMap);
191
+ }
192
+ if (Object.entries(keysCache).some(([ownerId, data]) => ownerId !== self.dataOwner.id && !this.hasVerifiedKey(data))) {
193
+ throw new Error('Some parent hcps have no verified keys: impossible to generate locally a new key for a parent.');
194
+ }
195
+ else if (this.hasVerifiedKey(keysCache[self.dataOwner.id])) {
196
+ this.keysCache = keysCache;
197
+ this.selfLegacyPublicKey = self.dataOwner.publicKey;
198
+ return undefined;
199
+ }
200
+ else {
201
+ const whatToDo = yield currentOwnerKeyGenerator(self.dataOwner);
202
+ if (whatToDo === false) {
203
+ throw new Error(`No verified key found for ${self.dataOwner.id} and settings do not allow creation of a new key.`);
204
+ }
205
+ else {
206
+ const updateInfo = yield this.createAndSaveNewKeyPair(whatToDo === true ? undefined : whatToDo, self);
207
+ // self may be outdated now
208
+ this.selfLegacyPublicKey = updateInfo.updatedSelf.dataOwner.publicKey;
209
+ this.keysCache = Object.assign(Object.assign({}, keysCache), { [self.dataOwner.id]: Object.assign(Object.assign({}, keysCache[self.dataOwner.id]), { [updateInfo.publicKeyFingerprint]: { pair: updateInfo.keyPair, isDevice: true, isVerified: true } }) });
210
+ return { pair: updateInfo.keyPair, fingerprint: updateInfo.publicKeyFingerprint };
211
+ }
212
+ }
213
+ });
214
+ }
215
+ createAndSaveNewKeyPair(importedKeyPair, selfDataOwner) {
216
+ return __awaiter(this, void 0, void 0, function* () {
217
+ const keyPair = importedKeyPair !== null && importedKeyPair !== void 0 ? importedKeyPair : (yield this.primitives.RSA.generateKeyPair());
218
+ const publicKeyHex = (0, utils_1.ua2hex)(yield this.primitives.RSA.exportKey(keyPair.publicKey, 'spki'));
219
+ const publicKeyFingerprint = publicKeyHex.slice(-32);
220
+ yield this.icureStorage.saveKey(selfDataOwner.dataOwner.id, publicKeyFingerprint, yield this.primitives.RSA.exportKeys(keyPair, 'jwk', 'jwk'), true);
221
+ const verifiedPublicKeysMap = yield this.icureStorage.saveSelfVerifiedKeys(selfDataOwner.dataOwner.id, { [publicKeyFingerprint]: true });
222
+ const { updatedDelegator } = yield this.baseExchangeKeyManager.createOrUpdateEncryptedExchangeKeyTo(selfDataOwner.dataOwner.id, keyPair, yield (0, utils_2.loadPublicKeys)(this.primitives.RSA, Array.from(this.dataOwnerApi.getHexPublicKeysOf(selfDataOwner.dataOwner)).filter((x) => verifiedPublicKeysMap[x.slice(-32)])));
223
+ return { publicKeyFingerprint, keyPair: keyPair, updatedSelf: updatedDelegator };
224
+ });
225
+ }
226
+ loadStoredKeys(dataOwner, pubKeysFingerprints) {
227
+ return __awaiter(this, void 0, void 0, function* () {
228
+ return yield pubKeysFingerprints.reduce((acc, currentFingerprint) => __awaiter(this, void 0, void 0, function* () {
229
+ const awaitedAcc = yield acc;
230
+ let loadedPair = undefined;
231
+ try {
232
+ const storedKeypair = yield this.icureStorage.loadKey(dataOwner.dataOwner.id, currentFingerprint, dataOwner.dataOwner.publicKey);
233
+ if (storedKeypair) {
234
+ const importedKey = yield this.primitives.RSA.importKeyPair('jwk', storedKeypair.pair.privateKey, 'jwk', storedKeypair.pair.publicKey);
235
+ loadedPair = { pair: importedKey, isDevice: storedKeypair.isDevice };
236
+ }
237
+ }
238
+ catch (e) {
239
+ console.warn('Error while loading keypair', currentFingerprint, e);
240
+ }
241
+ return loadedPair
242
+ ? Object.assign(Object.assign({}, awaitedAcc), { [currentFingerprint]: loadedPair }) : awaitedAcc;
243
+ }), Promise.resolve({}));
244
+ });
245
+ }
246
+ verifyKeys(keys, verifiedKeysMap) {
247
+ return Object.fromEntries(Object.entries(keys).map(([fp, keyData]) => [fp, Object.assign(Object.assign({}, keyData), { isVerified: keyData.isDevice || (verifiedKeysMap === null || verifiedKeysMap === void 0 ? void 0 : verifiedKeysMap[fp]) === true })]));
248
+ }
249
+ plainKeysByFingerprint(richKeys) {
250
+ return Object.fromEntries(Object.entries(richKeys).map(([fp, keyData]) => [fp, keyData.pair]));
251
+ }
252
+ ensureInitialised() {
253
+ if (!this.keysCache)
254
+ throw new Error('Key manager was not properly initialised');
255
+ }
256
+ recoverAndCacheKeys(dataOwner, availableKeys) {
257
+ return __awaiter(this, void 0, void 0, function* () {
258
+ const recoveredKeys = yield this.keyRecovery.recoverKeys(dataOwner, availableKeys);
259
+ for (const [fp, pair] of Object.entries(recoveredKeys)) {
260
+ yield this.icureStorage.saveKey(dataOwner.dataOwner.id, fp, yield this.primitives.RSA.exportKeys(pair, 'jwk', 'jwk'), false);
261
+ }
262
+ return recoveredKeys;
263
+ });
264
+ }
265
+ loadAndRecoverKeysFor(dataOwner) {
266
+ return __awaiter(this, void 0, void 0, function* () {
267
+ const selfPublicKeys = this.dataOwnerApi.getHexPublicKeysOf(dataOwner.dataOwner);
268
+ const pubKeysFingerprints = Array.from(selfPublicKeys).map((x) => x.slice(-32));
269
+ const loadedKeys = pubKeysFingerprints.length > 0 ? yield this.loadStoredKeys(dataOwner, pubKeysFingerprints) : {};
270
+ const loadedKeysFingerprints = Object.keys(loadedKeys);
271
+ if (loadedKeysFingerprints.length !== pubKeysFingerprints.length && loadedKeysFingerprints.length > 0) {
272
+ const recoveredKeys = yield this.recoverAndCacheKeys(dataOwner, this.plainKeysByFingerprint(loadedKeys));
273
+ for (const [fp, pair] of Object.entries(recoveredKeys)) {
274
+ loadedKeys[fp] = { pair, isDevice: false };
275
+ }
276
+ }
277
+ return loadedKeys;
278
+ });
279
+ }
280
+ ensureFingerprintKeys(obj) {
281
+ return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k.slice(-32), v]));
282
+ }
283
+ hasVerifiedKey(keysData) {
284
+ return Object.values(keysData).some((x) => x.isVerified || x.isDevice);
285
+ }
286
+ }
287
+ exports.KeyManager = KeyManager;
288
+ //# sourceMappingURL=KeyManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KeyManager.js","sourceRoot":"","sources":["../../../icc-x-api/crypto/KeyManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { DataOwner, DataOwnerWithType, IccDataOwnerXApi } from '../icc-data-owner-x-api'\nimport { KeyPair } from './RSA'\nimport { ua2hex } from '../utils'\nimport { IcureStorageFacade } from '../storage/IcureStorageFacade'\nimport { BaseExchangeKeysManager } from './BaseExchangeKeysManager'\nimport { fingerprintToPublicKeysMapOf, loadPublicKeys } from './utils'\nimport { CryptoPrimitives } from './CryptoPrimitives'\nimport { KeyRecovery } from './KeyRecovery'\nimport { CryptoStrategies } from './CryptoStrategies'\n\ntype KeyPairData = { pair: KeyPair<CryptoKey>; isVerified: boolean; isDevice: boolean }\ntype KeyRecovererAndVerifier = (\n keysData: {\n dataOwner: DataOwner\n unknownKeys: string[]\n unavailableKeys: string[]\n }[]\n) => Promise<{\n [dataOwnerId: string]: {\n recoveredKeys: { [keyPairFingerprint: string]: KeyPair<CryptoKey> }\n keyAuthenticity: { [keyPairFingerprint: string]: boolean }\n }\n}>\ntype CurrentOwnerKeyGenerator = (self: DataOwner) => Promise<KeyPair<CryptoKey> | boolean>\n\n/**\n * Allows to manage public and private keys for the current user and his parent hierarchy.\n */\nexport class KeyManager {\n private readonly primitives: CryptoPrimitives\n private readonly dataOwnerApi: IccDataOwnerXApi\n private readonly keyRecovery: KeyRecovery\n private readonly icureStorage: IcureStorageFacade\n private readonly baseExchangeKeyManager: BaseExchangeKeysManager\n private readonly strategies: CryptoStrategies\n\n private selfId: string | undefined\n private selfLegacyPublicKey: string | undefined\n private keysCache: { [selfOrParentId: string]: { [pubKeyFingerprint: string]: KeyPairData } } | undefined = undefined\n\n constructor(\n primitives: CryptoPrimitives,\n dataOwnerApi: IccDataOwnerXApi,\n icureStorage: IcureStorageFacade,\n keyRecovery: KeyRecovery,\n baseExchangeKeyManager: BaseExchangeKeysManager,\n strategies: CryptoStrategies\n ) {\n this.primitives = primitives\n this.icureStorage = icureStorage\n this.dataOwnerApi = dataOwnerApi\n this.keyRecovery = keyRecovery\n this.baseExchangeKeyManager = baseExchangeKeyManager\n this.strategies = strategies\n }\n\n /**\n * Get the public keys of available key pairs for the current user in hex-encoded spki representation (uses cached keys: no request is done to the\n * server).\n * By setting {@link verifiedOnly} to true only the public keys for verified key pairs will be returned: these will include only key pairs created\n * on this device or which have been verified using {@link CryptoStrategies} on this device.\n * @param verifiedOnly if true only the verified public keys will be returned.\n * @return the spki representation of public keys of available keypairs for the current user.\n */\n async getCurrentUserAvailablePublicKeysHex(verifiedOnly: boolean): Promise<string[]> {\n this.ensureInitialised()\n let selectedData = Object.values(this.keysCache![this.selfId!])\n if (verifiedOnly) {\n selectedData = selectedData.filter((data) => data.isVerified || data.isDevice)\n }\n return await Promise.all(selectedData.map(async (keyData) => ua2hex(await this.primitives.RSA.exportKey(keyData.pair.publicKey, 'spki'))))\n }\n\n /**\n * Get the public keys of available key pairs for the current user and his parents in hex-encoded spki representation (uses cached keys: no request\n * is done to the server).\n * Note that this will also include unverified keys.\n * @return the spki representation of public keys of available keypairs for the current user.\n */\n async getCurrentUserHierarchyAvailablePublicKeysHex(): Promise<string[]> {\n return await Promise.all(\n Object.values(this.keysCache!)\n .flatMap((pairsForParent) => Object.values(pairsForParent))\n .map(async (keyPairData) => ua2hex(await this.primitives.RSA.exportKey(keyPairData.pair.publicKey, 'spki')))\n )\n }\n\n /**\n * Get a key pair with the provided fingerprint if present.\n * @param fingerprint a key-pair/public-key fingerprint\n * @return the pair associated to the fingerprint and a boolean indicating if the pair is verified, if present, else undefined\n */\n getKeyPairForFingerprint(fingerprint: string): { pair: KeyPair<CryptoKey>; verified: boolean } | undefined {\n const foundVerified = this.getSelfVerifiedKeys().find((x) => x.fingerprint === fingerprint)\n if (foundVerified) return { pair: foundVerified.pair, verified: true }\n const foundOther = this.getDecryptionKeys()[fingerprint]\n if (foundOther) return { pair: foundOther, verified: false }\n return undefined\n }\n\n /**\n * @internal This method is intended for internal use only and may be changed without notice.\n * Initializes all keys for the current data owner. This method needs to be called before any other method of this class can be used.\n * @throws if the current user is not a data owner, or if there is no key and no new key could be created according to this manager crypt\n * strategies.\n * @return if a new key was created during initialisation the newly created key, else undefined.\n */\n async initialiseKeys(): Promise<{ newKeyPair: KeyPair<CryptoKey>; newKeyFingerprint: string } | undefined> {\n const newKey = await this.doLoadKeys(\n (x) => this.strategies.recoverAndVerifySelfHierarchyKeys(x, this.primitives),\n (x) => this.strategies.generateNewKeyForDataOwner(x, this.primitives)\n )\n return newKey ? { newKeyPair: newKey.pair, newKeyFingerprint: newKey.fingerprint } : undefined\n }\n\n /**\n * @internal This method is intended for internal use only and may be changed without notice.\n * Forces to reload keys for the current data owner. This could be useful if the data owner has logged in from another device in order to update the\n * transfer keys.\n * This method will complete only after keys have been reloaded successfully.\n */\n async reloadKeys(): Promise<void> {\n await this.doLoadKeys(\n (x) =>\n Promise.resolve(\n x.reduce(\n (acc, { dataOwner }) => ({ ...acc, [dataOwner.id]: { recoveredKeys: {}, keyAuthenticity: {} } }),\n {} as {\n [dataOwnerId: string]: {\n recoveredKeys: { [keyPairFingerprint: string]: KeyPair<CryptoKey> }\n keyAuthenticity: { [keyPairFingerprint: string]: boolean }\n }\n }\n )\n ),\n (x) => {\n throw new Error(\"Can't create new keys at reload time: it should have already been created on initialisation\")\n }\n )\n }\n\n /**\n * @internal This method is intended for internal use only and may be changed without notice.\n * Get all verified key pairs for the current data owner which can safely be used for encryption. This includes all key pairs created on the current\n * device and all recovered key pairs which have been verified.\n * The keys returned by this method will be in the following order:\n * 1. Legacy key pair if it is verified\n * 2. All device key pais, in alphabetical order according to the fingerprint\n * 3. Other verified key pairs, in alphabetical order according to the fingerprint\n * @return all verified keys, in order.\n */\n getSelfVerifiedKeys(): { fingerprint: string; pair: KeyPair<CryptoKey> }[] {\n this.ensureInitialised()\n const selfKeys = this.keysCache![this.selfId!]\n const allKeysEntries = Object.entries(selfKeys)\n\n const legacyKeyFp = this.selfLegacyPublicKey?.slice(-32)\n const legacyKeyData = legacyKeyFp ? selfKeys[legacyKeyFp] : undefined\n const legacyEntry = legacyKeyData?.isVerified && legacyKeyFp ? [{ fingerprint: legacyKeyFp, pair: legacyKeyData.pair }] : []\n\n function filteredEntries(filterFunction: (fp: string, data: KeyPairData) => boolean) {\n return allKeysEntries\n .filter(([fp, data]) => filterFunction(fp, data) && fp !== legacyKeyFp)\n .sort(([a], [b]) => {\n // need to make sure that the comparison is independent of the locale, but the actual ordering is not that important\n return a == b ? 0 : a > b ? 1 : -1\n })\n .map(([fingerprint, { pair }]) => ({ fingerprint, pair }))\n }\n return [...legacyEntry, ...filteredEntries((_, data) => data.isDevice), ...filteredEntries((_, data) => !data.isDevice && data.isVerified)]\n }\n\n /**\n * Get all verified keys for a member of the current data owner hierarchy in no particular order.\n * @param dataOwner the current data owner or a member of his hierarchy.\n * @throws if the provided data owner is not part of the current data owner hierarchy\n */\n async getVerifiedPublicKeysFor(dataOwner: DataOwner): Promise<string[]> {\n this.ensureInitialised()\n const availableKeys = this.keysCache![dataOwner.id!]\n if (!availableKeys) throw new Error(`Data owner ${dataOwner.id} is not part of the hierarchy of the current data owner ${this.selfId}`)\n const availableVerifiedKeysFp = new Set(Object.entries(availableKeys).flatMap(([fp, info]) => (info.isVerified || info.isDevice ? [fp] : [])))\n const otherVerifiedFp = new Set(\n Object.entries(await this.icureStorage.loadSelfVerifiedKeys(dataOwner.id)).flatMap(([fp, verified]) => (verified ? [fp] : []))\n )\n return Array.from(this.dataOwnerApi.getHexPublicKeysOf(dataOwner)).filter((key) => {\n const fp = key.slice(-32)\n return availableVerifiedKeysFp.has(fp) || otherVerifiedFp.has(fp)\n })\n }\n\n /**\n * @internal This method is intended for internal use only and may be changed without notice.\n * Get all key pairs for the current data owner and his parents. These keys should be used only for decryption as they may have not been verified.\n * @return all key pairs available for decryption.\n */\n getDecryptionKeys(): { [fingerprint: string]: KeyPair<CryptoKey> } {\n this.ensureInitialised()\n return Object.values(this.keysCache!).reduce((acc, curr) => {\n return {\n ...acc,\n ...this.plainKeysByFingerprint(curr),\n }\n }, {} as { [fp: string]: KeyPair<CryptoKey> })\n }\n\n private async doLoadKeys(\n keyRecovererAndVerifier: KeyRecovererAndVerifier,\n currentOwnerKeyGenerator: CurrentOwnerKeyGenerator\n ): Promise<{ pair: KeyPair<CryptoKey>; fingerprint: string } | undefined> {\n // Load all keys for self from key store\n const hierarchy = await this.dataOwnerApi.getCurrentDataOwnerHierarchy()\n const self = hierarchy[hierarchy.length - 1]\n this.selfId = self.dataOwner.id!\n const keysData = []\n for (const dowt of hierarchy) {\n const availableKeys = await this.loadAndRecoverKeysFor(dowt)\n const verifiedKeysMap = await this.icureStorage.loadSelfVerifiedKeys(dowt.dataOwner.id!)\n const allPublicKeys = this.dataOwnerApi.getHexPublicKeysOf(dowt.dataOwner)\n const fpToFullMap = fingerprintToPublicKeysMapOf(dowt.dataOwner)\n const unavailableKeys = Object.keys(availableKeys).flatMap((fp) => {\n const fullPublicKey = fpToFullMap[fp]\n return allPublicKeys.has(fullPublicKey) ? [] : [fullPublicKey]\n })\n const unknownKeys = Array.from(allPublicKeys).filter(\n (x) => !(x.slice(-32) in verifiedKeysMap) && !(availableKeys?.[x.slice(-32)]?.isDevice === true)\n )\n keysData.push({ dowt, availableKeys, unavailableKeys, unknownKeys })\n }\n const recoveryAndVerificationResult = await keyRecovererAndVerifier(\n keysData.map(({ dowt, unavailableKeys, unknownKeys }) => ({ dataOwner: dowt.dataOwner, unavailableKeys, unknownKeys }))\n )\n const keysCache: { [dataOwnerId: string]: { [fp: string]: KeyPairData } } = {}\n for (const keyData of keysData) {\n const currAuthenticity = this.ensureFingerprintKeys(recoveryAndVerificationResult[keyData.dowt.dataOwner.id].keyAuthenticity)\n const currExternallyRecovered = this.ensureFingerprintKeys(recoveryAndVerificationResult[keyData.dowt.dataOwner.id].recoveredKeys)\n for (const [fp, keyPair] of Object.entries(currExternallyRecovered)) {\n const jwkPair = await this.primitives.RSA.exportKeys(keyPair, 'jwk', 'jwk')\n await this.icureStorage.saveKey(keyData.dowt.dataOwner.id!, fp, jwkPair, true)\n }\n const updatedVerifiedMap = await this.icureStorage.saveSelfVerifiedKeys(\n keyData.dowt.dataOwner.id!,\n [...Object.keys(currAuthenticity), ...Object.keys(currExternallyRecovered)].reduce(\n (acc, currFp) => ({\n ...acc,\n [currFp]: currFp in currExternallyRecovered || currAuthenticity[currFp],\n }),\n {}\n )\n )\n const keysWithExternallyRecovered = {\n ...keyData.availableKeys,\n ...Object.fromEntries(Object.entries(currExternallyRecovered).map(([k, v]) => [k, { pair: v, isDevice: false }])),\n }\n const additionallyRecovered = await this.recoverAndCacheKeys(keyData.dowt, this.plainKeysByFingerprint(keysWithExternallyRecovered))\n const keys = {\n ...keysWithExternallyRecovered,\n ...Object.fromEntries(Object.entries(additionallyRecovered).map(([k, v]) => [k, { pair: v, isDevice: false }])),\n }\n keysCache[keyData.dowt.dataOwner.id!] = this.verifyKeys(keys, updatedVerifiedMap)\n }\n if (Object.entries(keysCache).some(([ownerId, data]) => ownerId !== self.dataOwner.id && !this.hasVerifiedKey(data))) {\n throw new Error('Some parent hcps have no verified keys: impossible to generate locally a new key for a parent.')\n } else if (this.hasVerifiedKey(keysCache[self.dataOwner.id])) {\n this.keysCache = keysCache\n this.selfLegacyPublicKey = self.dataOwner.publicKey\n return undefined\n } else {\n const whatToDo = await currentOwnerKeyGenerator(self.dataOwner)\n if (whatToDo === false) {\n throw new Error(`No verified key found for ${self.dataOwner.id} and settings do not allow creation of a new key.`)\n } else {\n const updateInfo = await this.createAndSaveNewKeyPair(whatToDo === true ? undefined : whatToDo, self)\n // self may be outdated now\n this.selfLegacyPublicKey = updateInfo.updatedSelf.dataOwner.publicKey\n this.keysCache = {\n ...keysCache,\n [self.dataOwner.id!]: {\n ...keysCache[self.dataOwner.id],\n [updateInfo.publicKeyFingerprint]: { pair: updateInfo.keyPair, isDevice: true, isVerified: true },\n },\n }\n return { pair: updateInfo.keyPair, fingerprint: updateInfo.publicKeyFingerprint }\n }\n }\n }\n\n private async createAndSaveNewKeyPair(\n importedKeyPair: undefined | KeyPair<CryptoKey>,\n selfDataOwner: DataOwnerWithType\n ): Promise<{ publicKeyFingerprint: string; keyPair: KeyPair<CryptoKey>; updatedSelf: DataOwnerWithType }> {\n const keyPair = importedKeyPair ?? (await this.primitives.RSA.generateKeyPair())\n const publicKeyHex = ua2hex(await this.primitives.RSA.exportKey(keyPair.publicKey, 'spki'))\n const publicKeyFingerprint = publicKeyHex.slice(-32)\n await this.icureStorage.saveKey(\n selfDataOwner.dataOwner.id!,\n publicKeyFingerprint,\n await this.primitives.RSA.exportKeys(keyPair, 'jwk', 'jwk'),\n true\n )\n const verifiedPublicKeysMap = await this.icureStorage.saveSelfVerifiedKeys(selfDataOwner.dataOwner.id!, { [publicKeyFingerprint]: true })\n const { updatedDelegator } = await this.baseExchangeKeyManager.createOrUpdateEncryptedExchangeKeyTo(\n selfDataOwner.dataOwner.id!,\n keyPair,\n await loadPublicKeys(\n this.primitives.RSA,\n Array.from(this.dataOwnerApi.getHexPublicKeysOf(selfDataOwner.dataOwner)).filter((x) => verifiedPublicKeysMap[x.slice(-32)])\n )\n )\n return { publicKeyFingerprint, keyPair: keyPair, updatedSelf: updatedDelegator }\n }\n\n private async loadStoredKeys(\n dataOwner: DataOwnerWithType,\n pubKeysFingerprints: string[]\n ): Promise<{ [pubKeyFingerprint: string]: { pair: KeyPair<CryptoKey>; isDevice: boolean } }> {\n return await pubKeysFingerprints.reduce(async (acc, currentFingerprint) => {\n const awaitedAcc = await acc\n let loadedPair: { pair: KeyPair<CryptoKey>; isDevice: boolean } | undefined = undefined\n try {\n const storedKeypair = await this.icureStorage.loadKey(dataOwner.dataOwner.id!, currentFingerprint, dataOwner.dataOwner.publicKey)\n if (storedKeypair) {\n const importedKey = await this.primitives.RSA.importKeyPair('jwk', storedKeypair.pair.privateKey, 'jwk', storedKeypair.pair.publicKey)\n loadedPair = { pair: importedKey, isDevice: storedKeypair.isDevice }\n }\n } catch (e) {\n console.warn('Error while loading keypair', currentFingerprint, e)\n }\n return loadedPair\n ? {\n ...awaitedAcc,\n [currentFingerprint]: loadedPair,\n }\n : awaitedAcc\n }, Promise.resolve({} as { [pubKeyFingerprint: string]: { pair: KeyPair<CryptoKey>; isDevice: boolean } }))\n }\n\n private verifyKeys(\n keys: { [pubKeyFingerprint: string]: { pair: KeyPair<CryptoKey>; isDevice: boolean } },\n verifiedKeysMap: { [pubKeyFingerprint: string]: boolean }\n ): { [pubKeyFingerprint: string]: KeyPairData } {\n return Object.fromEntries(\n Object.entries(keys).map(\n ([fp, keyData]) => [fp, { ...keyData, isVerified: keyData.isDevice || verifiedKeysMap?.[fp] === true }] as [string, KeyPairData]\n )\n )\n }\n\n private plainKeysByFingerprint(richKeys: { [pubKeyFingerprint: string]: { pair: KeyPair<CryptoKey> } }): {\n [pubKeyFingerprint: string]: KeyPair<CryptoKey>\n } {\n return Object.fromEntries(Object.entries(richKeys).map(([fp, keyData]) => [fp, keyData.pair]))\n }\n\n private ensureInitialised() {\n if (!this.keysCache) throw new Error('Key manager was not properly initialised')\n }\n\n private async recoverAndCacheKeys(\n dataOwner: DataOwnerWithType,\n availableKeys: { [pubKeyFingerprint: string]: KeyPair<CryptoKey> }\n ): Promise<{ [p: string]: KeyPair<CryptoKey> }> {\n const recoveredKeys = await this.keyRecovery.recoverKeys(dataOwner, availableKeys)\n for (const [fp, pair] of Object.entries(recoveredKeys)) {\n await this.icureStorage.saveKey(dataOwner.dataOwner.id!, fp, await this.primitives.RSA.exportKeys(pair, 'jwk', 'jwk'), false)\n }\n return recoveredKeys\n }\n\n private async loadAndRecoverKeysFor(dataOwner: DataOwnerWithType): Promise<{ [keyFp: string]: { pair: KeyPair<CryptoKey>; isDevice: boolean } }> {\n const selfPublicKeys = this.dataOwnerApi.getHexPublicKeysOf(dataOwner.dataOwner)\n const pubKeysFingerprints = Array.from(selfPublicKeys).map((x) => x.slice(-32))\n const loadedKeys = pubKeysFingerprints.length > 0 ? await this.loadStoredKeys(dataOwner, pubKeysFingerprints) : {}\n const loadedKeysFingerprints = Object.keys(loadedKeys)\n if (loadedKeysFingerprints.length !== pubKeysFingerprints.length && loadedKeysFingerprints.length > 0) {\n const recoveredKeys = await this.recoverAndCacheKeys(dataOwner, this.plainKeysByFingerprint(loadedKeys))\n for (const [fp, pair] of Object.entries(recoveredKeys)) {\n loadedKeys[fp] = { pair, isDevice: false }\n }\n }\n return loadedKeys\n }\n\n private ensureFingerprintKeys<T>(obj: { [shouldBeFingerprint: string]: T }): { [definitelyFingerprint: string]: T } {\n return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k.slice(-32), v]))\n }\n\n private hasVerifiedKey(keysData: { [fp: string]: KeyPairData }) {\n return Object.values(keysData).some((x) => x.isVerified || x.isDevice)\n }\n}\n"]}
@@ -0,0 +1,34 @@
1
+ import { DataOwnerWithType, IccDataOwnerXApi } from '../icc-data-owner-x-api';
2
+ import { KeyPair } from './RSA';
3
+ import { CryptoPrimitives } from './CryptoPrimitives';
4
+ import { BaseExchangeKeysManager } from './BaseExchangeKeysManager';
5
+ /**
6
+ * @internal this class is intended only for internal use and may be changed without notice.
7
+ *
8
+ */
9
+ export declare class KeyRecovery {
10
+ private readonly primitives;
11
+ private readonly baseExchangeKeysManager;
12
+ private readonly dataOwnerApi;
13
+ constructor(primitives: CryptoPrimitives, baseExchangeKeysManager: BaseExchangeKeysManager, dataOwnerApi: IccDataOwnerXApi);
14
+ /**
15
+ * Attempt to recover private keys of a data owner using all available key recovery methods and all available private keys. The method will
16
+ * automatically try to use newly recovered key pairs to recover additional key pairs.
17
+ * @param dataOwner a data owner.
18
+ * @param knownKeys keys available for the data owner.
19
+ * @return new key pairs (exclude already known pairs) which could be recovered using the known keys.
20
+ */
21
+ recoverKeys(dataOwner: DataOwnerWithType, knownKeys: {
22
+ [pubKeyFp: string]: KeyPair<CryptoKey>;
23
+ }): Promise<{
24
+ [pubKeyFp: string]: KeyPair<CryptoKey>;
25
+ }>;
26
+ private recoverFromShamirSplitKeys;
27
+ private recoverWithSplits;
28
+ private tryRecoverSplitPrivate;
29
+ private tryDecryptSplitPiece;
30
+ private validateDecryptedSplit;
31
+ private recoverFromTransferKeys;
32
+ private tryDecryptTransferData;
33
+ private tryDecryptTransferKey;
34
+ }