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
@@ -14,6 +14,8 @@ import InformMenuController from "../controller/InformMenuController/InformMenuC
14
14
  import GetLocaleController from "../controller/locale/getLocaleController";
15
15
  import GetOrFindPasswordPoliciesController from "../controller/passwordPolicies/getOrFindPasswordPoliciesController";
16
16
  import AutofillController from "../controller/autofill/AutofillController";
17
+ import GetOrFindLoggedInUserController from "../controller/user/getOrFindLoggedInUserController";
18
+ import GetOrFindMetadataKeysSettingsController from "../controller/metadata/getOrFindMetadataKeysSettingsController";
17
19
 
18
20
  /**
19
21
  * Listens the inform menu events
@@ -66,6 +68,18 @@ const listen = function(worker, apiClientOptions, account) {
66
68
  await informMenuController.close(requestId);
67
69
  });
68
70
 
71
+ /*
72
+ * Find the logged in user
73
+ *
74
+ * @listens passbolt.users.find-logged-in-user
75
+ * @param requestId {uuid} The request identifier
76
+ * @param refreshCache {bool} (Optional) Default false. Should request the API and refresh the cache.
77
+ */
78
+ worker.port.on('passbolt.users.find-logged-in-user', async(requestId, refreshCache = false) => {
79
+ const controller = new GetOrFindLoggedInUserController(worker, requestId, apiClientOptions, account);
80
+ await controller._exec(refreshCache);
81
+ });
82
+
69
83
  /*
70
84
  * Get locale language
71
85
  *
@@ -94,6 +108,23 @@ const listen = function(worker, apiClientOptions, account) {
94
108
  const controller = new GetOrFindPasswordPoliciesController(worker, requestId, account, apiClientOptions);
95
109
  await controller._exec();
96
110
  });
111
+
112
+ /*
113
+ * ==================================================================================
114
+ * Metadata events.
115
+ * ==================================================================================
116
+ */
117
+
118
+ /*
119
+ * Get or find metadata keys settings.
120
+ *
121
+ * @listens passbolt.metadata.get-or-find-metadata-keys-settings
122
+ * @param requestId {uuid} The request identifier
123
+ */
124
+ worker.port.on('passbolt.metadata.get-or-find-metadata-keys-settings', async requestId => {
125
+ const controller = new GetOrFindMetadataKeysSettingsController(worker, requestId, apiClientOptions, account);
126
+ await controller._exec();
127
+ });
97
128
  };
98
129
 
99
130
  export const InformMenuEvents = {listen};
@@ -5,7 +5,6 @@
5
5
  * @licence GNU Affero General Public License http://www.gnu.org/licenses/agpl-3.0.en.html
6
6
  */
7
7
  import BrowserTabService from "../service/ui/browserTab.service";
8
- import ResourceInProgressCacheService from "../service/cache/resourceInProgressCache.service";
9
8
  import i18n from "../sdk/i18n";
10
9
  import FindMeController from "../controller/rbac/findMeController";
11
10
  import GetOrFindLoggedInUserController from "../controller/user/getOrFindLoggedInUserController";
@@ -15,6 +14,9 @@ import GetOrFindPasswordExpirySettingsController from "../controller/passwordExp
15
14
  import GetOrFindMetadataTypesController from "../controller/metadata/getMetadataTypesSettingsController";
16
15
  import CopyToClipboardController from "../controller/clipboard/copyToClipboardController";
17
16
  import CopyTemporarilyToClipboardController from "../controller/clipboard/copyTemporarilyToClipboardController";
17
+ import PrepareResourceController from "../controller/quickaccess/prepareResourceController";
18
+ import ConsumeInProgressCreationResourceController from "../controller/quickaccess/consumeInProgressCreationResourceController";
19
+ import GetOrFindMetadataKeysSettingsController from "../controller/metadata/getOrFindMetadataKeysSettingsController";
18
20
 
19
21
  /**
20
22
  * Listens to the quickaccess application events
@@ -57,21 +59,8 @@ const listen = function(worker, apiClientOptions, account) {
57
59
  * @param tabId {string} The tab id
58
60
  */
