Verified Commit fafa8778 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 94a9c8d5
Loading
Loading
Loading
Loading
+44 −45
Original line number Diff line number Diff line
@@ -14,82 +14,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"
@@ -97,8 +96,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);
  }
+67 −38
Original line number Diff line number Diff line
@@ -9,45 +9,74 @@
  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>
    <description id="torPreferences-builtinBridge-description"> </description>
    <radiogroup id="torPreferences-builtinBridge-typeSelection">
      <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
        id="torPreferences-builtinBridges-radioObfs"
            aria-describedby="obfs-bridges-current obfs-bridges-description"
            value="obfs4"
        hidden="true"
          />
          <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="torPreferences-builtinBridges-descrObfs"
        class="indent"
        hidden="true"
        >&#8203;</html:div
          id="obfs-bridges-description"
          class="indent builtin-bridges-option-description"
        >
        </html:div>
      </vbox>
      <vbox class="builtin-bridges-option">
        <hbox>
          <radio
        id="torPreferences-builtinBridges-radioSnowflake"
            aria-describedby="snowflake-bridges-current snowflake-bridges-description"
            value="snowflake"
        hidden="true"
          />
          <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="torPreferences-builtinBridges-descrSnowflake"
        class="indent"
        hidden="true"
        >&#8203;</html:div
          id="snowflake-bridges-description"
          class="indent builtin-bridges-option-description"
        >
        </html:div>
      </vbox>
      <vbox class="builtin-bridges-option">
        <hbox>
          <radio
        id="torPreferences-builtinBridges-radioMeekAzure"
            aria-describedby="meek-bridges-current meek-bridges-description"
            value="meek-azure"
        hidden="true"
          />
          <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="torPreferences-builtinBridges-descrMeekAzure"
        class="indent"
        hidden="true"
        >&#8203;</html:div
          id="meek-bridges-description"
          class="indent builtin-bridges-option-description"
        >
        </html:div>
      </vbox>
    </radiogroup>
    <script type="application/javascript">
      <![CDATA[
+30 −12
Original line number Diff line number Diff line
@@ -116,7 +116,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",
@@ -160,7 +160,7 @@ const gConnectionPane = (function () {

    _controller: null,

    _currentBridge: "",
    _currentBridgeId: null,

    // populate xul with strings and cache the relevant elements
    _populateXUL() {
@@ -463,7 +463,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);
@@ -598,7 +598,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 {
@@ -705,9 +705,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;
            }
          }
@@ -778,7 +778,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
@@ -787,7 +787,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");
@@ -814,6 +814,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 =>
@@ -827,10 +833,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
@@ -148,9 +148,9 @@
        />
        <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