tor-browser

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

runtime-default-preferences.js (3402B)


      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 "use strict";
      6 
      7 /**
      8 * This module provides a workaround for remote debugging when a preference is
      9 * defined in the firefox preference file (browser/app/profile/firefox.js) but
     10 * still read from the server, without any default value.
     11 *
     12 * This causes the server to crash and can't easily be recovered.
     13 *
     14 * While we work on better linting to prevent such issues (Bug 1660182), this
     15 * module will be able to set default values for all missing preferences.
     16 */
     17 
     18 const PREFERENCE_TYPES = {
     19  BOOL: "BOOL",
     20  CHAR: "CHAR",
     21  INT: "INT",
     22 };
     23 exports.PREFERENCE_TYPES = PREFERENCE_TYPES;
     24 
     25 /**
     26 * Expected properties for the preference descriptors:
     27 * - prefName {String}: the name of the preference.
     28 * - defaultValue {String|Bool|Number}: the value to set if the preference is
     29 *   missing.
     30 * - trait {String}: the name of the trait corresponding to this pref on the
     31 *   PreferenceFront.
     32 * - type {String}: the preference type (either BOOL, CHAR or INT).
     33 */
     34 const DEFAULT_PREFERENCES = [];
     35 exports.DEFAULT_PREFERENCES = DEFAULT_PREFERENCES;
     36 
     37 const METHODS = {
     38  [PREFERENCE_TYPES.BOOL]: {
     39    setPref: "setBoolPref",
     40    getPref: "getBoolPref",
     41  },
     42  [PREFERENCE_TYPES.CHAR]: {
     43    setPref: "setCharPref",
     44    getPref: "getCharPref",
     45  },
     46  [PREFERENCE_TYPES.INT]: {
     47    setPref: "setIntPref",
     48    getPref: "getIntPref",
     49  },
     50 };
     51 
     52 /**
     53 * Set default values for all the provided preferences on the runtime
     54 * corresponding to the provided clientWrapper, if needed.
     55 *
     56 * Note: prefDescriptors will most likely be DEFAULT_PREFERENCES when
     57 * used in production code, but can be parameterized for tests.
     58 *
     59 * @param {ClientWrapper} clientWrapper
     60 * @param {Array} prefDescriptors
     61 *        Array of preference descriptors, see DEFAULT_PREFERENCES.
     62 */
     63 async function setDefaultPreferencesIfNeeded(clientWrapper, prefDescriptors) {
     64  if (!prefDescriptors || prefDescriptors.length === 0) {
     65    return;
     66  }
     67 
     68  const preferenceFront = await clientWrapper.getFront("preference");
     69  const preferenceTraits = await preferenceFront.getTraits();
     70 
     71  // Note: using Promise.all here fails because the request/responses get mixed.
     72  for (const prefDescriptor of prefDescriptors) {
     73    // If the fix for this preference is already on this server, skip it.
     74    if (preferenceTraits[prefDescriptor.trait]) {
     75      continue;
     76    }
     77 
     78    await setDefaultPreference(preferenceFront, prefDescriptor);
     79  }
     80 }
     81 exports.setDefaultPreferencesIfNeeded = setDefaultPreferencesIfNeeded;
     82 
     83 async function setDefaultPreference(preferenceFront, prefDescriptor) {
     84  const { prefName, type, defaultValue } = prefDescriptor;
     85 
     86  if (!Object.values(PREFERENCE_TYPES).includes(type)) {
     87    throw new Error(`Unsupported type for setDefaultPreference "${type}"`);
     88  }
     89 
     90  const prefMethods = METHODS[type];
     91  try {
     92    // Try to read the preference only to check if the call is successful.
     93    // If not, this means the preference is missing and should be initialized.
     94    await preferenceFront[prefMethods.getPref](prefName);
     95  } catch (e) {
     96    console.warn(
     97      `Preference "${prefName}"" is not set on the remote runtime. Setting default value.`
     98    );
     99    await preferenceFront[prefMethods.setPref](prefName, defaultValue);
    100  }
    101 }