passbolt-browser-extension 5.13.0 → 5.14.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 (282) hide show
  1. package/.devcontainer/Dockerfile +33 -3
  2. package/.devcontainer/devcontainer-lock.json +9 -0
  3. package/.devcontainer/post-start.sh +1 -2
  4. package/.github/workflows/codeql-analysis.yml +2 -1
  5. package/.github/workflows/release_candidate.yaml +3 -1
  6. package/.gitlab-ci.yml +1 -0
  7. package/CHANGELOG.md +202 -70
  8. package/CODEOWNERS +2 -0
  9. package/RELEASE_NOTES.md +4 -2
  10. package/package.json +9 -7
  11. package/renovate.json +6 -0
  12. package/src/all/background_page/controller/InformMenuController/InformMenuController.js +2 -5
  13. package/src/all/background_page/controller/InformMenuController/InformMenuController.test.js +31 -1
  14. package/src/all/background_page/controller/account/getAndInitializeAccountLocaleController.js +1 -1
  15. package/src/all/background_page/controller/account/getAndInitializeAccountLocaleController.test.js +6 -14
  16. package/src/all/background_page/controller/account/updatePrivateKeyController.js +7 -5
  17. package/src/all/background_page/controller/account/updatePrivateKeyController.test.js +18 -13
  18. package/src/all/background_page/controller/accountRecovery/accountRecoveryGenerateOrganizationKeyController.js +4 -2
  19. package/src/all/background_page/controller/accountRecovery/accountRecoveryGenerateOrganizationKeyController.test.js +25 -2
  20. package/src/all/background_page/controller/accountRecovery/accountRecoveryLoginController.js +1 -1
  21. package/src/all/background_page/controller/accountRecovery/accountRecoveryLoginController.test.js +10 -5
  22. package/src/all/background_page/controller/accountRecovery/recoverAccountController.js +6 -2
  23. package/src/all/background_page/controller/accountRecovery/recoverAccountController.test.js +11 -4
  24. package/src/all/background_page/controller/auth/authCheckStatus.test.data.js +6 -6
  25. package/src/all/background_page/controller/auth/authCheckStatusController.js +11 -3
  26. package/src/all/background_page/controller/auth/authCheckStatusController.test.js +74 -44
  27. package/src/all/background_page/controller/auth/authIsMfaRequiredController.js +11 -3
  28. package/src/all/background_page/controller/auth/authIsMfaRequiredController.test.js +18 -9
  29. package/src/all/background_page/controller/auth/authLoginController.js +1 -1
  30. package/src/all/background_page/controller/auth/authLoginController.test.js +10 -5
  31. package/src/all/background_page/controller/autofill/AutofillController.js +3 -3
  32. package/src/all/background_page/controller/autofill/AutofillController.test.js +20 -12
  33. package/src/all/background_page/controller/export/exportResourcesFileController.js +6 -3
  34. package/src/all/background_page/controller/export/exportResourcesFileController.test.js +34 -4
  35. package/src/all/background_page/controller/extension/onExtensionInstalledController.js +8 -2
  36. package/src/all/background_page/controller/extension/onExtensionInstalledController.test.js +5 -1
  37. package/src/all/background_page/controller/group/{getOrFindGroupsController.js → findGroupsByIdsForShareController.js} +9 -10
  38. package/src/all/background_page/controller/group/{getOrFindGroupsController.test.js → findGroupsByIdsForShareController.test.js} +8 -8
  39. package/src/all/background_page/controller/group/groupUpdateController.test.js +1 -0
  40. package/src/all/background_page/controller/import/importResourcesFileController.test.js +8 -1
  41. package/src/all/background_page/controller/informCallToActionController/informCallToActionController.js +2 -2
  42. package/src/all/background_page/controller/informCallToActionController/informCallToActionController.test.js +7 -4
  43. package/src/all/background_page/controller/locale/getLocaleController.js +3 -2
  44. package/src/all/background_page/controller/metadata/findMetadataTypesSettingsController.test.js +9 -15
  45. package/src/all/background_page/controller/metadata/getMetadataTypesSettingsController.test.js +9 -15
  46. package/src/all/background_page/controller/metadata/getOrFindMetadataKeysSettingsController.test.js +12 -22
  47. package/src/all/background_page/controller/metadata/shareMetadataKeyPrivateController.test.js +14 -2
  48. package/src/all/background_page/controller/move/moveFolderController.test.js +8 -0
  49. package/src/all/background_page/controller/move/moveResourcesController.test.js +8 -0
  50. package/src/all/background_page/controller/passwordExpiry/getOrFindPasswordExpirySettingsController.test.js +13 -8
  51. package/src/all/background_page/controller/passwordExpiry/savePasswordExpirySettingsController.js +4 -4
  52. package/src/all/background_page/controller/passwordExpiry/savePasswordExpirySettingsController.test.js +8 -10
  53. package/src/all/background_page/controller/permission/findPermissionsByIdsForShareController.js +62 -0
  54. package/src/all/background_page/controller/permission/findPermissionsByIdsForShareController.test.js +71 -0
  55. package/src/all/background_page/controller/recover/generateRecoverAccountRecoveryRequestKeyController.js +1 -1
  56. package/src/all/background_page/controller/resource/resourceCreateController.js +11 -4
  57. package/src/all/background_page/controller/resource/resourceCreateController.test.js +12 -1
  58. package/src/all/background_page/controller/resource/resourceUpdateController.js +11 -4
  59. package/src/all/background_page/controller/resource/resourceUpdateController.test.js +35 -2
  60. package/src/all/background_page/controller/resourceType/getResourceTypesController.js +5 -4
  61. package/src/all/background_page/controller/resourceType/getResourceTypesController.test.js +5 -2
  62. package/src/all/background_page/controller/resourceType/updateAllResourceTypesDeletedStatusController.js +3 -2
  63. package/src/all/background_page/controller/resourceType/updateAllResourceTypesDeletedStatusController.test.js +16 -3
  64. package/src/all/background_page/controller/secret/findSecretByResourceIdController.js +3 -3
  65. package/src/all/background_page/controller/secret/findSecretByResourceIdController.test.js +24 -0
  66. package/src/all/background_page/controller/secretRevision/findResourceSecretRevisionsForDisplayController.js +2 -1
  67. package/src/all/background_page/controller/setup/generateSetupKeyPairController.js +6 -3
  68. package/src/all/background_page/controller/setup/generateSetupKeyPairController.test.js +11 -1
  69. package/src/all/background_page/controller/setup/getAndInitSetupLocaleController.js +1 -1
  70. package/src/all/background_page/controller/setup/getAndInitSetupLocaleController.test.js +14 -18
  71. package/src/all/background_page/controller/setup/setSetupLocaleController.js +1 -1
  72. package/src/all/background_page/controller/setup/setSetupLocaleController.test.js +6 -10
  73. package/src/all/background_page/controller/setup/signInSetupController.js +6 -2
  74. package/src/all/background_page/controller/setup/signInSetupController.test.js +10 -5
  75. package/src/all/background_page/controller/share/shareOneFolderController.test.js +8 -0
  76. package/src/all/background_page/controller/share/shareResourcesController.test.js +9 -1
  77. package/src/all/background_page/controller/siteSettings/getOrFindSiteSettingsController.js +59 -0
  78. package/src/all/background_page/controller/siteSettings/getOrFindSiteSettingsController.test.js +150 -0
  79. package/src/all/background_page/controller/{group/getOrFindGroupsUsersController.js → user/getOrFindAllUsersController.js} +12 -17
  80. package/src/all/background_page/controller/user/getOrFindAllUsersController.test.js +55 -0
  81. package/src/all/background_page/controller/user/getOrFindLoggedInUserController.js +3 -3
  82. package/src/all/background_page/controller/user/getOrFindLoggedInUserController.test.js +19 -15
  83. package/src/all/background_page/controller/user/updateUserLocalStorageController.test.js +8 -5
  84. package/src/all/background_page/event/accountRecoveryEvents.js +4 -4
  85. package/src/all/background_page/event/appEvents.js +7 -2
  86. package/src/all/background_page/event/authEvents.js +2 -2
  87. package/src/all/background_page/event/groupEvents.js +4 -17
  88. package/src/all/background_page/event/informCallToActionEvents.js +1 -1
  89. package/src/all/background_page/event/informMenuEvents.js +1 -1
  90. package/src/all/background_page/event/localeEvents.js +4 -3
  91. package/src/all/background_page/event/permissionEvents.js +13 -0
  92. package/src/all/background_page/event/recoverEvents.js +4 -4
  93. package/src/all/background_page/event/resourceEvents.js +6 -15
  94. package/src/all/background_page/event/resourceTypeEvents.js +4 -3
  95. package/src/all/background_page/event/setupEvents.js +4 -4
  96. package/src/all/background_page/event/siteSettingsEvents.js +29 -0
  97. package/src/all/background_page/event/userEvents.js +4 -8
  98. package/src/all/background_page/index.js +0 -37
  99. package/src/all/background_page/model/entity/account/abstractAccountEntity.js +2 -2
  100. package/src/all/background_page/model/entity/account/accountAccountRecoveryEntity.js +7 -17
  101. package/src/all/background_page/model/entity/account/accountEntity.js +7 -14
  102. package/src/all/background_page/model/entity/account/accountKitEntity.js +1 -2
  103. package/src/all/background_page/model/entity/account/accountRecoverEntity.js +4 -14
  104. package/src/all/background_page/model/entity/account/accountSetupEntity.js +4 -14
  105. package/src/all/background_page/model/entity/account/accountTemporaryEntity.js +2 -5
  106. package/src/all/background_page/model/entity/gpgkey/generate/generateGpgKeyPairOptionsEntity.test.js +5 -5
  107. package/src/all/background_page/model/entity/localStorage/localStorageMetadataEntity.js +49 -0
  108. package/src/all/background_page/model/entity/localStorage/localStorageMetadataEntity.test.data.js +23 -0
  109. package/src/all/background_page/model/entity/localStorage/localStorageMetadataEntity.test.js +51 -0
  110. package/src/all/background_page/model/entity/{organizationSettings/organizationSettingsEntity.js → siteSettings/siteSettingsEntity.js} +17 -24
  111. package/src/all/background_page/model/entity/{organizationSettings/organizationSettingsEntity.test.data.js → siteSettings/siteSettingsEntity.test.data.js} +9 -9
  112. package/src/all/background_page/model/entity/{organizationSettings/organizationSettingsEntity.test.js → siteSettings/siteSettingsEntity.test.js} +30 -39
  113. package/src/all/background_page/model/entity/user/userEntity.test.js +6 -6
  114. package/src/all/background_page/model/export/resources/resourcesKdbxExporter.js +40 -3
  115. package/src/all/background_page/model/export/resources/resourcesKdbxExporter.test.js +122 -0
  116. package/src/all/background_page/model/import/resources/resourcesKdbxImportParser.js +1 -1
  117. package/src/all/background_page/model/locale/localeModel.js +13 -8
  118. package/src/all/background_page/model/passwordExpiry/passwordExpirySettingsModel.js +6 -6
  119. package/src/all/background_page/model/passwordExpiry/passwordExpirySettingsModel.test.js +3 -2
  120. package/src/all/background_page/model/resource/resourceModel.js +4 -4
  121. package/src/all/background_page/model/user/userModel.js +7 -28
  122. package/src/all/background_page/model/user/userModel.test.js +51 -99
  123. package/src/all/background_page/pagemod/appBootstrapPagemod.js +4 -1
  124. package/src/all/background_page/pagemod/appBootstrapPagemod.test.js +5 -2
  125. package/src/all/background_page/pagemod/appPagemod.js +32 -6
  126. package/src/all/background_page/pagemod/appPagemod.test.js +22 -10
  127. package/src/all/background_page/pagemod/authPagemod.js +2 -10
  128. package/src/all/background_page/pagemod/authPagemod.test.js +4 -4
  129. package/src/all/background_page/pagemod/pagemodManager.test.js +5 -2
  130. package/src/all/background_page/pagemod/quickAccessPagemod.js +2 -2
  131. package/src/all/background_page/pagemod/quickAccessPagemod.test.js +4 -4
  132. package/src/all/background_page/pagemod/recoverPagemod.js +2 -2
  133. package/src/all/background_page/pagemod/recoverPagemod.test.js +6 -0
  134. package/src/all/background_page/pagemod/setupPagemod.js +2 -2
  135. package/src/all/background_page/pagemod/setupPagemod.test.js +6 -0
  136. package/src/all/background_page/pagemod/webIntegrationPagemod.js +21 -2
  137. package/src/all/background_page/pagemod/webIntegrationPagemod.test.js +16 -25
  138. package/src/all/background_page/service/account/getActiveAccountService.js +2 -3
  139. package/src/all/background_page/service/account/getLegacyAccountService.js +3 -14
  140. package/src/all/background_page/service/account/updateSsoCredentialsService.js +9 -5
  141. package/src/all/background_page/service/api/group/groupApiService.js +9 -16
  142. package/src/all/background_page/service/api/group/groupApiService.test.js +59 -26
  143. package/src/all/background_page/service/api/siteSettings/siteSettingsApiService.js +46 -0
  144. package/src/all/background_page/service/api/siteSettings/siteSettingsApiService.test.js +63 -0
  145. package/src/all/background_page/service/auth/checkAuthStatusService.js +27 -14
  146. package/src/all/background_page/service/auth/checkAuthStatusService.test.js +80 -62
  147. package/src/all/background_page/service/auth/postLoginService.js +3 -3
  148. package/src/all/background_page/service/auth/postLoginService.test.js +4 -4
  149. package/src/all/background_page/service/auth/startLoopAuthSessionCheckService.js +5 -1
  150. package/src/all/background_page/service/auth/startLoopAuthSessionCheckService.test.js +14 -8
  151. package/src/all/background_page/service/authenticationStatusService.js +13 -18
  152. package/src/all/background_page/service/authenticationStatusService.test.js +9 -6
  153. package/src/all/background_page/service/crypto/generateGpgKeyPairService.test.js +5 -5
  154. package/src/all/background_page/service/crypto/getGpgKeyCreationDateService.js +7 -6
  155. package/src/all/background_page/service/crypto/getGpgKeyCreationDateService.test.js +10 -7
  156. package/src/all/background_page/service/extension/onExtensionUpdateAvailableService.js +7 -2
  157. package/src/all/background_page/service/extension/onExtensionUpdateAvailableService.test.js +5 -5
  158. package/src/all/background_page/service/group/findGroupsService.js +42 -1
  159. package/src/all/background_page/service/group/findGroupsService.test.js +82 -0
  160. package/src/all/background_page/service/group/groupUpdateSecretsCryptoService.js +82 -0
  161. package/src/all/background_page/service/group/groupUpdateSecretsCryptoService.test.js +102 -0
  162. package/src/all/background_page/service/group/groupUpdateService.js +49 -78
  163. package/src/all/background_page/service/group/groupUpdateService.test.js +136 -0
  164. package/src/all/background_page/service/localStorage/localStorageService.js +8 -6
  165. package/src/all/background_page/service/localStorage/localStorageService.test.js +33 -15
  166. package/src/all/background_page/service/local_storage/abstractLocalStorage.js +193 -0
  167. package/src/all/background_page/service/local_storage/abstractLocalStorage.test.data.js +45 -0
  168. package/src/all/background_page/service/local_storage/abstractLocalStorage.test.js +271 -0
  169. package/src/all/background_page/service/local_storage/activeSessionLocalStorage.js +105 -0
  170. package/src/all/background_page/service/local_storage/activeSessionLocalStorage.test.js +153 -0
  171. package/src/all/background_page/service/local_storage/rbacLocalStorage.js +10 -82
  172. package/src/all/background_page/service/local_storage/rbacLocalStorage.test.js +8 -8
  173. package/src/all/background_page/service/local_storage/resourceTypeLocalStorage.js +10 -43
  174. package/src/all/background_page/service/local_storage/resourceTypeLocalStorage.test.js +68 -0
  175. package/src/all/background_page/service/local_storage/siteSettingsLocalStorage.js +104 -0
  176. package/src/all/background_page/service/local_storage/siteSettingsLocalStorage.test.js +114 -0
  177. package/src/all/background_page/service/local_storage/userMeLocalStorage.js +50 -0
  178. package/src/all/background_page/service/{sessionStorage/userMeSessionStorageService.test.js → local_storage/userMeLocalStorage.test.js} +55 -36
  179. package/src/all/background_page/service/metadata/encryptMetadataService.js +3 -3
  180. package/src/all/background_page/service/metadata/encryptMetadataService.test.js +11 -11
  181. package/src/all/background_page/service/metadata/findAndUpdateMetadataSettingsLocalStorageService.js +4 -4
  182. package/src/all/background_page/service/metadata/findAndUpdateMetadataSettingsLocalStorageService.test.js +18 -16
  183. package/src/all/background_page/service/metadata/getOrFindMetadataSettingsService.test.js +6 -8
  184. package/src/all/background_page/service/metadata/rotateMetadata/rotateResourcesMetadataKeyService.test.js +4 -4
  185. package/src/all/background_page/service/metadata/shareMetadataKeyPrivateService.js +3 -3
  186. package/src/all/background_page/service/metadata/shareMetadataKeyPrivateService.test.js +1 -1
  187. package/src/all/background_page/service/metadata/verifyOrTrustMetadataKeyService.js +4 -4
  188. package/src/all/background_page/service/metadata/verifyOrTrustMetadataKeyService.test.js +9 -7
  189. package/src/all/background_page/service/migrateMetadata/migrateMetadataResourcesService.js +4 -4
  190. package/src/all/background_page/service/migrateMetadata/migrateMetadataResourcesService.test.js +6 -6
  191. package/src/all/background_page/service/rbac/findAndUpdateRbacsLocalStorageService.js +2 -2
  192. package/src/all/background_page/service/rbac/getOrFindRbacService.js +1 -1
  193. package/src/all/background_page/service/resource/create/resourceCreateService.js +41 -51
  194. package/src/all/background_page/service/resource/create/resourceCreateService.test.js +100 -98
  195. package/src/all/background_page/service/resource/export/exportResourcesService.js +7 -7
  196. package/src/all/background_page/service/resource/findAndUpdateResourcesLocalStorageService.js +4 -4
  197. package/src/all/background_page/service/resource/findResourcesService.js +13 -16
  198. package/src/all/background_page/service/resource/findResourcesService.test.js +12 -11
  199. package/src/all/background_page/service/resource/getOrFindResourcesService.js +3 -3
  200. package/src/all/background_page/service/resource/import/ImportResourcesService.js +9 -9
  201. package/src/all/background_page/service/resource/import/ImportResourcesService.test.js +30 -15
  202. package/src/all/background_page/service/resource/update/resourceUpdateService.js +38 -19
  203. package/src/all/background_page/service/resource/update/resourceUpdateService.test.js +64 -31
  204. package/src/all/background_page/service/resourceType/getOrFindResourceTypesService.js +49 -0
  205. package/src/all/background_page/service/resourceType/getOrFindResourceTypesService.test.js +61 -0
  206. package/src/all/background_page/service/resourceType/getSecretSchemaResourceTypeService.js +44 -0
  207. package/src/all/background_page/service/resourceType/updateResourceTypesService.js +6 -4
  208. package/src/all/background_page/service/resourceType/updateResourceTypesService.test.js +19 -14
  209. package/src/all/background_page/service/secretRevisions/findAndDecryptSecretRevisionsService.js +5 -4
  210. package/src/all/background_page/service/secretRevisions/findAndDecryptSecretRevisionsService.test.js +16 -9
  211. package/src/all/background_page/service/share/shareResourceService.js +4 -4
  212. package/src/all/background_page/service/share/shareResourceService.test.js +6 -6
  213. package/src/all/background_page/service/siteSettings/findAndUpdateSiteSettingsLocalStorageService.js +77 -0
  214. package/src/all/background_page/service/siteSettings/findAndUpdateSiteSettingsLocalStorageService.test.js +130 -0
  215. package/src/all/background_page/service/siteSettings/findSiteSettingsService.js +47 -0
  216. package/src/all/background_page/service/siteSettings/findSiteSettingsService.test.js +68 -0
  217. package/src/all/background_page/service/siteSettings/getOrFindSiteSettingsService.js +84 -0
  218. package/src/all/background_page/service/siteSettings/getOrFindSiteSettingsService.test.js +175 -0
  219. package/src/all/background_page/service/siteSettings/siteSettingsRuntimeCache.js +70 -0
  220. package/src/all/background_page/service/sso/generateSsoKitService.test.js +2 -2
  221. package/src/all/background_page/service/toolbar/toolbarService.js +6 -4
  222. package/src/all/background_page/service/toolbar/toolbarService.test.js +14 -13
  223. package/src/all/background_page/service/user/findAndUpdateUsersLocalStorageService.js +4 -4
  224. package/src/all/background_page/service/user/findAndUpdateUsersLocalStorageService.test.js +3 -3
  225. package/src/all/background_page/service/user/getOrFindMeService.js +64 -0
  226. package/src/all/background_page/service/user/getOrFindMeService.test.js +65 -0
  227. package/src/all/background_page/service/userKeyPolicies/findUserKeyPoliciesSettingsService.js +5 -4
  228. package/src/all/background_page/service/userKeyPolicies/findUserKeyPoliciesSettingsService.test.js +12 -11
  229. package/src/all/background_page/service/validator/appEmailValidatorService.js +11 -6
  230. package/src/all/background_page/service/validator/appEmailValidatorService.test.js +11 -11
  231. package/src/all/common/polyfill/browserPolyfill.js +8 -8
  232. package/src/all/locales/cs-CZ/common.json +1 -4
  233. package/src/all/locales/de-DE/common.json +1 -4
  234. package/src/all/locales/en-UK/common.json +0 -3
  235. package/src/all/locales/es-ES/common.json +1 -4
  236. package/src/all/locales/fr-FR/common.json +1 -4
  237. package/src/all/locales/it-IT/common.json +1 -4
  238. package/src/all/locales/ja-JP/common.json +1 -4
  239. package/src/all/locales/ko-KR/common.json +0 -3
  240. package/src/all/locales/lt-LT/common.json +1 -4
  241. package/src/all/locales/nl-NL/common.json +1 -4
  242. package/src/all/locales/pl-PL/common.json +1 -4
  243. package/src/all/locales/pt-BR/common.json +1 -4
  244. package/src/all/locales/ro-RO/common.json +1 -4
  245. package/src/all/locales/ru-RU/common.json +1 -4
  246. package/src/all/locales/sl-SI/common.json +1 -4
  247. package/src/all/locales/sv-SE/common.json +1 -4
  248. package/src/all/locales/uk-UA/common.json +1 -4
  249. package/src/all/webAccessibleResources/js/app/QuickAccess.js +7 -0
  250. package/src/chrome/manifest.json +1 -1
  251. package/src/chrome-mv3/manifest.json +1 -1
  252. package/src/chrome-mv3/offscreens/service/group/addUsersToGroupOffscreenService.js +132 -0
  253. package/src/chrome-mv3/offscreens/service/group/addUsersToGroupOffscreenService.test.js +125 -0
  254. package/src/chrome-mv3/offscreens/service/offscreen/handleOffscreenRequestService.js +4 -0
  255. package/src/chrome-mv3/serviceWorker/service/addUsersToGroup/requestAddUsersToGroupOffscreenService.js +83 -0
  256. package/src/chrome-mv3/serviceWorker/service/addUsersToGroup/requestAddUsersToGroupOffscreenService.test.js +116 -0
  257. package/src/chrome-mv3/serviceWorker/service/addUsersToGroup/responseAddUsersToGroupOffscreenService.js +99 -0
  258. package/src/chrome-mv3/serviceWorker/service/addUsersToGroup/responseAddUsersToGroupOffscreenService.test.data.js +45 -0
  259. package/src/chrome-mv3/serviceWorker/service/addUsersToGroup/responseAddUsersToGroupOffscreenService.test.js +87 -0
  260. package/src/chrome-mv3/serviceWorker/service/network/requestFetchOffscreenService.js +0 -1
  261. package/src/chrome-mv3/serviceWorker/service/offscreen/handleOffscreenResponseService.js +15 -0
  262. package/src/firefox/manifest.json +1 -1
  263. package/src/safari/background_page/index.js +0 -37
  264. package/src/safari/common/polyfill/safariBrowserPolyfill.js +10 -10
  265. package/src/safari/manifest.json +1 -1
  266. package/test/jest.setup.js +4 -2
  267. package/src/all/background_page/controller/group/getOrFindGroupsUsersController.test.js +0 -69
  268. package/src/all/background_page/controller/organizationSettings/getOrganizationSettingsController.js +0 -55
  269. package/src/all/background_page/controller/organizationSettings/getOrganizationSettingsController.test.js +0 -45
  270. package/src/all/background_page/controller/resource/findAllByIdsForDisplayPermissionsController.js +0 -76
  271. package/src/all/background_page/controller/resource/findAllByIdsForDisplayPermissionsController.test.js +0 -102
  272. package/src/all/background_page/event/organizationSettingsEvents.js +0 -37
  273. package/src/all/background_page/model/organizationSettings/organizationSettingsModel.js +0 -93
  274. package/src/all/background_page/model/resourceType/resourceTypeModel.js +0 -72
  275. package/src/all/background_page/model/resourceType/resourceTypeModel.test.js +0 -101
  276. package/src/all/background_page/service/api/organizationSettings/organizationSettingsService.js +0 -58
  277. package/src/all/background_page/service/group/getOrFindGroupsService.js +0 -65
  278. package/src/all/background_page/service/group/getOrFindGroupsService.test.js +0 -168
  279. package/src/all/background_page/service/group/getOrFindGroupsUsersService.js +0 -51
  280. package/src/all/background_page/service/group/getOrFindGroupsUsersService.test.js +0 -94
  281. package/src/all/background_page/service/local_storage/authStatusLocalStorage.js +0 -70
  282. package/src/all/background_page/service/sessionStorage/userMeSessionStorageService.js +0 -94
