Verified Commit c31a0fce authored by henry's avatar henry Committed by Pier Angelo Vendrame
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 a7845969
Loading
Loading
Loading
Loading
+44 −45
Original line number Diff line number Diff line
@@ -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);
  }
+49 −8
Original line number Diff line number Diff line
@@ -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";
+30 −12
Original line number Diff line number Diff line
@@ -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;
+3 −3
Original line number Diff line number Diff line
@@ -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>
+25 −11
Original line number Diff line number Diff line
@@ -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