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
@@ -19,6 +19,8 @@ import MfaAuthenticationRequiredError from "../../error/mfaAuthenticationRequire
19
19
  import WebIntegrationPagemod from "../../pagemod/webIntegrationPagemod";
20
20
  import WorkerService from "../worker/workerService";
21
21
  import PublicWebsiteSignInPagemod from "../../pagemod/publicWebsiteSignInPagemod";
22
+ import getActiveAccountService from "../account/getActiveAccountService";
23
+ import BuildApiClientOptionsService from "../account/buildApiClientOptionsService";
22
24
 
23
25
  const PASSBOLT_EXTENSION_UPDATE = "passboltExtensionUpdate";
24
26
 
@@ -59,14 +61,17 @@ class OnExtensionUpdateAvailableService {
59
61
 
60
62
  /**
61
63
  * Check and process event if the user is authenticated
62
- * @returns {Promise<bool>}
64
+ * @returns {Promise<boolean>}
63
65
  */
64
66
  const isUserAuthenticated = async () => {
65
67
  const user = User.getInstance();
66
68
  // Check if user is valid
67
69
  if (user.isValid()) {
68
70
  try {
69
- return await AuthenticationStatusService.isAuthenticated();
71
+ const account = await getActiveAccountService.get();
72
+ const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account);
73
+ const authenticationService = new AuthenticationStatusService(apiClientOptions);
74
+ return authenticationService.isAuthenticated();
70
75
  } catch (error) {
71
76
  if (error instanceof MfaAuthenticationRequiredError) {
72
77
  /*
@@ -47,7 +47,7 @@ describe("OnExtensionUpdateAvailableService", () => {
47
47
  const webIntegrationPortWrapper = new Port(webIntegrationPort);
48
48
  PortManager.registerPort(webIntegrationPortWrapper);
49
49
  // mock function
50
- jest.spyOn(AuthenticationStatusService, "isAuthenticated").mockImplementation(() => false);
50
+ jest.spyOn(AuthenticationStatusService.prototype, "isAuthenticated").mockImplementation(() => false);
51
51
  jest.spyOn(browser.runtime, "reload");
52
52
  jest.spyOn(webIntegrationPortWrapper, "emit");
53
53
  // process
@@ -73,7 +73,7 @@ describe("OnExtensionUpdateAvailableService", () => {
73
73
  expect.assertions(2);
74
74
  // mock function
75
75
  await MockExtension.withConfiguredAccount();
76
- jest.spyOn(AuthenticationStatusService, "isAuthenticated").mockImplementation(() => true);
76
+ jest.spyOn(AuthenticationStatusService.prototype, "isAuthenticated").mockImplementation(() => true);
77
77
  jest.spyOn(browser.runtime, "reload");
78
78
  // process
79
79
  await OnExtensionUpdateAvailableService.exec();
@@ -109,7 +109,7 @@ describe("OnExtensionUpdateAvailableService", () => {
109
109
  PortManager.registerPort(webIntegrationPortWrapper2);
110
110
  PortManager.registerPort(publicWebsiteSignInPortWrapper);
111
111
  // mock function
112
- jest.spyOn(AuthenticationStatusService, "isAuthenticated").mockImplementation(() => true);
112
+ jest.spyOn(AuthenticationStatusService.prototype, "isAuthenticated").mockImplementation(() => true);
113
113
  jest
114
114
  .spyOn(BrowserTabService, "sendMessage")
115
115
  .mockImplementation(() => PortManager.registerPort(webIntegrationPortWrapper));
@@ -144,7 +144,7 @@ describe("OnExtensionUpdateAvailableService", () => {
144
144
  expect.assertions(1);
145
145
  // mock function
146
146
  await MockExtension.withConfiguredAccount();
147
- jest.spyOn(AuthenticationStatusService, "isAuthenticated").mockImplementation(() => {
147
+ jest.spyOn(AuthenticationStatusService.prototype, "isAuthenticated").mockImplementation(() => {
148
148
  throw new Error("Error");
149
149
  });
150
150
  jest.spyOn(browser.runtime, "reload");
@@ -158,7 +158,7 @@ describe("OnExtensionUpdateAvailableService", () => {
158
158
  expect.assertions(2);
159
159
  // mock function
160
160
  await MockExtension.withConfiguredAccount();
161
- jest.spyOn(AuthenticationStatusService, "isAuthenticated").mockImplementation(() => {
161
+ jest.spyOn(AuthenticationStatusService.prototype, "isAuthenticated").mockImplementation(() => {
162
162
  throw new MfaAuthenticationRequiredError();
163
163
  });
164
164
  jest.spyOn(browser.runtime, "reload");
@@ -13,9 +13,10 @@
13
13
  */
14
14
 
15
15
  import GroupsCollection from "passbolt-styleguide/src/shared/models/entity/group/groupsCollection";
16
- import { assertBoolean, assertType } from "../../utils/assertions";
16
+ import { assertArrayUUID, assertBoolean, assertType } from "../../utils/assertions";
17
17
  import GroupApiService from "../api/group/groupApiService";
18
18
  import User from "../../model/user";
19
+ import ExecuteConcurrentlyService from "../execute/executeConcurrentlyService";
19
20
 
20
21
  export default class FindGroupsService {
21
22
  /**
@@ -70,4 +71,44 @@ export default class FindGroupsService {
70
71
  const contains = { groups_users: true, my_group_user: true, modifier: false };
71
72
  return await this.findAll(contains, null, true);
72
73
  }
74
+
75
+ /**
76
+ * Find all groups given their ids with the data tailored for the "Share" process.
77
+ * Each group embeds its members (groups_users with their associated user and user profile).
78
+ * @param {Array<string>} groupIds
79
+ */
80
+ async findAllByIdsForShare(groupIds) {
81
+ assertArrayUUID(groupIds);
82
+
83
+ const contains = { "groups_users.user.profile": true };
84
+ return await this.findAllByIds(groupIds, contains);
85
+ }
86
+
87
+ /**
88
+ * Find all groups given their ids.
89
+ * @param {Array<string>} groupIds
90
+ * @param {Object|null} [contains] optional
91
+ */
92
+ async findAllByIds(groupIds, contains) {
93
+ assertArrayUUID(groupIds);
94
+
95
+ // Short-circuit an empty id list: it produces no callbacks, and ExecuteConcurrentlyService
96
+ // never resolves when given none (its resolve() only fires from within the per-callback loop).
97
+ if (groupIds.length === 0) {
98
+ return new GroupsCollection([]);
99
+ }
100
+
101
+ // @todo: update to check for server capability for supporting `has-id` filter and use it instead.
102
+ const callbacks = groupIds.map((groupId) => {
103
+ return async () => {
104
+ const response = await this.groupApiService.get(groupId, contains);
105
+ return response.body;
106
+ };
107
+ });
108
+
109
+ // @todo Later (tm). The Collection should provide this capability, ensuring that validation build rules are executed and performance is guaranteed.
110
+ const executeConcurrentlyService = new ExecuteConcurrentlyService();
111
+ const groupsCollectionDto = await executeConcurrentlyService.execute(callbacks, 5);
112
+ return new GroupsCollection(groupsCollectionDto, { ignoreInvalidEntity: true });
113
+ }
73
114
  }
@@ -12,10 +12,12 @@
12
12
  * @since 5.7.0
13
13
  */
14
14
 
15
+ import { v4 as uuidv4 } from "uuid";
15
16
  import User from "../../model/user";
16
17
  import AccountEntity from "../../model/entity/account/accountEntity";
17
18
  import { defaultAccountDto } from "../../model/entity/account/accountEntity.test.data";
18
19
  import GroupsCollection from "passbolt-styleguide/src/shared/models/entity/group/groupsCollection";
20
+ import { defaultGroupDto } from "passbolt-styleguide/src/shared/models/entity/group/groupEntity.test.data";
19
21
  import BuildApiClientOptionsService from "../account/buildApiClientOptionsService";
20
22
  import FindGroupsService from "./findGroupsService";
21
23
  import MockExtension from "../../../../../test/mocks/mockExtension";
@@ -125,4 +127,84 @@ describe("FindGroupsService", () => {
125
127
  expect(result.id).toBe(groupsDtos.id);
126
128
  });
127
129
  });
130
+
131
+ describe("::findAllByIdsForShare", () => {
132
+ it("should delegate to findAllByIds with the contains tailored for the share process", async () => {
133
+ const groupIds = [uuidv4(), uuidv4()];
134
+ const expectedContains = { "groups_users.user.profile": true };
135
+ const expectedCollection = new GroupsCollection();
136
+ jest.spyOn(findGroupsService, "findAllByIds").mockResolvedValue(expectedCollection);
137
+
138
+ const result = await findGroupsService.findAllByIdsForShare(groupIds);
139
+
140
+ expect(findGroupsService.findAllByIds).toHaveBeenCalledWith(groupIds, expectedContains);
141
+ expect(result).toBe(expectedCollection);
142
+ });
143
+
144
+ it("should throw if the given group ids are not an array of uuids", async () => {
145
+ expect.assertions(3);
146
+ const spy = jest.spyOn(findGroupsService, "findAllByIds");
147
+
148
+ await expect(findGroupsService.findAllByIdsForShare("not-an-array")).rejects.toThrow();
149
+ await expect(findGroupsService.findAllByIdsForShare(["not-a-uuid"])).rejects.toThrow();
150
+ expect(spy).not.toHaveBeenCalled();
151
+ });
152
+ });
153
+
154
+ describe("::findAllByIds", () => {
155
+ it("should find all the groups given their ids", async () => {
156
+ const groupDtos = [
157
+ defaultGroupDto({ name: "Group 0" }),
158
+ defaultGroupDto({ name: "Group 1" }),
159
+ defaultGroupDto({ name: "Group 2" }),
160
+ ];
161
+ expect.assertions(4 + groupDtos.length);
162
+ const groupIds = groupDtos.map((groupDto) => groupDto.id);
163
+ const contains = { groups_users: true, my_group_user: false, modifier: false };
164
+ // The API returns a single group per id, wrapped in a PassboltResponseEntity like object.
165
+ const spy = jest
166
+ .spyOn(findGroupsService.groupApiService, "get")
167
+ .mockImplementation(async (id) => ({ body: groupDtos.find((groupDto) => groupDto.id === id) }));
168
+
169
+ const result = await findGroupsService.findAllByIds(groupIds, contains);
170
+
171
+ expect(spy).toHaveBeenCalledTimes(groupIds.length);
172
+ groupIds.forEach((groupId) => expect(spy).toHaveBeenCalledWith(groupId, contains));
173
+ expect(result).toBeInstanceOf(GroupsCollection);
174
+ expect(result).toHaveLength(groupIds.length);
175
+ expect(result.items.map((group) => group.id).sort()).toEqual([...groupIds].sort());
176
+ });
177
+
178
+ it("should return an empty collection without calling the API when the given group ids are empty", async () => {
179
+ expect.assertions(3);
180
+ const spy = jest.spyOn(findGroupsService.groupApiService, "get");
181
+
182
+ const result = await findGroupsService.findAllByIds([]);
183
+
184
+ expect(result).toBeInstanceOf(GroupsCollection);
185
+ expect(result).toHaveLength(0);
186
+ expect(spy).not.toHaveBeenCalled();
187
+ });
188
+
189
+ it("should reject if the API returns an invalid group", async () => {
190
+ const validGroupDto = defaultGroupDto();
191
+ const invalidGroupDto = defaultGroupDto({ name: 42 });
192
+ const groupIds = [validGroupDto.id, invalidGroupDto.id];
193
+ jest
194
+ .spyOn(findGroupsService.groupApiService, "get")
195
+ .mockImplementation(async (id) => ({ body: id === validGroupDto.id ? validGroupDto : invalidGroupDto }));
196
+
197
+ const collection = await findGroupsService.findAllByIds(groupIds);
198
+ expect(collection).toHaveLength(1);
199
+ });
200
+
201
+ it("should throw if the given group ids are not an array of uuids", async () => {
202
+ expect.assertions(3);
203
+ const spy = jest.spyOn(findGroupsService.groupApiService, "get");
204
+
205
+ await expect(findGroupsService.findAllByIds("not-an-array")).rejects.toThrow();
206
+ await expect(findGroupsService.findAllByIds(["not-a-uuid"])).rejects.toThrow();
207
+ expect(spy).not.toHaveBeenCalled();
208
+ });
209
+ });
128
210
  });
