passbolt-browser-extension 5.2.0 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/RELEASE_NOTES.md +50 -75
  3. package/doc/browser-extension-class-diagram.md +9 -0
  4. package/package.json +2 -2
  5. package/src/all/_locales/sl/messages.json +2 -2
  6. package/src/all/background_page/controller/resource/updateResourceLocalStorageByFolderParentIdController.js +70 -0
  7. package/src/all/background_page/controller/resource/updateResourceLocalStorageByFolderParentIdController.test.js +78 -0
  8. package/src/all/background_page/controller/share/shareOneFolderController.test.js +2 -1
  9. package/src/all/background_page/controller/share/shareResourcesController.test.js +1 -1
  10. package/src/all/background_page/event/resourceEvents.js +11 -0
  11. package/src/all/background_page/model/entity/resource/resourcesCollection.js +25 -0
  12. package/src/all/background_page/model/entity/resource/resourcesCollection.test.js +34 -0
  13. package/src/all/background_page/service/api/resource/resourceService.js +1 -0
  14. package/src/all/background_page/service/resource/findAndUpdateResourcesLocalStorageService.js +52 -1
  15. package/src/all/background_page/service/resource/findAndUpdateResourcesLocalStorageService.test.js +100 -0
  16. package/src/all/background_page/service/resource/findResourcesService.js +53 -19
  17. package/src/all/background_page/service/resource/findResourcesService.test.js +191 -0
  18. package/src/all/background_page/service/resourceType/updateResourceTypesService.test.js +1 -1
  19. package/src/all/background_page/service/share/shareResourceService.test.js +1 -1
  20. package/src/all/locales/de-DE/common.json +2 -2
  21. package/src/all/locales/es-ES/common.json +2 -2
  22. package/src/all/locales/fr-FR/common.json +5 -5
  23. package/src/all/locales/it-IT/common.json +2 -2
  24. package/src/all/locales/ja-JP/common.json +2 -2
  25. package/src/all/locales/ko-KR/common.json +2 -2
  26. package/src/all/locales/lt-LT/common.json +2 -2
  27. package/src/all/locales/nl-NL/common.json +2 -2
  28. package/src/all/locales/pl-PL/common.json +5 -5
  29. package/src/all/locales/pt-BR/common.json +2 -2
  30. package/src/all/locales/ro-RO/common.json +2 -2
  31. package/src/all/locales/ru-RU/common.json +2 -2
  32. package/src/all/locales/sl-SI/common.json +33 -33
  33. package/src/all/locales/sv-SE/common.json +2 -2
  34. package/src/all/locales/uk-UA/common.json +3 -3
  35. package/src/chrome/manifest.json +1 -1
  36. package/src/chrome-mv3/manifest.json +1 -1
  37. package/src/firefox/manifest.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,55 @@ This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [5.3.0] - 2025-06-09
