passbolt-browser-extension 5.2.0 → 5.3.2

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 (115) hide show
  1. package/CHANGELOG.md +79 -1
  2. package/Gruntfile.js +1 -1
  3. package/RELEASE_NOTES.md +27 -71
  4. package/doc/browser-extension-class-diagram.md +9 -0
  5. package/package.json +5 -5
  6. package/src/all/_locales/sl/messages.json +2 -2
  7. package/src/all/background_page/controller/clipboard/cancelClipboardContentFlushController.js +51 -0
  8. package/src/all/background_page/controller/clipboard/cancelClipboardContentFlushController.test.js +46 -0
  9. package/src/all/background_page/controller/clipboard/copyTemporarilyToClipboardController.js +53 -0
  10. package/src/all/background_page/controller/clipboard/copyTemporarilyToClipboardController.test.js +47 -0
  11. package/src/all/background_page/controller/clipboard/{clipboardController.js → copyToClipboardController.js} +8 -8
  12. package/src/all/background_page/controller/clipboard/copyToClipboardController.test.js +47 -0
  13. package/src/all/background_page/controller/extension/getExtensionVersionController.test.js +1 -1
  14. package/src/all/background_page/controller/metadata/getOrFindMetadataKeysSettingsController.js +53 -0
  15. package/src/all/background_page/controller/metadata/getOrFindMetadataKeysSettingsController.test.js +106 -0
  16. package/src/all/background_page/controller/resource/updateResourceLocalStorageByFolderParentIdController.js +70 -0
  17. package/src/all/background_page/controller/resource/updateResourceLocalStorageByFolderParentIdController.test.js +78 -0
  18. package/src/all/background_page/controller/share/shareOneFolderController.test.js +2 -1
  19. package/src/all/background_page/controller/share/shareResourcesController.test.js +1 -1
  20. package/src/all/background_page/controller/user/deleteDryRunUserController.js +73 -0
  21. package/src/all/background_page/controller/user/deleteDryRunUserController.test.js +129 -0
  22. package/src/all/background_page/controller/user/deleteUserController.js +76 -0
  23. package/src/all/background_page/controller/user/deleteUserController.test.js +141 -0
  24. package/src/all/background_page/event/actionLogEvents.js +5 -12
  25. package/src/all/background_page/event/appEvents.js +33 -0
  26. package/src/all/background_page/event/findAllForActionLogController.js +58 -0
  27. package/src/all/background_page/event/findAllForActionLogController.test.js +43 -0
  28. package/src/all/background_page/event/quickAccessEvents.js +32 -0
  29. package/src/all/background_page/event/resourceEvents.js +11 -0
  30. package/src/all/background_page/event/userEvents.js +7 -20
  31. package/src/all/background_page/event/webIntegrationEvents.js +11 -0
  32. package/src/all/background_page/model/actionLog/{actionLogModel.js → findActionLogService.js} +25 -5
  33. package/src/all/background_page/model/actionLog/findActionLogService.test.js +61 -0
  34. package/src/all/background_page/model/comment/commentModel.js +5 -5
  35. package/src/all/background_page/model/entity/actionLog/actionLogsCollection.test.data.js +18 -0
  36. package/src/all/background_page/model/entity/actionLog/defaultActionLogEntity.test.data.js +34 -0
  37. package/src/all/background_page/model/entity/resource/resourcesCollection.js +25 -0
  38. package/src/all/background_page/model/entity/resource/resourcesCollection.test.js +34 -0
  39. package/src/all/background_page/model/import/resources/resourcesKdbxImportParser.test.js +0 -1
  40. package/src/all/background_page/model/user/userModel.js +0 -60
  41. package/src/all/background_page/pagemod/appPagemod.js +0 -2
  42. package/src/all/background_page/pagemod/appPagemod.test.js +2 -6
  43. package/src/all/background_page/service/alarm/globalAlarmService.js +2 -0
  44. package/src/all/background_page/service/api/actionLog/{actionLogService.js → actionLogApiService.js} +5 -4
  45. package/src/all/background_page/service/api/actionLog/actionLogApiService.test.js +55 -0
  46. package/src/all/background_page/service/api/comment/{commentService.js → commentApiService.js} +6 -7
  47. package/src/all/background_page/service/api/comment/commentApiService.test.js +122 -0
  48. package/src/all/background_page/service/api/resource/resourceService.js +1 -0
  49. package/src/all/background_page/service/auth/postLogoutService.js +2 -0
  50. package/src/all/background_page/service/auth/postLogoutService.test.js +4 -1
  51. package/src/all/background_page/service/browser/browserService.js +22 -0
  52. package/src/all/background_page/service/clipboard/clipboardProviderService.js +40 -0
  53. package/src/all/background_page/service/clipboard/clipboardProviderService.test.js +61 -0
  54. package/src/all/background_page/service/clipboard/copyToClipboardService.js +123 -0
  55. package/src/all/background_page/service/clipboard/copyToClipboardService.test.js +174 -0
  56. package/src/all/background_page/service/resource/findAndUpdateResourcesLocalStorageService.js +52 -1
  57. package/src/all/background_page/service/resource/findAndUpdateResourcesLocalStorageService.test.js +100 -0
  58. package/src/all/background_page/service/resource/findResourcesService.js +53 -19
  59. package/src/all/background_page/service/resource/findResourcesService.test.js +191 -0
  60. package/src/all/background_page/service/resourceType/updateResourceTypesService.test.js +1 -1
  61. package/src/all/background_page/service/share/shareResourceService.test.js +1 -1
  62. package/src/all/background_page/service/user/deleteUserService.js +97 -0
  63. package/src/all/background_page/service/user/deleteUserService.test.js +178 -0
  64. package/src/all/locales/de-DE/common.json +2 -2
  65. package/src/all/locales/es-ES/common.json +2 -2
  66. package/src/all/locales/fr-FR/common.json +5 -5
  67. package/src/all/locales/it-IT/common.json +2 -2
  68. package/src/all/locales/ja-JP/common.json +2 -2
  69. package/src/all/locales/ko-KR/common.json +2 -2
  70. package/src/all/locales/lt-LT/common.json +2 -2
  71. package/src/all/locales/nl-NL/common.json +2 -2
  72. package/src/all/locales/pl-PL/common.json +5 -5
  73. package/src/all/locales/pt-BR/common.json +2 -2
  74. package/src/all/locales/ro-RO/common.json +2 -2
  75. package/src/all/locales/ru-RU/common.json +2 -2
  76. package/src/all/locales/sl-SI/common.json +33 -33
  77. package/src/all/locales/sv-SE/common.json +2 -2
  78. package/src/all/locales/uk-UA/common.json +3 -3
  79. package/src/chrome/manifest.json +1 -1
  80. package/src/chrome/polyfill/clipboard/edgeBackgroundPageClipboardService.js +31 -0
  81. package/src/chrome/polyfill/clipboard/edgeBackgroundPageClipboardService.test.js +51 -0
  82. package/src/chrome-mv3/index.js +3 -3
  83. package/src/chrome-mv3/manifest.json +1 -1
  84. package/src/chrome-mv3/offscreens/{fetch.html → offscreen.html} +1 -1
  85. package/src/chrome-mv3/offscreens/{fetch.js → offscreen.js} +2 -2
  86. package/src/chrome-mv3/offscreens/service/clipboard/writeClipobardOffscreenService.js +54 -0
  87. package/src/chrome-mv3/offscreens/service/clipboard/writeClipobardOffscreenService.test.js +56 -0
  88. package/src/chrome-mv3/offscreens/service/network/fetchOffscreenService.js +36 -44
  89. package/src/chrome-mv3/offscreens/service/network/fetchOffscreenService.test.data.js +0 -1
  90. package/src/chrome-mv3/offscreens/service/network/fetchOffscreenService.test.js +90 -120
  91. package/src/chrome-mv3/offscreens/service/offscreen/handleOffscreenRequestService.js +85 -0
  92. package/src/chrome-mv3/offscreens/service/offscreen/handleOffscreenRequestService.test.js +99 -0
  93. package/src/chrome-mv3/polyfill/clipboardOffscreenPolyfill.js +19 -0
  94. package/src/chrome-mv3/serviceWorker/service/clipboard/requestClipboardOffscreenService.js +51 -0
  95. package/src/chrome-mv3/serviceWorker/service/clipboard/requestClipboardOffscreenService.test.js +70 -0
  96. package/src/chrome-mv3/serviceWorker/service/clipboard/responseClipboardOffscreenService.js +25 -0
  97. package/src/chrome-mv3/serviceWorker/service/clipboard/responseClipboardOffscreenService.test.data.js +21 -0
  98. package/src/chrome-mv3/serviceWorker/service/clipboard/responseClipboardOffscreenService.test.js +33 -0
  99. package/src/chrome-mv3/serviceWorker/service/network/requestFetchOffscreenService.js +25 -50
  100. package/src/chrome-mv3/serviceWorker/service/network/requestFetchOffscreenService.test.js +16 -39
  101. package/src/chrome-mv3/serviceWorker/service/network/responseFetchOffscreenService.js +14 -45
  102. package/src/chrome-mv3/serviceWorker/service/network/responseFetchOffscreenService.test.js +5 -37
  103. package/src/chrome-mv3/serviceWorker/service/offscreen/createOffscreenDocumentService.js +43 -0
  104. package/src/chrome-mv3/serviceWorker/service/offscreen/createOffscreenDocumentService.test.js +48 -0
  105. package/src/chrome-mv3/serviceWorker/service/offscreen/handleOffscreenResponseService.js +119 -0
  106. package/src/chrome-mv3/serviceWorker/service/offscreen/handleOffscreenResponseService.test.js +159 -0
  107. package/src/firefox/manifest.json +1 -1
  108. package/src/safari/manifest.json +1 -1
  109. package/test/jest.setup.js +4 -0
  110. package/test/mocks/mockNavigatorClipboard.js +40 -0
  111. package/test/mocks/mockWebExtensionPolyfill.js +2 -1
  112. package/{webpack-offscreens.fetch.config.js → webpack-offscreens.config.js} +1 -1
  113. package/webpack.service-worker.config.js +1 -0
  114. package/src/all/background_page/controller/clipboard/clipboardController.test.js +0 -68
  115. package/src/all/background_page/event/clipboardEvents.js +0 -28