59
61
  worker.port.on('passbolt.quickaccess.prepare-resource', async(requestId, tabId) => {
60
- try {
61
- const resourceInProgress = await ResourceInProgressCacheService.consume();
62
- if (resourceInProgress === null) {
63
- // Retrieve resource name and uri from tab.
64
- const tab = tabId ? await BrowserTabService.getById(tabId) : await BrowserTabService.getCurrent();
65
- const name = tab.title;
66
- const uri = tab.url;
67
- worker.port.emit(requestId, 'SUCCESS', {name: name, uri: uri});
68
- } else {
69
- worker.port.emit(requestId, 'SUCCESS', resourceInProgress);
70
- }
71
- } catch (error) {
72
- console.error(error);
73
- worker.port.emit(requestId, 'ERROR', error);
74
- }
62
+ const controller = new PrepareResourceController(worker, requestId);
63
+ await controller._exec(tabId);
75
64
  });
76
65
 
77
66
  /*
@@ -81,13 +70,8 @@ const listen = function(worker, apiClientOptions, account) {
81
70
  * @param requestId {uuid} The request identifier
82
71
  */
83
72
  worker.port.on('passbolt.quickaccess.prepare-autosave', async requestId => {
84
- try {
85
- const resourceInProgress = await ResourceInProgressCacheService.consume() || {};
86
- worker.port.emit(requestId, 'SUCCESS', resourceInProgress);
87
- } catch (error) {
88
- console.error(error);
89
- worker.port.emit(requestId, 'ERROR', error);
90
- }
73
+ const controller = new ConsumeInProgressCreationResourceController(worker, requestId);
74
+ await controller._exec();
91
75
  });
92
76
 
93
77
  /*
@@ -161,6 +145,17 @@ const listen = function(worker, apiClientOptions, account) {
161
145
  await controller._exec();
162
146
  });
163
147
 
148
+ /*
149
+ * Get or find metadata keys settings.
150
+ *
151
+ * @listens passbolt.metadata.get-or-find-metadata-keys-settings
152
+ * @param requestId {uuid} The request identifier
153
+ */
154
+ worker.port.on('passbolt.metadata.get-or-find-metadata-keys-settings', async requestId => {
155
+ const controller = new GetOrFindMetadataKeysSettingsController(worker, requestId, apiClientOptions, account);
156
+ await controller._exec();
157
+ });
158
+
164
159
  /*
165
160
  * ==================================================================================
166
161
  * Clipboard events.
@@ -31,6 +31,7 @@ import SetSetupSecurityTokenController from "../controller/setup/setSetupSecurit
31
31
  import HasRecoverUserEnabledAccountRecoveryController from "../controller/recover/hasRecoverUserEnabledAccountRecoveryController";
32
32
  import GetUserPassphrasePoliciesController from "../controller/setup/getUserPassphrasePoliciesController";
33
33
  import ReloadTabController from "../controller/tab/reloadTabController";
34
+ import RedirectPostLoginController from "../controller/auth/redirectPostLoginController";
34
35
 
35
36
 
36
37
  const listen = (worker, apiClientOptions, account) => {
@@ -128,5 +129,16 @@ const listen = (worker, apiClientOptions, account) => {
128
129
  const controller = new ReloadTabController(worker, requestId);
129
130
  await controller._exec();
130
131
  });
132
+
133
+ /*
134
+ * Redirect the user post login.
135
+ *
136
+ * @listens passbolt.auth.post-login-redirect
137
+ * @param requestId {uuid} The request identifier
138
+ */
139
+ worker.port.on('passbolt.auth.post-login-redirect', async requestId => {
140
+ const controller = new RedirectPostLoginController(worker, requestId, account);
141
+ await controller._exec();
142
+ });
131
143
  };
132
144
  export const RecoverEvents = {listen};
@@ -4,7 +4,6 @@
4
4
  * @copyright (c) 2019 Passbolt SA
5
5
  * @licence GNU Affero General Public License http://www.gnu.org/licenses/agpl-3.0.en.html
6
6
  */
7
- import ResourceModel from "../model/resource/resourceModel";
8
7
  import ResourceCreateController from "../controller/resource/resourceCreateController";
9
8
  import ResourceUpdateController from "../controller/resource/resourceUpdateController";