8
+
9
+ ### Added
10
+ - PB-43269 Create the entity CustomFieldEntity
11
+ - PB-43271 Create the entity collection CustomFieldsCollection
12
+ - PB-43273 Create the entity SecretDataV5StandaloneCustomFieldsCollection
13
+ - PB-43275 Update the resource types schema definitions
14
+ - PB-43277 Update the ResourceMetadataEntity
15
+ - PB-43278 Update the ResourceFormEntity
16
+ - PB-43279 Update the Secret Entities
17
+ - PB-43283 Display a new entry the create/edit dialog to set custom fields on the left sidebar and the menu
18
+ - PB-43284 Create the CustomFieldForm for the create/edit dialog
19
+ - PB-43285 Handle the CustomFieldForm warnings and limitation
20
+ - PB-43286 Update create/edit resource to select secret custom fields for a standalone custom fields
21
+ - PB-43287 Display the Custom Fields section on the right sidebar
22
+ - PB-43289 Display standalone custom fields in the component DisplayResourceCreationMenu
23
+ - PB-43290 Display standalone custom fields in the component DisplayResourcesWorkspaceMainMenu
24
+ - PB-43291 Display the URIs section in the right sidebar
25
+ - PB-43374 Add validation on keys and values of each elements of custom fields for the resource form entity
26
+ - PB-43377 Add set collection into entity v2
27
+ - PB-43145 Find a list of resources based on IDs and that are suitable for local storage from the API
28
+ - PB-43146 Find a list of resources based on a parent folder id and that are suitable for the local storage from the API
29
+ - PB-43133 Display padding below tags in resource workspace left sidebar
30
+ - PB-42185 The folder caret that expands or collapses folders in the tree should have a larger clickable area to make it easier to use
31
+ - PB-43222 Improve the group dialog to match the new share dimensions
32
+ - PB-43147 Find and update resources based on parent folder id for the local storage
33
+ - PB-43148 Create a connector for finding resources based on a parent id for the styleguide to call it later
34
+ - PB-43149 Create a ResourcesServiceWorkerService to call the service worker for resource related operations
35
+ - PB-43150 Implement the optimised call in the Styleguide when filtering by a folder
36
+ - PB-43151 Optimise the data retrieved from the API such that updates are not done if unnecessary
37
+ - PB-43156 Clarify implications for backups and other devices before changing the passphrase in the user settings workspace
38
+ - PB-43489 Display unexpected error if there is any issue during the secret decryption
39
+
40
+ ### Fixed
41
+ - PB-43109 Fix: from the sidebar when upgrade from v4 to v5 goes wrong the error message in the notification
42
+ - PB-43118 Hide the "Share metadata keys" button in the users workspace action bar for the current signed-in user
43
+ - PB-43215 Fix account recovery creator name
44
+ - PB-43063 Fix group edit dialog double warning message has broken UI
45
+ - PB-43117 Hide the "Share metadata keys" button in the users workspace action bar after sharing missing metadata keys with a user
46
+ - PB-43064 Fix group edit dialog can show a mix of error and warning messages
47
+ - PB-43150: fix folder not being reloaded
48
+ - PB-43424 Clicking on the "open in a new tab” call to action in the quick application should open the resource url in a new tab
49
+ - PB-43108 Display attention required icon on "metadata keys" label in the user details sidebar if the user is not having access to some metadata keys
50
+ - PB-43217 The default icon stroke width is too thick in the grid and doesn't match the custom icons
51
+ - PB-43220 Copy URL field action button lacks padding and is broken in the SSO settings
52
+ - PB-43168 Align vertically resources workspace select check-boxes
53
+ - PB-43211 The feedback message notifying the administrator when a metadata key has been shared with a user contains a typo
54
+ - PB-43471 Center vertically the icon on the create and edit dialog
55
+
7
56
  ## [5.2.0] - 2025-06-04
8
57
 
9
58
  ### Added
package/RELEASE_NOTES.md CHANGED
@@ -1,81 +1,56 @@
1
- Song: https://youtu.be/ZA2JknKrCbM?si=H-rta-dE_IVIqm45
1
+ Release song: https://www.youtube.com/watch?v=ubWL8VAPoYw
2
2
 
3
- Passbolt v5.2.0 is now available. This version introduces the long-awaited metadata properties for v5 resources (beta): users can set a custom icon for a resource and associate multiple URIs with it. The release also ships with numerous bug fixes. For full details, please see the changelog.
3
+ Passbolt 5.3 adds custom fields, one of the five most‑requested features from the community. Built on top of encrypted‑metadata introduced earlier this year, custom fields let users attach additional key‑value pairs to a resource or as a standalone one. Typical use‑cases include centralising CI/CD job variables and storing environment‑specific configuration values that need more structure than a general note.
4
4
 
5
- As always, we warmly invite the community to test these new features before the production release, and we thank everyone for their valuable feedback and bug reports.
5
+ Custom fields rely on encrypted metadata, therefore the feature is still in beta and is not yet available on Passbolt Cloud. A step‑by‑step guide on how to enable the encrypted metadata on a self‑hosted instance will be available in a blog post that will be published soon. The encrypted‑metadata feature is scheduled to be marked as stable in Passbolt 5.4, planned for August 2025.
6
6
 
7
- ### Added
8
- - PB-42936 Translate the application into Ukrainian
9
- - PB-42897 Upgrade resource to v5 from information panel
10
- - PB-42896 PB-42896 Display an “Upgrade Resource to v5” card in the information panel
11
- - PB-42895 Upgrade v4 password string resources to v5 default
12
- - PB-42894 Upgrade a single v4 resource to v5
13
- - PB-42860 Translate the application into Slovenian
14
- - PB-42796 Add a limit for multiple URIs
15
- - PB-42788 As a user I can access the resource appearance customization from the create/edit
16
- - PB-42704 Display missing metadata keys information in the user sidebar
17
- - PB-42658 Refresh the users local storage after sharing missing metadata keys
18
- - PB-42598 Retrieve missing_metadata_keys_ids information when retrieving signed-in user details with the getOrFindMe method of the UserModel
19
- - PB-42590 Write the background color and icon ID into KDBX files
20
- - PB-42589 Read the background color and icon ID from KDBX files
21
- - PB-42588 Adapt the ResourceIcon component to handle IconEntity
22
- - PB-42587 Add the AddResourceAppearance form part for the resource dialog
23
- - PB-42586 Add the ‘appearance’ metadata field in the resource dialog
24
- - PB-42585 Add IconEntity as an associated entity in MetadataEntity
25
- - PB-42584 Create IconEntity to hold custom icon and color information
26
- - PB-42570 Create a method canSuggestUris using canSuggestUri
27
- - PB-42543 Allow users to navigate to the additional URIs from the SelectResourceForm
28
- - PB-42536 Allow user to add additional URIs from the Create and Edit Resource v5 dialogs
29
- - PB-42534 Display resource additional URIs badge in the filtered resource of the QuickApplication
30
- - PB-42533 Display resource additional URIs badge in the suggested resource of the QuickApplication
31
- - PB-42530 Display resource additional URIs in the details of a resource of the QuickApplication
32
- - PB-42529 Display resource additional URIs badge in the browsed resource of the QuickApplication
33
- - PB-42528 Display resource additional URIs badge in the resource details sidebar
34
- - PB-42527 Display resource additional URIs badge in the resources grid
35
- - PB-42526 Create the ResourceUrisBadge component to handle resource additional URIs badge and the tooltip displaying them
36
- - PB-42130 Add shareMetadataKeyPrivate event to AppEvents
37
- - PB-42129 Create ShareMetadataKeyPrivateController and use ShareMetadataKeyPrivateService to perform the action
38
- - PB-42127 Create ShareMetadataKeyPrivateService and implement shareMissing method
39
- - PB-42114 Add create or share method to metadata private key api service
40
- - PB-42368 Update EncryptOne method from EncryptMetadataPrivateKeysService to allow encryption without signature
41
- - PB-42134 Update DisplayUsersContextualMenu to display a Share metadata keys action if key is missing
42
- - PB-42133 Update DisplayUserWorkspaceActions to display a Share metadata keys action if key is missing
43
- - PB-42132 Implement Dialog confirmation when administrator wants to share keys with an user
44
- - PB-42131 Add share method into metadataKeysServiceWorkerService to perform the UI action
45
- - PB-42126 Add cloneForSharing method into MetadataPrivateKeyEntity
46
- - PB-42124 Create ShareMetadataPrivateKeysCollection
47
- - PB-42110 Update userModel updateLocalStorage method to include missing_metadata_keys_ids option
48
- - PB-42109 Add missing_metadata_keys_ids property to UserEntity
49
- - PB-41617 Add comfortable grid
50
- - PB-39042 Display upgrade resource to v5 card
51
-
52
- ### Improved
53
- - PB-42883 Improve performance by skipping the decryption of unchanged metadata.
54
- - PB-41654 Transform workspaces shifter into a dropdown
55
- - PB-42184 Increase the share dialog width to accommodate longer strings from translations or user names
56
-
57
- ### Fixed
58
- - PB-43161 Fix: dragging resources or folder should display any error
59
- - PB-43008 Fix dragging v5 resources into shared folders should trigger the share strategy on the resource
60
- - PB-42985 Translate the button manage account in the profile dropdown
61
- - PB-42789 Fix userAvatar on userInformationPanel with attention required svg
62
- - PB-42702 Fix contains missing_metadata_keys_ids miss match
63
- - PB-42606 Fix the Quick App Login form CTA spinner should not be displayed over the text of the button
64
- - PB-42272 Fix display v5 resource metadata in the grid when filtering by group
65
- - PB-42077 Update navigation menu icon width
66
- - PB-41649 Re-align components in the left sidebar
67
- - PB-41643 Remove TOTP MFA (profile workspace) border around the QR code and card
68
- - PB-41642 Update Turn off MFA primary button to be red
7
+ As part of our continuous performance work, this release concentrates on folder browsing. Loading folders and their resources is now faster and reduces the load on API and client, improving day-to-day usability for organizations having thousands of credentials under management.
69
8
 
