tor-browser

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

IPPStartupCache.sys.mjs (3725B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 const lazy = {};
      6 
      7 ChromeUtils.defineESModuleGetters(lazy, {
      8  IPProtectionService:
      9    "moz-src:///browser/components/ipprotection/IPProtectionService.sys.mjs",
     10  IPProtectionStates:
     11    "moz-src:///browser/components/ipprotection/IPProtectionService.sys.mjs",
     12 });
     13 
     14 const STATE_CACHE_PREF = "browser.ipProtection.stateCache";
     15 const ENTITLEMENT_CACHE_PREF = "browser.ipProtection.entitlementCache";
     16 const LOCATIONLIST_CACHE_PREF = "browser.ipProtection.locationListCache";
     17 
     18 /**
     19 * This class implements a cache for the IPP state machine. The cache is used
     20 * until we receive the `sessionstore-windows-restored` event
     21 */
     22 class IPPStartupCacheSingleton {
     23  #stateFromCache = null;
     24  #startupCompleted = false;
     25 
     26  constructor() {
     27    // For XPCShell tests, the cache must be disabled.
     28    if (
     29      Services.prefs.getBoolPref("browser.ipProtection.cacheDisabled", false)
     30    ) {
     31      this.#startupCompleted = true;
     32      return;
     33    }
     34 
     35    this.handleEvent = this.#handleEvent.bind(this);
     36 
     37    const stateFromCache = Services.prefs.getCharPref(
     38      STATE_CACHE_PREF,
     39      "unset"
     40    );
     41    if (stateFromCache !== "unset") {
     42      this.#stateFromCache = stateFromCache;
     43    }
     44 
     45    Services.obs.addObserver(this, "sessionstore-windows-restored");
     46  }
     47 
     48  init() {
     49    lazy.IPProtectionService.addEventListener(
     50      "IPProtectionService:StateChanged",
     51      this.handleEvent
     52    );
     53  }
     54 
     55  async initOnStartupCompleted() {}
     56 
     57  uninit() {
     58    lazy.IPProtectionService.removeEventListener(
     59      "IPProtectionService:StateChanged",
     60      this.handleEvent
     61    );
     62  }
     63 
     64  get isStartupCompleted() {
     65    return this.#startupCompleted;
     66  }
     67 
     68  get state() {
     69    if (this.#startupCompleted) {
     70      throw new Error("IPPStartupCache should not be used after the startup");
     71    }
     72 
     73    if (Object.values(lazy.IPProtectionStates).includes(this.#stateFromCache)) {
     74      return this.#stateFromCache;
     75    }
     76 
     77    // This should not happen.
     78    return lazy.IPProtectionStates.UNINITIALIZED;
     79  }
     80 
     81  async observe(_subject, topic, _) {
     82    if (topic !== "sessionstore-windows-restored") {
     83      return;
     84    }
     85 
     86    // The browser is ready! Let's invalidate the cache and let's recompute the
     87    // state.
     88 
     89    Services.obs.removeObserver(this, "sessionstore-windows-restored");
     90    this.#startupCompleted = true;
     91    this.#stateFromCache = null;
     92 
     93    await lazy.IPProtectionService.initOnStartupCompleted();
     94    lazy.IPProtectionService.updateState();
     95  }
     96 
     97  storeEntitlement(entitlement) {
     98    Services.prefs.setCharPref(
     99      ENTITLEMENT_CACHE_PREF,
    100      JSON.stringify(entitlement)
    101    );
    102  }
    103 
    104  get entitlement() {
    105    try {
    106      const entitlement = Services.prefs.getCharPref(
    107        ENTITLEMENT_CACHE_PREF,
    108        ""
    109      );
    110      return JSON.parse(entitlement);
    111    } catch (e) {
    112      return null;
    113    }
    114  }
    115 
    116  storeLocationList(locationList) {
    117    Services.prefs.setCharPref(
    118      LOCATIONLIST_CACHE_PREF,
    119      JSON.stringify(locationList)
    120    );
    121  }
    122 
    123  get locationList() {
    124    try {
    125      const locationList = Services.prefs.getCharPref(
    126        LOCATIONLIST_CACHE_PREF,
    127        ""
    128      );
    129      return JSON.parse(locationList);
    130    } catch (e) {
    131      return null;
    132    }
    133  }
    134 
    135  #handleEvent(_event) {
    136    const state = lazy.IPProtectionService.state;
    137    if (this.#startupCompleted) {
    138      Services.prefs.setCharPref(STATE_CACHE_PREF, state);
    139    } else {
    140      this.#stateFromCache = state;
    141    }
    142  }
    143 }
    144 
    145 const IPPStartupCache = new IPPStartupCacheSingleton();
    146 
    147 export { IPPStartupCache, IPPStartupCacheSingleton };