[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [tor-browser] 03/05: squash! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
This is an automated email from the git hooks/post-receive script.
richard pushed a commit to branch tor-browser-91.8.0esr-11.5-1
in repository tor-browser.
commit 207037ff0a0f29a5c152e76649bc4024466be940
Author: Pier Angelo Vendrame <pierov@xxxxxxxxxxxxxx>
AuthorDate: Thu Feb 10 10:35:38 2022 +0100
squash! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
Bug 40774: Update about:preferences page to match new UI designs
---
browser/components/preferences/preferences.js | 10 +-
browser/components/preferences/preferences.xhtml | 5 +-
.../torpreferences/content/bridgeQrDialog.jsm | 51 +
.../torpreferences/content/bridgeQrDialog.xhtml | 23 +
.../torpreferences/content/builtinBridgeDialog.jsm | 142 +++
.../content/builtinBridgeDialog.xhtml | 43 +
...gory.inc.xhtml => connectionCategory.inc.xhtml} | 8 +-
.../torpreferences/content/connectionPane.js | 1315 ++++++++++++++++++++
.../torpreferences/content/connectionPane.xhtml | 177 +++
.../content/connectionSettingsDialog.jsm | 393 ++++++
.../content/connectionSettingsDialog.xhtml | 62 +
.../components/torpreferences/content/network.svg | 6 +
.../torpreferences/content/provideBridgeDialog.jsm | 69 +
.../content/provideBridgeDialog.xhtml | 21 +
.../torpreferences/content/requestBridgeDialog.jsm | 32 +-
.../content/requestBridgeDialog.xhtml | 10 +-
.../torpreferences/content/torLogDialog.jsm | 18 +
.../components/torpreferences/content/torPane.js | 940 --------------
.../torpreferences/content/torPane.xhtml | 157 ---
.../torpreferences/content/torPreferences.css | 394 +++++-
browser/components/torpreferences/jar.mn | 15 +-
21 files changed, 2739 insertions(+), 1152 deletions(-)
diff --git a/browser/components/preferences/preferences.js b/browser/components/preferences/preferences.js
index ce338584142ed..5981bcd38fc83 100644
--- a/browser/components/preferences/preferences.js
+++ b/browser/components/preferences/preferences.js
@@ -13,7 +13,7 @@
/* import-globals-from findInPage.js */
/* import-globals-from ../../base/content/utilityOverlay.js */
/* import-globals-from ../../../toolkit/content/preferencesBindings.js */
-/* import-globals-from ../torpreferences/content/torPane.js */
+/* import-globals-from ../torpreferences/content/connectionPane.js */
"use strict";
@@ -137,12 +137,12 @@ function init_all() {
register_module("paneSync", gSyncPane);
}
register_module("paneSearchResults", gSearchResultsPane);
- if (gTorPane.enabled) {
- document.getElementById("category-tor").hidden = false;
- register_module("paneTor", gTorPane);
+ if (gConnectionPane.enabled) {
+ document.getElementById("category-connection").hidden = false;
+ register_module("paneConnection", gConnectionPane);
} else {
// Remove the pane from the DOM so it doesn't get incorrectly included in search results.
- document.getElementById("template-paneTor").remove();
+ document.getElementById("template-paneConnection").remove();
}
gSearchResultsPane.init();
diff --git a/browser/components/preferences/preferences.xhtml b/browser/components/preferences/preferences.xhtml
index 07ab5cc7b626d..30ce70079adb7 100644
--- a/browser/components/preferences/preferences.xhtml
+++ b/browser/components/preferences/preferences.xhtml
@@ -6,6 +6,7 @@
<?xml-stylesheet href="chrome://global/skin/global.css"?>
<?xml-stylesheet href="chrome://global/skin/in-content/common.css"?>
+<?xml-stylesheet href="chrome://global/skin/in-content/toggle-button.css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
<?xml-stylesheet href="chrome://browser/content/preferences/dialogs/handlers.css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/applications.css"?>
@@ -158,7 +159,7 @@
<label class="category-name" flex="1" data-l10n-id="pane-experimental-title"></label>
</richlistitem>
-#include ../torpreferences/content/torCategory.inc.xhtml
+#include ../torpreferences/content/connectionCategory.inc.xhtml
</richlistbox>
@@ -213,7 +214,7 @@
#include containers.inc.xhtml
#include sync.inc.xhtml
#include experimental.inc.xhtml
-#include ../torpreferences/content/torPane.xhtml
+#include ../torpreferences/content/connectionPane.xhtml
</vbox>
</vbox>
</vbox>
diff --git a/browser/components/torpreferences/content/bridgeQrDialog.jsm b/browser/components/torpreferences/content/bridgeQrDialog.jsm
new file mode 100644
index 0000000000000..e63347742ea50
--- /dev/null
+++ b/browser/components/torpreferences/content/bridgeQrDialog.jsm
@@ -0,0 +1,51 @@
+"use strict";
+
+var EXPORTED_SYMBOLS = ["BridgeQrDialog"];
+
+const { QRCode } = ChromeUtils.import("resource://gre/modules/QRCode.jsm");
+
+const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm");
+
+class BridgeQrDialog {
+ constructor() {
+ this._bridgeString = "";
+ }
+
+ static get selectors() {
+ return {
+ target: "#bridgeQr-target",
+ };
+ }
+
+ _populateXUL(window, dialog) {
+ dialog.parentElement.setAttribute("title", TorStrings.settings.scanQrTitle);
+ const target = dialog.querySelector(BridgeQrDialog.selectors.target);
+ const style = window.getComputedStyle(target);
+ const width = style.width.substr(0, style.width.length - 2);
+ const height = style.height.substr(0, style.height.length - 2);
+ new QRCode(target, {
+ text: this._bridgeString,
+ width,
+ height,
+ colorDark: style.color,
+ colorLight: style.backgroundColor,
+ document: window.document,
+ });
+ }
+
+ init(window, dialog) {
+ // Defer to later until Firefox has populated the dialog with all our elements
+ window.setTimeout(() => {
+ this._populateXUL(window, dialog);
+ }, 0);
+ }
+
+ openDialog(gSubDialog, bridgeString) {
+ this._bridgeString = bridgeString;
+ gSubDialog.open(
+ "chrome://browser/content/torpreferences/bridgeQrDialog.xhtml",
+ { features: "resizable=yes" },
+ this
+ );
+ }
+}
diff --git a/browser/components/torpreferences/content/bridgeQrDialog.xhtml b/browser/components/torpreferences/content/bridgeQrDialog.xhtml
new file mode 100644
index 0000000000000..2a49e4c0e7d9e
--- /dev/null
+++ b/browser/components/torpreferences/content/bridgeQrDialog.xhtml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
+<?xml-stylesheet href="chrome://browser/content/torpreferences/torPreferences.css"?>
+
+<window type="child"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+<dialog id="bridgeQr-dialog" buttons="accept">
+ <html:div id="bridgeQr-container">
+ <html:div id="bridgeQr-target"/>
+ <html:div id="bridgeQr-onionBox"/>
+ <html:div id="bridgeQr-onion"/>
+ </html:div>
+ <script type="application/javascript"><![CDATA[
+ "use strict";
+
+ let dialogObject = window.arguments[0];
+ let dialogElement = document.getElementById("bridgeQr-dialog");
+ dialogObject.init(window, dialogElement);
+ ]]></script>
+</dialog>
+</window>
diff --git a/browser/components/torpreferences/content/builtinBridgeDialog.jsm b/browser/components/torpreferences/content/builtinBridgeDialog.jsm
new file mode 100644
index 0000000000000..1d4dda8f5ca9c
--- /dev/null
+++ b/browser/components/torpreferences/content/builtinBridgeDialog.jsm
@@ -0,0 +1,142 @@
+"use strict";
+
+var EXPORTED_SYMBOLS = ["BuiltinBridgeDialog"];
+
+const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm");
+
+const {
+ TorSettings,
+ TorBridgeSource,
+ TorBuiltinBridgeTypes,
+} = ChromeUtils.import("resource:///modules/TorSettings.jsm");
+
+class BuiltinBridgeDialog {
+ constructor() {
+ this._dialog = null;
+ this._bridgeType = "";
+ this._windowPadding = 0;
+ }
+
+ static get selectors() {
+ return {
+ header: "#torPreferences-builtinBridge-header",
+ description: "#torPreferences-builtinBridge-description",
+ radiogroup: "#torPreferences-builtinBridge-typeSelection",
+ obfsRadio: "#torPreferences-builtinBridges-radioObfs",
+ obfsDescr: "#torPreferences-builtinBridges-descrObfs",
+ snowflakeRadio: "#torPreferences-builtinBridges-radioSnowflake",
+ snowflakeDescr: "#torPreferences-builtinBridges-descrSnowflake",
+ meekAzureRadio: "#torPreferences-builtinBridges-radioMeekAzure",
+ meekAzureDescr: "#torPreferences-builtinBridges-descrMeekAzure",
+ };
+ }
+
+ _populateXUL(window, aDialog) {
+ const selectors = BuiltinBridgeDialog.selectors;
+
+ this._dialog = aDialog;
+ const dialogWin = this._dialog.parentElement;
+ {
+ dialogWin.setAttribute("title", TorStrings.settings.builtinBridgeTitle);
+ let windowStyle = window.getComputedStyle(dialogWin);
+ this._windowPadding =
+ parseFloat(windowStyle.paddingLeft) +
+ parseFloat(windowStyle.paddingRight);
+ }
+ const initialWidth = dialogWin.clientWidth - this._windowPadding;
+
+ this._dialog.querySelector(selectors.header).textContent =
+ TorStrings.settings.builtinBridgeHeader;
+ this._dialog.querySelector(selectors.description).textContent =
+ TorStrings.settings.builtinBridgeDescription;
+ let radioGroup = this._dialog.querySelector(selectors.radiogroup);
+
+ let types = {
+ obfs4: {
+ elemRadio: this._dialog.querySelector(selectors.obfsRadio),
+ elemDescr: this._dialog.querySelector(selectors.obfsDescr),
+ label: TorStrings.settings.builtinBridgeObfs4,
+ descr: TorStrings.settings.builtinBridgeObfs4Description,
+ },
+ snowflake: {
+ elemRadio: this._dialog.querySelector(selectors.snowflakeRadio),
+ elemDescr: this._dialog.querySelector(selectors.snowflakeDescr),
+ label: TorStrings.settings.builtinBridgeSnowflake,
+ descr: TorStrings.settings.builtinBridgeSnowflakeDescription,
+ },
+ "meek-azure": {
+ elemRadio: this._dialog.querySelector(selectors.meekAzureRadio),
+ elemDescr: this._dialog.querySelector(selectors.meekAzureDescr),
+ label: TorStrings.settings.builtinBridgeMeekAzure,
+ descr: TorStrings.settings.builtinBridgeMeekAzureDescription,
+ },
+ };
+
+ TorBuiltinBridgeTypes.forEach(type => {
+ types[type].elemRadio.parentElement.setAttribute("hidden", "false");
+ types[type].elemDescr.parentElement.setAttribute("hidden", "false");
+ types[type].elemRadio.setAttribute("label", types[type].label);
+ types[type].elemDescr.textContent = types[type].descr;
+ });
+
+ if (
+ TorSettings.bridges.enabled &&
+ TorSettings.bridges.source == TorBridgeSource.BuiltIn
+ ) {
+ radioGroup.selectedItem =
+ types[TorSettings.bridges.builtin_type]?.elemRadio;
+ this._bridgeType = TorSettings.bridges.builtin_type;
+ } else {
+ radioGroup.selectedItem = null;
+ this._bridgeType = "";
+ }
+
+ // Use the initial width, because the window is expanded when we add texts
+ this.resized(initialWidth);
+
+ this._dialog.addEventListener("dialogaccept", e => {
+ this._bridgeType = radioGroup.value;
+ });
+ this._dialog.addEventListener("dialoghelp", e => {
+ window.top.openTrustedLinkIn(
+ "https://tb-manual.torproject.org/circumvention/",
+ "tab"
+ );
+ });
+ }
+
+ resized(width) {
+ if (this._dialog === null) {
+ return;
+ }
+ const dialogWin = this._dialog.parentElement;
+ if (width === undefined) {
+ width = dialogWin.clientWidth - this._windowPadding;
+ }
+ let windowPos = dialogWin.getBoundingClientRect();
+ dialogWin.querySelectorAll("div").forEach(div => {
+ let divPos = div.getBoundingClientRect();
+ div.style.width = width - (divPos.left - windowPos.left) + "px";
+ });
+ }
+
+ init(window, aDialog) {
+ // defer to later until firefox has populated the dialog with all our elements
+ window.setTimeout(() => {
+ this._populateXUL(window, aDialog);
+ }, 0);
+ }
+
+ openDialog(gSubDialog, aCloseCallback) {
+ gSubDialog.open(
+ "chrome://browser/content/torpreferences/builtinBridgeDialog.xhtml",
+ {
+ features: "resizable=yes",
+ closingCallback: () => {
+ aCloseCallback(this._bridgeType);
+ },
+ },
+ this
+ );
+ }
+}
diff --git a/browser/components/torpreferences/content/builtinBridgeDialog.xhtml b/browser/components/torpreferences/content/builtinBridgeDialog.xhtml
new file mode 100644
index 0000000000000..c1bf202ca1be5
--- /dev/null
+++ b/browser/components/torpreferences/content/builtinBridgeDialog.xhtml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
+<?xml-stylesheet href="chrome://browser/content/torpreferences/torPreferences.css"?>
+
+<window type="child"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+<dialog id="torPreferences-builtinBridge-dialog"
+ buttons="help,accept,cancel">
+ <html:h3 id="torPreferences-builtinBridge-header">​</html:h3>
+ <description>
+ <html:div id="torPreferences-builtinBridge-description">​<br/>​</html:div>
+ </description>
+ <radiogroup id="torPreferences-builtinBridge-typeSelection">
+ <hbox hidden="true">
+ <radio id="torPreferences-builtinBridges-radioObfs" value="obfs4"/>
+ </hbox>
+ <hbox hidden="true" class="indent">
+ <html:div id="torPreferences-builtinBridges-descrObfs"></html:div>
+ </hbox>
+ <hbox hidden="true">
+ <radio id="torPreferences-builtinBridges-radioSnowflake" value="snowflake"/>
+ </hbox>
+ <hbox hidden="true" class="indent">
+ <html:div id="torPreferences-builtinBridges-descrSnowflake"></html:div>
+ </hbox>
+ <hbox hidden="true">
+ <radio id="torPreferences-builtinBridges-radioMeekAzure" value="meek-azure"/>
+ </hbox>
+ <hbox hidden="true" class="indent">
+ <html:div id="torPreferences-builtinBridges-descrMeekAzure"></html:div>
+ </hbox>
+ </radiogroup>
+ <script type="application/javascript"><![CDATA[
+ "use strict";
+
+ let builtinBridgeDialog = window.arguments[0];
+ let dialog = document.getElementById("torPreferences-builtinBridge-dialog");
+ builtinBridgeDialog.init(window, dialog);
+ ]]></script>
+</dialog>
+</window>
diff --git a/browser/components/torpreferences/content/torCategory.inc.xhtml b/browser/components/torpreferences/content/connectionCategory.inc.xhtml
similarity index 57%
rename from browser/components/torpreferences/content/torCategory.inc.xhtml
rename to browser/components/torpreferences/content/connectionCategory.inc.xhtml
index abe56200f571b..15cf24cfe6950 100644
--- a/browser/components/torpreferences/content/torCategory.inc.xhtml
+++ b/browser/components/torpreferences/content/connectionCategory.inc.xhtml
@@ -1,9 +1,9 @@
-<richlistitem id="category-tor"
+<richlistitem id="category-connection"
class="category"
- value="paneTor"
- helpTopic="prefs-tor"
+ value="paneConnection"
+ helpTopic="prefs-connection"
align="center"
hidden="true">
<image class="category-icon"/>
- <label id="torPreferences-labelCategory" class="category-name" flex="1" value="Tor"/>
+ <label id="torPreferences-labelCategory" class="category-name" flex="1" value="Connection"/>
</richlistitem>
diff --git a/browser/components/torpreferences/content/connectionPane.js b/browser/components/torpreferences/content/connectionPane.js
new file mode 100644
index 0000000000000..309d6498a0c80
--- /dev/null
+++ b/browser/components/torpreferences/content/connectionPane.js
@@ -0,0 +1,1315 @@
+"use strict";
+
+/* global Services, gSubDialog */
+
+const { setTimeout, clearTimeout } = ChromeUtils.import(
+ "resource://gre/modules/Timer.jsm"
+);
+
+const {
+ TorSettings,
+ TorSettingsTopics,
+ TorSettingsData,
+ TorBridgeSource,
+} = ChromeUtils.import("resource:///modules/TorSettings.jsm");
+
+const { TorProtocolService } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+);
+
+const {
+ TorConnect,
+ TorConnectTopics,
+ TorConnectState,
+ TorCensorshipLevel,
+} = ChromeUtils.import("resource:///modules/TorConnect.jsm");
+
+const { TorLogDialog } = ChromeUtils.import(
+ "chrome://browser/content/torpreferences/torLogDialog.jsm"
+);
+
+const { ConnectionSettingsDialog } = ChromeUtils.import(
+ "chrome://browser/content/torpreferences/connectionSettingsDialog.jsm"
+);
+
+const { BridgeQrDialog } = ChromeUtils.import(
+ "chrome://browser/content/torpreferences/bridgeQrDialog.jsm"
+);
+
+const { BuiltinBridgeDialog } = ChromeUtils.import(
+ "chrome://browser/content/torpreferences/builtinBridgeDialog.jsm"
+);
+
+const { RequestBridgeDialog } = ChromeUtils.import(
+ "chrome://browser/content/torpreferences/requestBridgeDialog.jsm"
+);
+
+const { ProvideBridgeDialog } = ChromeUtils.import(
+ "chrome://browser/content/torpreferences/provideBridgeDialog.jsm"
+);
+
+const { MoatRPC } = ChromeUtils.import("resource:///modules/Moat.jsm");
+
+const { QRCode } = ChromeUtils.import("resource://gre/modules/QRCode.jsm");
+
+ChromeUtils.defineModuleGetter(
+ this,
+ "TorStrings",
+ "resource:///modules/TorStrings.jsm"
+);
+
+const InternetStatus = Object.freeze({
+ Unknown: 0,
+ Online: 1,
+ Offline: -1,
+});
+
+/*
+ Connection Pane
+
+ Code for populating the XUL in about:preferences#connection, handling input events, interfacing with tor-launcher
+*/
+const gConnectionPane = (function() {
+ /* CSS selectors for all of the Tor Network DOM elements we need to access */
+ const selectors = {
+ category: {
+ title: "label#torPreferences-labelCategory",
+ },
+ messageBox: {
+ box: "div#torPreferences-connectMessageBox",
+ message: "td#torPreferences-connectMessageBox-message",
+ button: "button#torPreferences-connectMessageBox-button",
+ },
+ torPreferences: {
+ header: "h1#torPreferences-header",
+ description: "span#torPreferences-description",
+ learnMore: "label#torPreferences-learnMore",
+ },
+ status: {
+ internetLabel: "#torPreferences-status-internet-label",
+ internetTest: "#torPreferences-status-internet-test",
+ internetIcon: "#torPreferences-status-internet-statusIcon",
+ internetStatus: "#torPreferences-status-internet-status",
+ torLabel: "#torPreferences-status-tor-label",
+ torIcon: "#torPreferences-status-tor-statusIcon",
+ torStatus: "#torPreferences-status-tor-status",
+ },
+ quickstart: {
+ header: "h2#torPreferences-quickstart-header",
+ description: "span#torPreferences-quickstart-description",
+ enableQuickstartCheckbox: "checkbox#torPreferences-quickstart-toggle",
+ },
+ bridges: {
+ header: "h1#torPreferences-bridges-header",
+ description: "span#torPreferences-bridges-description",
+ learnMore: "label#torPreferences-bridges-learnMore",
+ locationGroup: "#torPreferences-bridges-locationGroup",
+ locationLabel: "#torPreferences-bridges-locationLabel",
+ location: "#torPreferences-bridges-location",
+ locationEntries: "#torPreferences-bridges-locationEntries",
+ chooseForMe: "#torPreferences-bridges-buttonChooseBridgeForMe",
+ currentHeader: "#torPreferences-currentBridges-header",
+ currentHeaderText: "#torPreferences-currentBridges-headerText",
+ switch: "#torPreferences-currentBridges-switch",
+ cards: "#torPreferences-currentBridges-cards",
+ cardTemplate: "#torPreferences-bridgeCard-template",
+ card: ".torPreferences-bridgeCard",
+ cardId: ".torPreferences-bridgeCard-id",
+ cardHeadingAddr: ".torPreferences-bridgeCard-headingAddr",
+ cardConnectedLabel: ".torPreferences-bridgeCard-connectedLabel",
+ cardOptions: ".torPreferences-bridgeCard-options",
+ cardMenu: "#torPreferences-bridgeCard-menu",
+ cardQrGrid: ".torPreferences-bridgeCard-grid",
+ cardQrContainer: ".torPreferences-bridgeCard-qr",
+ cardQr: ".torPreferences-bridgeCard-qrCode",
+ cardShare: ".torPreferences-bridgeCard-share",
+ cardAddr: ".torPreferences-bridgeCard-addr",
+ cardLearnMore: ".torPreferences-bridgeCard-learnMore",
+ cardCopy: ".torPreferences-bridgeCard-copyButton",
+ showAll: "#torPreferences-currentBridges-showAll",
+ removeAll: "#torPreferences-currentBridges-removeAll",
+ addHeader: "#torPreferences-addBridge-header",
+ addBuiltinLabel: "#torPreferences-addBridge-labelBuiltinBridge",
+ addBuiltinButton: "#torPreferences-addBridge-buttonBuiltinBridge",
+ requestLabel: "#torPreferences-addBridge-labelRequestBridge",
+ requestButton: "#torPreferences-addBridge-buttonRequestBridge",
+ enterLabel: "#torPreferences-addBridge-labelEnterBridge",
+ enterButton: "#torPreferences-addBridge-buttonEnterBridge",
+ },
+ advanced: {
+ header: "h1#torPreferences-advanced-header",
+ label: "#torPreferences-advanced-label",
+ button: "#torPreferences-advanced-button",
+ torLogsLabel: "label#torPreferences-torLogs",
+ torLogsButton: "button#torPreferences-buttonTorLogs",
+ },
+ }; /* selectors */
+
+ let retval = {
+ // cached frequently accessed DOM elements
+ _enableQuickstartCheckbox: null,
+
+ _internetStatus: InternetStatus.Unknown,
+
+ _controller: null,
+
+ _currentBridge: "",
+
+ // disables the provided list of elements
+ _setElementsDisabled(elements, disabled) {
+ for (let currentElement of elements) {
+ currentElement.disabled = disabled;
+ }
+ },
+
+ // populate xul with strings and cache the relevant elements
+ _populateXUL() {
+ // saves tor settings to disk when navigate away from about:preferences
+ window.addEventListener("blur", val => {
+ TorProtocolService.flushSettings();
+ });
+
+ document
+ .querySelector(selectors.category.title)
+ .setAttribute("value", TorStrings.settings.categoryTitle);
+
+ let prefpane = document.getElementById("mainPrefPane");
+
+ // 'Connect to Tor' Message Bar
+
+ const messageBox = prefpane.querySelector(selectors.messageBox.box);
+ const messageBoxMessage = prefpane.querySelector(
+ selectors.messageBox.message
+ );
+ const messageBoxButton = prefpane.querySelector(
+ selectors.messageBox.button
+ );
+ // wire up connect button
+ messageBoxButton.addEventListener("click", () => {
+ TorConnect.beginBootstrap();
+ TorConnect.openTorConnect();
+ });
+
+ this._populateMessagebox = () => {
+ if (
+ TorConnect.shouldShowTorConnect &&
+ TorConnect.state === TorConnectState.Configuring
+ ) {
+ // set messagebox style and text
+ if (TorProtocolService.torBootstrapErrorOccurred()) {
+ messageBox.parentNode.style.display = null;
+ messageBox.className = "error";
+ messageBoxMessage.innerText = TorStrings.torConnect.tryAgainMessage;
+ messageBoxButton.innerText = TorStrings.torConnect.tryAgain;
+ } else {
+ messageBox.parentNode.style.display = null;
+ messageBox.className = "warning";
+ messageBoxMessage.innerText = TorStrings.torConnect.connectMessage;
+ messageBoxButton.innerText = TorStrings.torConnect.torConnectButton;
+ }
+ } else {
+ // we need to explicitly hide the groupbox, as switching between
+ // the tor pane and other panes will 'unhide' (via the 'hidden'
+ // attribute) the groupbox, offsetting all of the content down
+ // by the groupbox's margin (even if content is 0 height)
+ messageBox.parentNode.style.display = "none";
+ messageBox.className = "hidden";
+ messageBoxMessage.innerText = "";
+ messageBoxButton.innerText = "";
+ }
+ };
+ this._populateMessagebox();
+
+ // Heading
+ prefpane.querySelector(selectors.torPreferences.header).innerText =
+ TorStrings.settings.categoryTitle;
+ prefpane.querySelector(selectors.torPreferences.description).textContent =
+ TorStrings.settings.torPreferencesDescription;
+ {
+ let learnMore = prefpane.querySelector(
+ selectors.torPreferences.learnMore
+ );
+ learnMore.setAttribute("value", TorStrings.settings.learnMore);
+ learnMore.setAttribute(
+ "href",
+ TorStrings.settings.learnMoreTorBrowserURL
+ );
+ }
+
+ // Internet and Tor status
+ prefpane.querySelector(selectors.status.internetLabel).textContent =
+ TorStrings.settings.statusInternetLabel;
+ prefpane.querySelector(selectors.status.torLabel).textContent =
+ TorStrings.settings.statusTorLabel;
+ const internetTest = prefpane.querySelector(
+ selectors.status.internetTest
+ );
+ internetTest.setAttribute(
+ "label",
+ TorStrings.settings.statusInternetTest
+ );
+ internetTest.addEventListener("command", async () => {
+ this.onInternetTest();
+ });
+ const internetIcon = prefpane.querySelector(
+ selectors.status.internetIcon
+ );
+ const internetStatus = prefpane.querySelector(
+ selectors.status.internetStatus
+ );
+ const torIcon = prefpane.querySelector(selectors.status.torIcon);
+ const torStatus = prefpane.querySelector(selectors.status.torStatus);
+ this._populateStatus = () => {
+ switch (this._internetStatus) {
+ case InternetStatus.Unknown:
+ internetTest.removeAttribute("hidden");
+ break;
+ case InternetStatus.Online:
+ internetTest.setAttribute("hidden", "true");
+ internetIcon.className = "online";
+ internetStatus.textContent =
+ TorStrings.settings.statusInternetOnline;
+ break;
+ case InternetStatus.Offline:
+ internetTest.setAttribute("hidden", "true");
+ internetIcon.className = "offline";
+ internetStatus.textContent =
+ TorStrings.settings.statusInternetOffline;
+ break;
+ }
+ if (TorConnect.state === TorConnectState.Bootstrapped) {
+ torIcon.className = "connected";
+ torStatus.textContent = TorStrings.settings.statusTorConnected;
+ } else if (
+ TorConnect.detectedCensorshipLevel > TorCensorshipLevel.None
+ ) {
+ torIcon.className = "blocked";
+ torStatus.textContent = TorStrings.settings.statusTorBlocked;
+ } else {
+ torIcon.className = "";
+ torStatus.textContent = TorStrings.settings.statusTorNotConnected;
+ }
+ };
+ this._populateStatus();
+
+ // Quickstart
+ prefpane.querySelector(selectors.quickstart.header).innerText =
+ TorStrings.settings.quickstartHeading;
+ prefpane.querySelector(selectors.quickstart.description).textContent =
+ TorStrings.settings.quickstartDescription;
+
+ this._enableQuickstartCheckbox = prefpane.querySelector(
+ selectors.quickstart.enableQuickstartCheckbox
+ );
+ this._enableQuickstartCheckbox.setAttribute(
+ "label",
+ TorStrings.settings.quickstartCheckbox
+ );
+ this._enableQuickstartCheckbox.addEventListener("command", e => {
+ const checked = this._enableQuickstartCheckbox.checked;
+ TorSettings.quickstart.enabled = checked;
+ TorSettings.saveToPrefs().applySettings();
+ });
+ this._enableQuickstartCheckbox.checked = TorSettings.quickstart.enabled;
+ Services.obs.addObserver(this, TorSettingsTopics.SettingChanged);
+
+ // Bridge setup
+ prefpane.querySelector(selectors.bridges.header).innerText =
+ TorStrings.settings.bridgesHeading;
+ prefpane.querySelector(selectors.bridges.description).textContent =
+ TorStrings.settings.bridgesDescription;
+ {
+ let learnMore = prefpane.querySelector(selectors.bridges.learnMore);
+ learnMore.setAttribute("value", TorStrings.settings.learnMore);
+ learnMore.setAttribute("href", TorStrings.settings.learnMoreBridgesURL);
+ }
+
+ // Location
+ {
+ const locationGroup = prefpane.querySelector(
+ selectors.bridges.locationGroup
+ );
+ prefpane.querySelector(selectors.bridges.locationLabel).textContent =
+ TorStrings.settings.bridgeLocation;
+ const location = prefpane.querySelector(selectors.bridges.location);
+ const locationEntries = prefpane.querySelector(
+ selectors.bridges.locationEntries
+ );
+ const chooseForMe = prefpane.querySelector(
+ selectors.bridges.chooseForMe
+ );
+ chooseForMe.setAttribute(
+ "label",
+ TorStrings.settings.bridgeChooseForMe
+ );
+ chooseForMe.addEventListener("command", e => {
+ TorConnect.beginAutoBootstrap(location.value);
+ });
+ this._populateLocations = () => {
+ let value = location.value;
+ locationEntries.textContent = "";
+
+ {
+ const item = document.createXULElement("menuitem");
+ item.setAttribute("value", "");
+ item.setAttribute(
+ "label",
+ TorStrings.settings.bridgeLocationAutomatic
+ );
+ locationEntries.appendChild(item);
+ }
+
+ const codes = TorConnect.countryCodes;
+ const items = codes.map(code => {
+ const item = document.createXULElement("menuitem");
+ item.setAttribute("value", code);
+ item.setAttribute(
+ "label",
+ TorConnect.countryNames[code]
+ ? TorConnect.countryNames[code]
+ : code
+ );
+ return item;
+ });
+ items.sort((left, right) =>
+ left.textContent.localeCompare(right.textContent)
+ );
+ locationEntries.append(...items);
+ location.value = value;
+ };
+ this._showAutoconfiguration = () => {
+ if (
+ !TorConnect.shouldShowTorConnect ||
+ !TorProtocolService.torBootstrapErrorOccurred()
+ ) {
+ locationGroup.setAttribute("hidden", "true");
+ return;
+ }
+ // Populate locations, even though we will show only the automatic
+ // item for a moment. In my opinion showing the button immediately is
+ // better then waiting for the Moat query to finish (after a while)
+ // and showing the controls only after that.
+ this._populateLocations();
+ locationGroup.removeAttribute("hidden");
+ if (!TorConnect.countryCodes.length) {
+ TorConnect.getCountryCodes().then(() => this._populateLocations());
+ }
+ };
+ this._showAutoconfiguration();
+ }
+
+ // Bridge cards
+ const bridgeHeader = prefpane.querySelector(
+ selectors.bridges.currentHeader
+ );
+ bridgeHeader.querySelector(
+ selectors.bridges.currentHeaderText
+ ).textContent = TorStrings.settings.bridgeCurrent;
+ const bridgeSwitch = bridgeHeader.querySelector(selectors.bridges.switch);
+ bridgeSwitch.addEventListener("change", () => {
+ TorSettings.bridges.enabled = bridgeSwitch.checked;
+ TorSettings.saveToPrefs();
+ TorSettings.applySettings().then(result => {
+ this._populateBridgeCards();
+ });
+ });
+ const bridgeTemplate = prefpane.querySelector(
+ selectors.bridges.cardTemplate
+ );
+ {
+ const learnMore = bridgeTemplate.querySelector(
+ selectors.bridges.cardLearnMore
+ );
+ learnMore.setAttribute("value", TorStrings.settings.learnMore);
+ learnMore.setAttribute("href", "about:blank");
+ }
+ bridgeTemplate.querySelector(
+ selectors.bridges.cardConnectedLabel
+ ).textContent = TorStrings.settings.statusTorConnected;
+ bridgeTemplate
+ .querySelector(selectors.bridges.cardCopy)
+ .setAttribute("label", TorStrings.settings.bridgeCopy);
+ bridgeTemplate.querySelector(selectors.bridges.cardShare).textContent =
+ TorStrings.settings.bridgeShare;
+ const bridgeCards = prefpane.querySelector(selectors.bridges.cards);
+ const bridgeMenu = prefpane.querySelector(selectors.bridges.cardMenu);
+
+ this._addBridgeCard = bridgeString => {
+ const card = bridgeTemplate.cloneNode(true);
+ card.removeAttribute("id");
+ const grid = card.querySelector(selectors.bridges.cardQrGrid);
+ card.addEventListener("click", e => {
+ let target = e.target;
+ let apply = true;
+ while (target !== null && target !== card && apply) {
+ // Deal with mixture of "command" and "click" events
+ apply = !target.classList?.contains("stop-click");
+ target = target.parentElement;
+ }
+ if (apply) {
+ if (card.classList.toggle("expanded")) {
+ grid.classList.add("to-animate");
+ grid.style.height = `${grid.scrollHeight}px`;
+ } else {
+ // Be sure we still have the to-animate class
+ grid.classList.add("to-animate");
+ grid.style.height = "";
+ }
+ }
+ });
+ const emojis = makeBridgeId(bridgeString).map(e => {
+ const span = document.createElement("span");
+ span.className = "emoji";
+ span.textContent = e;
+ return span;
+ });
+ const idString = TorStrings.settings.bridgeId;
+ const id = card.querySelector(selectors.bridges.cardId);
+ const details = parseBridgeLine(bridgeString);
+ if (details && details.id !== undefined) {
+ card.setAttribute("data-bridge-id", details.id);
+ }
+ // TODO: properly handle "vanilla" bridges?
+ const type =
+ details && details.transport !== undefined
+ ? details.transport
+ : "vanilla";
+ for (const piece of idString.split(/(#[12])/)) {
+ if (piece == "#1") {
+ id.append(type);
+ } else if (piece == "#2") {
+ id.append(...emojis);
+ } else {
+ id.append(piece);
+ }
+ }
+ card.querySelector(
+ selectors.bridges.cardHeadingAddr
+ ).textContent = bridgeString;
+ const optionsButton = card.querySelector(selectors.bridges.cardOptions);
+ if (TorSettings.bridges.source === TorBridgeSource.BuiltIn) {
+ optionsButton.setAttribute("hidden", "true");
+ } else {
+ // Cloning the menupopup element does not work as expected.
+ // Therefore, we use only one, and just before opening it, we remove
+ // its previous items, and add the ones relative to the bridge whose
+ // button has been pressed.
+ optionsButton.addEventListener("click", () => {
+ const menuItem = document.createXULElement("menuitem");
+ menuItem.setAttribute("label", TorStrings.settings.remove);
+ menuItem.classList.add("menuitem-iconic");
+ menuItem.image = "chrome://global/skin/icons/delete.svg";
+ menuItem.addEventListener("command", e => {
+ const strings = TorSettings.bridges.bridge_strings;
+ const index = strings.indexOf(bridgeString);
+ if (index !== -1) {
+ strings.splice(index, 1);
+ }
+ TorSettings.bridges.enabled =
+ bridgeSwitch.checked && !!strings.length;
+ TorSettings.bridges.bridge_strings = strings.join("\n");
+ TorSettings.saveToPrefs();
+ TorSettings.applySettings().then(result => {
+ this._populateBridgeCards();
+ });
+ });
+ if (bridgeMenu.firstChild) {
+ bridgeMenu.firstChild.remove();
+ }
+ bridgeMenu.append(menuItem);
+ bridgeMenu.openPopup(optionsButton, {
+ position: "bottomleft topleft",
+ });
+ });
+ }
+ const bridgeAddr = card.querySelector(selectors.bridges.cardAddr);
+ bridgeAddr.setAttribute("value", bridgeString);
+ const bridgeCopy = card.querySelector(selectors.bridges.cardCopy);
+ let restoreTimeout = null;
+ bridgeCopy.addEventListener("command", e => {
+ this.onCopyBridgeAddress(bridgeAddr);
+ const label = bridgeCopy.querySelector("label");
+ label.setAttribute("value", TorStrings.settings.copied);
+ bridgeCopy.classList.add("primary");
+
+ const RESTORE_TIME = 1200;
+ if (restoreTimeout !== null) {
+ clearTimeout(restoreTimeout);
+ }
+ restoreTimeout = setTimeout(() => {
+ label.setAttribute("value", TorStrings.settings.bridgeCopy);
+ bridgeCopy.classList.remove("primary");
+ restoreTimeout = null;
+ }, RESTORE_TIME);
+ });
+ if (details && details.id === this._currentBridge) {
+ card.classList.add("currently-connected");
+ bridgeCards.prepend(card);
+ } else {
+ bridgeCards.append(card);
+ }
+ // Add the QR only after appending the card, to have the computed style
+ try {
+ const container = card.querySelector(selectors.bridges.cardQr);
+ const style = getComputedStyle(container);
+ const width = style.width.substr(0, style.width.length - 2);
+ const height = style.height.substr(0, style.height.length - 2);
+ new QRCode(container, {
+ text: bridgeString,
+ width,
+ height,
+ colorDark: style.color,
+ colorLight: style.backgroundColor,
+ document,
+ });
+ container.parentElement.addEventListener("click", () => {
+ this.onShowQr(bridgeString);
+ });
+ } catch (err) {
+ // TODO: Add a generic image in case of errors such as code overflow.
+ // It should never happen with correct codes, but after all this
+ // content can be generated by users...
+ console.error("Could not generate the QR code for the bridge:", err);
+ }
+ };
+ this._checkBridgeCardsHeight = () => {
+ for (const card of bridgeCards.children) {
+ // Expanded cards have the height set manually to their details for
+ // the CSS animation. However, when resizing the window, we may need
+ // to adjust their height.
+ if (card.classList.contains("expanded")) {
+ const grid = card.querySelector(selectors.bridges.cardQrGrid);
+ // Reset it first, to avoid having a height that is higher than
+ // strictly needed. Also, remove the to-animate class, because the
+ // animation interferes with this process!
+ grid.classList.remove("to-animate");
+ grid.style.height = "";
+ grid.style.height = `${grid.scrollHeight}px`;
+ }
+ }
+ };
+ this._currentBridgesExpanded = false;
+ const showAll = prefpane.querySelector(selectors.bridges.showAll);
+ showAll.setAttribute("label", TorStrings.settings.bridgeShowAll);
+ showAll.addEventListener("command", () => {
+ this._currentBridgesExpanded = true;
+ this._populateBridgeCards();
+ });
+ const removeAll = prefpane.querySelector(selectors.bridges.removeAll);
+ removeAll.setAttribute("label", TorStrings.settings.bridgeRemoveAll);
+ removeAll.addEventListener("command", () => {
+ this.onRemoveAllBridges();
+ });
+ this._populateBridgeCards = async () => {
+ const collapseThreshold = 4;
+
+ let newStrings = new Set(TorSettings.bridges.bridge_strings);
+ const numBridges = newStrings.size;
+ if (!newStrings.size) {
+ bridgeHeader.setAttribute("hidden", "true");
+ bridgeCards.setAttribute("hidden", "true");
+ showAll.setAttribute("hidden", "true");
+ removeAll.setAttribute("hidden", "true");
+ bridgeCards.textContent = "";
+ return;
+ }
+ bridgeHeader.removeAttribute("hidden");
+ bridgeCards.removeAttribute("hidden");
+ bridgeSwitch.checked = TorSettings.bridges.enabled;
+ bridgeCards.classList.toggle("disabled", !TorSettings.bridges.enabled);
+
+ let shownCards = 0;
+ const toShow = this._currentBridgesExpanded
+ ? numBridges
+ : collapseThreshold;
+
+ // Do not remove all the old cards, because it makes scrollbar "jump"
+ const currentCards = bridgeCards.querySelectorAll(
+ selectors.bridges.card
+ );
+ for (const card of currentCards) {
+ const string = card.querySelector(selectors.bridges.cardAddr).value;
+ const hadString = newStrings.delete(string);
+ if (!hadString || shownCards == toShow) {
+ card.remove();
+ } else {
+ shownCards++;
+ }
+ }
+
+ // Add only the new strings that remained in the set
+ for (const bridge of newStrings) {
+ if (shownCards >= toShow) {
+ if (this._currentBridge === "") {
+ break;
+ } else if (!bridge.includes(this._currentBridge)) {
+ continue;
+ }
+ }
+ this._addBridgeCard(bridge);
+ shownCards++;
+ }
+
+ // If we know the connected bridge, we may have added more than the ones
+ // we should actually show (but the connected ones have been prepended,
+ // if needed). So, remove any exceeding ones.
+ while (shownCards > toShow) {
+ bridgeCards.lastElementChild.remove();
+ shownCards--;
+ }
+
+ // And finally update the buttons
+ if (numBridges > collapseThreshold && !this._currentBridgesExpanded) {
+ showAll.removeAttribute("hidden");
+ if (TorSettings.bridges.enabled) {
+ showAll.classList.add("primary");
+ } else {
+ showAll.classList.remove("primary");
+ }
+ removeAll.setAttribute("hidden", "true");
+ if (TorSettings.bridges.enabled) {
+ // We do not want both collapsed and disabled at the same time,
+ // because we use collapsed only to display a gradient on the list.
+ bridgeCards.classList.add("list-collapsed");
+ }
+ } else {
+ showAll.setAttribute("hidden", "true");
+ removeAll.removeAttribute("hidden");
+ bridgeCards.classList.remove("list-collapsed");
+ }
+ };
+ this._populateBridgeCards();
+ this._updateConnectedBridges = () => {
+ for (const card of bridgeCards.querySelectorAll(
+ ".currently-connected"
+ )) {
+ card.classList.remove("currently-connected");
+ }
+ if (this._currentBridge === "") {
+ return;
+ }
+ // Make sure we have the connected bridge in the list
+ this._populateBridgeCards();
+ // At the moment, IDs do not have to be unique (and it is a concrete
+ // case also with built-in bridges!). E.g., one line for the IPv4
+ // address and one for the IPv6 address, so use querySelectorAll
+ const cards = bridgeCards.querySelectorAll(
+ `[data-bridge-id="${this._currentBridge}"]`
+ );
+ for (const card of cards) {
+ card.classList.add("currently-connected");
+ }
+ const placeholder = document.createElement("span");
+ bridgeCards.prepend(placeholder);
+ placeholder.replaceWith(...cards);
+ };
+ try {
+ const { controller } = ChromeUtils.import(
+ "resource://torbutton/modules/tor-control-port.js",
+ {}
+ );
+ // Avoid the cache because we set our custom event watcher, and at the
+ // moment, watchers cannot be removed from a controller.
+ controller(true).then(aController => {
+ this._controller = aController;
+ // Getting the circuits may be enough, if we have bootstrapped for a
+ // while, but at the beginning it gives many bridges as connected,
+ // because tor pokes all the bridges to find the best one.
+ // Also, watching circuit events does not work, at the moment, but in
+ // any case, checking the stream has the advantage that we can see if
+ // it really used for a connection, rather than tor having created
+ // this circuit to check if the bridge can be used. We do this by
+ // checking if the stream has SOCKS username, which actually contains
+ // the destination of the stream.
+ this._controller.watchEvent(
+ "STREAM",
+ event =>
+ event.StreamStatus === "SUCCEEDED" && "SOCKS_USERNAME" in event,
+ async event => {
+ const circuitStatuses = await this._controller.getInfo(
+ "circuit-status"
+ );
+ if (!circuitStatuses) {
+ return;
+ }
+ for (const status of circuitStatuses) {
+ if (status.id === event.CircuitID && status.circuit.length) {
+ // The id in the circuit begins with a $ sign
+ const bridgeId = status.circuit[0][0].substr(1);
+ if (bridgeId !== this._currentBridge) {
+ this._currentBridge = bridgeId;
+ this._updateConnectedBridges();
+ }
+ break;
+ }
+ }
+ }
+ );
+ });
+ } catch (err) {
+ console.warn(
+ "We could not load torbutton, bridge statuses will not be updated",
+ err
+ );
+ }
+
+ // Add a new bridge
+ prefpane.querySelector(selectors.bridges.addHeader).textContent =
+ TorStrings.settings.bridgeAdd;
+ prefpane
+ .querySelector(selectors.bridges.addBuiltinLabel)
+ .setAttribute("value", TorStrings.settings.bridgeSelectBrowserBuiltin);
+ {
+ let button = prefpane.querySelector(selectors.bridges.addBuiltinButton);
+ button.setAttribute("label", TorStrings.settings.bridgeSelectBuiltin);
+ button.addEventListener("command", e => {
+ this.onAddBuiltinBridge();
+ });
+ }
+ prefpane
+ .querySelector(selectors.bridges.requestLabel)
+ .setAttribute("value", TorStrings.settings.bridgeRequestFromTorProject);
+ {
+ let button = prefpane.querySelector(selectors.bridges.requestButton);
+ button.setAttribute("label", TorStrings.settings.bridgeRequest);
+ button.addEventListener("command", e => {
+ this.onRequestBridge();
+ });
+ }
+ prefpane
+ .querySelector(selectors.bridges.enterLabel)
+ .setAttribute("value", TorStrings.settings.bridgeEnterKnown);
+ {
+ const button = prefpane.querySelector(selectors.bridges.enterButton);
+ button.setAttribute("label", TorStrings.settings.bridgeAddManually);
+ button.addEventListener("command", e => {
+ this.onAddBridgeManually();
+ });
+ }
+
+ Services.obs.addObserver(this, TorConnectTopics.StateChange);
+
+ // Advanced setup
+ prefpane.querySelector(selectors.advanced.header).innerText =
+ TorStrings.settings.advancedHeading;
+ prefpane.querySelector(selectors.advanced.label).textContent =
+ TorStrings.settings.advancedLabel;
+ {
+ let settingsButton = prefpane.querySelector(selectors.advanced.button);
+ settingsButton.setAttribute(
+ "label",
+ TorStrings.settings.advancedButton
+ );
+ settingsButton.addEventListener("command", () => {
+ this.onAdvancedSettings();
+ });
+ }
+
+ // Tor logs
+ prefpane
+ .querySelector(selectors.advanced.torLogsLabel)
+ .setAttribute("value", TorStrings.settings.showTorDaemonLogs);
+ let torLogsButton = prefpane.querySelector(
+ selectors.advanced.torLogsButton
+ );
+ torLogsButton.setAttribute("label", TorStrings.settings.showLogs);
+ torLogsButton.addEventListener("command", () => {
+ this.onViewTorLogs();
+ });
+ },
+
+ init() {
+ this._populateXUL();
+
+ let onUnload = () => {
+ window.removeEventListener("unload", onUnload);
+ gConnectionPane.uninit();
+ };
+ window.addEventListener("unload", onUnload);
+
+ window.addEventListener("resize", () => {
+ this._checkBridgeCardsHeight();
+ });
+ },
+
+ uninit() {
+ // unregister our observer topics
+ Services.obs.removeObserver(this, TorSettingsTopics.SettingChanged);
+ Services.obs.removeObserver(this, TorConnectTopics.StateChange);
+
+ if (this._controller !== null) {
+ this._controller.close();
+ this._controller = null;
+ }
+ },
+
+ // whether the page should be present in about:preferences
+ get enabled() {
+ return TorProtocolService.ownsTorDaemon;
+ },
+
+ //
+ // Callbacks
+ //
+
+ observe(subject, topic, data) {
+ switch (topic) {
+ // triggered when a TorSettings param has changed
+ case TorSettingsTopics.SettingChanged: {
+ let obj = subject?.wrappedJSObject;
+ switch (data) {
+ case TorSettingsData.QuickStartEnabled: {
+ this._enableQuickstartCheckbox.checked = obj.value;
+ break;
+ }
+ }
+ break;
+ }
+ // triggered when tor connect state changes and we may
+ // need to update the messagebox
+ case TorConnectTopics.StateChange: {
+ this.onStateChange();
+ break;
+ }
+ }
+ },
+
+ async onInternetTest() {
+ const mrpc = new MoatRPC();
+ let status = null;
+ try {
+ await mrpc.init();
+ status = await mrpc.testInternetConnection();
+ } catch (err) {
+ console.log("Error while checking the Internet connection", err);
+ } finally {
+ mrpc.uninit();
+ }
+ if (status) {
+ this._internetStatus = status.successful
+ ? InternetStatus.Online
+ : InternetStatus.Offline;
+ this._populateStatus();
+ }
+ },
+
+ onStateChange() {
+ this._populateMessagebox();
+ this._populateStatus();
+ this._showAutoconfiguration();
+ this._populateBridgeCards();
+ },
+
+ onShowQr(bridgeString) {
+ const dialog = new BridgeQrDialog();
+ dialog.openDialog(gSubDialog, bridgeString);
+ },
+
+ onCopyBridgeAddress(addressElem) {
+ let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(
+ Ci.nsIClipboardHelper
+ );
+ clipboard.copyString(addressElem.value);
+ },
+
+ onRemoveAllBridges() {
+ TorSettings.bridges.enabled = false;
+ TorSettings.bridges.bridge_strings = "";
+ TorSettings.saveToPrefs();
+ TorSettings.applySettings().then(result => {
+ this._populateBridgeCards();
+ });
+ },
+
+ onAddBuiltinBridge() {
+ let builtinBridgeDialog = new BuiltinBridgeDialog();
+
+ let sizeObserver = null;
+ {
+ let ds = document.querySelector("#dialogStack");
+ let boxObserver;
+ boxObserver = new MutationObserver(() => {
+ let dialogBox = document.querySelector(".dialogBox");
+ if (dialogBox) {
+ sizeObserver = new MutationObserver(mutations => {
+ for (const m of mutations) {
+ if (m.attributeName === "style") {
+ builtinBridgeDialog.resized();
+ break;
+ }
+ }
+ });
+ sizeObserver.observe(dialogBox, { attributes: true });
+ boxObserver.disconnect();
+ }
+ });
+ boxObserver.observe(ds, { childList: true, subtree: true });
+ }
+
+ builtinBridgeDialog.openDialog(gSubDialog, aBridgeType => {
+ sizeObserver.disconnect();
+
+ if (!aBridgeType) {
+ TorSettings.bridges.enabled = false;
+ TorSettings.bridges.builtin_type = "";
+ } else {
+ TorSettings.bridges.enabled = true;
+ TorSettings.bridges.source = TorBridgeSource.BuiltIn;
+ TorSettings.bridges.builtin_type = aBridgeType;
+ }
+ TorSettings.saveToPrefs();
+ TorSettings.applySettings().then(result => {
+ this._populateBridgeCards();
+ });
+ });
+ },
+
+ // called when the request bridge button is activated
+ onRequestBridge() {
+ let requestBridgeDialog = new RequestBridgeDialog();
+ requestBridgeDialog.openDialog(gSubDialog, aBridges => {
+ if (aBridges.length) {
+ let bridgeStrings = aBridges.join("\n");
+ TorSettings.bridges.enabled = true;
+ TorSettings.bridges.source = TorBridgeSource.BridgeDB;
+ TorSettings.bridges.bridge_strings = bridgeStrings;
+ TorSettings.saveToPrefs();
+ TorSettings.applySettings().then(result => {
+ this._populateBridgeCards();
+ });
+ } else {
+ TorSettings.bridges.enabled = false;
+ }
+ });
+ },
+
+ onAddBridgeManually() {
+ let provideBridgeDialog = new ProvideBridgeDialog();
+ provideBridgeDialog.openDialog(gSubDialog, aBridgeString => {
+ if (aBridgeString.length) {
+ TorSettings.bridges.enabled = true;
+ TorSettings.bridges.source = TorBridgeSource.UserProvided;
+ TorSettings.bridges.bridge_strings = aBridgeString;
+ TorSettings.saveToPrefs();
+ TorSettings.applySettings().then(result => {
+ this._populateBridgeCards();
+ });
+ } else {
+ TorSettings.bridges.enabled = false;
+ TorSettings.bridges.source = TorBridgeSource.Invalid;
+ }
+ });
+ },
+
+ onAdvancedSettings() {
+ let connectionSettingsDialog = new ConnectionSettingsDialog();
+ connectionSettingsDialog.openDialog(gSubDialog);
+ },
+
+ onViewTorLogs() {
+ let torLogDialog = new TorLogDialog();
+ torLogDialog.openDialog(gSubDialog);
+ },
+ };
+ return retval;
+})(); /* gConnectionPane */
+
+function makeBridgeId(bridgeString) {
+ // JS uses UTF-16. While most of these emojis are surrogate pairs, a few
+ // ones fit one UTF-16 character. So we could not use neither indices,
+ // nor substr, nor some function to split the string.
+ const emojis = [
+ "😄️",
+ "😒️",
+ "😉",
+ "😭️",
+ "😂️",
+ "😎️",
+ "🤩️",
+ "😘",
+ "😜️",
+ "😏️",
+ "😷",
+ "🤢",
+ "🤕",
+ "🤧",
+ "🥵",
+ "🥶",
+ "🥴",
+ "😵️",
+ "🤮️",
+ "🤑",
+ "🤔",
+ "🫢",
+ "🤐",
+ "😮💨",
+ "😐",
+ "🤤",
+ "😴",
+ "🤯",
+ "🤠",
+ "🥳",
+ "🥸",
+ "🤓",
+ "🧐",
+ "😨",
+ "😳",
+ "🥺",
+ "🤬",
+ "😈",
+ "👿",
+ "💀",
+ "💩",
+ "🤡",
+ "👺",
+ "👻",
+ "👽",
+ "🦴",
+ "🤖",
+ "😸",
+ "🙈",
+ "🙉",
+ "🙊",
+ "💋",
+ "💖",
+ "💯",
+ "💢",
+ "💧",
+ "💨",
+ "💭",
+ "💤",
+ "👋",
+ "👌",
+ "✌",
+ "👍",
+ "👎",
+ "🤛",
+ "🙌",
+ "💪",
+ "🙏",
+ "✍",
+ "🧠",
+ "👀",
+ "👂",
+ "👅",
+ "🦷",
+ "🐾",
+ "🐶",
+ "🦊",
+ "🦝",
+ "🐈",
+ "🦁",
+ "🐯",
+ "🐴",
+ "🦄",
+ "🦓",
+ "🐮",
+ "🐷",
+ "🐑",
+ "🐪",
+ "🐘",
+ "🐭",
+ "🐰",
+ "🦔",
+ "🦇",
+ "🐻",
+ "🐨",
+ "🐼",
+ "🐔",
+ "🦨",
+ "🦘",
+ "🐦",
+ "🐧",
+ "🦩",
+ "🦉",
+ "🦜",
+ "🪶",
+ "🐸",
+ "🐊",
+ "🐢",
+ "🦎",
+ "🐍",
+ "🦖",
+ "🦀",
+ "🐬",
+ "🐙",
+ "🐌",
+ "🐝",
+ "🐞",
+ "🌸",
+ "🌲",
+ "🌵",
+ "🍀",
+ "🍁",
+ "🍇",
+ "🍉",
+ "🍊",
+ "🍋",
+ "🍌",
+ "🍍",
+ "🍎",
+ "🥥",
+ "🍐",
+ "🍒",
+ "🍓",
+ "🫐",
+ "🥝",
+ "🥔",
+ "🥕",
+ "🧅",
+ "🌰",
+ "🍄",
+ "🍞",
+ "🥞",
+ "🧀",
+ "🍖",
+ "🍔",
+ "🍟",
+ "🍕",
+ "🥚",
+ "🍿",
+ "🧂",
+ "🍙",
+ "🍦",
+ "🍩",
+ "🍪",
+ "🎂",
+ "🍬",
+ "🍭",
+ "🥛",
+ "☕",
+ "🫖",
+ "🍾",
+ "🍷",
+ "🍹",
+ "🍺",
+ "🍴",
+ "🥄",
+ "🫙",
+ "🧭",
+ "🌋",
+ "🪵",
+ "🏡",
+ "🏢",
+ "🏰",
+ "⛲",
+ "⛺",
+ "🎡",
+ "🚂",
+ "🚘",
+ "🚜",
+ "🚲",
+ "🚔",
+ "🚨",
+ "⛽",
+ "🚥",
+ "🚧",
+ "⚓",
+ "⛵",
+ "🛟",
+ "🪂",
+ "🚀",
+ "⌛",
+ "⏰",
+ "🌂",
+ "🌞",
+ "🌙",
+ "🌟",
+ "⛅",
+ "⚡",
+ "🔥",
+ "🌊",
+ "🎃",
+ "🎈",
+ "🎉",
+ "✨",
+ "🎀",
+ "🎁",
+ "🏆",
+ "🏅",
+ "🔮",
+ "🪄",
+ "🎾",
+ "🎳",
+ "🎲",
+ "🎭",
+ "🎨",
+ "🧵",
+ "🎩",
+ "📢",
+ "🔔",
+ "🎵",
+ "🎤",
+ "🎧",
+ "🎷",
+ "🎸",
+ "🥁",
+ "🔋",
+ "🔌",
+ "💻",
+ "💾",
+ "💿",
+ "🎬",
+ "📺",
+ "📷",
+ "🎮",
+ "🧩",
+ "🔍",
+ "💡",
+ "📖",
+ "💰",
+ "💼",
+ "📈",
+ "📌",
+ "📎",
+ "🔒",
+ "🔑",
+ "🔧",
+ "🪛",
+ "🔩",
+ "🧲",
+ "🔬",
+ "🔭",
+ "📡",
+ "🚪",
+ "🪑",
+ "⛔",
+ "🚩",
+ ];
+
+ // FNV-1a implementation that is compatible with other languages
+ const prime = 0x01000193;
+ const offset = 0x811c9dc5;
+ let hash = offset;
+ const encoder = new TextEncoder();
+ for (const charCode of encoder.encode(bridgeString)) {
+ hash = Math.imul(hash ^ charCode, prime);
+ }
+
+ const hashBytes = [
+ ((hash & 0x7f000000) >> 24) | (hash < 0 ? 0x80 : 0),
+ (hash & 0x00ff0000) >> 16,
+ (hash & 0x0000ff00) >> 8,
+ hash & 0x000000ff,
+ ];
+ return hashBytes.map(b => emojis[b]);
+}
+
+function parseBridgeLine(line) {
+ const re = /^([^\s]+\s+)?([0-9a-fA-F\.\[\]\:]+:[0-9]{1,5})\s*([0-9a-fA-F]{40})(\s+.+)?/;
+ const matches = line.match(re);
+ if (!matches) {
+ return null;
+ }
+ let bridge = { addr: matches[2] };
+ if (matches[1] !== undefined) {
+ bridge.transport = matches[1].trim();
+ }
+ if (matches[3] !== undefined) {
+ bridge.id = matches[3].toUpperCase();
+ }
+ if (matches[4] !== undefined) {
+ bridge.args = matches[4].trim();
+ }
+ return bridge;
+}
diff --git a/browser/components/torpreferences/content/connectionPane.xhtml b/browser/components/torpreferences/content/connectionPane.xhtml
new file mode 100644
index 0000000000000..67f98685d8038
--- /dev/null
+++ b/browser/components/torpreferences/content/connectionPane.xhtml
@@ -0,0 +1,177 @@
+<!-- Tor panel -->
+
+<script type="application/javascript"
+ src="chrome://browser/content/torpreferences/connectionPane.js"/>
+<html:template id="template-paneConnection">
+
+<!-- Tor Connect Message Box -->
+<groupbox data-category="paneConnection" hidden="true">
+ <html:div id="torPreferences-connectMessageBox"
+ class="subcategory"
+ data-category="paneConnection"
+ hidden="true">
+ <html:table>
+ <html:tr>
+ <html:td>
+ <html:div id="torPreferences-connectMessageBox-icon"/>
+ </html:td>
+ <html:td id="torPreferences-connectMessageBox-message">
+ </html:td>
+ <html:td>
+ <html:button id="torPreferences-connectMessageBox-button">
+ </html:button>
+ </html:td>
+ </html:tr>
+ </html:table>
+ </html:div>
+</groupbox>
+
+<hbox id="torPreferencesCategory"
+ class="subcategory"
+ data-category="paneConnection"
+ hidden="true">
+ <html:h1 id="torPreferences-header"/>
+</hbox>
+
+<groupbox data-category="paneConnection"
+ hidden="true">
+ <description flex="1">
+ <html:span id="torPreferences-description" class="tail-with-learn-more"/>
+ <label id="torPreferences-learnMore" class="learnMore text-link" is="text-link"/>
+ </description>
+</groupbox>
+
+<groupbox id="torPreferences-status-group"
+ data-category="paneConnection">
+ <hbox id="torPreferences-status-box">
+ <image id="torPreferences-status-internet-icon"/>
+ <html:span id="torPreferences-status-internet-label"/>
+ <button id="torPreferences-status-internet-test"/>
+ <image id="torPreferences-status-internet-statusIcon"/>
+ <html:span id="torPreferences-status-internet-status"/>
+ <image id="torPreferences-status-tor-icon"/>
+ <html:span id="torPreferences-status-tor-label"/>
+ <image id="torPreferences-status-tor-statusIcon"/>
+ <html:span id="torPreferences-status-tor-status"/>
+ </hbox>
+</groupbox>
+
+<!-- Quickstart -->
+<groupbox id="torPreferences-quickstart-group"
+ data-category="paneConnection"
+ hidden="true">
+ <html:h2 id="torPreferences-quickstart-header"/>
+ <description flex="1">
+ <html:span id="torPreferences-quickstart-description"/>
+ </description>
+ <checkbox id="torPreferences-quickstart-toggle"/>
+</groupbox>
+
+<!-- Bridges -->
+<hbox class="subcategory"
+ data-category="paneConnection"
+ hidden="true">
+ <html:h1 id="torPreferences-bridges-header"/>
+</hbox>
+<groupbox id="torPreferences-bridges-group"
+ data-category="paneConnection"
+ hidden="true">
+ <description flex="1">
+ <html:span id="torPreferences-bridges-description" class="tail-with-learn-more"/>
+ <label id="torPreferences-bridges-learnMore" class="learnMore text-link" is="text-link"/>
+ </description>
+ <hbox align="center" id="torPreferences-bridges-locationGroup" hidden="true">
+ <label id="torPreferences-bridges-locationLabel"
+ control="torPreferences-bridges-location"/>
+ <spacer flex="1"/>
+ <menulist id="torPreferences-bridges-location">
+ <menupopup id="torPreferences-bridges-locationEntries"/>
+ </menulist>
+ <button id="torPreferences-bridges-buttonChooseBridgeForMe" class="torMarginFix primary"/>
+ </hbox>
+ <html:h2 id="torPreferences-currentBridges-header">
+ <html:span id="torPreferences-currentBridges-headerText"/>
+ <html:input type="checkbox" id="torPreferences-currentBridges-switch" class="toggle-button"/>
+ </html:h2>
+ <menupopup id="torPreferences-bridgeCard-menu"/>
+ <vbox id="torPreferences-bridgeCard-template" class="torPreferences-bridgeCard">
+ <hbox class="torPreferences-bridgeCard-heading">
+ <html:div class="torPreferences-bridgeCard-id"/>
+ <html:div class="torPreferences-bridgeCard-headingAddr"/>
+ <html:div class="torPreferences-bridgeCard-buttons">
+ <html:span class="torPreferences-bridgeCard-connectedBadge">
+ <image class="torPreferences-bridgeCard-connectedIcon"/>
+ <html:span class="torPreferences-bridgeCard-connectedLabel"/>
+ </html:span>
+ <html:button class="torPreferences-bridgeCard-options stop-click"/>
+ </html:div>
+ </hbox>
+ <box class="torPreferences-bridgeCard-grid">
+ <box class="torPreferences-bridgeCard-qrWrapper">
+ <box class="torPreferences-bridgeCard-qr stop-click">
+ <html:div class="torPreferences-bridgeCard-qrCode"/>
+ <html:div class="torPreferences-bridgeCard-qrOnionBox"/>
+ <html:div class="torPreferences-bridgeCard-qrOnion"/>
+ </box>
+ <html:div class="torPreferences-bridgeCard-filler"/>
+ </box>
+ <description class="torPreferences-bridgeCard-share"></description>
+ <hbox class="torPreferences-bridgeCard-addrBox">
+ <html:input class="torPreferences-bridgeCard-addr torMarginFix stop-click" type="text" readonly="readonly"/>
+ </hbox>
+ <hbox class="torPreferences-bridgeCard-learnMoreBox" align="center">
+ <label class="torPreferences-bridgeCard-learnMore learnMore text-link stop-click" is="text-link"/>
+ </hbox>
+ <hbox class="torPreferences-bridgeCard-copy" align="center">
+ <button class="torPreferences-bridgeCard-copyButton stop-click"/>
+ </hbox>
+ </box>
+ </vbox>
+ <vbox id="torPreferences-currentBridges-cards"></vbox>
+ <vbox align="center">
+ <button id="torPreferences-currentBridges-showAll"/>
+ <button id="torPreferences-currentBridges-removeAll" class="primary danger-button"/>
+ </vbox>
+ <html:h2 id="torPreferences-addBridge-header"></html:h2>
+ <hbox align="center">
+ <label id="torPreferences-addBridge-labelBuiltinBridge"/>
+ <space flex="1"/>
+ <button id="torPreferences-addBridge-buttonBuiltinBridge" class="torMarginFix"/>
+ </hbox>
+ <hbox align="center">
+ <label id="torPreferences-addBridge-labelRequestBridge"/>
+ <space flex="1"/>
+ <button id="torPreferences-addBridge-buttonRequestBridge" class="torMarginFix"/>
+ </hbox>
+ <hbox align="center">
+ <label id="torPreferences-addBridge-labelEnterBridge"/>
+ <space flex="1"/>
+ <button id="torPreferences-addBridge-buttonEnterBridge" class="torMarginFix"/>
+ </hbox>
+</groupbox>
+
+<!-- Advanced -->
+<hbox class="subcategory"
+ data-category="paneConnection"
+ hidden="true">
+ <html:h1 id="torPreferences-advanced-header"/>
+</hbox>
+<groupbox id="torPreferences-advanced-group"
+ data-category="paneConnection"
+ hidden="true">
+ <box id="torPreferences-advanced-grid">
+ <hbox id="torPreferences-advanced-hbox" align="center">
+ <label id="torPreferences-advanced-label"/>
+ </hbox>
+ <hbox align="center">
+ <button id="torPreferences-advanced-button"/>
+ </hbox>
+ <hbox id="torPreferences-torDaemon-hbox" align="center">
+ <label id="torPreferences-torLogs"/>
+ </hbox>
+ <hbox align="center" data-subcategory="viewlogs">
+ <button id="torPreferences-buttonTorLogs"/>
+ </hbox>
+ </box>
+</groupbox>
+</html:template>
diff --git a/browser/components/torpreferences/content/connectionSettingsDialog.jsm b/browser/components/torpreferences/content/connectionSettingsDialog.jsm
new file mode 100644
index 0000000000000..abc177c43f884
--- /dev/null
+++ b/browser/components/torpreferences/content/connectionSettingsDialog.jsm
@@ -0,0 +1,393 @@
+"use strict";
+
+var EXPORTED_SYMBOLS = ["ConnectionSettingsDialog"];
+
+const { TorSettings, TorProxyType } = ChromeUtils.import(
+ "resource:///modules/TorSettings.jsm"
+);
+
+const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm");
+
+class ConnectionSettingsDialog {
+ constructor() {
+ this._dialog = null;
+ this._useProxyCheckbox = null;
+ this._proxyTypeLabel = null;
+ this._proxyTypeMenulist = null;
+ this._proxyAddressLabel = null;
+ this._proxyAddressTextbox = null;
+ this._proxyPortLabel = null;
+ this._proxyPortTextbox = null;
+ this._proxyUsernameLabel = null;
+ this._proxyUsernameTextbox = null;
+ this._proxyPasswordLabel = null;
+ this._proxyPasswordTextbox = null;
+ this._useFirewallCheckbox = null;
+ this._allowedPortsLabel = null;
+ this._allowedPortsTextbox = null;
+ }
+
+ static get selectors() {
+ return {
+ header: "#torPreferences-connection-header",
+ useProxyCheckbox: "checkbox#torPreferences-connection-toggleProxy",
+ proxyTypeLabel: "label#torPreferences-localProxy-type",
+ proxyTypeList: "menulist#torPreferences-localProxy-builtinList",
+ proxyAddressLabel: "label#torPreferences-localProxy-address",
+ proxyAddressTextbox: "input#torPreferences-localProxy-textboxAddress",
+ proxyPortLabel: "label#torPreferences-localProxy-port",
+ proxyPortTextbox: "input#torPreferences-localProxy-textboxPort",
+ proxyUsernameLabel: "label#torPreferences-localProxy-username",
+ proxyUsernameTextbox: "input#torPreferences-localProxy-textboxUsername",
+ proxyPasswordLabel: "label#torPreferences-localProxy-password",
+ proxyPasswordTextbox: "input#torPreferences-localProxy-textboxPassword",
+ useFirewallCheckbox: "checkbox#torPreferences-connection-toggleFirewall",
+ firewallAllowedPortsLabel: "label#torPreferences-connection-allowedPorts",
+ firewallAllowedPortsTextbox:
+ "input#torPreferences-connection-textboxAllowedPorts",
+ };
+ }
+
+ // disables the provided list of elements
+ _setElementsDisabled(elements, disabled) {
+ for (let currentElement of elements) {
+ currentElement.disabled = disabled;
+ }
+ }
+
+ _populateXUL(window, aDialog) {
+ const selectors = ConnectionSettingsDialog.selectors;
+
+ this._dialog = aDialog;
+ const dialogWin = this._dialog.parentElement;
+ dialogWin.setAttribute(
+ "title",
+ TorStrings.settings.connectionSettingsDialogTitle
+ );
+ this._dialog.querySelector(selectors.header).textContent =
+ TorStrings.settings.connectionSettingsDialogHeader;
+
+ // Local Proxy
+ this._useProxyCheckbox = this._dialog.querySelector(
+ selectors.useProxyCheckbox
+ );
+ this._useProxyCheckbox.setAttribute(
+ "label",
+ TorStrings.settings.useLocalProxy
+ );
+ this._useProxyCheckbox.addEventListener("command", e => {
+ const checked = this._useProxyCheckbox.checked;
+ this.onToggleProxy(checked);
+ });
+ this._proxyTypeLabel = this._dialog.querySelector(selectors.proxyTypeLabel);
+ this._proxyTypeLabel.setAttribute("value", TorStrings.settings.proxyType);
+
+ let mockProxies = [
+ {
+ value: TorProxyType.Socks4,
+ label: TorStrings.settings.proxyTypeSOCKS4,
+ },
+ {
+ value: TorProxyType.Socks5,
+ label: TorStrings.settings.proxyTypeSOCKS5,
+ },
+ { value: TorProxyType.HTTPS, label: TorStrings.settings.proxyTypeHTTP },
+ ];
+ this._proxyTypeMenulist = this._dialog.querySelector(
+ selectors.proxyTypeList
+ );
+ this._proxyTypeMenulist.addEventListener("command", e => {
+ const value = this._proxyTypeMenulist.value;
+ this.onSelectProxyType(value);
+ });
+ for (let currentProxy of mockProxies) {
+ let menuEntry = window.document.createXULElement("menuitem");
+ menuEntry.setAttribute("value", currentProxy.value);
+ menuEntry.setAttribute("label", currentProxy.label);
+ this._proxyTypeMenulist.querySelector("menupopup").appendChild(menuEntry);
+ }
+
+ this._proxyAddressLabel = this._dialog.querySelector(
+ selectors.proxyAddressLabel
+ );
+ this._proxyAddressLabel.setAttribute(
+ "value",
+ TorStrings.settings.proxyAddress
+ );
+ this._proxyAddressTextbox = this._dialog.querySelector(
+ selectors.proxyAddressTextbox
+ );
+ this._proxyAddressTextbox.setAttribute(
+ "placeholder",
+ TorStrings.settings.proxyAddressPlaceholder
+ );
+ this._proxyAddressTextbox.addEventListener("blur", e => {
+ let value = this._proxyAddressTextbox.value.trim();
+ let colon = value.lastIndexOf(":");
+ if (colon != -1) {
+ let maybePort = parseInt(value.substr(colon + 1));
+ if (!isNaN(maybePort) && maybePort > 0 && maybePort < 65536) {
+ this._proxyAddressTextbox.value = value.substr(0, colon);
+ this._proxyPortTextbox.value = maybePort;
+ }
+ }
+ });
+ this._proxyPortLabel = this._dialog.querySelector(selectors.proxyPortLabel);
+ this._proxyPortLabel.setAttribute("value", TorStrings.settings.proxyPort);
+ this._proxyPortTextbox = this._dialog.querySelector(
+ selectors.proxyPortTextbox
+ );
+ this._proxyUsernameLabel = this._dialog.querySelector(
+ selectors.proxyUsernameLabel
+ );
+ this._proxyUsernameLabel.setAttribute(
+ "value",
+ TorStrings.settings.proxyUsername
+ );
+ this._proxyUsernameTextbox = this._dialog.querySelector(
+ selectors.proxyUsernameTextbox
+ );
+ this._proxyUsernameTextbox.setAttribute(
+ "placeholder",
+ TorStrings.settings.proxyUsernamePasswordPlaceholder
+ );
+ this._proxyPasswordLabel = this._dialog.querySelector(
+ selectors.proxyPasswordLabel
+ );
+ this._proxyPasswordLabel.setAttribute(
+ "value",
+ TorStrings.settings.proxyPassword
+ );
+ this._proxyPasswordTextbox = this._dialog.querySelector(
+ selectors.proxyPasswordTextbox
+ );
+ this._proxyPasswordTextbox.setAttribute(
+ "placeholder",
+ TorStrings.settings.proxyUsernamePasswordPlaceholder
+ );
+
+ this.onToggleProxy(false);
+ if (TorSettings.proxy.enabled) {
+ this.onToggleProxy(true);
+ this.onSelectProxyType(TorSettings.proxy.type);
+ this._proxyAddressTextbox.value = TorSettings.proxy.address;
+ this._proxyPortTextbox.value = TorSettings.proxy.port;
+ this._proxyUsernameTextbox.value = TorSettings.proxy.username;
+ this._proxyPasswordTextbox.value = TorSettings.proxy.password;
+ }
+
+ // Local firewall
+ this._useFirewallCheckbox = this._dialog.querySelector(
+ selectors.useFirewallCheckbox
+ );
+ this._useFirewallCheckbox.setAttribute(
+ "label",
+ TorStrings.settings.useFirewall
+ );
+ this._useFirewallCheckbox.addEventListener("command", e => {
+ const checked = this._useFirewallCheckbox.checked;
+ this.onToggleFirewall(checked);
+ });
+ this._allowedPortsLabel = this._dialog.querySelector(
+ selectors.firewallAllowedPortsLabel
+ );
+ this._allowedPortsLabel.setAttribute(
+ "value",
+ TorStrings.settings.allowedPorts
+ );
+ this._allowedPortsTextbox = this._dialog.querySelector(
+ selectors.firewallAllowedPortsTextbox
+ );
+ this._allowedPortsTextbox.setAttribute(
+ "placeholder",
+ TorStrings.settings.allowedPortsPlaceholder
+ );
+
+ this.onToggleFirewall(false);
+ if (TorSettings.firewall.enabled) {
+ this.onToggleFirewall(true);
+ this._allowedPortsTextbox.value = TorSettings.firewall.allowed_ports.join(
+ ", "
+ );
+ }
+
+ this._dialog.addEventListener("dialogaccept", e => {
+ this._applySettings();
+ });
+ }
+
+ // callback when proxy is toggled
+ onToggleProxy(enabled) {
+ this._useProxyCheckbox.checked = enabled;
+ let disabled = !enabled;
+
+ this._setElementsDisabled(
+ [
+ this._proxyTypeLabel,
+ this._proxyTypeMenulist,
+ this._proxyAddressLabel,
+ this._proxyAddressTextbox,
+ this._proxyPortLabel,
+ this._proxyPortTextbox,
+ this._proxyUsernameLabel,
+ this._proxyUsernameTextbox,
+ this._proxyPasswordLabel,
+ this._proxyPasswordTextbox,
+ ],
+ disabled
+ );
+ if (enabled) {
+ this.onSelectProxyType(this._proxyTypeMenulist.value);
+ }
+ }
+
+ // callback when proxy type is changed
+ onSelectProxyType(value) {
+ if (typeof value === "string") {
+ value = parseInt(value);
+ }
+
+ this._proxyTypeMenulist.value = value;
+ switch (value) {
+ case TorProxyType.Invalid: {
+ this._setElementsDisabled(
+ [
+ this._proxyAddressLabel,
+ this._proxyAddressTextbox,
+ this._proxyPortLabel,
+ this._proxyPortTextbox,
+ this._proxyUsernameLabel,
+ this._proxyUsernameTextbox,
+ this._proxyPasswordLabel,
+ this._proxyPasswordTextbox,
+ ],
+ true
+ ); // DISABLE
+
+ this._proxyAddressTextbox.value = "";
+ this._proxyPortTextbox.value = "";
+ this._proxyUsernameTextbox.value = "";
+ this._proxyPasswordTextbox.value = "";
+ break;
+ }
+ case TorProxyType.Socks4: {
+ this._setElementsDisabled(
+ [
+ this._proxyAddressLabel,
+ this._proxyAddressTextbox,
+ this._proxyPortLabel,
+ this._proxyPortTextbox,
+ ],
+ false
+ ); // ENABLE
+ this._setElementsDisabled(
+ [
+ this._proxyUsernameLabel,
+ this._proxyUsernameTextbox,
+ this._proxyPasswordLabel,
+ this._proxyPasswordTextbox,
+ ],
+ true
+ ); // DISABLE
+
+ this._proxyUsernameTextbox.value = "";
+ this._proxyPasswordTextbox.value = "";
+ break;
+ }
+ case TorProxyType.Socks5:
+ case TorProxyType.HTTPS: {
+ this._setElementsDisabled(
+ [
+ this._proxyAddressLabel,
+ this._proxyAddressTextbox,
+ this._proxyPortLabel,
+ this._proxyPortTextbox,
+ this._proxyUsernameLabel,
+ this._proxyUsernameTextbox,
+ this._proxyPasswordLabel,
+ this._proxyPasswordTextbox,
+ ],
+ false
+ ); // ENABLE
+ break;
+ }
+ }
+ }
+
+ // callback when firewall proxy is toggled
+ onToggleFirewall(enabled) {
+ this._useFirewallCheckbox.checked = enabled;
+ let disabled = !enabled;
+
+ this._setElementsDisabled(
+ [this._allowedPortsLabel, this._allowedPortsTextbox],
+ disabled
+ );
+ }
+
+ // pushes settings from UI to tor
+ _applySettings() {
+ const type = this._useProxyCheckbox.checked
+ ? parseInt(this._proxyTypeMenulist.value)
+ : TorProxyType.Invalid;
+ const address = this._proxyAddressTextbox.value;
+ const port = this._proxyPortTextbox.value;
+ const username = this._proxyUsernameTextbox.value;
+ const password = this._proxyPasswordTextbox.value;
+ switch (type) {
+ case TorProxyType.Invalid:
+ TorSettings.proxy.enabled = false;
+ break;
+ case TorProxyType.Socks4:
+ TorSettings.proxy.enabled = true;
+ TorSettings.proxy.type = type;
+ TorSettings.proxy.address = address;
+ TorSettings.proxy.port = port;
+ break;
+ case TorProxyType.Socks5:
+ TorSettings.proxy.enabled = true;
+ TorSettings.proxy.type = type;
+ TorSettings.proxy.address = address;
+ TorSettings.proxy.port = port;
+ TorSettings.proxy.username = username;
+ TorSettings.proxy.password = password;
+ break;
+ case TorProxyType.HTTPS:
+ TorSettings.proxy.enabled = true;
+ TorSettings.proxy.type = type;
+ TorSettings.proxy.address = address;
+ TorSettings.proxy.port = port;
+ TorSettings.proxy.username = username;
+ TorSettings.proxy.password = password;
+ break;
+ }
+
+ let portListString = this._useFirewallCheckbox.checked
+ ? this._allowedPortsTextbox.value
+ : "";
+ if (portListString) {
+ TorSettings.firewall.enabled = true;
+ TorSettings.firewall.allowed_ports = portListString;
+ } else {
+ TorSettings.firewall.enabled = false;
+ }
+
+ TorSettings.saveToPrefs();
+ TorSettings.applySettings();
+ }
+
+ init(window, aDialog) {
+ // defer to later until firefox has populated the dialog with all our elements
+ window.setTimeout(() => {
+ this._populateXUL(window, aDialog);
+ }, 0);
+ }
+
+ openDialog(gSubDialog) {
+ gSubDialog.open(
+ "chrome://browser/content/torpreferences/connectionSettingsDialog.xhtml",
+ { features: "resizable=yes" },
+ this
+ );
+ }
+}
diff --git a/browser/components/torpreferences/content/connectionSettingsDialog.xhtml b/browser/components/torpreferences/content/connectionSettingsDialog.xhtml
new file mode 100644
index 0000000000000..88aa979256f02
--- /dev/null
+++ b/browser/components/torpreferences/content/connectionSettingsDialog.xhtml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
+<?xml-stylesheet href="chrome://browser/content/torpreferences/torPreferences.css"?>
+
+<window type="child"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+<dialog id="torPreferences-connection-dialog"
+ buttons="accept,cancel">
+ <html:h3 id="torPreferences-connection-header">​</html:h3>
+ <box id="torPreferences-connection-grid">
+ <!-- Local Proxy -->
+ <hbox class="torPreferences-connection-checkbox-container">
+ <checkbox id="torPreferences-connection-toggleProxy" label="​"/>
+ </hbox>
+ <hbox class="indent" align="center">
+ <label id="torPreferences-localProxy-type"/>
+ </hbox>
+ <hbox align="center">
+ <spacer flex="1"/>
+ <menulist id="torPreferences-localProxy-builtinList" class="torMarginFix">
+ <menupopup/>
+ </menulist>
+ </hbox>
+ <hbox class="indent" align="center">
+ <label id="torPreferences-localProxy-address"/>
+ </hbox>
+ <hbox align="center">
+ <html:input id="torPreferences-localProxy-textboxAddress" type="text" class="torMarginFix"/>
+ <label id="torPreferences-localProxy-port"/>
+ <!-- proxy-port-input class style pulled from preferences.css and used in the vanilla proxy setup menu -->
+ <html:input id="torPreferences-localProxy-textboxPort" class="proxy-port-input torMarginFix" hidespinbuttons="true" type="number" min="0" max="65535" maxlength="5"/>
+ </hbox>
+ <hbox class="indent" align="center">
+ <label id="torPreferences-localProxy-username"/>
+ </hbox>
+ <hbox align="center">
+ <html:input id="torPreferences-localProxy-textboxUsername" type="text" class="torMarginFix"/>
+ <label id="torPreferences-localProxy-password"/>
+ <html:input id="torPreferences-localProxy-textboxPassword" class="torMarginFix" type="password"/>
+ </hbox>
+ <!-- Firewall -->
+ <hbox class="torPreferences-connection-checkbox-container">
+ <checkbox id="torPreferences-connection-toggleFirewall" label="​"/>
+ </hbox>
+ <hbox class="indent" align="center">
+ <label id="torPreferences-connection-allowedPorts"/>
+ </hbox>
+ <hbox align="center">
+ <html:input id="torPreferences-connection-textboxAllowedPorts" type="text" class="torMarginFix" value="80,443"/>
+ </hbox>
+ </box>
+ <script type="application/javascript"><![CDATA[
+ "use strict";
+
+ let connectionSettingsDialog = window.arguments[0];
+ let dialog = document.getElementById("torPreferences-connection-dialog");
+ connectionSettingsDialog.init(window, dialog);
+ ]]></script>
+</dialog>
+</window>
diff --git a/browser/components/torpreferences/content/network.svg b/browser/components/torpreferences/content/network.svg
new file mode 100644
index 0000000000000..e1689b5e6d649
--- /dev/null
+++ b/browser/components/torpreferences/content/network.svg
@@ -0,0 +1,6 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity">
+ <path d="M8.5 1a7.5 7.5 0 1 0 0 15 7.5 7.5 0 0 0 0-15zm2.447 1.75a6.255 6.255 0 0 1 3.756 5.125l-2.229 0A9.426 9.426 0 0 0 10.54 2.75l.407 0zm-2.049 0a8.211 8.211 0 0 1 2.321 5.125l-5.438 0A8.211 8.211 0 0 1 8.102 2.75l.796 0zm-2.846 0 .408 0a9.434 9.434 0 0 0-1.934 5.125l-2.229 0A6.254 6.254 0 0 1 6.052 2.75zm0 11.5a6.252 6.252 0 0 1-3.755-5.125l2.229 0A9.426 9.426 0 0 0 6.46 14.25l-.408 0zm2.05 0a8.211 8.211 0 0 1-2.321-5.125l5.437 0a8.211 8.211 0 0 1-2.321 5.125l-.795 0zm2.846 0-.40 [...]
+</svg>
diff --git a/browser/components/torpreferences/content/provideBridgeDialog.jsm b/browser/components/torpreferences/content/provideBridgeDialog.jsm
new file mode 100644
index 0000000000000..b73a6f533afa6
--- /dev/null
+++ b/browser/components/torpreferences/content/provideBridgeDialog.jsm
@@ -0,0 +1,69 @@
+"use strict";
+
+var EXPORTED_SYMBOLS = ["ProvideBridgeDialog"];
+
+const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm");
+
+const { TorSettings, TorBridgeSource } = ChromeUtils.import(
+ "resource:///modules/TorSettings.jsm"
+);
+
+class ProvideBridgeDialog {
+ constructor() {
+ this._dialog = null;
+ this._textarea = null;
+ this._bridgeString = "";
+ }
+
+ static get selectors() {
+ return {
+ header: "#torPreferences-provideBridge-header",
+ textarea: "#torPreferences-provideBridge-textarea",
+ };
+ }
+
+ _populateXUL(aDialog) {
+ const selectors = ProvideBridgeDialog.selectors;
+
+ this._dialog = aDialog;
+ const dialogWin = this._dialog.parentElement;
+ dialogWin.setAttribute("title", TorStrings.settings.provideBridgeTitle);
+ this._dialog.querySelector(selectors.header).textContent =
+ TorStrings.settings.provideBridgeHeader;
+ this._textarea = this._dialog.querySelector(selectors.textarea);
+ this._textarea.setAttribute(
+ "placeholder",
+ TorStrings.settings.provideBridgePlaceholder
+ );
+ if (
+ TorSettings.bridges.enabled &&
+ TorSettings.bridges.source == TorBridgeSource.UserProvided
+ ) {
+ this._textarea.value = TorSettings.bridges.bridge_strings.join("\n");
+ }
+
+ this._dialog.addEventListener("dialogaccept", e => {
+ this._bridgeString = this._textarea.value;
+ });
+ }
+
+ init(window, aDialog) {
+ // defer to later until firefox has populated the dialog with all our elements
+ window.setTimeout(() => {
+ this._populateXUL(aDialog);
+ }, 0);
+ }
+
+ openDialog(gSubDialog, aCloseCallback) {
+ gSubDialog.open(
+ "chrome://browser/content/torpreferences/provideBridgeDialog.xhtml",
+ {
+ features: "resizable=yes",
+ closingCallback: () => {
+ aCloseCallback(this._bridgeString);
+ },
+ },
+ this
+ );
+ }
+}
diff --git a/browser/components/torpreferences/content/provideBridgeDialog.xhtml b/browser/components/torpreferences/content/provideBridgeDialog.xhtml
new file mode 100644
index 0000000000000..28d19cadaf9c9
--- /dev/null
+++ b/browser/components/torpreferences/content/provideBridgeDialog.xhtml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
+<?xml-stylesheet href="chrome://browser/content/torpreferences/torPreferences.css"?>
+
+<window type="child"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+<dialog id="torPreferences-provideBridge-dialog"
+ buttons="help,accept,cancel">
+ <html:h3 id="torPreferences-provideBridge-header">​</html:h3>
+ <html:textarea id="torPreferences-provideBridge-textarea" multiline="true" rows="3"/>
+ <script type="application/javascript"><![CDATA[
+ "use strict";
+
+ let provideBridgeDialog = window.arguments[0];
+ let dialog = document.getElementById("torPreferences-provideBridge-dialog");
+ provideBridgeDialog.init(window, dialog);
+ ]]></script>
+</dialog>
+</window>
diff --git a/browser/components/torpreferences/content/requestBridgeDialog.jsm b/browser/components/torpreferences/content/requestBridgeDialog.jsm
index 44ae11762def8..f14bbdcbbb448 100644
--- a/browser/components/torpreferences/content/requestBridgeDialog.jsm
+++ b/browser/components/torpreferences/content/requestBridgeDialog.jsm
@@ -9,7 +9,7 @@ class RequestBridgeDialog {
constructor() {
this._dialog = null;
this._submitButton = null;
- this._dialogDescription = null;
+ this._dialogHeader = null;
this._captchaImage = null;
this._captchaEntryTextbox = null;
this._captchaRefreshButton = null;
@@ -22,7 +22,7 @@ class RequestBridgeDialog {
return {
submitButton:
"accept" /* not really a selector but a key for dialog's getButton */,
- dialogDescription: "description#torPreferences-requestBridge-description",
+ dialogHeader: "h3#torPreferences-requestBridge-header",
captchaImage: "image#torPreferences-requestBridge-captchaImage",
captchaEntryTextbox: "input#torPreferences-requestBridge-captchaTextbox",
refreshCaptchaButton:
@@ -34,7 +34,7 @@ class RequestBridgeDialog {
};
}
- _populateXUL(dialog) {
+ _populateXUL(window, dialog) {
const selectors = RequestBridgeDialog.selectors;
this._dialog = dialog;
@@ -66,12 +66,15 @@ class RequestBridgeDialog {
e.preventDefault();
this.onSubmitCaptcha();
});
+ this._dialog.addEventListener("dialoghelp", e => {
+ window.top.openTrustedLinkIn(
+ "https://tb-manual.torproject.org/bridges/",
+ "tab"
+ );
+ });
- this._dialogDescription = this._dialog.querySelector(
- selectors.dialogDescription
- );
- this._dialogDescription.textContent =
- TorStrings.settings.contactingBridgeDB;
+ this._dialogHeader = this._dialog.querySelector(selectors.dialogHeader);
+ this._dialogHeader.textContent = TorStrings.settings.contactingBridgeDB;
this._captchaImage = this._dialog.querySelector(selectors.captchaImage);
@@ -115,7 +118,7 @@ class RequestBridgeDialog {
_setcaptchaImage(uri) {
if (uri != this._captchaImage.src) {
this._captchaImage.src = uri;
- this._dialogDescription.textContent = TorStrings.settings.solveTheCaptcha;
+ this._dialogHeader.textContent = TorStrings.settings.solveTheCaptcha;
this._setUIDisabled(false);
this._captchaEntryTextbox.focus();
this._captchaEntryTextbox.select();
@@ -135,7 +138,7 @@ class RequestBridgeDialog {
init(window, dialog) {
// defer to later until firefox has populated the dialog with all our elements
window.setTimeout(() => {
- this._populateXUL(dialog);
+ this._populateXUL(window, dialog);
}, 0);
}
@@ -176,15 +179,14 @@ class RequestBridgeDialog {
this._bridges = [];
this._setUIDisabled(false);
this._incorrectCaptchaHbox.style.visibility = "visible";
- console.log(eError);
+ console.log(aError);
});
}
onRefreshCaptcha() {
this._setUIDisabled(true);
this._captchaImage.src = "";
- this._dialogDescription.textContent =
- TorStrings.settings.contactingBridgeDB;
+ this._dialogHeader.textContent = TorStrings.settings.contactingBridgeDB;
this._captchaEntryTextbox.value = "";
this._incorrectCaptchaHbox.style.visibility = "hidden";
@@ -201,9 +203,9 @@ class RequestBridgeDialog {
closingCallback: () => {
this.close();
aCloseCallback(this._bridges);
- }
+ },
},
- this,
+ this
);
}
}
diff --git a/browser/components/torpreferences/content/requestBridgeDialog.xhtml b/browser/components/torpreferences/content/requestBridgeDialog.xhtml
index 64c4507807fbf..b7286528a8a5a 100644
--- a/browser/components/torpreferences/content/requestBridgeDialog.xhtml
+++ b/browser/components/torpreferences/content/requestBridgeDialog.xhtml
@@ -7,11 +7,11 @@
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
<dialog id="torPreferences-requestBridge-dialog"
- buttons="accept,cancel">
+ buttons="help,accept,cancel">
<!-- ok, so ​ is a zero-width space. We need to have *something* in the innerText so that XUL knows how tall the
- description node is so that it can determine how large to make the dialog element's inner draw area. If we have
- nothing in the innerText, then it collapse to 0 height, and the contents of the dialog ends up partially hidden >:( -->
- <description id="torPreferences-requestBridge-description">​</description>
+ title node is so that it can determine how large to make the dialog element's inner draw area. If we have nothing
+ in the innerText, then it collapse to 0 height, and the contents of the dialog ends up partially hidden >:( -->
+ <html:h3 id="torPreferences-requestBridge-header">​</html:h3>
<!-- init to transparent 400x125 png -->
<image id="torPreferences-requestBridge-captchaImage" flex="1"/>
<hbox id="torPreferences-requestBridge-inputHbox">
@@ -32,4 +32,4 @@
requestBridgeDialog.init(window, dialog);
]]></script>
</dialog>
-</window>
\ No newline at end of file
+</window>
diff --git a/browser/components/torpreferences/content/torLogDialog.jsm b/browser/components/torpreferences/content/torLogDialog.jsm
index ecc684d878c20..94a57b9b165ee 100644
--- a/browser/components/torpreferences/content/torLogDialog.jsm
+++ b/browser/components/torpreferences/content/torLogDialog.jsm
@@ -2,6 +2,10 @@
var EXPORTED_SYMBOLS = ["TorLogDialog"];
+const { setTimeout, clearTimeout } = ChromeUtils.import(
+ "resource://gre/modules/Timer.jsm"
+);
+
const { TorProtocolService } = ChromeUtils.import(
"resource:///modules/TorProtocolService.jsm"
);
@@ -12,6 +16,7 @@ class TorLogDialog {
this._dialog = null;
this._logTextarea = null;
this._copyLogButton = null;
+ this._restoreButtonTimeout = null;
}
static get selectors() {
@@ -36,6 +41,19 @@ class TorLogDialog {
this._copyLogButton.setAttribute("label", TorStrings.settings.copyLog);
this._copyLogButton.addEventListener("command", () => {
this.copyTorLog();
+ const label = this._copyLogButton.querySelector("label");
+ label.setAttribute("value", TorStrings.settings.copied);
+ this._copyLogButton.classList.add("primary");
+
+ const RESTORE_TIME = 1200;
+ if (this._restoreButtonTimeout !== null) {
+ clearTimeout(this._restoreButtonTimeout);
+ }
+ this._restoreButtonTimeout = setTimeout(() => {
+ label.setAttribute("value", TorStrings.settings.copyLog);
+ this._copyLogButton.classList.remove("primary");
+ this._restoreButtonTimeout = null;
+ }, RESTORE_TIME);
});
this._logTextarea.value = TorProtocolService.getLog();
diff --git a/browser/components/torpreferences/content/torPane.js b/browser/components/torpreferences/content/torPane.js
deleted file mode 100644
index 58eec7ff74aa6..0000000000000
--- a/browser/components/torpreferences/content/torPane.js
+++ /dev/null
@@ -1,940 +0,0 @@
-"use strict";
-
-/* global Services */
-
-const { TorSettings, TorSettingsTopics, TorSettingsData, TorBridgeSource, TorBuiltinBridgeTypes, TorProxyType } = ChromeUtils.import(
- "resource:///modules/TorSettings.jsm"
-);
-
-const { TorProtocolService } = ChromeUtils.import(
- "resource:///modules/TorProtocolService.jsm"
-);
-
-const { TorConnect, TorConnectTopics, TorConnectState } = ChromeUtils.import(
- "resource:///modules/TorConnect.jsm"
-);
-
-const { TorLogDialog } = ChromeUtils.import(
- "chrome://browser/content/torpreferences/torLogDialog.jsm"
-);
-
-const { RequestBridgeDialog } = ChromeUtils.import(
- "chrome://browser/content/torpreferences/requestBridgeDialog.jsm"
-);
-
-ChromeUtils.defineModuleGetter(
- this,
- "TorStrings",
- "resource:///modules/TorStrings.jsm"
-);
-
-/*
- Tor Pane
-
- Code for populating the XUL in about:preferences#tor, handling input events, interfacing with tor-launcher
-*/
-const gTorPane = (function() {
- /* CSS selectors for all of the Tor Network DOM elements we need to access */
- const selectors = {
- category: {
- title: "label#torPreferences-labelCategory",
- },
- messageBox: {
- box: "div#torPreferences-connectMessageBox",
- message: "td#torPreferences-connectMessageBox-message",
- button: "button#torPreferences-connectMessageBox-button",
- },
- torPreferences: {
- header: "h1#torPreferences-header",
- description: "span#torPreferences-description",
- learnMore: "label#torPreferences-learnMore",
- },
- quickstart: {
- header: "h2#torPreferences-quickstart-header",
- description: "span#torPreferences-quickstart-description",
- enableQuickstartCheckbox: "checkbox#torPreferences-quickstart-toggle",
- },
- bridges: {
- header: "h2#torPreferences-bridges-header",
- description: "span#torPreferences-bridges-description",
- learnMore: "label#torPreferences-bridges-learnMore",
- useBridgeCheckbox: "checkbox#torPreferences-bridges-toggle",
- bridgeSelectionRadiogroup:
- "radiogroup#torPreferences-bridges-bridgeSelection",
- builtinBridgeOption: "radio#torPreferences-bridges-radioBuiltin",
- builtinBridgeList: "menulist#torPreferences-bridges-builtinList",
- requestBridgeOption: "radio#torPreferences-bridges-radioRequestBridge",
- requestBridgeButton: "button#torPreferences-bridges-buttonRequestBridge",
- requestBridgeTextarea:
- "textarea#torPreferences-bridges-textareaRequestBridge",
- provideBridgeOption: "radio#torPreferences-bridges-radioProvideBridge",
- provideBridgeDescription:
- "description#torPreferences-bridges-descriptionProvideBridge",
- provideBridgeTextarea:
- "textarea#torPreferences-bridges-textareaProvideBridge",
- },
- advanced: {
- header: "h2#torPreferences-advanced-header",
- description: "span#torPreferences-advanced-description",
- learnMore: "label#torPreferences-advanced-learnMore",
- useProxyCheckbox: "checkbox#torPreferences-advanced-toggleProxy",
- proxyTypeLabel: "label#torPreferences-localProxy-type",
- proxyTypeList: "menulist#torPreferences-localProxy-builtinList",
- proxyAddressLabel: "label#torPreferences-localProxy-address",
- proxyAddressTextbox: "input#torPreferences-localProxy-textboxAddress",
- proxyPortLabel: "label#torPreferences-localProxy-port",
- proxyPortTextbox: "input#torPreferences-localProxy-textboxPort",
- proxyUsernameLabel: "label#torPreferences-localProxy-username",
- proxyUsernameTextbox: "input#torPreferences-localProxy-textboxUsername",
- proxyPasswordLabel: "label#torPreferences-localProxy-password",
- proxyPasswordTextbox: "input#torPreferences-localProxy-textboxPassword",
- useFirewallCheckbox: "checkbox#torPreferences-advanced-toggleFirewall",
- firewallAllowedPortsLabel: "label#torPreferences-advanced-allowedPorts",
- firewallAllowedPortsTextbox:
- "input#torPreferences-advanced-textboxAllowedPorts",
- torLogsLabel: "label#torPreferences-torLogs",
- torLogsButton: "button#torPreferences-buttonTorLogs",
- },
- }; /* selectors */
-
- let retval = {
- // cached frequently accessed DOM elements
- _messageBox: null,
- _messageBoxMessage: null,
- _messageBoxButton: null,
- _enableQuickstartCheckbox: null,
- _useBridgeCheckbox: null,
- _bridgeSelectionRadiogroup: null,
- _builtinBridgeOption: null,
- _builtinBridgeMenulist: null,
- _requestBridgeOption: null,
- _requestBridgeButton: null,
- _requestBridgeTextarea: null,
- _provideBridgeOption: null,
- _provideBridgeTextarea: null,
- _useProxyCheckbox: null,
- _proxyTypeLabel: null,
- _proxyTypeMenulist: null,
- _proxyAddressLabel: null,
- _proxyAddressTextbox: null,
- _proxyPortLabel: null,
- _proxyPortTextbox: null,
- _proxyUsernameLabel: null,
- _proxyUsernameTextbox: null,
- _proxyPasswordLabel: null,
- _proxyPasswordTextbox: null,
- _useFirewallCheckbox: null,
- _allowedPortsLabel: null,
- _allowedPortsTextbox: null,
-
- // tor network settings
- _bridgeSettings: null,
- _proxySettings: null,
- _firewallSettings: null,
-
- // disables the provided list of elements
- _setElementsDisabled(elements, disabled) {
- for (let currentElement of elements) {
- currentElement.disabled = disabled;
- }
- },
-
- // populate xul with strings and cache the relevant elements
- _populateXUL() {
- // saves tor settings to disk when navigate away from about:preferences
- window.addEventListener("blur", val => {
- TorProtocolService.flushSettings();
- });
-
- document
- .querySelector(selectors.category.title)
- .setAttribute("value", TorStrings.settings.categoryTitle);
-
- let prefpane = document.getElementById("mainPrefPane");
-
- // 'Connect to Tor' Message Bar
-
- this._messageBox = prefpane.querySelector(selectors.messageBox.box);
- this._messageBoxMessage = prefpane.querySelector(selectors.messageBox.message);
- this._messageBoxButton = prefpane.querySelector(selectors.messageBox.button);
- // wire up connect button
- this._messageBoxButton.addEventListener("click", () => {
- TorConnect.beginBootstrap();
- TorConnect.openTorConnect();
- });
-
- this._populateMessagebox = () => {
- if (TorConnect.shouldShowTorConnect &&
- TorConnect.state === TorConnectState.Configuring) {
- // set messagebox style and text
- if (TorProtocolService.torBootstrapErrorOccurred()) {
- this._messageBox.parentNode.style.display = null;
- this._messageBox.className = "error";
- this._messageBoxMessage.innerText = TorStrings.torConnect.tryAgainMessage;
- this._messageBoxButton.innerText = TorStrings.torConnect.tryAgain;
- } else {
- this._messageBox.parentNode.style.display = null;
- this._messageBox.className = "warning";
- this._messageBoxMessage.innerText = TorStrings.torConnect.connectMessage;
- this._messageBoxButton.innerText = TorStrings.torConnect.torConnectButton;
- }
- } else {
- // we need to explicitly hide the groupbox, as switching between
- // the tor pane and other panes will 'unhide' (via the 'hidden'
- // attribute) the groupbox, offsetting all of the content down
- // by the groupbox's margin (even if content is 0 height)
- this._messageBox.parentNode.style.display = "none";
- this._messageBox.className = "hidden";
- this._messageBoxMessage.innerText = "";
- this._messageBoxButton.innerText = "";
- }
- }
- this._populateMessagebox();
- Services.obs.addObserver(this, TorConnectTopics.StateChange);
-
- // update the messagebox whenever we come back to the page
- window.addEventListener("focus", val => {
- this._populateMessagebox();
- });
-
- // Heading
- prefpane.querySelector(selectors.torPreferences.header).innerText =
- TorStrings.settings.torPreferencesHeading;
- prefpane.querySelector(selectors.torPreferences.description).textContent =
- TorStrings.settings.torPreferencesDescription;
- {
- let learnMore = prefpane.querySelector(
- selectors.torPreferences.learnMore
- );
- learnMore.setAttribute("value", TorStrings.settings.learnMore);
- learnMore.setAttribute(
- "href",
- TorStrings.settings.learnMoreTorBrowserURL
- );
- }
-
- // Quickstart
- prefpane.querySelector(selectors.quickstart.header).innerText =
- TorStrings.settings.quickstartHeading;
- prefpane.querySelector(selectors.quickstart.description).textContent =
- TorStrings.settings.quickstartDescription;
-
- this._enableQuickstartCheckbox = prefpane.querySelector(
- selectors.quickstart.enableQuickstartCheckbox
- );
- this._enableQuickstartCheckbox.setAttribute(
- "label",
- TorStrings.settings.quickstartCheckbox
- );
- this._enableQuickstartCheckbox.addEventListener("command", e => {
- const checked = this._enableQuickstartCheckbox.checked;
- TorSettings.quickstart.enabled = checked;
- TorSettings.saveToPrefs().applySettings();
- });
- this._enableQuickstartCheckbox.checked = TorSettings.quickstart.enabled;
- Services.obs.addObserver(this, TorSettingsTopics.SettingChanged);
-
- // Bridge setup
- prefpane.querySelector(selectors.bridges.header).innerText =
- TorStrings.settings.bridgesHeading;
- prefpane.querySelector(selectors.bridges.description).textContent =
- TorStrings.settings.bridgesDescription;
- {
- let learnMore = prefpane.querySelector(selectors.bridges.learnMore);
- learnMore.setAttribute("value", TorStrings.settings.learnMore);
- learnMore.setAttribute("href", TorStrings.settings.learnMoreBridgesURL);
- }
-
- this._useBridgeCheckbox = prefpane.querySelector(
- selectors.bridges.useBridgeCheckbox
- );
- this._useBridgeCheckbox.setAttribute(
- "label",
- TorStrings.settings.useBridge
- );
- this._useBridgeCheckbox.addEventListener("command", e => {
- const checked = this._useBridgeCheckbox.checked;
- gTorPane.onToggleBridge(checked).onUpdateBridgeSettings();
- });
- this._bridgeSelectionRadiogroup = prefpane.querySelector(
- selectors.bridges.bridgeSelectionRadiogroup
- );
- this._bridgeSelectionRadiogroup.value = TorBridgeSource.BuiltIn;
- this._bridgeSelectionRadiogroup.addEventListener("command", e => {
- const value = this._bridgeSelectionRadiogroup.value;
- gTorPane.onSelectBridgeOption(value).onUpdateBridgeSettings();
- });
-
- // Builtin bridges
- this._builtinBridgeOption = prefpane.querySelector(
- selectors.bridges.builtinBridgeOption
- );
- this._builtinBridgeOption.setAttribute(
- "label",
- TorStrings.settings.selectBridge
- );
- this._builtinBridgeOption.setAttribute("value", TorBridgeSource.BuiltIn);
- this._builtinBridgeMenulist = prefpane.querySelector(
- selectors.bridges.builtinBridgeList
- );
- this._builtinBridgeMenulist.addEventListener("command", e => {
- gTorPane.onUpdateBridgeSettings();
- });
-
- // Request bridge
- this._requestBridgeOption = prefpane.querySelector(
- selectors.bridges.requestBridgeOption
- );
- this._requestBridgeOption.setAttribute(
- "label",
- TorStrings.settings.requestBridgeFromTorProject
- );
- this._requestBridgeOption.setAttribute("value", TorBridgeSource.BridgeDB);
- this._requestBridgeButton = prefpane.querySelector(
- selectors.bridges.requestBridgeButton
- );
- this._requestBridgeButton.setAttribute(
- "label",
- TorStrings.settings.requestNewBridge
- );
- this._requestBridgeButton.addEventListener("command", () =>
- gTorPane.onRequestBridge()
- );
- this._requestBridgeTextarea = prefpane.querySelector(
- selectors.bridges.requestBridgeTextarea
- );
-
- // Provide a bridge
- this._provideBridgeOption = prefpane.querySelector(
- selectors.bridges.provideBridgeOption
- );
- this._provideBridgeOption.setAttribute(
- "label",
- TorStrings.settings.provideBridge
- );
- this._provideBridgeOption.setAttribute(
- "value",
- TorBridgeSource.UserProvided
- );
- prefpane.querySelector(
- selectors.bridges.provideBridgeDescription
- ).textContent = TorStrings.settings.provideBridgeDirections;
- this._provideBridgeTextarea = prefpane.querySelector(
- selectors.bridges.provideBridgeTextarea
- );
- this._provideBridgeTextarea.setAttribute(
- "placeholder",
- TorStrings.settings.provideBridgePlaceholder
- );
- this._provideBridgeTextarea.addEventListener("blur", () => {
- gTorPane.onUpdateBridgeSettings();
- });
-
- // Advanced setup
- prefpane.querySelector(selectors.advanced.header).innerText =
- TorStrings.settings.advancedHeading;
- prefpane.querySelector(selectors.advanced.description).textContent =
- TorStrings.settings.advancedDescription;
- {
- let learnMore = prefpane.querySelector(selectors.advanced.learnMore);
- learnMore.setAttribute("value", TorStrings.settings.learnMore);
- learnMore.setAttribute(
- "href",
- TorStrings.settings.learnMoreNetworkSettingsURL
- );
- }
-
- // Local Proxy
- this._useProxyCheckbox = prefpane.querySelector(
- selectors.advanced.useProxyCheckbox
- );
- this._useProxyCheckbox.setAttribute(
- "label",
- TorStrings.settings.useLocalProxy
- );
- this._useProxyCheckbox.addEventListener("command", e => {
- const checked = this._useProxyCheckbox.checked;
- gTorPane.onToggleProxy(checked).onUpdateProxySettings();
- });
- this._proxyTypeLabel = prefpane.querySelector(
- selectors.advanced.proxyTypeLabel
- );
- this._proxyTypeLabel.setAttribute("value", TorStrings.settings.proxyType);
-
- let mockProxies = [
- {
- value: TorProxyType.Socks4,
- label: TorStrings.settings.proxyTypeSOCKS4,
- },
- {
- value: TorProxyType.Socks5,
- label: TorStrings.settings.proxyTypeSOCKS5,
- },
- { value: TorProxyType.HTTPS, label: TorStrings.settings.proxyTypeHTTP },
- ];
- this._proxyTypeMenulist = prefpane.querySelector(
- selectors.advanced.proxyTypeList
- );
- this._proxyTypeMenulist.addEventListener("command", e => {
- const value = this._proxyTypeMenulist.value;
- gTorPane.onSelectProxyType(value).onUpdateProxySettings();
- });
- for (let currentProxy of mockProxies) {
- let menuEntry = document.createXULElement("menuitem");
- menuEntry.setAttribute("value", currentProxy.value);
- menuEntry.setAttribute("label", currentProxy.label);
- this._proxyTypeMenulist
- .querySelector("menupopup")
- .appendChild(menuEntry);
- }
-
- this._proxyAddressLabel = prefpane.querySelector(
- selectors.advanced.proxyAddressLabel
- );
- this._proxyAddressLabel.setAttribute(
- "value",
- TorStrings.settings.proxyAddress
- );
- this._proxyAddressTextbox = prefpane.querySelector(
- selectors.advanced.proxyAddressTextbox
- );
- this._proxyAddressTextbox.setAttribute(
- "placeholder",
- TorStrings.settings.proxyAddressPlaceholder
- );
- this._proxyAddressTextbox.addEventListener("blur", () => {
- gTorPane.onUpdateProxySettings();
- });
- this._proxyPortLabel = prefpane.querySelector(
- selectors.advanced.proxyPortLabel
- );
- this._proxyPortLabel.setAttribute("value", TorStrings.settings.proxyPort);
- this._proxyPortTextbox = prefpane.querySelector(
- selectors.advanced.proxyPortTextbox
- );
- this._proxyPortTextbox.addEventListener("blur", () => {
- gTorPane.onUpdateProxySettings();
- });
- this._proxyUsernameLabel = prefpane.querySelector(
- selectors.advanced.proxyUsernameLabel
- );
- this._proxyUsernameLabel.setAttribute(
- "value",
- TorStrings.settings.proxyUsername
- );
- this._proxyUsernameTextbox = prefpane.querySelector(
- selectors.advanced.proxyUsernameTextbox
- );
- this._proxyUsernameTextbox.setAttribute(
- "placeholder",
- TorStrings.settings.proxyUsernamePasswordPlaceholder
- );
- this._proxyUsernameTextbox.addEventListener("blur", () => {
- gTorPane.onUpdateProxySettings();
- });
- this._proxyPasswordLabel = prefpane.querySelector(
- selectors.advanced.proxyPasswordLabel
- );
- this._proxyPasswordLabel.setAttribute(
- "value",
- TorStrings.settings.proxyPassword
- );
- this._proxyPasswordTextbox = prefpane.querySelector(
- selectors.advanced.proxyPasswordTextbox
- );
- this._proxyPasswordTextbox.setAttribute(
- "placeholder",
- TorStrings.settings.proxyUsernamePasswordPlaceholder
- );
- this._proxyPasswordTextbox.addEventListener("blur", () => {
- gTorPane.onUpdateProxySettings();
- });
-
- // Local firewall
- this._useFirewallCheckbox = prefpane.querySelector(
- selectors.advanced.useFirewallCheckbox
- );
- this._useFirewallCheckbox.setAttribute(
- "label",
- TorStrings.settings.useFirewall
- );
- this._useFirewallCheckbox.addEventListener("command", e => {
- const checked = this._useFirewallCheckbox.checked;
- gTorPane.onToggleFirewall(checked).onUpdateFirewallSettings();
- });
- this._allowedPortsLabel = prefpane.querySelector(
- selectors.advanced.firewallAllowedPortsLabel
- );
- this._allowedPortsLabel.setAttribute(
- "value",
- TorStrings.settings.allowedPorts
- );
- this._allowedPortsTextbox = prefpane.querySelector(
- selectors.advanced.firewallAllowedPortsTextbox
- );
- this._allowedPortsTextbox.setAttribute(
- "placeholder",
- TorStrings.settings.allowedPortsPlaceholder
- );
- this._allowedPortsTextbox.addEventListener("blur", () => {
- gTorPane.onUpdateFirewallSettings();
- });
-
- // Tor logs
- prefpane
- .querySelector(selectors.advanced.torLogsLabel)
- .setAttribute("value", TorStrings.settings.showTorDaemonLogs);
- let torLogsButton = prefpane.querySelector(
- selectors.advanced.torLogsButton
- );
- torLogsButton.setAttribute("label", TorStrings.settings.showLogs);
- torLogsButton.addEventListener("command", () => {
- gTorPane.onViewTorLogs();
- });
-
- // Disable all relevant elements by default
- this._setElementsDisabled(
- [
- this._builtinBridgeOption,
- this._builtinBridgeMenulist,
- this._requestBridgeOption,
- this._requestBridgeButton,
- this._requestBridgeTextarea,
- this._provideBridgeOption,
- this._provideBridgeTextarea,
- this._proxyTypeLabel,
- this._proxyTypeMenulist,
- this._proxyAddressLabel,
- this._proxyAddressTextbox,
- this._proxyPortLabel,
- this._proxyPortTextbox,
- this._proxyUsernameLabel,
- this._proxyUsernameTextbox,
- this._proxyPasswordLabel,
- this._proxyPasswordTextbox,
- this._allowedPortsLabel,
- this._allowedPortsTextbox,
- ],
- true
- );
-
- // init bridge UI
- for (let currentBridge of TorBuiltinBridgeTypes) {
- let menuEntry = document.createXULElement("menuitem");
- menuEntry.setAttribute("value", currentBridge);
- menuEntry.setAttribute("label", currentBridge);
- this._builtinBridgeMenulist
- .querySelector("menupopup")
- .appendChild(menuEntry);
- }
-
- if (TorSettings.bridges.enabled) {
- this.onSelectBridgeOption(TorSettings.bridges.source);
- this.onToggleBridge(
- TorSettings.bridges.source != TorBridgeSource.Invalid
- );
- switch (TorSettings.bridges.source) {
- case TorBridgeSource.Invalid:
- break;
- case TorBridgeSource.BuiltIn:
- this._builtinBridgeMenulist.value = TorSettings.bridges.builtin_type;
- break;
- case TorBridgeSource.BridgeDB:
- this._requestBridgeTextarea.value = TorSettings.bridges.bridge_strings.join("\n");
- break;
- case TorBridgeSource.UserProvided:
- this._provideBridgeTextarea.value = TorSettings.bridges.bridge_strings.join("\n");
- break;
- }
- }
-
- // init proxy UI
- if (TorSettings.proxy.enabled) {
- this.onToggleProxy(true);
- this.onSelectProxyType(TorSettings.proxy.type);
- this._proxyAddressTextbox.value = TorSettings.proxy.address;
- this._proxyPortTextbox.value = TorSettings.proxy.port;
- this._proxyUsernameTextbox.value = TorSettings.proxy.username;
- this._proxyPasswordTextbox.value = TorSettings.proxy.password;
- }
-
- // init firewall
- if (TorSettings.firewall.enabled) {
- this.onToggleFirewall(true);
- this._allowedPortsTextbox.value = TorSettings.firewall.allowed_ports.join(", ");
- }
- },
-
- init() {
- this._populateXUL();
-
- let onUnload = () => {
- window.removeEventListener("unload", onUnload);
- gTorPane.uninit();
- };
- window.addEventListener("unload", onUnload);
- },
-
- uninit() {
- // unregister our observer topics
- Services.obs.removeObserver(this, TorSettingsTopics.SettingChanged);
- Services.obs.removeObserver(this, TorConnectTopics.StateChange);
- },
-
- // whether the page should be present in about:preferences
- get enabled() {
- return TorProtocolService.ownsTorDaemon;
- },
-
- //
- // Callbacks
- //
-
- observe(subject, topic, data) {
- switch (topic) {
- // triggered when a TorSettings param has changed
- case TorSettingsTopics.SettingChanged: {
- let obj = subject?.wrappedJSObject;
- switch(data) {
- case TorSettingsData.QuickStartEnabled: {
- this._enableQuickstartCheckbox.checked = obj.value;
- break;
- }
- }
- break;
- }
- // triggered when tor connect state changes and we may
- // need to update the messagebox
- case TorConnectTopics.StateChange: {
- this._populateMessagebox();
- break;
- }
- }
- },
-
- // callback when using bridges toggled
- onToggleBridge(enabled) {
- this._useBridgeCheckbox.checked = enabled;
- let disabled = !enabled;
-
- // first disable all the bridge related elements
- this._setElementsDisabled(
- [
- this._builtinBridgeOption,
- this._builtinBridgeMenulist,
- this._requestBridgeOption,
- this._requestBridgeButton,
- this._requestBridgeTextarea,
- this._provideBridgeOption,
- this._provideBridgeTextarea,
- ],
- disabled
- );
-
- // and selectively re-enable based on the radiogroup's current value
- if (enabled) {
- this.onSelectBridgeOption(this._bridgeSelectionRadiogroup.value);
- } else {
- this.onSelectBridgeOption(TorBridgeSource.Invalid);
- }
- return this;
- },
-
- // callback when a bridge option is selected
- onSelectBridgeOption(source) {
- if (typeof source === "string") {
- source = parseInt(source);
- }
-
- // disable all of the bridge elements under radio buttons
- this._setElementsDisabled(
- [
- this._builtinBridgeMenulist,
- this._requestBridgeButton,
- this._requestBridgeTextarea,
- this._provideBridgeTextarea,
- ],
- true
- );
-
- if (source != TorBridgeSource.Invalid) {
- this._bridgeSelectionRadiogroup.value = source;
- }
-
- switch (source) {
- case TorBridgeSource.BuiltIn: {
- this._setElementsDisabled([this._builtinBridgeMenulist], false);
- break;
- }
- case TorBridgeSource.BridgeDB: {
- this._setElementsDisabled(
- [this._requestBridgeButton, this._requestBridgeTextarea],
- false
- );
- break;
- }
- case TorBridgeSource.UserProvided: {
- this._setElementsDisabled([this._provideBridgeTextarea], false);
- break;
- }
- }
- return this;
- },
-
- // called when the request bridge button is activated
- onRequestBridge() {
- let requestBridgeDialog = new RequestBridgeDialog();
- requestBridgeDialog.openDialog(
- gSubDialog,
- aBridges => {
- if (aBridges.length > 0) {
- let bridgeStrings = aBridges.join("\n");
- TorSettings.bridges.enabled = true;
- TorSettings.bridges.source = TorBridgeSource.BridgeDB;
- TorSettings.bridges.bridge_strings = bridgeStrings;
- TorSettings.saveToPrefs();
- TorSettings.applySettings().then((result) => {
- this._requestBridgeTextarea.value = bridgeStrings;
- });
- }
- }
- );
- return this;
- },
-
- // pushes bridge settings from UI to tor
- onUpdateBridgeSettings() {
- let source = this._useBridgeCheckbox.checked
- ? parseInt(this._bridgeSelectionRadiogroup.value)
- : TorBridgeSource.Invalid;
-
- switch (source) {
- case TorBridgeSource.Invalid: {
- TorSettings.bridges.enabled = false;
- }
- break;
- case TorBridgeSource.BuiltIn: {
- // if there is a built-in bridge already selected, use that
- let bridgeType = this._builtinBridgeMenulist.value;
- console.log(`bridge type: ${bridgeType}`);
- if (bridgeType) {
- TorSettings.bridges.enabled = true;
- TorSettings.bridges.source = TorBridgeSource.BuiltIn;
- TorSettings.bridges.builtin_type = bridgeType;
- } else {
- TorSettings.bridges.enabled = false;
- }
- break;
- }
- case TorBridgeSource.BridgeDB: {
- // if there are bridgedb bridges saved in the text area, use them
- let bridgeStrings = this._requestBridgeTextarea.value;
- if (bridgeStrings) {
- TorSettings.bridges.enabled = true;
- TorSettings.bridges.source = TorBridgeSource.BridgeDB;
- TorSettings.bridges.bridge_strings = bridgeStrings;
- } else {
- TorSettings.bridges.enabled = false;
- }
- break;
- }
- case TorBridgeSource.UserProvided: {
- // if bridges already exist in the text area, use them
- let bridgeStrings = this._provideBridgeTextarea.value;
- if (bridgeStrings) {
- TorSettings.bridges.enabled = true;
- TorSettings.bridges.source = TorBridgeSource.UserProvided;
- TorSettings.bridges.bridge_strings = bridgeStrings;
- } else {
- TorSettings.bridges.enabled = false;
- }
- break;
- }
- }
- TorSettings.saveToPrefs();
- TorSettings.applySettings();
-
- return this;
- },
-
- // callback when proxy is toggled
- onToggleProxy(enabled) {
- this._useProxyCheckbox.checked = enabled;
- let disabled = !enabled;
-
- this._setElementsDisabled(
- [
- this._proxyTypeLabel,
- this._proxyTypeMenulist,
- this._proxyAddressLabel,
- this._proxyAddressTextbox,
- this._proxyPortLabel,
- this._proxyPortTextbox,
- this._proxyUsernameLabel,
- this._proxyUsernameTextbox,
- this._proxyPasswordLabel,
- this._proxyPasswordTextbox,
- ],
- disabled
- );
- this.onSelectProxyType(this._proxyTypeMenulist.value);
- return this;
- },
-
- // callback when proxy type is changed
- onSelectProxyType(value) {
- if (typeof value === "string") {
- value = parseInt(value);
- }
-
- this._proxyTypeMenulist.value = value;
- switch (value) {
- case TorProxyType.Invalid: {
- this._setElementsDisabled(
- [
- this._proxyAddressLabel,
- this._proxyAddressTextbox,
- this._proxyPortLabel,
- this._proxyPortTextbox,
- this._proxyUsernameLabel,
- this._proxyUsernameTextbox,
- this._proxyPasswordLabel,
- this._proxyPasswordTextbox,
- ],
- true
- ); // DISABLE
-
- this._proxyAddressTextbox.value = "";
- this._proxyPortTextbox.value = "";
- this._proxyUsernameTextbox.value = "";
- this._proxyPasswordTextbox.value = "";
- break;
- }
- case TorProxyType.Socks4: {
- this._setElementsDisabled(
- [
- this._proxyAddressLabel,
- this._proxyAddressTextbox,
- this._proxyPortLabel,
- this._proxyPortTextbox,
- ],
- false
- ); // ENABLE
- this._setElementsDisabled(
- [
- this._proxyUsernameLabel,
- this._proxyUsernameTextbox,
- this._proxyPasswordLabel,
- this._proxyPasswordTextbox,
- ],
- true
- ); // DISABLE
-
- this._proxyUsernameTextbox.value = "";
- this._proxyPasswordTextbox.value = "";
- break;
- }
- case TorProxyType.Socks5:
- case TorProxyType.HTTPS: {
- this._setElementsDisabled(
- [
- this._proxyAddressLabel,
- this._proxyAddressTextbox,
- this._proxyPortLabel,
- this._proxyPortTextbox,
- this._proxyUsernameLabel,
- this._proxyUsernameTextbox,
- this._proxyPasswordLabel,
- this._proxyPasswordTextbox,
- ],
- false
- ); // ENABLE
- break;
- }
- }
- return this;
- },
-
- // pushes proxy settings from UI to tor
- onUpdateProxySettings() {
- const type = this._useProxyCheckbox.checked
- ? parseInt(this._proxyTypeMenulist.value)
- : TorProxyType.Invalid;
- const address = this._proxyAddressTextbox.value;
- const port = this._proxyPortTextbox.value;
- const username = this._proxyUsernameTextbox.value;
- const password = this._proxyPasswordTextbox.value;
-
- switch (type) {
- case TorProxyType.Invalid:
- TorSettings.proxy.enabled = false;
- break;
- case TorProxyType.Socks4:
- TorSettings.proxy.enabled = true;
- TorSettings.proxy.type = type;
- TorSettings.proxy.address = address;
- TorSettings.proxy.port = port;
-
- break;
- case TorProxyType.Socks5:
- TorSettings.proxy.enabled = true;
- TorSettings.proxy.type = type;
- TorSettings.proxy.address = address;
- TorSettings.proxy.port = port;
- TorSettings.proxy.username = username;
- TorSettings.proxy.password = password;
- break;
- case TorProxyType.HTTPS:
- TorSettings.proxy.enabled = true;
- TorSettings.proxy.type = type;
- TorSettings.proxy.address = address;
- TorSettings.proxy.port = port;
- TorSettings.proxy.username = username;
- TorSettings.proxy.password = password;
- break;
- }
- TorSettings.saveToPrefs();
- TorSettings.applySettings();
-
- return this;
- },
-
- // callback when firewall proxy is toggled
- onToggleFirewall(enabled) {
- this._useFirewallCheckbox.checked = enabled;
- let disabled = !enabled;
-
- this._setElementsDisabled(
- [this._allowedPortsLabel, this._allowedPortsTextbox],
- disabled
- );
-
- return this;
- },
-
- // pushes firewall settings from UI to tor
- onUpdateFirewallSettings() {
-
- let portListString = this._useFirewallCheckbox.checked
- ? this._allowedPortsTextbox.value
- : "";
-
- if (portListString) {
- TorSettings.firewall.enabled = true;
- TorSettings.firewall.allowed_ports = portListString;
- } else {
- TorSettings.firewall.enabled = false;
- }
- TorSettings.saveToPrefs();
- TorSettings.applySettings();
-
- return this;
- },
-
- onViewTorLogs() {
- let torLogDialog = new TorLogDialog();
- torLogDialog.openDialog(gSubDialog);
- },
- };
- return retval;
-})(); /* gTorPane */
diff --git a/browser/components/torpreferences/content/torPane.xhtml b/browser/components/torpreferences/content/torPane.xhtml
deleted file mode 100644
index 7c8071f2cf106..0000000000000
--- a/browser/components/torpreferences/content/torPane.xhtml
+++ /dev/null
@@ -1,157 +0,0 @@
-<!-- Tor panel -->
-
-<script type="application/javascript"
- src="chrome://browser/content/torpreferences/torPane.js"/>
-<html:template id="template-paneTor">
-
-<!-- Tor Connect Message Box -->
-<groupbox data-category="paneTor" hidden="true">
- <html:div id="torPreferences-connectMessageBox"
- class="subcategory"
- data-category="paneTor"
- hidden="true">
- <html:table >
- <html:tr>
- <html:td>
- <html:div id="torPreferences-connectMessageBox-icon"/>
- </html:td>
- <html:td id="torPreferences-connectMessageBox-message">
- </html:td>
- <html:td>
- <html:button id="torPreferences-connectMessageBox-button">
- </html:button>
- </html:td>
- </html:tr>
- </html:table>
- </html:div>
-</groupbox>
-
-<hbox id="torPreferencesCategory"
- class="subcategory"
- data-category="paneTor"
- hidden="true">
- <html:h1 id="torPreferences-header"/>
-</hbox>
-
-<groupbox data-category="paneTor"
- hidden="true">
- <description flex="1">
- <html:span id="torPreferences-description" class="tail-with-learn-more"/>
- <label id="torPreferences-learnMore" class="learnMore text-link" is="text-link"/>
- </description>
-</groupbox>
-
-<!-- Quickstart -->
-<groupbox id="torPreferences-quickstart-group"
- data-category="paneTor"
- hidden="true">
- <html:h2 id="torPreferences-quickstart-header"/>
- <description flex="1">
- <html:span id="torPreferences-quickstart-description"/>
- </description>
- <checkbox id="torPreferences-quickstart-toggle"/>
-</groupbox>
-
-<!-- Bridges -->
-<groupbox id="torPreferences-bridges-group"
- data-category="paneTor"
- hidden="true">
- <html:h2 id="torPreferences-bridges-header"/>
- <description flex="1">
- <html:span id="torPreferences-bridges-description" class="tail-with-learn-more"/>
- <label id="torPreferences-bridges-learnMore" class="learnMore text-link" is="text-link"/>
- </description>
- <checkbox id="torPreferences-bridges-toggle"/>
- <radiogroup id="torPreferences-bridges-bridgeSelection">
- <hbox class="indent">
- <radio id="torPreferences-bridges-radioBuiltin"/>
- <spacer flex="1"/>
- <menulist id="torPreferences-bridges-builtinList" class="torMarginFix">
- <menupopup/>
- </menulist>
- </hbox>
- <vbox class="indent">
- <hbox>
- <radio id="torPreferences-bridges-radioRequestBridge"/>
- <space flex="1"/>
- <button id="torPreferences-bridges-buttonRequestBridge" class="torMarginFix"/>
- </hbox>
- <html:textarea
- id="torPreferences-bridges-textareaRequestBridge"
- class="indent torMarginFix"
- multiline="true"
- rows="3"
- readonly="true"/>
- </vbox>
- <hbox class="indent" flex="1">
- <vbox flex="1">
- <radio id="torPreferences-bridges-radioProvideBridge"/>
- <description id="torPreferences-bridges-descriptionProvideBridge" class="indent"/>
- <html:textarea
- id="torPreferences-bridges-textareaProvideBridge"
- class="indent torMarginFix"
- multiline="true"
- rows="3"/>
- </vbox>
- </hbox>
- </radiogroup>
-</groupbox>
-
-<!-- Advanced -->
-<groupbox id="torPreferences-advanced-group"
- data-category="paneTor"
- hidden="true">
- <html:h2 id="torPreferences-advanced-header"/>
- <description flex="1">
- <html:span id="torPreferences-advanced-description" class="tail-with-learn-more"/>
- <label id="torPreferences-advanced-learnMore" class="learnMore text-link" is="text-link" style="display:none"/>
- </description>
- <box id="torPreferences-advanced-grid">
- <!-- Local Proxy -->
- <hbox class="torPreferences-advanced-checkbox-container">
- <checkbox id="torPreferences-advanced-toggleProxy"/>
- </hbox>
- <hbox class="indent" align="center">
- <label id="torPreferences-localProxy-type"/>
- </hbox>
- <hbox align="center">
- <spacer flex="1"/>
- <menulist id="torPreferences-localProxy-builtinList" class="torMarginFix">
- <menupopup/>
- </menulist>
- </hbox>
- <hbox class="indent" align="center">
- <label id="torPreferences-localProxy-address"/>
- </hbox>
- <hbox align="center">
- <html:input id="torPreferences-localProxy-textboxAddress" type="text" class="torMarginFix"/>
- <label id="torPreferences-localProxy-port"/>
- <!-- proxy-port-input class style pulled from preferences.css and used in the vanilla proxy setup menu -->
- <html:input id="torPreferences-localProxy-textboxPort" class="proxy-port-input torMarginFix" hidespinbuttons="true" type="number" min="0" max="65535" maxlength="5"/>
- </hbox>
- <hbox class="indent" align="center">
- <label id="torPreferences-localProxy-username"/>
- </hbox>
- <hbox align="center">
- <html:input id="torPreferences-localProxy-textboxUsername" type="text" class="torMarginFix"/>
- <label id="torPreferences-localProxy-password"/>
- <html:input id="torPreferences-localProxy-textboxPassword" class="torMarginFix" type="password"/>
- </hbox>
- <!-- Firewall -->
- <hbox class="torPreferences-advanced-checkbox-container">
- <checkbox id="torPreferences-advanced-toggleFirewall"/>
- </hbox>
- <hbox class="indent" align="center">
- <label id="torPreferences-advanced-allowedPorts"/>
- </hbox>
- <hbox align="center">
- <html:input id="torPreferences-advanced-textboxAllowedPorts" type="text" class="torMarginFix" value="80,443"/>
- </hbox>
- </box>
- <hbox id="torPreferences-torDaemon-hbox" align="center">
- <label id="torPreferences-torLogs"/>
- <spacer flex="1"/>
- <button id="torPreferences-buttonTorLogs" class="torMarginFix"/>
- </hbox>
-</groupbox>
-</html:template>
\ No newline at end of file
diff --git a/browser/components/torpreferences/content/torPreferences.css b/browser/components/torpreferences/content/torPreferences.css
index b6eb0a740e5e4..31b6e29d679f3 100644
--- a/browser/components/torpreferences/content/torPreferences.css
+++ b/browser/components/torpreferences/content/torPreferences.css
@@ -1,9 +1,14 @@
@import url("chrome://branding/content/tor-styles.css");
-#category-tor > .category-icon {
+#category-connection > .category-icon {
list-style-image: url("chrome://browser/content/torpreferences/torPreferencesIcon.svg");
}
+html:dir(rtl) input[type="checkbox"].toggle-button::before {
+ /* For some reason, the rule from toggle-button.css is not applied... */
+ scale: -1;
+}
+
/* Connect Message Box */
#torPreferences-connectMessageBox {
@@ -64,8 +69,7 @@
#torPreferences-connectMessageBox-message {
line-height: 16px;
- font-size: 1.11em;
- padding-left: 8px!important;
+ padding-inline-start: 8px;
}
#torPreferences-connectMessageBox-button {
@@ -112,36 +116,302 @@
background-color: var(--purple-90);
}
-/* Advanced Settings */
+/* Status */
+#torPreferences-status-box {
+ display: flex;
+ align-items: center;
+}
-#torPreferences-advanced-grid {
+#torPreferences-status-internet-icon, #torPreferences-status-tor-icon {
+ width: 18px;
+ height: 18px;
+ margin-inline-end: 8px;
+}
+
+#torPreferences-status-internet-label, #torPreferences-status-tor-label {
+ font-weight: bold;
+}
+
+#torPreferences-status-internet-icon {
+ list-style-image: url("chrome://devtools/skin/images/globe.svg");
+}
+
+#torPreferences-status-internet-statusIcon.online,
+#torPreferences-status-internet-statusIcon.offline,
+#torPreferences-status-tor-statusIcon {
+ margin-inline-start: 12px;
+ margin-inline-end: 9px;
+}
+
+#torPreferences-status-internet-statusIcon.online, #torPreferences-status-tor-statusIcon.connected {
+ list-style-image: url("chrome://devtools/skin/images/check.svg");
+ -moz-context-properties: fill;
+ fill: var(--purple-60);
+}
+
+#torPreferences-status-internet-status {
+ margin-inline-end: 32px;
+}
+
+#torPreferences-status-tor-icon {
+ list-style-image: url("chrome://browser/skin/onion.svg");
+}
+
+#torPreferences-status-internet-icon, #torPreferences-status-tor-icon {
+ -moz-context-properties: fill;
+ fill: var(--in-content-text-color);
+}
+
+#torPreferences-status-tor-statusIcon, #torPreferences-status-internet-statusIcon.offline {
+ list-style-image: url("chrome://browser/skin/warning.svg");
+}
+
+#torPreferences-status-tor-statusIcon.blocked {
+ -moz-context-properties: fill;
+ fill: var(--red-60);
+}
+
+/* Bridge settings */
+#torPreferences-bridges-location {
+ width: 280px;
+}
+
+/* Bridge cards */
+:root {
+ --bridgeCard-animation-time: 0.25s;
+}
+
+#torPreferences-currentBridges-cards {
+ /* The padding is needed because the mask-image creates an unexpected result
+ otherwise... */
+ padding: 24px 4px;
+}
+
+#torPreferences-currentBridges-cards.list-collapsed {
+ mask-image: linear-gradient(rgb(0, 0, 0), rgba(0, 0, 0, 0.1));
+}
+
+#torPreferences-currentBridges-cards.disabled {
+ opacity: 0.4;
+}
+
+.torPreferences-bridgeCard {
+ padding: 16px 12px;
+ /* define border-radius here because of the transition */
+ border-radius: 4px;
+ transition: margin var(--bridgeCard-animation-time), box-shadow 150ms;
+}
+
+.torPreferences-bridgeCard.expanded {
+ margin: 12px 0;
+ background: var(--in-content-box-background);
+ box-shadow: var(--card-shadow);
+}
+
+.torPreferences-bridgeCard:hover {
+ background: var(--in-content-box-background);
+ box-shadow: var(--card-shadow-hover);
+ cursor: pointer;
+}
+
+.torPreferences-bridgeCard-heading {
+ display: flex;
+ align-items: center;
+}
+
+.torPreferences-bridgeCard-id {
+ font-weight: 700;
+}
+
+.torPreferences-bridgeCard-id .emoji {
+ margin-inline-start: 4px;
+ padding: 4px;
+ font-size: 20px;
+ border-radius: 4px;
+ background: var(--in-content-button-background-hover);
+}
+
+.torPreferences-bridgeCard-headingAddr {
+ /* flex extends the element when needed, but without setting a width (any) the
+ overflow + ellipses does not work. */
+ width: 20px;
+ flex: 1;
+ margin: 0 8px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.expanded .torPreferences-bridgeCard-headingAddr {
+ display: none;
+}
+
+.torPreferences-bridgeCard-buttons {
+ display: flex;
+ align-items: center;
+ margin-inline-start: auto;
+ align-self: center;
+}
+
+.torPreferences-bridgeCard-connectedBadge {
+ display: none;
+ padding: 8px 12px;
+ border-radius: 16px;
+ background: rgba(128, 0, 215, 0.1);
+ color: var(--purple-60);
+}
+
+.currently-connected .torPreferences-bridgeCard-connectedBadge {
+ display: flex;
+}
+
+.torPreferences-bridgeCard-connectedIcon {
+ margin-inline-start: 1px;
+ margin-inline-end: 7px;
+ list-style-image: url("chrome://devtools/skin/images/check.svg");
+ -moz-context-properties: fill;
+ fill: var(--purple-60);
+}
+
+.torPreferences-bridgeCard-options {
+ width: 24px;
+ min-width: 0;
+ height: 24px;
+ min-height: 0;
+ margin-inline-start: 8px;
+ padding: 1px;
+ background-image: url("chrome://global/skin/icons/more.svg");
+ background-repeat: no-repeat;
+ background-position: center center;
+ fill: currentColor;
+ -moz-context-properties: fill;
+}
+
+.torPreferences-bridgeCard-qrWrapper {
+ grid-area: bridge-qr;
+ display: flex;
+ flex-direction: column;
+}
+
+.torPreferences-bridgeCard-qr {
+ width: 126px;
+ position: relative;
+}
+
+.torPreferences-bridgeCard-qrCode {
+ width: 112px;
+ height: 112px;
+ /* Define these colors, as they will be passed to the QR code library */
+ background: var(--in-content-box-background);
+ color: var(--in-content-text-color);
+}
+
+.torPreferences-bridgeCard-qrOnionBox {
+ width: 28px;
+ height: 28px;
+ position: absolute;
+ top: 42px;
+ inset-inline-start: 42px;
+ background: var(--in-content-box-background);
+}
+
+.torPreferences-bridgeCard-qrOnion {
+ width: 16px;
+ height: 16px;
+ position: absolute;
+ top: 48px;
+ inset-inline-start: 48px;
+
+ mask: url("chrome://browser/skin/onion.svg");
+ mask-repeat: no-repeat;
+ mask-size: 16px;
+ background: var(--in-content-text-color);
+}
+
+.torPreferences-bridgeCard-qr:hover .torPreferences-bridgeCard-qrOnionBox {
+ background: var(--in-content-text-color);
+}
+
+.torPreferences-bridgeCard-qr:hover .torPreferences-bridgeCard-qrOnion {
+ mask: url("chrome://global/skin/icons/search-glass.svg");
+ background: var(--in-content-box-background);
+}
+
+.torPreferences-bridgeCard-filler {
+ flex: 1;
+}
+
+.torPreferences-bridgeCard-grid {
+ height: 0; /* We will set it in JS when expanding it! */
display: grid;
- grid-template-columns: auto 1fr;
+ grid-template-rows: auto 1fr;
+ grid-template-columns: auto 1fr auto;
+ grid-template-areas:
+ 'bridge-qr bridge-share bridge-share'
+ 'bridge-qr bridge-address bridge-address'
+ 'bridge-qr bridge-learn-more bridge-copy';
+ padding-top: 12px;
+ visibility: hidden;
}
-.torPreferences-advanced-checkbox-container {
- grid-column: 1 / 3;
+.expanded .torPreferences-bridgeCard-grid {
+ visibility: visible;
}
-#torPreferences-localProxy-textboxAddress,
-#torPreferences-localProxy-textboxUsername,
-#torPreferences-localProxy-textboxPassword,
-#torPreferences-advanced-textboxAllowedPorts {
- -moz-box-flex: 1;
+.torPreferences-bridgeCard-grid.to-animate {
+ transition: height var(--bridgeCard-animation-time) ease-out, visibility var(--bridgeCard-animation-time);
+ overflow: hidden;
+}
+
+.torPreferences-bridgeCard-share {
+ grid-area: bridge-share;
+}
+
+.torPreferences-bridgeCard-addrBox {
+ grid-area: bridge-address;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin: 8px 0;
+}
+
+.torPreferences-bridgeCard-addr {
+ width: 100%;
+}
+
+.torPreferences-bridgeCard-leranMoreBox {
+ grid-area: bridge-learn-more;
+}
+
+.torPreferences-bridgeCard-copy {
+ grid-area: bridge-copy;
+}
+
+#torPreferences-bridgeCard-template {
+ display: none;
+}
+
+/* Advanced Settings */
+#torPreferences-advanced-grid {
+ display: grid;
+ grid-template-columns: 1fr auto;
}
-hbox#torPreferences-torDaemon-hbox {
- margin-top: 20px;
+#torPreferences-advanced-group button {
+ min-width: 150px;
}
-description#torPreferences-requestBridge-description {
- /*margin-bottom: 1em;*/
- min-height: 2em;
+#torPreferences-advanced-hbox, #torPreferences-torDaemon-hbox {
+ padding-inline-end: 15px;
+}
+
+h3#torPreferences-requestBridge-header {
+ margin: 0;
}
image#torPreferences-requestBridge-captchaImage {
- margin: 1em;
- min-height: 125px;
+ margin: 16px 0 8px 0;
+ min-height: 140px;
}
button#torPreferences-requestBridge-refreshCaptchaButton {
@@ -160,6 +430,61 @@ dialog#torPreferences-requestBridge-dialog > hbox {
margin-right : 4px;
}
+/* Show bridge QR dialog */
+#bridgeQr-container {
+ position: relative;
+ height: 300px;
+}
+
+#bridgeQr-target {
+ position: absolute;
+ width: 300px;
+ height: 300px;
+ left: calc(50% - 150px);
+ background: var(--in-content-box-background);
+ color: var(--in-content-text-color);
+}
+
+#bridgeQr-onionBox {
+ position: absolute;
+ width: 70px;
+ height: 70px;
+ top: 115px;
+ left: calc(50% - 35px);
+ background-color: var(--in-content-box-background);
+}
+
+#bridgeQr-onion {
+ position: absolute;
+ width: 38px;
+ height: 38px;
+ top: 131px;
+ left: calc(50% - 19px);
+ mask: url("chrome://browser/skin/onion.svg");
+ mask-repeat: no-repeat;
+ mask-size: 38px;
+ background: var(--in-content-text-color);
+}
+
+/* Builtin bridge dialog */
+#torPreferences-builtinBridge-header {
+ margin: 8px 0 10px 0;
+}
+
+#torPreferences-builtinBridge-description {
+ margin-bottom: 18px;
+}
+
+#torPreferences-builtinBridge-typeSelection {
+ margin-bottom: 16px;
+ min-height: 14em; /* Hack: make room for at least 4 lines of content for 3 types + 2 for spacing */
+}
+
+#torPreferences-builtinBridge-typeSelection radio label {
+ font-weight: 700;
+}
+
+/* Request bridge dialog */
/*
This hbox is hidden by css here by default so that the
xul dialog allocates enough screen space for the error message
@@ -178,6 +503,33 @@ groupbox#torPreferences-bridges-group textarea {
overflow: auto;
}
+/* Provide bridge dialog */
+#torPreferences-provideBridge-header {
+ margin-top: 8px;
+}
+
+/* Connection settings dialog */
+#torPreferences-connection-header {
+ margin: 4px 0 14px 0;
+}
+
+#torPreferences-connection-grid {
+ display: grid;
+ grid-template-columns: auto 1fr;
+}
+
+.torPreferences-connection-checkbox-container {
+ grid-column: 1 / 3;
+}
+
+#torPreferences-localProxy-textboxAddress,
+#torPreferences-localProxy-textboxUsername,
+#torPreferences-localProxy-textboxPassword,
+#torPreferences-connection-textboxAllowedPorts {
+ -moz-box-flex: 1;
+}
+
+/* Tor logs dialog */
textarea#torPreferences-torDialog-textarea {
-moz-box-flex: 1;
font-family: monospace;
@@ -186,4 +538,4 @@ textarea#torPreferences-torDialog-textarea {
overflow: auto;
/* 10 lines */
min-height: 20em;
-}
\ No newline at end of file
+}
diff --git a/browser/components/torpreferences/jar.mn b/browser/components/torpreferences/jar.mn
index 552c92b2feff6..ed3bb441084c9 100644
--- a/browser/components/torpreferences/jar.mn
+++ b/browser/components/torpreferences/jar.mn
@@ -1,10 +1,19 @@
browser.jar:
+ content/browser/torpreferences/bridgeQrDialog.xhtml (content/bridgeQrDialog.xhtml)
+ content/browser/torpreferences/bridgeQrDialog.jsm (content/bridgeQrDialog.jsm)
+ content/browser/torpreferences/builtinBridgeDialog.xhtml (content/builtinBridgeDialog.xhtml)
+ content/browser/torpreferences/builtinBridgeDialog.jsm (content/builtinBridgeDialog.jsm)
+ content/browser/torpreferences/connectionSettingsDialog.xhtml (content/connectionSettingsDialog.xhtml)
+ content/browser/torpreferences/connectionSettingsDialog.jsm (content/connectionSettingsDialog.jsm)
+ content/browser/torpreferences/network.svg (content/network.svg)
+ content/browser/torpreferences/provideBridgeDialog.xhtml (content/provideBridgeDialog.xhtml)
+ content/browser/torpreferences/provideBridgeDialog.jsm (content/provideBridgeDialog.jsm)
content/browser/torpreferences/requestBridgeDialog.xhtml (content/requestBridgeDialog.xhtml)
content/browser/torpreferences/requestBridgeDialog.jsm (content/requestBridgeDialog.jsm)
- content/browser/torpreferences/torCategory.inc.xhtml (content/torCategory.inc.xhtml)
+ content/browser/torpreferences/connectionCategory.inc.xhtml (content/connectionCategory.inc.xhtml)
content/browser/torpreferences/torLogDialog.jsm (content/torLogDialog.jsm)
content/browser/torpreferences/torLogDialog.xhtml (content/torLogDialog.xhtml)
- content/browser/torpreferences/torPane.js (content/torPane.js)
- content/browser/torpreferences/torPane.xhtml (content/torPane.xhtml)
+ content/browser/torpreferences/connectionPane.js (content/connectionPane.js)
+ content/browser/torpreferences/connectionPane.xhtml (content/connectionPane.xhtml)
content/browser/torpreferences/torPreferences.css (content/torPreferences.css)
content/browser/torpreferences/torPreferencesIcon.svg (content/torPreferencesIcon.svg)
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits