@icure/api 8.0.78 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/icc-x-api/crypto/ExchangeKeysManager.d.ts +1 -0
  2. package/icc-x-api/crypto/ExchangeKeysManager.js +26 -16
  3. package/icc-x-api/crypto/ExchangeKeysManager.js.map +1 -1
  4. package/icc-x-api/crypto/ExtendedApisUtils.d.ts +47 -2
  5. package/icc-x-api/crypto/ExtendedApisUtils.js.map +1 -1
  6. package/icc-x-api/crypto/ExtendedApisUtilsImpl.d.ts +8 -1
  7. package/icc-x-api/crypto/ExtendedApisUtilsImpl.js +81 -2
  8. package/icc-x-api/crypto/ExtendedApisUtilsImpl.js.map +1 -1
  9. package/icc-x-api/crypto/SecretIdUseOption.d.ts +60 -0
  10. package/icc-x-api/crypto/SecretIdUseOption.js +60 -0
  11. package/icc-x-api/crypto/SecretIdUseOption.js.map +1 -0
  12. package/icc-x-api/icc-accesslog-x-api.d.ts +2 -1
  13. package/icc-x-api/icc-accesslog-x-api.js +2 -3
  14. package/icc-x-api/icc-accesslog-x-api.js.map +1 -1
  15. package/icc-x-api/icc-calendar-item-x-api.d.ts +26 -3
  16. package/icc-x-api/icc-calendar-item-x-api.js +51 -16
  17. package/icc-x-api/icc-calendar-item-x-api.js.map +1 -1
  18. package/icc-x-api/icc-classification-x-api.d.ts +2 -1
  19. package/icc-x-api/icc-classification-x-api.js +2 -3
  20. package/icc-x-api/icc-classification-x-api.js.map +1 -1
  21. package/icc-x-api/icc-contact-x-api.d.ts +3 -2
  22. package/icc-x-api/icc-contact-x-api.js +5 -8
  23. package/icc-x-api/icc-contact-x-api.js.map +1 -1
  24. package/icc-x-api/icc-crypto-x-api.d.ts +1 -7
  25. package/icc-x-api/icc-crypto-x-api.js +1 -8
  26. package/icc-x-api/icc-crypto-x-api.js.map +1 -1
  27. package/icc-x-api/icc-document-x-api.d.ts +2 -1
  28. package/icc-x-api/icc-document-x-api.js +3 -6
  29. package/icc-x-api/icc-document-x-api.js.map +1 -1
  30. package/icc-x-api/icc-form-x-api.d.ts +2 -1
  31. package/icc-x-api/icc-form-x-api.js +2 -3
  32. package/icc-x-api/icc-form-x-api.js.map +1 -1
  33. package/icc-x-api/icc-helement-x-api.d.ts +3 -2
  34. package/icc-x-api/icc-helement-x-api.js +5 -8
  35. package/icc-x-api/icc-helement-x-api.js.map +1 -1
  36. package/icc-x-api/icc-invoice-x-api.d.ts +2 -1
  37. package/icc-x-api/icc-invoice-x-api.js +2 -3
  38. package/icc-x-api/icc-invoice-x-api.js.map +1 -1
  39. package/icc-x-api/icc-message-x-api.d.ts +2 -1
  40. package/icc-x-api/icc-message-x-api.js +2 -3
  41. package/icc-x-api/icc-message-x-api.js.map +1 -1
  42. package/icc-x-api/icc-patient-x-api.js +4 -6
  43. package/icc-x-api/icc-patient-x-api.js.map +1 -1
  44. package/icc-x-api/icc-topic-x-api.d.ts +2 -1
  45. package/icc-x-api/icc-topic-x-api.js +3 -2
  46. package/icc-x-api/icc-topic-x-api.js.map +1 -1
  47. package/icc-x-api/index.js +1 -3
  48. package/icc-x-api/index.js.map +1 -1
  49. package/package.json +1 -1
  50. package/test/icc-x-api/confidential-entities-test.js +49 -6
  51. package/test/icc-x-api/confidential-entities-test.js.map +1 -1
  52. package/test/icc-x-api/crypto/cryptoTest.js +5 -3
  53. package/test/icc-x-api/crypto/cryptoTest.js.map +1 -1
  54. package/test/icc-x-api/crypto/full-crypto-test.js +0 -2
  55. package/test/icc-x-api/crypto/full-crypto-test.js.map +1 -1
  56. package/test/icc-x-api/crypto/shamir.js +3 -1
  57. package/test/icc-x-api/crypto/shamir.js.map +1 -1
  58. package/test/icc-x-api/diocancaro.d.ts +1 -0
  59. package/test/icc-x-api/diocancaro.js +75 -0
  60. package/test/icc-x-api/diocancaro.js.map +1 -0
  61. package/test/icc-x-api/icc-calendar-item-x-api.js +1 -1
  62. package/test/icc-x-api/icc-calendar-item-x-api.js.map +1 -1
  63. package/test/icc-x-api/icc-contact-x-api.js +4 -2
  64. package/test/icc-x-api/icc-contact-x-api.js.map +1 -1
  65. package/test/icc-x-api/icc-helement-x-api-test.js +3 -1
  66. package/test/icc-x-api/icc-helement-x-api-test.js.map +1 -1
  67. package/icc-x-api/crypto/ConfidentialEntities.d.ts +0 -64
  68. package/icc-x-api/crypto/ConfidentialEntities.js +0 -112
  69. package/icc-x-api/crypto/ConfidentialEntities.js.map +0 -1