@@ -14,30 +14,23 @@
14
14
  import Entity from "passbolt-styleguide/src/shared/models/entity/abstract/entity";
15
15
  import EntitySchema from "passbolt-styleguide/src/shared/models/entity/abstract/entitySchema";
16
16
 
17
- const ENTITY_NAME = "OrganizationSettings";
17
+ const ENTITY_NAME = "SiteSettings";
18
18
 
19
19
  // Organization status
20
20
  const ORGANIZATION_ENABLED = "enabled";
21
21
  const ORGANIZATION_DISABLED = "disabled";
22
22
  const ORGANIZATION_NOT_FOUND = "not found";
23
23
 
24
- class OrganizationSettingsEntity extends Entity {
24
+ class SiteSettingsEntity extends Entity {
25
25
  /**
26
26
  * @inheritDoc
27
27
  * Sanitize: Override default settings using the data provided in the DTO.
28
28
  */
29
- constructor(organizationSettingsDto, options = {}) {
29
+ constructor(siteSettingsDto, options = {}) {
30
30
  // Default properties values
31
- const props = Object.assign(OrganizationSettingsEntity.getDefault(), organizationSettingsDto);
32
- const sanitizedDto = OrganizationSettingsEntity.sanitizeDto(props);
33
- super(
34
- EntitySchema.validate(
35
- OrganizationSettingsEntity.ENTITY_NAME,
36
- sanitizedDto,
37
- OrganizationSettingsEntity.getSchema(),
38
- ),
39
- options,
40
- );
31
+ const props = Object.assign(SiteSettingsEntity.getDefault(), siteSettingsDto);
32
+ const sanitizedDto = SiteSettingsEntity.sanitizeDto(props);
33
+ super(EntitySchema.validate(SiteSettingsEntity.ENTITY_NAME, sanitizedDto, SiteSettingsEntity.getSchema()), options);
41
34
  }
42
35
 
43
36
  /**
@@ -46,7 +39,7 @@ class OrganizationSettingsEntity extends Entity {
46
39
  */
47
40
  static getDefault() {
48
41
  return {
49
- status: OrganizationSettingsEntity.ORGANIZATION_ENABLED,
42
+ status: SiteSettingsEntity.ORGANIZATION_ENABLED,
50
43
  };
51
44
  }
52
45
 
@@ -62,9 +55,9 @@ class OrganizationSettingsEntity extends Entity {
62
55
  status: {
63
56
  type: "string",
64
57
  enum: [
65
- OrganizationSettingsEntity.ORGANIZATION_ENABLED,
66
- OrganizationSettingsEntity.ORGANIZATION_DISABLED,
67
- OrganizationSettingsEntity.ORGANIZATION_NOT_FOUND,
58
+ SiteSettingsEntity.ORGANIZATION_ENABLED,
59
+ SiteSettingsEntity.ORGANIZATION_DISABLED,
60
+ SiteSettingsEntity.ORGANIZATION_NOT_FOUND,
68
61
  ],
69
62
  },
70
63
  app: {
@@ -84,7 +77,7 @@ class OrganizationSettingsEntity extends Entity {
84
77
  /**
85
78
  * Return a disabled organization settings.
86
79
  */
87
- static get disabledOrganizationSettings() {
80
+ static get disabledSiteSettings() {
88
81
  return {
89
82
  status: this.ORGANIZATION_DISABLED,
90
83
  };
@@ -100,7 +93,7 @@ class OrganizationSettingsEntity extends Entity {
100
93
  static sanitizeDto(dto) {
101
94
  const sanitizedDto = JSON.parse(JSON.stringify(dto));
102
95
 
103
- OrganizationSettingsEntity.sanitizeEmailValidateRegex(sanitizedDto);
96
+ SiteSettingsEntity.sanitizeEmailValidateRegex(sanitizedDto);
104
97
 
105
98
  return sanitizedDto;
106
99
  }
@@ -215,7 +208,7 @@ class OrganizationSettingsEntity extends Entity {
215
208
  * ==================================================
216
209
  */
217
210
  /**
218
- * OrganizationSettingsEntity.ENTITY_NAME
211
+ * SiteSettingsEntity.ENTITY_NAME
219
212
  * @returns {string}
220
213
  */
221
214
  static get ENTITY_NAME() {
@@ -223,7 +216,7 @@ class OrganizationSettingsEntity extends Entity {
223
216
  }
224
217
 
225
218
  /**
226
- * OrganizationSettingsEntity.ORGANIZATION_ENABLED
219
+ * SiteSettingsEntity.ORGANIZATION_ENABLED
227
220
  * @returns {string}
228
221
  */
229
222
  static get ORGANIZATION_ENABLED() {
@@ -231,7 +224,7 @@ class OrganizationSettingsEntity extends Entity {
231
224
  }
232
225
 
233
226
  /**
234
- * OrganizationSettingsEntity.ORGANIZATION_DISABLED
227
+ * SiteSettingsEntity.ORGANIZATION_DISABLED
235
228
  * @returns {string}
236
229
  */
237
230
  static get ORGANIZATION_DISABLED() {
@@ -239,7 +232,7 @@ class OrganizationSettingsEntity extends Entity {
239
232
  }
240
233
 
241
234
  /**
242
- * OrganizationSettingsEntity.ORGANIZATION_NOT_FOUND
235
+ * SiteSettingsEntity.ORGANIZATION_NOT_FOUND
243
236
  * @returns {string}
244
237
  */
245
238
  static get ORGANIZATION_NOT_FOUND() {
@@ -247,4 +240,4 @@ class OrganizationSettingsEntity extends Entity {
247
240
  }
248
241
  }
249
242
 
250
- export default OrganizationSettingsEntity;
243
+ export default SiteSettingsEntity;
@@ -12,11 +12,11 @@
12
12
  * @since 3.6.0
13
13
  */
14
14
 
15
- import OrganizationSettingsEntity from "./organizationSettingsEntity";
15
+ import SiteSettingsEntity from "./siteSettingsEntity";
16
16
 
17
- export const anonymousOrganizationSettings = (data = {}) => {
17
+ export const anonymousSiteSettings = (data = {}) => {
18
18
  const defaultData = {
19
- status: OrganizationSettingsEntity.ORGANIZATION_ENABLED,
19
+ status: SiteSettingsEntity.ORGANIZATION_ENABLED,
20
20
  app: {
21
21
  url: "http://127.0.0.1:3001",
22
22
  locale: "en-UK",
@@ -132,8 +132,8 @@ export const anonymousOrganizationSettings = (data = {}) => {
132
132
  return Object.assign(defaultData, data);
133
133
  };
134
134
 
135
- export const defaultCeOrganizationSettings = (siteSettings) => {
136
- const defaultData = anonymousOrganizationSettings();
135
+ export const defaultCeSiteSettings = (siteSettings) => {
136
+ const defaultData = anonymousSiteSettings();
137
137
  defaultData.app = {
138
138
  url: "http://127.0.0.1:3001",
139
139
  locale: "en-UK",
@@ -214,8 +214,8 @@ export const defaultCeOrganizationSettings = (siteSettings) => {
214
214
  return Object.assign(defaultData, siteSettings);
215
215
  };
216
216
 
217
- export const defaultProOrganizationSettings = (siteSettings) => {
218
- const defaultData = defaultCeOrganizationSettings();
217
+ export const defaultProSiteSettings = (siteSettings) => {
218
+ const defaultData = defaultCeSiteSettings();
219
219
  defaultData.passbolt.edition = "pro";
220
220
  defaultData.passbolt.plugins = Object.assign(defaultData.passbolt.plugins, {
221
221
  accountRecoveryRequestHelp: {
@@ -267,8 +267,8 @@ export const defaultProOrganizationSettings = (siteSettings) => {
267
267
  return Object.assign(defaultData, siteSettings);
268
268
  };
269
269
 
270
- export const customEmailValidationProOrganizationSettings = (siteSettings) => {
271
- const defaultData = defaultProOrganizationSettings();
270
+ export const customEmailValidationProSiteSettings = (siteSettings) => {
271
+ const defaultData = defaultProSiteSettings();
272
272
  defaultData.passbolt.email = {
273
273
  validate: {
274
274
  regex: "\/.*@passbolt.(c|com)$\/",
@@ -13,25 +13,22 @@
13
13
  */
14
14
 
15
15
  import EntitySchema from "passbolt-styleguide/src/shared/models/entity/abstract/entitySchema";
16
- import OrganizationSettingsEntity from "./organizationSettingsEntity";
17
- import {
18
- customEmailValidationProOrganizationSettings,
19
- defaultProOrganizationSettings,
20
- } from "./organizationSettingsEntity.test.data";
16
+ import SiteSettingsEntity from "./siteSettingsEntity";
17
+ import { customEmailValidationProSiteSettings, defaultProSiteSettings } from "./siteSettingsEntity.test.data";
21
18
  import * as assertEntityProperty from "passbolt-styleguide/test/assert/assertEntityProperty";
22
19
 
23
- describe("OrganizationSettingsEntity entity", () => {
24
- describe("OrganizationSettingsEntity::getSchema", () => {
20
+ describe("SiteSettingsEntity entity", () => {
21
+ describe("SiteSettingsEntity::getSchema", () => {
25
22
  it("schema must validate", () => {
26
- EntitySchema.validateSchema(OrganizationSettingsEntity.ENTITY_NAME, OrganizationSettingsEntity.getSchema());
23
+ EntitySchema.validateSchema(SiteSettingsEntity.ENTITY_NAME, SiteSettingsEntity.getSchema());
27
24
  });
28
25
 
29
26
  it("validates status property", () => {
30
27
  const successValues = ["enabled", "disabled", "not found"];
31
28
  const failValues = ["string"];
32
29
 
33
- assertEntityProperty.enumeration(OrganizationSettingsEntity, "status", successValues, failValues);
34
- assertEntityProperty.notRequired(OrganizationSettingsEntity, "status");
30
+ assertEntityProperty.enumeration(SiteSettingsEntity, "status", successValues, failValues);
31
+ assertEntityProperty.notRequired(SiteSettingsEntity, "status");
35
32
  });
36
33
 
37
34
  it("validates app property", () => {
@@ -42,8 +39,8 @@ describe("OrganizationSettingsEntity entity", () => {
42
39
  */
43
40
  const failingScenarios = [];
44
41
 
45
- assertEntityProperty.assert(OrganizationSettingsEntity, "app", successScenarios, failingScenarios, "type");
46
- assertEntityProperty.notRequired(OrganizationSettingsEntity, "app");
42
+ assertEntityProperty.assert(SiteSettingsEntity, "app", successScenarios, failingScenarios, "type");
43
+ assertEntityProperty.notRequired(SiteSettingsEntity, "app");
47
44
  });
48
45
 
49
46
  it("validates passbolt property", () => {
@@ -54,8 +51,8 @@ describe("OrganizationSettingsEntity entity", () => {
54
51
  */
55
52
  const failingScenarios = [];
56
53
 
57
- assertEntityProperty.assert(OrganizationSettingsEntity, "passbolt", successScenarios, failingScenarios, "type");
58
- assertEntityProperty.notRequired(OrganizationSettingsEntity, "passbolt");
54
+ assertEntityProperty.assert(SiteSettingsEntity, "passbolt", successScenarios, failingScenarios, "type");
55
+ assertEntityProperty.notRequired(SiteSettingsEntity, "passbolt");
59
56
  });
60
57
 
61
58
  it("validates serverTimeDiff property", () => {
@@ -66,52 +63,46 @@ describe("OrganizationSettingsEntity entity", () => {
66
63
  assertEntityProperty.SCENARIO_OBJECT,
67
64
  ];
68
65
 
69
- assertEntityProperty.assert(
70
- OrganizationSettingsEntity,
71
- "serverTimeDiff",
72
- successScenarios,
73
- failingScenarios,
74
- "type",
75
- );
76
- assertEntityProperty.notRequired(OrganizationSettingsEntity, "serverTimeDiff");
66
+ assertEntityProperty.assert(SiteSettingsEntity, "serverTimeDiff", successScenarios, failingScenarios, "type");
67
+ assertEntityProperty.notRequired(SiteSettingsEntity, "serverTimeDiff");
77
68
  });
78
69
  });
79
70
 
80
- describe("OrganizationSettingsEntity::constructor", () => {
81
- it("Should instantiate an OrganizationSettingsEntity with a minimal DTO", () => {
71
+ describe("SiteSettingsEntity::constructor", () => {
72
+ it("Should instantiate an SiteSettingsEntity with a minimal DTO", () => {
82
73
  expect.assertions(2);
83
74
  const dto = {};
84
- expect(() => new OrganizationSettingsEntity(dto)).not.toThrow();
85
- expect(new OrganizationSettingsEntity(dto).toDto()).toStrictEqual({
75
+ expect(() => new SiteSettingsEntity(dto)).not.toThrow();
76
+ expect(new SiteSettingsEntity(dto).toDto()).toStrictEqual({
86
77
  status: "enabled",
87
78
  });
88
79
  });
89
80
 
90
- it("Should instantiate an OrganizationSettingsEntity with full DTO", () => {
81
+ it("Should instantiate an SiteSettingsEntity with full DTO", () => {
91
82
  expect.assertions(2);
92
- const dto = defaultProOrganizationSettings();
93
- expect(() => new OrganizationSettingsEntity(dto)).not.toThrow();
94
- expect(new OrganizationSettingsEntity(dto).toDto()).toStrictEqual(dto);
83
+ const dto = defaultProSiteSettings();
84
+ expect(() => new SiteSettingsEntity(dto)).not.toThrow();
85
+ expect(new SiteSettingsEntity(dto).toDto()).toStrictEqual(dto);
95
86
  });
96
87
  });
97
88
 
98
- describe("OrganizationSettingsEntity::sanitizeEmailValidateRegex", () => {
89
+ describe("SiteSettingsEntity::sanitizeEmailValidateRegex", () => {
99
90
  it("should sanitize API regex and remove starting and trailing slash", () => {
100
- const organizationSettings = customEmailValidationProOrganizationSettings();
101
- OrganizationSettingsEntity.sanitizeEmailValidateRegex(organizationSettings);
102
- expect(organizationSettings.passbolt.email.validate.regex).toEqual(".*@passbolt.(c|com)$");
91
+ const siteSettings = customEmailValidationProSiteSettings();
92
+ SiteSettingsEntity.sanitizeEmailValidateRegex(siteSettings);
93
+ expect(siteSettings.passbolt.email.validate.regex).toEqual(".*@passbolt.(c|com)$");
103
94
  });
104
95
  });
105
96
 
106
- describe("OrganizationSettingsEntity::emailValidateRegex", () => {
97
+ describe("SiteSettingsEntity::emailValidateRegex", () => {
107
98
  it("should return null if undefined", () => {
108
- const organizationSettings = defaultProOrganizationSettings();
109
- const entity = new OrganizationSettingsEntity(organizationSettings);
99
+ const siteSettings = defaultProSiteSettings();
100
+ const entity = new SiteSettingsEntity(siteSettings);
110
101
  expect(entity.emailValidateRegex).toBeNull();
111
102
  });
112
103
  it("should return the customized setting if any", () => {
113
- const organizationSettings = customEmailValidationProOrganizationSettings();
114
- const entity = new OrganizationSettingsEntity(organizationSettings);
104
+ const siteSettings = customEmailValidationProSiteSettings();
105
+ const entity = new SiteSettingsEntity(siteSettings);
115
106
  expect(entity.emailValidateRegex).toEqual(".*@passbolt.(c|com)$");
116
107
  });
117
108
  });
@@ -13,12 +13,12 @@
13
13
  */
14
14
  import BextUserEntity from "./userEntity";
15
15
  import AppEmailValidatorService from "../../../service/validator/appEmailValidatorService";
16
- import OrganizationSettingsModel from "../../organizationSettings/organizationSettingsModel";
17
- import OrganizationSettingsEntity from "../organizationSettings/organizationSettingsEntity";
18
- import { customEmailValidationProOrganizationSettings } from "../organizationSettings/organizationSettingsEntity.test.data";
16
+ import SiteSettingsEntity from "passbolt-styleguide/src/shared/models/entity/siteSettings/siteSettingsEntity";
17
+ import { customEmailValidationProSiteSettings } from "passbolt-styleguide/src/shared/models/entity/siteSettings/siteSettingsEntity.test.data";
19
18
  import { defaultUserDto } from "passbolt-styleguide/src/shared/models/entity/user/userEntity.test.data";
20
19
  import GroupsUsersCollection from "passbolt-styleguide/src/shared/models/entity/groupUser/groupsUsersCollection";
21
20
  import * as assertEntityProperty from "passbolt-styleguide/test/assert/assertEntityProperty";
21
+ import SiteSettingsRuntimeCache from "../../../service/siteSettings/siteSettingsRuntimeCache";
22
22
 
23
23
  describe("BextUserEntity", () => {
24
24
  describe("BextUserEntity::getSchema", () => {
@@ -36,8 +36,8 @@ describe("BextUserEntity", () => {
36
36
 
37
37
  it("validates username with custom validation rule", () => {
38
38
  expect.assertions(2);
39
- const organizationSettings = customEmailValidationProOrganizationSettings();
40
- OrganizationSettingsModel.set(new OrganizationSettingsEntity(organizationSettings));
39
+ const organizationSettings = customEmailValidationProSiteSettings();
40
+ SiteSettingsRuntimeCache.set(new SiteSettingsEntity(organizationSettings));
41
41
  const dto = defaultUserDto({ username: "ada@passbolt.c" });
42
42
  const entity = new BextUserEntity(dto);
43
43
  expect(entity.username).toEqual("ada@passbolt.c");
@@ -45,7 +45,7 @@ describe("BextUserEntity", () => {
45
45
  * Ensure that the custom formula used to validate the format of the email is dynamic, and can be changed even if the
46
46
  * entity schema is cached. This formula might loaded after the schema was cached and could lead to user not valid.
47
47
  */
48
- OrganizationSettingsModel.flushCache();
48
+ SiteSettingsRuntimeCache.flushAll();
49
49
  expect(() => new BextUserEntity(dto)).toThrowEntityValidationError("username", "custom");
50
50
  });
51
51
  });
@@ -14,6 +14,7 @@ import ExternalFolderEntity from "../../entity/folder/external/externalFolderEnt
14
14
  import * as kdbxweb from "kdbxweb";
15
15
  import { FORMAT_KDBX, FORMAT_KDBX_OTHERS } from "../../entity/export/exportResourcesFileEntity";
16
16
  import { ICON_TYPE_KEEPASS_ICON_SET } from "passbolt-styleguide/src/shared/models/entity/resource/metadata/IconEntity";
17
+ import { KDBX_SUPPORTED_FIELDS } from "../../import/resources/resourcesKdbxImportParser";
17
18
 
18
19
  class ResourcesKdbxExporter {
19
20
  /**
@@ -22,11 +23,12 @@ class ResourcesKdbxExporter {
22
23
  */
23
24
  constructor(exportEntity) {
24
25
  this.exportEntity = exportEntity;
26
+ this.customFieldsConflicts = [];
25
27
  }
26
28
 
27
29
  /**
28
30
  * Export
29
- * @returns {Promise<void>}
31
+ * @returns {Promise<Array<{resourceName: string, originalKey: string, newKey: string}>>} The custom fields renamed to avoid conflicting with reserved KeePass field names
30
32
  */
31
33
  async export() {
32
34
  const kdbxDb = await this.createKdbxDb();
@@ -39,6 +41,7 @@ class ResourcesKdbxExporter {
39
41
  this.createKdbxEntry(kdbxDb, childExportResource, kdbxDb.getDefaultGroup()),
40
42
  );
41
43
  this.exportEntity.file = await kdbxDb.save();
44
+ return this.customFieldsConflicts;
42
45
  }
43
46
 
44
47
  /**
@@ -120,7 +123,9 @@ class ResourcesKdbxExporter {
120
123
  }
121
124
 
122
125
  /**
123
- * Set the custom fields according to the kdbx format
126
+ * Set the custom fields according to the kdbx format.
127
+ * A custom field whose key collides with a reserved KeePass field (e.g. "Password") or an already set field
128
+ * is renamed with a post-fix numeration ("Password (1)") to avoid overwriting the reserved field value.
124
129
  * @param {kdbxweb.KdbxEntry} kdbxEntry
125
130
  * @param {ExternalResourceEntity} externalResourceEntity
126
131
  * @returns {void}
@@ -128,11 +133,43 @@ class ResourcesKdbxExporter {
128
133
  setCustomFields(kdbxEntry, externalResourceEntity) {
129
134
  if (externalResourceEntity.customFields) {
130
135
  externalResourceEntity.customFields.items.forEach((customField) => {
131
- kdbxEntry.fields.set(customField.key, kdbxweb.ProtectedValue.fromString(customField.value));
136
+ const key = this.getNonConflictingFieldName(kdbxEntry, customField.key);
137
+ if (key !== customField.key) {
138
+ this.customFieldsConflicts.push({
139
+ resourceName: externalResourceEntity.name,
140
+ originalKey: customField.key,
141
+ newKey: key,
142
+ });
143
+ }
144
+ kdbxEntry.fields.set(key, kdbxweb.ProtectedValue.fromString(customField.value));
132
145
  });
133
146
  }
134
147
  }
135
148
 
149
+ /**
150
+ * Resolve a custom field key to a name that does not conflict with a reserved KeePass field or an already set field.
151
+ * A name conflicts when it is a reserved field or already present on the entry. The static reserved list is required
152
+ * because some reserved fields (e.g. "Notes") are set after the custom fields, while already set fields (including
153
+ * the multi-uri KP2A_URL fields, written before the custom fields) are caught by the entry lookup.
154
+ * @param {kdbxweb.KdbxEntry} kdbxEntry
155
+ * @param {string} key The custom field key
156
+ * @returns {string} The original key, or a numbered variant ("key (1)", "key (2)", ...) when it conflicts
157
+ */
158
+ getNonConflictingFieldName(kdbxEntry, key) {
159
+ const isConflicting = (name) => KDBX_SUPPORTED_FIELDS.includes(name) || kdbxEntry.fields.has(name);
160
+
161
+ if (!isConflicting(key)) {
162
+ return key;
163
+ }
164
+ let index = 1;
165
+ let candidate = `${key} (${index})`;
166
+ while (isConflicting(candidate)) {
167
+ index++;
168
+ candidate = `${key} (${index})`;
169
+ }
170
+ return candidate;
171
+ }
172
+
136
173
  /**
137
174
  * Set the URL fields according to the kdbx format
138
175
  * @param {kdbxweb.KdbxEntry} kdbxEntry
@@ -21,6 +21,7 @@ import fs from "fs";
21
21
  import { defaultTotpDto } from "../../entity/totp/totpDto.test.data";
22
22
  import { defaultIconDto } from "passbolt-styleguide/src/shared/models/entity/resource/metadata/iconEntity.test.data";
23
23
  import { defaultCustomFieldsCollection } from "passbolt-styleguide/src/shared/models/entity/customField/customFieldsCollection.test.data";
24
+ import { defaultCustomField } from "passbolt-styleguide/src/shared/models/entity/customField/customFieldEntity.test.data";
24
25
 
25
26
  global.kdbxweb = kdbxweb;
26
27
  kdbxweb.CryptoEngine.argon2 = argon2;
@@ -398,4 +399,125 @@ describe("ResourcesKdbxExporter", () => {
398
399
  const kdbxCredentials = new kdbxweb.Credentials(null, kdbxweb.ByteUtils.base64ToBytes(exportEntity.keyfile));
399
400
  await kdbxweb.Kdbx.load(exportEntity.file, kdbxCredentials);
400
401
  });
402
+
403
+ describe("custom field name conflicts", () => {
404
+ async function exportAndLoadFirstEntry(customFields, data = {}) {
405
+ const exportResource = buildImportResourceDto(1, {
406
+ name: "GitHub",
407
+ totp: undefined,
408
+ uris: [],
409
+ custom_fields: customFields,
410
+ ...data,
411
+ });
412
+ const exportDto = { format: "kdbx", export_resources: [exportResource], export_folders: [] };
413
+ const exportEntity = new ExportResourcesFileEntity(exportDto);
414
+ const exporter = new ResourcesKdbxExporter(exportEntity);
415
+ const conflicts = await exporter.export();
416
+ const kdbxDb = await kdbxweb.Kdbx.load(exportEntity.file, new kdbxweb.Credentials(null, null));
417
+ return { entry: kdbxDb.groups[0].entries[0], conflicts };
418
+ }
419
+
420
+ it("should rename a custom field colliding with the reserved Password field and preserve the real password", async () => {
421
+ expect.assertions(3);
422
+ const { entry, conflicts } = await exportAndLoadFirstEntry([
423
+ defaultCustomField({ metadata_key: "Password", secret_value: "evil-password" }),
424
+ ]);
425
+
426
+ expect(entry.fields.get("Password").getText()).toEqual("Secret 1");
427
+ expect(entry.fields.get("Password (1)").getText()).toEqual("evil-password");
428
+ expect(conflicts).toEqual([{ resourceName: "GitHub", originalKey: "Password", newKey: "Password (1)" }]);
429
+ });
430
+
431
+ it("should rename a custom field named Notes even though Notes is written after the custom fields", async () => {
432
+ expect.assertions(2);
433
+ const { entry } = await exportAndLoadFirstEntry(
434
+ [defaultCustomField({ metadata_key: "Notes", secret_value: "evil-notes" })],
435
+ { description: "real description" },
436
+ );
437
+
438
+ expect(entry.fields.get("Notes")).toEqual("real description");
439
+ expect(entry.fields.get("Notes (1)").getText()).toEqual("evil-notes");
440
+ });
441
+
442
+ it("should number multiple custom fields colliding with the same reserved field", async () => {
443
+ expect.assertions(4);
444
+ const { entry, conflicts } = await exportAndLoadFirstEntry([
445
+ defaultCustomField({ metadata_key: "Password", secret_value: "v1" }),
446
+ defaultCustomField({ metadata_key: "Password", secret_value: "v2" }),
447
+ ]);
448
+
449
+ expect(entry.fields.get("Password").getText()).toEqual("Secret 1");
450
+ expect(entry.fields.get("Password (1)").getText()).toEqual("v1");
451
+ expect(entry.fields.get("Password (2)").getText()).toEqual("v2");
452
+ expect(conflicts).toHaveLength(2);
453
+ });
454
+
455
+ it("should not lose data when a custom field is literally named like a renamed field", async () => {
456
+ expect.assertions(3);
457
+ const { entry } = await exportAndLoadFirstEntry([
458
+ defaultCustomField({ metadata_key: "Password", secret_value: "v1" }),
459
+ defaultCustomField({ metadata_key: "Password (1)", secret_value: "literal" }),
460
+ ]);
461
+
462
+ expect(entry.fields.get("Password").getText()).toEqual("Secret 1");
463
+ expect(entry.fields.get("Password (1)").getText()).toEqual("v1");
464
+ expect(entry.fields.get("Password (1) (1)").getText()).toEqual("literal");
465
+ });
466
+
467
+ it("should rename a custom field colliding with the reserved Password field even when no real password is set", async () => {
468
+ expect.assertions(2);
469
+ const { entry } = await exportAndLoadFirstEntry(
470
+ [defaultCustomField({ metadata_key: "Password", secret_value: "value" })],
471
+ { secret_clear: "" },
472
+ );
473
+
474
+ // The reserved Password slot keeps its default empty value rather than the custom value.
475
+ const passwordField = entry.fields.get("Password");
476
+ const passwordValue = typeof passwordField === "string" ? passwordField : passwordField?.getText();
477
+ expect(passwordValue).not.toEqual("value");
478
+ expect(entry.fields.get("Password (1)").getText()).toEqual("value");
479
+ });
480
+
481
+ it("should rename a custom field colliding with the multi-uri KP2A_URL field", async () => {
482
+ expect.assertions(2);
483
+ const { entry } = await exportAndLoadFirstEntry(
484
+ [defaultCustomField({ metadata_key: "KP2A_URL", secret_value: "custom-value" })],
485
+ { uris: ["https://url.com", "https://alt.com"] },
486
+ );
487
+
488
+ expect(entry.fields.get("KP2A_URL")).toEqual("https://alt.com");
489
+ expect(entry.fields.get("KP2A_URL (1)").getText()).toEqual("custom-value");
490
+ });
491
+
492
+ it("should not rename custom fields that do not conflict and return no conflicts", async () => {
493
+ expect.assertions(3);
494
+ const { entry, conflicts } = await exportAndLoadFirstEntry([
495
+ defaultCustomField({ metadata_key: "Key 0", secret_value: "Value 0" }),
496
+ defaultCustomField({ metadata_key: "Key 1", secret_value: "Value 1" }),
497
+ ]);
498
+
499
+ expect(entry.fields.get("Key 0").getText()).toEqual("Value 0");
500
+ expect(entry.fields.get("Key 1").getText()).toEqual("Value 1");
501
+ expect(conflicts).toEqual([]);
502
+ });
503
+
504
+ it("should rename a custom field colliding with the reserved otp field for other keepass", async () => {
505
+ expect.assertions(2);
506
+ const exportResource = buildImportResourceDto(1, {
507
+ name: "GitHub",
508
+ uris: [],
509
+ totp: defaultTotpDto(),
510
+ custom_fields: [defaultCustomField({ metadata_key: "otp", secret_value: "custom-otp" })],
511
+ });
512
+ const exportDto = { format: "kdbx-others", export_resources: [exportResource], export_folders: [] };
513
+ const exportEntity = new ExportResourcesFileEntity(exportDto);
514
+ const exporter = new ResourcesKdbxExporter(exportEntity);
515
+ await exporter.export();
516
+ const kdbxDb = await kdbxweb.Kdbx.load(exportEntity.file, new kdbxweb.Credentials(null, null));
517
+ const entry = kdbxDb.groups[0].entries[0];
518
+
519
+ expect(entry.fields.get("otp").getText()).toContain("otpauth://");
520
+ expect(entry.fields.get("otp (1)").getText()).toEqual("custom-otp");
521
+ });
522
+ });
401
523
  });
@@ -21,7 +21,7 @@ import { CUSTOM_FIELD_TYPE } from "passbolt-styleguide/src/shared/models/entity/
21
21
  import { v4 as uuidv4 } from "uuid";
22
22
  import { RESOURCE_TYPE_VERSION_5 } from "passbolt-styleguide/src/shared/models/entity/metadata/metadataTypesSettingsEntity";
23
23
 
24
- const KDBX_SUPPORTED_FIELDS = [
24
+ export const KDBX_SUPPORTED_FIELDS = [
25
25
  "Title",
26
26
  "URL",
27
27
  "UserName",
@@ -11,7 +11,7 @@
11
11
  * @link https://www.passbolt.com Passbolt(tm)
12
12
  * @since 3.2.0
13
13
  */
14
- import OrganizationSettingsModel from "../organizationSettings/organizationSettingsModel";
14
+ import GetOrFindSiteSettingsService from "../../service/siteSettings/getOrFindSiteSettingsService";
15
15
  import AccountSettingsService from "../../service/api/accountSettings/accountSettingsService";
16
16
  import { Config } from "../config";
17
17
  import i18n from "../../sdk/i18n";
@@ -42,11 +42,14 @@ class LocaleModel {
42
42
  * Constructor
43
43
  *
44
44
  * @param {ApiClientOptions} apiClientOptions
45
+ * @param {AccountEntity} [account] The account. Required for the organization-locale finders that
46
+ * read the site settings; not needed by `updateUserLocale`.
45
47
  * @public
46
48
  */
47
- constructor(apiClientOptions) {
49
+ constructor(apiClientOptions, account) {
48
50
  this.accountSettingsService = new AccountSettingsService(apiClientOptions);
49
- this.organizationSettingsModel = new OrganizationSettingsModel(apiClientOptions);
51
+ this.apiClientOptions = apiClientOptions;
52
+ this.account = account;
50
53
  }
51
54
 
52
55
  /**
@@ -71,8 +74,9 @@ class LocaleModel {
71
74
  * @returns {Promise<LocaleEntity>}
72
75
  */
73
76
  async getOrganizationLocale() {
74
- const organizationSettings = await this.organizationSettingsModel.getOrFind();
75
- return this.getSupportedLocale(organizationSettings.locale);
77
+ const getOrFindSiteSettingsService = new GetOrFindSiteSettingsService(this.account, this.apiClientOptions);
78
+ const siteSettings = await getOrFindSiteSettingsService.getOrFind(false);
79
+ return this.getSupportedLocale(siteSettings.locale);
76
80
  }
77
81
 
78
82
  /**
@@ -80,11 +84,12 @@ class LocaleModel {
80
84
  * @returns {Promise<LocalesCollection>}
81
85
  */
82
86
  async getSupportedOrganizationLocales() {
83
- const organizationSettings = await this.organizationSettingsModel.getOrFind();
84
- const localePluginEnabled = organizationSettings.isPluginEnabled("locale");
87
+ const getOrFindSiteSettingsService = new GetOrFindSiteSettingsService(this.account, this.apiClientOptions);
88
+ const siteSettings = await getOrFindSiteSettingsService.getOrFind(false);
89
+ const localePluginEnabled = siteSettings.isPluginEnabled("locale");
85
90
 
86
91
  if (localePluginEnabled) {
87
- const localePluginSettings = organizationSettings.getPluginSettings("locale");
92
+ const localePluginSettings = siteSettings.getPluginSettings("locale");
88
93
  return new LocalesCollection(localePluginSettings.options || []);
89
94
  }
90
95
 
@@ -15,7 +15,7 @@
15
15
  import PasswordExpirySettingsService from "../../service/api/passwordExpiry/passwordExpirySettingsService";
16
16
  import { assertType, assertUuid } from "../../utils/assertions";
17
17
  import PasswordExpirySettingsEntity from "passbolt-styleguide/src/shared/models/entity/passwordExpiry/passwordExpirySettingsEntity";
18
- import OrganizationSettingsModel from "../organizationSettings/organizationSettingsModel";
18
+ import GetOrFindSiteSettingsService from "../../service/siteSettings/getOrFindSiteSettingsService";
19
19
  import PasswordExpiryProSettingsEntity from "passbolt-styleguide/src/shared/models/entity/passwordExpiryPro/passwordExpiryProSettingsEntity";
20
20
  import PasswordExpirySettingsLocalStorage from "../../service/local_storage/passwordExpirySettingsLocalStorage";
21
21
 
@@ -30,7 +30,7 @@ class PasswordExpirySettingsModel {
30
30
  constructor(account, apiClientOptions) {
31
31
  this.passwordExpirySettingsLocalStorage = new PasswordExpirySettingsLocalStorage(account);
32
32
  this.passwordExpirySettingsService = new PasswordExpirySettingsService(apiClientOptions);
33
- this.organisationSettingsModel = new OrganizationSettingsModel(apiClientOptions);
33
+ this.getOrFindSiteSettingsService = new GetOrFindSiteSettingsService(account, apiClientOptions);
34
34
  }
35
35
 
36
36
  /**
@@ -68,8 +68,8 @@ class PasswordExpirySettingsModel {
68
68
  * @returns {Promise<PasswordExpirySettingsEntity>}
69
69
  */
70
70
  async save(passwordExpirySettingsEntity) {
71
- const organizationSettings = await this.organisationSettingsModel.getOrFind();
72
- const isAdvancedSettingsEnable = organizationSettings.isPluginEnabled("passwordExpiryPolicies");
71
+ const siteSettings = await this.getOrFindSiteSettingsService.getOrFind(false);
72
+ const isAdvancedSettingsEnable = siteSettings.isPluginEnabled("passwordExpiryPolicies");
73
73
  if (!isAdvancedSettingsEnable) {
74
74
  assertType(
75
75
  passwordExpirySettingsEntity,
@@ -106,8 +106,8 @@ class PasswordExpirySettingsModel {
106
106
  * @returns {Promise<PasswordExpirySettingsEntity|PasswordExpiryProSettingsEntity>}
107
107
  */
108
108
  async createFromDefault(passwordExpirySettingsDto = {}) {
109
- const organizationSettings = await this.organisationSettingsModel.getOrFind();
110
- const isAdvancedSettingsEnabled = organizationSettings.isPluginEnabled("passwordExpiryPolicies");
109
+ const siteSettings = await this.getOrFindSiteSettingsService.getOrFind(false);
110
+ const isAdvancedSettingsEnabled = siteSettings.isPluginEnabled("passwordExpiryPolicies");
111
111
  if (!isAdvancedSettingsEnabled) {
112
112
  return PasswordExpirySettingsEntity.createFromDefault(passwordExpirySettingsDto);
113
113
  }