@@ -0,0 +1,82 @@
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.13.0
13
+ */
14
+ import { OpenpgpAssertion } from "../../utils/openpgp/openpgpAssertions";
15
+ import EncryptMessageService from "../crypto/encryptMessageService";
16
+ import DecryptMessageService from "../crypto/decryptMessageService";
17
+ import SecretEntity from "passbolt-styleguide/src/shared/models/entity/secret/secretEntity";
18
+ import GroupUpdateSecretsCollection from "../../model/entity/secret/groupUpdate/groupUpdateSecretsCollection";
19
+ import i18n from "../../sdk/i18n";
20
+
21
+ /**
22
+ * Shared decrypt/encrypt logic for the "add users to group" flow.
23
+ * It is called by both the MV2 path (GroupUpdateService, in the service worker / background page)
24
+ * and the MV3 path (AddUsersToGroupOffscreenService, in the offscreen document) so the
25
+ * cryptographic loop lives in a single place. The caller provides an `onProgress` callback to
26
+ * decide how progress is surfaced (direct progress service update vs throttled offscreen message).
27
+ */
28
+ class GroupUpdateSecretsCryptoService {
29
+ /**
30
+ * Decrypt a collection of secrets.
31
+ * @param {openpgp.PrivateKey} privateKey The logged in user private key
32
+ * @param {GroupUpdateSecretsCollection} secretsCollection The collection of secrets to decrypt
33
+ * @param {function(string):void} [onProgress] Called after each secret with the progress message
34
+ * @returns {Promise<object>} Decrypted secrets organized as {[resourceId]: secretDecrypted, ...}
35
+ */
36
+ static async decryptSecrets(privateKey, secretsCollection, onProgress) {
37
+ const result = [];
38
+ const collectionLength = secretsCollection.length;
39
+
40
+ for (let i = 0; i < collectionLength; i++) {
41
+ const secret = secretsCollection.items[i];
42
+ const secretMessage = await OpenpgpAssertion.readMessageOrFail(secret.data);
43
+ result[secret.resourceId] = await DecryptMessageService.decrypt(secretMessage, privateKey);
44
+
45
+ await onProgress?.(i18n.t("Decrypting {{counter}}/{{total}}", { counter: i + 1, total: collectionLength }));
46
+ }
47
+
48
+ return result;
49
+ }
50
+
51
+ /**
52
+ * Encrypt a collection of needed secrets.
53
+ * @param {openpgp.PrivateKey} privateKey The logged in user private key
54
+ * @param {object} usersPublicKeys The users public armored keys organized as {[userId]: armoredKey, ...}
55
+ * @param {NeededSecretsCollection} neededSecretsCollection A collection of needed secret
56
+ * @param {object} decryptedSecrets The decrypted secrets organized as {[resourceId]: secretDecrypted, ...}
57
+ * @param {function(string):void} [onProgress] Called after each secret with the progress message
58
+ * @returns {Promise<GroupUpdateSecretsCollection>}
59
+ */
60
+ static async encryptSecrets(privateKey, usersPublicKeys, neededSecretsCollection, decryptedSecrets, onProgress) {
61
+ const groupUpdateSecrets = new GroupUpdateSecretsCollection([]);
62
+ const collectionLength = neededSecretsCollection.length;
63
+
64
+ for (let i = 0; i < collectionLength; i++) {
65
+ const neededSecret = neededSecretsCollection.items[i];
66
+ const user_id = neededSecret.userId;
67
+ const resource_id = neededSecret.resourceId;
68
+
69
+ const encryptionKey = await OpenpgpAssertion.readKeyOrFail(usersPublicKeys[user_id]);
70
+ const data = await EncryptMessageService.encrypt(decryptedSecrets[resource_id], encryptionKey, [privateKey]);
71
+
72
+ const secret = new SecretEntity({ resource_id, user_id, data });
73
+ groupUpdateSecrets.push(secret);
74
+
75
+ onProgress?.(i18n.t("Encrypting {{counter}}/{{total}}", { counter: i + 1, total: collectionLength }));
76
+ }
77
+
78
+ return groupUpdateSecrets;
79
+ }
80
+ }
81
+
82
+ export default GroupUpdateSecretsCryptoService;
@@ -0,0 +1,102 @@
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.13.0
13
+ */
14
+ import { v4 as uuidv4 } from "uuid";
15
+ import { pgpKeys } from "passbolt-styleguide/test/fixture/pgpKeys/keys";
16
+ import { plaintextSecretPasswordAndDescriptionDto } from "passbolt-styleguide/src/shared/models/entity/plaintextSecret/plaintextSecretEntity.test.data";
17
+ import GroupUpdateSecretsCryptoService from "./groupUpdateSecretsCryptoService";
18
+ import { OpenpgpAssertion } from "../../utils/openpgp/openpgpAssertions";
19
+ import EncryptMessageService from "../crypto/encryptMessageService";
20
+ import DecryptMessageService from "../crypto/decryptMessageService";
21
+ import GroupUpdateSecretsCollection from "../../model/entity/secret/groupUpdate/groupUpdateSecretsCollection";
22
+ import NeededSecretsCollection from "../../model/entity/secret/needed/neededSecretsCollection";
23
+ import { defaultResourcesSecretsDtos } from "../../model/entity/secret/groupUpdate/groupUpdateSecretsCollection.test.data";
24
+
25
+ describe("GroupUpdateSecretsCryptoService", () => {
26
+ describe("::decryptSecrets", () => {
27
+ it("should decrypt the secrets and report progress for each one", async () => {
28
+ expect.assertions(3);
29
+
30
+ const originalDecryptedSecret = plaintextSecretPasswordAndDescriptionDto();
31
+ const adaPublicKey = await OpenpgpAssertion.readKeyOrFail(pgpKeys.ada.public);
32
+ const secretsDtos = defaultResourcesSecretsDtos(1);
33
+ secretsDtos[0].data = await EncryptMessageService.encrypt(JSON.stringify(originalDecryptedSecret), adaPublicKey);
34
+ const secrets = new GroupUpdateSecretsCollection(secretsDtos, { validate: false });
35
+ const privateKey = await OpenpgpAssertion.readKeyOrFail(pgpKeys.ada.private_decrypted);
36
+ const onProgress = jest.fn();
37
+
38
+ const result = await GroupUpdateSecretsCryptoService.decryptSecrets(privateKey, secrets, onProgress);
39
+
40
+ expect(JSON.parse(result[secretsDtos[0].resource_id])).toStrictEqual(originalDecryptedSecret);
41
+ expect(onProgress).toHaveBeenCalledTimes(1);
42
+ expect(onProgress).toHaveBeenCalledWith("Decrypting 1/1");
43
+ });
44
+ });
45
+
46
+ describe("::encryptSecrets", () => {
47
+ it("should encrypt the needed secrets for the recipient and report progress for each one", async () => {
48
+ expect.assertions(4);
49
+
50
+ const originalDecryptedSecret = plaintextSecretPasswordAndDescriptionDto();
51
+ const userId = uuidv4();
52
+ const resourceId = uuidv4();
53
+ const decryptedSecrets = { [resourceId]: JSON.stringify(originalDecryptedSecret) };
54
+ const neededSecrets = new NeededSecretsCollection([{ user_id: userId, resource_id: resourceId }], {
55
+ validate: false,
56
+ });
57
+ const usersPublicKeys = { [userId]: pgpKeys.betty.public };
58
+ const privateKey = await OpenpgpAssertion.readKeyOrFail(pgpKeys.ada.private_decrypted);
59
+ const onProgress = jest.fn();
60
+
61
+ const result = await GroupUpdateSecretsCryptoService.encryptSecrets(
62
+ privateKey,
63
+ usersPublicKeys,
64
+ neededSecrets,
65
+ decryptedSecrets,
66
+ onProgress,
67
+ );
68
+
69
+ const decryptedData = await DecryptMessageService.decrypt(
70
+ await OpenpgpAssertion.readMessageOrFail(result.items[0].data),
71
+ await OpenpgpAssertion.readKeyOrFail(pgpKeys.betty.private_decrypted),
72
+ );
73
+
74
+ expect(JSON.parse(decryptedData)).toStrictEqual(originalDecryptedSecret);
75
+ expect(result.items[0].userId).toEqual(userId);
76
+ expect(onProgress).toHaveBeenCalledTimes(1);
77
+ expect(onProgress).toHaveBeenCalledWith("Encrypting 1/1");
78
+ });
79
+
80
+ it("should not throw when no progress callback is provided", async () => {
81
+ expect.assertions(1);
82
+
83
+ const userId = uuidv4();
84
+ const resourceId = uuidv4();
85
+ const decryptedSecrets = { [resourceId]: JSON.stringify(plaintextSecretPasswordAndDescriptionDto()) };
86
+ const neededSecrets = new NeededSecretsCollection([{ user_id: userId, resource_id: resourceId }], {
87
+ validate: false,
88
+ });
89
+ const usersPublicKeys = { [userId]: pgpKeys.betty.public };
90
+ const privateKey = await OpenpgpAssertion.readKeyOrFail(pgpKeys.ada.private_decrypted);
91
+
92
+ const result = await GroupUpdateSecretsCryptoService.encryptSecrets(
93
+ privateKey,
94
+ usersPublicKeys,
95
+ neededSecrets,
96
+ decryptedSecrets,
97
+ );
98
+
99
+ expect(result.items).toHaveLength(1);
100
+ });
101
+ });
102
+ });
@@ -11,21 +11,19 @@
11
11
  * @link https://www.passbolt.com Passbolt(tm)
