diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f1b9f2e..472d9de0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,16 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [4.8.2] - 2024-06-13 +### Improved +- PB-33686 As a user I should be signed out after browser update + +### Fixed +- PB-33727 Fix session extension, service worker awaken and user instance storage not set +- PB-33801 Remove active account cache in memory + ## [4.8.1] - 2024-05-18 -### Fix +### Fixed - PB-33595 As a user running an instance serving an invalid certificate I should be able to sync the gpgkeyring ## [4.8.0] - 2024-05-16 @@ -1623,8 +1631,9 @@ self registration settings option in the left-side bar - AP: User with plugin installed - LU: Logged in user -[Unreleased]: https://github.com/passbolt/passbolt_browser_extension/compare/v4.8.1...HEAD -[4.8.0]: https://github.com/passbolt/passbolt_browser_extension/compare/v4.8.0...4.8.1 +[Unreleased]: https://github.com/passbolt/passbolt_browser_extension/compare/v4.8.2...HEAD +[4.8.2]: https://github.com/passbolt/passbolt_browser_extension/compare/v4.8.1...4.8.2 +[4.8.1]: https://github.com/passbolt/passbolt_browser_extension/compare/v4.8.0...4.8.1 [4.8.0]: https://github.com/passbolt/passbolt_browser_extension/compare/v4.7.8...4.8.0 [4.7.8]: https://github.com/passbolt/passbolt_browser_extension/compare/v4.7.7...v4.7.8 [4.7.7]: https://github.com/passbolt/passbolt_browser_extension/compare/v4.7.6...v4.7.7 diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 96fba600..e8f311f9 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,11 +1,13 @@ -Song: https://www.youtube.com/watch?v=hbe3CQamF8k +Song: https://www.youtube.com/watch?v=OypXGyN6OZw -Passbolt v4.8.1 is a maintenance update that addresses issues related to servers serving invalid SSL certificates, which affected the accessibility of the API with certain user journeys. +Passbolt v4.8.2 is a maintenance update that addresses issues related to MV3. We hope these updates enhance your experience with Passbolt. Your feedback is always valuable to us. -## [4.8.1] - 2024-05-18 -### Fix -- PB-33595 As a user running an instance serving an invalid certificate I should be able to sync the gpgkeyring -- PB-33596 As a user running an instance serving an invalid certificate I cannot sync my account settings -- PB-33597 As a user running an instance serving an invalid certificate I cannot install passbolt extension using an API < v3 +## [4.8.2] - 2024-06-13 +### Improved +- PB-33686 As a user I should be signed out after browser update + +### Fixed +- PB-33727 Fix session extension, service worker awaken and user instance storage not set +- PB-33801 Remove active account cache in memory diff --git a/package-lock.json b/package-lock.json index 82b58af6..38722d7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "passbolt-browser-extension", - "version": "4.8.1", + "version": "4.8.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "passbolt-browser-extension", - "version": "4.8.1", + "version": "4.8.2", "license": "AGPL-3.0", "dependencies": { "await-lock": "^2.1.0", diff --git a/package.json b/package.json index 3e2755e4..e13e4ec5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "passbolt-browser-extension", - "version": "4.8.1", + "version": "4.8.2", "license": "AGPL-3.0", "copyright": "Copyright 2022 Passbolt SA", "description": "Passbolt web extension for the open source password manager for teams", diff --git a/src/all/background_page/controller/extension/onExtensionInstalledController.js b/src/all/background_page/controller/extension/onExtensionInstalledController.js index c01dd520..74622df6 100644 --- a/src/all/background_page/controller/extension/onExtensionInstalledController.js +++ b/src/all/background_page/controller/extension/onExtensionInstalledController.js @@ -23,6 +23,8 @@ import Log from "../../model/log"; import {BrowserExtensionIconService} from "../../service/ui/browserExtensionIcon.service"; import storage from "../../sdk/storage"; import {Config} from "../../model/config"; +import AuthModel from "../../model/auth/authModel"; +import AppBootstrapPagemod from "../../pagemod/appBootstrapPagemod"; class OnExtensionInstalledController { /** @@ -45,6 +47,11 @@ class OnExtensionInstalledController { case browser.runtime.OnInstalledReason.UPDATE: await OnExtensionInstalledController.onUpdate(); break; + case browser.runtime.OnInstalledReason.CHROME_UPDATE: + case browser.runtime.OnInstalledReason.BROWSER_UPDATE: + // Force logout for users to not ask passphrase after a browser update which clear the session storage + await OnExtensionInstalledController.onBrowserUpdate(); + break; default: console.debug(`The install reason ${details.reason} is not supported`); break; @@ -67,6 +74,45 @@ class OnExtensionInstalledController { await OnExtensionInstalledController.updateToolbarIcon(); } + /** + * On update of the browser, logout the user. It helps mitigate issue where users update their browser, are still + * signed-in but session memory used to store user passphrase or other information is flushed. These behavior + * deteriorates the user experience, therefore it has been decided to sign the user out. + */ + static async onBrowserUpdate() { + const user = User.getInstance(); + // Check if user is valid + if (!user.isValid()) { + return; + } + let authStatus; + try { + const checkAuthStatusService = new CheckAuthStatusService(); + // use the cached data as the worker could wake up every 30 secondes. + authStatus = await checkAuthStatusService.checkAuthStatus(false); + } catch (error) { + // Service is unavailable, do nothing... + Log.write({level: 'debug', message: 'Could not check if the user is authenticated, the service is unavailable.'}); + return; + } + // Do nothing if user is not authenticated + if (!authStatus.isAuthenticated) { + return; + } + // Logout authenticated user to prevent to ask passphrase for SSO users + const apiClientOptions = await user.getApiClientOptions(); + const authModel = new AuthModel(apiClientOptions); + await authModel.logout(); + /* + * Reload only tabs that match passbolt app url. Reload is necessary as the application loaded in the tab + * could be unresponsive due to the forced triggered sign-out. + * - When the tab is started the API didn't redirect the user as the user is still signed-in. + * - This script sign-out the user + * - The pagemod of the app starts and throw an error as the user has been signed-out + */ + await browser.tabs.query({}).then(reloadTabsMatchPassboltAppUrl); + } + /** * Updates the Passbolt icon in the toolbar according to the sign-in status of the current user. * @returns {Promise} @@ -81,11 +127,11 @@ class OnExtensionInstalledController { let authStatus; try { const checkAuthStatusService = new CheckAuthStatusService(); - // user the cached data as the worker could wake up every 30 secondes. + // use the cached data as the worker could wake up every 30 secondes. authStatus = await checkAuthStatusService.checkAuthStatus(false); } catch (error) { // Service is unavailable, do nothing... - Log.write({level: 'debug', message: 'The Service is unavailable to check if the user is authenticated'}); + Log.write({level: 'debug', message: 'Could not check if the user is authenticated, the service is unavailable.'}); return; } @@ -127,13 +173,25 @@ const closeTabWebStore = tabs => { }; +/** + * Reload the tabs that match passsbolt app url + * @param tabs + */ +const reloadTabsMatchPassboltAppUrl = async tabs => { + for (const tab of tabs) { + if (await AppBootstrapPagemod.assertUrlAttachConstraint(tab)) { + browser.tabs.reload(tab.id); + } + } +}; + /** * Reload the tabs that match pagemod url * @param tabs */ -const reloadTabsMatchPagemodUrl = tabs => { - tabs.map(tab => { - if (PagemodManager.hasPagemodMatchUrlToReload(tab.url)) { +const reloadTabsMatchPagemodUrl = async tabs => { + for (const tab of tabs) { + if (await PagemodManager.hasPagemodMatchUrlToReload(tab.url)) { browser.tabs.reload(tab.id); } else { // For other tabs detect and inject the new content script @@ -144,7 +202,7 @@ const reloadTabsMatchPagemodUrl = tabs => { }; WebNavigationService.exec(frameDetails); } - }); + } }; export default OnExtensionInstalledController; diff --git a/src/all/background_page/controller/extension/onExtensionInstalledController.test.js b/src/all/background_page/controller/extension/onExtensionInstalledController.test.js index a58195f6..de03eb85 100644 --- a/src/all/background_page/controller/extension/onExtensionInstalledController.test.js +++ b/src/all/background_page/controller/extension/onExtensionInstalledController.test.js @@ -13,9 +13,12 @@ */ import OnExtensionInstalledController from "./onExtensionInstalledController"; -import User from "../../model/user"; import UserSettings from "../../model/userSettings/userSettings"; import WebNavigationService from "../../service/webNavigation/webNavigationService"; +import AuthModel from "../../model/auth/authModel"; +import CheckAuthStatusService from "../../service/auth/checkAuthStatusService"; +import GetActiveAccountService from "../../service/account/getActiveAccountService"; +import User from "../../model/user"; // Reset the modules before each test. beforeEach(() => { @@ -73,7 +76,7 @@ describe("OnExtensionInstalledController", () => { jest.spyOn(OnExtensionInstalledController, "onUpdate"); jest.spyOn(WebNavigationService, "exec"); jest.spyOn(browser.tabs, "query").mockImplementationOnce(() => Promise.resolve(tabs)); - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => true); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => {}); jest.spyOn(UserSettings.prototype, "getDomain").mockImplementation(() => "https://passbolt.dev"); // process await OnExtensionInstalledController.exec(details); @@ -89,8 +92,57 @@ describe("OnExtensionInstalledController", () => { expect(WebNavigationService.exec).toHaveBeenCalledTimes(2); }); + it("Should exec browser update if the reason is chrome update", async() => { + expect.assertions(3); + // data mocked + const details = { + reason: browser.runtime.OnInstalledReason.CHROME_UPDATE + }; + // mock function + jest.spyOn(OnExtensionInstalledController, "onBrowserUpdate"); + jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => false); + jest.spyOn(AuthModel.prototype, "logout"); + // process + await OnExtensionInstalledController.exec(details); + // expectation + expect(OnExtensionInstalledController.onBrowserUpdate).toHaveBeenCalled(); + expect(User.getInstance().isValid).toHaveBeenCalledTimes(1); + expect(AuthModel.prototype.logout).toHaveBeenCalledTimes(0); + }); + + it("Should exec browser update if the reason is browser update", async() => { + expect.assertions(4); + // data mocked + const details = { + reason: browser.runtime.OnInstalledReason.BROWSER_UPDATE + }; + const tabs = [ + {id: 1, url: "https://passbolt.dev/app/passwords"}, + {id: 2, url: "https://passbolt.dev/setup/recover/start/571bec7e-6cce-451d-b53a-f8c93e147228/5ea0fc9c-b180-4873-8e00-9457862e43e0"}, + {id: 3, url: "https://passbolt.dev/auth/login"}, + {id: 4, url: "https://passbolt.dev"}, + {id: 5, url: "https://passbolt.com"}, + {id: 6, url: "https://localhost"} + ]; + // mock function + jest.spyOn(OnExtensionInstalledController, "onBrowserUpdate"); + jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => true); + jest.spyOn(UserSettings.prototype, "getDomain").mockImplementation(() => "https://passbolt.dev"); + jest.spyOn(AuthModel.prototype, "logout").mockImplementation(() => {}); + jest.spyOn(browser.tabs, "query").mockImplementation(() => Promise.resolve(tabs)); + jest.spyOn(browser.tabs, "reload"); + jest.spyOn(CheckAuthStatusService.prototype, "checkAuthStatus").mockImplementation(() => ({isAuthenticated: true})); + // process + await OnExtensionInstalledController.exec(details); + // expectation + expect(OnExtensionInstalledController.onBrowserUpdate).toHaveBeenCalled(); + expect(AuthModel.prototype.logout).toHaveBeenCalledTimes(1); + expect(browser.tabs.query).toHaveBeenCalledTimes(1); + expect(browser.tabs.reload).toHaveBeenCalledWith(tabs[0].id); + }); + it("Should not exec update neither install if the reason is unknown", async() => { - expect.assertions(2); + expect.assertions(3); // data mocked const details = { reason: "unknown" @@ -98,12 +150,14 @@ describe("OnExtensionInstalledController", () => { // mock function jest.spyOn(OnExtensionInstalledController, "onUpdate"); jest.spyOn(OnExtensionInstalledController, "onInstall"); + jest.spyOn(OnExtensionInstalledController, "onBrowserUpdate"); // process await OnExtensionInstalledController.exec(details); // expectation expect(OnExtensionInstalledController.onUpdate).not.toHaveBeenCalled(); expect(OnExtensionInstalledController.onInstall).not.toHaveBeenCalled(); + expect(OnExtensionInstalledController.onBrowserUpdate).not.toHaveBeenCalled(); }); }); }); diff --git a/src/all/background_page/controller/passwordExpiry/deletePasswordExpirySettingsController.test.js b/src/all/background_page/controller/passwordExpiry/deletePasswordExpirySettingsController.test.js index d74902c3..58850ac9 100644 --- a/src/all/background_page/controller/passwordExpiry/deletePasswordExpirySettingsController.test.js +++ b/src/all/background_page/controller/passwordExpiry/deletePasswordExpirySettingsController.test.js @@ -29,7 +29,7 @@ describe("DeletePasswordExpirySettingsController", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); it("Should delete the entity from the API given an ID", () => { diff --git a/src/all/background_page/controller/passwordExpiry/getOrFindPasswordExpirySettingsController.test.js b/src/all/background_page/controller/passwordExpiry/getOrFindPasswordExpirySettingsController.test.js index 605326b2..9d95db72 100644 --- a/src/all/background_page/controller/passwordExpiry/getOrFindPasswordExpirySettingsController.test.js +++ b/src/all/background_page/controller/passwordExpiry/getOrFindPasswordExpirySettingsController.test.js @@ -39,7 +39,7 @@ describe("GetOrFindPasswordExpirySettingsController", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); it("Should return the value from the API", async() => { diff --git a/src/all/background_page/controller/passwordExpiry/savePasswordExpirySettingsController.test.js b/src/all/background_page/controller/passwordExpiry/savePasswordExpirySettingsController.test.js index aa1fe46d..6ed64598 100644 --- a/src/all/background_page/controller/passwordExpiry/savePasswordExpirySettingsController.test.js +++ b/src/all/background_page/controller/passwordExpiry/savePasswordExpirySettingsController.test.js @@ -42,7 +42,7 @@ describe("SavePasswordExpirySettingsController", () => { fetch.resetMocks(); jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); it("Should save the given dto on the API using PasswordExpirySettingsEntity", async() => { diff --git a/src/all/background_page/controller/passwordPolicies/findPasswordPoliciesController.test.js b/src/all/background_page/controller/passwordPolicies/findPasswordPoliciesController.test.js index 7e01d290..8d9a87ca 100644 --- a/src/all/background_page/controller/passwordPolicies/findPasswordPoliciesController.test.js +++ b/src/all/background_page/controller/passwordPolicies/findPasswordPoliciesController.test.js @@ -30,7 +30,7 @@ describe("FindPasswordPoliciesController::exec", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); it("Should return the registered password policies", async() => { diff --git a/src/all/background_page/controller/passwordPolicies/savePasswordPoliciesController.test.js b/src/all/background_page/controller/passwordPolicies/savePasswordPoliciesController.test.js index fc9b0282..68eec011 100644 --- a/src/all/background_page/controller/passwordPolicies/savePasswordPoliciesController.test.js +++ b/src/all/background_page/controller/passwordPolicies/savePasswordPoliciesController.test.js @@ -32,7 +32,7 @@ describe("SavePasswordPoliciesController::exec", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); it("Should save the given data", async() => { diff --git a/src/all/background_page/controller/userPassphrasePolicies/findUserPassphrasePoliciesController.test.js b/src/all/background_page/controller/userPassphrasePolicies/findUserPassphrasePoliciesController.test.js index 3d6471e9..274a1648 100644 --- a/src/all/background_page/controller/userPassphrasePolicies/findUserPassphrasePoliciesController.test.js +++ b/src/all/background_page/controller/userPassphrasePolicies/findUserPassphrasePoliciesController.test.js @@ -29,7 +29,7 @@ describe("FindUserPassphrasePoliciesController", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); const account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); it("Should return the value from the API", async() => { diff --git a/src/all/background_page/controller/userPassphrasePolicies/saveUserPassphrasePoliciesController.test.js b/src/all/background_page/controller/userPassphrasePolicies/saveUserPassphrasePoliciesController.test.js index f85f82f5..8ce096ed 100644 --- a/src/all/background_page/controller/userPassphrasePolicies/saveUserPassphrasePoliciesController.test.js +++ b/src/all/background_page/controller/userPassphrasePolicies/saveUserPassphrasePoliciesController.test.js @@ -31,7 +31,7 @@ describe("SaveUserPassphrasePoliciesController", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); const account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); it("Should save the given dto on the API", async() => { diff --git a/src/all/background_page/model/passwordExpiry/passwordExpirySettingsModel.test.js b/src/all/background_page/model/passwordExpiry/passwordExpirySettingsModel.test.js index 2f3267d4..71e387a7 100644 --- a/src/all/background_page/model/passwordExpiry/passwordExpirySettingsModel.test.js +++ b/src/all/background_page/model/passwordExpiry/passwordExpirySettingsModel.test.js @@ -35,7 +35,7 @@ describe("PasswordExpiry model", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); const account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); model = new PasswordExpirySettingsModel(account, apiClientOptions); jest.spyOn(model.organisationSettingsModel, "getOrFind").mockImplementation(() => (Promise.resolve({ isPluginEnabled: () => false diff --git a/src/all/background_page/model/passwordPolicies/passwordPoliciesModel.test.js b/src/all/background_page/model/passwordPolicies/passwordPoliciesModel.test.js index c602899e..ab5ee55f 100644 --- a/src/all/background_page/model/passwordPolicies/passwordPoliciesModel.test.js +++ b/src/all/background_page/model/passwordPolicies/passwordPoliciesModel.test.js @@ -31,7 +31,7 @@ describe("PasswordPoliciesModel", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); describe("::get", () => { diff --git a/src/all/background_page/model/user.js b/src/all/background_page/model/user.js index ea6d370c..8358aac8 100644 --- a/src/all/background_page/model/user.js +++ b/src/all/background_page/model/user.js @@ -11,6 +11,7 @@ import Validator from "validator"; import {ValidatorRule} from "../utils/validatorRules"; /** + * @deprecated * The class that deals with users. */ const User = (function() { diff --git a/src/all/background_page/model/userPassphrasePolicies/userPassphrasePoliciesModel.test.js b/src/all/background_page/model/userPassphrasePolicies/userPassphrasePoliciesModel.test.js index 13de2adc..2ab67ff7 100644 --- a/src/all/background_page/model/userPassphrasePolicies/userPassphrasePoliciesModel.test.js +++ b/src/all/background_page/model/userPassphrasePolicies/userPassphrasePoliciesModel.test.js @@ -32,7 +32,7 @@ describe("UserPassphrasePolicies model", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); const account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); describe('::findOrDefault', () => { diff --git a/src/all/background_page/pagemod/accountRecoveryPagemod.js b/src/all/background_page/pagemod/accountRecoveryPagemod.js index 36ec99ef..c1541409 100644 --- a/src/all/background_page/pagemod/accountRecoveryPagemod.js +++ b/src/all/background_page/pagemod/accountRecoveryPagemod.js @@ -43,7 +43,7 @@ class AccountRecovery extends Pagemod { try { const tab = port._port.sender.tab; const account = await GetRequestLocalAccountService.getAccountMatchingContinueUrl(tab.url); - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); for (const event of this.events) { event.listen({port, tab}, apiClientOptions, account); } diff --git a/src/all/background_page/pagemod/appBootstrapPagemod.js b/src/all/background_page/pagemod/appBootstrapPagemod.js index ab1c639f..60e773d2 100644 --- a/src/all/background_page/pagemod/appBootstrapPagemod.js +++ b/src/all/background_page/pagemod/appBootstrapPagemod.js @@ -12,11 +12,11 @@ * @since 4.0.0 */ import Pagemod from "./pagemod"; -import User from "../model/user"; import {AppBootstrapEvents} from "../event/appBootstrapEvents"; import ParseAppUrlService from "../service/app/parseAppUrlService"; import {PortEvents} from "../event/portEvents"; import CheckAuthStatusService from "../service/auth/checkAuthStatusService"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; class AppBootstrap extends Pagemod { /** @@ -63,7 +63,7 @@ class AppBootstrap extends Pagemod { */ async canBeAttachedTo(frameDetails) { return this.assertTopFrameAttachConstraint(frameDetails) - && this.assertUrlAttachConstraint(frameDetails) && + && await this.assertUrlAttachConstraint(frameDetails) && await this.assertUserAuthenticated(); } @@ -79,14 +79,16 @@ class AppBootstrap extends Pagemod { /** * Assert that the attached frame is a top frame. * @param {Object} frameDetails - * @returns {boolean} + * @returns {Promise} */ - assertUrlAttachConstraint(frameDetails) { - const user = User.getInstance(); - if (user.isValid()) { + async assertUrlAttachConstraint(frameDetails) { + try { + await GetActiveAccountService.get(); return ParseAppUrlService.test(frameDetails.url); + } catch (error) { + console.log(error); + return false; } - return false; } /** diff --git a/src/all/background_page/pagemod/appBootstrapPagemod.test.js b/src/all/background_page/pagemod/appBootstrapPagemod.test.js index ab5b5bff..34004bd2 100644 --- a/src/all/background_page/pagemod/appBootstrapPagemod.test.js +++ b/src/all/background_page/pagemod/appBootstrapPagemod.test.js @@ -11,7 +11,6 @@ * @link https://www.passbolt.com Passbolt(tm) * @since 3.8.0 */ -import User from "../model/user"; import UserSettings from "../model/userSettings/userSettings"; import AppBootstrap from "./appBootstrapPagemod"; import WorkersSessionStorage from "../service/sessionStorage/workersSessionStorage"; @@ -23,6 +22,7 @@ import each from "jest-each"; import {PortEvents} from "../event/portEvents"; import CheckAuthStatusService from "../service/auth/checkAuthStatusService"; import {userLoggedInAuthStatus, userLoggedOutAuthStatus} from "../controller/auth/authCheckStatus.test.data"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; const spyAddWorker = jest.spyOn(WorkersSessionStorage, "addWorker"); jest.spyOn(ScriptExecution.prototype, "injectPortname").mockImplementation(jest.fn()); @@ -60,7 +60,7 @@ describe("AppBootstrap", () => { it("Should be able to attach app bootstrap pagemod to browser frame", async() => { expect.assertions(1); // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => true); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => {}); jest.spyOn(CheckAuthStatusService.prototype, "checkAuthStatus").mockImplementation(async() => userLoggedInAuthStatus()); jest.spyOn(UserSettings.prototype, "getDomain").mockImplementation(() => "https://passbolt.dev"); const result = await AppBootstrap.canBeAttachedTo({frameId: Pagemod.TOP_FRAME_ID, url: "https://passbolt.dev/app"}); @@ -81,7 +81,7 @@ describe("AppBootstrap", () => { it("Should not be able to attach a pagemod if the user is not valid", async() => { expect.assertions(1); // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => false); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => { throw new Error(); }); // process const result = await AppBootstrap.canBeAttachedTo({frameId: 0}); // expectations @@ -91,7 +91,7 @@ describe("AppBootstrap", () => { it("Should not be able to attach a pagemod if the user is not authenticated", async() => { expect.assertions(1); // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => true); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => {}); jest.spyOn(CheckAuthStatusService.prototype, "checkAuthStatus").mockImplementation(async() => userLoggedOutAuthStatus()); jest.spyOn(UserSettings.prototype, "getDomain").mockImplementation(() => "https://passbolt"); // process diff --git a/src/all/background_page/pagemod/appPagemod.js b/src/all/background_page/pagemod/appPagemod.js index 8b1d8f4c..6b01ce56 100644 --- a/src/all/background_page/pagemod/appPagemod.js +++ b/src/all/background_page/pagemod/appPagemod.js @@ -12,7 +12,6 @@ * @since 4.0.0 */ import Pagemod from "./pagemod"; -import GetLegacyAccountService from "../service/account/getLegacyAccountService"; import AppInitController from "../controller/app/appInitController"; import {AppEvents} from "../event/appEvents"; import {ConfigEvents} from "../event/configEvents"; @@ -44,6 +43,7 @@ import {ClipboardEvents} from "../event/clipboardEvents"; import BuildApiClientOptionsService from "../service/account/buildApiClientOptionsService"; import {RememberMeEvents} from "../event/rememberMeEvents"; import CheckAuthStatusService from "../service/auth/checkAuthStatusService"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; class App extends Pagemod { /** @@ -107,8 +107,8 @@ class App extends Pagemod { const appInitController = new AppInitController(); await appInitController.main(); - const account = await GetLegacyAccountService.get({role: true}); - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + const account = await GetActiveAccountService.get({role: true}); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); for (const event of this.events) { event.listen({port, tab}, apiClientOptions, account); } diff --git a/src/all/background_page/pagemod/appPagemod.test.js b/src/all/background_page/pagemod/appPagemod.test.js index fc309aca..7b1b3fc3 100644 --- a/src/all/background_page/pagemod/appPagemod.test.js +++ b/src/all/background_page/pagemod/appPagemod.test.js @@ -13,7 +13,6 @@ */ import {ConfigEvents} from "../event/configEvents"; import App from "./appPagemod"; -import GetLegacyAccountService from "../service/account/getLegacyAccountService"; import {UserEvents} from "../event/userEvents"; import {KeyringEvents} from "../event/keyringEvents"; import {AuthEvents} from "../event/authEvents"; @@ -46,6 +45,7 @@ import {enableFetchMocks} from "jest-fetch-mock"; import {RememberMeEvents} from "../event/rememberMeEvents"; import CheckAuthStatusService from "../service/auth/checkAuthStatusService"; import {userLoggedInAuthStatus} from "../controller/auth/authCheckStatus.test.data"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; jest.spyOn(ConfigEvents, "listen").mockImplementation(jest.fn()); jest.spyOn(AppEvents, "listen").mockImplementation(jest.fn()); @@ -96,19 +96,17 @@ describe("App", () => { } } }; - jest.spyOn(GetLegacyAccountService, 'get').mockImplementation(() => mockedAccount); - // mock functions jest.spyOn(browser.cookies, "get").mockImplementation(() => ({value: "csrf-token"})); jest.spyOn(CheckAuthStatusService.prototype, "checkAuthStatus").mockImplementation(async() => userLoggedInAuthStatus()); const mockedAccount = {user_id: uuid(), domain: "https://test-domain.passbolt.com"}; - const mockApiClient = await BuildApiClientOptionsService.buildFromAccount(mockedAccount); - jest.spyOn(GetLegacyAccountService, 'get').mockImplementation(() => mockedAccount); + const mockApiClient = BuildApiClientOptionsService.buildFromAccount(mockedAccount); + jest.spyOn(GetActiveAccountService, 'get').mockImplementation(() => mockedAccount); // process await App.attachEvents(port); // expectations const expectedPortAndTab = {port: port, tab: port._port.sender.tab}; - expect(GetLegacyAccountService.get).toHaveBeenCalledWith({role: true}); + expect(GetActiveAccountService.get).toHaveBeenCalledWith({role: true}); expect(ConfigEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount); expect(AppEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount); expect(AuthEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount); diff --git a/src/all/background_page/pagemod/authBootstrapPagemod.js b/src/all/background_page/pagemod/authBootstrapPagemod.js index ba7d7eff..71397c46 100644 --- a/src/all/background_page/pagemod/authBootstrapPagemod.js +++ b/src/all/background_page/pagemod/authBootstrapPagemod.js @@ -12,9 +12,9 @@ * @since 4.0.0 */ import Pagemod from "./pagemod"; -import User from "../model/user"; import {PortEvents} from "../event/portEvents"; import ParseAuthUrlService from "../service/auth/parseAuthUrlService"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; class AuthBootstrap extends Pagemod { /** @@ -61,7 +61,7 @@ class AuthBootstrap extends Pagemod { */ async canBeAttachedTo(frameDetails) { return this.assertTopFrameAttachConstraint(frameDetails) - && this.assertUrlAttachConstraint(frameDetails); + && await this.assertUrlAttachConstraint(frameDetails); } /** @@ -76,14 +76,16 @@ class AuthBootstrap extends Pagemod { /** * Assert that the attached frame is a top frame. * @param {Object} frameDetails - * @returns {boolean} + * @returns {Promise} */ - assertUrlAttachConstraint(frameDetails) { - const user = User.getInstance(); - if (user.isValid()) { + async assertUrlAttachConstraint(frameDetails) { + try { + await GetActiveAccountService.get(); return ParseAuthUrlService.test(frameDetails.url); + } catch (error) { + console.log(error); + return false; } - return false; } } diff --git a/src/all/background_page/pagemod/authBootstrapPagemod.test.js b/src/all/background_page/pagemod/authBootstrapPagemod.test.js index 9e9aa78a..542a991a 100644 --- a/src/all/background_page/pagemod/authBootstrapPagemod.test.js +++ b/src/all/background_page/pagemod/authBootstrapPagemod.test.js @@ -11,7 +11,6 @@ * @link https://www.passbolt.com Passbolt(tm) * @since 3.8.0 */ -import User from "../model/user"; import UserSettings from "../model/userSettings/userSettings"; import AuthBootstrap from "./authBootstrapPagemod"; import WorkersSessionStorage from "../service/sessionStorage/workersSessionStorage"; @@ -20,6 +19,7 @@ import ScriptExecution from "../sdk/scriptExecution"; import {PortEvents} from "../event/portEvents"; import each from "jest-each"; import Pagemod from "./pagemod"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; const spyAddWorker = jest.spyOn(WorkersSessionStorage, "addWorker"); jest.spyOn(ScriptExecution.prototype, "injectPortname").mockImplementation(jest.fn()); @@ -56,7 +56,7 @@ describe("AuthBootstrap", () => { it("Should be able to attach auth bootstrap pagemod to browser frame", async() => { expect.assertions(1); // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => true); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => {}); jest.spyOn(UserSettings.prototype, "getDomain").mockImplementation(() => "https://passbolt.dev"); const result = await AuthBootstrap.canBeAttachedTo({frameId: Pagemod.TOP_FRAME_ID, url: "https://passbolt.dev/auth/login"}); expect(result).toBeTruthy(); @@ -69,7 +69,7 @@ describe("AuthBootstrap", () => { it(`Should be able to attach a pagemod to browser frame: ${_props.scenario}`, async() => { expect.assertions(1); // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => true); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => {}); jest.spyOn(UserSettings.prototype, "getDomain").mockImplementation(() => "https://passbolt.dev"); const result = await AuthBootstrap.canBeAttachedTo({frameId: _props.frameId, url: _props.url}); expect(result).toBeFalsy(); @@ -79,7 +79,7 @@ describe("AuthBootstrap", () => { it("Should have the constraint not valid if the user is not valid", async() => { expect.assertions(1); // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => false); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => { throw new Error(); }); // process const result = await AuthBootstrap.canBeAttachedTo({frameId: 0}); // expectations diff --git a/src/all/background_page/pagemod/authPagemod.js b/src/all/background_page/pagemod/authPagemod.js index 56907e27..a436b8e9 100644 --- a/src/all/background_page/pagemod/authPagemod.js +++ b/src/all/background_page/pagemod/authPagemod.js @@ -12,7 +12,6 @@ * @since 4.0.0 */ import Pagemod from "./pagemod"; -import GetLegacyAccountService from "../service/account/getLegacyAccountService"; import {UserEvents} from "../event/userEvents"; import {KeyringEvents} from "../event/keyringEvents"; import {AuthEvents} from "../event/authEvents"; @@ -21,6 +20,7 @@ import {OrganizationSettingsEvents} from "../event/organizationSettingsEvents"; import {LocaleEvents} from "../event/localeEvents"; import BuildApiClientOptionsService from "../service/account/buildApiClientOptionsService"; import {RememberMeEvents} from "../event/rememberMeEvents"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; class Auth extends Pagemod { /** @@ -52,8 +52,8 @@ class Auth extends Pagemod { async attachEvents(port) { try { const tab = port._port.sender.tab; - const account = await GetLegacyAccountService.get(); - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + const account = await GetActiveAccountService.get(); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); for (const event of this.events) { event.listen({port, tab}, apiClientOptions, account); } diff --git a/src/all/background_page/pagemod/authPagemod.test.js b/src/all/background_page/pagemod/authPagemod.test.js index f4b8a3a6..cbbbd26d 100644 --- a/src/all/background_page/pagemod/authPagemod.test.js +++ b/src/all/background_page/pagemod/authPagemod.test.js @@ -13,7 +13,6 @@ */ import {ConfigEvents} from "../event/configEvents"; import Auth from "./authPagemod"; -import GetLegacyAccountService from "../service/account/getLegacyAccountService"; import {UserEvents} from "../event/userEvents"; import {KeyringEvents} from "../event/keyringEvents"; import {AuthEvents} from "../event/authEvents"; @@ -23,6 +22,7 @@ import {v4 as uuid} from 'uuid'; import {enableFetchMocks} from "jest-fetch-mock"; import BuildApiClientOptionsService from "../service/account/buildApiClientOptionsService"; import {RememberMeEvents} from "../event/rememberMeEvents"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; jest.spyOn(ConfigEvents, "listen").mockImplementation(jest.fn()); jest.spyOn(UserEvents, "listen").mockImplementation(jest.fn()); @@ -54,13 +54,13 @@ describe("Auth", () => { }; jest.spyOn(browser.cookies, "get").mockImplementation(() => ({value: "csrf-token"})); const mockedAccount = {user_id: uuid(), domain: "https://test-domain.passbolt.com"}; - const mockApiClient = await BuildApiClientOptionsService.buildFromAccount(mockedAccount); - jest.spyOn(GetLegacyAccountService, 'get').mockImplementation(() => mockedAccount); + const mockApiClient = BuildApiClientOptionsService.buildFromAccount(mockedAccount); + jest.spyOn(GetActiveAccountService, 'get').mockImplementation(() => mockedAccount); // process await Auth.attachEvents(port); // expectations const expectedPortAndTab = {port: port, tab: port._port.sender.tab}; - expect(GetLegacyAccountService.get).toHaveBeenCalledTimes(1); + expect(GetActiveAccountService.get).toHaveBeenCalledTimes(1); expect(ConfigEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount); expect(UserEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount); expect(KeyringEvents.listen).toHaveBeenCalledWith(expectedPortAndTab, mockApiClient, mockedAccount); diff --git a/src/all/background_page/pagemod/informCallToActionPagemod.js b/src/all/background_page/pagemod/informCallToActionPagemod.js index 497ef50a..2cd7758d 100644 --- a/src/all/background_page/pagemod/informCallToActionPagemod.js +++ b/src/all/background_page/pagemod/informCallToActionPagemod.js @@ -13,8 +13,8 @@ */ import Pagemod from "./pagemod"; import {InformCallToActionEvents} from "../event/informCallToActionEvents"; -import GetLegacyAccountService from "../service/account/getLegacyAccountService"; import BuildApiClientOptionsService from "../service/account/buildApiClientOptionsService"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; class InFormCallToAction extends Pagemod { /** @@ -38,8 +38,8 @@ class InFormCallToAction extends Pagemod { async attachEvents(port) { try { const tab = port._port.sender.tab; - const account = await GetLegacyAccountService.get(); - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + const account = await GetActiveAccountService.get(); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); const name = this.appName; for (const event of this.events) { event.listen({port, tab, name}, apiClientOptions, account); diff --git a/src/all/background_page/pagemod/informCallToActionPagemod.test.js b/src/all/background_page/pagemod/informCallToActionPagemod.test.js index 355be3a6..ca9bf05e 100644 --- a/src/all/background_page/pagemod/informCallToActionPagemod.test.js +++ b/src/all/background_page/pagemod/informCallToActionPagemod.test.js @@ -13,10 +13,10 @@ */ import InformCallToAction from "./informCallToActionPagemod"; import {InformCallToActionEvents} from "../event/informCallToActionEvents"; -import GetLegacyAccountService from "../service/account/getLegacyAccountService"; import {v4 as uuid} from 'uuid'; import {enableFetchMocks} from "jest-fetch-mock"; import BuildApiClientOptionsService from "../service/account/buildApiClientOptionsService"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; jest.spyOn(InformCallToActionEvents, "listen").mockImplementation(jest.fn()); @@ -43,8 +43,8 @@ describe("InFormCallToAction", () => { // mock functions jest.spyOn(browser.cookies, "get").mockImplementation(() => ({value: "csrf-token"})); const mockedAccount = {user_id: uuid(), domain: "https://test.passbolt.local"}; - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(mockedAccount); - jest.spyOn(GetLegacyAccountService, 'get').mockImplementation(() => mockedAccount); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(mockedAccount); + jest.spyOn(GetActiveAccountService, 'get').mockImplementation(() => mockedAccount); // process await InformCallToAction.attachEvents(port); // expectations diff --git a/src/all/background_page/pagemod/informMenuPagemod.js b/src/all/background_page/pagemod/informMenuPagemod.js index e1d68c0d..d253ec37 100644 --- a/src/all/background_page/pagemod/informMenuPagemod.js +++ b/src/all/background_page/pagemod/informMenuPagemod.js @@ -13,8 +13,8 @@ */ import Pagemod from "./pagemod"; import {InformMenuEvents} from "../event/informMenuEvents"; -import GetLegacyAccountService from "../service/account/getLegacyAccountService"; import BuildApiClientOptionsService from "../service/account/buildApiClientOptionsService"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; class InFormMenu extends Pagemod { /** @@ -38,8 +38,8 @@ class InFormMenu extends Pagemod { async attachEvents(port) { try { const tab = port._port.sender.tab; - const account = await GetLegacyAccountService.get(); - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + const account = await GetActiveAccountService.get(); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); const name = this.appName; for (const event of this.events) { event.listen({port, tab, name}, apiClientOptions, account); diff --git a/src/all/background_page/pagemod/informMenuPagemod.test.js b/src/all/background_page/pagemod/informMenuPagemod.test.js index 1df5bf68..60747e70 100644 --- a/src/all/background_page/pagemod/informMenuPagemod.test.js +++ b/src/all/background_page/pagemod/informMenuPagemod.test.js @@ -14,9 +14,9 @@ import InformMenu from "./informMenuPagemod"; import {InformMenuEvents} from "../event/informMenuEvents"; import {v4 as uuid} from 'uuid'; -import GetLegacyAccountService from "../service/account/getLegacyAccountService"; import {enableFetchMocks} from "jest-fetch-mock"; import BuildApiClientOptionsService from "../service/account/buildApiClientOptionsService"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; jest.spyOn(InformMenuEvents, "listen").mockImplementation(jest.fn()); @@ -44,8 +44,8 @@ describe("InFormMenu", () => { // mock functions jest.spyOn(browser.cookies, "get").mockImplementation(() => ({value: "csrf-token"})); const mockedAccount = {user_id: uuid(), domain: "https://test.passbolt.local"}; - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(mockedAccount); - jest.spyOn(GetLegacyAccountService, 'get').mockImplementation(() => mockedAccount); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(mockedAccount); + jest.spyOn(GetActiveAccountService, 'get').mockImplementation(() => mockedAccount); // process await InformMenu.attachEvents(port); diff --git a/src/all/background_page/pagemod/pagemodManager.js b/src/all/background_page/pagemod/pagemodManager.js index 9f31fc8a..c53bb5da 100644 --- a/src/all/background_page/pagemod/pagemodManager.js +++ b/src/all/background_page/pagemod/pagemodManager.js @@ -100,10 +100,14 @@ class PagemodManager { /** * Has pagemod that match tab url to reload * @param url The url - * @return {boolean} + * @return {Promise} */ - hasPagemodMatchUrlToReload(url) { - return this.pagemods.some(pagemod => pagemod.mustReloadOnExtensionUpdate && pagemod.assertUrlAttachConstraint({url})); + async hasPagemodMatchUrlToReload(url) { + for (const pagemod of this.pagemods) { + if (pagemod.mustReloadOnExtensionUpdate && await pagemod.assertUrlAttachConstraint({url})) { + return true; + } + } } } diff --git a/src/all/background_page/pagemod/pagemodManager.test.js b/src/all/background_page/pagemod/pagemodManager.test.js index 1d7e3bf3..3d69937f 100644 --- a/src/all/background_page/pagemod/pagemodManager.test.js +++ b/src/all/background_page/pagemod/pagemodManager.test.js @@ -16,13 +16,13 @@ import pagemod from "./pagemod"; import RecoverBootstrapPagemod from "./recoverBootstrapPagemod"; import SetupBootstrapPagemod from "./setupBootstrapPagemod"; import AuthBootstrapPagemod from "./authBootstrapPagemod"; -import User from "../model/user"; import UserSettings from "../model/userSettings/userSettings"; import AppBootstrapPagemod from "./appBootstrapPagemod"; import WebIntegrationPagemod from "./webIntegrationPagemod"; import PublicWebsiteSignInPagemod from "./publicWebsiteSignInPagemod"; import CheckAuthStatusService from "../service/auth/checkAuthStatusService"; import {userLoggedInAuthStatus} from "../controller/auth/authCheckStatus.test.data"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; jest.spyOn(pagemod.prototype, "injectFiles").mockImplementation(jest.fn()); jest.spyOn(pagemod.prototype, "attachEvents").mockImplementation(jest.fn()); @@ -73,7 +73,7 @@ describe("PagemodManager", () => { url: "https://passbolt.dev/auth/login" }; // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => true); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => {}); jest.spyOn(UserSettings.prototype, "getDomain").mockImplementation(() => "https://passbolt.dev"); // process await PagemodManager.exec(details); @@ -91,7 +91,7 @@ describe("PagemodManager", () => { url: "https://passbolt.dev/app" }; // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => true); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => {}); jest.spyOn(CheckAuthStatusService.prototype, "checkAuthStatus").mockImplementation(async() => userLoggedInAuthStatus()); jest.spyOn(UserSettings.prototype, "getDomain").mockImplementation(() => "https://passbolt.dev"); // process @@ -110,7 +110,7 @@ describe("PagemodManager", () => { url: "https://test.dev/auth/login" }; // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => true); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => {}); jest.spyOn(UserSettings.prototype, "getDomain").mockImplementation(() => "https://passbolt.dev"); // process await PagemodManager.exec(details); @@ -128,7 +128,7 @@ describe("PagemodManager", () => { url: "https://www.passbolt.com" }; // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => true); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => {}); jest.spyOn(UserSettings.prototype, "getDomain").mockImplementation(() => "https://passbolt.dev"); // process await PagemodManager.exec(details); @@ -183,16 +183,16 @@ describe("PagemodManager", () => { it("Should refresh tab if pagemod must refresh tab url", async() => { expect.assertions(7); // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => true); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => {}); jest.spyOn(UserSettings.prototype, "getDomain").mockImplementation(() => "https://passbolt.dev"); // expectations - expect(PagemodManager.hasPagemodMatchUrlToReload("https://passbolt.dev")).toBeTruthy(); - expect(PagemodManager.hasPagemodMatchUrlToReload("https://www.passbolt.com")).toBeFalsy(); - expect(PagemodManager.hasPagemodMatchUrlToReload("https://passbolt.dev/setup/recover/d57c10f5-639d-5160-9c81-8a0c6c4ec856/efc85bca-fc9f-4b32-aebf-b82765312e47")).toBeTruthy(); - expect(PagemodManager.hasPagemodMatchUrlToReload("https://passbolt.dev/auth/login")).toBeTruthy(); - expect(PagemodManager.hasPagemodMatchUrlToReload("https://passbolt.dev/setup/start/d57c10f5-639d-5160-9c81-8a0c6c4ec856/efc85bca-fc9f-4b32-aebf-b82765312e47")).toBeTruthy(); - expect(PagemodManager.hasPagemodMatchUrlToReload("https://passbolt.dev/account-recovery/continue/d57c10f5-639d-5160-9c81-8a0c6c4ec856/cb66b7ca-bb85-4088-b0da-c50f6f0c2a13")).toBeTruthy(); - expect(PagemodManager.hasPagemodMatchUrlToReload("https://localhost")).toBeFalsy(); + expect(await PagemodManager.hasPagemodMatchUrlToReload("https://passbolt.dev")).toBeTruthy(); + expect(await PagemodManager.hasPagemodMatchUrlToReload("https://www.passbolt.com")).toBeFalsy(); + expect(await PagemodManager.hasPagemodMatchUrlToReload("https://passbolt.dev/setup/recover/d57c10f5-639d-5160-9c81-8a0c6c4ec856/efc85bca-fc9f-4b32-aebf-b82765312e47")).toBeTruthy(); + expect(await PagemodManager.hasPagemodMatchUrlToReload("https://passbolt.dev/auth/login")).toBeTruthy(); + expect(await PagemodManager.hasPagemodMatchUrlToReload("https://passbolt.dev/setup/start/d57c10f5-639d-5160-9c81-8a0c6c4ec856/efc85bca-fc9f-4b32-aebf-b82765312e47")).toBeTruthy(); + expect(await PagemodManager.hasPagemodMatchUrlToReload("https://passbolt.dev/account-recovery/continue/d57c10f5-639d-5160-9c81-8a0c6c4ec856/cb66b7ca-bb85-4088-b0da-c50f6f0c2a13")).toBeTruthy(); + expect(await PagemodManager.hasPagemodMatchUrlToReload("https://localhost")).toBeFalsy(); }); }); }); diff --git a/src/all/background_page/pagemod/publicWebsiteSignInPagemod.js b/src/all/background_page/pagemod/publicWebsiteSignInPagemod.js index d9c98b91..bd807817 100644 --- a/src/all/background_page/pagemod/publicWebsiteSignInPagemod.js +++ b/src/all/background_page/pagemod/publicWebsiteSignInPagemod.js @@ -12,10 +12,9 @@ * @since 4.0.0 */ import Pagemod from "./pagemod"; -import User from "../model/user"; import {PublicWebsiteSignInEvents} from "../event/publicWebsiteSignInEvents"; import ParsePublicWebsiteUrlService from "../service/publicWebsite/parsePublicWebsiteUrlService"; -import GetLegacyAccountService from "../service/account/getLegacyAccountService"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; class PublicWebsiteSignIn extends Pagemod { /** @@ -49,7 +48,7 @@ class PublicWebsiteSignIn extends Pagemod { async canBeAttachedTo(frameDetails) { return this.assertTopFrameAttachConstraint(frameDetails) && this.assertUrlAttachConstraint(frameDetails) - && this.assertUserValidConstraint(); + && await this.assertUserValidConstraint(); } /** @@ -58,7 +57,7 @@ class PublicWebsiteSignIn extends Pagemod { async attachEvents(port) { try { const tab = port._port.sender.tab; - const account = await GetLegacyAccountService.get(); + const account = await GetActiveAccountService.get(); for (const event of this.events) { event.listen({port, tab}, null, account); } @@ -89,11 +88,16 @@ class PublicWebsiteSignIn extends Pagemod { /** * Assert that the user is valid. - * @returns {boolean} + * @returns {Promise} */ - assertUserValidConstraint() { - const user = User.getInstance(); - return user.isValid(); + async assertUserValidConstraint() { + try { + await GetActiveAccountService.get(); + return true; + } catch (error) { + console.log(error); + return false; + } } } diff --git a/src/all/background_page/pagemod/publicWebsiteSignInPagemod.test.js b/src/all/background_page/pagemod/publicWebsiteSignInPagemod.test.js index 2e540b85..ffa08cc8 100644 --- a/src/all/background_page/pagemod/publicWebsiteSignInPagemod.test.js +++ b/src/all/background_page/pagemod/publicWebsiteSignInPagemod.test.js @@ -11,7 +11,6 @@ * @link https://www.passbolt.com Passbolt(tm) * @since 3.8.0 */ -import User from "../model/user"; import WorkersSessionStorage from "../service/sessionStorage/workersSessionStorage"; import WorkerEntity from "../model/entity/worker/workerEntity"; import ScriptExecution from "../sdk/scriptExecution"; @@ -19,8 +18,8 @@ import each from "jest-each"; import Pagemod from "./pagemod"; import {PublicWebsiteSignInEvents} from "../event/publicWebsiteSignInEvents"; import PublicWebsiteSignIn from "./publicWebsiteSignInPagemod"; -import GetLegacyAccountService from "../service/account/getLegacyAccountService"; import {v4 as uuid} from 'uuid'; +import GetActiveAccountService from "../service/account/getActiveAccountService"; const spyAddWorker = jest.spyOn(WorkersSessionStorage, "addWorker"); jest.spyOn(ScriptExecution.prototype, "injectPortname").mockImplementation(jest.fn()); @@ -57,7 +56,7 @@ describe("PublicWebsiteSign", () => { it("Should be able to attach auth bootstrap pagemod to browser frame", async() => { expect.assertions(1); // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => true); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => {}); const result = await PublicWebsiteSignIn.canBeAttachedTo({frameId: Pagemod.TOP_FRAME_ID, url: "https://www.passbolt.com"}); expect(result).toBeTruthy(); }); @@ -76,7 +75,7 @@ describe("PublicWebsiteSign", () => { it("Should have the constraint not valid if the user is not valid", async() => { expect.assertions(1); // mock functions - jest.spyOn(User.getInstance(), "isValid").mockImplementation(() => false); + jest.spyOn(GetActiveAccountService, "get").mockImplementation(() => { throw new Error(); }); // process const result = await PublicWebsiteSignIn.canBeAttachedTo({frameId: 0, url: "https://www.passbolt.com"}); // expectations @@ -100,11 +99,11 @@ describe("PublicWebsiteSign", () => { }; const mockedAccount = {user_id: uuid()}; - jest.spyOn(GetLegacyAccountService, 'get').mockImplementation(() => mockedAccount); + jest.spyOn(GetActiveAccountService, 'get').mockImplementation(() => mockedAccount); // process await PublicWebsiteSignIn.attachEvents(port); // expectations - expect(GetLegacyAccountService.get).toHaveBeenCalled(); + expect(GetActiveAccountService.get).toHaveBeenCalled(); expect(PublicWebsiteSignInEvents.listen).toHaveBeenCalledWith({port: port, tab: port._port.sender.tab}, null, mockedAccount); }); }); diff --git a/src/all/background_page/pagemod/quickAccessPagemod.js b/src/all/background_page/pagemod/quickAccessPagemod.js index 955f07e3..0c78a892 100644 --- a/src/all/background_page/pagemod/quickAccessPagemod.js +++ b/src/all/background_page/pagemod/quickAccessPagemod.js @@ -24,10 +24,10 @@ import {OrganizationSettingsEvents} from "../event/organizationSettingsEvents"; import {TabEvents} from "../event/tabEvents"; import {LocaleEvents} from "../event/localeEvents"; import {PownedPasswordEvents} from '../event/pownedPasswordEvents'; -import GetLegacyAccountService from "../service/account/getLegacyAccountService"; import {RememberMeEvents} from "../event/rememberMeEvents"; import {ResourceTypeEvents} from "../event/resourceTypeEvents"; import BuildApiClientOptionsService from "../service/account/buildApiClientOptionsService"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; class QuickAccess extends Pagemod { /** @@ -66,8 +66,8 @@ class QuickAccess extends Pagemod { async attachEvents(port) { let account, apiClientOptions; try { - account = await GetLegacyAccountService.get(); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + account = await GetActiveAccountService.get(); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); } catch (error) { //Ensure the application does not crash completely if the legacy account cannot be retrieved console.error('quickaccessPagemod::attach legacy account cannot be retrieved, please contact your administrator.'); diff --git a/src/all/background_page/pagemod/quickAccessPagemod.test.js b/src/all/background_page/pagemod/quickAccessPagemod.test.js index a685c560..0cf0618f 100644 --- a/src/all/background_page/pagemod/quickAccessPagemod.test.js +++ b/src/all/background_page/pagemod/quickAccessPagemod.test.js @@ -24,14 +24,13 @@ import {OrganizationSettingsEvents} from "../event/organizationSettingsEvents"; import {TabEvents} from "../event/tabEvents"; import {LocaleEvents} from "../event/localeEvents"; import {PownedPasswordEvents} from '../event/pownedPasswordEvents'; -import GetLegacyAccountService from "../service/account/getLegacyAccountService"; import {v4 as uuid} from 'uuid'; import {enableFetchMocks} from "jest-fetch-mock"; import {RememberMeEvents} from "../event/rememberMeEvents"; import {ResourceTypeEvents} from "../event/resourceTypeEvents"; import BuildApiClientOptionsService from "../service/account/buildApiClientOptionsService"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; -jest.spyOn(GetLegacyAccountService, "get").mockImplementation(jest.fn()); jest.spyOn(AuthEvents, "listen").mockImplementation(jest.fn()); jest.spyOn(ConfigEvents, "listen").mockImplementation(jest.fn()); jest.spyOn(KeyringEvents, "listen").mockImplementation(jest.fn()); @@ -66,8 +65,8 @@ describe("QuickAccess", () => { // mock functions jest.spyOn(browser.cookies, "get").mockImplementation(() => ({value: "csrf-token"})); const mockedAccount = {user_id: uuid(), domain: "https://test.passbolt.local"}; - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(mockedAccount); - jest.spyOn(GetLegacyAccountService, 'get').mockImplementation(() => mockedAccount); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(mockedAccount); + jest.spyOn(GetActiveAccountService, 'get').mockImplementation(() => mockedAccount); // process await QuickAccess.attachEvents(port); // expectations diff --git a/src/all/background_page/pagemod/recoverPagemod.js b/src/all/background_page/pagemod/recoverPagemod.js index 8771ed2d..a07fb0b5 100644 --- a/src/all/background_page/pagemod/recoverPagemod.js +++ b/src/all/background_page/pagemod/recoverPagemod.js @@ -49,7 +49,7 @@ class Recover extends Pagemod { try { const tab = port._port.sender.tab; const account = BuildAccountRecoverService.buildFromRecoverUrl(tab.url); - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); await (new OrganizationSettingsModel(apiClientOptions)).getOrFind(true); for (const event of this.events) { event.listen({port, tab}, apiClientOptions, account); diff --git a/src/all/background_page/pagemod/setupPagemod.js b/src/all/background_page/pagemod/setupPagemod.js index 63a7ca00..5cbed906 100644 --- a/src/all/background_page/pagemod/setupPagemod.js +++ b/src/all/background_page/pagemod/setupPagemod.js @@ -47,7 +47,7 @@ class Setup extends Pagemod { try { const tab = port._port.sender.tab; const account = BuildAccountSetupService.buildFromSetupUrl(tab.url); - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); await (new OrganizationSettingsModel(apiClientOptions)).getOrFind(true); for (const event of this.events) { event.listen({port, tab}, apiClientOptions, account); diff --git a/src/all/background_page/pagemod/webIntegrationPagemod.js b/src/all/background_page/pagemod/webIntegrationPagemod.js index 622076ae..0ae5249a 100644 --- a/src/all/background_page/pagemod/webIntegrationPagemod.js +++ b/src/all/background_page/pagemod/webIntegrationPagemod.js @@ -12,12 +12,12 @@ * @since 4.0.0 */ import Pagemod from "./pagemod"; -import User from "../model/user"; import {ConfigEvents} from "../event/configEvents"; import {WebIntegrationEvents} from "../event/webIntegrationEvents"; import {OrganizationSettingsEvents} from "../event/organizationSettingsEvents"; import {PortEvents} from "../event/portEvents"; import ParseWebIntegrationUrlService from "../service/webIntegration/parseWebIntegrationUrlService"; +import GetActiveAccountService from "../service/account/getActiveAccountService"; class WebIntegration extends Pagemod { /** @@ -62,7 +62,7 @@ class WebIntegration extends Pagemod { */ async canBeAttachedTo(frameDetails) { return this.assertTopFrameAttachConstraint(frameDetails) - && this.assertUrlAttachConstraint(frameDetails); + && await this.assertUrlAttachConstraint(frameDetails); } /** @@ -77,14 +77,16 @@ class WebIntegration extends Pagemod { /** * Assert that the attached frame is a top frame. * @param {Object} frameDetails - * @returns {boolean} + * @returns {Promise} */ - assertUrlAttachConstraint(frameDetails) { - const user = User.getInstance(); - if (user.isValid()) { + async assertUrlAttachConstraint(frameDetails) { + try { + await GetActiveAccountService.get(); return ParseWebIntegrationUrlService.test(frameDetails.url); + } catch (error) { + console.log(error); + return false; } - return false; } } diff --git a/src/all/background_page/service/account/buildApiClientOptionsService.js b/src/all/background_page/service/account/buildApiClientOptionsService.js index fbc207b3..5d69261f 100644 --- a/src/all/background_page/service/account/buildApiClientOptionsService.js +++ b/src/all/background_page/service/account/buildApiClientOptionsService.js @@ -17,18 +17,18 @@ class BuildApiClientOptionsService { /** * Build Api client options based on an account. * @param {AbstractAccountEntity} account The account to build the api client options based on - * @returns {Promise} + * @returns {ApiClientOptions} */ - static async buildFromAccount(account) { + static buildFromAccount(account) { return this.buildFromDomain(account.domain); } /** * Build Api client options based on a domain. * @param {string} domain The domain to build the api client options based on. - * @returns {Promise} + * @returns {ApiClientOptions} */ - static async buildFromDomain(domain) { + static buildFromDomain(domain) { return new ApiClientOptions() .setBaseUrl(domain); } diff --git a/src/all/background_page/service/account/buildApiClientOptionsService.test.js b/src/all/background_page/service/account/buildApiClientOptionsService.test.js index 09f569e9..f52ce4db 100644 --- a/src/all/background_page/service/account/buildApiClientOptionsService.test.js +++ b/src/all/background_page/service/account/buildApiClientOptionsService.test.js @@ -25,7 +25,7 @@ describe("BuildAccountApiClientOptionsService", () => { // mocked function jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: csrfToken})); // execution - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); const headers = await apiClientOptions.getHeaders(); // expectations expect(apiClientOptions.baseUrl).toStrictEqual(new URL(account.domain)); @@ -41,7 +41,7 @@ describe("BuildAccountApiClientOptionsService", () => { // mocked function jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: csrfToken})); // execution - const apiClientOptions = await BuildApiClientOptionsService.buildFromDomain(domain); + const apiClientOptions = BuildApiClientOptionsService.buildFromDomain(domain); const headers = await apiClientOptions.getHeaders(); // expectations expect(apiClientOptions.baseUrl).toStrictEqual(new URL(domain)); @@ -57,7 +57,7 @@ describe("BuildAccountApiClientOptionsService", () => { // mocked function jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: csrfToken})); // execution - const apiClientOptions = await BuildApiClientOptionsService.buildFromDomain(domain); + const apiClientOptions = BuildApiClientOptionsService.buildFromDomain(domain); const headers = await apiClientOptions.getHeaders(); // expectations expect(apiClientOptions.baseUrl).toStrictEqual(new URL(domain)); @@ -73,7 +73,7 @@ describe("BuildAccountApiClientOptionsService", () => { // mocked function jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: csrfToken})); // execution - const apiClientOptions = await BuildApiClientOptionsService.buildFromDomain(domain); + const apiClientOptions = BuildApiClientOptionsService.buildFromDomain(domain); const headers = await apiClientOptions.getHeaders(); // expectations expect(apiClientOptions.baseUrl).toStrictEqual(new URL(domain)); diff --git a/src/all/background_page/service/account/getActiveAccountService.js b/src/all/background_page/service/account/getActiveAccountService.js new file mode 100644 index 00000000..f763b34c --- /dev/null +++ b/src/all/background_page/service/account/getActiveAccountService.js @@ -0,0 +1,41 @@ +/** + * Passbolt ~ Open source password manager for teams + * Copyright (c) Passbolt SA (https://www.passbolt.com) + * + * Licensed under GNU Affero General Public License version 3 of the or any later version. + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Passbolt SA (https://www.passbolt.com) + * @license https://opensource.org/licenses/AGPL-3.0 AGPL License + * @link https://www.passbolt.com Passbolt(tm) + * @since 4.8.2 + */ +import storage from "../../sdk/storage"; +import {Config} from "../../model/config"; +import GetLegacyAccountService from "./getLegacyAccountService"; + +const ACTIVE_ACCOUNT_KEY = "active-account"; + +export class GetActiveAccountService { + /** + * Get the active account associated with this extension. + * @param {Object} options The option to add more data in the account + * @return {Promise} + * @throw {Error} if no account yet associated with this extension. + */ + get(options = {}) { + return navigator.locks.request(ACTIVE_ACCOUNT_KEY, async() => { + // Check if the storage have some data + if (Object.keys(storage._data).length === 0) { + // Fix the initialization of the storage after an update + await storage.init(); + // Initialization of the config to get the user information + Config.init(); + } + return await GetLegacyAccountService.get(options); + }); + } +} + +export default new GetActiveAccountService(); diff --git a/src/all/background_page/service/account/getActiveAccountService.test.js b/src/all/background_page/service/account/getActiveAccountService.test.js new file mode 100644 index 00000000..55af5d3a --- /dev/null +++ b/src/all/background_page/service/account/getActiveAccountService.test.js @@ -0,0 +1,53 @@ +/** + * Passbolt ~ Open source password manager for teams + * Copyright (c) Passbolt SA (https://www.passbolt.com) + * + * Licensed under GNU Affero General Public License version 3 of the or any later version. + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Passbolt SA (https://www.passbolt.com) + * @license https://opensource.org/licenses/AGPL-3.0 AGPL License + * @link https://www.passbolt.com Passbolt(tm) + * @since 4.8.2 + */ +import {GetActiveAccountService} from "./getActiveAccountService"; +import GetLegacyAccountService from "./getLegacyAccountService"; +import MockExtension from "../../../../../test/mocks/mockExtension"; +import UserModel from "../../model/user/userModel"; + +describe("GetActiveAccountService", () => { + beforeEach(async() => { + jest.clearAllMocks(); + await MockExtension.withConfiguredAccount(); + }); + + it("GetActiveAccountService:get", async() => { + expect.assertions(1); + // data + const getActiveAccountService = new GetActiveAccountService(); + // spy function + jest.spyOn(GetLegacyAccountService, "get"); + // execution + await getActiveAccountService.get(); + // expectations + expect(GetLegacyAccountService.get).toHaveBeenCalledTimes(1); + }); + + it("GetActiveAccountService:get should call GetLegacyAccountService each time", async() => { + expect.assertions(3); + // data + const getActiveAccountService = new GetActiveAccountService(); + // spy function + jest.spyOn(UserModel.prototype, "findOne").mockImplementation(() => ({role: {name: "admin"}})); + jest.spyOn(GetLegacyAccountService, "get"); + // execution + const account = await getActiveAccountService.get({role: true}); + const account2 = await getActiveAccountService.get({role: true}); + const account3 = await getActiveAccountService.get(); + // expectations + expect(GetLegacyAccountService.get).toHaveBeenCalledTimes(3); + expect(account).toStrictEqual(account2); + expect(account3.roleName).toBeNull(); + }); +}); diff --git a/src/all/background_page/service/account/getLegacyAccountService.js b/src/all/background_page/service/account/getLegacyAccountService.js index bf6b0254..bc72b10d 100644 --- a/src/all/background_page/service/account/getLegacyAccountService.js +++ b/src/all/background_page/service/account/getLegacyAccountService.js @@ -28,7 +28,7 @@ class GetLegacyAccountService { */ static async get(option = {}) { const keyring = new Keyring(); - const user = await User.getInstance().get(); + const user = User.getInstance().get(); const serverPublicKeyInfo = keyring.findPublic(Uuid.get(user.settings.domain)); const userPublicKeyInfo = keyring.findPublic(user.id); const userPrivateKeyInfo = keyring.findPrivate(); @@ -37,7 +37,7 @@ class GetLegacyAccountService { let userEntity; if (option?.role) { // Load the application settings, necessary to validate the account username. - const apiClientOptions = await BuildApiClientOptionsService.buildFromDomain(user.settings.domain); + const apiClientOptions = BuildApiClientOptionsService.buildFromDomain(user.settings.domain); userEntity = await (new UserModel(apiClientOptions)).findOne(user.id, {role: true}); } diff --git a/src/all/background_page/service/api/passwordExpiry/passwordExpiryResourceService.test.js b/src/all/background_page/service/api/passwordExpiry/passwordExpiryResourceService.test.js index 597c4e0f..757ba7d3 100644 --- a/src/all/background_page/service/api/passwordExpiry/passwordExpiryResourceService.test.js +++ b/src/all/background_page/service/api/passwordExpiry/passwordExpiryResourceService.test.js @@ -32,7 +32,7 @@ describe("PasswordExpiry service", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); const account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); describe('::update', () => { diff --git a/src/all/background_page/service/api/passwordExpiry/passwordExpirySettingsService.test.js b/src/all/background_page/service/api/passwordExpiry/passwordExpirySettingsService.test.js index acf1752e..dff9d495 100644 --- a/src/all/background_page/service/api/passwordExpiry/passwordExpirySettingsService.test.js +++ b/src/all/background_page/service/api/passwordExpiry/passwordExpirySettingsService.test.js @@ -31,7 +31,7 @@ describe("PasswordExpiry service", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); const account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); describe('::find', () => { diff --git a/src/all/background_page/service/api/passwordPolicies/passwordPoliciesService.test.js b/src/all/background_page/service/api/passwordPolicies/passwordPoliciesService.test.js index f44ac06e..068caf47 100644 --- a/src/all/background_page/service/api/passwordPolicies/passwordPoliciesService.test.js +++ b/src/all/background_page/service/api/passwordPolicies/passwordPoliciesService.test.js @@ -30,7 +30,7 @@ describe("PasswordPoliciesService", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); const account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); describe("::find", () => { diff --git a/src/all/background_page/service/api/userPassphrasePolicies/userPassphrasePoliciesService.test.js b/src/all/background_page/service/api/userPassphrasePolicies/userPassphrasePoliciesService.test.js index 1a1f1702..8b32fd5e 100644 --- a/src/all/background_page/service/api/userPassphrasePolicies/userPassphrasePoliciesService.test.js +++ b/src/all/background_page/service/api/userPassphrasePolicies/userPassphrasePoliciesService.test.js @@ -30,7 +30,7 @@ describe("UserPassphrasePolicies service", () => { jest.spyOn(browser.cookies, "get").mockImplementationOnce(() => ({value: "csrf-token"})); const account = new AccountEntity(defaultAccountDto()); - apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); }); describe('::find', () => { diff --git a/src/all/background_page/service/auth/checkAuthStatusService.js b/src/all/background_page/service/auth/checkAuthStatusService.js index d75daef9..104f6b67 100644 --- a/src/all/background_page/service/auth/checkAuthStatusService.js +++ b/src/all/background_page/service/auth/checkAuthStatusService.js @@ -21,7 +21,7 @@ class CheckAuthStatusService { * Returns the authentication status of the current user. * It first interrogates the local storage and if necessary the API afterward. * @param {boolean} [flushCache] should the cache be flushed before or not. - * @return {Promise<{isAuthenticated: {bool}, isMfaRequired: {bool}}>} + * @return {Promise<{isAuthenticated: {boolean}, isMfaRequired: {boolean}}>} * @throws {Error} if something wrong happened on the API */ async checkAuthStatus(flushCache = false) { diff --git a/src/all/background_page/service/auth/startLoopAuthSessionCheckService.js b/src/all/background_page/service/auth/startLoopAuthSessionCheckService.js index 0b87b263..ac6cfd20 100644 --- a/src/all/background_page/service/auth/startLoopAuthSessionCheckService.js +++ b/src/all/background_page/service/auth/startLoopAuthSessionCheckService.js @@ -50,7 +50,6 @@ class StartLoopAuthSessionCheckService { if (alarm.name !== StartLoopAuthSessionCheckService.ALARM_NAME) { return; } - const checkAuthService = new CheckAuthStatusService(); const authStatus = await checkAuthService.checkAuthStatus(true); if (!authStatus.isAuthenticated) { diff --git a/src/all/background_page/service/authenticationStatusService.js b/src/all/background_page/service/authenticationStatusService.js index 71d3a852..4fce96ec 100644 --- a/src/all/background_page/service/authenticationStatusService.js +++ b/src/all/background_page/service/authenticationStatusService.js @@ -11,12 +11,12 @@ * @link https://www.passbolt.com Passbolt(tm) * @since 2.11.0 */ -import User from "../model/user"; import MfaAuthenticationRequiredError from "../error/mfaAuthenticationRequiredError"; import NotFoundError from "../error/notFoundError"; import {ApiClient} from "passbolt-styleguide/src/shared/lib/apiClient/apiClient"; -import {ApiClientOptions} from "passbolt-styleguide/src/shared/lib/apiClient/apiClientOptions"; import PassboltBadResponseError from "../error/passboltBadResponseError"; +import GetActiveAccountService from "./account/getActiveAccountService"; +import BuildApiClientOptionsService from "./account/buildApiClientOptionsService"; const AUTH_RESOURCE_NAME = '/auth'; @@ -26,7 +26,7 @@ class AuthenticationStatusService { * @returns {Promise} */ static async isAuthenticated() { - const apiClient = new ApiClient(this.apiClientOptions); + const apiClient = new ApiClient(await this.getApiClientOptions()); const url = apiClient.buildUrl(`${apiClient.baseUrl.toString()}/is-authenticated`, null); const fetchOptions = { @@ -68,11 +68,9 @@ class AuthenticationStatusService { * @returns {ApiClientOptions} * @private */ - static get apiClientOptions() { - const domain = User.getInstance()?.settings?.getDomain(); - - return new ApiClientOptions() - .setBaseUrl(domain) + static async getApiClientOptions() { + const account = await GetActiveAccountService.get(); + return BuildApiClientOptionsService.buildFromAccount(account) .setResourceName(AUTH_RESOURCE_NAME); } } diff --git a/src/all/background_page/service/authenticationStatusService.test.js b/src/all/background_page/service/authenticationStatusService.test.js index 570b3fac..797b2337 100644 --- a/src/all/background_page/service/authenticationStatusService.test.js +++ b/src/all/background_page/service/authenticationStatusService.test.js @@ -22,9 +22,9 @@ beforeAll(() => { enableFetchMocks(); }); -beforeEach(() => { +beforeEach(async() => { jest.clearAllMocks(); - MockExtension.withConfiguredAccount(); + await MockExtension.withConfiguredAccount(); }); describe("AuthenticationStatusService::isAuthenticated", () => { diff --git a/src/all/background_page/service/passwordExpirySettings/passwordExpirySettingsGetOrFindService.test.js b/src/all/background_page/service/passwordExpirySettings/passwordExpirySettingsGetOrFindService.test.js index 59091066..cae0f64b 100644 --- a/src/all/background_page/service/passwordExpirySettings/passwordExpirySettingsGetOrFindService.test.js +++ b/src/all/background_page/service/passwordExpirySettings/passwordExpirySettingsGetOrFindService.test.js @@ -31,7 +31,7 @@ describe("PasswordExpirySettingsGetOrFindService", () => { expect.assertions(1); // data const account = new AccountEntity(defaultAccountDto()); - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(account); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); const passwordExpirySettingsService = new PasswordExpirySettingsGetOrFindService(account, apiClientOptions); // mocked functions jest.spyOn(passwordExpirySettingsService.passwordExpirySettingsModel, "getOrFindOrDefault").mockImplementationOnce(jest.fn); diff --git a/src/all/background_page/service/session_storage/keepSessionAliveService.js b/src/all/background_page/service/session_storage/keepSessionAliveService.js index 221fe275..ebd44b44 100644 --- a/src/all/background_page/service/session_storage/keepSessionAliveService.js +++ b/src/all/background_page/service/session_storage/keepSessionAliveService.js @@ -11,9 +11,10 @@ * @link https://www.passbolt.com Passbolt(tm) * @since 4.7.0 */ -import User from "../../model/user"; import UserService from "../api/user/userService"; import PassphraseStorageService from "./passphraseStorageService"; +import GetActiveAccountService from "../account/getActiveAccountService"; +import BuildApiClientOptionsService from "../account/buildApiClientOptionsService"; const SESSION_KEEP_ALIVE_ALARM = "SessionKeepAlive"; const SESSION_CHECK_INTERNAL = 15; @@ -59,13 +60,12 @@ class KeepSessionAliveService { if (alarm.name !== KeepSessionAliveService.ALARM_NAME) { return; } - // The session is kept alive only for the duration users wanted their passphrase to be remembered. if (await PassphraseStorageService.get() === null) { return; } - - const apiClientOptions = await User.getInstance().getApiClientOptions(); + const account = await GetActiveAccountService.get(); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(account); const userService = new UserService(apiClientOptions); userService.keepSessionAlive(); } diff --git a/src/all/background_page/service/toolbar/toolbarService.js b/src/all/background_page/service/toolbar/toolbarService.js index 4c1a0a21..1cb046bf 100644 --- a/src/all/background_page/service/toolbar/toolbarService.js +++ b/src/all/background_page/service/toolbar/toolbarService.js @@ -61,7 +61,7 @@ class ToolbarService { */ async handleUserLoggedIn() { this.account = await GetLegacyAccountService.get(); - const apiClientOptions = await BuildApiClientOptionsService.buildFromAccount(this.account); + const apiClientOptions = BuildApiClientOptionsService.buildFromAccount(this.account); this.resourceModel = new ResourceModel(apiClientOptions, this.account); BrowserExtensionIconService.activate(); diff --git a/src/chrome-mv3/manifest.json b/src/chrome-mv3/manifest.json index eac3eb9b..61d8006b 100644 --- a/src/chrome-mv3/manifest.json +++ b/src/chrome-mv3/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 3, "name": "__MSG_appName__", "short_name": "passbolt", - "version": "4.8.1", + "version": "4.8.2", "description": "__MSG_appDescription__", "default_locale": "en", "externally_connectable": { diff --git a/src/chrome/manifest.json b/src/chrome/manifest.json index 1c2976ae..1ae62da8 100644 --- a/src/chrome/manifest.json +++ b/src/chrome/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_appName__", "short_name": "passbolt", - "version": "4.8.1", + "version": "4.8.2", "description": "__MSG_appDescription__", "default_locale": "en", "externally_connectable": {}, diff --git a/src/firefox/manifest.json b/src/firefox/manifest.json index d68ce042..bb9bbfc6 100644 --- a/src/firefox/manifest.json +++ b/src/firefox/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_appName__", "short_name": "passbolt", - "version": "4.8.1", + "version": "4.8.2", "description": "__MSG_appDescription__", "default_locale": "en", "browser_specific_settings": { diff --git a/src/safari/manifest.json b/src/safari/manifest.json index 241058a0..2094db4f 100644 --- a/src/safari/manifest.json +++ b/src/safari/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 3, "name": "__MSG_appName__", "short_name": "passbolt", - "version": "4.8.1", + "version": "4.8.2", "description": "__MSG_appDescription__", "default_locale": "en", "externally_connectable": {}, diff --git a/test/mocks/mockExtension.js b/test/mocks/mockExtension.js index 747bd1d9..2c26f042 100644 --- a/test/mocks/mockExtension.js +++ b/test/mocks/mockExtension.js @@ -22,24 +22,22 @@ import {Uuid} from "../../src/all/background_page/utils/uuid"; class MockExtension { /** * Mock the extension with a configured account. Ada by default. - * @returns {Promise} + * @returns {void} */ static async withConfiguredAccount(keyData = pgpKeys.ada) { const user = this.withMissingPrivateKeyAccount(keyData); - // Mock user private key const keyring = new Keyring(); await keyring.importPrivate(keyData.private); await keyring.importPublic(keyData.public, keyData.userId); await keyring.importPublic(pgpKeys.server.public, Uuid.get(user.settings.getDomain())); - return user; } /** * Mock the extension with a partially configured account. Ada by default without the private key set. * - * @returns {Promise} + * @returns {User} */ static withMissingPrivateKeyAccount(keyData = pgpKeys.ada) { const user = User.getInstance();