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,40 @@
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 AbstractService from "../abstract/abstractService";
16
+ import PassboltResponseEntity from "passbolt-styleguide/src/shared/models/entity/apiService/PassboltResponseEntity";
17
+
18
+ const METADATA_SETUP_RESOURCE_NAME = "metadata/setup/";
19
+
20
+ export default class MetadataSetupSettingsApiService extends AbstractService {
21
+ /**
22
+ * @constructor
23
+ * @param {ApiClientOptions} apiClientOptions
24
+ * @public
25
+ */
26
+ constructor(apiClientOptions) {
27
+ super(apiClientOptions, METADATA_SETUP_RESOURCE_NAME);
28
+ }
29
+
30
+ /**
31
+ * Find the metadata setup settings on the Passbolt API
32
+ *
33
+ * @returns {Promise<PassboltResponseEntity>} the api response
34
+ * @public
35
+ */
36
+ async find() {
37
+ const response = await this.apiClient.get("settings");
38
+ return new PassboltResponseEntity(response);
39
+ }
40
+ }
@@ -0,0 +1,54 @@
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 {mockApiResponse} from '../../../../../../test/mocks/mockApiResponse';
16
+ import MetadataSetupSettingsApiService from "./metadataSetupSettingsApiService";
17
+ import {defaultApiClientOptions} from "passbolt-styleguide/src/shared/lib/apiClient/apiClientOptions.test.data";
18
+ import {enableMetadataSetupSettingsDto} from "passbolt-styleguide/src/shared/models/entity/metadata/metadataSetupSettingsEntity.test.data";
19
+ import PassboltResponseEntity from "passbolt-styleguide/src/shared/models/entity/apiService/PassboltResponseEntity";
20
+
21
+ beforeEach(() => {
22
+ jest.resetAllMocks();
23
+ enableFetchMocks();
24
+ });
25
+
26
+ describe("metadataSetupSettingsApiService", () => {
27
+ describe('::find', () => {
28
+ it("Should return a PassboltResponseEntity if everything goes well.", async() => {
29
+ expect.assertions(2);
30
+
31
+ const apiClientOptions = defaultApiClientOptions();
32
+ const service = new MetadataSetupSettingsApiService(apiClientOptions);
33
+ const expectedBodyResponse = enableMetadataSetupSettingsDto();
34
+
35
+ fetch.doMockOnceIf(/\/metadata\/setup\/settings\.json/, () => mockApiResponse(expectedBodyResponse));
36
+
37
+ const apiResult = await service.find();
38
+
39
+ expect(apiResult).toBeInstanceOf(PassboltResponseEntity);
40
+ expect(apiResult.body).toStrictEqual(expectedBodyResponse);
41
+ });
42
+
43
+ it("should throw an error if something goes wrong during the fetch", async() => {
44
+ expect.assertions(1);
45
+
46
+ const apiClientOptions = defaultApiClientOptions();
47
+ const service = new MetadataSetupSettingsApiService(apiClientOptions);
48
+
49
+ fetch.doMockOnceIf(/\/metadata\/setup\/settings\.json/, () => { throw new Error("Something went wrong"); });
50
+
51
+ await expect(() => service.find()).rejects.toThrowError();
52
+ });
53
+ });
54
+ });
@@ -44,7 +44,7 @@ class SetupService extends AbstractService {
44
44
  */
45
45
  async complete(userId, completeDto) {
46
46
  this.assertValidId(userId);
47
- const url = new URL(`${this.apiClient.baseUrl}/complete/${userId}`);
47
+ const url = this.apiClient.buildUrl(`${this.apiClient.baseUrl}/complete/${userId}`, {});
48
48
  const bodyString = this.apiClient.buildBody(completeDto);
49
49
  return this.apiClient.fetchAndHandleResponse('POST', url, bodyString);
50
50
  }
@@ -58,7 +58,7 @@ class SetupService extends AbstractService {
58
58
  */
59
59
  async completeRecover(userId, completeDto) {
60
60
  this.assertValidId(userId);
61
- const url = new URL(`${this.apiClient.baseUrl}/recover/complete/${userId}`);
61
+ const url = this.apiClient.buildUrl(`${this.apiClient.baseUrl}/recover/complete/${userId}`, {});
62
62
  const bodyString = this.apiClient.buildBody(completeDto);
63
63
  return this.apiClient.fetchAndHandleResponse('POST', url, bodyString);
64
64
  }
@@ -0,0 +1,132 @@
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 {v4 as uuidv4} from "uuid";
15
+ import {enableFetchMocks} from "jest-fetch-mock";
16
+ import {mockApiResponse, mockApiResponseError} from "passbolt-styleguide/test/mocks/mockApiResponse";
17
+ import PassboltApiFetchError from "passbolt-styleguide/src/shared/lib/Error/PassboltApiFetchError";
18
+ import PassboltServiceUnavailableError from "passbolt-styleguide/src/shared/lib/Error/PassboltServiceUnavailableError";
19
+ import SetupService from "./setupService";
20
+ import BuildApiClientOptionsService from "../../account/buildApiClientOptionsService";
21
+ import AccountEntity from "../../../model/entity/account/accountEntity";
22
+ import {defaultAccountDto} from "../../../model/entity/account/accountEntity.test.data";
23
+ import {initialAccountAccountRecoveryDto} from "../../../model/entity/account/accountAccountRecoveryEntity.test.data";
24
+ import {startAccountSetupDto} from "../../../model/entity/account/accountSetupEntity.test.data";
25
+
26
+ describe("SetupService", () => {
27
+ let service, apiClientOptions, userId,
28
+ accountRecoveryDto, setupCompleteDto;
29
+
30
+ beforeEach(() => {
31
+ enableFetchMocks();
32
+ fetch.resetMocks();
33
+ const account = new AccountEntity(defaultAccountDto());
34
+ apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
35
+ service = new SetupService(apiClientOptions);
36
+
37
+ userId = uuidv4();
38
+ });
39
+
40
+ describe("::complete", () => {
41
+ beforeEach(() => {
42
+ setupCompleteDto = startAccountSetupDto();
43
+ });
44
+
45
+ it("calls the complete API with correct URL", async() => {
46
+ expect.assertions(2);
47
+
48
+ fetch.doMockOnceIf(new RegExp(`/complete/${userId}`), () => mockApiResponse({success: true}));
49
+
50
+ await service.complete(userId, setupCompleteDto);
51
+
52
+ const lastCall = fetch.mock.calls[0];
53
+ const [url, options] = lastCall;
54
+
55
+ expect(url).toMatch(`/complete/${userId}.json`);
56
+ expect(options.method).toBe("POST");
57
+ });
58
+
59
+ it("throws API error if API returns an error", async() => {
60
+ expect.assertions(1);
61
+
62
+ fetch.mockResponseOnce(async() => {
63
+ const mockResponse = await mockApiResponseError(400, "Invalid request", {});
64
+ return {
65
+ status: mockResponse.status,
66
+ body: mockResponse.body,
67
+ headers: {"Content-Type": "application/json"}
68
+ };
69
+ });
70
+
71
+ await expect(service.complete(userId, setupCompleteDto)).rejects.toThrow(PassboltApiFetchError);
72
+ });
73
+
74
+ it("throws service unavailable error on unexpected failure", async() => {
75
+ expect.assertions(1);
76
+ fetch.mockImplementationOnce(() => { throw new Error("Service Down"); });
77
+
78
+ await expect(() => service.complete(userId, setupCompleteDto)).rejects.toThrow(PassboltServiceUnavailableError);
79
+ });
80
+
81
+ it("throws an error if userId is invalid", async() => {
82
+ expect.assertions(1);
83
+ await expect(() => service.complete("invalid-id", setupCompleteDto)).rejects.toThrow(Error);
84
+ });
85
+ });
86
+
87
+ describe("::completeRecover", () => {
88
+ beforeEach(() => {
89
+ accountRecoveryDto = initialAccountAccountRecoveryDto();
90
+ });
91
+
92
+ it("calls the completeRecover API with correct URL", async() => {
93
+ expect.assertions(2);
94
+
95
+ fetch.doMockOnceIf(new RegExp(`/recover/complete/${userId}`), () => mockApiResponse({success: true}));
96
+
97
+ await service.completeRecover(userId, accountRecoveryDto);
98
+
99
+ const lastCall = fetch.mock.calls[0];
100
+ const [url, options] = lastCall;
101
+
102
+ expect(url).toMatch(`/recover/complete/${userId}.json`);
103
+ expect(options.method).toBe("POST");
104
+ });
105
+
106
+ it("throws API error if API returns an error", async() => {
107
+ expect.assertions(1);
108
+ fetch.mockResponseOnce(async() => {
109
+ const mockResponse = await mockApiResponseError(400, "Invalid request", {});
110
+ return {
111
+ status: mockResponse.status,
112
+ body: mockResponse.body,
113
+ headers: {"Content-Type": "application/json"}
114
+ };
115
+ });
116
+
117
+ await expect(() => service.completeRecover(userId, accountRecoveryDto)).rejects.toThrow(PassboltApiFetchError);
118
+ });
119
+
120
+ it("throws service unavailable error on unexpected failure", async() => {
121
+ expect.assertions(1);
122
+ fetch.mockImplementationOnce(() => { throw new Error("Service unavailable"); });
123
+
124
+ await expect(() => service.completeRecover(userId, accountRecoveryDto)).rejects.toThrow(PassboltServiceUnavailableError);
125
+ });
126
+
127
+ it("throws an error if userId is invalid", async() => {
128
+ expect.assertions(1);
129
+ await expect(() => service.completeRecover("invalid-id", accountRecoveryDto)).rejects.toThrow(Error);
130
+ });
131
+ });
132
+ });
@@ -15,7 +15,7 @@ import Log from "../../model/log";
15
15
  import ResourcesCollection from "../../model/entity/resource/resourcesCollection";
16
16
  import ResourceEntity from "../../model/entity/resource/resourceEntity";
17
17
  import Lock from "../../utils/lock";
18
- import {assertType, assertUuid} from "../../utils/assertions";
18
+ import {assertArrayUUID, assertType, assertUuid} from "../../utils/assertions";
19
19
  import PasswordExpiryResourceEntity from "../../model/entity/passwordExpiry/passwordExpiryResourceEntity";
20
20
 
21
21
  const lock = new Lock();
@@ -273,6 +273,30 @@ class ResourceLocalStorage {
273
273
  }
274
274
  }
275
275
 
276
+ /**
277
+ * Delete multiple resources in local storage by Id
278
+ * @param {Array<string>} resourceIds
279
+ */
280
+ static async deleteResources(resourceIds) {
281
+ assertArrayUUID(resourceIds);
282
+ await lock.acquire();
283
+ try {
284
+ const resources = await ResourceLocalStorage.get() || [];
285
+
286
+ if (resources.length > 0 && resourceIds.length > 0) {
287
+ const setOfResourceIds = new Set(resourceIds);
288
+
289
+ const filteredResources = resources.filter(resource => !setOfResourceIds.has(resource.id));
290
+
291
+ await browser.storage.local.set({resources: filteredResources});
292
+ ResourceLocalStorage._cachedData = filteredResources;
293
+ }
294
+ } finally {
295
+ lock.release();
296
+ }
297
+ }
298
+
299
+
276
300
  /*
277
301
  * =================================================
278
302
  * Static methods
@@ -600,4 +600,58 @@ describe("ResourceLocalStorage", () => {
600
600
  expect(ResourceLocalStorage._cachedData).toBeNull();
601
601
  });
602
602
  });
603
+
604
+ describe("::deleteResources", () => {
605
+ it("Should throw if no data passed as parameter", async() => {
606
+ expect.assertions(1);
607
+ const promise = ResourceLocalStorage.deleteResources();
608
+ await expect(promise).rejects.toThrow("The given parameter is not a valid array of uuid");
609
+ });
610
+
611
+ it("Should throw if the resourceIds parameter is not a valid entry", async() => {
612
+ expect.assertions(1);
613
+ const promise = ResourceLocalStorage.deleteResources(42);
614
+ await expect(promise).rejects.toThrow("he given parameter is not a valid array of uuid");
615
+ });
616
+
617
+ it("Should do nothing if the resource is not found in the local storage", async() => {
618
+ expect.assertions(2);
619
+ const resourceDto = defaultResourceDto();
620
+ const resourcesDtos = [resourceDto];
621
+ await browser.storage.local.set({[RESOURCES_LOCAL_STORAGE_KEY]: resourcesDtos});
622
+ await ResourceLocalStorage.deleteResources([uuidv4()]);
623
+ const localStorageData = await browser.storage.local.get([RESOURCES_LOCAL_STORAGE_KEY]);
624
+ expect(localStorageData[RESOURCES_LOCAL_STORAGE_KEY]).toEqual(expect.any(Array));
625
+ expect(localStorageData[RESOURCES_LOCAL_STORAGE_KEY]).toHaveLength(1);
626
+ });
627
+
628
+ it("Should update the resources", async() => {
629
+ expect.assertions(3);
630
+ const resourceDto1 = defaultResourceDto();
631
+ const resourceDto2 = defaultResourceDto();
632
+ const resourceDto3 = defaultResourceDto();
633
+ const resourcesDtos = [resourceDto1, resourceDto2, resourceDto3];
634
+ await browser.storage.local.set({[RESOURCES_LOCAL_STORAGE_KEY]: resourcesDtos});
635
+ await ResourceLocalStorage.deleteResources([resourceDto1.id, resourceDto2.id]);
636
+ const localStorageData = await browser.storage.local.get([RESOURCES_LOCAL_STORAGE_KEY]);
637
+ expect(localStorageData[RESOURCES_LOCAL_STORAGE_KEY]).toEqual(expect.any(Array));
638
+ expect(localStorageData[RESOURCES_LOCAL_STORAGE_KEY]).toHaveLength(1);
639
+ expect(localStorageData[RESOURCES_LOCAL_STORAGE_KEY][0]).toEqual(resourceDto3);
640
+ });
641
+
642
+ it("Should update cache after deleting the resources", async() => {
643
+ expect.assertions(5);
644
+ const resourceDto1 = defaultResourceDto();
645
+ const resourceDto2 = defaultResourceDto();
646
+ const resourceDto3 = defaultResourceDto();
647
+ const resourcesDtos = [resourceDto1, resourceDto2, resourceDto3];
648
+ await browser.storage.local.set({[RESOURCES_LOCAL_STORAGE_KEY]: resourcesDtos});
649
+ expect(ResourceLocalStorage.hasCachedData()).toBeFalsy();
650
+ await ResourceLocalStorage.deleteResources([resourceDto1.id, resourceDto2.id]);
651
+ expect(ResourceLocalStorage.hasCachedData()).toBeTruthy();
652
+ expect(ResourceLocalStorage._cachedData).toEqual(expect.any(Array));
653
+ expect(ResourceLocalStorage._cachedData).toHaveLength(1);
654
+ expect(ResourceLocalStorage._cachedData[0]).toEqual(resourceDto3);
655
+ });
656
+ });
603
657
  });
@@ -0,0 +1,100 @@
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 MetadataTypesSettingsEntity from "passbolt-styleguide/src/shared/models/entity/metadata/metadataTypesSettingsEntity";
15
+ import MetadataKeysSettingsEntity from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysSettingsEntity";
16
+ import GenerateMetadataKeyService from "./generateMetadataKeyService";
17
+ import CreateMetadataKeyService from "./createMetadataKeyService";
18
+ import SaveMetadataSettingsService from "./saveMetadataSettingsService";
19
+ import {assertString} from "../../utils/assertions";
20
+ import FindMetadataGettingStartedSettingsService from "passbolt-styleguide/src/shared/services/metadata/findMetadataGettingStartedSettingsService";
21
+
22
+ /**
23
+ * The service aims to orchestrate the enablement of the metadata encryption.
24
+ */
25
+ export default class ConfigureMetadataSettingsService {
26
+ /**
27
+ * @constructor
28
+ * @param {AccountEntity} account The user account
29
+ * @param {ApiClientOptions} apiClientOptions The api client options
30
+ */
31
+ constructor(account, apiClientOptions) {
32
+ this.generateMetadataKeyService = new GenerateMetadataKeyService(account);
33
+ this.createMetadataKeyService = new CreateMetadataKeyService(account, apiClientOptions);
34
+ this.saveMetadaSettingsService = new SaveMetadataSettingsService(account, apiClientOptions);
35
+ this.findMetadataGettingStartedSettingsService = new FindMetadataGettingStartedSettingsService(apiClientOptions);
36
+ }
37
+
38
+ /**
39
+ * Enables metadata encryption with confuguration that matches a new instance.
40
+ * @param {string} passphrase
41
+ * @return {Promise<void>}
42
+ * @throws {TypeError} if the `passphrase` is not a valid string
43
+ */
44
+ async enableEncryptedMetadataForNewInstance(passphrase) {
45
+ assertString(passphrase);
46
+
47
+ const gpgKeyPairEntity = await this.generateMetadataKeyService.generateKey(passphrase);
48
+ await this.createMetadataKeyService.create(gpgKeyPairEntity, passphrase);
49
+
50
+ const metadataKeySettings = MetadataKeysSettingsEntity.createFromDefault();
51
+ await this.saveMetadaSettingsService.saveKeysSettings(metadataKeySettings);
52
+
53
+ const metadataTypeSettings = MetadataTypesSettingsEntity.createFromV5Default();
54
+ await this.saveMetadaSettingsService.saveTypesSettings(metadataTypeSettings);
55
+ }
56
+
57
+ /**
58
+ * Enables metadata encryption with confuguration that matches an existing instance.
59
+ * @param {string} passphrase
60
+ * @return {Promise<void>}
61
+ * @throws {TypeError} if the `passphrase` is not a valid string
62
+ */
63
+ async enableEncryptedMetadataForExistingInstance(passphrase) {
64
+ await this.assertProcessIsEnabled();
65
+ assertString(passphrase);
66
+
67
+ const gpgKeyPairEntity = await this.generateMetadataKeyService.generateKey(passphrase);
68
+ await this.createMetadataKeyService.create(gpgKeyPairEntity, passphrase);
69
+
70
+ const metadataKeySettings = MetadataKeysSettingsEntity.createFromDefault();
71
+ await this.saveMetadaSettingsService.saveKeysSettings(metadataKeySettings);
72
+
73
+ const metadataTypeSettings = MetadataTypesSettingsEntity.createFromV5Default({
74
+ allow_v4_v5_upgrade: true,
75
+ });
76
+ await this.saveMetadaSettingsService.saveTypesSettings(metadataTypeSettings);
77
+ }
78
+
79
+ /**
80
+ * Configure metadata settings to keep legacy metadata in cleartext.
81
+ * @return {Promise<void>}
82
+ */
83
+ async keepCleartextMetadataForExistingInstance() {
84
+ await this.assertProcessIsEnabled();
85
+ const metadataTypeSettings = MetadataTypesSettingsEntity.createFromV4Default();
86
+ await this.saveMetadaSettingsService.saveTypesSettings(metadataTypeSettings);
87
+ }
88
+
89
+ /**
90
+ * Asserts that the process can be run before proceeding.
91
+ * @returns {Promise<void>}
92
+ * @throws {Error}
93
+ */
94
+ async assertProcessIsEnabled() {
95
+ const gettingStartedEntity = await this.findMetadataGettingStartedSettingsService.findGettingStartedSettings();
96
+ if (!gettingStartedEntity.enabled) {
97
+ throw new Error("The metadata encryption strategy has been already chosen.");
98
+ }
99
+ }
100
+ }