[tor-commits] [Git][tpo/applications/tor-browser][tor-browser-115.6.0esr-13.5-1] 8 commits: fixup! Bug 40597: Implement TorSettings module

Pier Angelo Vendrame (@pierov) git at gitlab.torproject.org
Mon Jan 8 14:14:51 UTC 2024



Pier Angelo Vendrame pushed to branch tor-browser-115.6.0esr-13.5-1 at The Tor Project / Applications / Tor Browser


Commits:
be025b30 by Pier Angelo Vendrame at 2024-01-08T14:38:58+01:00
fixup! Bug 40597: Implement TorSettings module

Convert TorSettings to an ES class.

- - - - -
440a0aae by Pier Angelo Vendrame at 2024-01-08T14:39:01+01:00
fixup! Bug 40597: Implement TorSettings module

Replace _ with # for private stuff in TorSettings.

- - - - -
08bc6b26 by Pier Angelo Vendrame at 2024-01-08T14:39:01+01:00
fixup! Bug 40597: Implement TorSettings module

Bug 42343: Read built-in bridges from pt_config.json instead of
preferences.

- - - - -
28351513 by Pier Angelo Vendrame at 2024-01-08T14:39:02+01:00
fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection

Bug 42343: Read built-in bridges from pt_config.json instead of
preferences.

Update the way in which we query the PTs we have bundled bridge lines
for.

- - - - -
6e7488b0 by Pier Angelo Vendrame at 2024-01-08T14:39:02+01:00
fixup! Bug 40562: Added Tor Browser preferences to 000-tor-browser.js

Bug 42343: Read built-in bridges from pt_config.json instead of
preferences.

Remove some preferences we do not use anymore and their documentation.

- - - - -
8da34d3a by Pier Angelo Vendrame at 2024-01-08T14:39:02+01:00
fixup! Bug 41089: Add tor-browser build scripts + Makefile to tor-browser

Bug 42343: Read built-in bridges from pt_config.json instead of
preferences.

Do not copy the bridges anymore when doing the deploy.

- - - - -
51e8c714 by Pier Angelo Vendrame at 2024-01-08T14:39:03+01:00
fixup! Bug 40597: Implement TorSettings module

Added checks on TorSettings.initialized, and some documentation
improvements.

- - - - -
7272b554 by Pier Angelo Vendrame at 2024-01-08T14:39:03+01:00
fixup! Bug 40597: Implement TorSettings module

Batch of changes requested in the MR.

- - - - -


9 changed files:

- browser/app/profile/000-tor-browser.js
- browser/components/torpreferences/content/builtinBridgeDialog.mjs
- browser/components/torpreferences/content/connectionPane.js
- toolkit/content/jar.mn
- + toolkit/content/pt_config.json
- toolkit/modules/TorConnect.sys.mjs
- toolkit/modules/TorSettings.sys.mjs
- − tools/torbrowser/bridges.js
- tools/torbrowser/deploy.sh


Changes:

=====================================
browser/app/profile/000-tor-browser.js
=====================================
@@ -69,7 +69,6 @@ pref("extensions.torbutton.pref_fixup_version", 0);
 
 pref("extensions.torlauncher.start_tor", true);
 pref("extensions.torlauncher.prompt_at_startup", true);
-pref("extensions.torlauncher.quickstart", false);
 
 pref("extensions.torlauncher.max_tor_log_entries", 1000);
 
@@ -113,11 +112,3 @@ pref("extensions.torlauncher.tordatadir_path", "");
 pref("extensions.torlauncher.bridgedb_front", "foursquare.com");
 pref("extensions.torlauncher.bridgedb_reflector", "https://moat.torproject.org.global.prod.fastly.net/");
 pref("extensions.torlauncher.moat_service", "https://bridges.torproject.org/moat");
-pref("extensions.torlauncher.bridgedb_bridge_type", "obfs4");
-
-// Recommended default bridge type.
-// pref("extensions.torlauncher.default_bridge_recommended_type", "obfs3");
-
-// Default bridges.
-// pref("extensions.torlauncher.default_bridge.TYPE.1", "TYPE x.x.x.x:yy");
-// pref("extensions.torlauncher.default_bridge.TYPE.2", "TYPE x.x.x.x:yy");