70
- ### Maintenance
71
- - PB-43012 Change authentication_token parameter to token for get the user key policies endpoint
72
- - PB-42790 Replace legacy Icon by SVG
73
- - PB-42572 Update Quickaccess HomePage to use the canSuggestUris
74
- - PB-42571 Update isSuggestion in resource entity to use canSuggestUris
75
- - PB-42569 Create and merge canSuggestUri into a service
76
- - PB-42978 Check object_type is defined and valid before metadata encryption
9
+ Several bugs reported by the community have also been fixed. As always, thank you to everyone who took the time to file issues, test patches and suggest improvements. For a complete list of changes, consult the changelog.
77
10
 
78
- ### Security
79
- - PB-42700 Upgrade vulnerable library undici and lockfile-lint-api
80
- - PB-42391 Update Papaparse library
11
+ ### Added
12
+ - PB-43269 Create the entity CustomFieldEntity
13
+ - PB-43271 Create the entity collection CustomFieldsCollection
14
+ - PB-43273 Create the entity SecretDataV5StandaloneCustomFieldsCollection
15
+ - PB-43275 Update the resource types schema definitions
16
+ - PB-43277 Update the ResourceMetadataEntity
17
+ - PB-43278 Update the ResourceFormEntity
18
+ - PB-43279 Update the Secret Entities
19
+ - PB-43283 Display a new entry the create/edit dialog to set custom fields on the left sidebar and the menu
20
+ - PB-43284 Create the CustomFieldForm for the create/edit dialog
21
+ - PB-43285 Handle the CustomFieldForm warnings and limitation
22
+ - PB-43286 Update create/edit resource to select secret custom fields for a standalone custom fields
23
+ - PB-43287 Display the Custom Fields section on the right sidebar
24
+ - PB-43289 Display standalone custom fields in the component DisplayResourceCreationMenu
25
+ - PB-43290 Display standalone custom fields in the component DisplayResourcesWorkspaceMainMenu
26
+ - PB-43291 Display the URIs section in the right sidebar
27
+ - PB-43374 Add validation on keys and values of each elements of custom fields for the resource form entity
28
+ - PB-43377 Add set collection into entity v2
29
+ - PB-43145 Find a list of resources based on IDs and that are suitable for local storage from the API
30
+ - PB-43146 Find a list of resources based on a parent folder id and that are suitable for the local storage from the API
31
+ - PB-43133 Display padding below tags in resource workspace left sidebar
32
+ - PB-42185 The folder caret that expands or collapses folders in the tree should have a larger clickable area to make it easier to use
33
+ - PB-43222 Improve the group dialog to match the new share dimensions
34
+ - PB-43147 Find and update resources based on parent folder id for the local storage
35
+ - PB-43148 Create a connector for finding resources based on a parent id for the styleguide to call it later
36
+ - PB-43149 Create a ResourcesServiceWorkerService to call the service worker for resource related operations
37
+ - PB-43150 Implement the optimised call in the Styleguide when filtering by a folder
38
+ - PB-43151 Optimise the data retrieved from the API such that updates are not done if unnecessary
39
+ - PB-43156 Clarify implications for backups and other devices before changing the passphrase in the user settings workspace
40
+ - PB-43489 Display unexpected error if there is any issue during the secret decryption
81
41
 
42
+ ### Fixed
43
+ - PB-43109 Fix: from the sidebar when upgrade from v4 to v5 goes wrong the error message in the notification
44
+ - PB-43118 Hide the "Share metadata keys" button in the users workspace action bar for the current signed-in user
45
+ - PB-43215 Fix account recovery creator name
46
+ - PB-43063 Fix group edit dialog double warning message has broken UI
47
+ - PB-43117 Hide the "Share metadata keys" button in the users workspace action bar after sharing missing metadata keys with a user
48
+ - PB-43064 Fix group edit dialog can show a mix of error and warning messages
49
+ - PB-43150: fix folder not being reloaded
50
+ - PB-43424 Clicking on the "open in a new tab” call to action in the quick application should open the resource url in a new tab
51
+ - PB-43108 Display attention required icon on "metadata keys" label in the user details sidebar if the user is not having access to some metadata keys
52
+ - PB-43217 The default icon stroke width is too thick in the grid and doesn't match the custom icons
53
+ - PB-43220 Copy URL field action button lacks padding and is broken in the SSO settings
54
+ - PB-43168 Align vertically resources workspace select check-boxes
55
+ - PB-43211 The feedback message notifying the administrator when a metadata key has been shared with a user contains a typo
56
+ - PB-43471 Center vertically the icon on the create and edit dialog
@@ -48,6 +48,11 @@ classDiagram
48
48
  +exec() Promise
49
49
  }
50
50
 
51
+ class UpdateResourceLocalStorageByFolderParentIdController{
52
+ event "passbolt.resources.update-local-storage-for-parent-folder"
53
+ +exec(string parentFolderId) Promise
54
+ }
55
+
51
56
  %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52
57
  %% Resources services
53
58
  %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -62,6 +67,7 @@ classDiagram
62
67
 
63
68
  class FindAndUpdateResourcesLocalStorageService {
64
69
  +findAndUpdateAll(FindAndUpdateResourcesLocalStorageOptions) Promise~ResourcesCollection~
70
+ +findAndUpdateAllByParentFolderId(uuid parentFolderId, string passphrase) Promise~ResourcesCollection~
65
71
  +findAndUpdateByIsSharedWithGroup(uuid groupId) Promise~ResourcesCollection~
66
72
  }
67
73
 
@@ -79,6 +85,8 @@ classDiagram
79
85
  +findAllByIdsWithPermissions(array~uuid~ resourcesIds) Promise~ResourcesCollection~
80
86
  +findAllByIsSharedWithGroupForLocalStorage(uuid groupId) Promise~ResourcesCollection~
81
87
  +findAllForDecrypt(array~uuid~ resourceIds) Promise~ResourcesCollection~
88
+ +findAllByIdsForLocalStorage(Array~uuid~ resourcesIds) Promise~ResourcesCollection~
89
+ +findAllByParentFolderIdForLocalStorage(string uuid) Promise~ResourcesCollection~
82
90
  +findOneById(string uuid, object contains) Promise~ResourceEntity~
83
91
  +findOneByIdForDetails(string uuid) Promise~ResourceEntity~
84
92
  }
@@ -1065,6 +1073,7 @@ classDiagram
1065
1073
  UpdateAllResourcesLocalStorageController*--FindAndUpdateResourcesLocalStorageService
1066
1074
  %% UpdateResourceController*--GetPassphraseService
1067
1075
  UpdateResourceController*--UpdateResourceService
1076
+ UpdateResourceLocalStorageByFolderParentIdController *--FindAndUpdateResourcesLocalStorage
1068
1077
  style CreateResourceController fill:#D2E0FB
1069
1078
  style ExportResourcesFileController fill:#D2E0FB
1070
1079
  style FindAllIdsByIsSharedWithGroupController fill:#D2E0FB
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "passbolt-browser-extension",
3
- "version": "5.2.0",
3
+ "version": "5.3.0",
4
4
  "license": "AGPL-3.0",
5
5
  "copyright": "Copyright 2025 Passbolt SA",
6
6
  "description": "Passbolt web extension for the open source password manager for teams",
@@ -22,7 +22,7 @@
22
22
  "locutus": "~2.0.9",
23
23
  "openpgp": "^6.1.1",
24
24
  "papaparse": "^5.5.2",
25
- "passbolt-styleguide": "^5.2.2",
25
+ "passbolt-styleguide": "^5.3.1",
26
26
  "react": "17.0.2",
27
27
  "react-dom": "17.0.2",
28
28
  "secrets-passbolt": "github:passbolt/secrets.js#v2.0.1",
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "appName": {
3
- "message": "Passbolt - upravljalnik gesel z odprto kodo",
3
+ "message": "Passbolt - Odprtokodni upravitelj gesel",
4
4
  "description": "The application name of the extension, displayed in the web store. 45 characters max."
5
5
  },
6
6
  "appDescription": {
7
- "message": "Razširitev Passbolt za upravljalnik gesel z odprto kodo za ekipe.",
7
+ "message": "Razširitev Passbolt za odprtokodnega upravitelja gesel za ekipe.",
8
8
  "description": "The description of the extension, displayed in the web store. 85 characters max."
9
9
  }
10
10
  }
@@ -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";
@@ -22,6 +22,7 @@ import FindAllByIdsForDisplayPermissionsController
22
22
  import MoveResourcesController from "../controller/move/moveResourcesController";