@@ -0,0 +1,53 @@
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 GetOrFindMetadataSettingsService from "../../service/metadata/getOrFindMetadataSettingsService";
15
+
16
+ class GetOrFindMetadataKeysController {
17
+ /**
18
+ * @constructor
19
+ * @param {Worker} worker
20
+ * @param {string} requestId
21
+ * @param {ApiClientOptions} apiClientOptions the api client options
22
+ * @param {AccountEntity} account the user account
23
+ */
24
+ constructor(worker, requestId, apiClientOptions, account) {
25
+ this.worker = worker;
26
+ this.requestId = requestId;
27
+ this.getOrFindMetadaSettingsService = new GetOrFindMetadataSettingsService(account, apiClientOptions);
28
+ }
29
+
30
+ /**
31
+ * Controller executor.
32
+ * @returns {Promise<void>}
33
+ */
34
+ async _exec() {
35
+ try {
36
+ const result = await this.exec();
37
+ this.worker.port.emit(this.requestId, 'SUCCESS', result);
38
+ } catch (error) {
39
+ console.error(error);
40
+ this.worker.port.emit(this.requestId, 'ERROR', error);
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Get or find the metadata keys settings entity.
46
+ * @returns {Promise<MetadataKeysSettingsEntity>}
47
+ */
48
+ async exec() {
49
+ return this.getOrFindMetadaSettingsService.getOrFindKeysSettings();
50
+ }
51
+ }
52
+
53
+ export default GetOrFindMetadataKeysController;
@@ -0,0 +1,106 @@
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 AccountEntity from "../../model/entity/account/accountEntity";
16
+ import {defaultAccountDto} from "../../model/entity/account/accountEntity.test.data";
17
+ import {defaultApiClientOptions} from "passbolt-styleguide/src/shared/lib/apiClient/apiClientOptions.test.data";
18
+ import GetOrFindMetadataKeysController from "./getOrFindMetadataKeysSettingsController";
19
+ import {
20
+ defaultMetadataKeysSettingsDto,
21
+ } from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysSettingsEntity.test.data";
22
+ import MetadataKeysSettingsEntity
23
+ from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysSettingsEntity";
24
+ import {enableFetchMocks} from "jest-fetch-mock";
25
+ import {
26
+ defaultCeOrganizationSettings
27
+ } from "../../model/entity/organizationSettings/organizationSettingsEntity.test.data";
28
+
29
+ beforeEach(() => {
30
+ enableFetchMocks();
31
+ });
32
+
33
+ jest.mock("../../service/passphrase/getPassphraseService");
34
+
35
+ describe("GetOrFindMetadataKeysSettingsController", () => {
36
+ let controller, account, apiClientOptions;
37
+
38
+ beforeEach(async() => {
39
+ account = new AccountEntity(defaultAccountDto());
40
+ apiClientOptions = defaultApiClientOptions();
41
+ controller = new GetOrFindMetadataKeysController(null, null, apiClientOptions, account);
42
+ // flush account related storage before each.
43
+ await controller.getOrFindMetadaSettingsService.metadataKeysSettingsLocalStorage.flush();
44
+ });
45
+
46
+ describe("::exec", () => {
47
+ it("get or find metadata keys settings for a v5.", async() => {
48
+ expect.assertions(3);
49
+
50
+ const metadataKeysSettingsDto = defaultMetadataKeysSettingsDto();
51
+ const siteSettingsDto = defaultCeOrganizationSettings();
52
+ jest.spyOn(controller.getOrFindMetadaSettingsService.findAndUpdateMetadataSettingsLocalStorageService.findMetadataSettingsService, "findKeysSettings")
53
+ .mockImplementationOnce(() => new MetadataKeysSettingsEntity(metadataKeysSettingsDto));
54
+ jest.spyOn(controller.getOrFindMetadaSettingsService.findAndUpdateMetadataSettingsLocalStorageService.organisationSettingsModel.organizationSettingsService, "find")
55
+ .mockImplementation(() => siteSettingsDto);
56
+
57
+ const metadataKeysSettings = await controller.exec();
58
+
59
+ expect(metadataKeysSettings).toBeInstanceOf(MetadataKeysSettingsEntity);
60
+ expect(metadataKeysSettings.toDto()).toEqual(metadataKeysSettingsDto);
61
+ const storageValue = await controller.getOrFindMetadaSettingsService.metadataKeysSettingsLocalStorage.get();
62
+ expect(storageValue).toEqual(metadataKeysSettingsDto);
63
+ });
64
+
65
+ it("get or find metadata keys settings with usage of the shared key for a v5.", async() => {
66
+ expect.assertions(3);
67
+
68
+ const metadataKeysSettingsDto = defaultMetadataKeysSettingsDto({
69
+ allow_usage_of_personal_keys: false,
70
+ zero_knowledge_key_share: true,
71
+ });
72
+ const siteSettingsDto = defaultCeOrganizationSettings();
73
+ jest.spyOn(controller.getOrFindMetadaSettingsService.findAndUpdateMetadataSettingsLocalStorageService.findMetadataSettingsService, "findKeysSettings")
74
+ .mockImplementationOnce(() => new MetadataKeysSettingsEntity(metadataKeysSettingsDto));
75
+ jest.spyOn(controller.getOrFindMetadaSettingsService.findAndUpdateMetadataSettingsLocalStorageService.organisationSettingsModel.organizationSettingsService, "find")
76
+ .mockImplementation(() => siteSettingsDto);
77
+
78
+ const metadataKeysSettings = await controller.exec();
79
+
80
+ expect(metadataKeysSettings).toBeInstanceOf(MetadataKeysSettingsEntity);
81
+ expect(metadataKeysSettings.toDto()).toEqual(metadataKeysSettingsDto);
82
+ const storageValue = await controller.getOrFindMetadaSettingsService.metadataKeysSettingsLocalStorage.get();
83
+ expect(storageValue).toEqual(metadataKeysSettingsDto);
84
+ });
85
+
86
+ it("get or find metadata keys settings for a v4 should have the default.", async() => {
87
+ expect.assertions(3);
88
+
89
+ const siteSettingsDto = defaultCeOrganizationSettings();
90
+ // disable the plugin metadata.
91
+ delete siteSettingsDto.passbolt.plugins.metadata;
92
+ jest.spyOn(controller.getOrFindMetadaSettingsService.findAndUpdateMetadataSettingsLocalStorageService.organisationSettingsModel.organizationSettingsService, "find")
93
+ .mockImplementation(() => siteSettingsDto);
94
+ jest.spyOn(controller.getOrFindMetadaSettingsService.findAndUpdateMetadataSettingsLocalStorageService.findMetadataSettingsService.metadataKeysSettingsApiService, "findSettings")
95
+ .mockImplementationOnce(() => {});
96
+
97
+ const metadataKeysSettings = await controller.exec();
98
+
99
+ const expectedMetadataKeysSettingsDto = MetadataKeysSettingsEntity.createFromDefault().toDto();
100
+ expect(metadataKeysSettings).toBeInstanceOf(MetadataKeysSettingsEntity);
101
+ expect(metadataKeysSettings.toDto()).toEqual(expectedMetadataKeysSettingsDto);
102
+ const storageValue = await controller.getOrFindMetadaSettingsService.metadataKeysSettingsLocalStorage.get();
103
+ expect(storageValue).toEqual(expectedMetadataKeysSettingsDto);
104
+ });
105
+ });
106
+ });
@@ -0,0 +1,70 @@
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.3.0
13
+ */
14
+ import {assertUuid} from "../../utils/assertions";
15
+ import FindAndUpdateResourcesLocalStorage from "../../service/resource/findAndUpdateResourcesLocalStorageService";
16
+ import UserPassphraseRequiredError from "passbolt-styleguide/src/shared/error/userPassphraseRequiredError";
17
+ import GetPassphraseService from "../../service/passphrase/getPassphraseService";
18
+
19
+ class UpdateResourceLocalStorageByFolderParentIdController {
20
+ /**
21
+ * Constructor.
22
+ * @param {Worker} worker The associated worker.
23
+ * @param {string} requestId The associated request id.
24
+ * @param {ApiClientOptions} apiClientOptions The api client options.
25
+ * @param {AccountEntity} account The user account
26
+ */
27
+ constructor(worker, requestId, apiClientOptions, account) {
28
+ this.worker = worker;
29
+ this.requestId = requestId;
30
+ this.findAndUpdateResourcesLocalStorage = new FindAndUpdateResourcesLocalStorage(account, apiClientOptions);
31
+ this.getPassphraseService = new GetPassphraseService(account);
32
+ }
33
+
34
+ /**
35
+ * Controller executor.
36
+ * @param {string} parentFolderId the resources parent folder id
37
+ * @returns {Promise<void>}
38
+ */
39
+ async _exec(parentFolderId) {
40
+ try {
41
+ await this.exec(parentFolderId);
42
+ this.worker.port.emit(this.requestId, 'SUCCESS');
43
+ } catch (error) {
44
+ console.error(error);
45
+ this.worker.port.emit(this.requestId, 'ERROR', error);
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Update resource local storage resource for a given folder.
51
+ * @param {string} parentFolderId the resources parent folder id
52
+ * @returns {Promise<void>}
53
+ */
54
+ async exec(parentFolderId) {
55
+ assertUuid(parentFolderId);
56
+ try {
57
+ await this.findAndUpdateResourcesLocalStorage.findAndUpdateAllByParentFolderId(parentFolderId);
58
+ return;
59
+ } catch (error) {
60
+ if (!(error instanceof UserPassphraseRequiredError)) {
61
+ throw error;
62
+ }
63
+ }
64
+
65
+ const passphrase = await this.getPassphraseService.getPassphrase(this.worker, 60);
66
+ await this.findAndUpdateResourcesLocalStorage.findAndUpdateAllByParentFolderId(parentFolderId, passphrase);
67
+ }
68
+ }
69
+
70
+ export default UpdateResourceLocalStorageByFolderParentIdController;
@@ -0,0 +1,78 @@
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.3.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 {v4 as uuidv4} from "uuid";
19
+ import UpdateResourceLocalStorageByFolderParentIdController from "./updateResourceLocalStorageByFolderParentIdController";
20
+ import UserPassphraseRequiredError from "passbolt-styleguide/src/shared/error/userPassphraseRequiredError";
21
+
22
+ describe("UpdateResourceLocalStorageByFolderParentIdController", () => {
23
+ let controller, worker;
24
+
25
+ beforeEach(() => {
26
+ worker = {
27
+ port: {
28
+ emit: jest.fn()
29
+ }
30
+ };
31
+ const account = new AccountEntity(defaultAccountDto());
32
+ const apiClientOptions = defaultApiClientOptions();
33
+ controller = new UpdateResourceLocalStorageByFolderParentIdController(worker, null, apiClientOptions, account);
34
+ });
35
+
36
+ describe("::exec", () => {
37
+ it("should call for update the local storage given a folder ID", async() => {
38
+ expect.assertions(2);
39
+
40
+ const parentFolderId = uuidv4();
41
+
42
+ jest.spyOn(controller.findAndUpdateResourcesLocalStorage, "findAndUpdateAllByParentFolderId").mockImplementation(() => {});
43
+
44
+ await controller.exec(parentFolderId);
45
+
46
+ expect(controller.findAndUpdateResourcesLocalStorage.findAndUpdateAllByParentFolderId).toHaveBeenCalledTimes(1);
47
+ expect(controller.findAndUpdateResourcesLocalStorage.findAndUpdateAllByParentFolderId).toHaveBeenCalledWith(parentFolderId);
48
+ });
49
+
50
+ it("should call for update the local storage given a folder ID a second time with a passphrase if the first time it failed", async() => {
51
+ expect.assertions(3);
52
+
53
+ const parentFolderId = uuidv4();
54
+ const passphrase = "passphrase";
55
+
56
+ jest.spyOn(controller.getPassphraseService, "getPassphrase").mockImplementation(async() => passphrase);
57
+ jest.spyOn(controller.findAndUpdateResourcesLocalStorage, "findAndUpdateAllByParentFolderId").mockImplementation(async(_, passphrase) => {
58
+ if (!passphrase) {
59
+ throw new UserPassphraseRequiredError("Missing passphrase");
60
+ }
61
+ });
62
+
63
+ await controller.exec(parentFolderId);
64
+
65
+ expect(controller.findAndUpdateResourcesLocalStorage.findAndUpdateAllByParentFolderId).toHaveBeenCalledTimes(2);
66
+ expect(controller.findAndUpdateResourcesLocalStorage.findAndUpdateAllByParentFolderId).toHaveBeenCalledWith(parentFolderId);
67
+ expect(controller.findAndUpdateResourcesLocalStorage.findAndUpdateAllByParentFolderId).toHaveBeenCalledWith(parentFolderId, passphrase);
68
+ });
69
+
70
+ it("should throw an error if the parent folder id is not a valid uuid", async() => {
71
+ expect.assertions(1);
72
+
73
+ const promise = controller.exec(42);
74
+
75
+ await expect(promise).rejects.toThrowError("The given parameter is not a valid UUID");
76
+ });
77
+ });
78
+ });
@@ -15,7 +15,7 @@ import {v4 as uuidv4} from "uuid";
15
15
  import AccountEntity from "../../model/entity/account/accountEntity";
16
16
  import {adminAccountDto} from "../../model/entity/account/accountEntity.test.data";
17
17
  import {defaultApiClientOptions} from "passbolt-styleguide/src/shared/lib/apiClient/apiClientOptions.test.data";
18
- import MockPort from "passbolt-styleguide/test/mocks/mockPort";
18
+ import MockPort from "passbolt-styleguide/src/react-extension/test/mock/MockPort";
19
19
  import {
20
20
  defaultPermissionDto,
21
21
  minimumPermissionDto
@@ -26,6 +26,7 @@ import FoldersCollection from "../../model/entity/folder/foldersCollection";
26
26
  import {defaultFolderDto} from "passbolt-styleguide/src/shared/models/entity/folder/folderEntity.test.data";
27
27
  const {pgpKeys} = require("passbolt-styleguide/test/fixture/pgpKeys/keys");
28
28
 
29
+
29
30
  describe("ShareOneFolderController", () => {
30
31
  describe("::exec", () => {
31
32
  let account, controller;
@@ -23,7 +23,7 @@ import {
23
23
  import ResourcesCollection from "../../model/entity/resource/resourcesCollection";
24
24
  import expect from "expect";
25
25
  import {defaultApiClientOptions} from "passbolt-styleguide/src/shared/lib/apiClient/apiClientOptions.test.data";
26
- import MockPort from "passbolt-styleguide/test/mocks/mockPort";
26
+ import MockPort from "passbolt-styleguide/src/react-extension/test/mock/MockPort";
27
27
  import {v4 as uuidv4} from "uuid";
28
28
  import {minimumPermissionDto} from "passbolt-styleguide/src/shared/models/entity/permission/permissionEntity.test.data";
29
29
  import EncryptMessageService from "../../service/crypto/encryptMessageService";
@@ -0,0 +1,73 @@
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 DeleteDryRunError from "../../error/deleteDryRunError";
16
+ import GetPassphraseService from "../../service/passphrase/getPassphraseService";
17
+ import DeleteUserService from "../../service/user/deleteUserService";
18
+ import DecryptMetadataService from "../../service/metadata/decryptMetadataService";
19
+
20
+ class DeleteDryRunUserController {
21
+ /**
22
+ * Constructor
23
+ * @param {Worker} worker
24
+ * @param {string} requestId uuid
25
+ * @param {ApiClientOptions} apiClientOptions The api client options
26
+ * @param {AccountEntity} account The account associated to the worker.
27
+ */
28
+ constructor(worker, requestId, apiClientOptions, account) {
29
+ this.worker = worker;
30
+ this.requestId = requestId;
31
+ this.deleteUserService = new DeleteUserService(account, apiClientOptions);
32
+ this.getPassphraseService = new GetPassphraseService(account);
33
+ this.decryptMetadataService = new DecryptMetadataService(apiClientOptions, account);
34
+ }
35
+
36
+ /**
37
+ * Controller executor.
38
+ * @returns {Promise<void>}
39
+ */
40
+ async _exec(userId) {
41
+ try {
42
+ await this.exec(userId);
43
+ this.worker.port.emit(this.requestId, 'SUCCESS');
44
+ } catch (error) {
45
+ console.error(error);
46
+ this.worker.port.emit(this.requestId, 'ERROR', error);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Delete dry run the user.
52
+ * @param {string} userId The user id.
53
+ * @return {Promise<void>}
54
+ * @throws {DeleteDryRunError} if the data should be transferred to someone.
55
+ * @throws {Error} if the data returned by the API is not a PassboltApiFetchError with error code 400.
56
+ */
57
+ async exec(userId) {
58
+ try {
59
+ await this.deleteUserService.deleteDryRun(userId);
60
+ } catch (error) {
61
+ if (error instanceof DeleteDryRunError) {
62
+ const resourcesCollection = error.errors.resources?.sole_owner;
63
+ if (resourcesCollection?.items.some(resourceEntity => !resourceEntity.isMetadataDecrypted())) {
64
+ const passphrase = await this.getPassphraseService.getPassphrase(this.worker);
65
+ await this.decryptMetadataService.decryptAllFromForeignModels(error.errors.resources.sole_owner, passphrase);
66
+ }
67
+ }
68
+ throw error;
69
+ }
70
+ }
71
+ }
72
+
73
+ export default DeleteDryRunUserController;
@@ -0,0 +1,129 @@
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 {enableFetchMocks} from "jest-fetch-mock";
16
+ import {mockApiResponse, mockApiResponseError} from "../../../../../test/mocks/mockApiResponse";
17
+ import {defaultApiClientOptions} from "passbolt-styleguide/src/shared/lib/apiClient/apiClientOptions.test.data";
18
+ import RoleEntity from "passbolt-styleguide/src/shared/models/entity/role/roleEntity";
19
+ import AccountEntity from "../../model/entity/account/accountEntity";
20
+ import {defaultAccountDto} from "../../model/entity/account/accountEntity.test.data";
21
+ import {defaultSharedResourcesWithEncryptedMetadataDtos, defaultResourcesDtos} from "passbolt-styleguide/src/shared/models/entity/resource/resourcesCollection.test.data";
22
+ import {defaultDecryptedSharedMetadataKeysDtos} from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysCollection.test.data";
23
+ import PassboltApiFetchError from "passbolt-styleguide/src/shared/lib/Error/PassboltApiFetchError";
24
+ import DeleteDryRunUserController from "./deleteDryRunUserController";
25
+ import {v4 as uuidv4} from "uuid";
26
+ import DeleteDryRunError from "../../error/deleteDryRunError";
27
+ import {pgpKeys} from 'passbolt-styleguide/test/fixture/pgpKeys/keys';
28
+ import MetadataKeysCollection from "passbolt-styleguide/src/shared/models/entity/metadata/metadataKeysCollection";
29
+
30
+ beforeEach(() => {
31
+ enableFetchMocks();
32
+ });
33
+
34
+ describe("DeleteDryRunUserController", () => {
35
+ describe("::exec", () => {
36
+ const accountDto = defaultAccountDto();
37
+ accountDto.role_name = RoleEntity.ROLE_ADMIN;
38
+ const account = new AccountEntity(accountDto);
39
+
40
+ it("Should delete dry run the user without transfer", async() => {
41
+ expect.assertions(1);
42
+
43
+ const userId = uuidv4();
44
+
45
+ fetch.doMockOnceIf(new RegExp(`/users/${userId}/dry-run.json`), () => mockApiResponse({}));
46
+
47
+ const controller = new DeleteDryRunUserController(null, null, defaultApiClientOptions(), account);
48
+ jest.spyOn(controller.deleteUserService, "deleteDryRun");
49
+
50
+ await controller.exec(userId);
51
+
52
+ expect(controller.deleteUserService.deleteDryRun).toHaveBeenCalledWith(userId);
53
+ });
54
+
55
+ it("Should throw an error if the user has transfer and decrypt", async() => {
56
+ expect.assertions(2);
57
+
58
+ const userId = uuidv4();
59
+ const metadataKeysDtos = defaultDecryptedSharedMetadataKeysDtos();
60
+ const metadataKeys = new MetadataKeysCollection(metadataKeysDtos);
61
+ const collectionDto = defaultSharedResourcesWithEncryptedMetadataDtos(10, {
62
+ metadata_key_id: metadataKeysDtos[0].id
63
+ });
64
+ const body = {
65
+ errors: {
66
+ resources: {
67
+ sole_owner: collectionDto
68
+ }
69
+ }
70
+ };
71
+
72
+ fetch.doMockOnceIf(new RegExp(`/users/${userId}/dry-run.json`), () => mockApiResponseError(400, "Need transfer", body));
73
+
74
+ const controller = new DeleteDryRunUserController(null, null, defaultApiClientOptions(), account);
75
+ jest.spyOn(controller.decryptMetadataService.getOrFindMetadataKeysService, "getOrFindAll").mockImplementation(() => metadataKeys);
76
+ jest.spyOn(controller.getPassphraseService, "getPassphrase").mockImplementationOnce(() => pgpKeys.ada.passphrase);
77
+
78
+ try {
79
+ await controller.exec(userId);
80
+ } catch (error) {
81
+ expect(error).toBeInstanceOf(DeleteDryRunError);
82
+ expect(error.errors.resources.sole_owner.items.every(resourceEntity => resourceEntity.isMetadataDecrypted())).toBeTruthy();
83
+ }
84
+ });
85
+
86
+ it("Should throw an error if the user has transfer without decryption", async() => {
87
+ expect.assertions(4);
88
+
89
+ const userId = uuidv4();
90
+ const collectionDto = defaultResourcesDtos();
91
+ const body = {
92
+ errors: {
93
+ resources: {
94
+ sole_owner: collectionDto
95
+ }
96
+ }
97
+ };
98
+
99
+ fetch.doMockOnceIf(new RegExp(`/users/${userId}/dry-run.json`), () => mockApiResponseError(400, "Need transfer", body));
100
+
101
+ const controller = new DeleteDryRunUserController(null, null, defaultApiClientOptions(), account);
102
+ jest.spyOn(controller.decryptMetadataService.getOrFindMetadataKeysService, "getOrFindAll");
103
+ jest.spyOn(controller.getPassphraseService, "getPassphrase");
104
+
105
+ try {
106
+ await controller.exec(userId);
107
+ } catch (error) {
108
+ expect(error).toBeInstanceOf(DeleteDryRunError);
109
+ expect(error.errors.resources.sole_owner.items.every(resourceEntity => resourceEntity.isMetadataDecrypted())).toBeTruthy();
110
+ expect(controller.decryptMetadataService.getOrFindMetadataKeysService.getOrFindAll).not.toHaveBeenCalled();
111
+ expect(controller.getPassphraseService.getPassphrase).not.toHaveBeenCalled();
112
+ }
113
+ });
114
+
115
+ it("Should throw an error if something wrong happens on the API", async() => {
116
+ expect.assertions(1);
117
+
118
+ const userId = uuidv4();
119
+ fetch.doMockOnceIf(new RegExp(`/users/${userId}/dry-run.json`), async() => mockApiResponseError(500, "Something went wrong"));
120
+
121
+ const controller = new DeleteDryRunUserController(null, null, defaultApiClientOptions(), account);
122
+ try {
123
+ await controller.exec(userId);
124
+ } catch (e) {
125
+ expect(e).toBeInstanceOf(PassboltApiFetchError);
126
+ }
127
+ });
128
+ });
129
+ });
@@ -0,0 +1,76 @@
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 DeleteDryRunError from "../../error/deleteDryRunError";
16
+ import GetPassphraseService from "../../service/passphrase/getPassphraseService";
17
+ import DeleteUserService from "../../service/user/deleteUserService";
18
+ import DecryptMetadataService from "../../service/metadata/decryptMetadataService";
19
+ import UserDeleteTransferEntity from "../../model/entity/user/transfer/userDeleteTransferEntity";
20
+
21
+ class DeleteUserController {
22
+ /**
23
+ * Constructor
24
+ * @param {Worker} worker
25
+ * @param {string} requestId uuid
26
+ * @param {ApiClientOptions} apiClientOptions The api client options
27
+ * @param {AccountEntity} account The account associated to the worker.
28
+ */
29
+ constructor(worker, requestId, apiClientOptions, account) {
30
+ this.worker = worker;
31
+ this.requestId = requestId;
32
+ this.deleteUserService = new DeleteUserService(account, apiClientOptions);
33
+ this.getPassphraseService = new GetPassphraseService(account);
34
+ this.decryptMetadataService = new DecryptMetadataService(apiClientOptions, account);
35
+ }
36
+
37
+ /**
38
+ * Controller executor.
39
+ * @returns {Promise<void>}
40
+ */
41
+ async _exec(userId, transferDto) {
42
+ try {
43
+ await this.exec(userId, transferDto);
44
+ this.worker.port.emit(this.requestId, 'SUCCESS');
45
+ } catch (error) {
46
+ console.error(error);
47
+ this.worker.port.emit(this.requestId, 'ERROR', error);
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Delete dry run the user.
53
+ * @param {string} userId The user id.
54
+ * @param {object} [transferDto = null] The transfer dto.
55
+ * @return {Promise<void>}
56
+ * @throws {DeleteDryRunError} if the data should be transferred to someone.
57
+ * @throws {Error} if the data returned by the API is not a PassboltApiFetchError with error code 400.
58
+ */
59
+ async exec(userId, transferDto = null) {
60
+ try {
61
+ const transferEntity = transferDto ? new UserDeleteTransferEntity(transferDto) : null;
62
+ await this.deleteUserService.delete(userId, transferEntity);
63
+ } catch (error) {
64
+ if (error instanceof DeleteDryRunError) {
65
+ const resourcesCollection = error.errors.resources?.sole_owner;
66
+ if (resourcesCollection?.items.some(resourceEntity => !resourceEntity.isMetadataDecrypted())) {
67
+ const passphrase = this.getPassphraseService.getPassphrase(this.worker);
68
+ await this.decryptMetadataService.decryptAllFromForeignModels(error.errors.resources.sole_owner, passphrase);
69
+ }
70
+ }
71
+ throw error;
72
+ }
73
+ }
74
+ }
75
+
76
+ export default DeleteUserController;