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
@@ -0,0 +1,265 @@
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 AccountEntity from "../../model/entity/account/accountEntity";
15
+ import BuildApiClientOptionsService from "../account/buildApiClientOptionsService";
16
+ import ConfigureMetadataSettingsService from "./configureMetadataSettingsService";
17
+ import MetadataTypesSettingsEntity from "passbolt-styleguide/src/shared/models/entity/metadata/metadataTypesSettingsEntity";
18
+ import MetadataKeysSettingsEntity from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysSettingsEntity";
19
+ import ExternalGpgKeyPairEntity from "passbolt-styleguide/src/shared/models/entity/gpgkey/external/externalGpgKeyPairEntity";
20
+ import {defaultAccountDto} from "../../model/entity/account/accountEntity.test.data";
21
+ import MetadataGettingStartedSettingsEntity from "passbolt-styleguide/src/shared/models/entity/metadata/metadataGettingStartedSettingsEntity";
22
+ import {defaultMetadataGettingStartedSettingsDto, enableMetadataGettingStartedSettingsDto} from "passbolt-styleguide/src/shared/models/entity/metadata/metadataGettingStartedSettingsEntity.test.data";
23
+
24
+ describe("ConfigureMetadataSettingsService", () => {
25
+ describe("::enableEncryptedMetadataForNewInstance", () => {
26
+ it("should orchestrate all the necessary service in order to activate the encryption of metadata", async() => {
27
+ expect.assertions(8);
28
+
29
+ const passphrase = "ada@passbolt.com";
30
+ const account = new AccountEntity(defaultAccountDto());
31
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
32
+
33
+ const expectedKeySettings = MetadataKeysSettingsEntity.createFromDefault();
34
+ const expectedTypeSettings = MetadataTypesSettingsEntity.createFromV5Default();
35
+
36
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
37
+ jest.spyOn(orchestrator.generateMetadataKeyService, "generateKey");
38
+ jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => {});
39
+ jest.spyOn(orchestrator.saveMetadaSettingsService, "saveKeysSettings").mockImplementation(() => {});
40
+ jest.spyOn(orchestrator.saveMetadaSettingsService, "saveTypesSettings").mockImplementation(() => {});
41
+
42
+ await orchestrator.enableEncryptedMetadataForNewInstance(passphrase);
43
+
44
+ expect(orchestrator.generateMetadataKeyService.generateKey).toHaveBeenCalledTimes(1);
45
+ expect(orchestrator.generateMetadataKeyService.generateKey).toHaveBeenCalledWith(passphrase);
46
+
47
+ expect(orchestrator.createMetadataKeyService.create).toHaveBeenCalledTimes(1);
48
+ expect(orchestrator.createMetadataKeyService.create).toHaveBeenCalledWith(expect.any(ExternalGpgKeyPairEntity), passphrase);
49
+
50
+ expect(orchestrator.saveMetadaSettingsService.saveKeysSettings).toHaveBeenCalledTimes(1);
51
+ expect(orchestrator.saveMetadaSettingsService.saveKeysSettings).toHaveBeenCalledWith(expectedKeySettings);
52
+
53
+ expect(orchestrator.saveMetadaSettingsService.saveTypesSettings).toHaveBeenCalledTimes(1);
54
+ expect(orchestrator.saveMetadaSettingsService.saveTypesSettings).toHaveBeenCalledWith(expectedTypeSettings);
55
+ });
56
+
57
+ it("should not intercept errors if anything goes wrong and let the caller manage it: errors from the key generation", async() => {
58
+ expect.assertions(1);
59
+
60
+ const passphrase = "ada@passbolt.com";
61
+ const account = new AccountEntity(defaultAccountDto());
62
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
63
+
64
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
65
+ jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => { throw new Error("unexpected error"); });
66
+
67
+ await expect(() => orchestrator.enableEncryptedMetadataForNewInstance(passphrase)).rejects.toThrowError();
68
+ });
69
+
70
+ it("should not intercept errors if anything goes wrong and let the caller manage it: errors from the key save", async() => {
71
+ expect.assertions(1);
72
+
73
+ const passphrase = "ada@passbolt.com";
74
+ const account = new AccountEntity(defaultAccountDto());
75
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
76
+
77
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
78
+ jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => { throw new Error("unexpected error"); });
79
+
80
+ await expect(() => orchestrator.enableEncryptedMetadataForNewInstance(passphrase)).rejects.toThrowError();
81
+ });
82
+
83
+ it("should not intercept errors if anything goes wrong and let the caller manage it: errors from saving the key settings", async() => {
84
+ expect.assertions(1);
85
+
86
+ const passphrase = "ada@passbolt.com";
87
+ const account = new AccountEntity(defaultAccountDto());
88
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
89
+
90
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
91
+ jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => {});
92
+ jest.spyOn(orchestrator.saveMetadaSettingsService, "saveKeysSettings").mockImplementation(() => { throw new Error("unexpected error"); });
93
+
94
+ await expect(() => orchestrator.enableEncryptedMetadataForNewInstance(passphrase)).rejects.toThrowError();
95
+ });
96
+
97
+ it("should not intercept errors if anything goes wrong and let the caller manage it: errors from saving the types settings", async() => {
98
+ expect.assertions(1);
99
+
100
+ const passphrase = "ada@passbolt.com";
101
+ const account = new AccountEntity(defaultAccountDto());
102
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
103
+
104
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
105
+ jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => {});
106
+ jest.spyOn(orchestrator.saveMetadaSettingsService, "saveKeysSettings").mockImplementation(() => {});
107
+ jest.spyOn(orchestrator.saveMetadaSettingsService, "saveTypesSettings").mockImplementation(() => { throw new Error("unexpected error"); });
108
+
109
+ await expect(() => orchestrator.enableEncryptedMetadataForNewInstance(passphrase)).rejects.toThrowError();
110
+ });
111
+ });
112
+
113
+ describe("::enableEncryptedMetadataForExistingInstance", () => {
114
+ it("should orchestrate all the necessary service in order to activate the encryption of metadata", async() => {
115
+ expect.assertions(8);
116
+
117
+ const passphrase = "ada@passbolt.com";
118
+ const account = new AccountEntity(defaultAccountDto());
119
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
120
+
121
+ const expectedKeySettings = MetadataKeysSettingsEntity.createFromDefault();
122
+ const expectedTypeSettings = MetadataTypesSettingsEntity.createFromV5Default({
123
+ allow_v4_v5_upgrade: true
124
+ });
125
+
126
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
127
+ jest.spyOn(orchestrator.generateMetadataKeyService, "generateKey");
128
+ jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => {});
129
+ jest.spyOn(orchestrator.saveMetadaSettingsService, "saveKeysSettings").mockImplementation(() => {});
130
+ jest.spyOn(orchestrator.saveMetadaSettingsService, "saveTypesSettings").mockImplementation(() => {});
131
+ jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
132
+
133
+ await orchestrator.enableEncryptedMetadataForExistingInstance(passphrase);
134
+
135
+ expect(orchestrator.generateMetadataKeyService.generateKey).toHaveBeenCalledTimes(1);
136
+ expect(orchestrator.generateMetadataKeyService.generateKey).toHaveBeenCalledWith(passphrase);
137
+
138
+ expect(orchestrator.createMetadataKeyService.create).toHaveBeenCalledTimes(1);
139
+ expect(orchestrator.createMetadataKeyService.create).toHaveBeenCalledWith(expect.any(ExternalGpgKeyPairEntity), passphrase);
140
+
141
+ expect(orchestrator.saveMetadaSettingsService.saveKeysSettings).toHaveBeenCalledTimes(1);
142
+ expect(orchestrator.saveMetadaSettingsService.saveKeysSettings).toHaveBeenCalledWith(expectedKeySettings);
143
+
144
+ expect(orchestrator.saveMetadaSettingsService.saveTypesSettings).toHaveBeenCalledTimes(1);
145
+ expect(orchestrator.saveMetadaSettingsService.saveTypesSettings).toHaveBeenCalledWith(expectedTypeSettings);
146
+ });
147
+
148
+ it("should not intercept errors if anything goes wrong and let the caller manage it: errors from the key generation", async() => {
149
+ expect.assertions(1);
150
+
151
+ const passphrase = "ada@passbolt.com";
152
+ const account = new AccountEntity(defaultAccountDto());
153
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
154
+
155
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
156
+ jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => { throw new Error("unexpected error"); });
157
+ jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
158
+
159
+ await expect(() => orchestrator.enableEncryptedMetadataForExistingInstance(passphrase)).rejects.toThrowError();
160
+ });
161
+
162
+ it("should not intercept errors if anything goes wrong and let the caller manage it: errors from the key save", async() => {
163
+ expect.assertions(1);
164
+
165
+ const passphrase = "ada@passbolt.com";
166
+ const account = new AccountEntity(defaultAccountDto());
167
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
168
+
169
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
170
+ jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => { throw new Error("unexpected error"); });
171
+ jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
172
+
173
+ await expect(() => orchestrator.enableEncryptedMetadataForExistingInstance(passphrase)).rejects.toThrowError();
174
+ });
175
+
176
+ it("should not intercept errors if anything goes wrong and let the caller manage it: errors from saving the key settings", async() => {
177
+ expect.assertions(1);
178
+
179
+ const passphrase = "ada@passbolt.com";
180
+ const account = new AccountEntity(defaultAccountDto());
181
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
182
+
183
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
184
+ jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => {});
185
+ jest.spyOn(orchestrator.saveMetadaSettingsService, "saveKeysSettings").mockImplementation(() => { throw new Error("unexpected error"); });
186
+ jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
187
+
188
+ await expect(() => orchestrator.enableEncryptedMetadataForExistingInstance(passphrase)).rejects.toThrowError();
189
+ });
190
+
191
+ it("should not intercept errors if anything goes wrong and let the caller manage it: errors from saving the types settings", async() => {
192
+ expect.assertions(1);
193
+
194
+ const passphrase = "ada@passbolt.com";
195
+ const account = new AccountEntity(defaultAccountDto());
196
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
197
+
198
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
199
+ jest.spyOn(orchestrator.createMetadataKeyService, "create").mockImplementation(() => {});
200
+ jest.spyOn(orchestrator.saveMetadaSettingsService, "saveKeysSettings").mockImplementation(() => {});
201
+ jest.spyOn(orchestrator.saveMetadaSettingsService, "saveTypesSettings").mockImplementation(() => { throw new Error("unexpected error"); });
202
+ jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
203
+
204
+ await expect(() => orchestrator.enableEncryptedMetadataForExistingInstance(passphrase)).rejects.toThrowError();
205
+ });
206
+
207
+ it("should not proceed if a strategy has already been defined", async() => {
208
+ expect.assertions(1);
209
+
210
+ const passphrase = "ada@passbolt.com";
211
+ const account = new AccountEntity(defaultAccountDto());
212
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
213
+
214
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
215
+ jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(defaultMetadataGettingStartedSettingsDto()));
216
+
217
+ await expect(() => orchestrator.enableEncryptedMetadataForExistingInstance(passphrase)).rejects.toThrowError();
218
+ });
219
+ });
220
+
221
+ describe("::keepCleartextMetadataForExistingInstance", () => {
222
+ it("should orchestrate all the necessary service in order to deactivate the encryption of metadata", async() => {
223
+ expect.assertions(2);
224
+
225
+ const account = new AccountEntity(defaultAccountDto());
226
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
227
+
228
+ const expectedTypeSettings = MetadataTypesSettingsEntity.createFromV4Default();
229
+
230
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
231
+ jest.spyOn(orchestrator.saveMetadaSettingsService, "saveTypesSettings").mockImplementation(() => {});
232
+ jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
233
+
234
+ await orchestrator.keepCleartextMetadataForExistingInstance();
235
+
236
+ expect(orchestrator.saveMetadaSettingsService.saveTypesSettings).toHaveBeenCalledTimes(1);
237
+ expect(orchestrator.saveMetadaSettingsService.saveTypesSettings).toHaveBeenCalledWith(expectedTypeSettings);
238
+ });
239
+
240
+ it("should not intercept errors if anything goes wrong and let the caller manage it: errors from saving the types settings", async() => {
241
+ expect.assertions(1);
242
+
243
+ const account = new AccountEntity(defaultAccountDto());
244
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
245
+
246
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
247
+ jest.spyOn(orchestrator.saveMetadaSettingsService, "saveTypesSettings").mockImplementation(() => { throw new Error("unexpected error"); });
248
+ jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(enableMetadataGettingStartedSettingsDto()));
249
+
250
+ await expect(() => orchestrator.keepCleartextMetadataForExistingInstance()).rejects.toThrowError();
251
+ });
252
+
253
+ it("should not intercept errors if anything goes wrong and let the caller manage it: errors from saving the types settings", async() => {
254
+ expect.assertions(1);
255
+
256
+ const account = new AccountEntity(defaultAccountDto());
257
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
258
+
259
+ const orchestrator = new ConfigureMetadataSettingsService(account, apiClientOptions);
260
+ jest.spyOn(orchestrator.findMetadataGettingStartedSettingsService, "findGettingStartedSettings").mockImplementation(() => new MetadataGettingStartedSettingsEntity(defaultMetadataGettingStartedSettingsDto()));
261
+
262
+ await expect(() => orchestrator.keepCleartextMetadataForExistingInstance()).rejects.toThrowError();
263
+ });
264
+ });
265
+ });
@@ -49,7 +49,7 @@ export default class CreateMetadataKeyService {
49
49
  * Note: the service does not handle yet the zero knowledge, the key will be encrypted for the API.
50
50
  * @param {ExternalGpgKeyPairEntity} metadataKeyPair The metadata key pair.
51
51
  * @param {string} passphrase The user passphrase.
52
- * @return {MetadataKeyEntity}
52
+ * @returns {Promise<MetadataKeyEntity>}
53
53
  * @throws {TypeError} if metadataKeyPair argument is not of the expected type
54
54
  * @throws {TypeError} if passphrase argument is not a string
55
55
  */
@@ -17,7 +17,6 @@ import MetadataPrivateKeyEntity from "passbolt-styleguide/src/shared/models/enti
17
17
  import MetadataPrivateKeyDataEntity from "passbolt-styleguide/src/shared/models/entity/metadata/metadataPrivateKeyDataEntity";
18
18
  import MetadataPrivateKeysCollection from "passbolt-styleguide/src/shared/models/entity/metadata/metadataPrivateKeysCollection";
19
19
  import MetadataKeysCollection from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysCollection";
20
- import UserPassphraseRequiredError from "passbolt-styleguide/src/shared/error/userPassphraseRequiredError";
21
20
  import {assertType} from '../../utils/assertions';
22
21
  import DecryptPrivateKeyService from '../crypto/decryptPrivateKeyService';
23
22
  import DecryptMessageService from '../crypto/decryptMessageService';
@@ -53,7 +52,7 @@ class DecryptMetadataPrivateKeysService {
53
52
 
54
53
  const message = await OpenpgpAssertion.readMessageOrFail(metadataPrivateKeyEntity.data);
55
54
 
56
- passphrase = passphrase || await this.getPassphraseFromSessionStorageOrFail();
55
+ passphrase = passphrase || await PassphraseStorageService.getOrFail();
57
56
 
58
57
  const userDecryptedPrivateArmoredKey = await DecryptPrivateKeyService.decryptArmoredKey(this.account.userPrivateArmoredKey, passphrase);
59
58
  const userPublicKey = await OpenpgpAssertion.readKeyOrFail(this.account.userPublicArmoredKey);
@@ -88,7 +87,7 @@ class DecryptMetadataPrivateKeysService {
88
87
  async decryptAll(metadataPrivateKeysCollection, passphrase = null) {
89
88
  assertType(metadataPrivateKeysCollection, MetadataPrivateKeysCollection, "The given collection is not of the type MetadataPrivateKeysCollection");
90
89
 
91
- passphrase = passphrase || await this.getPassphraseFromSessionStorageOrFail();
90
+ passphrase = passphrase || await PassphraseStorageService.getOrFail();
92
91
 
93
92
  const items = metadataPrivateKeysCollection.items;
94
93
  for (let i = 0; i < items.length; i++) {
@@ -119,26 +118,11 @@ class DecryptMetadataPrivateKeysService {
119
118
  if (!metadataPrivateKeysCollection || !metadataPrivateKeysCollection.length || !metadataKeysCollection?.hasEncryptedKeys()) {
120
119
  continue;
121
120
  }
122
- passphrase = passphrase || await this.getPassphraseFromSessionStorageOrFail();
121
+ passphrase = passphrase || await PassphraseStorageService.getOrFail();
123
122
  await this.decryptAll(metadataPrivateKeysCollection, passphrase);
124
123
  }
125
124
  }
126
125
 
127
- /**
128
- * Retrieve the user passphrase from the session storage or fail.
129
- *
130
- * @returns {Promise<string>}
131
- * @throws {UserPassphraseRequiredError} if the `passphrase` cannot be retrieved.
132
- * @private
133
- */
134
- async getPassphraseFromSessionStorageOrFail() {
135
- const passphrase = await PassphraseStorageService.get();
136
- if (!passphrase) {
137
- throw new UserPassphraseRequiredError();
138
- }
139
- return passphrase;
140
- }
141
-
142
126
  /**
143
127
  * Verify the metadata private key entity fingerprint is equal to the armored key fingerprint.
144
128
  * @param {MetadataPrivateKeyEntity} metadataPrivateKeyEntity the metadata private key entity to decrypt.
@@ -87,12 +87,13 @@ class DecryptMetadataService {
87
87
 
88
88
  try {
89
89
  sessionKeys = await this.getOrFindSessionKeysService.getOrFindAllByForeignModelAndForeignIds("Resource", collection.ids, passphrase);
90
- for (const sessionKey of sessionKeys) {
90
+ for (let i = sessionKeys.items.length - 1; i >= 0; i--) {
91
+ const sessionKey = sessionKeys.items[i];
91
92
  try {
92
93
  const entity = collection.getFirst("id", sessionKey.foreignId);
93
94
  await this.decryptMetadataWithSessionKey(entity, sessionKey.sessionKey);
94
95
  } catch (error) {
95
- sessionKeys.remove(sessionKey);
96
+ sessionKeys.items.splice(i, 1);
96
97
  console.debug(`Metadata of the entity "${sessionKey.foreignModel}:${sessionKey.foreignId}" cannot be decrypted with session key.`, {cause: error});
97
98
  }
98
99
  }
@@ -267,7 +268,8 @@ class DecryptMetadataService {
267
268
  return {
268
269
  foreign_model: "Resource",
269
270
  foreign_id: entity.id,
270
- session_key: sessionKeyString
271
+ session_key: sessionKeyString,
272
+ modified: entity.modified
271
273
  };
272
274
  }
273
275
 
@@ -31,7 +31,6 @@ import {
31
31
  import SessionKeysCollection from "passbolt-styleguide/src/shared/models/entity/sessionKey/sessionKeysCollection";
32
32
  import {metadata} from "passbolt-styleguide/test/fixture/encryptedMetadata/metadata";
33
33
  import {defaultSessionKeyDto} from "passbolt-styleguide/src/shared/models/entity/sessionKey/sessionKeyEntity.test.data";
34
- import SessionKeyEntity from "passbolt-styleguide/src/shared/models/entity/sessionKey/sessionKeyEntity";
35
34
  import ResourceEntity from "../../model/entity/resource/resourceEntity";
36
35
  import {defaultResourceDto} from "passbolt-styleguide/src/shared/models/entity/resource/resourceEntity.test.data";
37
36
  import EntityValidationError from "passbolt-styleguide/src/shared/models/entity/abstract/entityValidationError";
@@ -396,8 +395,8 @@ describe("DecryptMetadataService", () => {
396
395
  await expect(service.decryptAllFromForeignModels(collection, pgpKeys.ada.passphrase, {ignoreDecryptionError: true})).resolves.toBeUndefined();
397
396
  });
398
397
 
399
- it("should remove the invalid session keys from the collection", async() => {
400
- expect.assertions(3);
398
+ it("should not update the session storage with the session keys when discovering a new session key if not specifically requested", async() => {
399
+ expect.assertions(1);
401
400
 
402
401
  const metadataKeysDtos = defaultDecryptedSharedMetadataKeysDtos();
403
402
  const metadataKeys = new MetadataKeysCollection(metadataKeysDtos);
@@ -405,29 +404,24 @@ describe("DecryptMetadataService", () => {
405
404
  metadata_key_id: metadataKeysDtos[0].id
406
405
  });
407
406
  const collection = new ResourcesCollection(collectionDto);
408
- const sessionsKeysForeignIds = collection.items.map(resource => ({foreign_id: resource.id}));
409
- const sessionKeysCount = collection.length;
410
- const sessionKeysDtos = sharedResourcesSessionKeys(sessionsKeysForeignIds, {count: sessionKeysCount});
411
407
 
412
- //invalid session key
413
- sessionKeysDtos[3] = defaultSessionKeyDto({...sessionKeysDtos[3], session_key: "9:901D6ED579AFF935F9F157A5198BCE48B50AD87345DEADBA06F42C5D018C78CC"});
414
- const invalidSessionKeyEntity = new SessionKeyEntity(sessionKeysDtos[3]);
415
408
 
409
+ const sessionsKeysForeignIds = collection.items.map(resource => ({foreign_id: resource.id}));
410
+ const sessionKeysDtos = sharedResourcesSessionKeys(sessionsKeysForeignIds, {count: collection.length});
411
+ sessionKeysDtos[3] = defaultSessionKeyDto({...sessionKeysDtos[3], session_key: "9:901D6ED579AFF935F9F157A5198BCE48B50AD87345DEADBA06F42C5D018C78CC"});
416
412
  const sessionKeys = new SessionKeysCollection(sessionKeysDtos);
417
413
 
418
- jest.spyOn(sessionKeys, "remove");
414
+ jest.spyOn(service.saveSessionKeysService, "save");
419
415
  jest.spyOn(service.getOrFindMetadataKeysService, "getOrFindAll").mockImplementation(() => metadataKeys);
420
416
  jest.spyOn(service.getOrFindSessionKeysService, "getOrFindAllByForeignModelAndForeignIds").mockImplementation(() => sessionKeys);
421
417
 
422
418
  await service.decryptAllFromForeignModels(collection);
423
419
 
424
- expect(sessionKeys.remove).toHaveBeenCalledTimes(1);
425
- expect(sessionKeys.remove).toHaveBeenCalledWith(invalidSessionKeyEntity);
426
- expect(sessionKeys.length).toStrictEqual(sessionKeysCount - 1);
420
+ expect(service.saveSessionKeysService.save).not.toHaveBeenCalled();
427
421
  });
428
422
 
429
- it("should not update the session storage with the session keys", async() => {
430
- expect.assertions(1);
423
+ it("should update the session storage with the session keys when a new session key is discovered if the option `updateSessionKeys` is passed", async() => {
424
+ expect.assertions(3);
431
425
 
432
426
  const metadataKeysDtos = defaultDecryptedSharedMetadataKeysDtos();
433
427
  const metadataKeys = new MetadataKeysCollection(metadataKeysDtos);
@@ -436,23 +430,28 @@ describe("DecryptMetadataService", () => {
436
430
  });
437
431
  const collection = new ResourcesCollection(collectionDto);
438
432
 
439
-
440
433
  const sessionsKeysForeignIds = collection.items.map(resource => ({foreign_id: resource.id}));
441
434
  const sessionKeysDtos = sharedResourcesSessionKeys(sessionsKeysForeignIds, {count: collection.length});
442
- sessionKeysDtos[3] = defaultSessionKeyDto({...sessionKeysDtos[3], session_key: "9:901D6ED579AFF935F9F157A5198BCE48B50AD87345DEADBA06F42C5D018C78CC"});
435
+ const sessionKeyDiscovered = sessionKeysDtos[3];
436
+ sessionKeysDtos.splice(3, 1);
443
437
  const sessionKeys = new SessionKeysCollection(sessionKeysDtos);
438
+ sessionKeyDiscovered.modified = collection.resources[3].modified;
439
+ const expectedSessionKeysDto = [...sessionKeysDtos, sessionKeyDiscovered];
444
440
 
445
441
  jest.spyOn(service.saveSessionKeysService, "save");
446
442
  jest.spyOn(service.getOrFindMetadataKeysService, "getOrFindAll").mockImplementation(() => metadataKeys);
447
443
  jest.spyOn(service.getOrFindSessionKeysService, "getOrFindAllByForeignModelAndForeignIds").mockImplementation(() => sessionKeys);
448
444
 
449
- await service.decryptAllFromForeignModels(collection);
445
+ await service.decryptAllFromForeignModels(collection, null, {updateSessionKeys: true});
450
446
 
451
- expect(service.saveSessionKeysService.save).not.toHaveBeenCalled();
447
+ const [[savedSessionKeys, passphraseArg]] = service.saveSessionKeysService.save.mock.calls;
448
+ expect(service.saveSessionKeysService.save).toHaveBeenCalledTimes(1);
449
+ expect(savedSessionKeys.toDto()).toEqual(expectedSessionKeysDto);
450
+ expect(passphraseArg).toBe(null);
452
451
  });
453
452
 
454
- it("should update the session storage with the session keys if the option `updateSessionKeys` is passed", async() => {
455
- expect.assertions(2);
453
+ it("should remove invalid session key and add newly discovered to the list of session keys to save", async() => {
454
+ expect.assertions(3);
456
455
 
457
456
  const metadataKeysDtos = defaultDecryptedSharedMetadataKeysDtos();
458
457
  const metadataKeys = new MetadataKeysCollection(metadataKeysDtos);
@@ -461,11 +460,17 @@ describe("DecryptMetadataService", () => {
461
460
  });
462
461
  const collection = new ResourcesCollection(collectionDto);
463
462
 
464
-
465
463
  const sessionsKeysForeignIds = collection.items.map(resource => ({foreign_id: resource.id}));
466
464
  const sessionKeysDtos = sharedResourcesSessionKeys(sessionsKeysForeignIds, {count: collection.length});
467
- sessionKeysDtos[3] = defaultSessionKeyDto({...sessionKeysDtos[3], session_key: "9:901D6ED579AFF935F9F157A5198BCE48B50AD87345DEADBA06F42C5D018C78CC"});
465
+ const sessionKeyDiscovered = sessionKeysDtos[3]; // Copy the working session key.
466
+ sessionKeysDtos[3] = JSON.parse(JSON.stringify(sessionKeysDtos[3]));
467
+ sessionKeysDtos[3].session_key = "9:901D6ED579AFF935F9F157A5198BCE48B50AD87345DEADBA06F42C5D018C78CC"; // Replace session key with a non working one
468
468
  const sessionKeys = new SessionKeysCollection(sessionKeysDtos);
469
+ // Expected sessions keys arry.
470
+ sessionKeyDiscovered.modified = collection.resources[3].modified;
471
+ const expectedSessionKeysDto = JSON.parse(JSON.stringify(sessionKeysDtos));
472
+ expectedSessionKeysDto.splice(3, 1);
473
+ expectedSessionKeysDto.push(sessionKeyDiscovered);
469
474
 
470
475
  jest.spyOn(service.saveSessionKeysService, "save");
471
476
  jest.spyOn(service.getOrFindMetadataKeysService, "getOrFindAll").mockImplementation(() => metadataKeys);
@@ -473,8 +478,10 @@ describe("DecryptMetadataService", () => {
473
478
 
474
479
  await service.decryptAllFromForeignModels(collection, null, {updateSessionKeys: true});
475
480
 
481
+ const [[savedSessionKeys, passphraseArg]] = service.saveSessionKeysService.save.mock.calls;
476
482
  expect(service.saveSessionKeysService.save).toHaveBeenCalledTimes(1);
477
- expect(service.saveSessionKeysService.save).toHaveBeenCalledWith(sessionKeys, null);
483
+ expect(savedSessionKeys.toDto()).toEqual(expectedSessionKeysDto);
484
+ expect(passphraseArg).toBe(null);
478
485
  });
479
486
  });
480
487
 
@@ -12,7 +12,6 @@
12
12
  * @since 4.10.0
13
13
  */
14
14
  import PassphraseStorageService from '../session_storage/passphraseStorageService';
15
- import UserPassphraseRequiredError from "passbolt-styleguide/src/shared/error/userPassphraseRequiredError";
16
15
  import GetOrFindMetadataKeysService from "./getOrFindMetadataKeysService";
17
16
  import EncryptMessageService from "../crypto/encryptMessageService";
18
17
  import {OpenpgpAssertion} from "../../utils/openpgp/openpgpAssertions";
@@ -70,7 +69,7 @@ class EncryptMetadataService {
70
69
  // Prevent future issue if an encrypted metadata is stored without object_type, this will fail the decryption validation of the entity
71
70
  this.assertValidMetadataObjectType(entity);
72
71
 
73
- passphrase = passphrase || await this.getPassphraseFromLocalStorageOrFail();
72
+ passphrase = passphrase || await PassphraseStorageService.getOrFail();
74
73
  const userPrivateKey = await DecryptPrivateKeyService.decryptArmoredKey(this.account.userPrivateArmoredKey, passphrase);
75
74
  const serializedMetadata = JSON.stringify(entity.metadata.toDto(entity.metadata.constructor.DEFAULT_CONTAIN));
76
75
 
@@ -116,7 +115,7 @@ class EncryptMetadataService {
116
115
  }
117
116
 
118
117
  const canUsePersonalKeys = await this.allowUsageOfPersonalKeys();
119
- passphrase = passphrase || await this.getPassphraseFromLocalStorageOrFail();
118
+ passphrase = passphrase || await PassphraseStorageService.getOrFail();
120
119
 
121
120
  const userDecryptedPrivateKey = await DecryptPrivateKeyService.decryptArmoredKey(this.account.userPrivateArmoredKey, passphrase);
122
121
 
@@ -222,21 +221,6 @@ class EncryptMetadataService {
222
221
  return {metadataKeyId, metadataPublicKey, metadataPrivateKey};
223
222
  }
224
223
 
225
- /**
226
- * Retrieve the user passphrase from the local storage or fail.
227
- *
228
- * @returns {Promise<string>}
229
- * @throws {UserPassphraseRequiredError} if the `passphrase` is not set and cannot be retrieved.
230
- * @private
231
- */
232
- async getPassphraseFromLocalStorageOrFail() {
233
- const passphrase = await PassphraseStorageService.get();
234
- if (!passphrase) {
235
- throw new UserPassphraseRequiredError();
236
- }
237
- return passphrase;
238
- }
239
-
240
224
  /**
241
225
  * Allow usage of personal keys
242
226
  * @returns {Promise<boolean>}
@@ -14,6 +14,7 @@
14
14
  import FindMetadataKeysService from "./findMetadataKeysService";
15
15
  import MetadataKeysSessionStorage from "../session_storage/metadataKeysSessionStorage";
16
16
  import MetadataKeysCollection from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysCollection";
17
+ import DecryptMetadataPrivateKeysService from "./decryptMetadataPrivateKeysService";
17
18
 
18
19
  const FIND_AND_UPDATE_METADATA_KEYS_SS_LOCK_PREFIX = "FIND_AND_UPDATE_METADATA_KEYS_SS_LOCK-";
19
20
 
@@ -28,8 +29,9 @@ export default class FindAndUpdateMetadataKeysSessionStorageService {
28
29
  */
29
30
  constructor(account, apiClientOptions) {
30
31
  this.account = account;
31
- this.findMetadataKeysService = new FindMetadataKeysService(apiClientOptions, account);
32
+ this.findMetadataKeysService = new FindMetadataKeysService(apiClientOptions);
32
33
  this.metadataKeysSessionStorage = new MetadataKeysSessionStorage(account);
34
+ this.decryptMetadataPrivateKeysService = new DecryptMetadataPrivateKeysService(account);
33
35
  }
34
36
 
35
37
  /**
@@ -51,7 +53,8 @@ export default class FindAndUpdateMetadataKeysSessionStorageService {
51
53
  }
52
54
 
53
55
  // Lock is granted, retrieve the metadata keys and update the session storage.
54
- const metadataKeys = await this.findMetadataKeysService.findAllForSessionStorage(passphrase);
56
+ const metadataKeys = await this.findMetadataKeysService.findAllForSessionStorage();
57
+ await this.decryptMetadataPrivateKeysService.decryptAllFromMetadataKeysCollection(metadataKeys, passphrase);
55
58
  await this.metadataKeysSessionStorage.set(metadataKeys);
56
59
  return metadataKeys;
57
60
  });
@@ -16,9 +16,6 @@ import AccountEntity from "../../model/entity/account/accountEntity";
16
16
  import {defaultAccountDto} from "../../model/entity/account/accountEntity.test.data";
17
17
  import {defaultApiClientOptions} from "passbolt-styleguide/src/shared/lib/apiClient/apiClientOptions.test.data";
18
18
  import FindAndUpdateMetadataKeysSessionStorageService from "./findAndUpdateMetadataKeysSessionStorageService";
19
- import {
20
- defaultMetadataKeysDtos
21
- } from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysCollection.test.data";
22
19
  import UserPassphraseRequiredError from "passbolt-styleguide/src/shared/error/userPassphraseRequiredError";
23
20
  import PassphraseStorageService from "../session_storage/passphraseStorageService";
24
21
  import {pgpKeys} from "passbolt-styleguide/test/fixture/pgpKeys/keys";
@@ -49,13 +46,15 @@ describe("FindAndUpdateMetadataKeysSessionStorageService", () => {
49
46
  describe("::findAndUpdateAll", () => {
50
47
  it("should throw an error if the user passphrase is not set and is required", async() => {
51
48
  expect.assertions(1);
52
- const metadataKeysDto = defaultMetadataKeysDtos(1, {}, {withMetadataPrivateKeys: true});
49
+ const id = uuidv4();
50
+ const metadataPrivateKeysDto = [defaultMetadataPrivateKeyDto({metadata_key_id: id, data: pgpKeys.metadataKey.encryptedMetadataPrivateKeyDataMessage})];
51
+ const metadataKeysDto = [defaultMetadataKeyDto({id: id, metadata_private_keys: metadataPrivateKeysDto, fingerprint: "c0dce0aaea4d8cce961c26bddfb6e74e598f025c"})];
53
52
  jest.spyOn(findAndUpdateKeysSessionStorageService.findMetadataKeysService.metadataKeysApiService, "findAll").mockImplementation(() => metadataKeysDto);
54
53
 
55
54
  await expect(() => findAndUpdateKeysSessionStorageService.findAndUpdateAll()).rejects.toThrow(UserPassphraseRequiredError);
56
55
  });
57
56
 
58
- it("retrieves the metadata keys from the API and store them into the session storage using the passphrase from the session storage.", async() => {
57
+ it("retrieves the metadata keys from the API and store them into the session storage and decrypt them using the passphrase from the session storage.", async() => {
59
58
  expect.assertions(7);
60
59
 
61
60
  const id = uuidv4();
@@ -97,7 +96,6 @@ describe("FindAndUpdateMetadataKeysSessionStorageService", () => {
97
96
  expect(PassphraseStorageService.get).not.toHaveBeenCalled();
98
97
  });
99
98
 
100
-
101
99
  it("overrides session storage with a second update call.", async() => {
102
100
  expect.assertions(2);
103
101