12
12
  * @since 4.10.1
13
13
  */
14
- import { OpenpgpAssertion } from "../../utils/openpgp/openpgpAssertions";
15
14
  import Keyring from "../../model/keyring";
16
- import EncryptMessageService from "../../service/crypto/encryptMessageService";
17
- import DecryptMessageService from "../../service/crypto/decryptMessageService";
18
15
  import GroupModel from "../../model/group/groupModel";
19
16
  import GroupEntity from "passbolt-styleguide/src/shared/models/entity/group/groupEntity";
20
17
  import GroupUpdateEntity from "../../model/entity/group/update/groupUpdateEntity";
21
18
  import i18n from "../../sdk/i18n";
22
- import SecretEntity from "passbolt-styleguide/src/shared/models/entity/secret/secretEntity";
23
19
  import GroupUpdateSecretsCollection from "../../model/entity/secret/groupUpdate/groupUpdateSecretsCollection";
24
20
  import DecryptPrivateKeyService from "../crypto/decryptPrivateKeyService";
25
21
  import { assertString, assertType } from "../../utils/assertions";
26
22
  import GroupUpdatesCollection from "../../model/entity/group/update/groupUpdatesCollection";
27
23
  import GroupLocalStorage from "../local_storage/groupLocalStorage";
28
24
  import GroupApiService from "../api/group/groupApiService";
