tor-browser

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

InstallerPrefs.sys.mjs (4978B)


      1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /**
      7 * The installer prefs component provides a way to get a specific set of prefs
      8 * from a profile into a place where the installer can read them. The primary
      9 * reason for wanting to do this is so we can run things like Shield studies
     10 * on installer features; normally those are enabled by setting a pref, but
     11 * the installer runs outside of any profile and so has no access to prefs.
     12 * So we need to do something else to allow it to read these prefs.
     13 *
     14 * The mechanism we use here is to reflect the values of a list of relevant
     15 * prefs into registry values. One registry value is created for each pref
     16 * that is set. Each installation of the product gets its own registry key
     17 * (based on the path hash). This is obviously a somewhat wider scope than a
     18 * single profile, but it should be close enough in enough cases to suit our
     19 * purposes here.
     20 *
     21 * Currently this module only supports bool prefs. Other types could likely
     22 * be added if needed, but it doesn't seem necessary for the primary use case.
     23 */
     24 
     25 // All prefs processed through this component must be in this branch.
     26 const INSTALLER_PREFS_BRANCH = "installer.";
     27 
     28 // This is the list of prefs that will be reflected to the registry. It should
     29 // be kept up to date so that it reflects the list of prefs that are in
     30 // current use (e.g., currently active experiments).
     31 // Only add prefs to this list which are in INSTALLER_PREFS_BRANCH;
     32 // any others will be ignored.
     33 const INSTALLER_PREFS_LIST = ["installer.taskbarpin.win10.enabled"];
     34 
     35 import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
     36 
     37 // This constructor can take a list of prefs to override the default one,
     38 // but this is really only intended for tests to use. Normal usage should be
     39 // to leave the parameter omitted/undefined.
     40 export function InstallerPrefs(prefsList) {
     41  this.prefsList = prefsList || INSTALLER_PREFS_LIST;
     42 
     43  // Each pref to be reflected will get a value created under this key, in HKCU.
     44  // The path will look something like:
     45  // "Software\Mozilla\Firefox\Installer\71AE18FE3142402B\".
     46  ChromeUtils.defineLazyGetter(this, "_registryKeyPath", function () {
     47    const app = AppConstants.MOZ_APP_NAME;
     48    const vendor = Services.appinfo.vendor || "Mozilla";
     49    const xreDirProvider = Cc[
     50      "@mozilla.org/xre/directory-provider;1"
     51    ].getService(Ci.nsIXREDirProvider);
     52    const installHash = xreDirProvider.getInstallHash();
     53    return `Software\\${vendor}\\${app}\\Installer\\${installHash}`;
     54  });
     55 }
     56 
     57 InstallerPrefs.prototype = {
     58  classID: Components.ID("{cd8a6995-1f19-4cdd-9ed1-d6263302f594}"),
     59  contractID: "@mozilla.org/installerprefs;1",
     60 
     61  QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
     62 
     63  observe(subject, topic, data) {
     64    switch (topic) {
     65      case "profile-after-change": {
     66        if (
     67          AppConstants.platform != "win" ||
     68          !this.prefsList ||
     69          !this.prefsList.length
     70        ) {
     71          // This module has no work to do.
     72          break;
     73        }
     74        const regKey = this._openRegKey();
     75        this._reflectPrefsToRegistry(regKey);
     76        this._registerPrefListeners();
     77        regKey.close();
     78        break;
     79      }
     80      case "nsPref:changed": {
     81        const regKey = this._openRegKey();
     82        if (this.prefsList.includes(data)) {
     83          this._reflectOnePrefToRegistry(regKey, data);
     84        }
     85        regKey.close();
     86        break;
     87      }
     88    }
     89  },
     90 
     91  _registerPrefListeners() {
     92    Services.prefs.addObserver(INSTALLER_PREFS_BRANCH, this);
     93  },
     94 
     95  _cleanRegistryKey(regKey) {
     96    for (let i = regKey.valueCount - 1; i >= 0; --i) {
     97      const name = regKey.getValueName(i);
     98      if (name.startsWith(INSTALLER_PREFS_BRANCH)) {
     99        regKey.removeValue(name);
    100      }
    101    }
    102  },
    103 
    104  _reflectPrefsToRegistry(regKey) {
    105    this._cleanRegistryKey(regKey);
    106    this.prefsList.forEach(pref =>
    107      this._reflectOnePrefToRegistry(regKey, pref)
    108    );
    109  },
    110 
    111  _reflectOnePrefToRegistry(regKey, pref) {
    112    if (!pref.startsWith(INSTALLER_PREFS_BRANCH)) {
    113      return;
    114    }
    115 
    116    const value = Services.prefs.getBoolPref(pref, false);
    117    if (value) {
    118      regKey.writeIntValue(pref, 1);
    119    } else {
    120      try {
    121        regKey.removeValue(pref);
    122      } catch (ex) {
    123        // This removeValue call is prone to failing because the value we
    124        // tried to remove didn't exist. Obviously that isn't really an error
    125        // that we need to handle.
    126      }
    127    }
    128  },
    129 
    130  _openRegKey() {
    131    const key = Cc["@mozilla.org/windows-registry-key;1"].createInstance(
    132      Ci.nsIWindowsRegKey
    133    );
    134    key.create(
    135      key.ROOT_KEY_CURRENT_USER,
    136      this._registryKeyPath,
    137      key.ACCESS_READ | key.ACCESS_WRITE | key.WOW64_64
    138    );
    139    return key;
    140  },
    141 };