@icure/api 8.0.64 → 8.0.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/icc-api/api/internal/IccExchangeDataApi.d.ts +2 -0
- package/icc-api/api/internal/IccExchangeDataApi.js +10 -0
- package/icc-api/api/internal/IccExchangeDataApi.js.map +1 -1
- package/icc-api/iccApi.d.ts +0 -1
- package/icc-api/iccApi.js +0 -1
- package/icc-api/iccApi.js.map +1 -1
- package/icc-api/index.d.ts +0 -1
- package/icc-api/index.js +0 -1
- package/icc-api/index.js.map +1 -1
- package/icc-x-api/crypto/AccessControlSecretUtils.d.ts +4 -13
- package/icc-x-api/crypto/AccessControlSecretUtils.js +19 -29
- package/icc-x-api/crypto/AccessControlSecretUtils.js.map +1 -1
- package/icc-x-api/crypto/BaseExchangeDataManager.d.ts +6 -2
- package/icc-x-api/crypto/BaseExchangeDataManager.js +26 -9
- package/icc-x-api/crypto/BaseExchangeDataManager.js.map +1 -1
- package/icc-x-api/crypto/BaseExchangeKeysManager.d.ts +2 -3
- package/icc-x-api/crypto/BaseExchangeKeysManager.js +8 -16
- package/icc-x-api/crypto/BaseExchangeKeysManager.js.map +1 -1
- package/icc-x-api/crypto/CryptoPrimitives.d.ts +2 -0
- package/icc-x-api/crypto/CryptoPrimitives.js +3 -0
- package/icc-x-api/crypto/CryptoPrimitives.js.map +1 -1
- package/icc-x-api/crypto/DelegationsDeAnonymization.d.ts +3 -3
- package/icc-x-api/crypto/DelegationsDeAnonymization.js +7 -7
- package/icc-x-api/crypto/DelegationsDeAnonymization.js.map +1 -1
- package/icc-x-api/crypto/ExchangeDataManager.d.ts +19 -29
- package/icc-x-api/crypto/ExchangeDataManager.js +200 -225
- package/icc-x-api/crypto/ExchangeDataManager.js.map +1 -1
- package/icc-x-api/crypto/ExchangeDataMapManager.js +6 -4
- package/icc-x-api/crypto/ExchangeDataMapManager.js.map +1 -1
- package/icc-x-api/crypto/ExchangeKeysManager.d.ts +4 -16
- package/icc-x-api/crypto/ExchangeKeysManager.js +44 -41
- package/icc-x-api/crypto/ExchangeKeysManager.js.map +1 -1
- package/icc-x-api/crypto/ExtendedApisUtils.d.ts +47 -25
- package/icc-x-api/crypto/ExtendedApisUtils.js.map +1 -1
- package/icc-x-api/crypto/ExtendedApisUtilsImpl.d.ts +19 -18
- package/icc-x-api/crypto/ExtendedApisUtilsImpl.js +213 -134
- package/icc-x-api/crypto/ExtendedApisUtilsImpl.js.map +1 -1
- package/icc-x-api/crypto/HMACUtils.d.ts +2 -2
- package/icc-x-api/crypto/HMACUtils.js +3 -4
- package/icc-x-api/crypto/HMACUtils.js.map +1 -1
- package/icc-x-api/crypto/NativeCryptoPrimitivesBridge.d.ts +1 -0
- package/icc-x-api/crypto/NativeCryptoPrimitivesBridge.js +5 -0
- package/icc-x-api/crypto/NativeCryptoPrimitivesBridge.js.map +1 -1
- package/icc-x-api/crypto/SecureDelegationsManager.d.ts +0 -1
- package/icc-x-api/crypto/SecureDelegationsManager.js +17 -49
- package/icc-x-api/crypto/SecureDelegationsManager.js.map +1 -1
- package/icc-x-api/crypto/SecurityMetadataDecryptor.d.ts +59 -90
- package/icc-x-api/crypto/SecurityMetadataDecryptor.js +470 -56
- package/icc-x-api/crypto/SecurityMetadataDecryptor.js.map +1 -1
- package/icc-x-api/crypto/ShamirKeysManager.js +1 -1
- package/icc-x-api/crypto/ShamirKeysManager.js.map +1 -1
- package/icc-x-api/crypto/TransferKeysManager.d.ts +1 -3
- package/icc-x-api/crypto/TransferKeysManager.js +2 -4
- package/icc-x-api/crypto/TransferKeysManager.js.map +1 -1
- package/icc-x-api/icc-accesslog-x-api.d.ts +2 -2
- package/icc-x-api/icc-accesslog-x-api.js +7 -3
- package/icc-x-api/icc-accesslog-x-api.js.map +1 -1
- package/icc-x-api/icc-calendar-item-x-api.js +4 -2
- package/icc-x-api/icc-calendar-item-x-api.js.map +1 -1
- package/icc-x-api/icc-contact-x-api.d.ts +0 -1
- package/icc-x-api/icc-contact-x-api.js +33 -48
- package/icc-x-api/icc-contact-x-api.js.map +1 -1
- package/icc-x-api/icc-crypto-x-api.js +1 -1
- package/icc-x-api/icc-crypto-x-api.js.map +1 -1
- package/icc-x-api/icc-document-x-api.d.ts +2 -2
- package/icc-x-api/icc-document-x-api.js +45 -42
- package/icc-x-api/icc-document-x-api.js.map +1 -1
- package/icc-x-api/icc-form-x-api.js +3 -1
- package/icc-x-api/icc-form-x-api.js.map +1 -1
- package/icc-x-api/icc-helement-x-api.js +4 -4
- package/icc-x-api/icc-helement-x-api.js.map +1 -1
- package/icc-x-api/icc-maintenance-task-x-api.js +4 -2
- package/icc-x-api/icc-maintenance-task-x-api.js.map +1 -1
- package/icc-x-api/icc-message-x-api.js +4 -2
- package/icc-x-api/icc-message-x-api.js.map +1 -1
- package/icc-x-api/icc-patient-x-api.js +5 -7
- package/icc-x-api/icc-patient-x-api.js.map +1 -1
- package/icc-x-api/icc-topic-x-api.js +2 -2
- package/icc-x-api/icc-topic-x-api.js.map +1 -1
- package/icc-x-api/index.d.ts +1 -2
- package/icc-x-api/index.js +7 -13
- package/icc-x-api/index.js.map +1 -1
- package/icc-x-api/utils/crypto-utils.d.ts +6 -4
- package/icc-x-api/utils/crypto-utils.js +27 -6
- package/icc-x-api/utils/crypto-utils.js.map +1 -1
- package/icc-x-api/utils/simple-lru-cache.d.ts +19 -0
- package/icc-x-api/utils/simple-lru-cache.js +90 -0
- package/icc-x-api/utils/simple-lru-cache.js.map +1 -0
- package/package.json +4 -2
- package/test/icc-x-api/crud/entities-crud-test-interface.js +0 -8
- package/test/icc-x-api/crud/entities-crud-test-interface.js.map +1 -1
- package/test/icc-x-api/crypto/exchange-data-manager-test.js +74 -92
- package/test/icc-x-api/crypto/exchange-data-manager-test.js.map +1 -1
- package/test/icc-x-api/crypto/legacy-metadata-migration-test.js.map +1 -1
- package/test/icc-x-api/crypto/secure-delegations-manager-test.js +27 -15
- package/test/icc-x-api/crypto/secure-delegations-manager-test.js.map +1 -1
- package/test/utils/FakeEncryptionKeysManager.d.ts +1 -0
- package/test/utils/FakeEncryptionKeysManager.js +11 -0
- package/test/utils/FakeEncryptionKeysManager.js.map +1 -1
- package/test/utils/FakeExchangeDataApi.d.ts +4 -2
- package/test/utils/FakeExchangeDataApi.js +24 -6
- package/test/utils/FakeExchangeDataApi.js.map +1 -1
- package/test/utils/FakeExchangeDataManager.d.ts +10 -10
- package/test/utils/FakeExchangeDataManager.js +12 -22
- package/test/utils/FakeExchangeDataManager.js.map +1 -1
- package/icc-api/api/IccArticleApi.d.ts +0 -72
- package/icc-api/api/IccArticleApi.js +0 -149
- package/icc-api/api/IccArticleApi.js.map +0 -1
- package/icc-x-api/crypto/LegacyDelegationSecurityMetadataDecryptor.d.ts +0 -33
- package/icc-x-api/crypto/LegacyDelegationSecurityMetadataDecryptor.js +0 -141
- package/icc-x-api/crypto/LegacyDelegationSecurityMetadataDecryptor.js.map +0 -1
- package/icc-x-api/crypto/SecureDelegationsSecurityMetadataDecryptor.d.ts +0 -46
- package/icc-x-api/crypto/SecureDelegationsSecurityMetadataDecryptor.js +0 -312
- package/icc-x-api/crypto/SecureDelegationsSecurityMetadataDecryptor.js.map +0 -1
- package/icc-x-api/crypto/UserSignatureKeysManager.d.ts +0 -26
- package/icc-x-api/crypto/UserSignatureKeysManager.js +0 -78
- package/icc-x-api/crypto/UserSignatureKeysManager.js.map +0 -1
- package/test/icc-x-api/crypto/secure-delegations-metadata-decryptor-test.d.ts +0 -1
- package/test/icc-x-api/crypto/secure-delegations-metadata-decryptor-test.js +0 -393
- package/test/icc-x-api/crypto/secure-delegations-metadata-decryptor-test.js.map +0 -1
- package/test/icc-x-api/crypto/security-metadata-decryptor-chain-test.d.ts +0 -1
- package/test/icc-x-api/crypto/security-metadata-decryptor-chain-test.js +0 -213
- package/test/icc-x-api/crypto/security-metadata-decryptor-chain-test.js.map +0 -1
- package/test/icc-x-api/crypto/signature-keys-manager-test.d.ts +0 -1
- package/test/icc-x-api/crypto/signature-keys-manager-test.js +0 -44
- package/test/icc-x-api/crypto/signature-keys-manager-test.js.map +0 -1
- package/test/utils/FakeSignatureKeysManager.d.ts +0 -16
- package/test/utils/FakeSignatureKeysManager.js +0 -54
- package/test/utils/FakeSignatureKeysManager.js.map +0 -1
|
@@ -8,72 +8,486 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
12
|
-
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
13
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
14
|
-
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
15
|
-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
16
|
-
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
|
17
|
-
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
18
|
-
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
19
|
-
function fulfill(value) { resume("next", value); }
|
|
20
|
-
function reject(value) { resume("throw", value); }
|
|
21
|
-
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
22
|
-
};
|
|
23
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
12
|
+
exports.SecurityMetadataDecryptor = exports.SecurityMetadataType = void 0;
|
|
13
|
+
const utils_1 = require("../utils");
|
|
14
|
+
const models_1 = require("../../icc-api/model/models");
|
|
15
|
+
var AccessLevelEnum = models_1.SecureDelegation.AccessLevelEnum;
|
|
16
|
+
var SecurityMetadataType;
|
|
17
|
+
(function (SecurityMetadataType) {
|
|
18
|
+
SecurityMetadataType[SecurityMetadataType["SecretId"] = 1] = "SecretId";
|
|
19
|
+
SecurityMetadataType[SecurityMetadataType["EncryptionKey"] = 2] = "EncryptionKey";
|
|
20
|
+
SecurityMetadataType[SecurityMetadataType["OwningEntityId"] = 3] = "OwningEntityId";
|
|
21
|
+
})(SecurityMetadataType = exports.SecurityMetadataType || (exports.SecurityMetadataType = {}));
|
|
22
|
+
class SecurityMetadataDecryptor {
|
|
23
|
+
constructor(exchangeKeysManager, primitives, exchangeData, exchangeDataMap, secureDelegationsEncryption, dataOwnerApi) {
|
|
24
|
+
this.exchangeKeysManager = exchangeKeysManager;
|
|
25
|
+
this.primitives = primitives;
|
|
26
|
+
this.exchangeData = exchangeData;
|
|
27
|
+
this.exchangeDataMap = exchangeDataMap;
|
|
28
|
+
this.secureDelegationsEncryption = secureDelegationsEncryption;
|
|
29
|
+
this.dataOwnerApi = dataOwnerApi;
|
|
30
|
+
}
|
|
31
|
+
decryptLegacyDelegations(entities, dataOwnersHierarchySubset, metadataType) {
|
|
32
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
33
|
+
// For legacy delegations there is no advantage in doing stuff in bulk.
|
|
34
|
+
const res = {};
|
|
35
|
+
for (const e of entities) {
|
|
36
|
+
const allDecrypted = yield this.extractFromLegacyDelegations(e, dataOwnersHierarchySubset, metadataType);
|
|
37
|
+
const deduplicatedDecrypted = new Set(allDecrypted.map((x) => x.decrypted));
|
|
38
|
+
res[e.id] = [...deduplicatedDecrypted];
|
|
39
|
+
}
|
|
40
|
+
return res;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
extractFromLegacyDelegations(entity, dataOwnersHierarchySubset, metadataType) {
|
|
44
|
+
var _a, _b, _c;
|
|
45
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
if (!dataOwnersHierarchySubset.length)
|
|
47
|
+
throw new Error("`dataOwnersHierarchySubset` can't be empty");
|
|
48
|
+
let delegations;
|
|
49
|
+
let validateDecrypted = (x) => Promise.resolve(!!x);
|
|
50
|
+
let mapDecrypted = (x) => x;
|
|
51
|
+
switch (metadataType) {
|
|
52
|
+
case SecurityMetadataType.SecretId:
|
|
53
|
+
delegations = (_a = entity.delegations) !== null && _a !== void 0 ? _a : {};
|
|
54
|
+
break;
|
|
55
|
+
case SecurityMetadataType.EncryptionKey:
|
|
56
|
+
delegations = (_b = entity.encryptionKeys) !== null && _b !== void 0 ? _b : {};
|
|
57
|
+
validateDecrypted = (key) => __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
if (!/^[0-9A-Fa-f\-]+$/g.test(key))
|
|
59
|
+
return false;
|
|
60
|
+
try {
|
|
61
|
+
yield this.primitives.AES.importKey('raw', (0, utils_1.hex2ua)(key.replace(/-/g, '')));
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
console.warn(`Could not import key ${key} as an encryption key.`, e);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
mapDecrypted = (key) => key.replace(/-/g, '');
|
|
70
|
+
break;
|
|
71
|
+
case SecurityMetadataType.OwningEntityId:
|
|
72
|
+
delegations = (_c = entity.cryptedForeignKeys) !== null && _c !== void 0 ? _c : {};
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
throw new Error(`Internal error: invalid SecurityMetadataType ${metadataType}`);
|
|
76
|
+
}
|
|
77
|
+
const delegationsWithOwner = Object.entries(delegations).flatMap(([delegateId, delegations]) => dataOwnersHierarchySubset.some((dataOwnerId) => dataOwnerId === delegateId)
|
|
78
|
+
? this.populateLegacyDelegationDelegate(delegateId, delegations)
|
|
79
|
+
: this.populateLegacyDelegationDelegate(delegateId, delegations.filter((d) => dataOwnersHierarchySubset.some((dataOwnerId) => d.owner === dataOwnerId))));
|
|
80
|
+
const res = [];
|
|
81
|
+
for (const delegation of delegationsWithOwner) {
|
|
82
|
+
const decrypted = yield this.tryDecryptLegacyDelegation(delegation, (k) => validateDecrypted(k));
|
|
83
|
+
if (decrypted)
|
|
84
|
+
res.push({
|
|
85
|
+
decrypted: mapDecrypted(decrypted),
|
|
86
|
+
dataOwnersWithAccess: delegation.owner ? [delegation.owner, delegation.delegatedTo] : [delegation.delegatedTo],
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return res;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
populateLegacyDelegationDelegate(delegateId, delegations) {
|
|
93
|
+
return delegations.map((d) => (d.delegatedTo === delegateId ? d : Object.assign(Object.assign({}, d), { delegatedTo: delegateId })));
|
|
94
|
+
}
|
|
95
|
+
tryDecryptLegacyDelegation(delegation, validateDecrypted) {
|
|
45
96
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
-
|
|
47
|
-
for (const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
97
|
+
const exchangeKeys = yield this.exchangeKeysManager.getDecryptionExchangeKeysFor(delegation.owner, delegation.delegatedTo);
|
|
98
|
+
for (const key of exchangeKeys) {
|
|
99
|
+
try {
|
|
100
|
+
// Format of encrypted key for any delegation should be entityId:key, but with the merging of entities the entityId might not match the
|
|
101
|
+
// current id. As a checksum we are only verifying that the decrypted bytes can be represented as a string with exactly one ':'.
|
|
102
|
+
// Additionally, we also have a validator that is specific for each type of delegation content (encryption key, secret id, ...)
|
|
103
|
+
const decrypted = (0, utils_1.ua2string)(yield this.primitives.AES.decrypt(key, (0, utils_1.hex2ua)(delegation.key)));
|
|
104
|
+
const decryptedSplit = decrypted.split(':');
|
|
105
|
+
if (decryptedSplit.length === 2) {
|
|
106
|
+
if (yield validateDecrypted(decryptedSplit[1]))
|
|
107
|
+
return decryptedSplit[1];
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
console.warn("Error in the decrypted delegation: content should contain exactly 1 ':', the delegation is ignored.");
|
|
111
|
+
}
|
|
51
112
|
}
|
|
52
|
-
|
|
53
|
-
|
|
113
|
+
catch (e) {
|
|
114
|
+
// Do nothing: the delegation uses another exchange key owner->delegator
|
|
54
115
|
}
|
|
55
116
|
}
|
|
56
|
-
return currMaxLevel;
|
|
57
117
|
});
|
|
58
118
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
for (const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
119
|
+
decryptSecureDelegationsUsingCache(entities, dataOwnersHierarchySubset, metadataType) {
|
|
120
|
+
var _a, _b, _c, _d;
|
|
121
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
122
|
+
const toSearchById = new Set([]);
|
|
123
|
+
const toSearchByDelegationKey = new Set([]);
|
|
124
|
+
for (const e of entities) {
|
|
125
|
+
for (const [delegationKey, delegation] of Object.entries((_b = (_a = e.securityMetadata) === null || _a === void 0 ? void 0 : _a.secureDelegations) !== null && _b !== void 0 ? _b : {})) {
|
|
126
|
+
if (!delegation.delegator ||
|
|
127
|
+
!delegation.delegate ||
|
|
128
|
+
dataOwnersHierarchySubset.some((it) => it == delegation.delegator || it == delegation.delegate)) {
|
|
129
|
+
if (delegation.exchangeDataId) {
|
|
130
|
+
toSearchById.add(delegation.exchangeDataId);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
toSearchByDelegationKey.add(delegationKey);
|
|
134
|
+
}
|
|
71
135
|
}
|
|
72
136
|
}
|
|
73
|
-
}
|
|
137
|
+
}
|
|
138
|
+
const cachedByExchangeDataId = yield this.exchangeData.getDecryptionDataKeyByIds([...toSearchById], false);
|
|
139
|
+
const cachedByDelegationKey = yield this.exchangeData.getCachedDecryptionDataKeyByAccessControlHash([...toSearchByDelegationKey]);
|
|
140
|
+
const res = {};
|
|
141
|
+
for (const entity of entities) {
|
|
142
|
+
const currEntityRes = new Set([]);
|
|
143
|
+
for (const [delegationKey, delegation] of Object.entries((_d = (_c = entity.securityMetadata) === null || _c === void 0 ? void 0 : _c.secureDelegations) !== null && _d !== void 0 ? _d : {})) {
|
|
144
|
+
const cached = delegation.exchangeDataId ? cachedByExchangeDataId[delegation.exchangeDataId] : cachedByDelegationKey[delegationKey];
|
|
145
|
+
if ((cached === null || cached === void 0 ? void 0 : cached.exchangeKey) &&
|
|
146
|
+
dataOwnersHierarchySubset.some((it) => { var _a, _b; return it == ((_a = cached === null || cached === void 0 ? void 0 : cached.exchangeData) === null || _a === void 0 ? void 0 : _a.delegator) || it == ((_b = cached === null || cached === void 0 ? void 0 : cached.exchangeData) === null || _b === void 0 ? void 0 : _b.delegate); })) {
|
|
147
|
+
;
|
|
148
|
+
(yield this.decryptSecureDelegationMetadata(delegation, metadataType, cached.exchangeKey)).forEach((decrypted) => currEntityRes.add(decrypted));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
res[entity.id] = [...currEntityRes];
|
|
152
|
+
}
|
|
153
|
+
return res;
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
hasSecurityMetadataOfType(delegation, metadataType) {
|
|
157
|
+
var _a, _b, _c;
|
|
158
|
+
switch (metadataType) {
|
|
159
|
+
case SecurityMetadataType.SecretId:
|
|
160
|
+
return ((_a = delegation.secretIds) !== null && _a !== void 0 ? _a : []).length > 0;
|
|
161
|
+
case SecurityMetadataType.EncryptionKey:
|
|
162
|
+
return ((_b = delegation.encryptionKeys) !== null && _b !== void 0 ? _b : []).length > 0;
|
|
163
|
+
case SecurityMetadataType.OwningEntityId:
|
|
164
|
+
return ((_c = delegation.owningEntityIds) !== null && _c !== void 0 ? _c : []).length > 0;
|
|
165
|
+
default:
|
|
166
|
+
throw new Error('Internal error: invalid metadata type');
|
|
74
167
|
}
|
|
75
|
-
|
|
168
|
+
}
|
|
169
|
+
decryptSecureDelegationsUsingKnownExchangeData(entities, dataOwnersHierarchySubset, metadataType) {
|
|
170
|
+
var _a, _b, _c, _d;
|
|
171
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
172
|
+
const toSearchById = new Set([]);
|
|
173
|
+
for (const e of entities) {
|
|
174
|
+
for (const delegation of Object.values((_b = (_a = e.securityMetadata) === null || _a === void 0 ? void 0 : _a.secureDelegations) !== null && _b !== void 0 ? _b : {})) {
|
|
175
|
+
if (dataOwnersHierarchySubset.some((it) => it == delegation.delegator || it == delegation.delegate)) {
|
|
176
|
+
if (delegation.exchangeDataId && this.hasSecurityMetadataOfType(delegation, metadataType)) {
|
|
177
|
+
toSearchById.add(delegation.exchangeDataId);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const retrievedByExchangeDataId = toSearchById.size > 0 ? yield this.exchangeData.getDecryptionDataKeyByIds([...toSearchById], true) : {};
|
|
183
|
+
const res = {};
|
|
184
|
+
for (const entity of entities) {
|
|
185
|
+
const currEntityRes = new Set([]);
|
|
186
|
+
for (const delegation of Object.values((_d = (_c = entity.securityMetadata) === null || _c === void 0 ? void 0 : _c.secureDelegations) !== null && _d !== void 0 ? _d : {})) {
|
|
187
|
+
const currDelegationExchangeData = delegation.exchangeDataId ? retrievedByExchangeDataId[delegation.exchangeDataId] : undefined;
|
|
188
|
+
if (currDelegationExchangeData === null || currDelegationExchangeData === void 0 ? void 0 : currDelegationExchangeData.exchangeKey) {
|
|
189
|
+
;
|
|
190
|
+
(yield this.decryptSecureDelegationMetadata(delegation, metadataType, currDelegationExchangeData.exchangeKey)).forEach((decrypted) => currEntityRes.add(decrypted));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
res[entity.id] = [...currEntityRes];
|
|
194
|
+
}
|
|
195
|
+
return res;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
decryptSecureDelegationsUsingExchangeDataMap(entities, dataOwnersHierarchySubset, metadataType) {
|
|
199
|
+
var _a, _b, _c, _d;
|
|
200
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
201
|
+
const toSearchByExchangeDataMap = new Set([]);
|
|
202
|
+
for (const e of entities) {
|
|
203
|
+
for (const [delegationKey, delegation] of Object.entries((_b = (_a = e.securityMetadata) === null || _a === void 0 ? void 0 : _a.secureDelegations) !== null && _b !== void 0 ? _b : {})) {
|
|
204
|
+
if (dataOwnersHierarchySubset.some((it) => it == delegation.delegator || it == delegation.delegate)) {
|
|
205
|
+
if (!delegation.exchangeDataId && this.hasSecurityMetadataOfType(delegation, metadataType)) {
|
|
206
|
+
toSearchByExchangeDataMap.add(delegationKey);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const exchangeDataMaps = toSearchByExchangeDataMap.size > 0 ? yield this.exchangeDataMap.getExchangeDataMapBatch([...toSearchByExchangeDataMap]) : [];
|
|
212
|
+
const exchangeDataIdByDelegationKey = {};
|
|
213
|
+
for (const exchangeDataMap of exchangeDataMaps) {
|
|
214
|
+
const decrypted = yield this.secureDelegationsEncryption.decryptExchangeDataId(exchangeDataMap.encryptedExchangeDataIds);
|
|
215
|
+
if (decrypted) {
|
|
216
|
+
exchangeDataIdByDelegationKey[exchangeDataMap.id] = decrypted;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (Object.keys(exchangeDataIdByDelegationKey).length == 0)
|
|
220
|
+
return {};
|
|
221
|
+
const retrievedByExchangeDataId = Object.values(exchangeDataIdByDelegationKey).length > 0
|
|
222
|
+
? yield this.exchangeData.getDecryptionDataKeyByIds([...new Set(Object.values(exchangeDataIdByDelegationKey))], true)
|
|
223
|
+
: {};
|
|
224
|
+
const res = {};
|
|
225
|
+
for (const entity of entities) {
|
|
226
|
+
const currEntityRes = new Set([]);
|
|
227
|
+
for (const [delegationKey, delegation] of Object.entries((_d = (_c = entity.securityMetadata) === null || _c === void 0 ? void 0 : _c.secureDelegations) !== null && _d !== void 0 ? _d : {})) {
|
|
228
|
+
const exchangeDataId = exchangeDataIdByDelegationKey[delegationKey];
|
|
229
|
+
const cached = exchangeDataId ? retrievedByExchangeDataId[exchangeDataId] : undefined;
|
|
230
|
+
if (cached === null || cached === void 0 ? void 0 : cached.exchangeKey) {
|
|
231
|
+
;
|
|
232
|
+
(yield this.decryptSecureDelegationMetadata(delegation, metadataType, cached.exchangeKey)).forEach((decrypted) => currEntityRes.add(decrypted));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
res[entity.id] = [...currEntityRes];
|
|
236
|
+
}
|
|
237
|
+
return res;
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
decryptAll(entity, dataOwnersHierarchySubset, metadataType) {
|
|
241
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
242
|
+
const allExtractedWithDataOwners = [
|
|
243
|
+
...(yield this.decryptAllLegacyDelegations(entity, dataOwnersHierarchySubset, metadataType)),
|
|
244
|
+
...(yield this.decryptAllSecureDelegations(entity, dataOwnersHierarchySubset, metadataType)),
|
|
245
|
+
];
|
|
246
|
+
return dataOwnersHierarchySubset.map((dataOwner) => {
|
|
247
|
+
const decryptedEntriesForDataOwner = allExtractedWithDataOwners
|
|
248
|
+
.filter((x) => x.dataOwnersWithAccess.some((d) => dataOwner == d))
|
|
249
|
+
.map((x) => x.decrypted);
|
|
250
|
+
return {
|
|
251
|
+
ownerId: dataOwner,
|
|
252
|
+
extracted: [...new Set(decryptedEntriesForDataOwner)],
|
|
253
|
+
};
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
decryptAllLegacyDelegations(entity, dataOwnersHierarchySubset, metadataType) {
|
|
258
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
259
|
+
return this.extractFromLegacyDelegations(entity, dataOwnersHierarchySubset, metadataType);
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
decryptAllSecureDelegations(entity, dataOwnersHierarchySubset, metadataType) {
|
|
263
|
+
var _a, _b;
|
|
264
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
265
|
+
const secureDelegationEntries = Object.entries((_b = (_a = entity.securityMetadata) === null || _a === void 0 ? void 0 : _a.secureDelegations) !== null && _b !== void 0 ? _b : {});
|
|
266
|
+
const toSearchByDelegationKey = secureDelegationEntries.flatMap(([delegationKey, delegation]) => {
|
|
267
|
+
if (!delegation.exchangeDataId) {
|
|
268
|
+
return [delegationKey];
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
return [];
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
const exchangeDataByDelegationKey = yield this.exchangeData.getCachedDecryptionDataKeyByAccessControlHash(toSearchByDelegationKey);
|
|
275
|
+
const toSearchWithExchangeDataMap = secureDelegationEntries.flatMap(([delegationKey, delegation]) => {
|
|
276
|
+
if (!delegation.exchangeDataId &&
|
|
277
|
+
dataOwnersHierarchySubset.some((it) => delegation.delegate == it || delegation.delegator == it) &&
|
|
278
|
+
!exchangeDataByDelegationKey[delegationKey] &&
|
|
279
|
+
this.hasSecurityMetadataOfType(delegation, metadataType)) {
|
|
280
|
+
return [delegationKey];
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
return [];
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
const exchangeDataMaps = toSearchWithExchangeDataMap.length > 0 ? yield this.exchangeDataMap.getExchangeDataMapBatch(toSearchWithExchangeDataMap) : [];
|
|
287
|
+
const exchangeDataIdByDelegationKey = {};
|
|
288
|
+
for (const exchangeDataMap of exchangeDataMaps) {
|
|
289
|
+
const decrypted = yield this.secureDelegationsEncryption.decryptExchangeDataId(exchangeDataMap.encryptedExchangeDataIds);
|
|
290
|
+
if (decrypted) {
|
|
291
|
+
exchangeDataIdByDelegationKey[exchangeDataMap.id] = decrypted;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const toSearchDirectlyById = secureDelegationEntries.flatMap(([delegationKey, delegation]) => {
|
|
295
|
+
if (delegation.exchangeDataId &&
|
|
296
|
+
dataOwnersHierarchySubset.some((it) => delegation.delegate == it || delegation.delegator == it) &&
|
|
297
|
+
!exchangeDataByDelegationKey[delegationKey] &&
|
|
298
|
+
this.hasSecurityMetadataOfType(delegation, metadataType)) {
|
|
299
|
+
return [delegation.exchangeDataId];
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
return [];
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
const allExchangeDataIdToRetrieve = [...new Set([...toSearchDirectlyById, ...Object.values(exchangeDataIdByDelegationKey)])];
|
|
306
|
+
const exchangeDataById = allExchangeDataIdToRetrieve.length > 0 ? yield this.exchangeData.getDecryptionDataKeyByIds(allExchangeDataIdToRetrieve, true) : {};
|
|
307
|
+
const allExtractedWithDataOwners = [];
|
|
308
|
+
for (const [delegationKey, delegation] of secureDelegationEntries) {
|
|
309
|
+
let exchangeData = undefined;
|
|
310
|
+
if (exchangeDataByDelegationKey[delegationKey]) {
|
|
311
|
+
exchangeData = exchangeDataByDelegationKey[delegationKey];
|
|
312
|
+
}
|
|
313
|
+
else if (delegation.exchangeDataId) {
|
|
314
|
+
exchangeData = exchangeDataById[delegation.exchangeDataId];
|
|
315
|
+
}
|
|
316
|
+
else if (exchangeDataIdByDelegationKey[delegationKey]) {
|
|
317
|
+
exchangeData = exchangeDataById[exchangeDataIdByDelegationKey[delegationKey]];
|
|
318
|
+
}
|
|
319
|
+
if (exchangeData && exchangeData.exchangeKey) {
|
|
320
|
+
const decrypted = yield this.decryptSecureDelegationMetadata(delegation, metadataType, exchangeData.exchangeKey);
|
|
321
|
+
for (const d of decrypted) {
|
|
322
|
+
allExtractedWithDataOwners.push({
|
|
323
|
+
decrypted: d,
|
|
324
|
+
dataOwnersWithAccess: [exchangeData.exchangeData.delegator, exchangeData.exchangeData.delegate],
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return allExtractedWithDataOwners;
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
getDelegationMemberDetails(typedEntity) {
|
|
333
|
+
var _a, _b;
|
|
334
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
335
|
+
const res = {};
|
|
336
|
+
// 1. Add all explicit data owners, keep only delegations with at least an anonymous data owner to check later
|
|
337
|
+
let remainingDelegations = Object.entries((_b = (_a = typedEntity.entity.securityMetadata) === null || _a === void 0 ? void 0 : _a.secureDelegations) !== null && _b !== void 0 ? _b : {});
|
|
338
|
+
let updatedRemainingDelegations = [];
|
|
339
|
+
for (const delegationEntry of remainingDelegations) {
|
|
340
|
+
const delegation = delegationEntry[1];
|
|
341
|
+
if (delegation.delegator && delegation.delegate) {
|
|
342
|
+
res[delegationEntry[0]] = {
|
|
343
|
+
delegate: delegation.delegate,
|
|
344
|
+
delegator: delegation.delegator,
|
|
345
|
+
fullyExplicit: true,
|
|
346
|
+
accessLevel: delegation.permissions,
|
|
347
|
+
accessControlSecret: undefined,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
updatedRemainingDelegations.push(delegationEntry);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
remainingDelegations = updatedRemainingDelegations;
|
|
355
|
+
if (!remainingDelegations.length)
|
|
356
|
+
return res;
|
|
357
|
+
updatedRemainingDelegations = [];
|
|
358
|
+
// 2. Attempt to identify the anonymous data owner of remaining delegations by checking if we have the exchange data cached by hash
|
|
359
|
+
// Note: we can find exchange data by hash only if we could successfully decrypt it
|
|
360
|
+
const cachedExchangeData = yield this.exchangeData.getCachedDecryptionDataKeyByAccessControlHash(remainingDelegations.map((d) => d[0]));
|
|
361
|
+
for (const delegationEntry of remainingDelegations) {
|
|
362
|
+
const exchangeDataOfDelegation = cachedExchangeData[delegationEntry[0]];
|
|
363
|
+
if (exchangeDataOfDelegation) {
|
|
364
|
+
res[delegationEntry[0]] = {
|
|
365
|
+
delegate: exchangeDataOfDelegation.exchangeData.delegate,
|
|
366
|
+
delegator: exchangeDataOfDelegation.exchangeData.delegator,
|
|
367
|
+
fullyExplicit: false,
|
|
368
|
+
accessLevel: delegationEntry[1].permissions,
|
|
369
|
+
accessControlSecret: exchangeDataOfDelegation.accessControlSecret,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
updatedRemainingDelegations.push(delegationEntry);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
remainingDelegations = updatedRemainingDelegations;
|
|
377
|
+
if (!remainingDelegations.length)
|
|
378
|
+
return res;
|
|
379
|
+
updatedRemainingDelegations = [];
|
|
380
|
+
// 3. Attempt to identify the anonymous data owner of remaining delegations between us (or one of our parents) and an anonymous data owner
|
|
381
|
+
const hierarchy = yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds();
|
|
382
|
+
const remainingExchangeDataMaps = yield this.exchangeDataMap.getExchangeDataMapBatch(remainingDelegations
|
|
383
|
+
.filter(([_, delegation]) => hierarchy.some((x) => x == delegation.delegator || x == delegation.delegate))
|
|
384
|
+
.map(([hash, _]) => hash));
|
|
385
|
+
const exchangeDataIdByDelegationKey = {};
|
|
386
|
+
for (const exchangeDataMap of remainingExchangeDataMaps) {
|
|
387
|
+
if (!!exchangeDataMap.encryptedExchangeDataIds) {
|
|
388
|
+
const decrypted = yield this.secureDelegationsEncryption.decryptExchangeDataId(exchangeDataMap.encryptedExchangeDataIds);
|
|
389
|
+
if (decrypted) {
|
|
390
|
+
exchangeDataIdByDelegationKey[exchangeDataMap.id] = decrypted;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const exchangeDataByIds = yield this.exchangeData.getDecryptionDataKeyByIds(Object.values(exchangeDataIdByDelegationKey), true);
|
|
395
|
+
for (const [hash, delegation] of remainingDelegations) {
|
|
396
|
+
if (hierarchy.some((x) => x === delegation.delegate || x === delegation.delegator)) {
|
|
397
|
+
const dataId = exchangeDataIdByDelegationKey[hash];
|
|
398
|
+
const exchangeDataInfo = dataId ? exchangeDataByIds[dataId] : undefined;
|
|
399
|
+
if (exchangeDataInfo) {
|
|
400
|
+
res[hash] = {
|
|
401
|
+
delegator: exchangeDataInfo.exchangeData.delegator,
|
|
402
|
+
delegate: exchangeDataInfo.exchangeData.delegate,
|
|
403
|
+
fullyExplicit: false,
|
|
404
|
+
accessLevel: delegation.permissions,
|
|
405
|
+
accessControlSecret: exchangeDataInfo.accessControlSecret,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
updatedRemainingDelegations.push([hash, delegation]);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
updatedRemainingDelegations.push([hash, delegation]);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return Object.assign(Object.assign({}, res), Object.fromEntries(updatedRemainingDelegations.map(([hash, secureDelegation]) => [
|
|
417
|
+
hash,
|
|
418
|
+
{
|
|
419
|
+
delegator: secureDelegation.delegator,
|
|
420
|
+
delegate: secureDelegation.delegate,
|
|
421
|
+
fullyExplicit: false,
|
|
422
|
+
accessLevel: secureDelegation.permissions,
|
|
423
|
+
accessControlSecret: undefined,
|
|
424
|
+
},
|
|
425
|
+
])));
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
decryptSecureDelegationMetadata(delegation, metadataType, key) {
|
|
429
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
430
|
+
switch (metadataType) {
|
|
431
|
+
case SecurityMetadataType.SecretId:
|
|
432
|
+
return this.secureDelegationsEncryption.decryptSecretIds(delegation, key);
|
|
433
|
+
case SecurityMetadataType.EncryptionKey:
|
|
434
|
+
return this.secureDelegationsEncryption.decryptEncryptionKeys(delegation, key);
|
|
435
|
+
case SecurityMetadataType.OwningEntityId:
|
|
436
|
+
return this.secureDelegationsEncryption.decryptOwningEntityIds(delegation, key);
|
|
437
|
+
default:
|
|
438
|
+
throw new Error(`Internal error: invalid SecurityMetadataType ${metadataType}`);
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
getEntityLegacyDelegationAccessLevel(entity, dataOwnersHierarchySubset) {
|
|
443
|
+
var _a;
|
|
444
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
445
|
+
if (!dataOwnersHierarchySubset.length)
|
|
446
|
+
throw new Error("`dataOwnersHierarchySubset` can't be empty");
|
|
447
|
+
// Legacy delegations provide write access
|
|
448
|
+
if (Object.keys((_a = entity.delegations) !== null && _a !== void 0 ? _a : {}).some((delegate) => dataOwnersHierarchySubset.includes(delegate))) {
|
|
449
|
+
return AccessLevelEnum.WRITE;
|
|
450
|
+
}
|
|
451
|
+
return undefined;
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
getEntitySecureDelegationAccessLevel(entity, dataOwnersHierarchySubset) {
|
|
455
|
+
var _a, _b, _c, _d;
|
|
456
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
457
|
+
if (!dataOwnersHierarchySubset.length)
|
|
458
|
+
throw new Error("`dataOwnersHierarchySubset` can't be empty");
|
|
459
|
+
// If the data owner is explicit all delegations he can access has his id. If the delegator is anonymous all delegations he can access are
|
|
460
|
+
// accessible by hash. No mixed scenario possible.
|
|
461
|
+
let accessibleDelegations = Object.values((_b = (_a = entity.securityMetadata) === null || _a === void 0 ? void 0 : _a.secureDelegations) !== null && _b !== void 0 ? _b : {}).filter((secureDelegation) => dataOwnersHierarchySubset.some((dataOwner) => dataOwner === secureDelegation.delegator || dataOwner === secureDelegation.delegate));
|
|
462
|
+
if (!accessibleDelegations.length) {
|
|
463
|
+
const availableCanonicalHashes = Object.keys(yield this.exchangeData.getCachedDecryptionDataKeyByAccessControlHash(Object.keys((_d = (_c = entity.securityMetadata) === null || _c === void 0 ? void 0 : _c.secureDelegations) !== null && _d !== void 0 ? _d : {})));
|
|
464
|
+
accessibleDelegations = availableCanonicalHashes.map((hash) => { var _a, _b; return ((_b = (_a = entity.securityMetadata) === null || _a === void 0 ? void 0 : _a.secureDelegations) !== null && _b !== void 0 ? _b : {})[hash]; });
|
|
465
|
+
}
|
|
466
|
+
const permissions = accessibleDelegations.map((secureDelegation) => secureDelegation.permissions);
|
|
467
|
+
let maxLevel = undefined;
|
|
468
|
+
for (const permission of permissions) {
|
|
469
|
+
if (permission === AccessLevelEnum.WRITE) {
|
|
470
|
+
return AccessLevelEnum.WRITE;
|
|
471
|
+
}
|
|
472
|
+
if (permission === AccessLevelEnum.READ) {
|
|
473
|
+
maxLevel = AccessLevelEnum.READ;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return maxLevel;
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
getEntityAccessLevel(entity, dataOwnersHierarchySubset) {
|
|
480
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
481
|
+
const legacyAccess = yield this.getEntityLegacyDelegationAccessLevel(entity, dataOwnersHierarchySubset);
|
|
482
|
+
if (legacyAccess != undefined)
|
|
483
|
+
return legacyAccess;
|
|
484
|
+
return this.getEntitySecureDelegationAccessLevel(entity, dataOwnersHierarchySubset);
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
hasAnyEncryptionKeys(entity) {
|
|
488
|
+
var _a, _b, _c;
|
|
489
|
+
return Object.keys((_a = entity.encryptionKeys) !== null && _a !== void 0 ? _a : {}).length > 0 || Object.keys((_c = (_b = entity.securityMetadata) === null || _b === void 0 ? void 0 : _b.secureDelegations) !== null && _c !== void 0 ? _c : {}).length > 0;
|
|
76
490
|
}
|
|
77
491
|
}
|
|
78
|
-
exports.
|
|
492
|
+
exports.SecurityMetadataDecryptor = SecurityMetadataDecryptor;
|
|
79
493
|
//# sourceMappingURL=SecurityMetadataDecryptor.js.map
|