25
+ import GroupUpdateSecretsCryptoService from "./groupUpdateSecretsCryptoService";
26
+ import { RequestAddUsersToGroupOffscreenService } from "../../../../chrome-mv3/serviceWorker/service/addUsersToGroup/requestAddUsersToGroupOffscreenService";
29
27
 
30
28
  /**
31
29
  * Progress goals are:
@@ -37,7 +35,6 @@ import GroupApiService from "../api/group/groupApiService";
37
35
  * - Done
38
36
  */
39
37
  const PROGRESS_GOAL = 6;
40
- const YIELD_INTERVAL_MS = 8000; // PB-51648 yield reduce to 8s due to chrome 148 more strict to ping service worker
41
38
 
42
39
  class GroupUpdateService {
43
40
  /**
@@ -103,9 +100,18 @@ class GroupUpdateService {
103
100
  */
104
101
  async encryptNeededSecrets(passphrase, groupUpdateDryRunResultEntity) {
105
102
  this.progressService.finishStep(i18n.t("Encrypt required secrets for new users"), true);
106
- const privateKey = await DecryptPrivateKeyService.decryptArmoredKey(this.account.userPrivateArmoredKey, passphrase);
107
- const decryptedSecrets = await this.decryptSecrets(privateKey, groupUpdateDryRunResultEntity.secrets);
108
- return await this.encryptSecrets(privateKey, groupUpdateDryRunResultEntity.neededSecrets, decryptedSecrets);
103
+
104
+ const isMV3 = chrome.runtime.getManifest().manifest_version === 3;
105
+ if (isMV3) {
106
+ return await this.decryptAndEncryptSecretsFromOffscreen(passphrase, groupUpdateDryRunResultEntity);
107
+ } else {
108
+ const privateKey = await DecryptPrivateKeyService.decryptArmoredKey(
109
+ this.account.userPrivateArmoredKey,
110
+ passphrase,
111
+ );
112
+ const decryptedSecrets = await this.decryptSecrets(privateKey, groupUpdateDryRunResultEntity.secrets);
113
+ return await this.encryptSecrets(privateKey, groupUpdateDryRunResultEntity.neededSecrets, decryptedSecrets);
114
+ }
109
115
  }
110
116
 
111
117
  /**
@@ -117,44 +123,16 @@ class GroupUpdateService {
117
123
  * @private
118
124
  */
119
125
  async encryptSecrets(privateKey, neededSecretsCollection, decryptedSecrets) {
120
- const groupUpdateSecrets = new GroupUpdateSecretsCollection([]);
121
- let lastYield = Date.now();
122
126
  this.progressService.finishStep(i18n.t("Synchronizing keyring"), true);
123
127
  const usersPublicKeys = await this.retrieveAndReadUserPublicKeys(neededSecretsCollection);
124
128
 
125
- const collectionLength = neededSecretsCollection.length;
126
- for (let i = 0; i < collectionLength; i++) {
127
- const neededSecret = neededSecretsCollection.items[i];
128
- const user_id = neededSecret.userId;
129
- const resource_id = neededSecret.resourceId;
130
-
131
- this.progressService.updateStepMessage(
132
- i18n.t("Encrypting {{counter}}/{{total}}", { counter: i + 1, total: collectionLength }),
133
- );
134
- const data = await EncryptMessageService.encrypt(decryptedSecrets[resource_id], usersPublicKeys[user_id], [
135
- privateKey,
136
- ]);
137
-
138
- const secret = new SecretEntity({ resource_id, user_id, data });
139
- groupUpdateSecrets.push(secret);
140
-
141
- /*
142
- * PB-51434
143
- * Force a timeout promise to let the service worker respond to chromium
144
- *
145
- * Starting with Chrome 147, the regular check of the service worker on the event lop seems more strict
146
- * If the service worker do a process that consume too much time and performance that it can not respond
147
- * It will be killed by the browser as it is not responding at time.
148
- *
149
- * Using promise set timeout will solve the issue it releases the even loop enough time to respond
150
- */
151
- if (Date.now() - lastYield >= YIELD_INTERVAL_MS) {
152
- await new Promise((resolve) => setTimeout(resolve, 0));
153
- lastYield = Date.now();
154
- }
155
- }
156
-
157
- return groupUpdateSecrets;
129
+ return GroupUpdateSecretsCryptoService.encryptSecrets(
130
+ privateKey,
131
+ usersPublicKeys,
132
+ neededSecretsCollection,
133
+ decryptedSecrets,
134
+ (message) => this.progressService.updateStepMessage(message),
135
+ );
158
136
  }
159
137
 
160
138
  /**
@@ -165,36 +143,9 @@ class GroupUpdateService {
165
143
  * @private
166
144
  */
167
145
  async decryptSecrets(privateKey, secretsCollection) {
168
- const result = [];
169
- let lastYield = Date.now();
170
-
171
- const collectionLength = secretsCollection.length;
172
- for (let i = 0; i < collectionLength; i++) {
173
- const secret = secretsCollection.items[i];
174
- const secretMessage = await OpenpgpAssertion.readMessageOrFail(secret.data);
175
-
176
- this.progressService.updateStepMessage(
177
- i18n.t("Decrypting {{counter}}/{{total}}", { counter: i + 1, total: collectionLength }),
178
- );
179
- result[secret.resourceId] = await DecryptMessageService.decrypt(secretMessage, privateKey);
180
-
181
- /*
182
- * PB-51434
183
- * Force a timeout promise to let the service worker respond to chromium
184
- *
185
- * Starting with Chrome 147, the regular check of the service worker on the event lop seems more strict
186
- * If the service worker do a process that consume too much time and performance that it can not respond
187
- * It will be killed by the browser as it is not responding at time.
188
- *
189
- * Using promise set timeout will solve the issue it releases the even loop enough time to respond
190
- */
191
- if (Date.now() - lastYield >= YIELD_INTERVAL_MS) {
192
- await new Promise((resolve) => setTimeout(resolve, 0));
193
- lastYield = Date.now();
194
- }
195
- }
196
-
197
- return result;
146
+ return GroupUpdateSecretsCryptoService.decryptSecrets(privateKey, secretsCollection, (message) =>
147
+ this.progressService.updateStepMessage(message),
148
+ );
198
149
  }
199
150
 
200
151
  /**
@@ -225,10 +176,10 @@ class GroupUpdateService {
225
176
  }
226
177
 
227
178
  /**
228
- * Retrieve and read the user public keys.
179
+ * Retrieve the user public keys.
229
180
  * @param {NeededSecretsCollection} neededSecrets The needed secrets
230
- * @returns {Promise<object>} User public key organized in an object where the property name represents the user id,
231
- * and the value contains the user openpgp public key.
181
+ * @returns {Promise<object>} User public keys organized in an object where the property name represents the user id,
182
+ * and the value contains the user public armored key.
232
183
  * @private
233
184
  */
234
185
  async retrieveAndReadUserPublicKeys(neededSecrets) {
@@ -239,12 +190,32 @@ class GroupUpdateService {
239
190
  await keyring.sync();
240
191
 
241
192
  for (const userId of userIds) {
242
- const userPublicArmoredKey = keyring.findPublic(userId).armoredKey;
243
- userOpenpgpPublicKeys[userId] = await OpenpgpAssertion.readKeyOrFail(userPublicArmoredKey);
193
+ // Keep armored key to send it through a message for offscreen
194
+ userOpenpgpPublicKeys[userId] = keyring.findPublic(userId).armoredKey;
244
195
  }
245
196
 
246
197
  return userOpenpgpPublicKeys;
247
198
  }
199
+
200
+ /**
201
+ * Delegate the decryption and encryption secrets to the offscreen
202
+ * @param {string} passphrase
203
+ * @param {GroupUpdateDryRunResultEntity} groupUpdateDryRunResultEntity
204
+ * @return {Promise<GroupUpdateSecretsCollection>}
205
+ */
206
+ async decryptAndEncryptSecretsFromOffscreen(passphrase, groupUpdateDryRunResultEntity) {
207
+ this.progressService.finishStep(i18n.t("Synchronizing keyring"), true);
208
+ // User public key are stored in local storage that is not accessible from offscreen
209
+ const usersPublicKeys = await this.retrieveAndReadUserPublicKeys(groupUpdateDryRunResultEntity.neededSecrets);
210
+ const groupUpdateSecrets = await RequestAddUsersToGroupOffscreenService.decryptAndEncryptSecrets(
211
+ this.account,
212
+ passphrase,
213
+ groupUpdateDryRunResultEntity,
214
+ usersPublicKeys,
215
+ this.progressService,
216
+ );
217
+ return new GroupUpdateSecretsCollection(groupUpdateSecrets, { validate: false });
218
+ }
248
219
  }
249
220
 
250
221
  export default GroupUpdateService;