23
23
  import ResetResourceGridUserSettingController
24
24
  from "../controller/resourceGridSetting/resetResourceGridUserSettingController";
25
+ import UpdateResourceLocalStorageByFolderParentIdController from "../controller/resource/updateResourceLocalStorageByFolderParentIdController";
25
26
 
26
27
  const listen = function(worker, apiClientOptions, account) {
27
28
  /*
@@ -173,6 +174,16 @@ const listen = function(worker, apiClientOptions, account) {
173
174
  const controller = new MoveResourcesController(worker, requestId, apiClientOptions, account);
174
175
  await controller._exec(resourcesIds, destinationFolderId);
175
176
  });
177
+
178
+ /*
179
+ * Update the local storage for resources in the specified parent folder.
180
+ * @listens passbolt.resources.update-local-storage-by-folder-parent-id
181
+ * @param {string} parentFolderId The id of the parent folder.
182
+ */
183
+ worker.port.on('passbolt.resources.update-local-storage-by-folder-parent-id', async(requestId, parentFolderId) => {
184
+ const controller = new UpdateResourceLocalStorageByFolderParentIdController(worker, requestId, apiClientOptions, account);
185
+ await controller._exec(parentFolderId);
186
+ });
176
187
  };
177
188
 
178
189
  export const ResourceEvents = {listen};
@@ -336,6 +336,31 @@ class ResourcesCollection extends EntityV2Collection {
336
336
  return result;
337
337
  }
338
338
 
339
+ /**
340
+ * Update the current resource collection with the given collection.
341
+ * If an element already exists, it is replaced, otherwise, it's added.
342
+ * Note: mutation of the original collection does not trigger collection validation (schema or build rules).
343
+ * @param {ResourcesCollection} resourcesCollection
344
+ */
345
+ updateWithCollection(resourcesCollection) {
346
+ assertType(resourcesCollection, ResourcesCollection);
347
+
348
+ const resourceMapByIdWithIndex = this.items.reduce((result, resource, currentIndex) => {
349
+ result[resource.id] = currentIndex;
350
+ return result;
351
+ }, {});
352
+
353
+ for (let i = 0; i < resourcesCollection.length; i++) {
354
+ const resource = resourcesCollection.items[i];
355
+ const mappedResourceIndex = resourceMapByIdWithIndex[resource.id];
356
+ if (typeof mappedResourceIndex === "undefined") {
357
+ this.push(resource, {validate: false});
358
+ } else {
359
+ this._items[mappedResourceIndex] = resource;
360
+ }
361
+ }
362
+ }
363
+
339
364
  /*
340
365
  * ==================================================
341
366
  * Static getters
@@ -446,4 +446,38 @@ describe("ResourcesCollection", () => {
446
446
  expect(() => collection.setDecryptedMetadataFromCollection("test")).toThrow('The `resourcesCollection` parameter should be a ResourcesCollection.');
447
447
  });
448
448
  });
449
+
450
+ describe("::updateWithCollection", () => {
451
+ it("should update the existing resources and add the new ones", () => {
452
+ expect.assertions(5);
453
+ const resource1 = defaultResourceDto();
454
+ const resource2 = defaultResourceDto();
455
+ const collection = new ResourcesCollection([resource1, resource2]);
456
+
457
+ const updatedResource2 = {
458
+ ...resource2,
459
+ metadata: defaultResourceMetadataDto({
460
+ name: "UPDATE - RESOURCE",
461
+ }),
462
+ };
463
+
464
+ const resource3 = defaultResourceDto();
465
+ const collectionForUpdate = new ResourcesCollection([resource3, updatedResource2]);
466
+
467
+ collection.updateWithCollection(collectionForUpdate);
468
+
469
+ expect(collection).toHaveLength(3);
470
+ expect(collection.items[0].id).toStrictEqual(resource1.id);
471
+ expect(collection.items[1].id).toStrictEqual(resource2.id);
472
+ expect(collection.items[1].metadata.name).toStrictEqual(updatedResource2.metadata.name);
473
+ expect(collection.items[2].id).toStrictEqual(resource3.id);
474
+ });
475
+
476
+ it("should assert its parameters", () => {
477
+ expect.assertions(1);
478
+ const collection = new ResourcesCollection([]);
479
+
480
+ expect(() => collection.updateWithCollection("test")).toThrow();
481
+ });
482
+ });
449
483
  });
@@ -73,6 +73,7 @@ class ResourceService extends AbstractService {
73
73
  'has-id',
74
74
  // if tag plugin
75
75
  'has-tag',
76
+ "has-parent",
76
77
  ];
77
78
  }
78
79
 
@@ -12,7 +12,7 @@
12
12
  * @since 4.6.0
13
13
  */