10
9
  import Log from "../model/log";
@@ -23,6 +22,7 @@ import MoveResourcesController from "../controller/move/moveResourcesController"
23
22
  import ResetResourceGridUserSettingController
24
23
  from "../controller/resourceGridSetting/resetResourceGridUserSettingController";
25
24
  import UpdateResourceLocalStorageByFolderParentIdController from "../controller/resource/updateResourceLocalStorageByFolderParentIdController";
25
+ import ResourceDeleteController from "../controller/resource/resourceDeleteController";
26
26
 
27
27
  const listen = function(worker, apiClientOptions, account) {
28
28
  /*
@@ -79,18 +79,11 @@ const listen = function(worker, apiClientOptions, account) {
79
79
  *
80
80
  * @listens passbolt.resources.delete-all
81
81
  * @param requestId {uuid} The request identifier
82
- * @param resourcesIds {array} The resources ids to delete
82
+ * @param resourcesIds {array} The resources ids to del ete
83
83
  */
84
84
  worker.port.on('passbolt.resources.delete-all', async(requestId, resourcesIds) => {
85
- try {
86
- // TODO DeleteResourcesController with progress dialog if resourceIds > 1
87
- const resourceModel = new ResourceModel(apiClientOptions, account);
88
- await resourceModel.bulkDelete(resourcesIds);
89
- worker.port.emit(requestId, 'SUCCESS');
90
- } catch (error) {
91
- console.error(error);
92
- worker.port.emit(requestId, 'ERROR', error);
93
- }
85
+ const controller = new ResourceDeleteController(worker, requestId, apiClientOptions, account);
86
+ await controller._exec(resourcesIds);
94
87
  });
95
88
 
96
89
  /*
@@ -30,6 +30,12 @@ import SetSetupSecurityTokenController from "../controller/setup/setSetupSecurit
30
30
  import GetAccountRecoveryOrganizationPolicyController from "../controller/setup/getAccountRecoveryOrganizationPolicyController";
31
31
  import GetUserPassphrasePoliciesController from "../controller/setup/getUserPassphrasePoliciesController";
32
32
  import ReloadTabController from "../controller/tab/reloadTabController";
33
+ import FindMetadataSetupSettingsController from "../controller/metadata/findMetadataSetupSettingsController";
34
+ import EnableMetadataSetupSettingsController from "../controller/metadata/enableMetadataSetupSettingsController";
35
+ import RedirectPostLoginController from "../controller/auth/redirectPostLoginController";
36
+ import GetActiveAccountService from "../service/account/getActiveAccountService";
37
+ import RedirectToAdminWorkspaceController from "../controller/auth/redirectToAdminWorkspaceController";
38
+ import GetOrFindLoggedInUserController from "../controller/user/getOrFindLoggedInUserController";
33
39
 
34
40
  const listen = function(worker, apiClientOptions, account) {
35
41
  worker.port.on('passbolt.setup.is-first-install', async requestId => {
@@ -121,5 +127,54 @@ const listen = function(worker, apiClientOptions, account) {
121
127
  const controller = new ReloadTabController(worker, requestId);
122
128
  await controller._exec();
123
129
  });
130
+
131
+ worker.port.on('passbolt.metadata.find-setup-settings', async requestId => {
132
+ const controller = new FindMetadataSetupSettingsController(worker, requestId, apiClientOptions);
133
+ await controller._exec();
134
+ });
135
+
136
+ worker.port.on('passbolt.metadata.enable', async requestId => {
137
+ /*
138
+ * The global account at this stage is an `AccountSetupEntity` that is tempered as this process is run after the sign-in
139
+ * So, to addresse the enablement of the metadata in the Setup app, we need to get a `AccountEntity` instead.
140
+ * That's why, we use `GetActiveAccountService.get()` to find an account.
141
+ */
142
+ const account = await GetActiveAccountService.get();
143
+ const controller = new EnableMetadataSetupSettingsController(worker, requestId, apiClientOptions, account);
144
+ await controller._exec();
145
+ });
146
+
147
+ /*
148
+ * Redirect the user post login.
149
+ *
150
+ * @listens passbolt.auth.post-login-redirect
151
+ * @param requestId {uuid} The request identifier
152
+ */
153
+ worker.port.on('passbolt.auth.post-login-redirect', async requestId => {
154
+ const controller = new RedirectPostLoginController(worker, requestId, account);
155
+ await controller._exec();
156
+ });
157
+
158
+ /*
159
+ * Redirect the user to the administration workspace.
160
+ *
161
+ * @listens passbolt.auth.post-login-redirect-to-admin-workspace
162
+ * @param requestId {uuid} The request identifier
163
+ */
164
+ worker.port.on("passbolt.auth.post-login-redirect-to-admin-workspace", async requestId => {
165
+ const controller = new RedirectToAdminWorkspaceController(worker, requestId, account);
166
+ await controller._exec();
167
+ });
168
+
169
+ /*
170
+ * Find the logged in user
171
+ *
172
+ * @listens passbolt.users.find-logged-in-user
173
+ * @param requestId {uuid} The request identifier
174
+ */
175
+ worker.port.on('passbolt.users.find-logged-in-user', async requestId => {
176
+ const controller = new GetOrFindLoggedInUserController(worker, requestId, apiClientOptions, account);
177
+ await controller._exec();
178
+ });
124
179
  };
125
180
  export const SetupEvents = {listen};
@@ -14,8 +14,9 @@
14
14
  import CommentEntity from "../entity/comment/commentEntity";
15
15
  import CommentsCollection from "../entity/comment/commentsCollection";
16
16
  import CommentApiService from "../../service/api/comment/commentApiService";
17
+ import {assertType, assertUuid} from "../../utils/assertions";
17
18
 
18
- class CommentModel {
19
+ class CommentService {
19
20
  /**
20
21
  * Constructor
21
22
  *
@@ -34,6 +35,7 @@ class CommentModel {
34
35
  * @return {CommentsCollection}
35
36
  */
36
37
  async findAllByResourceId(resourceId) {
38
+ assertUuid(resourceId);
37
39
  const foreignKey = 'Resource';
38
40
  const commentsDtos = await this.commentApiService.findAll(foreignKey, resourceId, {creator: true, modifier: false});
39
41
  return new CommentsCollection(commentsDtos);
@@ -46,6 +48,7 @@ class CommentModel {
46
48
  * @returns {Promise<CommentEntity>}
47
49
  */
48
50
  async create(commentEntity) {
51
+ assertType(commentEntity, CommentEntity, "The parameter 'commentEntity' should be a CommentEntity");
49
52
  const commentDto = await this.commentApiService.create(commentEntity.toDto({creator: false, modifier: false}));
50
53
  return new CommentEntity(commentDto);
51
54
  }
@@ -57,8 +60,9 @@ class CommentModel {
57
60
  * @returns {Promise<void>}
58
61
  */
59
62
  async delete(commentId) {
63
+ assertUuid(commentId);
60
64
  await this.commentApiService.delete(commentId);
61
65
  }
62
66
  }
63
67
 
64
- export default CommentModel;
68
+ export default CommentService;
@@ -0,0 +1,98 @@
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 BuildApiClientOptionsService from "../../service/account/buildApiClientOptionsService";
15
+ import AccountEntity from "../../model/entity/account/accountEntity";
16
+ import {defaultAccountDto} from "../../model/entity/account/accountEntity.test.data";
17
+ import {v4 as uuidv4} from "uuid";
18
+ import {enableFetchMocks} from "jest-fetch-mock";
19
+ import CommentApiService from "../../service/api/comment/commentApiService";
20
+ import CommentService from "./commentService";
21
+ import {defaultCommentCollectionDto} from "passbolt-styleguide/src/shared/models/entity/comment/commentEntityCollection.test.data";
22
+ import CommentsCollection from "../entity/comment/commentsCollection";
23
+ import {defaultCommentDto} from "passbolt-styleguide/src/shared/models/entity/comment/commentEntity.test.data";
24
+ import CommentEntity from "../entity/comment/commentEntity";
25
+
26
+ describe("CommentService", () => {
27
+ let apiClientOptions, account,
28
+ service;
29
+
30
+ beforeEach(async() => {
31
+ enableFetchMocks();
32
+ jest.clearAllMocks();
33
+ fetch.resetMocks();
34
+ account = new AccountEntity(defaultAccountDto());
35
+ apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
36
+ service = new CommentService(apiClientOptions, account);
37
+ });
38
+
39
+ describe('::findAllByResourceId', () => {
40
+ it("Should call the comments service API to get the comments collection", async() => {
41
+ expect.assertions(2);
42
+ const resourceId = uuidv4();
43
+ const commentsDto = defaultCommentCollectionDto();
44
+
45
+ jest.spyOn(CommentApiService.prototype, "findAll").mockImplementation(() => commentsDto);
46
+
47
+ const resultsDto = await service.findAllByResourceId(resourceId);
48
+ expect(resultsDto).toHaveLength(commentsDto.length);
49
+ expect(resultsDto).toBeInstanceOf(CommentsCollection);
50
+ });
51
+
52
+ it("should throw an error if id is not defined", async() => {
53
+ expect.assertions(1);
54
+ const promise = service.findAllByResourceId();
55
+ await expect(promise).rejects.toThrowError("The given parameter is not a valid UUID");
56
+ });
57
+ });
58
+
59
+ describe('::create', () => {
60
+ it("Should call the comments service API to create a new comment", async() => {
61
+ expect.assertions(2);
62
+ const commentDto = new CommentEntity(defaultCommentDto());
63
+
64
+ jest.spyOn(CommentApiService.prototype, "create").mockImplementation(() => commentDto);
65
+
66
+ const resultsDto = await service.create(commentDto);
67
+ expect(resultsDto).toBeInstanceOf(CommentEntity);
68
+ expect(resultsDto).toStrictEqual(commentDto);
69
+ });
70
+
71
+ it("should throw an error if comment is not defined", async() => {
72
+ expect.assertions(1);
73
+ const commentDto = new CommentEntity(defaultCommentDto());
74
+ jest.spyOn(CommentApiService.prototype, "create").mockImplementation(() => null);
75
+ const promise = service.create(commentDto);
76
+ await expect(promise).rejects.toThrowError("Could not validate entity CommentEntity. No data provided.");
77
+ });
78
+ });
79
+
80
+ describe('::delete', () => {
81
+ it("Should call the comments service API to delete a new comment", async() => {
82
+ expect.assertions(1);
83
+ const resourceId = uuidv4();
84
+
85
+ jest.spyOn(CommentApiService.prototype, "delete").mockImplementation(() => {});
86
+
87
+ await service.delete(resourceId);
88
+ await expect(service.delete(resourceId)).resolves.not.toThrow();
89
+ });
90
+
91
+ it("should throw an error if comment id is not defined", async() => {
92
+ expect.assertions(1);
93
+
94
+ const expectedError = new Error("The given parameter is not a valid UUID");
95
+ expect(() => service.delete("test")).rejects.toThrow(expectedError);
96
+ });
97
+ });
98
+ });
@@ -12,7 +12,7 @@
12
12
  */
13
13
  import AbstractActionLogEntity from "./abstractActionLogEntity";
14
14
  import DefaultActionLogEntity from "./defaultActionLogEntity";
15
- import PermissionsUpdatedActionLog from "./permissionsUpdatedActionLogEntity";
15
+ import PermissionsUpdatedActionLogEntity from "./permissionsUpdatedActionLogEntity";
16
16
  import EntityCollection from "passbolt-styleguide/src/shared/models/entity/abstract/entityCollection";
17
17
  import EntitySchema from "passbolt-styleguide/src/shared/models/entity/abstract/entitySchema";
18
18
  import EntityCollectionError from "passbolt-styleguide/src/shared/models/entity/abstract/entityCollectionError";
@@ -65,8 +65,8 @@ class ActionLogsCollection extends EntityCollection {
65
65
  * @returns {AbstractActionLogEntity|null}
66
66
  */
67
67
  constructActionLogEntityFromDto(actionLogDto, options = {}) {
68
- if (PermissionsUpdatedActionLog.ALLOWED_TYPES.includes(actionLogDto.type)) {
69
- return new PermissionsUpdatedActionLog(actionLogDto, options);
68
+ if (PermissionsUpdatedActionLogEntity.ALLOWED_TYPES.includes(actionLogDto.type)) {
69
+ return new PermissionsUpdatedActionLogEntity(actionLogDto, options);
70
70
  } else {
71
71
  return new DefaultActionLogEntity(actionLogDto, options);
72
72
  }
@@ -53,6 +53,10 @@ class PermissionsUpdatedActionLogEntity extends AbstractActionLogEntity {
53
53
  this._permissionsAdded = new UpdatedPermissionsCollection(permissionsAddedDto, {clone: false});
54
54
  this._permissionsUpdated = new UpdatedPermissionsCollection(permissionsUpdatedDto, {clone: false});
55
55
  this._permissionsRemoved = new UpdatedPermissionsCollection(permissionsRemovedDto, {clone: false});
56
+
57
+ this._permissionsAdded.sort();
58
+ this._permissionsUpdated.sort();
59
+ this._permissionsRemoved.sort();
56
60
  }
57
61
 
58
62
  /**
@@ -28,7 +28,7 @@ export const defaultKDBXCSVData = (lineCount = 1) => {
28
28
  const lines = [];
29
29
 
30
30
  for (let i = 1; i <= lineCount; i++) {
31
- const line = `Password ${i},Username ${i},https://url${i}.com,Secret ${i},Description ${i},Folder ${i},otpauth://totp/Password%20${i}%3AUsername%20${i}?secret=THISISASECRET&issuer=https%253A%252F%252Furl${i}.com&algorithm=SHA1&digits=6&period=30`;
31
+ const line = `Password ${i},Username ${i},https://url${i}.com,Password ${i},Description ${i},Folder ${i},otpauth://totp/Password%20${i}%3AUsername%20${i}?secret=THISISASECRET&issuer=https%253A%252F%252Furl${i}.com&algorithm=SHA1&digits=6&period=30`;
32
32
  lines.push(line);
33
33
  }
34
34
 
@@ -114,8 +114,8 @@ export const onePasswordCsvFile = [
114
114
  ].join("\r\n");
115
115
 
116
116
  export const bitwardenCsvFile = [
117
- '"name","login_username","login_uri","login_password","notes","folder"',
118
- '"Password 1","Username 1","https://url1.com","Password 1","Description 1","Folder 1"',
117
+ '"name","login_username","login_uri","login_password","notes","folder","login_totp"',
118
+ '"Password 1","Username 1","https://url1.com","Password 1","Description 1","Folder 1","otpauth://totp/Password%201%3AUsername%201?secret=THISISASECRET&issuer=https%253A%252F%252Furl1.com&algorithm=SHA1&digits=6&period=30"',
119
119
  ].join("\r\n");
120
120
 
121
121
  export const lastpassCsvFile = [
@@ -108,6 +108,10 @@ export const anonymousOrganizationSettings = (data = {}) => {
108
108
  }, {
109
109
  "locale": "uk-UA",
110
110
  "label": "Українська (beta)"
111
+ },
112
+ {
113
+ "locale": "cs-CZ",
114
+ "label": "Čeština (beta)"
111
115
  }
112
116
  ]
113
117
  },
@@ -0,0 +1,23 @@
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 {defaultUserDto} from "passbolt-styleguide/src/shared/models/entity/user/userEntity.test.data";
15
+ import PermissionEntity from "../permissionEntity";
16
+ import {v4 as uuidv4} from "uuid";
17
+
18
+ export const defaultUpdatePermissionDto = data => ({
19
+ id: uuidv4(),
20
+ type: PermissionEntity.PERMISSION_OWNER,
21
+ user: defaultUserDto(),
22
+ ...data
23
+ });
@@ -13,6 +13,7 @@
13
13
  import EntitySchema from "passbolt-styleguide/src/shared/models/entity/abstract/entitySchema";
14
14
  import EntityValidationError from "passbolt-styleguide/src/shared/models/entity/abstract/entityValidationError";
15
15
  import UpdatedPermissionEntity from "./updatedPermissionEntity";
16
+ import {defaultUpdatePermissionDto} from "./updatedPermissionEntity.test.data";
16
17
 
17
18
  describe("Updated permission entity", () => {
18
19
  it("schema must validate", () => {
@@ -20,43 +21,27 @@ describe("Updated permission entity", () => {
20
21
  });
21
22
 
22
23
  it("constructor works if valid minimal DTO is provided", () => {
23
- const dto = {
24
- "id": "fa5f5d7a-32cc-4c5b-9478-f58584ca4222",
25
- "type": 15,
26
- "user": {
27
- "id": "f848277c-5398-58f8-a82a-72397af2d450",
28
- "username": "ada@passbolt.com",
29
- "profile": {
30
- "first_name": "Ada",
31
- "last_name": "Lovelace",
32
- "avatar": {
33
- "url": {
34
- "medium": "img\/public\/Avatar\/22\/47\/85\/50adf80e3534413abdd8e34c9be6d1b6\/50adf80e3534413abdd8e34c9be6d1b6.a99472d5.png",
35
- "small": "img\/public\/Avatar\/22\/47\/85\/50adf80e3534413abdd8e34c9be6d1b6\/50adf80e3534413abdd8e34c9be6d1b6.65a0ba70.png"
36
- }
37
- }
38
- },
39
- }
40
- };
24
+ expect.assertions(9);
25
+
26
+ const dto = defaultUpdatePermissionDto();
41
27
  const entity = new UpdatedPermissionEntity(dto);
28
+
42
29
  expect(entity.toDto(UpdatedPermissionEntity.ALL_CONTAIN_OPTIONS)).toEqual(dto);
43
- expect(entity.id).toEqual("fa5f5d7a-32cc-4c5b-9478-f58584ca4222");
44
- expect(entity.type).toEqual(15);
45
- expect(entity.user.id).toEqual('f848277c-5398-58f8-a82a-72397af2d450');
46
- expect(entity.user.username).toEqual('ada@passbolt.com');
47
- expect(entity.user.profile.firstName).toBe('Ada');
48
- expect(entity.user.profile.lastName).toBe('Lovelace');
49
- expect(entity.user.profile.avatar.urlMedium).toBe("img\/public\/Avatar\/22\/47\/85\/50adf80e3534413abdd8e34c9be6d1b6\/50adf80e3534413abdd8e34c9be6d1b6.a99472d5.png");
50
- expect(entity.user.profile.avatar.urlSmall).toBe("img\/public\/Avatar\/22\/47\/85\/50adf80e3534413abdd8e34c9be6d1b6\/50adf80e3534413abdd8e34c9be6d1b6.65a0ba70.png");
30
+ expect(entity.id).toStrictEqual(dto.id);
31
+ expect(entity.type).toStrictEqual(dto.type);
32
+ expect(entity.user.id).toStrictEqual(dto.user.id);
33
+ expect(entity.user.username).toStrictEqual(dto.user.username);
34
+ expect(entity.user.profile.firstName).toStrictEqual(dto.user.profile.first_name);
35
+ expect(entity.user.profile.lastName).toStrictEqual(dto.user.profile.last_name);
36
+ expect(entity.user.profile.avatar.urlMedium).toStrictEqual(dto.user.profile.avatar.url.medium);
37
+ expect(entity.user.profile.avatar.urlSmall).toStrictEqual(dto.user.profile.avatar.url.small);
51
38
  });
52
39
 
53
40
  it("constructor works fails if not enough data is provided", () => {
54
- let t;
55
- t = () => { new UpdatedPermissionEntity({}); };
56
- expect(t).toThrow(EntityValidationError);
57
- t = () => { new UpdatedPermissionEntity({id: "fa5f5d7a-32cc-4c5b-9478-f58584ca4222"}); };
58
- expect(t).toThrow(EntityValidationError);
59
- t = () => { new UpdatedPermissionEntity({"type": 15}); };
60
- expect(t).toThrow(EntityValidationError);
41
+ expect.assertions(3);
42
+
43
+ expect(() => new UpdatedPermissionEntity({})).toThrow(EntityValidationError);
44
+ expect(() => new UpdatedPermissionEntity({id: "fa5f5d7a-32cc-4c5b-9478-f58584ca4222"})).toThrow(EntityValidationError);
45
+ expect(() => new UpdatedPermissionEntity({"type": 15})).toThrow(EntityValidationError);
61
46
  });
62
47
  });
@@ -90,8 +90,7 @@ class UpdatedPermissionsCollection extends EntityCollection {
90
90
  return;
91
91
  }
92
92
  const length = this.updatedPermissions.length;
93
- let i = 0;
94
- for (; i < length; i++) {
93
+ for (let i = 0; i < length; i++) {
95
94
  const existingUpdatedPermission = this.updatedPermissions[i];
96
95
  if (existingUpdatedPermission.id && existingUpdatedPermission.id === updatedPermission.id) {
97
96
  throw new EntityCollectionError(i, UpdatedPermissionsCollection.RULE_UNIQUE_ID, `Updated permission id ${updatedPermission.id} already exists.`);
@@ -124,6 +123,76 @@ class UpdatedPermissionsCollection extends EntityCollection {
124
123
  super.push(updatedPermissionEntity);
125
124
  }
126
125
 
126
+ /**
127
+ * Sort the current collection by grantee type and their names.
128
+ * This method is mutatative
129
+ */
130
+ sort() {
131
+ this._items.sort(UpdatedPermissionsCollection.sortPermissionsByGranteeTypeAndName);
132
+ }
133
+
134
+ /**
135
+ * Delegate function to use as a callback to sort permissions.
136
+ * Permissions are sorted this way:
137
+ * - Defined users first
138
+ * - Defined groups second
139
+ * - Unknown users third
140
+ * - Unknown groups fourth
141
+ * - Unknown grantee type fifth
142
+ * Users are sorted by their `${user.first_name} ${user.last_name}`
143
+ * Groups are sorted by their `${group.name}`
144
+ *
145
+ * @param {PermissionEntity} permissionA
146
+ * @param {PermissionEntity} permissionB
147
+ * @returns {number} -1 if permissionA comes first, 1 if permissionB comes first, 0 it they are "equals"
148
+ * @static
149
+ * @private
150
+ */
151
+ static sortPermissionsByGranteeTypeAndName(permissionA, permissionB) {
152
+ //compare AROs, if they are different, aro User is coming first in the list
153
+ const isADefinedUserPermission = Boolean(permissionA.user);
154
+ const isBDefinedUserPermission = Boolean(permissionB.user);
155
+
156
+ if (isADefinedUserPermission && isBDefinedUserPermission) {
157
+ //both users are defined, we need to order by their full name.
158
+ const userAName = permissionA.user.profile.name;
159
+ const userBName = permissionB.user.profile.name;
160
+
161
+ return userAName.localeCompare(userBName);
162
+ }
163
+
164
+ if (isADefinedUserPermission) {
165
+ // permissionA is a user, permissionB is either an undefined user, a group, an undefined group. So permissionA comes first.
166
+ return -1;
167
+ } else if (isBDefinedUserPermission) {
168
+ // permissionB is a user, permissionA is either an undefined user, a group, an undefined group. So permissionB comes first.
169
+ return 1;
170
+ }
171
+
172
+ //here both permissionA and permissionB are for group permission. But their group could be undefined though
173
+ const isADefinedGroupPermission = Boolean(permissionA.group);
174
+ const isBDefinedGroupPermission = Boolean(permissionB.group);
175
+
176
+ if (isADefinedGroupPermission && isBDefinedGroupPermission) {
177
+ // both permission are for defined group, we need to order them by their group name
178
+ const groupAName = permissionA.group.name;
179
+ const groupBName = permissionB.group.name;
180
+
181
+ return groupAName.localeCompare(groupBName);
182
+ }
183
+
184
+ if (isADefinedGroupPermission) {
185
+ // permissionA is for a defined group and permissionB is for an undefined group. permissionA comes first
186
+ return -1;
187
+ } else if (isBDefinedGroupPermission) {
188
+ // permissionB is for a defined group and permissionA is for an undefined group. permissionB comes first
189
+ return 1;
190
+ }
191
+
192
+ // both permissions are for unknown grantee type. They are considered "equals"
193
+ return 0;
194
+ }
195
+
127
196
  /*
128
197
  * ==================================================
129
198
  * Static getters