Skip to content
Snippets Groups Projects
Commit db0a953f authored by henry's avatar henry
Browse files

fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in...

fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection

Bug 41734 - Add a connected label to the built-in bridge dialog.
parent c2d6837d
No related branches found
No related tags found
1 merge request!660Bug 41734 - Add a connected label to the built-in bridge dialog.
......@@ -17,82 +17,81 @@ const { TorConnect, TorConnectTopics } = ChromeUtils.import(
);
class BuiltinBridgeDialog {
/**
* Create a new instance.
*
* @param {Function} onSubmit - A callback for when the user accepts the
* dialog selection.
*/
constructor(onSubmit) {
this.onSubmit = onSubmit;
this._dialog = null;
this._acceptButton = null;
}
static get selectors() {
return {
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;
_populateXUL(window, dialog) {
const dialogWin = dialog.parentElement;
dialogWin.setAttribute("title", TorStrings.settings.builtinBridgeHeader);
this._dialog.querySelector(selectors.description).textContent =
TorStrings.settings.builtinBridgeDescription2;
dialog.querySelector(
"#torPreferences-builtinBridge-description"
).textContent = TorStrings.settings.builtinBridgeDescription2;
this._acceptButton = this._dialog.getButton("accept");
this._acceptButton = dialog.getButton("accept");
this.onTorStateChange();
let radioGroup = this._dialog.querySelector(selectors.radiogroup);
const radioGroup = dialog.querySelector(
"#torPreferences-builtinBridge-typeSelection"
);
let types = {
const typeStrings = {
obfs4: {
elemRadio: this._dialog.querySelector(selectors.obfsRadio),
elemDescr: this._dialog.querySelector(selectors.obfsDescr),
label: TorStrings.settings.builtinBridgeObfs4Title,
descr: TorStrings.settings.builtinBridgeObfs4Description2,
},
snowflake: {
elemRadio: this._dialog.querySelector(selectors.snowflakeRadio),
elemDescr: this._dialog.querySelector(selectors.snowflakeDescr),
label: TorStrings.settings.builtinBridgeSnowflake,
descr: TorStrings.settings.builtinBridgeSnowflakeDescription2,
},
"meek-azure": {
elemRadio: this._dialog.querySelector(selectors.meekAzureRadio),
elemDescr: this._dialog.querySelector(selectors.meekAzureDescr),
label: TorStrings.settings.builtinBridgeMeekAzure,
descr: TorStrings.settings.builtinBridgeMeekAzureDescription2,
},
};
TorBuiltinBridgeTypes.forEach(type => {
types[type].elemRadio.setAttribute("label", types[type].label);
types[type].elemRadio.setAttribute("hidden", "false");
types[type].elemDescr.textContent = types[type].descr;
types[type].elemDescr.removeAttribute("hidden");
});
if (
const currentBuiltinType =
TorSettings.bridges.enabled &&
TorSettings.bridges.source == TorBridgeSource.BuiltIn
) {
radioGroup.selectedItem =
types[TorSettings.bridges.builtin_type]?.elemRadio;
? TorSettings.bridges.builtin_type
: null;
if (currentBuiltinType) {
radioGroup.value = currentBuiltinType;
} else {
radioGroup.selectedItem = null;
}
this._dialog.addEventListener("dialogaccept", () => {
for (const optionEl of radioGroup.querySelectorAll(
".builtin-bridges-option"
)) {
const radio = optionEl.querySelector("radio");
const type = radio.value;
optionEl.hidden = !TorBuiltinBridgeTypes.includes(type);
radio.label = typeStrings[type].label;
optionEl.querySelector(
".builtin-bridges-option-description"
).textContent = typeStrings[type].descr;
optionEl.querySelector(
".torPreferences-current-bridge-label"
).textContent = TorStrings.settings.currentBridge;
optionEl.classList.toggle(
"current-builtin-bridge-type",
type === currentBuiltinType
);
}
dialog.addEventListener("dialogaccept", () => {
this.onSubmit(radioGroup.value, TorConnect.canBeginBootstrap);
});
this._dialog.addEventListener("dialoghelp", e => {
dialog.addEventListener("dialoghelp", e => {
window.top.openTrustedLinkIn(
TorStrings.settings.learnMoreCircumventionURL,
"tab"
......@@ -100,8 +99,8 @@ class BuiltinBridgeDialog {
});
// Hack: see the CSS
this._dialog.style.minWidth = "0";
this._dialog.style.minHeight = "0";
dialog.style.minWidth = "0";
dialog.style.minHeight = "0";
Services.obs.addObserver(this, TorConnectTopics.StateChange);
}
......
......@@ -8,16 +8,57 @@
xmlns:html="http://www.w3.org/1999/xhtml">
<dialog id="torPreferences-builtinBridge-dialog"
buttons="help,accept,cancel">
<description>
<html:div id="torPreferences-builtinBridge-description">&#8203;<br/>&#8203;</html:div>
<description id="torPreferences-builtinBridge-description">
</description>
<radiogroup id="torPreferences-builtinBridge-typeSelection">
<radio id="torPreferences-builtinBridges-radioObfs" value="obfs4" hidden="true"/>
<html:div id="torPreferences-builtinBridges-descrObfs" class="indent" hidden="true">&#8203;</html:div>
<radio id="torPreferences-builtinBridges-radioSnowflake" value="snowflake" hidden="true"/>
<html:div id="torPreferences-builtinBridges-descrSnowflake" class="indent" hidden="true">&#8203;</html:div>
<radio id="torPreferences-builtinBridges-radioMeekAzure" value="meek-azure" hidden="true"/>
<html:div id="torPreferences-builtinBridges-descrMeekAzure" class="indent" hidden="true">&#8203;</html:div>
<vbox class="builtin-bridges-option">
<hbox>
<!-- The radio option is described by both the "Current bridge" label
- and the full description. If the "Connected" label is hidden, then
- only the latter description should contribute. -->
<radio aria-describedby="obfs-bridges-current obfs-bridges-description"
value="obfs4"/>
<html:span class="torPreferences-current-bridge-badge">
<image class="torPreferences-current-bridge-icon"/>
<html:span id="obfs-bridges-current"
class="torPreferences-current-bridge-label">
</html:span>
</html:span>
</hbox>
<html:div id="obfs-bridges-description"
class="indent builtin-bridges-option-description">
</html:div>
</vbox>
<vbox class="builtin-bridges-option">
<hbox>
<radio aria-describedby="snowflake-bridges-current snowflake-bridges-description"
value="snowflake"/>
<html:span class="torPreferences-current-bridge-badge">
<image class="torPreferences-current-bridge-icon"/>
<html:span id="snowflake-bridges-current"
class="torPreferences-current-bridge-label">
</html:span>
</html:span>
</hbox>
<html:div id="snowflake-bridges-description"
class="indent builtin-bridges-option-description">
</html:div>
</vbox>
<vbox class="builtin-bridges-option">
<hbox>
<radio aria-describedby="meek-bridges-current meek-bridges-description"
value="meek-azure"/>
<html:span class="torPreferences-current-bridge-badge">
<image class="torPreferences-current-bridge-icon"/>
<html:span id="meek-bridges-current"
class="torPreferences-current-bridge-label">
</html:span>
</html:span>
</hbox>
<html:div id="meek-bridges-description"
class="indent builtin-bridges-option-description">
</html:div>
</vbox>
</radiogroup>
<script type="application/javascript"><![CDATA[
"use strict";
......
......@@ -124,7 +124,7 @@ const gConnectionPane = (function() {
cardId: ".torPreferences-bridgeCard-id",
cardHeadingManualLink: ".torPreferences-bridgeCard-manualLink",
cardHeadingAddr: ".torPreferences-bridgeCard-headingAddr",
cardConnectedLabel: ".torPreferences-bridgeCard-connectedLabel",
cardConnectedLabel: ".torPreferences-current-bridge-label",
cardOptions: ".torPreferences-bridgeCard-options",
cardMenu: "#torPreferences-bridgeCard-menu",
cardQrGrid: ".torPreferences-bridgeCard-grid",
......@@ -168,7 +168,7 @@ const gConnectionPane = (function() {
_controller: null,
_currentBridge: "",
_currentBridgeId: null,
// populate xul with strings and cache the relevant elements
_populateXUL() {
......@@ -471,7 +471,7 @@ const gConnectionPane = (function() {
}
bridgeTemplate.querySelector(
selectors.bridges.cardConnectedLabel
).textContent = TorStrings.settings.statusTorConnected;
).textContent = TorStrings.settings.connectedBridge;
bridgeTemplate
.querySelector(selectors.bridges.cardCopy)
.setAttribute("label", TorStrings.settings.bridgeCopy);
......@@ -607,7 +607,7 @@ const gConnectionPane = (function() {
restoreTimeout = null;
}, RESTORE_TIME);
});
if (details && details.id === this._currentBridge) {
if (details?.id && details.id === this._currentBridgeId) {
card.classList.add("currently-connected");
bridgeCards.prepend(card);
} else {
......@@ -714,9 +714,9 @@ const gConnectionPane = (function() {
// Add only the new strings that remained in the set
for (const bridge of newStrings) {
if (shownCards >= toShow) {
if (this._currentBridge === "") {
if (!this._currentBridgeId) {
break;
} else if (!bridge.includes(this._currentBridge)) {
} else if (!bridge.includes(this._currentBridgeId)) {
continue;
}
}
......@@ -787,7 +787,7 @@ const gConnectionPane = (function() {
)) {
card.classList.remove("currently-connected");
}
if (this._currentBridge === "") {
if (!this._currentBridgeId) {
return;
}
// Make sure we have the connected bridge in the list
......@@ -796,7 +796,7 @@ const gConnectionPane = (function() {
// 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}"]`
`[data-bridge-id="${this._currentBridgeId}"]`
);
for (const card of cards) {
card.classList.add("currently-connected");
......@@ -823,6 +823,12 @@ const gConnectionPane = (function() {
// 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.
// FIXME: We only know the currentBridge *after* a circuit event, but
// if the circuit event is sent *before* about:torpreferences is
// opened we will miss it. Therefore this approach only works if a
// circuit is created after opening about:torconnect. A dedicated
// backend outside of about:preferences would help, and could be
// shared with gTorCircuitPanel. See tor-browser#41700.
this._controller.watchEvent(
"STREAM",
event =>
......@@ -836,10 +842,22 @@ const gConnectionPane = (function() {
}
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].substring(1);
if (bridgeId !== this._currentBridge) {
this._currentBridge = bridgeId;
// The id in the circuit begins with a $ sign.
const id = status.circuit[0][0].replace(/^\$/, "");
if (id !== this._currentBridgeId) {
const bridge = (
await this._controller.getConf("bridge")
)?.find(
foundBridge =>
foundBridge.ID?.toUpperCase() === id.toUpperCase()
);
if (!bridge) {
// Either there is no bridge, or bridge with no
// fingerprint.
this._currentBridgeId = null;
} else {
this._currentBridgeId = id;
}
this._updateConnectedBridges();
}
break;
......
......@@ -109,9 +109,9 @@
<label class="torPreferences-bridgeCard-manualLink learnMore text-link stop-click" is="text-link"/>
<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 class="torPreferences-current-bridge-badge">
<image class="torPreferences-current-bridge-icon"/>
<html:span class="torPreferences-current-bridge-label"></html:span>
</html:span>
<html:button class="torPreferences-bridgeCard-options stop-click"/>
</html:div>
......
......@@ -298,28 +298,38 @@ html:dir(rtl) input[type="checkbox"].toggle-button::before {
align-self: center;
}
.torPreferences-bridgeCard-connectedBadge {
.torPreferences-current-bridge-badge {
/* Hidden by default, otherwise display is "flex". */
display: none;
margin-inline-end: 12px;
color: var(--purple-60);
}
@media (prefers-color-scheme: dark) {
.torPreferences-bridgeCard-connectedBadge {
color: var(--purple-30);
}
align-items: center;
font-size: 0.85em;
}
.currently-connected .torPreferences-bridgeCard-connectedBadge {
:is(
.builtin-bridges-option.current-builtin-bridge-type,
.torPreferences-bridgeCard.currently-connected
) .torPreferences-current-bridge-badge {
display: flex;
}
.torPreferences-bridgeCard-connectedIcon {
.torPreferences-current-bridge-icon {
margin-inline-start: 1px;
margin-inline-end: 7px;
list-style-image: url("chrome://browser/content/torpreferences/check.svg");
-moz-context-properties: fill;
fill: currentColor;
flex: 0 0 auto;
}
.torPreferences-bridgeCard .torPreferences-current-bridge-badge {
color: var(--purple-60);
margin-inline-end: 12px;
}
@media (prefers-color-scheme: dark) {
.torPreferences-bridgeCard .torPreferences-current-bridge-badge {
color: var(--purple-30);
}
}
.torPreferences-bridgeCard-options {
......@@ -564,6 +574,10 @@ dialog#torPreferences-requestBridge-dialog > hbox {
font-weight: 700;
}
.builtin-bridges-option .torPreferences-current-bridge-badge {
color: var(--in-content-accent-color);
}
/* Request bridge dialog */
/*
This hbox is hidden by css here by default so that the
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment