passbolt-browser-extension 5.3.2 → 5.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/CHANGELOG.md +58 -1
  2. package/README.md +2 -2
  3. package/RELEASE_NOTES.md +8 -30
  4. package/crowdin.yml +1 -0
  5. package/package.json +4 -3
  6. package/src/all/_locales/cs/messages.json +10 -0
  7. package/src/all/background_page/controller/InformMenuController/InformMenuController.js +3 -3
  8. package/src/all/background_page/controller/auth/redirectPostLoginController.js +57 -0
  9. package/src/all/background_page/controller/auth/redirectPostLoginController.test.js +82 -0
  10. package/src/all/background_page/controller/auth/redirectToAdminWorkspaceController.js +50 -0
  11. package/src/all/background_page/controller/auth/redirectToAdminWorkspaceController.test.js +45 -0
  12. package/src/all/background_page/controller/comment/createCommentController.js +3 -3
  13. package/src/all/background_page/controller/comment/createCommentController.test.js +5 -5
  14. package/src/all/background_page/controller/comment/deleteCommentController.js +3 -3
  15. package/src/all/background_page/controller/comment/deleteCommentController.test.js +3 -3
  16. package/src/all/background_page/controller/comment/getCommentsByRessourceIdController.js +3 -3
  17. package/src/all/background_page/controller/comment/getCommentsByRessourceidController.test.js +2 -2
  18. package/src/all/background_page/controller/import/importResourcesFileController.test.js +23 -23
  19. package/src/all/background_page/controller/metadata/enableEncryptedMetadataForExistingInstanceController.js +54 -0
  20. package/src/all/background_page/controller/metadata/enableEncryptedMetadataForExistingInstanceController.test.js +54 -0
  21. package/src/all/background_page/controller/metadata/enableMetadataSetupSettingsController.js +54 -0
  22. package/src/all/background_page/controller/metadata/enableMetadataSetupSettingsController.test.js +64 -0
  23. package/src/all/background_page/controller/metadata/findAllNonDeletedMetadataKeysController.js +2 -3
  24. package/src/all/background_page/controller/metadata/findMetadataGettingStartedSettingsController.js +50 -0
  25. package/src/all/background_page/controller/metadata/findMetadataGettingStartedSettingsController.test.js +33 -0
  26. package/src/all/background_page/controller/metadata/findMetadataSetupSettingsController.js +50 -0
  27. package/src/all/background_page/controller/metadata/findMetadataSetupSettingsController.test.js +42 -0
  28. package/src/all/background_page/controller/metadata/keepCleartextMetadataForExistingInstanceController.js +51 -0
  29. package/src/all/background_page/controller/metadata/keepCleartextMetadataForExistingInstanceController.test.js +47 -0
  30. package/src/all/background_page/controller/permission/FindAcoPermissionsForDisplayController.js +1 -0
  31. package/src/all/background_page/controller/quickaccess/consumeInProgressCreationResourceController.js +53 -0
  32. package/src/all/background_page/controller/quickaccess/consumeInProgressCreationResourceController.test.js +40 -0
  33. package/src/all/background_page/controller/quickaccess/prepareResourceController.js +64 -0
  34. package/src/all/background_page/controller/quickaccess/prepareResourceController.test.js +73 -0
  35. package/src/all/background_page/controller/resource/resourceDeleteController.js +67 -0
  36. package/src/all/background_page/controller/resource/resourceDeleteController.test.js +114 -0
  37. package/src/all/background_page/controller/resourceLocalStorage/resourceUpdateLocalStorageController.js +1 -1
  38. package/src/all/background_page/controller/resourceLocalStorage/resourceUpdateLocalStorageController.test.js +5 -1
  39. package/src/all/background_page/controller/setup/signInSetupController.js +0 -10
  40. package/src/all/background_page/controller/setup/signInSetupController.test.js +11 -12
  41. package/src/all/background_page/controller/sso/saveSsoSettingsAsDraftController.test.data.js +1 -0
  42. package/src/all/background_page/controller/webIntegration/webIntegrationController.js +1 -1
  43. package/src/all/background_page/event/appEvents.js +47 -0
  44. package/src/all/background_page/event/authEvents.js +4 -8
  45. package/src/all/background_page/event/informMenuEvents.js +31 -0
  46. package/src/all/background_page/event/quickAccessEvents.js +18 -23
  47. package/src/all/background_page/event/recoverEvents.js +12 -0
  48. package/src/all/background_page/event/resourceEvents.js +4 -11
  49. package/src/all/background_page/event/setupEvents.js +55 -0
  50. package/src/all/background_page/model/comment/{commentModel.js → commentService.js} +6 -2
  51. package/src/all/background_page/model/comment/commentService.test.js +98 -0
  52. package/src/all/background_page/model/entity/actionLog/actionLogsCollection.js +3 -3
  53. package/src/all/background_page/model/entity/actionLog/permissionsUpdatedActionLogEntity.js +4 -0
  54. package/src/all/background_page/model/entity/import/importResourcesFileEntity.test.data.js +3 -3
  55. package/src/all/background_page/model/entity/organizationSettings/organizationSettingsEntity.test.data.js +4 -0
  56. package/src/all/background_page/model/entity/permission/actionLog/updatedPermissionEntity.test.data.js +23 -0
  57. package/src/all/background_page/model/entity/permission/actionLog/updatedPermissionEntity.test.js +18 -33
  58. package/src/all/background_page/model/entity/permission/actionLog/updatedPermissionsCollection.js +71 -2
  59. package/src/all/background_page/model/entity/permission/actionLog/updatedPermissionsCollection.test.js +204 -0
  60. package/src/all/background_page/model/entity/permission/permissionsCollection.js +78 -0
  61. package/src/all/background_page/model/entity/permission/permissionsCollection.test.js +139 -7
  62. package/src/all/background_page/model/entity/plaintext/plaintextEntity.js +9 -0
  63. package/src/all/background_page/model/entity/resource/external/externalResourceEntity.js +65 -8
  64. package/src/all/background_page/model/entity/resource/external/externalResourceEntity.test.data.js +5 -4
  65. package/src/all/background_page/model/entity/resource/external/externalResourceEntity.test.js +72 -16
  66. package/src/all/background_page/model/entity/resource/external/externalResourcesCollection.test.js +2 -1
  67. package/src/all/background_page/model/entity/totp/externalTotpEntity.js +2 -2
  68. package/src/all/background_page/model/entity/totp/totpEntity.test.js +1 -1
  69. package/src/all/background_page/model/export/resources/csvRowComposer/csv1PasswordRowComposer.test.js +2 -2
  70. package/src/all/background_page/model/export/resources/csvRowComposer/csv1passwordRowComposer.js +5 -1
  71. package/src/all/background_page/model/export/resources/csvRowComposer/csvBitWardenRowComposer.js +9 -1
  72. package/src/all/background_page/model/export/resources/csvRowComposer/csvBitWardenRowComposer.test.js +6 -4
  73. package/src/all/background_page/model/export/resources/csvRowComposer/csvChromiumRowComposer.js +5 -1
  74. package/src/all/background_page/model/export/resources/csvRowComposer/csvChromiumRowComposer.test.js +3 -2
  75. package/src/all/background_page/model/export/resources/csvRowComposer/csvDashlaneRowComposer.js +5 -1
  76. package/src/all/background_page/model/export/resources/csvRowComposer/csvDashlaneRowComposer.test.js +2 -3
  77. package/src/all/background_page/model/export/resources/csvRowComposer/csvKdbxRowComposer.js +3 -1
  78. package/src/all/background_page/model/export/resources/csvRowComposer/csvKdbxRowComposer.test.js +6 -4
  79. package/src/all/background_page/model/export/resources/csvRowComposer/csvLastPassRowComposer.js +5 -1
  80. package/src/all/background_page/model/export/resources/csvRowComposer/csvLastPassRowComposer.test.js +2 -3
  81. package/src/all/background_page/model/export/resources/csvRowComposer/csvLogMeOnceRowComposer.js +5 -1
  82. package/src/all/background_page/model/export/resources/csvRowComposer/csvLogMeOnceRowComposer.test.js +2 -3
  83. package/src/all/background_page/model/export/resources/csvRowComposer/csvMozillaPlatformRowComposer.js +6 -2
  84. package/src/all/background_page/model/export/resources/csvRowComposer/csvMozillaPlatformRowComposer.test.js +2 -2
  85. package/src/all/background_page/model/export/resources/csvRowComposer/csvNordpassRowComposer.js +5 -1
  86. package/src/all/background_page/model/export/resources/csvRowComposer/csvNordpassRowComposer.test.js +2 -2
  87. package/src/all/background_page/model/export/resources/csvRowComposer/csvSafariRowComposer.js +5 -1
  88. package/src/all/background_page/model/export/resources/csvRowComposer/csvSafariRowComposer.test.js +2 -2
  89. package/src/all/background_page/model/export/resources/resourcesKdbxExporter.js +44 -2
  90. package/src/all/background_page/model/export/resources/resourcesKdbxExporter.test.js +24 -3
  91. package/src/all/background_page/model/import/resources/csvRowParser/abstractCsvRowParser.js +1 -1
  92. package/src/all/background_page/model/import/resources/csvRowParser/csv1PasswordRowParser.js +5 -3
  93. package/src/all/background_page/model/import/resources/csvRowParser/csv1PasswordRowParser.test.js +3 -2
  94. package/src/all/background_page/model/import/resources/csvRowParser/csvBitWardenRowParser.js +22 -3
  95. package/src/all/background_page/model/import/resources/csvRowParser/csvBitWardenRowParser.test.js +92 -4
  96. package/src/all/background_page/model/import/resources/csvRowParser/csvChromiumRowParser.js +4 -2
  97. package/src/all/background_page/model/import/resources/csvRowParser/csvChromiumRowParser.test.js +2 -2
  98. package/src/all/background_page/model/import/resources/csvRowParser/csvDashlaneRowParser.js +4 -2
  99. package/src/all/background_page/model/import/resources/csvRowParser/csvDashlaneRowParser.test.js +3 -2
  100. package/src/all/background_page/model/import/resources/csvRowParser/csvKdbxRowParser.js +5 -3
  101. package/src/all/background_page/model/import/resources/csvRowParser/csvKdbxRowParser.test.js +4 -4
  102. package/src/all/background_page/model/import/resources/csvRowParser/csvLastPassRowParser.js +4 -2
  103. package/src/all/background_page/model/import/resources/csvRowParser/csvLastPassRowParser.test.js +2 -2
  104. package/src/all/background_page/model/import/resources/csvRowParser/csvLogMeOnceRowParser.js +5 -2
  105. package/src/all/background_page/model/import/resources/csvRowParser/csvLogMeOnceRowParser.test.js +2 -2
  106. package/src/all/background_page/model/import/resources/csvRowParser/csvMozillaPlatformRowParser.js +5 -3
  107. package/src/all/background_page/model/import/resources/csvRowParser/csvMozillaPlatformRowParser.test.js +2 -2
  108. package/src/all/background_page/model/import/resources/csvRowParser/csvNordpassRowParser.js +4 -2
  109. package/src/all/background_page/model/import/resources/csvRowParser/csvNordpassRowParser.test.js +2 -2
  110. package/src/all/background_page/model/import/resources/csvRowParser/csvSafariRowParser.js +4 -2
  111. package/src/all/background_page/model/import/resources/csvRowParser/csvSafariRowParser.test.js +2 -2
  112. package/src/all/background_page/model/import/resources/kdbx/kdbx-custom-fields-with-uris.kdbx +0 -0
  113. package/src/all/background_page/model/import/resources/kdbx/kdbx-multiple-uris-with-33-entries.kdbx +0 -0
  114. package/src/all/background_page/model/import/resources/kdbx/kdbx-multiple-uris.kdbx +0 -0
  115. package/src/all/background_page/model/import/resources/kdbx/kdbx-with-protected-custom-fields.kdbx +0 -0
  116. package/src/all/background_page/model/import/resources/resourcesCsvImportParser.test.js +1 -1
  117. package/src/all/background_page/model/import/resources/resourcesKdbxImportParser.js +124 -41
  118. package/src/all/background_page/model/import/resources/resourcesKdbxImportParser.test.js +133 -1
  119. package/src/all/background_page/model/import/resourcesImportParser.test.js +0 -1
  120. package/src/all/background_page/model/resource/resourceModel.js +0 -68
  121. package/src/all/background_page/service/api/comment/commentApiService.test.js +1 -1
  122. package/src/all/background_page/service/api/metadata/metadataSetupSettingsApiService.js +40 -0
  123. package/src/all/background_page/service/api/metadata/metadataSetupSettingsApiService.test.js +54 -0
  124. package/src/all/background_page/service/api/setup/setupService.js +2 -2
  125. package/src/all/background_page/service/api/setup/setupService.test.js +132 -0
  126. package/src/all/background_page/service/local_storage/resourceLocalStorage.js +25 -1
  127. package/src/all/background_page/service/local_storage/resourceLocalStorage.test.js +54 -0
  128. package/src/all/background_page/service/metadata/configureMetadataSettingsService.js +100 -0
  129. package/src/all/background_page/service/metadata/configureMetadataSettingsService.test.js +265 -0
  130. package/src/all/background_page/service/metadata/createMetadataKeyService.js +1 -1
  131. package/src/all/background_page/service/metadata/decryptMetadataPrivateKeysService.js +3 -19
  132. package/src/all/background_page/service/metadata/decryptMetadataService.js +5 -3
  133. package/src/all/background_page/service/metadata/decryptMetadataService.test.js +31 -24
  134. package/src/all/background_page/service/metadata/encryptMetadataService.js +2 -18
  135. package/src/all/background_page/service/metadata/findAndUpdateMetadataKeysSessionStorageService.js +5 -2
  136. package/src/all/background_page/service/metadata/findAndUpdateMetadataKeysSessionStorageService.test.js +4 -6
  137. package/src/all/background_page/service/metadata/findMetadataKeysService.js +8 -12
  138. package/src/all/background_page/service/metadata/findMetadataKeysService.test.js +21 -47
  139. package/src/all/background_page/service/metadata/findMetadataSetupSettingsService.js +45 -0
  140. package/src/all/background_page/service/metadata/findMetadataSetupSettingsService.test.js +68 -0
  141. package/src/all/background_page/service/metadata/generateMetadataKeyService.js +1 -1
  142. package/src/all/background_page/service/metadata/verifyOrTrustMetadataKeyService.test.js +16 -0
  143. package/src/all/background_page/service/passphrase/getPassphraseService.js +13 -0
  144. package/src/all/background_page/service/permission/findPermissionsService.js +3 -1
  145. package/src/all/background_page/service/resource/delete/deleteResourceService.js +60 -0
  146. package/src/all/background_page/service/resource/delete/deleteResourceService.test.js +75 -0
  147. package/src/all/background_page/service/resource/export/exportResourcesService.js +22 -0
  148. package/src/all/background_page/service/resource/export/exportResourcesService.test.js +48 -1
  149. package/src/all/background_page/service/resource/import/ImportResourcesService.js +34 -3
  150. package/src/all/background_page/service/resource/import/ImportResourcesService.test.js +55 -13
  151. package/src/all/background_page/service/sessionKey/decryptSessionKeysBundlesService.js +2 -18
  152. package/src/all/background_page/service/sessionKey/encryptSessionKeysBundlesService.js +1 -17
  153. package/src/all/locales/cs-CZ/common.json +130 -0
  154. package/src/all/locales/de-DE/common.json +11 -5
  155. package/src/all/locales/en-UK/common.json +6 -0
  156. package/src/all/locales/es-ES/common.json +6 -0
  157. package/src/all/locales/fr-FR/common.json +6 -0
  158. package/src/all/locales/it-IT/common.json +6 -0
  159. package/src/all/locales/ja-JP/common.json +6 -0
  160. package/src/all/locales/ko-KR/common.json +6 -0
  161. package/src/all/locales/lt-LT/common.json +6 -0
  162. package/src/all/locales/nl-NL/common.json +6 -0
  163. package/src/all/locales/pl-PL/common.json +6 -0
  164. package/src/all/locales/pt-BR/common.json +6 -0
  165. package/src/all/locales/ro-RO/common.json +6 -0
  166. package/src/all/locales/ru-RU/common.json +6 -0
  167. package/src/all/locales/sl-SI/common.json +6 -0
  168. package/src/all/locales/sv-SE/common.json +6 -0
  169. package/src/all/locales/uk-UA/common.json +6 -0
  170. package/src/chrome/manifest.json +1 -1
  171. package/src/chrome-mv3/manifest.json +1 -1
  172. package/src/firefox/manifest.json +1 -1
  173. package/src/safari/manifest.json +1 -1
@@ -13,7 +13,6 @@
13
13
  */
14
14
 
15
15
  import MetadataKeysCollection from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysCollection";
16
- import DecryptMetadataPrivateKeysService from "../metadata/decryptMetadataPrivateKeysService";
17
16
  import MetadataKeysApiService from "../api/metadata/metadataKeysApiService";
18
17
  import {OpenpgpAssertion} from "../../utils/openpgp/openpgpAssertions";
19
18
  import CollectionValidationError from "passbolt-styleguide/src/shared/models/entity/abstract/collectionValidationError";
@@ -24,12 +23,10 @@ class FindMetadataKeysService {
24
23
  * Constructor
25
24
  *
26
25
  * @param {ApiClientOptions} apiClientOptions
27
- * @param {AccountEntity} account the user account
28
26
  * @public
29
27
  */
30
- constructor(apiClientOptions, account) {
28
+ constructor(apiClientOptions) {
31
29
  this.metadataKeysApiService = new MetadataKeysApiService(apiClientOptions);
32
- this.decryptMetadataPrivateKeysService = new DecryptMetadataPrivateKeysService(account);
33
30
  }
34
31
 
35
32
  /**
@@ -37,12 +34,10 @@ class FindMetadataKeysService {
37
34
  *
38
35
  * @param {Object} [contains] Return entities associated models, example: {metadata_private_keys: true}.
39
36
  * @param {Object} [filters] Return entities applied filters, example: {deleted: true}.
40
- * @param {string|null} [passphrase = null] The passphrase to use to decrypt the metadata. Marked as optional as it
41
- * might be available in the passphrase session storage.
42
37
  * @returns {Promise<MetadataKeysCollection>}
43
38
  * @public
44
39
  */
45
- async findAll(contains = {}, filters = {}, passphrase = null) {
40
+ async findAll(contains = {}, filters = {}) {
46
41
  const supportedOptions = MetadataKeysApiService.getSupportedContainOptions();
47
42
  if (contains && !Object.keys(contains).every(option => supportedOptions.includes(option))) {
48
43
  throw new Error("Unsupported contains parameter used, please check supported contains");
@@ -59,7 +54,6 @@ class FindMetadataKeysService {
59
54
  throw new Error("The metadata private keys should not be decrypted.");
60
55
  }
61
56
 
62
- await this.decryptMetadataPrivateKeysService.decryptAllFromMetadataKeysCollection(collection, passphrase);
63
57
  await this.assertArmoredFingerprintPublicAndEntitysMatch(collection);
64
58
 
65
59
  return collection;
@@ -67,13 +61,15 @@ class FindMetadataKeysService {
67
61
 
68
62
  /**
69
63
  * Retrieve the metadata keys from the API with the contained data necessary for the local storage.
70
- * @param {string|null} [passphrase = null] The passphrase to use to decrypt the metadata. Marked as optional as it
71
- * might be available in the passphrase session storage.
72
64
  * @returns {Promise<MetadataKeysCollection>}
73
65
  * @public
74
66
  */
75
- findAllForSessionStorage(passphrase = null) {
76
- return this.findAll({metadata_private_keys: true, creator: true, "creator.profile": true}, {deleted: false}, passphrase);
67
+ async findAllForSessionStorage() {
68
+ const contains = {metadata_private_keys: true, creator: true, "creator.profile": true};
69
+ const filters = {deleted: false};
70
+ const metadataKeys = await this.findAll(contains, filters);
71
+ metadataKeys.filterOutMissingMetadataPrivateKeys();
72
+ return metadataKeys;
77
73
  }
78
74
 
79
75
  /**
@@ -15,7 +15,6 @@
15
15
  import {enableFetchMocks} from "jest-fetch-mock";
16
16
  import AccountEntity from "../../model/entity/account/accountEntity";
17
17
  import {defaultAccountDto} from "../../model/entity/account/accountEntity.test.data";
18
- import PassphraseStorageService from "../session_storage/passphraseStorageService";
19
18
  import BuildApiClientOptionsService from "../account/buildApiClientOptionsService";
20
19
  import FindMetadataKeysService from "./findMetadataKeysService";
21
20
  import {mockApiResponseError} from "passbolt-styleguide/test/mocks/mockApiResponse";
@@ -43,43 +42,25 @@ describe("FindMetadataKeysApiService", () => {
43
42
  });
44
43
 
45
44
  describe('::findAll', () => {
46
- it("retrieves the metadata keys from API with the right contains and decrypt them using the passphrase from the session storage", async() => {
45
+ it("retrieves the metadata keys from API with the right contains", async() => {
47
46
  expect.assertions(5);
48
47
 
49
- jest.spyOn(PassphraseStorageService, "get").mockReturnValue(pgpKeys.ada.passphrase);
50
-
51
48
  const id = uuidv4();
52
49
  const metadata_private_keys = [defaultMetadataPrivateKeyDto({metadata_key_id: id, data: pgpKeys.metadataKey.encryptedMetadataPrivateKeyDataMessage})];
53
50
  const fingerprint = "c0dce0aaea4d8cce961c26bddfb6e74e598f025c";
54
51
  const apiMetadataKeysCollection = [defaultMetadataKeyDto({id, metadata_private_keys, fingerprint})];
55
52
 
56
- const service = new FindMetadataKeysService(apiClientOptions, account);
53
+ const service = new FindMetadataKeysService(apiClientOptions);
57
54
  jest.spyOn(service.metadataKeysApiService, "findAll").mockImplementation(() => apiMetadataKeysCollection);
58
55
  const resultDto = await service.findAll();
59
56
 
60
57
  expect(resultDto).toBeInstanceOf(MetadataKeysCollection);
61
58
  expect(resultDto).toHaveLength(apiMetadataKeysCollection.length);
62
- expect(resultDto.hasEncryptedKeys()).toStrictEqual(false);
59
+ expect(resultDto.hasDecryptedKeys()).toStrictEqual(false);
63
60
  expect(service.metadataKeysApiService.findAll).toHaveBeenCalledTimes(1);
64
61
  expect(service.metadataKeysApiService.findAll).toHaveBeenCalledWith({}, {});
65
62
  });
66
63
 
67
- it("does not retrieve the passphrase from the session storage if passed as parameter", async() => {
68
- expect.assertions(1);
69
-
70
- const id = uuidv4();
71
- const metadata_private_keys = [defaultMetadataPrivateKeyDto({metadata_key_id: id, data: pgpKeys.metadataKey.encryptedMetadataPrivateKeyDataMessage})];
72
- const fingerprint = "c0dce0aaea4d8cce961c26bddfb6e74e598f025c";
73
- const apiMetadataKeysCollection = [defaultMetadataKeyDto({id, metadata_private_keys, fingerprint})];
74
-
75
- const service = new FindMetadataKeysService(apiClientOptions, account);
76
- jest.spyOn(PassphraseStorageService, "get");
77
- jest.spyOn(service.metadataKeysApiService, "findAll").mockImplementation(() => apiMetadataKeysCollection);
78
- await service.findAll({}, {}, pgpKeys.ada.passphrase);
79
-
80
- expect(PassphraseStorageService.get).not.toHaveBeenCalled();
81
- });
82
-
83
64
  it("throw an error if fingerprint is not matching with the armored public key", async() => {
84
65
  expect.assertions(2);
85
66
 
@@ -88,8 +69,7 @@ describe("FindMetadataKeysApiService", () => {
88
69
  const fingerprint = "c0dce0aaea4d8cce961c26bddfb6e74e598f025d";
89
70
  const apiMetadataKeysCollection = [defaultMetadataKeyDto({id, metadata_private_keys, fingerprint})];
90
71
 
91
- const service = new FindMetadataKeysService(apiClientOptions, account);
92
- jest.spyOn(PassphraseStorageService, "get").mockReturnValue(pgpKeys.ada.passphrase);
72
+ const service = new FindMetadataKeysService(apiClientOptions);
93
73
  jest.spyOn(service.metadataKeysApiService, "findAll").mockImplementation(() => apiMetadataKeysCollection);
94
74
 
95
75
  try {
@@ -112,8 +92,7 @@ describe("FindMetadataKeysApiService", () => {
112
92
  const metadata_private_keys = [decryptedMetadataPrivateKeyDto({metadata_key_id: id})];
113
93
  const apiMetadataKeysCollection = [defaultMetadataKeyDto({id, metadata_private_keys})];
114
94
 
115
- const service = new FindMetadataKeysService(apiClientOptions, account);
116
- jest.spyOn(PassphraseStorageService, "get").mockReturnValue(pgpKeys.ada.passphrase);
95
+ const service = new FindMetadataKeysService(apiClientOptions);
117
96
  jest.spyOn(service.metadataKeysApiService, "findAll").mockImplementation(() => apiMetadataKeysCollection);
118
97
 
119
98
  const expectedError = new Error("The metadata private keys should not be decrypted.");
@@ -162,7 +141,7 @@ describe("FindMetadataKeysApiService", () => {
162
141
  });
163
142
 
164
143
  describe('::findAllForSessionStorage', () => {
165
- it("retrieves the metadata keys from API with the right contains and decrypt them using the passphrase from the session storage", async() => {
144
+ it("retrieves the metadata keys from API with the right contains ", async() => {
166
145
  expect.assertions(5);
167
146
 
168
147
  const id = uuidv4();
@@ -170,48 +149,43 @@ describe("FindMetadataKeysApiService", () => {
170
149
  const fingerprint = "c0dce0aaea4d8cce961c26bddfb6e74e598f025c";
171
150
  const apiMetadataKeysCollection = [defaultMetadataKeyDto({id, metadata_private_keys, fingerprint})];
172
151
 
173
- const service = new FindMetadataKeysService(apiClientOptions, account);
174
- jest.spyOn(PassphraseStorageService, "get").mockReturnValue(pgpKeys.ada.passphrase);
152
+ const service = new FindMetadataKeysService(apiClientOptions);
175
153
  jest.spyOn(service.metadataKeysApiService, "findAll").mockImplementation(() => apiMetadataKeysCollection);
176
154
  const resultDto = await service.findAllForSessionStorage();
177
155
 
178
156
  expect(resultDto).toBeInstanceOf(MetadataKeysCollection);
179
157
  expect(resultDto).toHaveLength(apiMetadataKeysCollection.length);
180
- expect(resultDto.hasEncryptedKeys()).toStrictEqual(false);
158
+ expect(resultDto.hasDecryptedKeys()).toStrictEqual(false);
181
159
  expect(service.metadataKeysApiService.findAll).toHaveBeenCalledTimes(1);
182
160
  expect(service.metadataKeysApiService.findAll).toHaveBeenCalledWith({metadata_private_keys: true, creator: true, "creator.profile": true}, {deleted: false});
183
161
  });
184
162
 
185
- it("retrieves the metadata keys from API with the right contains and decrypt them using the passphrase given in parameter", async() => {
186
- expect.assertions(6);
163
+ it("filter out metadata key not having at least a metadata private key.", async() => {
164
+ expect.assertions(3);
187
165
 
188
- const id = uuidv4();
189
- const metadata_private_keys = [defaultMetadataPrivateKeyDto({metadata_key_id: id, data: pgpKeys.metadataKey.encryptedMetadataPrivateKeyDataMessage})];
190
166
  const fingerprint = "c0dce0aaea4d8cce961c26bddfb6e74e598f025c";
191
- const apiMetadataKeysCollection = [defaultMetadataKeyDto({id, metadata_private_keys, fingerprint})];
167
+ const apiMetadataKeysCollection = [
168
+ defaultMetadataKeyDto({fingerprint}, {withMetadataPrivateKeys: true}),
169
+ defaultMetadataKeyDto({fingerprint: pgpKeys.ada.fingerprint, armored_key: pgpKeys.ada.public})
170
+ ];
192
171
 
193
- const service = new FindMetadataKeysService(apiClientOptions, account);
194
- jest.spyOn(PassphraseStorageService, "get");
172
+ const service = new FindMetadataKeysService(apiClientOptions);
195
173
  jest.spyOn(service.metadataKeysApiService, "findAll").mockImplementation(() => apiMetadataKeysCollection);
196
- const resultDto = await service.findAllForSessionStorage(pgpKeys.ada.passphrase);
174
+ const resultDto = await service.findAllForSessionStorage();
197
175
 
198
- expect(PassphraseStorageService.get).not.toHaveBeenCalled();
199
176
  expect(resultDto).toBeInstanceOf(MetadataKeysCollection);
200
- expect(resultDto).toHaveLength(apiMetadataKeysCollection.length);
201
- expect(resultDto.hasEncryptedKeys()).toStrictEqual(false);
202
- expect(service.metadataKeysApiService.findAll).toHaveBeenCalledTimes(1);
203
- expect(service.metadataKeysApiService.findAll).toHaveBeenCalledWith({metadata_private_keys: true, creator: true, "creator.profile": true}, {deleted: false});
177
+ expect(resultDto).toHaveLength(1);
178
+ expect(resultDto.hasDecryptedKeys()).toStrictEqual(false);
204
179
  });
205
180
 
206
- it("throws an error if the keys from the API is already decrypted", async() => {
181
+ it("throws an error if one of the key from the API is already decrypted", async() => {
207
182
  expect.assertions(1);
208
183
 
209
184
  const id = uuidv4();
210
185
  const metadata_private_keys = [decryptedMetadataPrivateKeyDto({metadata_key_id: id})];
211
186
  const apiMetadataKeysCollection = [defaultMetadataKeyDto({id, metadata_private_keys})];
212
187
 
213
- const service = new FindMetadataKeysService(apiClientOptions, account);
214
- jest.spyOn(PassphraseStorageService, "get").mockReturnValue(pgpKeys.ada.passphrase);
188
+ const service = new FindMetadataKeysService(apiClientOptions);
215
189
  jest.spyOn(service.metadataKeysApiService, "findAll").mockImplementation(() => apiMetadataKeysCollection);
216
190
 
217
191
  const expectedError = new Error("The metadata private keys should not be decrypted.");
@@ -242,7 +216,7 @@ describe("FindMetadataKeysApiService", () => {
242
216
  expect.assertions(3);
243
217
 
244
218
  const apiMetadataKeysCollection = defaultMetadataKeysDtos();
245
- const service = new FindMetadataKeysService(apiClientOptions, account);
219
+ const service = new FindMetadataKeysService(apiClientOptions);
246
220
  jest.spyOn(service, "findAll")
247
221
  .mockImplementation(() => new MetadataKeysCollection(apiMetadataKeysCollection));
248
222
 
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Passbolt ~ Open source password manager for teams
3
+ * Copyright (c) Passbolt SA (https://www.passbolt.com)
4
+ *
5
+ * Licensed under GNU Affero General Public License version 3 of the or any later version.
6
+ * For full copyright and license information, please see the LICENSE.txt
7
+ * Redistributions of files must retain the above copyright notice.
8
+ *
9
+ * @copyright Copyright (c) Passbolt SA (https://www.passbolt.com)
10
+ * @license https://opensource.org/licenses/AGPL-3.0 AGPL License
11
+ * @link https://www.passbolt.com Passbolt(tm)
12
+ * @since 5.4.0
13
+ */
14
+
15
+ import MetadataSetupSettingsApiService from "../api/metadata/metadataSetupSettingsApiService";
16
+ import MetadataSetupSettingsEntity from "passbolt-styleguide/src/shared/models/entity/metadata/metadataSetupSettingsEntity";
17
+
18
+ /**
19
+ * The service aims to find metadata setup settings.
20
+ */
21
+ export default class FindMetadataSetupSettingsService {
22
+ /**
23
+ * @constructor
24
+ * @param {ApiClientOptions} apiClientOptions The api client options
25
+ */
26
+ constructor(apiClientOptions) {
27
+ this.metadataSetupSettingsApiService = new MetadataSetupSettingsApiService(apiClientOptions);
28
+ }
29
+
30
+ /**
31
+ * Finds the metadata setup settings.
32
+ * @returns {Promise<MetadataSetupSettingsEntity>}
33
+ */
34
+ async findSetupSettings() {
35
+ try {
36
+ const passboltResponse = await this.metadataSetupSettingsApiService.find();
37
+ return MetadataSetupSettingsEntity.createFromDefault(passboltResponse.body);
38
+ } catch (e) {
39
+ if (e?.data?.code === 404) {
40
+ return MetadataSetupSettingsEntity.createFromDefault();
41
+ }
42
+ throw e;
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Passbolt ~ Open source password manager for teams
3
+ * Copyright (c) Passbolt SA (https://www.passbolt.com)
4
+ *
5
+ * Licensed under GNU Affero General Public License version 3 of the or any later version.
6
+ * For full copyright and license information, please see the LICENSE.txt
7
+ * Redistributions of files must retain the above copyright notice.
8
+ *
9
+ * @copyright Copyright (c) Passbolt SA (https://www.passbolt.com)
10
+ * @license https://opensource.org/licenses/AGPL-3.0 AGPL License
11
+ * @link https://www.passbolt.com Passbolt(tm)
12
+ * @since 5.4.0
13
+ */
14
+ import {enableFetchMocks} from "jest-fetch-mock";
15
+ import FindMetadataSetupSettingsService from "./findMetadataSetupSettingsService";
16
+ import {defaultApiClientOptions} from "passbolt-styleguide/src/shared/lib/apiClient/apiClientOptions.test.data";
17
+ import MetadataSetupSettingsEntity from "passbolt-styleguide/src/shared/models/entity/metadata/metadataSetupSettingsEntity";
18
+ import {enableMetadataSetupSettingsDto} from "passbolt-styleguide/src/shared/models/entity/metadata/metadataSetupSettingsEntity.test.data";
19
+ import {mockApiResponse, mockApiResponseError} from "../../../../../test/mocks/mockApiResponse";
20
+
21
+ beforeEach(() => {
22
+ jest.clearAllMocks();
23
+ enableFetchMocks();
24
+ });
25
+
26
+ describe("FindMetadataSetupSettingsService", () => {
27
+ describe("::findSetupSettings", () => {
28
+ it("retrieve the metadata setup settings.", async() => {
29
+ expect.assertions(2);
30
+
31
+ const expectedSettings = enableMetadataSetupSettingsDto();
32
+ const apiClientOptions = defaultApiClientOptions();
33
+ const service = new FindMetadataSetupSettingsService(apiClientOptions);
34
+
35
+ fetch.doMockOnceIf(/\/metadata\/setup\/settings\.json/, () => mockApiResponse(expectedSettings));
36
+
37
+ const metadataSetupSettingsEntity = await service.findSetupSettings();
38
+
39
+ expect(metadataSetupSettingsEntity).toBeInstanceOf(MetadataSetupSettingsEntity);
40
+ expect(metadataSetupSettingsEntity.enableEncryptedMetadataOnInstall).toStrictEqual(true);
41
+ });
42
+
43
+ it("should consider default disabled settings if the API sends back a 404", async() => {
44
+ expect.assertions(2);
45
+
46
+ const apiClientOptions = defaultApiClientOptions();
47
+ const service = new FindMetadataSetupSettingsService(apiClientOptions);
48
+
49
+ fetch.doMockOnceIf(/\/metadata\/setup\/settings.json/, () => mockApiResponseError(404, "Endpoint does not exists"));
50
+
51
+ const metadataSetupSettingsEntity = await service.findSetupSettings();
52
+
53
+ expect(metadataSetupSettingsEntity).toBeInstanceOf(MetadataSetupSettingsEntity);
54
+ expect(metadataSetupSettingsEntity.enableEncryptedMetadataOnInstall).toStrictEqual(false);
55
+ });
56
+
57
+ it("should not intercept the error from the API if something goes wrong and it is not a 404", async() => {
58
+ expect.assertions(1);
59
+
60
+ const apiClientOptions = defaultApiClientOptions();
61
+ const service = new FindMetadataSetupSettingsService(apiClientOptions);
62
+
63
+ fetch.doMockOnce(/\/metadata\/setup\/settings.json/, () => mockApiResponseError(500, "Something went wrong!"));
64
+
65
+ await expect(() => service.findSetupSettings()).rejects.toThrowError();
66
+ });
67
+ });
68
+ });
@@ -29,7 +29,7 @@ class GenerateMetadataKeyService {
29
29
  /**
30
30
  * Generate metadata key.
31
31
  * @param {string} passphrase The user passphrase.
32
- * @return {ExternalGpgKeyPairEntity}
32
+ * @return {Promise<ExternalGpgKeyPairEntity>}
33
33
  */
34
34
  async generateKey(passphrase) {
35
35
  assertString(passphrase);
@@ -100,6 +100,22 @@ describe("VerifyOrTrustMetadataKeyService", () => {
100
100
  expect(service.confirmMetadataKeyContentCodeService.requestConfirm).not.toHaveBeenCalled();
101
101
  });
102
102
 
103
+ it("does nothing if the user does not have a metadata private key shared with the active metadata key returned by the server.", async() => {
104
+ expect.assertions(2);
105
+
106
+ const metadataKeyDto = defaultMetadataKeyDto();
107
+ const metadataKeysCollection = new MetadataKeysCollection([metadataKeyDto]);
108
+
109
+ jest.spyOn(service.getOrFindMetadataKeysService.findAndUpdateMetadataKeysService.findMetadataKeysService, "findAll").mockReturnValue(metadataKeysCollection);
110
+ jest.spyOn(service.trustMetadataKeyService, "trust").mockImplementationOnce(jest.fn);
111
+ jest.spyOn(service.confirmMetadataKeyContentCodeService, "requestConfirm").mockImplementationOnce(jest.fn);
112
+
113
+ await service.verifyTrustedOrTrustNewMetadataKey(pgpKeys.ada.passphrase);
114
+
115
+ expect(service.trustMetadataKeyService.trust).not.toHaveBeenCalled();
116
+ expect(service.confirmMetadataKeyContentCodeService.requestConfirm).not.toHaveBeenCalled();
117
+ });
118
+
103
119
  it("throws if the active metadata key is not the one already trusted, and the user does not trust it.", async() => {
104
120
  expect.assertions(2);
105
121
 
@@ -37,6 +37,19 @@ export default class GetPassphraseService {
37
37
  return this.requestPassphrase(worker);
38
38
  }
39
39
 
40
+ /**
41
+ * Read the user master password from the storage.
42
+ * @return {Promise<string>}
43
+ * @throw Error if the passphrase is not available.
44
+ */
45
+ async getFromStorageOrFail() {
46
+ const passphrase = await PassphraseStorageService.get();
47
+ if (!passphrase) {
48
+ throw new Error("No passphrase found in the session storage.");
49
+ }
50
+ return passphrase;
51
+ }
52
+
40
53
  /**
41
54
  * Request the user passphrase.
42
55
  *
@@ -38,7 +38,9 @@ class FindPermissionsService {
38
38
  async findAllByAcoForeignKeyForDisplay(resourceId) {
39
39
  assertUuid(resourceId, `Service error. The id '${resourceId}' is not a valid uuid.`);
40
40
  const permissionsCollectionDto = await this.permissionService.findAllByAcoForeignKey(resourceId, FindPermissionsService.DEFAULT_CONTAIN);
41
- return new PermissionsCollection(permissionsCollectionDto);
41
+ const collection = new PermissionsCollection(permissionsCollectionDto);
42
+ collection.sort();
43
+ return collection;
42
44
  }
43
45
 
44
46
  /**
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Passbolt ~ Open source password manager for teams
3
+ * Copyright (c) Passbolt SA (https://www.passbolt.com)
4
+ *
5
+ * Licensed under GNU Affero General Public License version 3 of the or any later version.
6
+ * For full copyright and license information, please see the LICENSE.txt
7
+ * Redistributions of files must retain the above copyright notice.
8
+ *
9
+ * @copyright Copyright (c) Passbolt SA (https://www.passbolt.com)
10
+ * @license https://opensource.org/licenses/AGPL-3.0 AGPL License
11
+ * @link https://www.passbolt.com Passbolt(tm)
12
+ * @since 5.4.0
13
+ */
14
+ import ResourceService from "../../api/resource/resourceService";
15
+ import ResourceLocalStorage from "../../local_storage/resourceLocalStorage";
16
+ import i18n from "../../../sdk/i18n";
17
+ import {assertArrayUUID} from "../../../utils/assertions";
18
+ import ExecuteConcurrentlyService from "../../execute/executeConcurrentlyService";
19
+ class DeleteResourceService {
20
+ /**
21
+ * Constructor
22
+ * @param {AccountEntity} account The user account
23
+ * @param {ApiClientOptions} apiClientOptions The api client options
24
+ * @param {ProgressService} progressService
25
+ */
26
+ constructor(account, apiClientOptions, progressService) {
27
+ this.account = account;
28
+ this.resourceService = new ResourceService(apiClientOptions);
29
+ this.progressService = progressService;
30
+ }
31
+
32
+ /**
33
+ * Delete a bulk of resources
34
+ * @param {Array<string>} resourceIds The resourceIds
35
+ * @returns {Promise<void>}
36
+ */
37
+ async deleteResources(resourceIds) {
38
+ assertArrayUUID(resourceIds);
39
+ /**
40
+ * 1. Delete the Resources
41
+ * 2. Update the local storage
42
+ */
43
+ this.progressService.finishStep(i18n.t("Deleting Resource(s)"), true);
44
+ let deleteCounter = 0;
45
+ const deleteCallBacks = resourceId => {
46
+ this.progressService.updateStepMessage(i18n.t("Deleting resource(s) {{counter}}/{{total}}", {counter: ++deleteCounter, total: resourceIds.length}));
47
+ return this.resourceService.delete(resourceId);
48
+ };
49
+
50
+ const callbacks = resourceIds.map(resourceId => () => deleteCallBacks(resourceId));
51
+ const executeConcurrentlyService = new ExecuteConcurrentlyService();
52
+ await executeConcurrentlyService.execute(callbacks, 5);
53
+
54
+ this.progressService.finishStep(i18n.t("Updating resources local storage"), true);
55
+ await ResourceLocalStorage.deleteResources(resourceIds);
56
+ }
57
+ }
58
+
59
+
60
+ export default DeleteResourceService;
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Passbolt ~ Open source password manager for teams
3
+ * Copyright (c) Passbolt SA (https://www.passbolt.com)
4
+ *
5
+ * Licensed under GNU Affero General Public License version 3 of the or any later version.
6
+ * For full copyright and license information, please see the LICENSE.txt
7
+ * Redistributions of files must retain the above copyright notice.
8
+ *
9
+ * @copyright Copyright (c) Passbolt SA (https://www.passbolt.com)
10
+ * @license https://opensource.org/licenses/AGPL-3.0 AGPL License
11
+ * @link https://www.passbolt.com Passbolt(tm)
12
+ * @since 5.4.0
13
+ */
14
+
15
+ import {defaultApiClientOptions} from "passbolt-styleguide/src/shared/lib/apiClient/apiClientOptions.test.data";
16
+ import AccountEntity from "../../../model/entity/account/accountEntity";
17
+ import {defaultAccountDto} from "../../../model/entity/account/accountEntity.test.data";
18
+ import {defaultResourceDto} from "passbolt-styleguide/src/shared/models/entity/resource/resourceEntity.test.data";
19
+ import DeleteResourceService from "./deleteResourceService";
20
+ import ResourceLocalStorage from "../../local_storage/resourceLocalStorage";
21
+ import ProgressService from "../../progress/progressService";
22
+
23
+ jest.mock("../../../service/progress/progressService");
24
+
25
+ beforeEach(() => {
26
+ jest.clearAllMocks();
27
+ });
28
+
29
+ describe("DeleteResourceService", () => {
30
+ let deleteResourceService, worker;
31
+ const account = new AccountEntity(defaultAccountDto());
32
+ const apiClientOptions = defaultApiClientOptions();
33
+
34
+ beforeEach(async() => {
35
+ worker = {
36
+ port: {
37
+ emit: jest.fn()
38
+ }
39
+ };
40
+ deleteResourceService = new DeleteResourceService(account, apiClientOptions, new ProgressService(worker, ""));
41
+ jest.spyOn(ResourceLocalStorage, "deleteResources");
42
+ });
43
+
44
+ describe("DeleteResourceService::deleteResources", () => {
45
+ it("Should delete the resources and call local storage update", async() => {
46
+ expect.assertions(5);
47
+
48
+ const resourceDto1 = defaultResourceDto();
49
+ const resourceDto2 = defaultResourceDto();
50
+ const resourceDto3 = defaultResourceDto();
51
+ jest.spyOn(deleteResourceService.resourceService, "delete").mockImplementation(() => {});
52
+ await deleteResourceService.deleteResources([resourceDto1.id, resourceDto2.id, resourceDto3.id]);
53
+
54
+ expect(deleteResourceService.resourceService.delete).toHaveBeenCalledTimes(3);
55
+ expect(deleteResourceService.resourceService.delete).toHaveBeenCalledWith(resourceDto1.id);
56
+ expect(deleteResourceService.resourceService.delete).toHaveBeenCalledWith(resourceDto2.id);
57
+ expect(deleteResourceService.resourceService.delete).toHaveBeenCalledWith(resourceDto3.id);
58
+ expect(ResourceLocalStorage.deleteResources).toHaveBeenCalledWith([resourceDto1.id, resourceDto2.id, resourceDto3.id]);
59
+ });
60
+
61
+ it("Should call progress service during the different steps of deletion", async() => {
62
+ expect.assertions(3);
63
+
64
+ const resourceDto1 = defaultResourceDto();
65
+ const resourceDto2 = defaultResourceDto();
66
+ const resourceDto3 = defaultResourceDto();
67
+ jest.spyOn(deleteResourceService.resourceService, "delete").mockImplementation(() => {});
68
+ await deleteResourceService.deleteResources([resourceDto1.id, resourceDto2.id, resourceDto3.id]);
69
+
70
+ expect(deleteResourceService.progressService.finishStep).toHaveBeenCalledTimes(2);
71
+ expect(deleteResourceService.progressService.finishStep).toHaveBeenCalledWith('Deleting Resource(s)', true);
72
+ expect(deleteResourceService.progressService.finishStep).toHaveBeenCalledWith("Updating resources local storage", true);
73
+ });
74
+ });
75
+ });
@@ -12,6 +12,7 @@
12
12
  * @since 4.10.1
13
13
  */
14
14
 
15
+ import CustomFieldEntity from "passbolt-styleguide/src/shared/models/entity/customField/customFieldEntity";
15
16
  import ExternalFoldersCollection from "../../../model/entity/folder/external/externalFoldersCollection";
16
17
  import ExternalResourcesCollection from "../../../model/entity/resource/external/externalResourcesCollection";
17
18
  import ExternalTotpEntity from "../../../model/entity/totp/externalTotpEntity";
@@ -23,6 +24,7 @@ import DecryptPrivateKeyService from "../../crypto/decryptPrivateKeyService";
23
24
  import DecryptMetadataService from "../../metadata/decryptMetadataService";
24
25
  import DecryptAndParseResourceSecretService from "../../secret/decryptAndParseResourceSecretService";
25
26
  import FindResourcesService from "../findResourcesService";
27
+ import CustomFieldsCollection from "passbolt-styleguide/src/shared/models/entity/customField/customFieldsCollection";
26
28
 
27
29
  /**
28
30
  * The service aim to export the resources to a file.
@@ -99,9 +101,29 @@ class ExportResourcesService {
99
101
  if (plaintextSecret.totp) {
100
102
  exportResourceEntity.totp = new ExternalTotpEntity(plaintextSecret.totp);
101
103
  }
104
+ if (plaintextSecret.customFields) {
105
+ exportResourceEntity.customFields = this.buildCustomFieldWithSecretDto(exportResourceEntity, plaintextSecret);
106
+ }
102
107
  }
103
108
  }
104
109
 
110
+ /**
111
+ * Build custom fields with secret
112
+ * @param {ExternalResourceEntity} exportResourcesFileEntity The export object
113
+ * @param {Object} plaintextSecret The plaintext secret
114
+ * @returns {CustomFieldsCollection}
115
+ */
116
+ buildCustomFieldWithSecretDto(exportResourceEntity, plaintextSecret) {
117
+ const customFieldsDto = [];
118
+ exportResourceEntity.customFields?.items?.forEach(customField => {
119
+ const customFieldDto = customField.toDto();
120
+ const secret = plaintextSecret.customFields.find(customFieldSecret => customFieldSecret.id === customFieldDto.id);
121
+ customFieldDto.secret_value = secret?.secret_value;
122
+ customFieldsDto.push(new CustomFieldEntity(customFieldDto));
123
+ });
124
+ return new CustomFieldsCollection(customFieldsDto);
125
+ }
126
+
105
127
  /**
106
128
  * Export
107
129
  * @param {ExportResourcesFileEntity} exportResourcesFileEntity The export object
@@ -46,6 +46,8 @@ import {defaultDecryptedSharedMetadataKeysDtos} from "passbolt-styleguide/src/sh
46
46
  import MetadataKeysCollection from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysCollection";
47
47
  import EncryptMetadataService from "../../metadata/encryptMetadataService";
48
48
  import {defaultMetadataKeysSettingsDto} from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysSettingsEntity.test.data";
49
+ import CustomFieldsCollection from "passbolt-styleguide/src/shared/models/entity/customField/customFieldsCollection";
50
+ import {defaultCustomFieldsCollection} from "passbolt-styleguide/src/shared/models/entity/customField/customFieldsCollection.test.data";
49
51
 
50
52
  jest.mock("../../../service/progress/progressService");
51
53
 
@@ -88,7 +90,6 @@ describe("ExportResourcesService", () => {
88
90
  {format: FORMAT_CSV_LASTPASS, expected: lastpassCsvFile},
89
91
  {format: FORMAT_CSV_1PASSWORD, expected: onePasswordCsvFile},
90
92
  {format: FORMAT_CSV_CHROMIUM, expected: chromiumCsvFile},
91
- {format: FORMAT_CSV_BITWARDEN, expected: bitwardenCsvFile},
92
93
  {format: FORMAT_CSV_MOZILLA, expected: mozillaCsvFile},
93
94
  {format: FORMAT_CSV_SAFARI, expected: safariCsvFile},
94
95
  {format: FORMAT_CSV_DASHLANE, expected: dashlaneCsvFile},
@@ -136,6 +137,7 @@ describe("ExportResourcesService", () => {
136
137
  });
137
138
  });
138
139
  each([
140
+ {format: FORMAT_CSV_BITWARDEN, expected: bitwardenCsvFile},
139
141
  {format: FORMAT_CSV_KDBX, expected: KdbxCsvFile},
140
142
  ]).describe("Should export the csv file with password, description and totp.", test => {
141
143
  each([
@@ -322,4 +324,49 @@ describe("ExportResourcesService", () => {
322
324
  expect(service.progressService.finishStep).toHaveBeenCalledWith("Decrypting 1/1");
323
325
  });
324
326
  });
327
+
328
+ describe("::buildCustomFieldWithSecretDto", () => {
329
+ it("Should build custom fields with secret", () => {
330
+ expect.assertions(4);
331
+
332
+ const customFieldsCollection = defaultCustomFieldsCollection();
333
+
334
+ const plaintextSecret = {
335
+ customFields: [
336
+ {id: customFieldsCollection[0].id, secret_value: "Secret Value 1"},
337
+ {id: customFieldsCollection[1].id, secret_value: "Secret Value 2"}
338
+ ]
339
+ };
340
+
341
+ const exportResourceEntity = {
342
+ customFields: new CustomFieldsCollection(customFieldsCollection)
343
+ };
344
+
345
+ const result = service.buildCustomFieldWithSecretDto(exportResourceEntity, plaintextSecret);
346
+
347
+ expect(result).toBeInstanceOf(CustomFieldsCollection);
348
+ expect(result.items).toHaveLength(2);
349
+ expect(result.items[0].value).toEqual("Secret Value 1");
350
+ expect(result.items[1].value).toEqual("Secret Value 2");
351
+ });
352
+
353
+ it("Should handle missing custom fields", () => {
354
+ expect.assertions(2);
355
+
356
+ const exportResourceEntity = {
357
+ customFields: {
358
+ items: []
359
+ }
360
+ };
361
+
362
+ const plaintextSecret = {
363
+ customFields: []
364
+ };
365
+
366
+ const result = service.buildCustomFieldWithSecretDto(exportResourceEntity, plaintextSecret);
367
+
368
+ expect(result).toBeInstanceOf(CustomFieldsCollection);
369
+ expect(result.items).toHaveLength(0);
370
+ });
371
+ });
325
372
  });