[tbb-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/tbb-commits/attachments/20240108/f597a59a/attachment-0001.htm>
More information about the tbb-commits
mailing list