tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 5f3af8f6b058653ba4d2fadf908e4e96fa1c665a
parent 38b532434e1eb733fae221bdacfeb3f3e5a07d3e
Author: Andrea Marchesini <amarchesini@mozilla.com>
Date:   Mon, 10 Nov 2025 14:06:19 +0000

Bug 1998795 - IPProtection: implement the ACTIVATING state - part 2 - Remove ERROR state, r=ip-protection-reviewers,sstreich

Differential Revision: https://phabricator.services.mozilla.com/D271667

Diffstat:
Mbrowser/components/ipprotection/IPPAutoStart.sys.mjs | 2--
Mbrowser/components/ipprotection/IPPProxyManager.sys.mjs | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mbrowser/components/ipprotection/IPProtection.sys.mjs | 31++++++++++++++++++++++---------
Mbrowser/components/ipprotection/IPProtectionPanel.sys.mjs | 16++++++++++++----
Mbrowser/components/ipprotection/IPProtectionService.sys.mjs | 68++------------------------------------------------------------------
Mbrowser/components/ipprotection/docs/StateMachine.rst | 1-
Mbrowser/components/ipprotection/tests/browser/browser_IPProtectionService.js | 11+++++------
Mbrowser/components/ipprotection/tests/browser/head.js | 2+-
Mbrowser/components/ipprotection/tests/xpcshell/head.js | 38++++++++++++++++++++++++++++++++++++++
Mbrowser/components/ipprotection/tests/xpcshell/test_IPPStartupCache.js | 4----
Mbrowser/components/ipprotection/tests/xpcshell/test_IPProtectionPanel.js | 6------
Mbrowser/components/ipprotection/tests/xpcshell/test_IPProtectionService.js | 38--------------------------------------
Mbrowser/components/ipprotection/tests/xpcshell/test_IPProtectionStates.js | 44--------------------------------------------
Mbrowser/components/ipprotection/tests/xpcshell/test_IPProxyManager.js | 66++++++++++++++++++++++++++++++++++++++++++++++++++----------------
14 files changed, 239 insertions(+), 199 deletions(-)

