tor-browser

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

Discovery.sys.mjs (4242B)


      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 file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
      6 
      7 const lazy = {};
      8 
      9 ChromeUtils.defineESModuleGetters(lazy, {
     10  ClientID: "resource://gre/modules/ClientID.sys.mjs",
     11  ContextualIdentityService:
     12    "resource://gre/modules/ContextualIdentityService.sys.mjs",
     13 });
     14 
     15 const RECOMMENDATION_ENABLED = "browser.discovery.enabled";
     16 const TELEMETRY_ENABLED = "datareporting.healthreport.uploadEnabled";
     17 const TAAR_COOKIE_NAME = "taarId";
     18 
     19 export const Discovery = {
     20  set enabled(val) {
     21    val = !!val;
     22    if (val && !lazy.gTelemetryEnabled) {
     23      throw Error("unable to turn on recommendations");
     24    }
     25    Services.prefs.setBoolPref(RECOMMENDATION_ENABLED, val);
     26  },
     27 
     28  get enabled() {
     29    return lazy.gTelemetryEnabled && lazy.gRecommendationEnabled;
     30  },
     31 
     32  reset() {
     33    return DiscoveryInternal.update(true);
     34  },
     35 
     36  update() {
     37    return DiscoveryInternal.update();
     38  },
     39 };
     40 
     41 XPCOMUtils.defineLazyPreferenceGetter(
     42  lazy,
     43  "gRecommendationEnabled",
     44  RECOMMENDATION_ENABLED,
     45  false,
     46  Discovery.update
     47 );
     48 XPCOMUtils.defineLazyPreferenceGetter(
     49  lazy,
     50  "gTelemetryEnabled",
     51  TELEMETRY_ENABLED,
     52  false,
     53  Discovery.update
     54 );
     55 XPCOMUtils.defineLazyPreferenceGetter(
     56  lazy,
     57  "gCachedClientID",
     58  "toolkit.telemetry.cachedClientID",
     59  "",
     60  Discovery.reset
     61 );
     62 XPCOMUtils.defineLazyPreferenceGetter(
     63  lazy,
     64  "gContainersEnabled",
     65  "browser.discovery.containers.enabled",
     66  false,
     67  Discovery.reset
     68 );
     69 
     70 Services.obs.addObserver(Discovery.update, "contextual-identity-created");
     71 
     72 const DiscoveryInternal = {
     73  get sites() {
     74    delete this.sites;
     75    this.sites = Services.prefs
     76      .getCharPref("browser.discovery.sites", "")
     77      .split(",");
     78    return this.sites;
     79  },
     80 
     81  getContextualIDs() {
     82    // There is never a zero id, this is just for use in update.
     83    let IDs = [0];
     84    if (lazy.gContainersEnabled) {
     85      lazy.ContextualIdentityService.getPublicIdentities().forEach(identity => {
     86        IDs.push(identity.userContextId);
     87      });
     88    }
     89    return IDs;
     90  },
     91 
     92  async update(reset = false) {
     93    if (reset || !Discovery.enabled) {
     94      for (let site of this.sites) {
     95        Services.cookies.remove(site, TAAR_COOKIE_NAME, "/", {});
     96        lazy.ContextualIdentityService.getPublicIdentities().forEach(
     97          identity => {
     98            let { userContextId } = identity;
     99            Services.cookies.remove(site, TAAR_COOKIE_NAME, "/", {
    100              userContextId,
    101            });
    102          }
    103        );
    104      }
    105    }
    106 
    107    if (Discovery.enabled) {
    108      // If the client id is not cached, wait for the notification that it is
    109      // cached.  This will happen shortly after startup in TelemetryController.sys.mjs.
    110      // When that happens, we'll get a pref notification for the cached id,
    111      // which will call update again.
    112      if (!lazy.gCachedClientID) {
    113        return;
    114      }
    115      let id = await lazy.ClientID.getClientIdHash();
    116      for (let site of this.sites) {
    117        // This cookie gets tied down as much as possible.  Specifically,
    118        // SameSite, Secure, HttpOnly and non-PrivateBrowsing.
    119        for (let userContextId of this.getContextualIDs()) {
    120          let originAttributes = { privateBrowsingId: 0 };
    121          if (userContextId > 0) {
    122            originAttributes.userContextId = userContextId;
    123          }
    124          if (
    125            Services.cookies.cookieExists(
    126              site,
    127              "/",
    128              TAAR_COOKIE_NAME,
    129              originAttributes
    130            )
    131          ) {
    132            continue;
    133          }
    134          const cv = Services.cookies.add(
    135            site,
    136            "/",
    137            TAAR_COOKIE_NAME,
    138            id,
    139            true, // secure
    140            true, // httpOnly
    141            true, // session
    142            Number.MAX_SAFE_INTEGER,
    143            originAttributes,
    144            Ci.nsICookie.SAMESITE_LAX,
    145            Ci.nsICookie.SCHEME_HTTPS
    146          );
    147          if (cv.result != Ci.nsICookieValidation.eOK) {
    148            throw new Error("Invalid cookie!");
    149          }
    150        }
    151      }
    152    }
    153  },
    154 };