14
14
  import ResourceLocalStorage from "../local_storage/resourceLocalStorage";
15
- import {assertNumber} from "../../utils/assertions";
15
+ import {assertNumber, assertUuid} from "../../utils/assertions";
16
16
  import FindResourcesService from "./findResourcesService";
17
17
  import ResourcesCollection from "../../model/entity/resource/resourcesCollection";
18
18
  import ResourceTypeModel from "../../model/resourceType/resourceTypeModel";
@@ -113,6 +113,57 @@ class FindAndUpdateResourcesLocalStorage {
113
113
  await ResourceLocalStorage.addOrReplaceResourcesCollection(resourcesCollection);
114
114
  return resourcesCollection;
115
115
  }
116
+
117
+ /**
118
+ * Find and update the local storage with the resources filtered by parent folder id retrieved from the API.
119
+ * @param {string} parentFolderId The parent folder id to filter the resources with.
120
+ * @param {string|null} [passphrase = null] The passphrase to use to decrypt the metadata. Marked as optional as it
121
+ * might be available in the passphrase session storage.
122
+ * @return {Promise<ResourcesCollection>} The resource shared with the group
123
+ * @throw {TypeError} If the parentFolderId is not valid UUID
124
+ */
125
+ async findAndUpdateAllByParentFolderId(parentFolderId, passphrase = null) {
126
+ assertUuid(parentFolderId);
127
+ const resourceTypes = await this.resourceTypeModel.getOrFindAll();
128
+
129
+ const apiResourcesCollection = await this.findResourcesServices.findAllByParentFolderIdForLocalStorage(parentFolderId);
130
+ apiResourcesCollection.filterByResourceTypes(resourceTypes);
131
+
132
+ const apiResourcesCollectionMapIds = apiResourcesCollection.items.reduce((result, resource) => {
133
+ result[resource.id] = resource;
134
+ return result;
135
+ }, {});
136
+
137
+ const localStorageResourcesCollection = new ResourcesCollection(await ResourceLocalStorage.get(), {validate: false});
138
+ const knownResourcesCollectionInFolderIds = localStorageResourcesCollection.items.reduce((result, resource) => {
139
+ if (resource.folderParentId === parentFolderId) {
140
+ result.push(resource.id);
141
+ }
142
+ return result;
143
+ }, Array(apiResourcesCollection.length));
144
+
145
+ apiResourcesCollection.setDecryptedMetadataFromCollection(localStorageResourcesCollection);
146
+ localStorageResourcesCollection.updateWithCollection(apiResourcesCollection);
147
+
148
+ const movedOrRemovedResourcesIds = knownResourcesCollectionInFolderIds.filter(id => !apiResourcesCollectionMapIds[id]);
149
+ if (movedOrRemovedResourcesIds.length > 0) {
150
+ const updatedResources = await this.findResourcesServices.findAllByIdsForLocalStorage(movedOrRemovedResourcesIds);
151
+
152
+ updatedResources.setDecryptedMetadataFromCollection(localStorageResourcesCollection);
153
+ localStorageResourcesCollection.updateWithCollection(updatedResources);
154
+
155
+ // These resources have been deleted (or permissions revoked) and need to be removed from the local storage.
156
+ const remainingResourcesIds = movedOrRemovedResourcesIds
157
+ .filter(id => !updatedResources.getFirstById(id));
158
+
159
+ localStorageResourcesCollection.removeMany(remainingResourcesIds);
160
+ }
161
+
162
+ await this.decryptMetadataService.decryptAllFromForeignModels(localStorageResourcesCollection, passphrase, {ignoreDecryptionError: true, updateSessionKeys: true});
163
+ localStorageResourcesCollection.filterOutMetadataEncrypted();
164
+
165
+ await ResourceLocalStorage.set(localStorageResourcesCollection);
166
+ }
116
167
  }
117
168
 
118
169
  export default FindAndUpdateResourcesLocalStorage;