diff --git a/browser/components/ipprotection/IPPAutoStart.sys.mjs b/browser/components/ipprotection/IPPAutoStart.sys.mjs @@ -79,7 +79,6 @@ class IPPAutoStartSingleton { case lazy.IPProtectionStates.UNINITIALIZED: case lazy.IPProtectionStates.UNAVAILABLE: case lazy.IPProtectionStates.UNAUTHENTICATED: - case lazy.IPProtectionStates.ERROR: this.#shouldStartWhenReady = true; break; @@ -143,7 +142,6 @@ class IPPEarlyStartupFilter { switch (lazy.IPProtectionService.state) { case lazy.IPProtectionStates.UNAVAILABLE: case lazy.IPProtectionStates.UNAUTHENTICATED: - case lazy.IPProtectionStates.ERROR: // These states block the auto-start at startup. this.#cancelChannelFilter(); this.uninit(); diff --git a/browser/components/ipprotection/IPPProxyManager.sys.mjs b/browser/components/ipprotection/IPPProxyManager.sys.mjs @@ -5,6 +5,8 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { + IPPEnrollAndEntitleManager: + "resource:///modules/ipprotection/IPPEnrollAndEntitleManager.sys.mjs", IPPChannelFilter: "resource:///modules/ipprotection/IPPChannelFilter.sys.mjs", IPProtectionUsage: "resource:///modules/ipprotection/IPProtectionUsage.sys.mjs", @@ -18,7 +20,10 @@ ChromeUtils.defineESModuleGetters(lazy, { "resource:///modules/ipprotection/IPProtectionService.sys.mjs", }); +import { ERRORS } from "chrome://browser/content/ipprotection/ipprotection-constants.mjs"; + const LOG_PREF = "browser.ipProtection.log"; +const MAX_ERROR_HISTORY = 50; ChromeUtils.defineLazyGetter(lazy, "logConsole", function () { return console.createInstance({ @@ -28,9 +33,29 @@ ChromeUtils.defineLazyGetter(lazy, "logConsole", function () { }); /** + * @typedef {object} IPPProxyStates + * List of the possible states of the IPPProxyManager. + * @property {string} READY + * The proxy is ready to be activated. + * @property {string} ERROR + * Error + * + * TODO: eventually this will be a proper state machine. + * + * Note: If you update this list of states, make sure to update the + * corresponding documentation in the `docs` folder as well. + */ +export const IPPProxyStates = Object.freeze({ + READY: "ready", + ERROR: "error", +}); + +/** * Manages the proxy connection for the IPProtectionService. */ -class IPPProxyManagerSingleton { +class IPPProxyManagerSingleton extends EventTarget { + #state = IPPProxyStates.READY; + #pass = null; /**@type {import("./IPPChannelFilter.sys.mjs").IPPChannelFilter | null} */ #connection = null; @@ -40,7 +65,12 @@ class IPPProxyManagerSingleton { #rotateProxyPassPromise = null; #activatedAt = false; + errors = []; + constructor() { + super(); + + this.setErrorState = this.#setErrorState.bind(this); this.handleProxyErrorEvent = this.#handleProxyErrorEvent.bind(this); this.handleEvent = this.#handleEvent.bind(this); } @@ -60,6 +90,8 @@ class IPPProxyManagerSingleton { this.handleEvent ); + this.errors = []; + this.reset(); this.#connection = null; this.usageObserver.stop(); @@ -118,15 +150,50 @@ class IPPProxyManagerSingleton { } } + get state() { + return this.#state; + } + /** * Starts the proxy connection: * - Gets a new proxy pass if needed. * - Find the server to use. * - Adds usage and network-error observers. * - * @returns {Promise<boolean|Error>} + * @returns {Promise<boolean>} */ async start() { + await lazy.IPProtectionServerlist.maybeFetchList(); + + const enrollAndEntitleData = + await lazy.IPPEnrollAndEntitleManager.maybeEnrollAndEntitle(); + if (!enrollAndEntitleData || !enrollAndEntitleData.isEnrolledAndEntitled) { + this.#setErrorState(enrollAndEntitleData.error || ERRORS.GENERIC); + return false; + } + + if (lazy.IPProtectionService.state !== lazy.IPProtectionStates.READY) { + this.#setErrorState(ERRORS.GENERIC); + return false; + } + + // Retry getting state if the previous attempt failed. + if (this.#state === IPPProxyStates.ERROR) { + this.updateState(); + } + + this.errors = []; + + try { + const started = await this.#startInternal(); + return started; + } catch (error) { + this.#setErrorState(ERRORS.GENERIC, error); + return false; + } + } + + async #startInternal() { this.createChannelFilter(); // If the current proxy pass is valid, no need to re-authenticate. @@ -275,6 +342,46 @@ class IPPProxyManagerSingleton { } return null; } + + updateState() { + // TODO: something better here. + this.#setState(IPPProxyStates.READY); + } + + /** + * Helper to dispatch error messages. + * + * @param {string} error - the error message to send. + * @param {string} [errorContext] - the error message to log. + */ + #setErrorState(error, errorContext) { + this.errors.push(error); + + if (this.errors.length > MAX_ERROR_HISTORY) { + this.errors.splice(0, this.errors.length - MAX_ERROR_HISTORY); + } + + this.#setState(IPPProxyStates.ERROR); + lazy.logConsole.error(errorContext || error); + } + + #setState(state) { + if (state === this.#state) { + return; + } + + this.#state = state; + + this.dispatchEvent( + new CustomEvent("IPPProxyManager:StateChanged", { + bubbles: true, + composed: true, + detail: { + state, + }, + }) + ); + } } const IPPProxyManager = new IPPProxyManagerSingleton(); diff --git a/browser/components/ipprotection/IPProtection.sys.mjs b/browser/components/ipprotection/IPProtection.sys.mjs @@ -17,6 +17,8 @@ ChromeUtils.defineESModuleGetters(lazy, { "resource:///modules/ipprotection/IPProtectionService.sys.mjs", IPProtectionStates: "resource:///modules/ipprotection/IPProtectionService.sys.mjs", + IPPProxyManager: "resource:///modules/ipprotection/IPPProxyManager.sys.mjs", + IPPProxyStates: "resource:///modules/ipprotection/IPPProxyManager.sys.mjs", requestIdleCallback: "resource://gre/modules/Timer.sys.mjs", cancelIdleCallback: "resource://gre/modules/Timer.sys.mjs", }); @@ -272,11 +274,11 @@ class IPProtectionWidget { * @param {XULElement} toolbaritem - the widget toolbaritem. */ #onCreated(toolbaritem) { - let state = lazy.IPProtectionService.state; - let isActive = state === lazy.IPProtectionStates.ACTIVE; + let isActive = + lazy.IPProtectionService.state === lazy.IPProtectionStates.ACTIVE; let isError = - state === lazy.IPProtectionStates.ERROR && - lazy.IPProtectionService.errors.includes(ERRORS.GENERIC); + lazy.IPPProxyManager.state === lazy.IPPProxyStates.ERROR && + lazy.IPPProxyManager.errors.includes(ERRORS.GENERIC); this.updateIconStatus(toolbaritem, { isActive, isError, @@ -290,9 +292,17 @@ class IPProtectionWidget { "IPProtectionService:StateChanged", this.handleEvent ); + lazy.IPPProxyManager.addEventListener( + "IPPProxyManager:StateChanged", + this.handleEvent + ); } #onDestroyed() { + lazy.IPPProxyManager.removeEventListener( + "IPPProxyManager:StateChanged", + this.handleEvent + ); lazy.IPProtectionService.removeEventListener( "IPProtectionService:StateChanged", this.handleEvent @@ -324,13 +334,16 @@ class IPProtectionWidget { } #handleEvent(event) { - if (event.type == "IPProtectionService:StateChanged") { - let state = lazy.IPProtectionService.state; + if ( + event.type == "IPProtectionService:StateChanged" || + event.type == "IPPProxyManager:StateChanged" + ) { let status = { - isActive: state === lazy.IPProtectionStates.ACTIVE, + isActive: + lazy.IPProtectionService.state === lazy.IPProtectionStates.ACTIVE, isError: - state === lazy.IPProtectionStates.ERROR && - lazy.IPProtectionService.errors.includes(ERRORS.GENERIC), + lazy.IPPProxyManager.state === lazy.IPPProxyStates.ERROR && + lazy.IPPProxyManager.errors.includes(ERRORS.GENERIC), }; let widget = lazy.CustomizableUI.getWidget(IPProtectionWidget.WIDGET_ID); diff --git a/browser/components/ipprotection/IPProtectionPanel.sys.mjs b/browser/components/ipprotection/IPProtectionPanel.sys.mjs @@ -10,10 +10,9 @@ ChromeUtils.defineESModuleGetters(lazy, { IPPEnrollAndEntitleManager: "resource:///modules/ipprotection/IPPEnrollAndEntitleManager.sys.mjs", IPPProxyManager: "resource:///modules/ipprotection/IPPProxyManager.sys.mjs", + IPPProxyStates: "resource:///modules/ipprotection/IPPProxyManager.sys.mjs", IPProtectionService: "resource:///modules/ipprotection/IPProtectionService.sys.mjs", - IPProtectionStates: - "resource:///modules/ipprotection/IPProtectionService.sys.mjs", IPProtection: "resource:///modules/ipprotection/IPProtection.sys.mjs", IPPSignInWatcher: "resource:///modules/ipprotection/IPPSignInWatcher.sys.mjs", }); @@ -336,6 +335,10 @@ export class IPProtectionPanel { "IPProtectionService:StateChanged", this.handleEvent ); + lazy.IPPProxyManager.addEventListener( + "IPPProxyManager:StateChanged", + this.handleEvent + ); lazy.IPPEnrollAndEntitleManager.addEventListener( "IPPEnrollAndEntitleManager:StateChanged", this.handleEvent @@ -347,6 +350,10 @@ export class IPProtectionPanel { "IPPEnrollAndEntitleManager:StateChanged", this.handleEvent ); + lazy.IPPProxyManager.removeEventListener( + "IPPProxyManager:StateChanged", + this.handleEvent + ); lazy.IPProtectionService.removeEventListener( "IPProtectionService:StateChanged", this.handleEvent @@ -373,13 +380,14 @@ export class IPProtectionPanel { } else if (event.type == "IPProtection:SignIn") { this.startLoginFlow(); } else if ( + event.type == "IPPProxyManager:StateChanged" || event.type == "IPProtectionService:StateChanged" || event.type === "IPPEnrollAndEntitleManager:StateChanged" ) { let { activatedAt: protectionEnabledSince } = lazy.IPPProxyManager; let hasError = - lazy.IPProtectionService.state === lazy.IPProtectionStates.ERROR && - lazy.IPProtectionService.errors.includes(ERRORS.GENERIC); + lazy.IPPProxyManager.state === lazy.IPPProxyStates.ERROR && + lazy.IPPProxyManager.errors.includes(ERRORS.GENERIC); this.setState({ isSignedOut: !lazy.IPPSignInWatcher.isSignedIn, diff --git a/browser/components/ipprotection/IPProtectionService.sys.mjs b/browser/components/ipprotection/IPProtectionService.sys.mjs @@ -13,29 +13,15 @@ ChromeUtils.defineESModuleGetters(lazy, { IPPHelpers: "resource:///modules/ipprotection/IPProtectionHelpers.sys.mjs", IPPNimbusHelper: "resource:///modules/ipprotection/IPPNimbusHelper.sys.mjs", IPPProxyManager: "resource:///modules/ipprotection/IPPProxyManager.sys.mjs", - IPProtectionServerlist: - "resource:///modules/ipprotection/IPProtectionServerlist.sys.mjs", IPPSignInWatcher: "resource:///modules/ipprotection/IPPSignInWatcher.sys.mjs", IPPStartupCache: "resource:///modules/ipprotection/IPPStartupCache.sys.mjs", SpecialMessageActions: "resource://messaging-system/lib/SpecialMessageActions.sys.mjs", }); -import { - SIGNIN_DATA, - ERRORS, -} from "chrome://browser/content/ipprotection/ipprotection-constants.mjs"; +import { SIGNIN_DATA } from "chrome://browser/content/ipprotection/ipprotection-constants.mjs"; const ENABLED_PREF = "browser.ipProtection.enabled"; -const LOG_PREF = "browser.ipProtection.log"; -const MAX_ERROR_HISTORY = 50; - -ChromeUtils.defineLazyGetter(lazy, "logConsole", function () { - return console.createInstance({ - prefix: "IPProtectionService", - maxLogLevel: Services.prefs.getBoolPref(LOG_PREF, false) ? "Debug" : "Warn", - }); -}); /** * @typedef {object} IPProtectionStates @@ -50,8 +36,6 @@ ChromeUtils.defineLazyGetter(lazy, "logConsole", function () { * Ready to be activated. * @property {string} ACTIVE * Proxy is active. - * @property {string} ERROR - * Error * * Note: If you update this list of states, make sure to update the * corresponding documentation in the `docs` folder as well. @@ -62,7 +46,6 @@ export const IPProtectionStates = Object.freeze({ UNAUTHENTICATED: "unauthenticated", READY: "ready", ACTIVE: "active", - ERROR: "error", }); /** @@ -75,8 +58,6 @@ export const IPProtectionStates = Object.freeze({ class IPProtectionServiceSingleton extends EventTarget { #state = IPProtectionStates.UNINITIALIZED; - errors = []; - guardian = null; #helpers = null; @@ -98,7 +79,6 @@ class IPProtectionServiceSingleton extends EventTarget { this.updateState = this.#updateState.bind(this); this.setState = this.#setState.bind(this); - this.setErrorState = this.#setErrorState.bind(this); this.#helpers = lazy.IPPHelpers; } @@ -148,8 +128,6 @@ class IPProtectionServiceSingleton extends EventTarget { this.stop(false); } - this.errors = []; - this.#helpers.forEach(helper => helper.uninit()); this.#setState(IPProtectionStates.UNINITIALIZED); @@ -168,32 +146,7 @@ class IPProtectionServiceSingleton extends EventTarget { * True if started by user action, false if system action */ async start(userAction = true) { - await lazy.IPProtectionServerlist.maybeFetchList(); - - const enrollAndEntitleData = - await lazy.IPPEnrollAndEntitleManager.maybeEnrollAndEntitle(); - if (!enrollAndEntitleData || !enrollAndEntitleData.isEnrolledAndEntitled) { - this.setErrorState(enrollAndEntitleData.error || ERRORS.GENERIC); - return; - } - - // Retry getting state if the previous attempt failed. - if (this.#state === IPProtectionStates.ERROR) { - this.#updateState(); - } - - if (this.#state !== IPProtectionStates.READY) { - this.#setErrorState(ERRORS.GENERIC); - return; - } - this.errors = []; - - let started; - try { - started = await lazy.IPPProxyManager.start(); - } catch (error) { - this.#setErrorState(ERRORS.GENERIC, error); - } + const started = await lazy.IPPProxyManager.start(); // Proxy failed to start but no error was given. if (!started) { @@ -335,23 +288,6 @@ class IPProtectionServiceSingleton extends EventTarget { }) ); } - - /** - * Helper to dispatch error messages. - * - * @param {string} error - the error message to send. - * @param {string} [errorContext] - the error message to log. - */ - #setErrorState(error, errorContext) { - this.errors.push(error); - - if (this.errors.length > MAX_ERROR_HISTORY) { - this.errors.splice(0, this.errors.length - MAX_ERROR_HISTORY); - } - - this.#setState(IPProtectionStates.ERROR); - lazy.logConsole.error(errorContext || error); - } } const IPProtectionService = new IPProtectionServiceSingleton(); diff --git a/browser/components/ipprotection/docs/StateMachine.rst b/browser/components/ipprotection/docs/StateMachine.rst @@ -14,7 +14,6 @@ The service transitions across the following states: - ``UNAUTHENTICATED``: User signed out but eligible; UI shows login. - ``READY``: Ready to activate the proxy. - ``ACTIVE``: Proxy is active. -- ``ERROR``: An error occurred (see ``IPProtectionService.errors``). High‑level transitions ---------------------- diff --git a/browser/components/ipprotection/tests/browser/browser_IPProtectionService.js b/browser/components/ipprotection/tests/browser/browser_IPProtectionService.js @@ -283,8 +283,8 @@ add_task(async function test_IPProtectionService_pass_errors() { await messageBarLoadedPromise; Assert.equal( - IPProtectionService.state, - IPProtectionStates.ERROR, + IPPProxyManager.state, + IPPProxyStates.ERROR, "Proxy is not active" ); @@ -309,8 +309,7 @@ add_task(async function test_IPProtectionService_pass_errors() { Assert.equal(content.state.error, "", "Should have no error"); // Reset the errors - IPProtectionService.hasError = false; - IPProtectionService.errors = []; + IPPProxyManager.errors = []; await cleanupAlpha(); cleanupService(); @@ -327,13 +326,13 @@ add_task(async function test_IPProtectionService_retry_errors() { }); let cleanupAlpha = await setupExperiment({ enabled: true, variant: "alpha" }); - IPProtectionService.updateState(); + IPPProxyManager.updateState(); let content = await openPanel(); // Mock a failure IPPEnrollAndEntitleManager.resetEntitlement(); - await IPProtectionService.setErrorState(); + IPPProxyManager.setErrorState(); let startedEventPromise = BrowserTestUtils.waitForEvent( IPProtectionService, diff --git a/browser/components/ipprotection/tests/browser/head.js b/browser/components/ipprotection/tests/browser/head.js @@ -13,7 +13,7 @@ const { IPProtectionService, IPProtectionStates } = ChromeUtils.importESModule( "resource:///modules/ipprotection/IPProtectionService.sys.mjs" ); -const { IPPProxyManager } = ChromeUtils.importESModule( +const { IPPProxyManager, IPPProxyStates } = ChromeUtils.importESModule( "resource:///modules/ipprotection/IPPProxyManager.sys.mjs" ); diff --git a/browser/components/ipprotection/tests/xpcshell/head.js b/browser/components/ipprotection/tests/xpcshell/head.js @@ -4,6 +4,12 @@ "use strict"; +const { IPProtectionService, IPProtectionStates } = ChromeUtils.importESModule( + "resource:///modules/ipprotection/IPProtectionService.sys.mjs" +); +const { IPPSignInWatcher } = ChromeUtils.importESModule( + "resource:///modules/ipprotection/IPPSignInWatcher.sys.mjs" +); const { ProxyPass } = ChromeUtils.importESModule( "resource:///modules/ipprotection/GuardianClient.sys.mjs" ); @@ -51,3 +57,35 @@ async function putServerInRemoteSettings( await client.db.importChanges({}, Date.now()); } /* exported putServerInRemoteSettings */ + +function setupStubs( + sandbox, + options = { + signedIn: true, + isLinkedToGuardian: true, + validProxyPass: true, + entitlement: { + subscribed: false, + uid: 42, + created_at: "2023-01-01T12:00:00.000Z", + }, + } +) { + sandbox.stub(IPPSignInWatcher, "isSignedIn").get(() => options.signedIn); + sandbox + .stub(IPProtectionService.guardian, "isLinkedToGuardian") + .resolves(options.isLinkedToGuardian); + sandbox.stub(IPProtectionService.guardian, "fetchUserInfo").resolves({ + status: 200, + error: null, + entitlement: options.entitlement, + }); + sandbox.stub(IPProtectionService.guardian, "fetchProxyPass").resolves({ + status: 200, + error: undefined, + pass: { + isValid: () => options.validProxyPass, + asBearerToken: () => "Bearer helloworld", + }, + }); +} diff --git a/browser/components/ipprotection/tests/xpcshell/test_IPPStartupCache.js b/browser/components/ipprotection/tests/xpcshell/test_IPPStartupCache.js @@ -8,10 +8,6 @@ const { IPPStartupCacheSingleton } = ChromeUtils.importESModule( "resource:///modules/ipprotection/IPPStartupCache.sys.mjs" ); -const { IPProtectionStates } = ChromeUtils.importESModule( - "resource:///modules/ipprotection/IPProtectionService.sys.mjs" -); - /** * Test the disabled cache */ diff --git a/browser/components/ipprotection/tests/xpcshell/test_IPProtectionPanel.js b/browser/components/ipprotection/tests/xpcshell/test_IPProtectionPanel.js @@ -6,12 +6,6 @@ https://creativecommons.org/publicdomain/zero/1.0/ */ const { IPProtectionPanel } = ChromeUtils.importESModule( "resource:///modules/ipprotection/IPProtectionPanel.sys.mjs" ); -const { IPProtectionService, IPProtectionStates } = ChromeUtils.importESModule( - "resource:///modules/ipprotection/IPProtectionService.sys.mjs" -); -const { IPPSignInWatcher } = ChromeUtils.importESModule( - "resource:///modules/ipprotection/IPPSignInWatcher.sys.mjs" -); const { IPPEnrollAndEntitleManager } = ChromeUtils.importESModule( "resource:///modules/ipprotection/IPPEnrollAndEntitleManager.sys.mjs" ); diff --git a/browser/components/ipprotection/tests/xpcshell/test_IPProtectionService.js b/browser/components/ipprotection/tests/xpcshell/test_IPProtectionService.js @@ -12,12 +12,6 @@ const { ExtensionTestUtils } = ChromeUtils.importESModule( const { IPPProxyManager } = ChromeUtils.importESModule( "resource:///modules/ipprotection/IPPProxyManager.sys.mjs" ); -const { IPProtectionService, IPProtectionStates } = ChromeUtils.importESModule( - "resource:///modules/ipprotection/IPProtectionService.sys.mjs" -); -const { IPPSignInWatcher } = ChromeUtils.importESModule( - "resource:///modules/ipprotection/IPPSignInWatcher.sys.mjs" -); const { IPPEnrollAndEntitleManager } = ChromeUtils.importESModule( "resource:///modules/ipprotection/IPPEnrollAndEntitleManager.sys.mjs" ); @@ -34,38 +28,6 @@ AddonTestUtils.createAppInfo( ExtensionTestUtils.init(this); -function setupStubs( - sandbox, - options = { - signedIn: true, - isLinkedToGuardian: true, - validProxyPass: true, - entitlement: { - subscribed: false, - uid: 42, - created_at: "2023-01-01T12:00:00.000Z", - }, - } -) { - sandbox.stub(IPPSignInWatcher, "isSignedIn").get(() => options.signedIn); - sandbox - .stub(IPProtectionService.guardian, "isLinkedToGuardian") - .resolves(options.isLinkedToGuardian); - sandbox.stub(IPProtectionService.guardian, "fetchUserInfo").resolves({ - status: 200, - error: null, - entitlement: options.entitlement, - }); - sandbox.stub(IPProtectionService.guardian, "fetchProxyPass").resolves({ - status: 200, - error: undefined, - pass: { - isValid: () => options.validProxyPass, - asBearerToken: () => "Bearer helloworld", - }, - }); -} - add_setup(async function () { await putServerInRemoteSettings(); IPProtectionService.uninit(); diff --git a/browser/components/ipprotection/tests/xpcshell/test_IPProtectionStates.js b/browser/components/ipprotection/tests/xpcshell/test_IPProtectionStates.js @@ -3,15 +3,9 @@ https://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -const { IPProtectionService, IPProtectionStates } = ChromeUtils.importESModule( - "resource:///modules/ipprotection/IPProtectionService.sys.mjs" -); const { IPPNimbusHelper } = ChromeUtils.importESModule( "resource:///modules/ipprotection/IPPNimbusHelper.sys.mjs" ); -const { IPPSignInWatcher } = ChromeUtils.importESModule( - "resource:///modules/ipprotection/IPPSignInWatcher.sys.mjs" -); const { IPPEnrollAndEntitleManager } = ChromeUtils.importESModule( "resource:///modules/ipprotection/IPPEnrollAndEntitleManager.sys.mjs" ); @@ -265,41 +259,3 @@ add_task(async function test_IPProtectionStates_active() { IPProtectionService.uninit(); sandbox.restore(); }); - -/** - * Tests the error state. - */ -add_task(async function test_IPProtectionStates_error() { - let sandbox = sinon.createSandbox(); - sandbox.stub(IPPSignInWatcher, "isSignedIn").get(() => true); - sandbox - .stub(IPProtectionService.guardian, "isLinkedToGuardian") - .resolves(true); - sandbox.stub(IPProtectionService.guardian, "fetchUserInfo").resolves({ - status: 200, - error: undefined, - entitlement: { uid: 42 }, - }); - sandbox.stub(IPProtectionService.guardian, "fetchProxyPass").resolves({ - status: 403, - }); - - await IPProtectionService.init(); - - Assert.equal( - IPProtectionService.state, - IPProtectionStates.READY, - "IP Protection service should be ready" - ); - - await IPProtectionService.start(false); - - Assert.equal( - IPProtectionService.state, - IPProtectionStates.ERROR, - "IP Protection service should be active" - ); - - IPProtectionService.uninit(); - sandbox.restore(); -}); diff --git a/browser/components/ipprotection/tests/xpcshell/test_IPProxyManager.js b/browser/components/ipprotection/tests/xpcshell/test_IPProxyManager.js @@ -4,14 +4,11 @@ "use strict"; -const { IPPProxyManager } = ChromeUtils.importESModule( +const { IPPProxyManager, IPPProxyStates } = ChromeUtils.importESModule( "resource:///modules/ipprotection/IPPProxyManager.sys.mjs" ); -const { IPProtectionService } = ChromeUtils.importESModule( - "resource:///modules/ipprotection/IPProtectionService.sys.mjs" -); -const { IPProtectionServerlist } = ChromeUtils.importESModule( - "resource:///modules/ipprotection/IPProtectionServerlist.sys.mjs" +const { IPPEnrollAndEntitleManager } = ChromeUtils.importESModule( + "resource:///modules/ipprotection/IPPEnrollAndEntitleManager.sys.mjs" ); add_setup(async function () { @@ -23,17 +20,16 @@ add_setup(async function () { * and removes the connection after after stop. */ add_task(async function test_IPPProxyManager_start_stop_reset() { - let sandbox = sinon.createSandbox(); - sandbox.stub(IPProtectionService.guardian, "fetchProxyPass").returns({ - status: 200, - error: undefined, - pass: { - isValid: () => true, - asBearerToken: () => "Bearer hello world", - }, - }); + const sandbox = sinon.createSandbox(); + setupStubs(sandbox); - await IPProtectionServerlist.maybeFetchList(); + IPProtectionService.init(); + + await waitForEvent( + IPProtectionService, + "IPProtectionService:StateChanged", + () => IPProtectionService.state === IPProtectionStates.READY + ); await IPPProxyManager.start(); @@ -106,3 +102,41 @@ add_task(async function test_IPPProxyManager_reset() { sandbox.restore(); }); + +/** + * Tests the error state. + */ +add_task(async function test_IPPProxyStates_error() { + let sandbox = sinon.createSandbox(); + sandbox.stub(IPPSignInWatcher, "isSignedIn").get(() => true); + sandbox + .stub(IPProtectionService.guardian, "isLinkedToGuardian") + .resolves(true); + sandbox.stub(IPProtectionService.guardian, "fetchUserInfo").resolves({ + status: 200, + error: undefined, + entitlement: { uid: 42 }, + }); + sandbox + .stub(IPPEnrollAndEntitleManager, "maybeEnrollAndEntitle") + .resolves({ isEnrolledAndEntitled: false }); + + await IPProtectionService.init(); + + Assert.equal( + IPProtectionService.state, + IPProtectionStates.READY, + "IP Protection service should be ready" + ); + + await IPProtectionService.start(false); + + Assert.equal( + IPPProxyManager.state, + IPPProxyStates.ERROR, + "IP Protection service should be active" + ); + + IPProtectionService.uninit(); + sandbox.restore(); +});