=====================================
browser/components/torpreferences/content/builtinBridgeDialog.mjs
=====================================
@@ -3,7 +3,6 @@ import { TorStrings } from "resource://gre/modules/TorStrings.sys.mjs";
 import {
   TorSettings,
   TorBridgeSource,
-  TorBuiltinBridgeTypes,
 } from "resource://gre/modules/TorSettings.sys.mjs";
 
 import {
@@ -62,7 +61,7 @@ export class BuiltinBridgeDialog {
     )) {
       const radio = optionEl.querySelector("radio");
       const type = radio.value;
-      optionEl.hidden = !TorBuiltinBridgeTypes.includes(type);
+      optionEl.hidden = !TorSettings.builtinBridgeTypes.includes(type);
       radio.label = typeStrings[type].label;
       optionEl.querySelector(
         ".builtin-bridges-option-description"


=====================================
browser/components/torpreferences/content/connectionPane.js
=====================================
@@ -867,7 +867,7 @@ const gConnectionPane = (function () {
     },
 
     init() {
-      this._populateXUL();
+      TorSettings.initializedPromise.then(() => this._populateXUL());
 
       const onUnload = () => {
         window.removeEventListener("unload", onUnload);


=====================================
toolkit/content/jar.mn
=====================================
@@ -137,3 +137,5 @@ toolkit.jar:
 # Third party files
    content/global/third_party/d3/d3.js                (/third_party/js/d3/d3.js)
    content/global/third_party/cfworker/json-schema.js (/third_party/js/cfworker/json-schema.js)
+
+   content/global/pt_config.json               (pt_config.json)


=====================================
toolkit/content/pt_config.json
=====================================
@@ -0,0 +1,32 @@
+{
+  "_comment": "Used for dev build, replaced for release builds in tor-browser-build. This file is copied from tor-browser-build cb513eec:tor-expert-bundle/pt_config.json",
+  "recommendedDefault" : "obfs4",
+  "pluggableTransports" : {
+    "lyrebird" : "ClientTransportPlugin meek_lite,obfs2,obfs3,obfs4,scramblesuit exec ${pt_path}lyrebird${pt_extension}",
+    "snowflake" : "ClientTransportPlugin snowflake exec ${pt_path}snowflake-client${pt_extension}",
+    "webtunnel" : "ClientTransportPlugin webtunnel exec ${pt_path}webtunnel-client${pt_extension}",
+    "conjure" : "ClientTransportPlugin conjure exec ${pt_path}conjure-client${pt_extension} -registerURL https://registration.refraction.network/api"
+  },
+  "bridges" : {
+    "meek-azure" : [
+      "meek_lite 192.0.2.18:80 BE776A53492E1E044A26F17306E1BC46A55A1625 url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com"
+    ],
+    "obfs4" : [
+      "obfs4 192.95.36.142:443 CDF2E852BF539B82BD10E27E9115A31734E378C2 cert=qUVQ0srL1JI/vO6V6m/24anYXiJD3QP2HgzUKQtQ7GRqqUvs7P+tG43RtAqdhLOALP7DJQ iat-mode=1",
+      "obfs4 37.218.245.14:38224 D9A82D2F9C2F65A18407B1D2B764F130847F8B5D cert=bjRaMrr1BRiAW8IE9U5z27fQaYgOhX1UCmOpg2pFpoMvo6ZgQMzLsaTzzQNTlm7hNcb+Sg iat-mode=0",
+      "obfs4 85.31.186.98:443 011F2599C0E9B27EE74B353155E244813763C3E5 cert=ayq0XzCwhpdysn5o0EyDUbmSOx3X/oTEbzDMvczHOdBJKlvIdHHLJGkZARtT4dcBFArPPg iat-mode=0",
+      "obfs4 85.31.186.26:443 91A6354697E6B02A386312F68D82CF86824D3606 cert=PBwr+S8JTVZo6MPdHnkTwXJPILWADLqfMGoVvhZClMq/Urndyd42BwX9YFJHZnBB3H0XCw iat-mode=0",
+      "obfs4 193.11.166.194:27015 2D82C2E354D531A68469ADF7F878FA6060C6BACA cert=4TLQPJrTSaDffMK7Nbao6LC7G9OW/NHkUwIdjLSS3KYf0Nv4/nQiiI8dY2TcsQx01NniOg iat-mode=0",
+      "obfs4 193.11.166.194:27020 86AC7B8D430DAC4117E9F42C9EAED18133863AAF cert=0LDeJH4JzMDtkJJrFphJCiPqKx7loozKN7VNfuukMGfHO0Z8OGdzHVkhVAOfo1mUdv9cMg iat-mode=0",
+      "obfs4 193.11.166.194:27025 1AE2C08904527FEA90C4C4F8C1083EA59FBC6FAF cert=ItvYZzW5tn6v3G4UnQa6Qz04Npro6e81AP70YujmK/KXwDFPTs3aHXcHp4n8Vt6w/bv8cA iat-mode=0",
+      "obfs4 209.148.46.65:443 74FAD13168806246602538555B5521A0383A1875 cert=ssH+9rP8dG2NLDN2XuFw63hIO/9MNNinLmxQDpVa+7kTOa9/m+tGWT1SmSYpQ9uTBGa6Hw iat-mode=0",
+      "obfs4 146.57.248.225:22 10A6CD36A537FCE513A322361547444B393989F0 cert=K1gDtDAIcUfeLqbstggjIw2rtgIKqdIhUlHp82XRqNSq/mtAjp1BIC9vHKJ2FAEpGssTPw iat-mode=0",
+      "obfs4 45.145.95.6:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0",
+      "obfs4 51.222.13.177:80 5EDAC3B810E12B01F6FD8050D2FD3E277B289A08 cert=2uplIpLQ0q9+0qMFrK5pkaYRDOe460LL9WHBvatgkuRr/SL31wBOEupaMMJ6koRE6Ld0ew iat-mode=0"
+    ],
+    "snowflake" : [
+      "snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72 fingerprint=2B280B23E1107BB62ABFC40DDCC8824814F80A72 url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=foursquare.com ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn",
+      "snowflake 192.0.2.4:80 8838024498816A039FCBBAB14E6F40A0843051FA fingerprint=8838024498816A039FCBBAB14E6F40A0843051FA url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=foursquare.com ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.net:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn"
+    ]
+  }
+}


=====================================
toolkit/modules/TorConnect.sys.mjs
=====================================
@@ -23,7 +23,6 @@ import { TorLauncherUtil } from "resource://gre/modules/TorLauncherUtil.sys.mjs"
 import {
   TorSettings,
   TorSettingsTopics,
-  TorBuiltinBridgeTypes,
 } from "resource://gre/modules/TorSettings.sys.mjs";
 
 import { TorStrings } from "resource://gre/modules/TorStrings.sys.mjs";
@@ -609,7 +608,7 @@ export const TorConnect = (() => {
                 }
 
                 const settings = await this.mrpc.circumvention_settings(
-                  [...TorBuiltinBridgeTypes, "vanilla"],
+                  [...TorSettings.builtinBridgeTypes, "vanilla"],
                   countryCode
                 );
 
@@ -625,7 +624,7 @@ export const TorConnect = (() => {
                 } else {
                   try {
                     this.settings = await this.mrpc.circumvention_defaults([
-                      ...TorBuiltinBridgeTypes,
+                      ...TorSettings.builtinBridgeTypes,
                       "vanilla",
                     ]);
                   } catch (err) {


=====================================
toolkit/modules/TorSettings.sys.mjs
=====================================
@@ -67,16 +67,6 @@ const TorSettingsPrefs = Object.freeze({
   },
 });
 
-/* Legacy tor-launcher prefs and pref branches*/
-const TorLauncherPrefs = Object.freeze({
-  quickstart: "extensions.torlauncher.quickstart",
-  default_bridge_type: "extensions.torlauncher.default_bridge_type",
-  default_bridge: "extensions.torlauncher.default_bridge.",
-  default_bridge_recommended_type:
-    "extensions.torlauncher.default_bridge_recommended_type",
-  bridgedb_bridge: "extensions.torlauncher.bridgedb_bridge.",
-});
-
 /* Config Keys used to configure tor daemon */
 const TorConfigKeys = Object.freeze({
   useBridges: "UseBridges",
@@ -105,101 +95,41 @@ export const TorProxyType = Object.freeze({
   HTTPS: 2,
 });
 
-export const TorBuiltinBridgeTypes = Object.freeze(
-  (() => {
-    const bridgeListBranch = Services.prefs.getBranch(
-      TorLauncherPrefs.default_bridge
-    );
-    const bridgePrefs = bridgeListBranch.getChildList("");
-
-    // an unordered set for shoving bridge types into
-    const bridgeTypes = new Set();
-    // look for keys ending in ".N" and treat string before that as the bridge type
-    const pattern = /\.[0-9]+$/;
-    for (const key of bridgePrefs) {
-      const offset = key.search(pattern);
-      if (offset != -1) {
-        const bt = key.substring(0, offset);
-        bridgeTypes.add(bt);
-      }
-    }
-
-    // recommended bridge type goes first in the list
-    const recommendedBridgeType = Services.prefs.getCharPref(
-      TorLauncherPrefs.default_bridge_recommended_type,
-      null
-    );
-
-    const retval = [];
-    if (recommendedBridgeType && bridgeTypes.has(recommendedBridgeType)) {
-      retval.push(recommendedBridgeType);
-    }
-
-    for (const bridgeType of bridgeTypes.values()) {
-      if (bridgeType != recommendedBridgeType) {
-        retval.push(bridgeType);
-      }
-    }
-    return retval;
-  })()
-);
-
-/* Parsing Methods */
-
-// expects a '\n' or '\r\n' delimited bridge string, which we split and trim
-// each bridge string can also optionally have 'bridge' at the beginning ie:
-// bridge $(type) $(address):$(port) $(certificate)
-// we strip out the 'bridge' prefix here
-const parseBridgeStrings = function (aBridgeStrings) {
+/**
+ * Split a blob of bridge lines into an array with single lines.
+ * Lines are delimited by \r\n or \n and each bridge string can also optionally
+ * have 'bridge' at the beginning.
+ * We split the text by \r\n, we trim the lines, remove the bridge prefix and
+ * filter out any remaiing empty item.
+ *
+ * @param {string} aBridgeStrings The text with the lines
+ * @returns {string[]} An array where each bridge line is an item
+ */
+function parseBridgeStrings(aBridgeStrings) {
   // replace carriage returns ('\r') with new lines ('\n')
   aBridgeStrings = aBridgeStrings.replace(/\r/g, "\n");
   // then replace contiguous new lines ('\n') with a single one
   aBridgeStrings = aBridgeStrings.replace(/[\n]+/g, "\n");
 
-  // split on the newline and for each bridge string: trim, remove starting 'bridge' string
-  // finally discard entries that are empty strings; empty strings could occur if we receive
-  // a new line containing only whitespace
+  // Split on the newline and for each bridge string: trim, remove starting
+  // 'bridge' string.
+  // Finally, discard entries that are empty strings; empty strings could occur
+  // if we receive a new line containing only whitespace.
   const splitStrings = aBridgeStrings.split("\n");
   return splitStrings
     .map(val => val.trim().replace(/^bridge\s+/i, ""))
-    .filter(bridgeString => bridgeString != "");
-};
-
-const getBuiltinBridgeStrings = function (builtinType) {
-  if (!builtinType) {
-    return [];
-  }
-
-  const bridgeBranch = Services.prefs.getBranch(
-    TorLauncherPrefs.default_bridge
-  );
-  const bridgeBranchPrefs = bridgeBranch.getChildList("");
-  const retval = [];
-
-  // regex matches against strings ending in ".N" where N is a positive integer
-  const pattern = /\.[0-9]+$/;
-  for (const key of bridgeBranchPrefs) {
-    // verify the location of the match is the correct offset required for aBridgeType
-    // to fit, and that the string begins with aBridgeType
-    if (
-      key.search(pattern) == builtinType.length &&
-      key.startsWith(builtinType)
-    ) {
-      const bridgeStr = bridgeBranch.getCharPref(key);
-      retval.push(bridgeStr);
-    }
-  }
-
-  // shuffle so that Tor Browser users don't all try the built-in bridges in the same order
-  arrayShuffle(retval);
-
-  return retval;
-};
-
-/* Helper methods */
-
-const arrayShuffle = function (array) {
-  // fisher-yates shuffle
+    .filter(bridgeString => bridgeString !== "");
+}
+
+/**
+ * Return a shuffled (Fisher-Yates) copy of an array.
+ *
+ * @template T
+ * @param {T[]} array
+ * @returns {T[]}
+ */
+function arrayShuffle(array) {
+  array = [...array];
   for (let i = array.length - 1; i > 0; --i) {
     // number n such that 0.0 <= n < 1.0
     const n = Math.random();
@@ -211,17 +141,18 @@ const arrayShuffle = function (array) {
     array[i] = array[j];
     array[j] = tmp;
   }
-};
+  return array;
+}
 
 /* TorSettings module */
 
-export const TorSettings = {
+class TorSettingsImpl {
   /**
    * The underlying settings values.
    *
    * @type {object}
    */
-  _settings: {
+  #settings = {
     quickstart: {
       enabled: false,
     },
@@ -243,34 +174,207 @@ export const TorSettings = {
       enabled: false,
       allowed_ports: [],
     },
-  },
+  };
+
+  /**
+   * The recommended pluggable transport.
+   *
+   * @type {string}
+   */
+  #recommendedPT = "";
+
+  /**
+   * The bridge lines for built-in bridges.
+   * Keys are pluggable transports, and values are arrays of bridge lines.
+   *
+   * @type {Object.<string, string[]>}
+   */
+  #builtinBridges = {};
+
+  /**
+   * Resolve callback of the initializedPromise.
+   */
+  #initComplete;
+  /**
+   * Reject callback of the initializedPromise.
+   */
+  #initFailed;
+  /**
+   * Tell whether the initializedPromise has been resolved.
+   * We keep this additional member to avoid making everything async.
+   *
+   * @type {boolean}
+   */
+  #initialized = false;
+  /**
+   * During some phases of the initialization, allow calling setters and
+   * getters without throwing errors.
+   *
+   * @type {boolean}
+   */
+  #allowUninitialized = false;
+
+  constructor() {
+    this.initializedPromise = new Promise((resolve, reject) => {
+      this.#initComplete = resolve;
+      this.#initFailed = reject;
+    });
+
+    this.#addProperties("quickstart", {
+      enabled: {},
+    });
+    this.#addProperties("bridges", {
+      enabled: {},
+      source: {
+        transform: val => {
+          if (Object.values(TorBridgeSource).includes(val)) {
+            return val;
+          }
+          lazy.logger.error(`Not a valid bridge source: "${val}"`);
+          return TorBridgeSource.Invalid;
+        },
+      },
+      bridge_strings: {
+        transform: val => {
+          if (Array.isArray(val)) {
+            return [...val];
+          }
+          return parseBridgeStrings(val);
+        },
+        copy: val => [...val],
+        equal: (val1, val2) => this.#arrayEqual(val1, val2),
+      },
+      builtin_type: {
+        callback: val => {
+          if (!val) {
+            // Make sure that the source is not BuiltIn
+            if (this.bridges.source === TorBridgeSource.BuiltIn) {
+              this.bridges.source = TorBridgeSource.Invalid;
+            }
+            return;
+          }
+          const bridgeStrings = this.#getBuiltinBridges(val);
+          if (bridgeStrings.length) {
+            this.bridges.bridge_strings = bridgeStrings;
+            return;
+          }
+          lazy.logger.error(`No built-in ${val} bridges found`);
+          // Change to be empty, this will trigger this callback again,
+          // but with val as "".
+          this.bridges.builtin_type == "";
+        },
+      },
+    });
+    this.#addProperties("proxy", {
+      enabled: {
+        callback: val => {
+          if (val) {
+            return;
+          }
+          // Reset proxy settings.
+          this.proxy.type = TorProxyType.Invalid;
+          this.proxy.address = "";
+          this.proxy.port = 0;
+          this.proxy.username = "";
+          this.proxy.password = "";
+        },
+      },
+      type: {
+        transform: val => {
+          if (Object.values(TorProxyType).includes(val)) {
+            return val;
+          }
+          lazy.logger.error(`Not a valid proxy type: "${val}"`);
+          return TorProxyType.Invalid;
+        },
+      },
+      address: {},
+      port: {
+        transform: val => {
+          if (val === 0) {
+            // This is a valid value that "unsets" the port.
+            // Keep this value without giving a warning.
+            // NOTE: In contrast, "0" is not valid.
+            return 0;
+          }
+          // Unset to 0 if invalid null is returned.
+          return this.#parsePort(val, false) ?? 0;
+        },
+      },
+      username: {},
+      password: {},
+      uri: {
+        getter: () => {
+          const { type, address, port, username, password } = this.proxy;
+          switch (type) {
+            case TorProxyType.Socks4:
+              return `socks4a://${address}:${port}`;
+            case TorProxyType.Socks5:
+              if (username) {
+                return `socks5://${username}:${password}@${address}:${port}`;
+              }
+              return `socks5://${address}:${port}`;
+            case TorProxyType.HTTPS:
+              if (username) {
+                return `http://${username}:${password}@${address}:${port}`;
+              }
+              return `http://${address}:${port}`;
+          }
+          return null;
+        },
+      },
+    });
+    this.#addProperties("firewall", {
+      enabled: {
+        callback: val => {
+          if (!val) {
+            this.firewall.allowed_ports = "";
+          }
+        },
+      },
+      allowed_ports: {
+        transform: val => {
+          if (!Array.isArray(val)) {
+            val = val === "" ? [] : val.split(",");
+          }
+          // parse and remove duplicates
+          const portSet = new Set(val.map(p => this.#parsePort(p, true)));
+          // parsePort returns null for failed parses, so remove it.
+          portSet.delete(null);
+          return [...portSet];
+        },
+        copy: val => [...val],
+        equal: (val1, val2) => this.#arrayEqual(val1, val2),
+      },
+    });
+  }
 
   /**
    * The current number of freezes applied to the notifications.
    *
    * @type {integer}
    */
-  _freezeNotificationsCount: 0,
+  #freezeNotificationsCount = 0;
   /**
    * The queue for settings that have changed. To be broadcast in the
    * notification when not frozen.
    *
    * @type {Set<string>}
    */
-  _notificationQueue: new Set(),
+  #notificationQueue = new Set();
   /**
    * Send a notification if we have any queued and we are not frozen.
    */
-  _tryNotification() {
-    if (this._freezeNotificationsCount || !this._notificationQueue.size) {
+  #tryNotification() {
+    if (this.#freezeNotificationsCount || !this.#notificationQueue.size) {
       return;
     }
     Services.obs.notifyObservers(
-      { changes: [...this._notificationQueue] },
+      { changes: [...this.#notificationQueue] },
       TorSettingsTopics.SettingsChanged
     );
-    this._notificationQueue.clear();
-  },
+    this.#notificationQueue.clear();
+  }
   /**
    * Pause notifications for changes in setting values. This is useful if you
    * need to make batch changes to settings.
@@ -281,8 +385,8 @@ export const TorSettings = {
    * `finally` block.
    */
   freezeNotifications() {
-    this._freezeNotificationsCount++;
-  },
+    this.#freezeNotificationsCount++;
+  }
   /**
    * Release the hold on notifications so they may be sent out.
    *
@@ -290,9 +394,9 @@ export const TorSettings = {
    * only release them once it has also called this method.
    */
   thawNotifications() {
-    this._freezeNotificationsCount--;
-    this._tryNotification();
-  },
+    this.#freezeNotificationsCount--;
+    this.#tryNotification();
+  }
   /**
    * @typedef {object} TorSettingProperty
    *
@@ -316,22 +420,32 @@ export const TorSettings = {
    * @param {string} groupname - The name of the setting group. The given
    *   settings will be accessible from the TorSettings property of the same
    *   name.
-   * @param {object<string, TorSettingProperty>} propParams - An object that
+   * @param {object.<string, TorSettingProperty>} propParams - An object that
    *   defines the settings to add to this group. The object property names
    *   will be mapped to properties of TorSettings under the given groupname
    *   property. Details about the setting should be described in the
    *   TorSettingProperty property value.
    */
-  _addProperties(groupname, propParams) {
+  #addProperties(groupname, propParams) {
     // Create a new object to hold all these settings.
     const group = {};
     for (const name in propParams) {
       const { getter, transform, callback, copy, equal } = propParams[name];
       Object.defineProperty(group, name, {
         get: getter
-          ? getter
+          ? () => {
+              // Allow getting in loadFromPrefs before we are initialized.
+              if (!this.#allowUninitialized) {
+                this.#checkIfInitialized();
+              }
+              return getter();
+            }
           : () => {
-              let val = this._settings[groupname][name];
+              // Allow getting in loadFromPrefs before we are initialized.
+              if (!this.#allowUninitialized) {
+                this.#checkIfInitialized();
+              }
+              let val = this.#settings[groupname][name];
               if (copy) {
                 val = copy(val);
               }
@@ -341,7 +455,11 @@ export const TorSettings = {
         set: getter
           ? undefined
           : val => {
-              const prevVal = this._settings[groupname][name];
+              // Allow setting in loadFromPrefs before we are initialized.
+              if (!this.#allowUninitialized) {
+                this.#checkIfInitialized();
+              }
+              const prevVal = this.#settings[groupname][name];
               this.freezeNotifications();
               try {
                 if (transform) {
@@ -352,8 +470,8 @@ export const TorSettings = {
                   if (callback) {
                     callback(val);
                   }
-                  this._settings[groupname][name] = val;
-                  this._notificationQueue.add(`${groupname}.${name}`);
+                  this.#settings[groupname][name] = val;
+                  this.#notificationQueue.add(`${groupname}.${name}`);
                 }
               } finally {
                 this.thawNotifications();
@@ -367,14 +485,14 @@ export const TorSettings = {
       writable: false,
       value: group,
     });
-  },
+  }
 
   /**
    * Regular expression for a decimal non-negative integer.
    *
    * @type {RegExp}
    */
-  _portRegex: /^[0-9]+$/,
+  #portRegex = /^[0-9]+$/;
   /**
    * Parse a string as a port number.
    *
@@ -385,13 +503,13 @@ export const TorSettings = {
    * @return {integer?} - The port number, or null if the given value was not
    *   valid.
    */
-  _parsePort(val, trim) {
+  #parsePort(val, trim) {
     if (typeof val === "string") {
       if (trim) {
         val = val.trim();
       }
       // ensure port string is a valid positive integer
-      if (this._portRegex.test(val)) {
+      if (this.#portRegex.test(val)) {
         val = Number.parseInt(val, 10);
       } else {
         lazy.logger.error(`Invalid port string "${val}"`);
@@ -403,7 +521,7 @@ export const TorSettings = {
       return null;
     }
     return val;
-  },
+  }
   /**
    * Test whether two arrays have equal members and order.
    *
@@ -412,142 +530,57 @@ export const TorSettings = {
    *
    * @return {boolean} - Whether the two arrays are equal.
    */
-  _arrayEqual(val1, val2) {
+  #arrayEqual(val1, val2) {
     if (val1.length !== val2.length) {
       return false;
     }
     return val1.every((v, i) => v === val2[i]);
-  },
+  }
+
+  /**
+   * Return the bridge lines associated to a certain pluggable transport.
+   *
+   * @param {string} pt The pluggable transport to return the lines for
+   * @returns {string[]} The bridge lines in random order
+   */
+  #getBuiltinBridges(pt) {
+    // Shuffle so that Tor Browser users do not all try the built-in bridges in
+    // the same order.
+    return arrayShuffle(this.#builtinBridges[pt] ?? []);
+  }
 
-  /* load or init our settings, and register observers */
+  /**
+   * Load or init our settings, and register observers.
+   */
   async init() {
-    this._addProperties("quickstart", {
-      enabled: {},
-    });
-    this._addProperties("bridges", {
-      enabled: {},
-      source: {
-        transform: val => {
-          if (Object.values(TorBridgeSource).includes(val)) {
-            return val;
-          }
-          lazy.logger.error(`Not a valid bridge source: "${val}"`);
-          return TorBridgeSource.Invalid;
-        },
-      },
-      bridge_strings: {
-        transform: val => {
-          if (Array.isArray(val)) {
-            return [...val];
-          }
-          return parseBridgeStrings(val);
-        },
-        copy: val => [...val],
-        equal: (val1, val2) => this._arrayEqual(val1, val2),
-      },
-      builtin_type: {
-        callback: val => {
-          if (!val) {
-            // Make sure that the source is not BuiltIn
-            if (this.bridges.source === TorBridgeSource.BuiltIn) {
-              this.bridges.source = TorBridgeSource.Invalid;
-            }
-            return;
-          }
-          const bridgeStrings = getBuiltinBridgeStrings(val);
-          if (bridgeStrings.length) {
-            this.bridges.bridge_strings = bridgeStrings;
-            return;
-          }
-          lazy.logger.error(`No built-in ${val} bridges found`);
-          // Change to be empty, this will trigger this callback again,
-          // but with val as "".
-          this.bridges.builtin_type == "";
-        },
-      },
-    });
-    this._addProperties("proxy", {
-      enabled: {
-        callback: val => {
-          if (val) {
-            return;
-          }
-          // Reset proxy settings.
-          this.proxy.type = TorProxyType.Invalid;
-          this.proxy.address = "";
-          this.proxy.port = 0;
-          this.proxy.username = "";
-          this.proxy.password = "";
-        },
-      },
-      type: {
-        transform: val => {
-          if (Object.values(TorProxyType).includes(val)) {
-            return val;
-          }
-          lazy.logger.error(`Not a valid proxy type: "${val}"`);
-          return TorProxyType.Invalid;
-        },
-      },
-      address: {},
-      port: {
-        transform: val => {
-          if (val === 0) {
-            // This is a valid value that "unsets" the port.
-            // Keep this value without giving a warning.
-            // NOTE: In contrast, "0" is not valid.
-            return 0;
-          }
-          // Unset to 0 if invalid null is returned.
-          return this._parsePort(val, false) ?? 0;
-        },
-      },
-      username: {},
-      password: {},
-      uri: {
-        getter: () => {
-          const { type, address, port, username, password } = this.proxy;
-          switch (type) {
-            case TorProxyType.Socks4:
-              return `socks4a://${address}:${port}`;
-            case TorProxyType.Socks5:
-              if (username) {
-                return `socks5://${username}:${password}@${address}:${port}`;
-              }
-              return `socks5://${address}:${port}`;
-            case TorProxyType.HTTPS:
-              if (username) {
-                return `http://${username}:${password}@${address}:${port}`;
-              }
-              return `http://${address}:${port}`;
-          }
-          return null;
-        },
-      },
-    });
-    this._addProperties("firewall", {
-      enabled: {
-        callback: val => {
-          if (!val) {
-            this.firewall.allowed_ports = "";
-          }
-        },
-      },
-      allowed_ports: {
-        transform: val => {
-          if (!Array.isArray(val)) {
-            val = val === "" ? [] : val.split(",");
-          }
-          // parse and remove duplicates
-          const portSet = new Set(val.map(p => this._parsePort(p, true)));
-          // parsePort returns null for failed parses, so remove it.
-          portSet.delete(null);
-          return [...portSet];
-        },
-        copy: val => [...val],
-        equal: (val1, val2) => this._arrayEqual(val1, val2),
-      },
-    });
+    if (this.#initialized) {
+      lazy.logger.warn("Called init twice.");
+      return;
+    }
+    try {
+      await this.#initInternal();
+      this.#initialized = true;
+      this.#initComplete();
+    } catch (e) {
+      this.#initFailed(e);
+      throw e;
+    }
+  }
+
+  /**
+   * The actual implementation of the initialization, which is wrapped to make
+   * it easier to update initializatedPromise.
+   */
+  async #initInternal() {
+    try {
+      const req = await fetch("chrome://global/content/pt_config.json");
+      const config = await req.json();
+      lazy.logger.debug("Loaded pt_config.json", config);
+      this.#recommendedPT = config.recommendedDefault;
+      this.#builtinBridges = config.bridges;
+    } catch (e) {
+      lazy.logger.error("Could not load the built-in PT config.", e);
+    }
 
     // TODO: We could use a shared promise, and wait for it to be fullfilled
     // instead of Service.obs.
@@ -557,16 +590,18 @@ export const TorSettings = {
         // Do not want notifications for initially loaded prefs.
         this.freezeNotifications();
         try {
-          this.loadFromPrefs();
+          this.#allowUninitialized = true;
+          this.#loadFromPrefs();
         } finally {
-          this._notificationQueue.clear();
+          this.#allowUninitialized = false;
+          this.#notificationQueue.clear();
           this.thawNotifications();
         }
       }
       try {
         const provider = await lazy.TorProviderBuilder.build();
         if (provider.isRunning) {
-          this.handleProcessReady();
+          this.#handleProcessReady();
           // No need to add an observer to call this again.
           return;
         }
@@ -574,9 +609,33 @@ export const TorSettings = {
 
       Services.obs.addObserver(this, lazy.TorProviderTopics.ProcessIsReady);
     }
-  },
+  }
+
+  /**
+   * Check whether the object has been successfully initialized, and throw if
+   * it has not.
+   */
+  #checkIfInitialized() {
+    if (!this.#initialized) {
+      lazy.logger.trace("Not initialized code path.");
+      throw new Error(
+        "TorSettings has not been initialized yet, or its initialization failed"
+      );
+    }
+  }
+
+  /**
+   * Tell whether TorSettings has been successfully initialized.
+   *
+   * @returns {boolean}
+   */
+  get initialized() {
+    return this.#initialized;
+  }
 
-  /* wait for relevant life-cycle events to apply saved settings */
+  /**
+   * Wait for relevant life-cycle events to apply saved settings.
+   */
   async observe(subject, topic, data) {
     lazy.logger.debug(`Observed ${topic}`);
 
@@ -586,21 +645,26 @@ export const TorSettings = {
           this,
           lazy.TorProviderTopics.ProcessIsReady
         );
-        await this.handleProcessReady();
+        await this.#handleProcessReady();
         break;
     }
-  },
+  }
 
-  // once the tor daemon is ready, we need to apply our settings
-  async handleProcessReady() {
+  /**
+   * Apply the settings once the tor provider is ready and notify any observer
+   * that the settings can be used.
+   */
+  async #handleProcessReady() {
     // push down settings to tor
-    await this.applySettings();
+    await this.#applySettings(true);
     lazy.logger.info("Ready");
     Services.obs.notifyObservers(null, TorSettingsTopics.Ready);
-  },
+  }
 
-  // load our settings from prefs
-  loadFromPrefs() {
+  /**
+   * Load our settings from prefs.
+   */
+  #loadFromPrefs() {
     lazy.logger.debug("loadFromPrefs()");
 
     /* Quickstart */
@@ -671,12 +735,16 @@ export const TorSettings = {
         ""
       );
     }
-  },
+  }
 
-  // save our settings to prefs
+  /**
+   * Save our settings to prefs.
+   */
   saveToPrefs() {
     lazy.logger.debug("saveToPrefs()");
 
+    this.#checkIfInitialized();
+
     /* Quickstart */
     Services.prefs.setBoolPref(
       TorSettingsPrefs.quickstart.enabled,
@@ -758,77 +826,100 @@ export const TorSettings = {
     Services.prefs.setBoolPref(TorSettingsPrefs.enabled, true);
 
     return this;
-  },
+  }
 
-  // push our settings down to the tor daemon
+  /**
+   * Push our settings down to the tor provider.
+   */
   async applySettings() {
-    lazy.logger.debug("applySettings()");
+    this.#checkIfInitialized();
+    return this.#applySettings(false);
+  }
+
+  /**
+   * Internal implementation of applySettings that does not check if we are
+   * initialized.
+   */
+  async #applySettings(allowUninitialized) {
+    lazy.logger.debug("#applySettings()");
+
     const settingsMap = new Map();
 
-    /* Bridges */
-    const haveBridges =
-      this.bridges.enabled && !!this.bridges.bridge_strings.length;
-    settingsMap.set(TorConfigKeys.useBridges, haveBridges);
-    if (haveBridges) {
-      settingsMap.set(TorConfigKeys.bridgeList, this.bridges.bridge_strings);
-    } else {
-      settingsMap.set(TorConfigKeys.bridgeList, null);
-    }
+    // #applySettings can be called only when #allowUninitialized is false
+    this.#allowUninitialized = allowUninitialized;
 
-    /* Proxy */
-    settingsMap.set(TorConfigKeys.socks4Proxy, null);
-    settingsMap.set(TorConfigKeys.socks5Proxy, null);
-    settingsMap.set(TorConfigKeys.socks5ProxyUsername, null);
-    settingsMap.set(TorConfigKeys.socks5ProxyPassword, null);
-    settingsMap.set(TorConfigKeys.httpsProxy, null);
-    settingsMap.set(TorConfigKeys.httpsProxyAuthenticator, null);
-    if (this.proxy.enabled) {
-      const address = this.proxy.address;
-      const port = this.proxy.port;
-      const username = this.proxy.username;
-      const password = this.proxy.password;
-
-      switch (this.proxy.type) {
-        case TorProxyType.Socks4:
-          settingsMap.set(TorConfigKeys.socks4Proxy, `${address}:${port}`);
-          break;
-        case TorProxyType.Socks5:
-          settingsMap.set(TorConfigKeys.socks5Proxy, `${address}:${port}`);
-          settingsMap.set(TorConfigKeys.socks5ProxyUsername, username);
-          settingsMap.set(TorConfigKeys.socks5ProxyPassword, password);
-          break;
-        case TorProxyType.HTTPS:
-          settingsMap.set(TorConfigKeys.httpsProxy, `${address}:${port}`);
-          settingsMap.set(
-            TorConfigKeys.httpsProxyAuthenticator,
-            `${username}:${password}`
-          );
-          break;
+    try {
+      /* Bridges */
+      const haveBridges =
+        this.bridges.enabled && !!this.bridges.bridge_strings.length;
+      settingsMap.set(TorConfigKeys.useBridges, haveBridges);
+      if (haveBridges) {
+        settingsMap.set(TorConfigKeys.bridgeList, this.bridges.bridge_strings);
+      } else {
+        settingsMap.set(TorConfigKeys.bridgeList, null);
       }
-    }
 
-    /* Firewall */
-    if (this.firewall.enabled) {
-      const reachableAddresses = this.firewall.allowed_ports
-        .map(port => `*:${port}`)
-        .join(",");
-      settingsMap.set(TorConfigKeys.reachableAddresses, reachableAddresses);
-    } else {
-      settingsMap.set(TorConfigKeys.reachableAddresses, null);
+      /* Proxy */
+      settingsMap.set(TorConfigKeys.socks4Proxy, null);
+      settingsMap.set(TorConfigKeys.socks5Proxy, null);
+      settingsMap.set(TorConfigKeys.socks5ProxyUsername, null);
+      settingsMap.set(TorConfigKeys.socks5ProxyPassword, null);
+      settingsMap.set(TorConfigKeys.httpsProxy, null);
+      settingsMap.set(TorConfigKeys.httpsProxyAuthenticator, null);
+      if (this.proxy.enabled) {
+        const address = this.proxy.address;
+        const port = this.proxy.port;
+        const username = this.proxy.username;
+        const password = this.proxy.password;
+
+        switch (this.proxy.type) {
+          case TorProxyType.Socks4:
+            settingsMap.set(TorConfigKeys.socks4Proxy, `${address}:${port}`);
+            break;
+          case TorProxyType.Socks5:
+            settingsMap.set(TorConfigKeys.socks5Proxy, `${address}:${port}`);
+            settingsMap.set(TorConfigKeys.socks5ProxyUsername, username);
+            settingsMap.set(TorConfigKeys.socks5ProxyPassword, password);
+            break;
+          case TorProxyType.HTTPS:
+            settingsMap.set(TorConfigKeys.httpsProxy, `${address}:${port}`);
+            settingsMap.set(
+              TorConfigKeys.httpsProxyAuthenticator,
+              `${username}:${password}`
+            );
+            break;
+        }
+      }
+
+      /* Firewall */
+      if (this.firewall.enabled) {
+        const reachableAddresses = this.firewall.allowed_ports
+          .map(port => `*:${port}`)
+          .join(",");
+        settingsMap.set(TorConfigKeys.reachableAddresses, reachableAddresses);
+      } else {
+        settingsMap.set(TorConfigKeys.reachableAddresses, null);
+      }
+    } finally {
+      this.#allowUninitialized = false;
     }
 
     /* Push to Tor */
     const provider = await lazy.TorProviderBuilder.build();
     await provider.writeSettings(settingsMap);
+  }
 
-    return this;
-  },
-
-  // set all of our settings at once from a settings object
+  /**
+   * Set all of our settings at once from a settings object.
+   *
+   * @param {object} settings The settings object to set
+   */
   setSettings(settings) {
     lazy.logger.debug("setSettings()");
+    this.#checkIfInitialized();
+
     const backup = this.getSettings();
-    const backup_notifications = [...this._notificationQueue];
+    const backupNotifications = [...this.#notificationQueue];
 
     // Hold off on lots of notifications until all settings are changed.
     this.freezeNotifications();
@@ -869,10 +960,10 @@ export const TorSettings = {
       // some other call to TorSettings to change anything whilst we are
       // in this context (other than lower down in this call stack), so it is
       // safe to discard all changes to settings and notifications.
-      this._settings = backup;
-      this._notificationQueue.clear();
-      for (const notification of backup_notifications) {
-        this._notificationQueue.add(notification);
+      this.#settings = backup;
+      this.#notificationQueue.clear();
+      for (const notification of backupNotifications) {
+        this.#notificationQueue.add(notification);
       }
 
       lazy.logger.error("setSettings failed", ex);
@@ -880,12 +971,36 @@ export const TorSettings = {
       this.thawNotifications();
     }
 
-    lazy.logger.debug("setSettings result", this._settings);
-  },
+    lazy.logger.debug("setSettings result", this.#settings);
+  }
 
-  // get a copy of all our settings
+  /**
+   * Get a copy of all our settings.
+   *
+   * @returns {object} A copy of the settings object
+   */
   getSettings() {
     lazy.logger.debug("getSettings()");
-    return structuredClone(this._settings);
-  },
-};
+    this.#checkIfInitialized();
+    return structuredClone(this.#settings);
+  }
+
+  /**
+   * Return an array with the pluggable transports for which we have at least a
+   * built-in bridge line.
+   *
+   * @returns {string[]} An array with PT identifiers
+   */
+  get builtinBridgeTypes() {
+    this.#checkIfInitialized();
+    const types = Object.keys(this.#builtinBridges);
+    const recommendedIndex = types.indexOf(this.#recommendedPT);
+    if (recommendedIndex > 0) {
+      types.splice(recommendedIndex, 1);
+      types.unshift(this.#recommendedPT);
+    }
+    return types;
+  }
+}
+
+export const TorSettings = new TorSettingsImpl();


=====================================
tools/torbrowser/bridges.js deleted
=====================================
@@ -1,62 +0,0 @@
-pref("extensions.torlauncher.default_bridge_recommended_type", "obfs4");
-
-// Default bridges.
-pref(
-  "extensions.torlauncher.default_bridge.obfs4.1",
-  "obfs4 192.95.36.142:443 CDF2E852BF539B82BD10E27E9115A31734E378C2 cert=qUVQ0srL1JI/vO6V6m/24anYXiJD3QP2HgzUKQtQ7GRqqUvs7P+tG43RtAqdhLOALP7DJQ iat-mode=1"
-);
-pref(
-  "extensions.torlauncher.default_bridge.obfs4.2",
-  "obfs4 37.218.245.14:38224 D9A82D2F9C2F65A18407B1D2B764F130847F8B5D cert=bjRaMrr1BRiAW8IE9U5z27fQaYgOhX1UCmOpg2pFpoMvo6ZgQMzLsaTzzQNTlm7hNcb+Sg iat-mode=0"
-);
-pref(
-  "extensions.torlauncher.default_bridge.obfs4.3",
-  "obfs4 85.31.186.98:443 011F2599C0E9B27EE74B353155E244813763C3E5 cert=ayq0XzCwhpdysn5o0EyDUbmSOx3X/oTEbzDMvczHOdBJKlvIdHHLJGkZARtT4dcBFArPPg iat-mode=0"
-);
-pref(
-  "extensions.torlauncher.default_bridge.obfs4.4",
-  "obfs4 85.31.186.26:443 91A6354697E6B02A386312F68D82CF86824D3606 cert=PBwr+S8JTVZo6MPdHnkTwXJPILWADLqfMGoVvhZClMq/Urndyd42BwX9YFJHZnBB3H0XCw iat-mode=0"
-);
-pref(
-  "extensions.torlauncher.default_bridge.obfs4.5",
-  "obfs4 193.11.166.194:27015 2D82C2E354D531A68469ADF7F878FA6060C6BACA cert=4TLQPJrTSaDffMK7Nbao6LC7G9OW/NHkUwIdjLSS3KYf0Nv4/nQiiI8dY2TcsQx01NniOg iat-mode=0"
-);
-pref(
-  "extensions.torlauncher.default_bridge.obfs4.6",
-  "obfs4 193.11.166.194:27020 86AC7B8D430DAC4117E9F42C9EAED18133863AAF cert=0LDeJH4JzMDtkJJrFphJCiPqKx7loozKN7VNfuukMGfHO0Z8OGdzHVkhVAOfo1mUdv9cMg iat-mode=0"
-);
-pref(
-  "extensions.torlauncher.default_bridge.obfs4.7",
-  "obfs4 193.11.166.194:27025 1AE2C08904527FEA90C4C4F8C1083EA59FBC6FAF cert=ItvYZzW5tn6v3G4UnQa6Qz04Npro6e81AP70YujmK/KXwDFPTs3aHXcHp4n8Vt6w/bv8cA iat-mode=0"
-);
-pref(
-  "extensions.torlauncher.default_bridge.obfs4.8",
-  "obfs4 209.148.46.65:443 74FAD13168806246602538555B5521A0383A1875 cert=ssH+9rP8dG2NLDN2XuFw63hIO/9MNNinLmxQDpVa+7kTOa9/m+tGWT1SmSYpQ9uTBGa6Hw iat-mode=0"
-);
-pref(
-  "extensions.torlauncher.default_bridge.obfs4.9",
-  "obfs4 146.57.248.225:22 10A6CD36A537FCE513A322361547444B393989F0 cert=K1gDtDAIcUfeLqbstggjIw2rtgIKqdIhUlHp82XRqNSq/mtAjp1BIC9vHKJ2FAEpGssTPw iat-mode=0"
-);
-pref(
-  "extensions.torlauncher.default_bridge.obfs4.10",
-  "obfs4 45.145.95.6:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0"
-);
-pref(
-  "extensions.torlauncher.default_bridge.obfs4.11",
-  "obfs4 51.222.13.177:80 5EDAC3B810E12B01F6FD8050D2FD3E277B289A08 cert=2uplIpLQ0q9+0qMFrK5pkaYRDOe460LL9WHBvatgkuRr/SL31wBOEupaMMJ6koRE6Ld0ew iat-mode=0"
-);
-
-pref(
-  "extensions.torlauncher.default_bridge.meek-azure.1",
-  "meek_lite 192.0.2.18:80 BE776A53492E1E044A26F17306E1BC46A55A1625 url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com"
-);
-
-pref(
-  "extensions.torlauncher.default_bridge.snowflake.1",
-  "snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72 fingerprint=2B280B23E1107BB62ABFC40DDCC8824814F80A72 url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=cdn.sstatic.net ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn"
-);
-
-pref(
-  "extensions.torlauncher.default_bridge.snowflake.2",
-  "snowflake 192.0.2.4:80 8838024498816A039FCBBAB14E6F40A0843051FA fingerprint=8838024498816A039FCBBAB14E6F40A0843051FA url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=cdn.sstatic.net ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.net:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn"
-);


=====================================
tools/torbrowser/deploy.sh
=====================================
@@ -6,17 +6,10 @@ BUILD_OUTPUT="$2"
 SCRIPT_DIR="$(realpath "$(dirname "$0")")"
 
 RESDIR="$BUILD_OUTPUT/dist/firefox"
-if [ "$(uname)" = "Darwin" ]; then 
+if [ "$(uname)" = "Darwin" ]; then
     RESDIR="$RESDIR/Tor Browser.app/Contents/Resources"
 fi
 
-# Add built-in bridges
-mkdir -p "$BUILD_OUTPUT/_omni/defaults/preferences"
-cat "$BUILD_OUTPUT/dist/bin/browser/defaults/preferences/000-tor-browser.js" "$SCRIPT_DIR/bridges.js" >> "$BUILD_OUTPUT/_omni/defaults/preferences/000-tor-browser.js"
-cd "$BUILD_OUTPUT/_omni"
-zip -Xmr "$RESDIR/browser/omni.ja" "defaults/preferences/000-tor-browser.js"
-rm -rf "$BUILD_OUTPUT/_omni"
-
 # Repackage the manual
 # rm -rf $BUILD_OUTPUT/_omni
 # mkdir $BUILD_OUTPUT/_omni
@@ -34,12 +27,12 @@ if [ "$(uname)" = "Darwin" ]; then
     cd "$BINARIES/Tor Browser.app/Contents/MacOS"
     "$SCRIPT_DIR/browser-self-sign-macos.sh"
 
-  else
+else
 
     # backup the startup script
     mv "$BINARIES/dev/Browser/firefox" "$BINARIES/dev/Browser/firefox.bak"
-    
-    # copy binaries 
+
+    # copy binaries
     cp -r "$RESDIR/"* "$BINARIES/dev/Browser"
     rm -rf "$BINARIES/dev/Browser/TorBrowser/Data/Browser/profile.default/startupCache"
 



View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/0d07d3a66cfa68372d5eeb8e8d78ddc7abe38004...7272b5541ce26e4f4fd4df09de9b430dfd6b27b0

-- 
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/0d07d3a66cfa68372d5eeb8e8d78ddc7abe38004...7272b5541ce26e4f4fd4df09de9b430dfd6b27b0
You're receiving this email because of your account on gitlab.torproject.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tor-commits/attachments/20240108/d5819ad7/attachment-0001.htm>


More information about the tor-commits mailing list