@@ -25,6 +25,7 @@ export declare class ExchangeKeysManager {
25
25
  * @return all available exchange keys from the delegator-delegate pair.
26
26
  */
27
27
  getDecryptionExchangeKeysFor(delegatorId: string, delegateId: string): Promise<CryptoKey[]>;
28
+ private decryptChunk;
28
29
  /**
29
30
  * Reloads all exchange keys for the cache.
30
31
  */
@@ -37,9 +37,28 @@ class ExchangeKeysManager {
37
37
  * @return all available exchange keys from the delegator-delegate pair.
38
38
  */
39
39
  getDecryptionExchangeKeysFor(delegatorId, delegateId) {
40
- var _a, _b;
40
+ var _a;
41
41
  return __awaiter(this, void 0, void 0, function* () {
42
- return (_b = (_a = this.cache[delegatorId]) === null || _a === void 0 ? void 0 : _a[delegateId]) !== null && _b !== void 0 ? _b : [];
42
+ const entry = (_a = this.cache[delegatorId]) === null || _a === void 0 ? void 0 : _a[delegateId];
43
+ if (entry != undefined) {
44
+ if ('decrypted' in entry) {
45
+ return yield entry.decrypted;
46
+ }
47
+ else {
48
+ const decryptedPromise = this.decryptChunk(entry.encrypted);
49
+ this.cache[delegatorId][delegateId] = { decrypted: decryptedPromise };
50
+ return yield decryptedPromise;
51
+ }
52
+ }
53
+ else {
54
+ return [];
55
+ }
56
+ });
57
+ }
58
+ decryptChunk(encryptedKeys) {
59
+ return __awaiter(this, void 0, void 0, function* () {
60
+ const decryptionKeys = this.keyManager.getDecryptionKeys();
61
+ return (yield this.base.tryDecryptExchangeKeys(encryptedKeys, decryptionKeys)).successfulDecryptions;
43
62
  });
44
63
  }
45
64
  /**
@@ -56,11 +75,11 @@ class ExchangeKeysManager {
56
75
  encryptedKeys[delegator] = {};
57
76
  }
58
77
  if (!encryptedKeys[delegator][dataOwner]) {
59
- encryptedKeys[delegator][dataOwner] = [];
78
+ encryptedKeys[delegator][dataOwner] = { encrypted: [] };
60
79
  }
61
80
  const keysForDelegatorDelegate = encryptedKeys[delegator][dataOwner];
62
81
  for (const encryptedEntries of Object.values(encryptedByDelegatorFp)) {
63
- keysForDelegatorDelegate.push(encryptedEntries);
82
+ keysForDelegatorDelegate.encrypted.push(encryptedEntries);
64
83
  }
65
84
  }
66
85
  for (const encryptedByDelegateId of Object.values(info.keysFromOwner)) {
@@ -69,22 +88,13 @@ class ExchangeKeysManager {
69
88
  encryptedKeys[dataOwner] = {};
70
89
  }
71
90
  if (!encryptedKeys[dataOwner][delegate]) {
72
- encryptedKeys[dataOwner][delegate] = [];
91
+ encryptedKeys[dataOwner][delegate] = { encrypted: [] };
73
92
  }
74
- encryptedKeys[dataOwner][delegate].push(encryptedEntries);
93
+ encryptedKeys[dataOwner][delegate].encrypted.push(encryptedEntries);
75
94
  }
76
95
  }
77
96
  }
78
- const decryptionKeys = this.keyManager.getDecryptionKeys();
79
- const decrypted = {};
80
- for (const [delegator, keysByDelegate] of Object.entries(encryptedKeys)) {
81
- const currDelegatorData = {};
82
- for (const [delegate, keys] of Object.entries(keysByDelegate)) {
83
- currDelegatorData[delegate] = (yield this.base.tryDecryptExchangeKeys(keys, decryptionKeys)).successfulDecryptions;
84
- }
85
- decrypted[delegator] = currDelegatorData;
86
- }
87
- this.cache = decrypted;
97
+ this.cache = encryptedKeys;
88
98
  });
89
99
  }
90
100
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ExchangeKeysManager.js","sourceRoot":"","sources":["../../../icc-x-api/crypto/ExchangeKeysManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { UserEncryptionKeysManager } from './UserEncryptionKeysManager'\nimport { BaseExchangeKeysManager } from './BaseExchangeKeysManager'\nimport { IccDataOwnerXApi } from '../icc-data-owner-x-api'\nimport { CryptoPrimitives } from './CryptoPrimitives'\nimport { CryptoStrategies } from './CryptoStrategies'\nimport { IcureStorageFacade } from '../storage/IcureStorageFacade'\nimport { DataOwnerTypeEnum } from '../../icc-api/model/DataOwnerTypeEnum'\n\n/**\n * @internal This class is meant only for internal use and may be changed without notice.\n * More powerful version of {@link BaseExchangeKeysManager} with a simplified interface. Has the following functionalities:\n * - Caches results\n * - Automatically creates new exchange keys if none is available\n * - Automatically choose the public keys to use during the creation of new exchange keys\n * - Automatically retrieves the private keys to use during decryption.\n */\nexport class ExchangeKeysManager {\n private cache: { [delegator: string]: { [delegate: string]: CryptoKey[] } } = {}\n\n get base(): BaseExchangeKeysManager {\n return this.baseExchangeKeysManager\n }\n\n constructor(\n private readonly keyManager: UserEncryptionKeysManager,\n private readonly baseExchangeKeysManager: BaseExchangeKeysManager,\n private readonly dataOwnerApi: IccDataOwnerXApi\n ) {}\n\n /**\n * Get all keys currently available for a delegator-delegate pair. At least one of the two data owners must be part of the hierarchy for the current\n * data owner.\n * @param delegatorId id of a delegator\n * @param delegateId id of a delegate\n * @throws if neither the delegator nor the delegate is part of the hierarchy of the current data owner.\n * @return all available exchange keys from the delegator-delegate pair.\n */\n async getDecryptionExchangeKeysFor(delegatorId: string, delegateId: string): Promise<CryptoKey[]> {\n return this.cache[delegatorId]?.[delegateId] ?? []\n }\n\n /**\n * Reloads all exchange keys for the cache.\n */\n async reloadCache(): Promise<void> {\n const hierarchy = await this.dataOwnerApi.getCurrentDataOwnerHierarchyIds()\n const encryptedKeysDataByHierarchyMember = Object.fromEntries(\n await Promise.all(\n hierarchy.map((doId) =>\n this.base.getAllExchangeKeysWith(doId, null).then(\n (\n res\n ): [\n string,\n {\n keysToOwner: { [p: string]: { [p: string]: { [p: string]: string } } }\n keysFromOwner: { [p: string]: { [p: string]: { [p: string]: string } } }\n }\n ] => [doId, res]\n )\n )\n )\n )\n const encryptedKeys: { [delegator: string]: { [delegate: string]: { [pubFp: string]: string }[] } } = {}\n for (const [dataOwner, info] of Object.entries(encryptedKeysDataByHierarchyMember)) {\n for (const [delegator, encryptedByDelegatorFp] of Object.entries(info.keysToOwner)) {\n if (!encryptedKeys[delegator]) {\n encryptedKeys[delegator] = {}\n }\n if (!encryptedKeys[delegator][dataOwner]) {\n encryptedKeys[delegator][dataOwner] = []\n }\n const keysForDelegatorDelegate = encryptedKeys[delegator][dataOwner]\n for (const encryptedEntries of Object.values(encryptedByDelegatorFp)) {\n keysForDelegatorDelegate.push(encryptedEntries)\n }\n }\n for (const encryptedByDelegateId of Object.values(info.keysFromOwner)) {\n for (const [delegate, encryptedEntries] of Object.entries(encryptedByDelegateId)) {\n if (!encryptedKeys[dataOwner]) {\n encryptedKeys[dataOwner] = {}\n }\n if (!encryptedKeys[dataOwner][delegate]) {\n encryptedKeys[dataOwner][delegate] = []\n }\n encryptedKeys[dataOwner][delegate].push(encryptedEntries)\n }\n }\n }\n const decryptionKeys = this.keyManager.getDecryptionKeys()\n const decrypted: { [delegator: string]: { [delegate: string]: CryptoKey[] } } = {}\n for (const [delegator, keysByDelegate] of Object.entries(encryptedKeys)) {\n const currDelegatorData: { [delegate: string]: CryptoKey[] } = {}\n for (const [delegate, keys] of Object.entries(keysByDelegate)) {\n currDelegatorData[delegate] = (await this.base.tryDecryptExchangeKeys(keys, decryptionKeys)).successfulDecryptions\n }\n decrypted[delegator] = currDelegatorData\n }\n this.cache = decrypted\n }\n}\n"]}
1
+ {"version":3,"file":"ExchangeKeysManager.js","sourceRoot":"","sources":["../../../icc-x-api/crypto/ExchangeKeysManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { UserEncryptionKeysManager } from './UserEncryptionKeysManager'\nimport { BaseExchangeKeysManager } from './BaseExchangeKeysManager'\nimport { IccDataOwnerXApi } from '../icc-data-owner-x-api'\nimport { CryptoPrimitives } from './CryptoPrimitives'\nimport { CryptoStrategies } from './CryptoStrategies'\nimport { IcureStorageFacade } from '../storage/IcureStorageFacade'\nimport { DataOwnerTypeEnum } from '../../icc-api/model/DataOwnerTypeEnum'\n\ntype CacheValue =\n | {\n encrypted: { [fp: string]: string }[]\n }\n | {\n decrypted: Promise<CryptoKey[]>\n }\n\n/**\n * @internal This class is meant only for internal use and may be changed without notice.\n * More powerful version of {@link BaseExchangeKeysManager} with a simplified interface. Has the following functionalities:\n * - Caches results\n * - Automatically creates new exchange keys if none is available\n * - Automatically choose the public keys to use during the creation of new exchange keys\n * - Automatically retrieves the private keys to use during decryption.\n */\nexport class ExchangeKeysManager {\n private cache: { [delegator: string]: { [delegate: string]: CacheValue } } = {}\n\n get base(): BaseExchangeKeysManager {\n return this.baseExchangeKeysManager\n }\n\n constructor(\n private readonly keyManager: UserEncryptionKeysManager,\n private readonly baseExchangeKeysManager: BaseExchangeKeysManager,\n private readonly dataOwnerApi: IccDataOwnerXApi\n ) {}\n\n /**\n * Get all keys currently available for a delegator-delegate pair. At least one of the two data owners must be part of the hierarchy for the current\n * data owner.\n * @param delegatorId id of a delegator\n * @param delegateId id of a delegate\n * @throws if neither the delegator nor the delegate is part of the hierarchy of the current data owner.\n * @return all available exchange keys from the delegator-delegate pair.\n */\n async getDecryptionExchangeKeysFor(delegatorId: string, delegateId: string): Promise<CryptoKey[]> {\n const entry = this.cache[delegatorId]?.[delegateId]\n if (entry != undefined) {\n if ('decrypted' in entry) {\n return await entry.decrypted\n } else {\n const decryptedPromise = this.decryptChunk(entry.encrypted)\n this.cache[delegatorId][delegateId] = { decrypted: decryptedPromise }\n return await decryptedPromise\n }\n } else {\n return []\n }\n }\n\n private async decryptChunk(encryptedKeys: { [fp: string]: string }[]): Promise<CryptoKey[]> {\n const decryptionKeys = this.keyManager.getDecryptionKeys()\n return (await this.base.tryDecryptExchangeKeys(encryptedKeys, decryptionKeys)).successfulDecryptions\n }\n\n /**\n * Reloads all exchange keys for the cache.\n */\n async reloadCache(): Promise<void> {\n const hierarchy = await this.dataOwnerApi.getCurrentDataOwnerHierarchyIds()\n const encryptedKeysDataByHierarchyMember = Object.fromEntries(\n await Promise.all(\n hierarchy.map((doId) =>\n this.base.getAllExchangeKeysWith(doId, null).then(\n (\n res\n ): [\n string,\n {\n keysToOwner: { [p: string]: { [p: string]: { [p: string]: string } } }\n keysFromOwner: { [p: string]: { [p: string]: { [p: string]: string } } }\n }\n ] => [doId, res]\n )\n )\n )\n )\n const encryptedKeys: { [delegator: string]: { [delegate: string]: { encrypted: { [pubFp: string]: string }[] } } } = {}\n for (const [dataOwner, info] of Object.entries(encryptedKeysDataByHierarchyMember)) {\n for (const [delegator, encryptedByDelegatorFp] of Object.entries(info.keysToOwner)) {\n if (!encryptedKeys[delegator]) {\n encryptedKeys[delegator] = {}\n }\n if (!encryptedKeys[delegator][dataOwner]) {\n encryptedKeys[delegator][dataOwner] = { encrypted: [] }\n }\n const keysForDelegatorDelegate = encryptedKeys[delegator][dataOwner]\n for (const encryptedEntries of Object.values(encryptedByDelegatorFp)) {\n keysForDelegatorDelegate.encrypted.push(encryptedEntries)\n }\n }\n for (const encryptedByDelegateId of Object.values(info.keysFromOwner)) {\n for (const [delegate, encryptedEntries] of Object.entries(encryptedByDelegateId)) {\n if (!encryptedKeys[dataOwner]) {\n encryptedKeys[dataOwner] = {}\n }\n if (!encryptedKeys[dataOwner][delegate]) {\n encryptedKeys[dataOwner][delegate] = { encrypted: [] }\n }\n encryptedKeys[dataOwner][delegate].encrypted.push(encryptedEntries)\n }\n }\n }\n this.cache = encryptedKeys\n }\n}\n"]}
@@ -9,6 +9,7 @@ import { ShareResult } from '../utils/ShareResult';
9
9
  import { MinimalEntityBulkShareResult } from '../../icc-api/model/requests/MinimalEntityBulkShareResult';
10
10
  import { EncryptedFieldsManifest } from '../utils';
11
11
  import { BulkShareOrUpdateMetadataParams } from '../../icc-api/model/requests/BulkShareOrUpdateMetadataParams';
12
+ import { SecretIdUseOption } from './SecretIdUseOption';
12
13
  /**
13
14
  * @internal this interface is meant only for internal use and may be changed without notice.
14
15
  * Gives access to several functions to access encrypted entities metadata.
@@ -93,6 +94,7 @@ export interface ExtendedApisUtils {
93
94
  * @return if the entity has no encryption metadata and can be safely initialised using .
94
95
  */
95
96
  hasEmptyEncryptionMetadata(entity: EncryptedEntity): boolean;
97
+ resolveSecretIdUseOptions(entity: EncryptedEntityWithType, option: SecretIdUseOption): Promise<string[]>;
96
98
  /**
97
99
  * Initializes encryption metadata for an entity. This includes the encrypted secret id, owning entity id, encryption key for the entity, and
98
100
  * the clear text secret foreign key of the parent entity.
@@ -100,7 +102,7 @@ export interface ExtendedApisUtils {
100
102
  * @param entity entity which requires encryption metadata initialisation.
101
103
  * @param entityType type of the entity.
102
104
  * @param owningEntity id of the owning entity, if any (e.g. patient id for Contact/HealtchareElement, message id for Document, ...).
103
- * @param owningEntitySecretId secret id of the parent entity, to use in the secret foreign keys for the provided entity, if any.
105
+ * @param owningEntitySecretIds secret id of the parent entity, to use in the secret foreign keys for the provided entity, if any.
104
106
  * @param initialiseEncryptionKey if false this method will not initialize an encryption key for the entity. Use only for entities which use
105
107
  * delegations for access control but don't actually have any encrypted content.
106
108
  * HealthcareElement).
@@ -108,7 +110,7 @@ export interface ExtendedApisUtils {
108
110
  * @throws if the entity already has non-empty values for encryption metadata.
109
111
  * @return an updated copy of the entity.
110
112
  */
111
- entityWithInitialisedEncryptedMetadata<T extends EncryptedEntity>(entity: T, entityType: EntityWithDelegationTypeName, owningEntity: string | undefined, owningEntitySecretId: string | undefined, initialiseEncryptionKey: boolean, autoDelegations: {
113
+ entityWithInitialisedEncryptedMetadata<T extends EncryptedEntity>(entity: T, entityType: EntityWithDelegationTypeName, owningEntity: string | undefined, owningEntitySecretIds: string[] | undefined, initialiseEncryptionKey: boolean, autoDelegations: {
112
114
  [p: string]: SecureDelegation.AccessLevelEnum;
113
115
  }): Promise<{
114
116
  updatedEntity: T;
@@ -330,4 +332,47 @@ export interface ExtendedApisUtils {
330
332
  }[]) => Promise<{
331
333
  success: T;
332
334
  } | null>): Promise<Map<string, T>>;
335
+ /**
336
+ * 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
337
+ * 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
338
+ * 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.
339
+ * New confidential secret ids will have an appropriate tag, but existing confidential secret ids may not necessarily have it.
340
+ * @param entity an entity which needs to have a confidential secret id for the current data owner
341
+ * @param entityType the type of the entity
342
+ * @param doRequestBulkShareOrUpdate perform the request to share or update an entity encrypted metadata on the cloud API (and save to DB).
343
+ * @return undefined if the entity already had a confidential secret id for the current user, or the updated AND SAVED entity with the new
344
+ * confidential secret id.
345
+ */
346
+ initialiseConfidentialSecretId<T extends EncryptedEntity>(entity: T, entityType: EntityWithDelegationTypeName, doRequestBulkShareOrUpdate: (request: BulkShareOrUpdateMetadataParams) => Promise<EntityBulkShareResult<T>[]>): Promise<T | undefined>;
347
+ /**
348
+ * Get an existing confidential secret id of the provided entity for the provided data owner (current data owner by default). A confidential secret
349
+ * 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.
350
+ * @param entity an entity for which you want to retrieve the confidential secret id.
351
+ * @param dataOwnerId (current data owner by default) a data owner for which you want to get a confidential secret id.
352
+ * @return the confidential secret id or undefined if there is no confidential secret id for the provided data owner.
353
+ */
354
+ getConfidentialSecretId(entity: EncryptedEntityWithType, dataOwnerId?: string): Promise<string | undefined>;
355
+ /**
356
+ * Get all existing confidential secret ids of the provided entity for the provided data owner (current data owner by default). A confidential secret
357
+ * 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.
358
+ * @param entity an entity for which you want to retrieve the confidential secret id.
359
+ * @param dataOwnerId (current data owner by default) a data owner for which you want to get a confidential secret id.
360
+ * @return the confidential secret ids for the data owner (may be empty).
361
+ */
362
+ getConfidentialSecretIds(entity: EncryptedEntityWithType, dataOwnerId?: string): Promise<string[]>;
363
+ /**
364
+ * 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
365
+ * there is no guarantee on which one will be chosen.
366
+ * @param entity an entity.
367
+ * @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
368
+ * for the topmost parent.
369
+ */
370
+ getAnySecretIdSharedWithParents(entity: EncryptedEntityWithType): Promise<string | undefined>;
371
+ /**
372
+ * 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
373
+ * not part of any data owner hierarchy).
374
+ * @param entity an entity.
375
+ * @return all secret ids known by the topmost parent of the current data owner hierarchy, may be empty.
376
+ */
377
+ getSecretIdsSharedWithParents(entity: EncryptedEntityWithType): Promise<string[]>;
333
378
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ExtendedApisUtils.js","sourceRoot":"","sources":["../../../icc-x-api/crypto/ExtendedApisUtils.ts"],"names":[],"mappings":"","sourcesContent":["import { EncryptedEntity, EncryptedEntityStub } from '../../icc-api/model/models'\nimport { EncryptedEntityWithType, EntityWithDelegationTypeName } from '../utils/EntityWithDelegationTypeName'\nimport { SecureDelegation } from '../../icc-api/model/SecureDelegation'\nimport AccessLevelEnum = SecureDelegation.AccessLevelEnum\nimport { EntityShareOrMetadataUpdateRequest } from '../../icc-api/model/requests/EntityShareOrMetadataUpdateRequest'\nimport { EntityShareRequest } from '../../icc-api/model/requests/EntityShareRequest'\nimport { EntityBulkShareResult } from '../../icc-api/model/requests/EntityBulkShareResult'\nimport RequestedPermissionEnum = EntityShareRequest.RequestedPermissionEnum\nimport { ShareMetadataBehaviour } from './ShareMetadataBehaviour'\nimport { ShareResult } from '../utils/ShareResult'\nimport { MinimalEntityBulkShareResult } from '../../icc-api/model/requests/MinimalEntityBulkShareResult'\nimport { EncryptedFieldsManifest } from '../utils'\nimport { BulkShareOrUpdateMetadataParams } from '../../icc-api/model/requests/BulkShareOrUpdateMetadataParams'\n\n/**\n * @internal this interface is meant only for internal use and may be changed without notice.\n * Gives access to several functions to access encrypted entities metadata.\n */\nexport interface ExtendedApisUtils {\n // region metadata decryption\n /**\n * Get the encryption keys of an entity that the provided data owner can access, potentially using the keys for his parent.\n * There should only be one encryption key for each entity, but the method supports more to allow to deal with conflicts and merged duplicate data.\n * @param entity an encrypted entity.\n * @param dataOwnerId optionally a data owner part of the hierarchy for the current data owner, defaults to the current data owner.\n * @return the encryption keys that the provided data owner can decrypt, deduplicated.\n */\n encryptionKeysOf(entity: EncryptedEntityWithType, dataOwnerId: string | undefined): Promise<string[]>\n\n /**\n * Get the encryption keys of an entity that the current data owner and his parents can access. The resulting array contains the keys for each data\n * owner in the hierarchy which can be decrypted using only that data owner keys (excludes keys accessible through the parent keys). The order of\n * the array is the same as in {@link IccDataOwnerXApi.getCurrentDataOwnerHierarchyIds}.\n * Note that different data owners may have access to the same keys, but the keys extracted for each data owner are deduplicated.\n * There should only be one encryption key for each entity, but the method supports more to allow to deal with conflicts and merged duplicate data.\n * @param entity an encrypted entity.\n * @return the encryption keys that each member of the current data owner hierarchy can decrypt using only his keys and not keys of his parents.\n */\n encryptionKeysForHcpHierarchyOf(entity: EncryptedEntityWithType): Promise<{ ownerId: string; extracted: string[] }[]>\n\n /**\n * Get the secret ids (SFKs) of an entity that the provided data owner can access, potentially using the keys for his parent.\n * @param entity an encrypted entity.\n * @param dataOwnerId optionally a data owner part of the hierarchy for the current data owner, defaults to the current data owner.\n * @return the secret ids (SFKs) that the provided data owner can decrypt, deduplicated.\n */\n secretIdsOf(entity: EncryptedEntityWithType, dataOwnerId: string | undefined): Promise<string[]>\n\n /**\n * Get the secret ids (SFKs) of an entity that the current data owner and his parents can access. The resulting array contains the ids for each data\n * owner in the hierarchy which can be decrypted using only that data owner keys (excludes ids accessible through the parent keys). The order of\n * the array is the same as in {@link IccDataOwnerXApi.getCurrentDataOwnerHierarchyIds}.\n * Note that different data owners may have access to the same secret ids, but the secret ids extracted for each data owner are deduplicated.\n * @param entity an encrypted entity.\n * @return the secret ids that each member of the current data owner hierarchy can decrypt using only his keys and not keys of his parents.\n */\n secretIdsForHcpHierarchyOf(entity: EncryptedEntityWithType): Promise<{ ownerId: string; extracted: string[] }[]>\n\n /**\n * Get the decrypted owning entity ids (formerly CFKs) for the provided entity that can be decrypted using the private keys of the current data\n * owner and his parents. The owning entity id would be, for example, the id of a patient for contact and healthcare elements, or the id of a\n * message for documents.\n * There should only be one owning entity id for each entity, but the method supports more to allow to deal with conflicts and merged duplicate\n * data.\n * @param entity an encrypted entity.\n * @param dataOwnerId optionally a data owner part of the hierarchy for the current data owner, defaults to the current data owner.\n * @return the owning entity ids (CFKs) that the provided data owner can decrypt, deduplicated.\n */\n owningEntityIdsOf(entity: EncryptedEntityWithType, dataOwnerId: string | undefined): Promise<string[]>\n\n /**\n * Get the decrypted owning entity ids (formerly CFKs) for the provided entity that can be decrypted using the private keys of the current data\n * owner and his parents. The owning entity id would be, for example, the id of a patient for contact and healthcare elements, or the id of a\n * message for documents.\n * The resulting array contains the ids for each data owner in the hierarchy which can be decrypted using only that data owner keys (excludes ids\n * accessible through the parent keys). The order of the array is the same as in {@link IccDataOwnerXApi.getCurrentDataOwnerHierarchyIds}.\n * Note that different data owners may have access to the same owning entity ids, but the owning entity ids extracted for each data owner are\n * deduplicated in case they could be accessed through different delegations.\n * There should only be one owning entity id for each entity, but the method supports more to allow to deal with conflicts and merged duplicate\n * data.\n * @param entity an encrypted entity.\n * @return the owning entity ids that each member of the current data owner hierarchy can decrypt using only his keys and not keys of his parents.\n */\n owningEntityIdsForHcpHierarchyOf(entity: EncryptedEntityWithType): Promise<{ ownerId: string; extracted: string[] }[]>\n\n /**\n * Get if the current data owner has write access to the content of the entity.\n * @param entity an entity\n * @return if the current data owner (or one of his parents) has write access to the content of the entity.\n */\n hasWriteAccess(entity: EncryptedEntityWithType): Promise<boolean>\n\n /**\n * @param entity an entity\n * @return if the entity has no encryption metadata and can be safely initialised using .\n */\n hasEmptyEncryptionMetadata(entity: EncryptedEntity): boolean\n // endregion\n\n // region metadata initialisation and share\n /**\n * Initializes encryption metadata for an entity. This includes the encrypted secret id, owning entity id, encryption key for the entity, and\n * the clear text secret foreign key of the parent entity.\n * This method returns a modified copy of the entity and DOES NOT SAVE the entity to the cloud/DB: you will have to save the entity manually.\n * @param entity entity which requires encryption metadata initialisation.\n * @param entityType type of the entity.\n * @param owningEntity id of the owning entity, if any (e.g. patient id for Contact/HealtchareElement, message id for Document, ...).\n * @param owningEntitySecretId secret id of the parent entity, to use in the secret foreign keys for the provided entity, if any.\n * @param initialiseEncryptionKey if false this method will not initialize an encryption key for the entity. Use only for entities which use\n * delegations for access control but don't actually have any encrypted content.\n * HealthcareElement).\n * @param autoDelegations automatically shares the metadata with the provided data owners, with the provided access level.\n * @throws if the entity already has non-empty values for encryption metadata.\n * @return an updated copy of the entity.\n */\n entityWithInitialisedEncryptedMetadata<T extends EncryptedEntity>(\n entity: T,\n entityType: EntityWithDelegationTypeName,\n owningEntity: string | undefined,\n owningEntitySecretId: string | undefined,\n initialiseEncryptionKey: boolean,\n autoDelegations: { [p: string]: SecureDelegation.AccessLevelEnum }\n ): Promise<{ updatedEntity: T; rawEncryptionKey: string | undefined; secretId: string | undefined }>\n\n /**\n * Updates encryption metadata for an entity in order to share it with a delegate or in order to add additional encrypted metadata for an existing\n * delegate.\n * The first time this method is used for a specific delegate it will give access to all unencrypted content of the entity to the delegate data\n * owner. Additionally, this method also allows to share new or existing secret ids (shareSecretId), encryption keys (shareEncryptionKeys) and\n * owning entity ids (shareOwningEntityIds) for the entity.\n * You can use methods like {@link secretIdsOf}, {@link secretIdsForHcpHierarchyOf}, {@link encryptionKeysOf}, ... to retrieve the data you want to\n * share. In most cases you may want to share everything related to the entity, but note that if you use confidential delegations for patients you\n * may want to avoid sharing the confidential secret ids of the current user with other hcps.\n * This updates the entity in the cloud/DB (the updated entities in the returned promise are already saved in the DB). NOTE: this method can only\n * be used with entities which already exist in the cloud (the entities must have been saved).\n * @param entitiesType type of entities to update\n * @param entitiesUpdates share/update requests for each entity. An array of objects containing:\n * - The entity to share/update (or at least its encrypted metadata)\n * - The data to share/update for each delegate. An object associating to each delegate id the data to share/update for that delegate, and the\n * permissions requested for the delegate (ignored if the request will only update already existing shared metadata).\n * @param doRequestBulkShareOrUpdate perform the request to share or update an entity encrypted metadata on the cloud API (and save to DB).\n * @throws if there are duplicate entities in the requested updates.\n * @return a promise which will be completed with an object containing:\n * - the updated entities, only for entities were at least one update was successful\n * - information on the individual requests failed, containing the id of the entity, id of the delegate that the request was for, the content,\n * an error code mirroring an http status code, and a human-friendly description of the error (but not necessarily end-user friendly).\n */\n bulkShareOrUpdateEncryptedEntityMetadata<T extends EncryptedEntityStub>(\n entitiesType: EntityWithDelegationTypeName,\n entitiesUpdates: {\n entity: EncryptedEntityStub\n dataForDelegates: {\n [delegateId: string]: {\n shareSecretIds: string[]\n shareEncryptionKeys: string[]\n shareOwningEntityIds: string[]\n requestedPermissions: RequestedPermissionEnum\n }\n }\n }[],\n doRequestBulkShareOrUpdate: (request: BulkShareOrUpdateMetadataParams) => Promise<EntityBulkShareResult<T>[]>\n ): Promise<{\n updatedEntities: T[]\n unmodifiedEntitiesIds: string[]\n updateErrors: {\n entityId: string\n delegateId: string\n request?: {\n shareSecretIds?: string[]\n shareEncryptionKeys?: string[]\n shareOwningEntityIds?: string[]\n requestedPermissions: RequestedPermissionEnum\n }\n updatedForMigration: boolean\n code?: number\n reason?: string\n }[]\n }>\n\n bulkShareOrUpdateEncryptedEntityMetadataNoEntities(\n entitiesType: EntityWithDelegationTypeName,\n entitiesUpdates: {\n entity: EncryptedEntityStub\n dataForDelegates: {\n [delegateId: string]: {\n shareSecretIds: string[]\n shareEncryptionKeys: string[]\n shareOwningEntityIds: string[]\n requestedPermissions: RequestedPermissionEnum\n }\n }\n }[],\n doRequestBulkShareOrUpdate: (request: BulkShareOrUpdateMetadataParams) => Promise<MinimalEntityBulkShareResult[]>\n ): Promise<{\n unmodifiedEntitiesIds: string[]\n successfulUpdates: { entityId: string; delegateId: string }[]\n updateErrors: {\n entityId: string\n delegateId: string\n request?: {\n shareSecretIds?: string[]\n shareEncryptionKeys?: string[]\n shareOwningEntityIds?: string[]\n requestedPermissions: RequestedPermissionEnum\n }\n updatedForMigration: boolean\n code?: number\n reason?: string\n }[]\n }>\n\n /**\n * Simplified version of {@link bulkShareOrUpdateEncryptedEntityMetadata} for a single entity and with automatic retrieval of the encryption keys\n * and owning entity ids if requested. NOTE: this method can only be used with entities which already exist in the cloud (the entity must have\n * been saved).\n * @param entity an entity.\n * versions. If true the method expects `shareSecretIds` options to always be undefined and will always share any available secret ids. If false\n * it expects `shareSecretIds` options to always be defined and will only share the secret ids specified in the options.\n * @param delegates associates the id of data owners which will be granted access to the entity, to the following sharing options:\n * - shareEncryptionKeys specifies if the encryption keys of the entity should be shared. Defaults to\n * {@link ShareMetadataBehaviour.IF_AVAILABLE}.\n * - shareOwningEntityIds specifies if the owning entity ids of the entity should be shared. Defaults to\n * {@link ShareMetadataBehaviour.IF_AVAILABLE}.\n * - shareSecretIds specifies which secret ids of the entity should be shared. Should be defined only if {@link unusedSecretIds} is false.\n * - requestedPermissions requested permissions for the delegate. Defaults to {@link RequestedPermissionEnum.MAX_WRITE}.\n * @param doRequestBulkShareOrUpdate perform the request to share or update an entity encrypted metadata on the cloud API (and save to DB).\n * @return a promise which will be completed with the result of the operation\n * @throws if shareEncryptionKeys or shareOwningEntityIds is {@link ShareMetadataBehaviour.REQUIRED} and the current data owner can't access any\n * value for the required metadata.\n */\n simpleShareOrUpdateEncryptedEntityMetadata<T extends EncryptedEntityStub>(\n entity: { entity: T; type: EntityWithDelegationTypeName },\n delegates: {\n [p: string]: {\n shareSecretIds: string[] | undefined\n shareEncryptionKeys: ShareMetadataBehaviour | undefined\n shareOwningEntityIds: ShareMetadataBehaviour | undefined\n requestedPermissions: EntityShareRequest.RequestedPermissionEnum | undefined\n }\n },\n doRequestBulkShareOrUpdate: (request: BulkShareOrUpdateMetadataParams) => Promise<EntityBulkShareResult<T>[]>\n ): Promise<ShareResult<T>>\n // endregion\n\n // region content encryption and decryption\n /**\n * Encrypts data using a key of the entity that the provided data owner can access (current data owner by default). If the provided data owner can\n * access multiple encryption keys of the entity there is no guarantee on which key will be used.\n * Note: you should not use this method to encrypt the `encryptedSelf` of iCure entities, since that will be automatically handled by the extended\n * apis. You should use this method only to encrypt additional data, such as document attachments.\n * @param entity an entity.\n * @param type type of the entity.\n * @param content data of the entity which you want to encrypt.\n * @param saveEntity a function which saves the entity to the cloud/DB. Used only if a new encryption key needed to be initialised for the entity.\n * @return the encrypted data and, if a new encryption key was initialised for the entity, the updated entity.\n * @throws if the provided data owner can't access any encryption keys for the entity.\n */\n encryptDataOf<T extends EncryptedEntityStub>(\n entity: T,\n type: EntityWithDelegationTypeName,\n content: ArrayBuffer | Uint8Array,\n saveEntity: (entity: T) => Promise<T>\n ): Promise<{ encryptedData: ArrayBuffer; updatedEntity: T | undefined }>\n\n /**\n * Decrypts data using a key of the entity that the provided data owner can access (current data owner by default). If the provided data owner can\n * access multiple encryption keys each of them will be tried for decryption until one of them gives a result that is valid according to the\n * provided validator.\n * Note: you should not use this method to decrypt the `encryptedSelf` of iCure entities, since that will be automatically handled by the extended\n * apis. You should use this method only to decrypt additional data, such as document attachments.\n * @param entity an entity.\n * @param content data of the entity which you want to decrypt.\n * @param validator a function which verifies the correctness of decrypted content: helps to identify decryption with the wrong key without relying\n * solely on padding.\n * @return the decrypted data.\n * @throws if the provided data owner can't access any encryption keys for the entity, or if no key could be found which provided valid decrypted\n * content according to the validator.\n */\n tryDecryptDataOf(\n entity: EncryptedEntityWithType,\n content: ArrayBuffer | Uint8Array,\n validator: (decryptedData: ArrayBuffer) => Promise<boolean> | undefined\n ): Promise<{ data: ArrayBuffer; wasDecrypted: boolean }>\n\n tryDecryptEntities<T extends EncryptedEntity>(\n entities: T[],\n entityType: EntityWithDelegationTypeName,\n constructor: (json: any) => T\n ): Promise<{ entity: T; decrypted: boolean }[]>\n\n /**\n * Tries to decrypt data to a json object using the provided keys.\n */\n tryDecryptJson(potentialKeys: { key: CryptoKey; raw: string }[], encrypted: Uint8Array, truncateTrailingDecryptedNulls: boolean): Promise<{} | null>\n\n /**\n * Tries to encrypt the content of an encrypted entity.\n * 1. If valid key for encryption is found the method returns the entity with the encrypted fields specified by cryptedKeys\n * 2. If requireEncryption is true and no key could be found for encryption of the entity the method fails.\n * 3. If requireEncryption is false and no key could be found for encryption the method will only check that the entity does not specify any value\n * for fields which should be encrypted according to cryptedKeys (e.g. note in a patient using the default configuration). If the entity specifies\n * a value for any field which should be encrypted the method throws an error, otherwise the method returns the original entity.\n */\n tryEncryptEntities<T extends EncryptedEntity>(\n entities: T[],\n entityType: EntityWithDelegationTypeName,\n fieldsToEncrypt: EncryptedFieldsManifest,\n encodeBinaryData: boolean,\n requireEncryption: boolean,\n constructor: (json: any) => T\n ): Promise<T[]>\n\n /**\n * Verifies if the entity has valid encryption keys (regardless of whether the current data owner has access to them or not). If not this method\n * will throw an error, otherwise it will return undefined. For pre-2018 users there are some cases where the data may have been encrypted with a\n * key not safe for encryption anymore, in which case this method will return the entity with a new and safe encryption key.\n * After this method is called, if it returns an entity it should also be re-encrypted (using the new key) and saved to the cloud.\n */\n ensureEncryptionKeysInitialised<T extends EncryptedEntity>(entity: T, entityType: EntityWithDelegationTypeName): Promise<T | undefined>\n\n /**\n * Attempts to do the action providing \"incrementally decrypted\" keys as input; stops the first time the action\n * completes successfully.\n * The method tries to decrypt encryption keys for the entity \"incrementally\", trying first to decrypt keys that\n * require less effort for decryption (e.g. using already cached exchange data or using exchange data for which the\n * id is known without going through the exchange data map). Each time one or more new keys are decrypted the action\n * is called providing ALL keys decrypted up to that point.\n * If no key can be decrypted at all the method returns null without ever attempting the action (the action always\n * receives at least a key in input or is not called).\n * @param entity the entity from which to decrypt the encryption keys.\n * @param entityType the type of entity\n * @param action the action that consumes the encryption key.\n * @return the wrapped result of the first successful action invocation, or null if the action never succeeded or if\n * no key could be decrypted\n */\n doIncrementallyDecryptingKeys<E extends EncryptedEntity | EncryptedEntityStub, T>(\n entity: E,\n entityType: EntityWithDelegationTypeName,\n action: (entity: E, entityType: EntityWithDelegationTypeName, keys: { key: CryptoKey; raw: string }[]) => Promise<{ success: T } | null>\n ): Promise<{ success: T } | null>\n\n /**\n * Bulk version of {@link doIncrementallyDecryptingKeys}.\n * Differences:\n * - The action is called until it succeeds for all entities or until all decryptable keys have been tried.\n * - For each input the action must return an entry for that entity id with the result if successful or not include\n * the entity id in the result keys if unsuccessful.\n * - An attempt on the action is done only if new keys could be decrypted for all the entities.\n * Additionally, there will be a final attempt after attempting all decryption steps if at least a new key could be\n * decrypted for an entity since the last attempt.\n * In this case entities for which no new key could be decrypted are omitted from the input.\n * @param entities\n * @param entitiesType\n * @param action\n * @return all entities id for which the action completed successfully associated to the result.\n */\n doManyIncrementallyDecryptingKeys<E extends EncryptedEntity | EncryptedEntityStub, T>(\n entities: E[],\n entitiesType: EntityWithDelegationTypeName,\n action: (entity: E, entityType: EntityWithDelegationTypeName, keys: { key: CryptoKey; raw: string }[]) => Promise<{ success: T } | null>\n ): Promise<Map<string, T>>\n // endregion\n}\n"]}
1
+ {"version":3,"file":"ExtendedApisUtils.js","sourceRoot":"","sources":["../../../icc-x-api/crypto/ExtendedApisUtils.ts"],"names":[],"mappings":"","sourcesContent":["import { EncryptedEntity, EncryptedEntityStub } from '../../icc-api/model/models'\nimport { EncryptedEntityWithType, EntityWithDelegationTypeName } from '../utils/EntityWithDelegationTypeName'\nimport { SecureDelegation } from '../../icc-api/model/SecureDelegation'\nimport AccessLevelEnum = SecureDelegation.AccessLevelEnum\nimport { EntityShareOrMetadataUpdateRequest } from '../../icc-api/model/requests/EntityShareOrMetadataUpdateRequest'\nimport { EntityShareRequest } from '../../icc-api/model/requests/EntityShareRequest'\nimport { EntityBulkShareResult } from '../../icc-api/model/requests/EntityBulkShareResult'\nimport RequestedPermissionEnum = EntityShareRequest.RequestedPermissionEnum\nimport { ShareMetadataBehaviour } from './ShareMetadataBehaviour'\nimport { ShareResult } from '../utils/ShareResult'\nimport { MinimalEntityBulkShareResult } from '../../icc-api/model/requests/MinimalEntityBulkShareResult'\nimport { EncryptedFieldsManifest } from '../utils'\nimport { BulkShareOrUpdateMetadataParams } from '../../icc-api/model/requests/BulkShareOrUpdateMetadataParams'\nimport { SecretIdUseOption } from './SecretIdUseOption'\n\n/**\n * @internal this interface is meant only for internal use and may be changed without notice.\n * Gives access to several functions to access encrypted entities metadata.\n */\nexport interface ExtendedApisUtils {\n // region metadata decryption\n /**\n * Get the encryption keys of an entity that the provided data owner can access, potentially using the keys for his parent.\n * There should only be one encryption key for each entity, but the method supports more to allow to deal with conflicts and merged duplicate data.\n * @param entity an encrypted entity.\n * @param dataOwnerId optionally a data owner part of the hierarchy for the current data owner, defaults to the current data owner.\n * @return the encryption keys that the provided data owner can decrypt, deduplicated.\n */\n encryptionKeysOf(entity: EncryptedEntityWithType, dataOwnerId: string | undefined): Promise<string[]>\n\n /**\n * Get the encryption keys of an entity that the current data owner and his parents can access. The resulting array contains the keys for each data\n * owner in the hierarchy which can be decrypted using only that data owner keys (excludes keys accessible through the parent keys). The order of\n * the array is the same as in {@link IccDataOwnerXApi.getCurrentDataOwnerHierarchyIds}.\n * Note that different data owners may have access to the same keys, but the keys extracted for each data owner are deduplicated.\n * There should only be one encryption key for each entity, but the method supports more to allow to deal with conflicts and merged duplicate data.\n * @param entity an encrypted entity.\n * @return the encryption keys that each member of the current data owner hierarchy can decrypt using only his keys and not keys of his parents.\n */\n encryptionKeysForHcpHierarchyOf(entity: EncryptedEntityWithType): Promise<{ ownerId: string; extracted: string[] }[]>\n\n /**\n * Get the secret ids (SFKs) of an entity that the provided data owner can access, potentially using the keys for his parent.\n * @param entity an encrypted entity.\n * @param dataOwnerId optionally a data owner part of the hierarchy for the current data owner, defaults to the current data owner.\n * @return the secret ids (SFKs) that the provided data owner can decrypt, deduplicated.\n */\n secretIdsOf(entity: EncryptedEntityWithType, dataOwnerId: string | undefined): Promise<string[]>\n\n /**\n * Get the secret ids (SFKs) of an entity that the current data owner and his parents can access. The resulting array contains the ids for each data\n * owner in the hierarchy which can be decrypted using only that data owner keys (excludes ids accessible through the parent keys). The order of\n * the array is the same as in {@link IccDataOwnerXApi.getCurrentDataOwnerHierarchyIds}.\n * Note that different data owners may have access to the same secret ids, but the secret ids extracted for each data owner are deduplicated.\n * @param entity an encrypted entity.\n * @return the secret ids that each member of the current data owner hierarchy can decrypt using only his keys and not keys of his parents.\n */\n secretIdsForHcpHierarchyOf(entity: EncryptedEntityWithType): Promise<{ ownerId: string; extracted: string[] }[]>\n\n /**\n * Get the decrypted owning entity ids (formerly CFKs) for the provided entity that can be decrypted using the private keys of the current data\n * owner and his parents. The owning entity id would be, for example, the id of a patient for contact and healthcare elements, or the id of a\n * message for documents.\n * There should only be one owning entity id for each entity, but the method supports more to allow to deal with conflicts and merged duplicate\n * data.\n * @param entity an encrypted entity.\n * @param dataOwnerId optionally a data owner part of the hierarchy for the current data owner, defaults to the current data owner.\n * @return the owning entity ids (CFKs) that the provided data owner can decrypt, deduplicated.\n */\n owningEntityIdsOf(entity: EncryptedEntityWithType, dataOwnerId: string | undefined): Promise<string[]>\n\n /**\n * Get the decrypted owning entity ids (formerly CFKs) for the provided entity that can be decrypted using the private keys of the current data\n * owner and his parents. The owning entity id would be, for example, the id of a patient for contact and healthcare elements, or the id of a\n * message for documents.\n * The resulting array contains the ids for each data owner in the hierarchy which can be decrypted using only that data owner keys (excludes ids\n * accessible through the parent keys). The order of the array is the same as in {@link IccDataOwnerXApi.getCurrentDataOwnerHierarchyIds}.\n * Note that different data owners may have access to the same owning entity ids, but the owning entity ids extracted for each data owner are\n * deduplicated in case they could be accessed through different delegations.\n * There should only be one owning entity id for each entity, but the method supports more to allow to deal with conflicts and merged duplicate\n * data.\n * @param entity an encrypted entity.\n * @return the owning entity ids that each member of the current data owner hierarchy can decrypt using only his keys and not keys of his parents.\n */\n owningEntityIdsForHcpHierarchyOf(entity: EncryptedEntityWithType): Promise<{ ownerId: string; extracted: string[] }[]>\n\n /**\n * Get if the current data owner has write access to the content of the entity.\n * @param entity an entity\n * @return if the current data owner (or one of his parents) has write access to the content of the entity.\n */\n hasWriteAccess(entity: EncryptedEntityWithType): Promise<boolean>\n\n /**\n * @param entity an entity\n * @return if the entity has no encryption metadata and can be safely initialised using .\n */\n hasEmptyEncryptionMetadata(entity: EncryptedEntity): boolean\n // endregion\n\n // region metadata initialisation and share\n resolveSecretIdUseOptions(entity: EncryptedEntityWithType, option: SecretIdUseOption): Promise<string[]>\n\n /**\n * Initializes encryption metadata for an entity. This includes the encrypted secret id, owning entity id, encryption key for the entity, and\n * the clear text secret foreign key of the parent entity.\n * This method returns a modified copy of the entity and DOES NOT SAVE the entity to the cloud/DB: you will have to save the entity manually.\n * @param entity entity which requires encryption metadata initialisation.\n * @param entityType type of the entity.\n * @param owningEntity id of the owning entity, if any (e.g. patient id for Contact/HealtchareElement, message id for Document, ...).\n * @param owningEntitySecretIds secret id of the parent entity, to use in the secret foreign keys for the provided entity, if any.\n * @param initialiseEncryptionKey if false this method will not initialize an encryption key for the entity. Use only for entities which use\n * delegations for access control but don't actually have any encrypted content.\n * HealthcareElement).\n * @param autoDelegations automatically shares the metadata with the provided data owners, with the provided access level.\n * @throws if the entity already has non-empty values for encryption metadata.\n * @return an updated copy of the entity.\n */\n entityWithInitialisedEncryptedMetadata<T extends EncryptedEntity>(\n entity: T,\n entityType: EntityWithDelegationTypeName,\n owningEntity: string | undefined,\n owningEntitySecretIds: string[] | undefined,\n initialiseEncryptionKey: boolean,\n autoDelegations: { [p: string]: SecureDelegation.AccessLevelEnum }\n ): Promise<{ updatedEntity: T; rawEncryptionKey: string | undefined; secretId: string | undefined }>\n\n /**\n * Updates encryption metadata for an entity in order to share it with a delegate or in order to add additional encrypted metadata for an existing\n * delegate.\n * The first time this method is used for a specific delegate it will give access to all unencrypted content of the entity to the delegate data\n * owner. Additionally, this method also allows to share new or existing secret ids (shareSecretId), encryption keys (shareEncryptionKeys) and\n * owning entity ids (shareOwningEntityIds) for the entity.\n * You can use methods like {@link secretIdsOf}, {@link secretIdsForHcpHierarchyOf}, {@link encryptionKeysOf}, ... to retrieve the data you want to\n * share. In most cases you may want to share everything related to the entity, but note that if you use confidential delegations for patients you\n * may want to avoid sharing the confidential secret ids of the current user with other hcps.\n * This updates the entity in the cloud/DB (the updated entities in the returned promise are already saved in the DB). NOTE: this method can only\n * be used with entities which already exist in the cloud (the entities must have been saved).\n * @param entitiesType type of entities to update\n * @param entitiesUpdates share/update requests for each entity. An array of objects containing:\n * - The entity to share/update (or at least its encrypted metadata)\n * - The data to share/update for each delegate. An object associating to each delegate id the data to share/update for that delegate, and the\n * permissions requested for the delegate (ignored if the request will only update already existing shared metadata).\n * @param doRequestBulkShareOrUpdate perform the request to share or update an entity encrypted metadata on the cloud API (and save to DB).\n * @throws if there are duplicate entities in the requested updates.\n * @return a promise which will be completed with an object containing:\n * - the updated entities, only for entities were at least one update was successful\n * - information on the individual requests failed, containing the id of the entity, id of the delegate that the request was for, the content,\n * an error code mirroring an http status code, and a human-friendly description of the error (but not necessarily end-user friendly).\n */\n bulkShareOrUpdateEncryptedEntityMetadata<T extends EncryptedEntityStub>(\n entitiesType: EntityWithDelegationTypeName,\n entitiesUpdates: {\n entity: EncryptedEntityStub\n dataForDelegates: {\n [delegateId: string]: {\n shareSecretIds: string[]\n shareEncryptionKeys: string[]\n shareOwningEntityIds: string[]\n requestedPermissions: RequestedPermissionEnum\n }\n }\n }[],\n doRequestBulkShareOrUpdate: (request: BulkShareOrUpdateMetadataParams) => Promise<EntityBulkShareResult<T>[]>\n ): Promise<{\n updatedEntities: T[]\n unmodifiedEntitiesIds: string[]\n updateErrors: {\n entityId: string\n delegateId: string\n request?: {\n shareSecretIds?: string[]\n shareEncryptionKeys?: string[]\n shareOwningEntityIds?: string[]\n requestedPermissions: RequestedPermissionEnum\n }\n updatedForMigration: boolean\n code?: number\n reason?: string\n }[]\n }>\n\n bulkShareOrUpdateEncryptedEntityMetadataNoEntities(\n entitiesType: EntityWithDelegationTypeName,\n entitiesUpdates: {\n entity: EncryptedEntityStub\n dataForDelegates: {\n [delegateId: string]: {\n shareSecretIds: string[]\n shareEncryptionKeys: string[]\n shareOwningEntityIds: string[]\n requestedPermissions: RequestedPermissionEnum\n }\n }\n }[],\n doRequestBulkShareOrUpdate: (request: BulkShareOrUpdateMetadataParams) => Promise<MinimalEntityBulkShareResult[]>\n ): Promise<{\n unmodifiedEntitiesIds: string[]\n successfulUpdates: { entityId: string; delegateId: string }[]\n updateErrors: {\n entityId: string\n delegateId: string\n request?: {\n shareSecretIds?: string[]\n shareEncryptionKeys?: string[]\n shareOwningEntityIds?: string[]\n requestedPermissions: RequestedPermissionEnum\n }\n updatedForMigration: boolean\n code?: number\n reason?: string\n }[]\n }>\n\n /**\n * Simplified version of {@link bulkShareOrUpdateEncryptedEntityMetadata} for a single entity and with automatic retrieval of the encryption keys\n * and owning entity ids if requested. NOTE: this method can only be used with entities which already exist in the cloud (the entity must have\n * been saved).\n * @param entity an entity.\n * versions. If true the method expects `shareSecretIds` options to always be undefined and will always share any available secret ids. If false\n * it expects `shareSecretIds` options to always be defined and will only share the secret ids specified in the options.\n * @param delegates associates the id of data owners which will be granted access to the entity, to the following sharing options:\n * - shareEncryptionKeys specifies if the encryption keys of the entity should be shared. Defaults to\n * {@link ShareMetadataBehaviour.IF_AVAILABLE}.\n * - shareOwningEntityIds specifies if the owning entity ids of the entity should be shared. Defaults to\n * {@link ShareMetadataBehaviour.IF_AVAILABLE}.\n * - shareSecretIds specifies which secret ids of the entity should be shared. Should be defined only if {@link unusedSecretIds} is false.\n * - requestedPermissions requested permissions for the delegate. Defaults to {@link RequestedPermissionEnum.MAX_WRITE}.\n * @param doRequestBulkShareOrUpdate perform the request to share or update an entity encrypted metadata on the cloud API (and save to DB).\n * @return a promise which will be completed with the result of the operation\n * @throws if shareEncryptionKeys or shareOwningEntityIds is {@link ShareMetadataBehaviour.REQUIRED} and the current data owner can't access any\n * value for the required metadata.\n */\n simpleShareOrUpdateEncryptedEntityMetadata<T extends EncryptedEntityStub>(\n entity: { entity: T; type: EntityWithDelegationTypeName },\n delegates: {\n [p: string]: {\n shareSecretIds: string[] | undefined\n shareEncryptionKeys: ShareMetadataBehaviour | undefined\n shareOwningEntityIds: ShareMetadataBehaviour | undefined\n requestedPermissions: EntityShareRequest.RequestedPermissionEnum | undefined\n }\n },\n doRequestBulkShareOrUpdate: (request: BulkShareOrUpdateMetadataParams) => Promise<EntityBulkShareResult<T>[]>\n ): Promise<ShareResult<T>>\n // endregion\n\n // region content encryption and decryption\n /**\n * Encrypts data using a key of the entity that the provided data owner can access (current data owner by default). If the provided data owner can\n * access multiple encryption keys of the entity there is no guarantee on which key will be used.\n * Note: you should not use this method to encrypt the `encryptedSelf` of iCure entities, since that will be automatically handled by the extended\n * apis. You should use this method only to encrypt additional data, such as document attachments.\n * @param entity an entity.\n * @param type type of the entity.\n * @param content data of the entity which you want to encrypt.\n * @param saveEntity a function which saves the entity to the cloud/DB. Used only if a new encryption key needed to be initialised for the entity.\n * @return the encrypted data and, if a new encryption key was initialised for the entity, the updated entity.\n * @throws if the provided data owner can't access any encryption keys for the entity.\n */\n encryptDataOf<T extends EncryptedEntityStub>(\n entity: T,\n type: EntityWithDelegationTypeName,\n content: ArrayBuffer | Uint8Array,\n saveEntity: (entity: T) => Promise<T>\n ): Promise<{ encryptedData: ArrayBuffer; updatedEntity: T | undefined }>\n\n /**\n * Decrypts data using a key of the entity that the provided data owner can access (current data owner by default). If the provided data owner can\n * access multiple encryption keys each of them will be tried for decryption until one of them gives a result that is valid according to the\n * provided validator.\n * Note: you should not use this method to decrypt the `encryptedSelf` of iCure entities, since that will be automatically handled by the extended\n * apis. You should use this method only to decrypt additional data, such as document attachments.\n * @param entity an entity.\n * @param content data of the entity which you want to decrypt.\n * @param validator a function which verifies the correctness of decrypted content: helps to identify decryption with the wrong key without relying\n * solely on padding.\n * @return the decrypted data.\n * @throws if the provided data owner can't access any encryption keys for the entity, or if no key could be found which provided valid decrypted\n * content according to the validator.\n */\n tryDecryptDataOf(\n entity: EncryptedEntityWithType,\n content: ArrayBuffer | Uint8Array,\n validator: (decryptedData: ArrayBuffer) => Promise<boolean> | undefined\n ): Promise<{ data: ArrayBuffer; wasDecrypted: boolean }>\n\n tryDecryptEntities<T extends EncryptedEntity>(\n entities: T[],\n entityType: EntityWithDelegationTypeName,\n constructor: (json: any) => T\n ): Promise<{ entity: T; decrypted: boolean }[]>\n\n /**\n * Tries to decrypt data to a json object using the provided keys.\n */\n tryDecryptJson(potentialKeys: { key: CryptoKey; raw: string }[], encrypted: Uint8Array, truncateTrailingDecryptedNulls: boolean): Promise<{} | null>\n\n /**\n * Tries to encrypt the content of an encrypted entity.\n * 1. If valid key for encryption is found the method returns the entity with the encrypted fields specified by cryptedKeys\n * 2. If requireEncryption is true and no key could be found for encryption of the entity the method fails.\n * 3. If requireEncryption is false and no key could be found for encryption the method will only check that the entity does not specify any value\n * for fields which should be encrypted according to cryptedKeys (e.g. note in a patient using the default configuration). If the entity specifies\n * a value for any field which should be encrypted the method throws an error, otherwise the method returns the original entity.\n */\n tryEncryptEntities<T extends EncryptedEntity>(\n entities: T[],\n entityType: EntityWithDelegationTypeName,\n fieldsToEncrypt: EncryptedFieldsManifest,\n encodeBinaryData: boolean,\n requireEncryption: boolean,\n constructor: (json: any) => T\n ): Promise<T[]>\n\n /**\n * Verifies if the entity has valid encryption keys (regardless of whether the current data owner has access to them or not). If not this method\n * will throw an error, otherwise it will return undefined. For pre-2018 users there are some cases where the data may have been encrypted with a\n * key not safe for encryption anymore, in which case this method will return the entity with a new and safe encryption key.\n * After this method is called, if it returns an entity it should also be re-encrypted (using the new key) and saved to the cloud.\n */\n ensureEncryptionKeysInitialised<T extends EncryptedEntity>(entity: T, entityType: EntityWithDelegationTypeName): Promise<T | undefined>\n\n /**\n * Attempts to do the action providing \"incrementally decrypted\" keys as input; stops the first time the action\n * completes successfully.\n * The method tries to decrypt encryption keys for the entity \"incrementally\", trying first to decrypt keys that\n * require less effort for decryption (e.g. using already cached exchange data or using exchange data for which the\n * id is known without going through the exchange data map). Each time one or more new keys are decrypted the action\n * is called providing ALL keys decrypted up to that point.\n * If no key can be decrypted at all the method returns null without ever attempting the action (the action always\n * receives at least a key in input or is not called).\n * @param entity the entity from which to decrypt the encryption keys.\n * @param entityType the type of entity\n * @param action the action that consumes the encryption key.\n * @return the wrapped result of the first successful action invocation, or null if the action never succeeded or if\n * no key could be decrypted\n */\n doIncrementallyDecryptingKeys<E extends EncryptedEntity | EncryptedEntityStub, T>(\n entity: E,\n entityType: EntityWithDelegationTypeName,\n action: (entity: E, entityType: EntityWithDelegationTypeName, keys: { key: CryptoKey; raw: string }[]) => Promise<{ success: T } | null>\n ): Promise<{ success: T } | null>\n\n /**\n * Bulk version of {@link doIncrementallyDecryptingKeys}.\n * Differences:\n * - The action is called until it succeeds for all entities or until all decryptable keys have been tried.\n * - For each input the action must return an entry for that entity id with the result if successful or not include\n * the entity id in the result keys if unsuccessful.\n * - An attempt on the action is done only if new keys could be decrypted for all the entities.\n * Additionally, there will be a final attempt after attempting all decryption steps if at least a new key could be\n * decrypted for an entity since the last attempt.\n * In this case entities for which no new key could be decrypted are omitted from the input.\n * @param entities\n * @param entitiesType\n * @param action\n * @return all entities id for which the action completed successfully associated to the result.\n */\n doManyIncrementallyDecryptingKeys<E extends EncryptedEntity | EncryptedEntityStub, T>(\n entities: E[],\n entitiesType: EntityWithDelegationTypeName,\n action: (entity: E, entityType: EntityWithDelegationTypeName, keys: { key: CryptoKey; raw: string }[]) => Promise<{ success: T } | null>\n ): Promise<Map<string, T>>\n // endregion\n\n // region confidential ids\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 * @param entityType the type of the entity\n * @param doRequestBulkShareOrUpdate perform the request to share or update an entity encrypted metadata on the cloud API (and save to DB).\n * @return undefined if the entity already had a confidential secret id for the current user, or the updated AND SAVED entity with the new\n * confidential secret id.\n */\n initialiseConfidentialSecretId<T extends EncryptedEntity>(\n entity: T,\n entityType: EntityWithDelegationTypeName,\n doRequestBulkShareOrUpdate: (request: BulkShareOrUpdateMetadataParams) => Promise<EntityBulkShareResult<T>[]>\n ): Promise<T | undefined>\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 getConfidentialSecretId(entity: EncryptedEntityWithType, dataOwnerId?: string): Promise<string | undefined>\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 getConfidentialSecretIds(entity: EncryptedEntityWithType, dataOwnerId?: string): Promise<string[]>\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 getAnySecretIdSharedWithParents(entity: EncryptedEntityWithType): Promise<string | undefined>\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 getSecretIdsSharedWithParents(entity: EncryptedEntityWithType): Promise<string[]>\n // endregion\n}\n"]}
@@ -14,6 +14,7 @@ import { IccUserXApi } from '../icc-user-x-api';
14
14
  import { MinimalEntityBulkShareResult } from '../../icc-api/model/requests/MinimalEntityBulkShareResult';
15
15
  import { BulkShareOrUpdateMetadataParams } from '../../icc-api/model/requests/BulkShareOrUpdateMetadataParams';
16
16
  import RequestedPermissionEnum = EntityShareRequest.RequestedPermissionEnum;
17
+ import { SecretIdUseOption } from './SecretIdUseOption';
17
18
  /**
18
19
  * @internal this class is for internal use only and may be changed without notice.
19
20
  * Methods to support extended apis.
@@ -42,7 +43,7 @@ export declare class ExtendedApisUtilsImpl implements ExtendedApisUtils {
42
43
  extracted: string[];
43
44
  }[]>;
44
45
  hasWriteAccess(entity: EncryptedEntityWithType): Promise<boolean>;
45
- entityWithInitialisedEncryptedMetadata<T extends EncryptedEntity>(entity: T, entityType: EntityWithDelegationTypeName, owningEntity: string | undefined, owningEntitySecretId: string | undefined, initialiseEncryptionKey: boolean, autoDelegations: {
46
+ entityWithInitialisedEncryptedMetadata<T extends EncryptedEntity>(entity: T, entityType: EntityWithDelegationTypeName, owningEntity: string | undefined, owningEntitySecretIds: string[] | undefined, initialiseEncryptionKey: boolean, autoDelegations: {
46
47
  [p: string]: SecureDelegation.AccessLevelEnum;
47
48
  }): Promise<{
48
49
  updatedEntity: T;
@@ -160,4 +161,10 @@ export declare class ExtendedApisUtilsImpl implements ExtendedApisUtils {
160
161
  private checkEmptyEncryptionMetadata;
161
162
  hasEmptyEncryptionMetadata(entity: EncryptedEntity): boolean;
162
163
  private doCheckEmptyEncryptionMetadata;
164
+ initialiseConfidentialSecretId<T extends EncryptedEntity>(entity: T, entityType: EntityWithDelegationTypeName, doRequestBulkShareOrUpdate: (request: BulkShareOrUpdateMetadataParams) => Promise<EntityBulkShareResult<T>[]>): Promise<T | undefined>;
165
+ getConfidentialSecretId(entity: EncryptedEntityWithType, dataOwnerId?: string): Promise<string | undefined>;
166
+ getConfidentialSecretIds(entity: EncryptedEntityWithType, dataOwnerId?: string): Promise<string[]>;
167
+ getAnySecretIdSharedWithParents(entity: EncryptedEntityWithType): Promise<string | undefined>;
168
+ getSecretIdsSharedWithParents(entity: EncryptedEntityWithType): Promise<string[]>;
169
+ resolveSecretIdUseOptions(entity: EncryptedEntityWithType, option: SecretIdUseOption): Promise<string[]>;
163
170
  }
@@ -20,6 +20,7 @@ var AccessLevel = SecureDelegation_1.SecureDelegation.AccessLevelEnum;
20
20
  var RequestedPermissionEnum = EntityShareRequest_1.EntityShareRequest.RequestedPermissionEnum;
21
21
  var RequestedPermissionInternal = EntityShareRequest_1.EntityShareRequest.RequestedPermissionInternal;
22
22
  var AccessLevelEnum = SecureDelegation_1.SecureDelegation.AccessLevelEnum;
23
+ const SecretIdUseOption_1 = require("./SecretIdUseOption");
23
24
  /**
24
25
  * @internal this class is for internal use only and may be changed without notice.
25
26
  * Methods to support extended apis.
@@ -69,14 +70,14 @@ class ExtendedApisUtilsImpl {
69
70
  AccessLevel.WRITE);
70
71
  });
71
72
  }
72
- entityWithInitialisedEncryptedMetadata(entity, entityType, owningEntity, owningEntitySecretId, initialiseEncryptionKey, autoDelegations) {
73
+ entityWithInitialisedEncryptedMetadata(entity, entityType, owningEntity, owningEntitySecretIds, initialiseEncryptionKey, autoDelegations) {
73
74
  return __awaiter(this, arguments, void 0, function* () {
74
75
  this.throwDetailedExceptionForInvalidParameter('entity.id', entity.id, 'entityWithInitialisedEncryptedMetadata', arguments);
75
76
  this.checkEmptyEncryptionMetadata(entity);
76
77
  const newRawKey = initialiseEncryptionKey ? yield this.primitives.AES.generateCryptoKey(true) : undefined;
77
78
  const newSecretId = this.primitives.randomUuid();
78
79
  return {
79
- updatedEntity: yield this.secureDelegationsManager.entityWithInitialisedEncryptedMetadata(Object.assign(Object.assign({}, entity), { secretForeignKeys: owningEntitySecretId ? [owningEntitySecretId] : [] }), entityType, newSecretId ? [newSecretId] : [], !!owningEntity ? [owningEntity] : [], newRawKey ? [newRawKey] : [], autoDelegations),
80
+ updatedEntity: yield this.secureDelegationsManager.entityWithInitialisedEncryptedMetadata(Object.assign(Object.assign({}, entity), { secretForeignKeys: owningEntitySecretIds !== null && owningEntitySecretIds !== void 0 ? owningEntitySecretIds : [] }), entityType, newSecretId ? [newSecretId] : [], !!owningEntity ? [owningEntity] : [], newRawKey ? [newRawKey] : [], autoDelegations),
80
81
  rawEncryptionKey: newRawKey,
81
82
  secretId: newSecretId,
82
83
  };
@@ -644,6 +645,84 @@ class ExtendedApisUtilsImpl {
644
645
  }
645
646
  return true;
646
647
  }
648
+ initialiseConfidentialSecretId(entity, entityType, doRequestBulkShareOrUpdate) {
649
+ return __awaiter(this, void 0, void 0, function* () {
650
+ if (yield this.getConfidentialSecretId({ entity, type: entityType }))
651
+ return undefined;
652
+ const confidentialSecretId = this.primitives.randomUuid();
653
+ return (yield this.simpleShareOrUpdateEncryptedEntityMetadata({ entity, type: entityType }, {
654
+ [yield this.dataOwnerApi.getCurrentDataOwnerId()]: {
655
+ shareEncryptionKeys: ShareMetadataBehaviour_1.ShareMetadataBehaviour.NEVER,
656
+ shareOwningEntityIds: ShareMetadataBehaviour_1.ShareMetadataBehaviour.NEVER,
657
+ shareSecretIds: [confidentialSecretId],
658
+ requestedPermissions: RequestedPermissionEnum.MAX_WRITE,
659
+ },
660
+ }, (request) => doRequestBulkShareOrUpdate(request))).updatedEntityOrThrow;
661
+ });
662
+ }
663
+ getConfidentialSecretId(entity, dataOwnerId) {
664
+ return __awaiter(this, void 0, void 0, function* () {
665
+ return this.getConfidentialSecretIds(entity, dataOwnerId).then((x) => x[0]);
666
+ });
667
+ }
668
+ getConfidentialSecretIds(entity, dataOwnerId) {
669
+ return __awaiter(this, void 0, void 0, function* () {
670
+ const chosenDataOwnerId = dataOwnerId !== null && dataOwnerId !== void 0 ? dataOwnerId : (yield this.dataOwnerApi.getCurrentDataOwnerId());
671
+ const dataOwnerHierarchy = yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIdsFrom(chosenDataOwnerId);
672
+ const hierarchySecretIds = (yield this.secretIdsForHcpHierarchyOf(entity)).filter((x) => dataOwnerHierarchy.includes(x.ownerId));
673
+ const keysForDataOwner = hierarchySecretIds.find((x) => x.ownerId === chosenDataOwnerId);
674
+ if (!keysForDataOwner)
675
+ return [];
676
+ return keysForDataOwner.extracted.filter((k) => !hierarchySecretIds.some((x) => x.ownerId !== chosenDataOwnerId && x.extracted.includes(k)));
677
+ });
678
+ }
679
+ getAnySecretIdSharedWithParents(entity) {
680
+ return __awaiter(this, void 0, void 0, function* () {
681
+ return (yield this.getSecretIdsSharedWithParents(entity))[0];
682
+ });
683
+ }
684
+ getSecretIdsSharedWithParents(entity) {
685
+ return __awaiter(this, void 0, void 0, function* () {
686
+ return (yield this.secretIdsForHcpHierarchyOf(entity))[0].extracted;
687
+ });
688
+ }
689
+ resolveSecretIdUseOptions(entity, option) {
690
+ return __awaiter(this, void 0, void 0, function* () {
691
+ if (option == SecretIdUseOption_1.SecretIdUseOption.UseNone) {
692
+ return [];
693
+ }
694
+ else if (option == SecretIdUseOption_1.SecretIdUseOption.UseAnyConfidential) {
695
+ const all = yield this.getConfidentialSecretIds(entity, undefined);
696
+ if (all.length == 0)
697
+ throw new Error("Couldn't find any confidential secret id");
698
+ return [all[0]];
699
+ }
700
+ else if (option == SecretIdUseOption_1.SecretIdUseOption.UseAllConfidential) {
701
+ const all = yield this.getConfidentialSecretIds(entity, undefined);
702
+ if (all.length == 0)
703
+ throw new Error("Couldn't find any confidential secret id");
704
+ return all;
705
+ }
706
+ else if (option == SecretIdUseOption_1.SecretIdUseOption.UseAnySharedWithParent) {
707
+ const all = yield this.getSecretIdsSharedWithParents(entity);
708
+ if (all.length == 0)
709
+ throw new Error("Couldn't find any secret id shared with parent");
710
+ return [all[0]];
711
+ }
712
+ else if (option == SecretIdUseOption_1.SecretIdUseOption.UseAllSharedWithParent) {
713
+ const all = yield this.getSecretIdsSharedWithParents(entity);
714
+ if (all.length == 0)
715
+ throw new Error("Couldn't find any secret id shared with parent");
716
+ return all;
717
+ }
718
+ else if (option instanceof SecretIdUseOption_1.SecretIdUseOption.Use) {
719
+ return [...new Set(option.secretIds)];
720
+ }
721
+ else {
722
+ throw new Error(`Unrecognized SecretIdUseOption ${option}`);
723
+ }
724
+ });
725
+ }
647
726
  }
648
727
  exports.ExtendedApisUtilsImpl = ExtendedApisUtilsImpl;
649
728
  //# sourceMappingURL=ExtendedApisUtilsImpl.js.map