/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { IPProtectionService: "resource:///modules/ipprotection/IPProtectionService.sys.mjs", IPProtectionStates: "resource:///modules/ipprotection/IPProtectionService.sys.mjs", }); const STATE_CACHE_PREF = "browser.ipProtection.stateCache"; const ENTITLEMENT_CACHE_PREF = "browser.ipProtection.entitlementCache"; /** * This class implements a cache for the IPP state machine. The cache is used * until we receive the `sessionstore-windows-restored` event */ class IPPStartupCacheSingleton { #stateFromCache = null; #startupCompleted = false; constructor() { // For XPCShell tests, the cache must be disabled. if ( Services.prefs.getBoolPref("browser.ipProtection.cacheDisabled", false) ) { this.#startupCompleted = true; return; } this.handleEvent = this.#handleEvent.bind(this); const stateFromCache = Services.prefs.getCharPref( STATE_CACHE_PREF, "unset" ); if (stateFromCache !== "unset") { this.#stateFromCache = stateFromCache; } Services.obs.addObserver(this, "sessionstore-windows-restored"); } init() { lazy.IPProtectionService.addEventListener( "IPProtectionService:StateChanged", this.handleEvent ); // The state cannot be "ACTIVE" from cache. In case we need to activate the // proxy at startup time, something else will take care of it. if (this.#stateFromCache === lazy.IPProtectionStates.ACTIVE) { this.#stateFromCache = lazy.IPProtectionStates.READY; } } async initOnStartupCompleted() {} uninit() { lazy.IPProtectionService.removeEventListener( "IPProtectionService:StateChanged", this.handleEvent ); } get isStartupCompleted() { return this.#startupCompleted; } get state() { if (this.#startupCompleted) { throw new Error("IPPStartupCache should not be used after the startup"); } if (Object.values(lazy.IPProtectionStates).includes(this.#stateFromCache)) { return this.#stateFromCache; } // This should not happen. return lazy.IPProtectionStates.UNINITIALIZED; } async observe(_subject, topic, _) { if (topic !== "sessionstore-windows-restored") { return; } // The browser is ready! Let's invalidate the cache and let's recompute the // state. Services.obs.removeObserver(this, "sessionstore-windows-restored"); this.#startupCompleted = true; this.#stateFromCache = null; await lazy.IPProtectionService.initOnStartupCompleted(); lazy.IPProtectionService.updateState(); } storeEntitlement(entitlement) { Services.prefs.setCharPref( ENTITLEMENT_CACHE_PREF, JSON.stringify(entitlement) ); } get entitlement() { try { const entitlement = Services.prefs.getCharPref( ENTITLEMENT_CACHE_PREF, "" ); return JSON.parse(entitlement); } catch (e) { return null; } } #handleEvent(_event) { const state = lazy.IPProtectionService.state; if (this.#startupCompleted) { Services.prefs.setCharPref(STATE_CACHE_PREF, state); } else { this.#stateFromCache = state; } } } const IPPStartupCache = new IPPStartupCacheSingleton(); export { IPPStartupCache, IPPStartupCacheSingleton };