[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [Git][tpo/applications/tor-browser][tor-browser-115.7.0esr-13.5-1] 3 commits: fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in...



Title: GitLab

richard pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser

Commits:

  • 47afbf56
    by Henry Wilkes at 2024-01-23T20:27:35+00:00
    fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
    
    Bug 42036: Replace replace/add bridges section with new design, ready
    for Lox.
    
  • 0021e3f3
    by Henry Wilkes at 2024-01-23T20:27:36+00:00
    fixup! Tor Browser strings
    
    Bug 42036: Add strings for adding/replacing bridges.
    
  • c1bcea9d
    by Henry Wilkes at 2024-01-23T20:27:36+00:00
    fixup! Add TorStrings module for localization
    
    Bug 42036: Remove old strings for replacing bridges.
    

11 changed files:

Changes:

  • browser/components/torpreferences/content/bridge-bot.svg
    1
    +<svg width="40" height="44" viewBox="0 0 40 44" fill="none" xmlns="http://www.w3.org/2000/svg">
    
    2
    +<path d="M37.1877 22.7584C38.7409 25.1504 38.9178 27.7923 37.5828 28.6591C36.2478 29.5259 33.9065 28.2895 32.3533 25.8975C30.8001 23.5055 30.6232 20.8637 31.9582 19.9969C33.2932 19.13 35.6345 20.3664 37.1877 22.7584Z" fill="#C069FF"/>
    
    3
    +<path d="M2.81234 22.7584C1.25915 25.1504 1.08224 27.7923 2.41721 28.6591C3.75217 29.5259 6.09349 28.2895 7.64668 25.8975C9.19987 23.5055 9.37678 20.8637 8.04181 19.9969C6.70685 19.13 4.36553 20.3664 2.81234 22.7584Z" fill="#C069FF"/>
    
    4
    +<path d="M32.2002 19.4754C33.9149 19.4754 35.3181 20.8678 35.1823 22.5772C34.7579 27.9186 33.2458 32.9181 30.8541 36.7668C28.0043 41.3527 24.1391 43.9291 20.1088 43.9291C16.0785 43.9291 12.2133 41.3527 9.36344 36.7668C6.97177 32.9181 5.45965 27.9186 5.03525 22.5772C4.89944 20.8678 6.30265 19.4754 8.0174 19.4754L32.2002 19.4754Z" fill="#C069FF"/>
    
    5
    +<path d="M28.4375 32.1121C28.4375 27.4522 24.6599 23.6746 20 23.6746C15.3401 23.6746 11.5625 27.4522 11.5625 32.1121V33.5139H12.8809V32.1121C12.8809 28.1803 16.0682 24.9929 20 24.9929C23.9318 24.9929 27.1191 28.1803 27.1191 32.1121V33.5139H28.4375V32.1121Z" fill="#15141A"/>
    
    6
    +<path d="M25.9062 32.1121C25.9062 28.8501 23.2619 26.2058 20 26.2058C16.7381 26.2058 14.0937 28.8501 14.0937 32.1121L14.0936 33.5139H15.412L15.4121 32.1121C15.4121 29.5782 17.4662 27.5242 20 27.5242C22.5338 27.5242 24.5879 29.5782 24.5879 32.1121L24.588 33.5139H25.9064L25.9062 32.1121Z" fill="#15141A"/>
    
    7
    +<path d="M20 28.7371C21.864 28.7371 23.375 30.2481 23.375 32.1121L23.3753 33.5139H22.0569L22.0566 32.1121C22.0566 30.9762 21.1359 30.0554 20 30.0554C18.8642 30.0554 17.9434 30.9762 17.9434 32.1121L17.9431 33.5139H16.6247V32.1121C16.6247 30.2481 18.136 28.7371 20 28.7371Z" fill="#15141A"/>
    
    8
    +<path d="M8.9145 17.8162C7.19975 17.8162 5.78665 16.4193 6.02668 14.7215C6.53221 11.1456 7.9061 7.82078 9.99195 5.21826C12.6698 1.87706 16.3018 -1.07451e-07 20.0889 0C23.8759 1.07451e-07 27.5079 1.87706 30.1858 5.21826C32.2716 7.82078 33.6455 11.1456 34.151 14.7215C34.3911 16.4193 32.978 17.8162 31.2632 17.8162H8.9145Z" fill="#C069FF"/>
    
    9
    +<path d="M13.1064 15.1091C11.3916 15.1091 9.96814 13.7048 10.3139 12.0252C10.7578 9.86855 11.6634 7.87853 12.956 6.27814C14.8477 3.93602 17.4134 2.62024 20.0887 2.62024C22.7639 2.62024 25.3296 3.93602 27.2213 6.27814C28.514 7.87853 29.4195 9.86855 29.8635 12.0252C30.2092 13.7048 28.7857 15.1091 27.071 15.1091H13.1064Z" fill="#EBD0FF"/>
    
    10
    +<path d="M17.5125 6.81215C17.5125 7.58388 16.9065 8.2095 16.1589 8.2095C15.4112 8.2095 14.8052 7.58388 14.8052 6.81215C14.8052 6.04041 15.4112 5.41479 16.1589 5.41479C16.9065 5.41479 17.5125 6.04041 17.5125 6.81215Z" fill="#15141A"/>
    
    11
    +<path d="M25.1981 6.81215C25.1981 7.58388 24.592 8.2095 23.8444 8.2095C23.0968 8.2095 22.4907 7.58388 22.4907 6.81215C22.4907 6.04041 23.0968 5.41479 23.8444 5.41479C24.592 5.41479 25.1981 6.04041 25.1981 6.81215Z" fill="#15141A"/>
    
    12
    +<path fill-rule="evenodd" clip-rule="evenodd" d="M22.4395 9.01993L22.4044 9.11353C21.5971 11.2673 18.526 11.1951 17.8208 9.0058L18.427 8.81052C18.9472 10.4254 21.2125 10.4787 21.808 8.88998L21.8431 8.79639L22.4395 9.01993Z" fill="#15141A"/>
    
    13
    +</svg>

  • browser/components/torpreferences/content/connectionPane.js
    ... ... @@ -1316,6 +1316,18 @@ const gBridgeSettings = {
    1316 1316
        * @type {Element?}
    
    1317 1317
        */
    
    1318 1318
       _noBridgesEl: null,
    
    1319
    +  /**
    
    1320
    +   * The heading element for changing bridges.
    
    1321
    +   *
    
    1322
    +   * @type {Element?}
    
    1323
    +   */
    
    1324
    +  _changeHeadingEl: null,
    
    1325
    +  /**
    
    1326
    +   * The button for user to provide a bridge address or share code.
    
    1327
    +   *
    
    1328
    +   * @type {Element?}
    
    1329
    +   */
    
    1330
    +  _userProvideButton: null,
    
    1319 1331
     
    
    1320 1332
       /**
    
    1321 1333
        * Initialize the bridge settings.
    
    ... ... @@ -1345,6 +1357,47 @@ const gBridgeSettings = {
    1345 1357
           });
    
    1346 1358
         });
    
    1347 1359
     
    
    1360
    +    this._changeHeadingEl = document.getElementById(
    
    1361
    +      "tor-bridges-change-heading"
    
    1362
    +    );
    
    1363
    +    this._userProvideButton = document.getElementById(
    
    1364
    +      "tor-bridges-open-user-provide-dialog-button"
    
    1365
    +    );
    
    1366
    +
    
    1367
    +    document.l10n.setAttributes(
    
    1368
    +      document.getElementById("tor-bridges-user-provide-description"),
    
    1369
    +      // TODO: Set a different string if we have Lox enabled.
    
    1370
    +      "tor-bridges-add-addresses-description"
    
    1371
    +    );
    
    1372
    +
    
    1373
    +    // TODO: Change to GetLoxBridges if Lox enabled, and the account is set up.
    
    1374
    +    const telegramUserName = "GetBridgesBot";
    
    1375
    +    const telegramInstruction = document.getElementById(
    
    1376
    +      "tor-bridges-provider-instruction-telegram"
    
    1377
    +    );
    
    1378
    +    telegramInstruction.querySelector(
    
    1379
    +      "a"
    
    1380
    +    ).href = `https://t.me/${telegramUserName}`;
    
    1381
    +    document.l10n.setAttributes(
    
    1382
    +      telegramInstruction,
    
    1383
    +      "tor-bridges-provider-telegram-instruction",
    
    1384
    +      { telegramUserName }
    
    1385
    +    );
    
    1386
    +
    
    1387
    +    document
    
    1388
    +      .getElementById("tor-bridges-open-built-in-dialog-button")
    
    1389
    +      .addEventListener("click", () => {
    
    1390
    +        this._openBuiltinDialog();
    
    1391
    +      });
    
    1392
    +    this._userProvideButton.addEventListener("click", () => {
    
    1393
    +      this._openUserProvideDialog(this._haveBridges ? "replace" : "add");
    
    1394
    +    });
    
    1395
    +    document
    
    1396
    +      .getElementById("tor-bridges-open-request-dialog-button")
    
    1397
    +      .addEventListener("click", () => {
    
    1398
    +        this._openRequestDialog();
    
    1399
    +      });
    
    1400
    +
    
    1348 1401
         Services.obs.addObserver(this, TorSettingsTopics.SettingsChanged);
    
    1349 1402
     
    
    1350 1403
         gBridgeGrid.init();
    
    ... ... @@ -1488,6 +1541,17 @@ const gBridgeSettings = {
    1488 1541
         // and hidden.
    
    1489 1542
         this._groupEl.classList.toggle("no-bridges", !haveBridges);
    
    1490 1543
         this._groupEl.classList.toggle("have-bridges", haveBridges);
    
    1544
    +
    
    1545
    +    document.l10n.setAttributes(
    
    1546
    +      this._changeHeadingEl,
    
    1547
    +      haveBridges
    
    1548
    +        ? "tor-bridges-replace-bridges-heading"
    
    1549
    +        : "tor-bridges-add-bridges-heading"
    
    1550
    +    );
    
    1551
    +    document.l10n.setAttributes(
    
    1552
    +      this._userProvideButton,
    
    1553
    +      haveBridges ? "tor-bridges-replace-button" : "tor-bridges-add-new-button"
    
    1554
    +    );
    
    1491 1555
       },
    
    1492 1556
     
    
    1493 1557
       /**
    
    ... ... @@ -1615,9 +1679,7 @@ const gBridgeSettings = {
    1615 1679
           "tor-bridges-options-edit-all-menu-item"
    
    1616 1680
         );
    
    1617 1681
         editItem.addEventListener("click", () => {
    
    1618
    -      // TODO: move to gBridgeSettings.
    
    1619
    -      // TODO: Change dialog title. Do not allow Lox invite.
    
    1620
    -      gConnectionPane.onAddBridgeManually();
    
    1682
    +      this._openUserProvideDialog("edit");
    
    1621 1683
         });
    
    1622 1684
     
    
    1623 1685
         // TODO: Do we want a different item for built-in bridges, rather than
    
    ... ... @@ -1687,6 +1749,138 @@ const gBridgeSettings = {
    1687 1749
       _forceCloseBridgesMenu() {
    
    1688 1750
         this._bridgesMenu.hide(null, { force: true });
    
    1689 1751
       },
    
    1752
    +
    
    1753
    +  /**
    
    1754
    +   * Open a bridge dialog that will change the users bridges.
    
    1755
    +   *
    
    1756
    +   * @param {string} url - The url of the dialog to open.
    
    1757
    +   * @param {object?} inputData - The input data to send to the dialog window.
    
    1758
    +   * @param {Function} onAccept - The method to call if the bridge dialog was
    
    1759
    +   *   accepted by the user. This will be passed a "result" object containing
    
    1760
    +   *   data set by the dialog. This should return a promise that resolves once
    
    1761
    +   *   the bridge settings have been set, or null if the settings have not
    
    1762
    +   *   been applied.
    
    1763
    +   */
    
    1764
    +  _openDialog(url, inputData, onAccept) {
    
    1765
    +    const result = { accepted: false, connect: false };
    
    1766
    +    let savedSettings = null;
    
    1767
    +    gSubDialog.open(
    
    1768
    +      url,
    
    1769
    +      {
    
    1770
    +        features: "resizable=yes",
    
    1771
    +        closingCallback: () => {
    
    1772
    +          if (!result.accepted) {
    
    1773
    +            return;
    
    1774
    +          }
    
    1775
    +          savedSettings = onAccept(result);
    
    1776
    +          if (!savedSettings) {
    
    1777
    +            // No change in settings.
    
    1778
    +            return;
    
    1779
    +          }
    
    1780
    +          if (!result.connect) {
    
    1781
    +            // Do not open about:torconnect.
    
    1782
    +            return;
    
    1783
    +          }
    
    1784
    +
    
    1785
    +          // Wait until the settings are applied before bootstrapping.
    
    1786
    +          savedSettings.then(() => {
    
    1787
    +            // The bridge dialog button is "connect" when Tor is not
    
    1788
    +            // bootstrapped, so do the connect.
    
    1789
    +
    
    1790
    +            // Start Bootstrapping, which should use the configured bridges.
    
    1791
    +            // NOTE: We do this regardless of any previous TorConnect Error.
    
    1792
    +            if (TorConnect.canBeginBootstrap) {
    
    1793
    +              TorConnect.beginBootstrap();
    
    1794
    +            }
    
    1795
    +            // Open "about:torconnect".
    
    1796
    +            // FIXME: If there has been a previous bootstrapping error then
    
    1797
    +            // "about:torconnect" will be trying to get the user to use
    
    1798
    +            // AutoBootstrapping. It is not set up to handle a forced direct
    
    1799
    +            // entry to plain Bootstrapping from this dialog so the UI will
    
    1800
    +            // not be aligned. In particular the
    
    1801
    +            // AboutTorConnect.uiState.bootstrapCause will be aligned to
    
    1802
    +            // whatever was shown previously in "about:torconnect" instead.
    
    1803
    +            TorConnect.openTorConnect();
    
    1804
    +          });
    
    1805
    +        },
    
    1806
    +        // closedCallback should be called after gSubDialog has already
    
    1807
    +        // re-assigned focus back to the document.
    
    1808
    +        closedCallback: () => {
    
    1809
    +          if (!savedSettings) {
    
    1810
    +            return;
    
    1811
    +          }
    
    1812
    +          // Wait until the settings have changed, so that the UI could
    
    1813
    +          // respond, then move focus.
    
    1814
    +          savedSettings.then(() => gBridgeSettings.takeFocus());
    
    1815
    +        },
    
    1816
    +      },
    
    1817
    +      result,
    
    1818
    +      inputData
    
    1819
    +    );
    
    1820
    +  },
    
    1821
    +
    
    1822
    +  /**
    
    1823
    +   * Open the built-in bridge dialog.
    
    1824
    +   */
    
    1825
    +  _openBuiltinDialog() {
    
    1826
    +    this._openDialog(
    
    1827
    +      "chrome://browser/content/torpreferences/builtinBridgeDialog.xhtml",
    
    1828
    +      null,
    
    1829
    +      result => {
    
    1830
    +        if (!result.type) {
    
    1831
    +          return null;
    
    1832
    +        }
    
    1833
    +        return setTorSettings(() => {
    
    1834
    +          TorSettings.bridges.enabled = true;
    
    1835
    +          TorSettings.bridges.source = TorBridgeSource.BuiltIn;
    
    1836
    +          TorSettings.bridges.builtin_type = result.type;
    
    1837
    +        });
    
    1838
    +      }
    
    1839
    +    );
    
    1840
    +  },
    
    1841
    +
    
    1842
    +  /*
    
    1843
    +   * Open the request bridge dialog.
    
    1844
    +   */
    
    1845
    +  _openRequestDialog() {
    
    1846
    +    this._openDialog(
    
    1847
    +      "chrome://browser/content/torpreferences/requestBridgeDialog.xhtml",
    
    1848
    +      null,
    
    1849
    +      result => {
    
    1850
    +        if (!result.bridges?.length) {
    
    1851
    +          return null;
    
    1852
    +        }
    
    1853
    +        return setTorSettings(() => {
    
    1854
    +          TorSettings.bridges.enabled = true;
    
    1855
    +          TorSettings.bridges.source = TorBridgeSource.BridgeDB;
    
    1856
    +          TorSettings.bridges.bridge_strings = result.bridges.join("\n");
    
    1857
    +        });
    
    1858
    +      }
    
    1859
    +    );
    
    1860
    +  },
    
    1861
    +
    
    1862
    +  /**
    
    1863
    +   * Open the user provide dialog.
    
    1864
    +   *
    
    1865
    +   * @param {string} mode - The mode to open the dialog in: "add", "replace" or
    
    1866
    +   *   "edit".
    
    1867
    +   */
    
    1868
    +  _openUserProvideDialog(mode) {
    
    1869
    +    this._openDialog(
    
    1870
    +      "chrome://browser/content/torpreferences/provideBridgeDialog.xhtml",
    
    1871
    +      { mode },
    
    1872
    +      result => {
    
    1873
    +        if (!result.bridgeStrings) {
    
    1874
    +          return null;
    
    1875
    +        }
    
    1876
    +        return setTorSettings(() => {
    
    1877
    +          TorSettings.bridges.enabled = true;
    
    1878
    +          TorSettings.bridges.source = TorBridgeSource.UserProvided;
    
    1879
    +          TorSettings.bridges.bridge_strings = result.bridgeStrings;
    
    1880
    +        });
    
    1881
    +      }
    
    1882
    +    );
    
    1883
    +  },
    
    1690 1884
     };
    
    1691 1885
     
    
    1692 1886
     /*
    
    ... ... @@ -1719,13 +1913,6 @@ const gConnectionPane = (function () {
    1719 1913
           location: "#torPreferences-bridges-location",
    
    1720 1914
           locationEntries: "#torPreferences-bridges-locationEntries",
    
    1721 1915
           chooseForMe: "#torPreferences-bridges-buttonChooseBridgeForMe",
    
    1722
    -      addHeader: "#torPreferences-addBridge-header",
    
    1723
    -      addBuiltinLabel: "#torPreferences-addBridge-labelBuiltinBridge",
    
    1724
    -      addBuiltinButton: "#torPreferences-addBridge-buttonBuiltinBridge",
    
    1725
    -      requestLabel: "#torPreferences-addBridge-labelRequestBridge",
    
    1726
    -      requestButton: "#torPreferences-addBridge-buttonRequestBridge",
    
    1727
    -      enterLabel: "#torPreferences-addBridge-labelEnterBridge",
    
    1728
    -      enterButton: "#torPreferences-addBridge-buttonEnterBridge",
    
    1729 1916
         },
    
    1730 1917
         advanced: {
    
    1731 1918
           header: "h1#torPreferences-advanced-header",
    
    ... ... @@ -1985,39 +2172,6 @@ const gConnectionPane = (function () {
    1985 2172
             this._showAutoconfiguration();
    
    1986 2173
           }
    
    1987 2174
     
    
    1988
    -      // Add a new bridge
    
    1989
    -      prefpane.querySelector(selectors.bridges.addHeader).textContent =
    
    1990
    -        TorStrings.settings.bridgeAdd;
    
    1991
    -      prefpane.querySelector(selectors.bridges.addBuiltinLabel).textContent =
    
    1992
    -        TorStrings.settings.bridgeSelectBrowserBuiltin;
    
    1993
    -      {
    
    1994
    -        const button = prefpane.querySelector(
    
    1995
    -          selectors.bridges.addBuiltinButton
    
    1996
    -        );
    
    1997
    -        button.setAttribute("label", TorStrings.settings.bridgeSelectBuiltin);
    
    1998
    -        button.addEventListener("command", e => {
    
    1999
    -          this.onAddBuiltinBridge();
    
    2000
    -        });
    
    2001
    -      }
    
    2002
    -      prefpane.querySelector(selectors.bridges.requestLabel).textContent =
    
    2003
    -        TorStrings.settings.bridgeRequestFromTorProject;
    
    2004
    -      {
    
    2005
    -        const button = prefpane.querySelector(selectors.bridges.requestButton);
    
    2006
    -        button.setAttribute("label", TorStrings.settings.bridgeRequest);
    
    2007
    -        button.addEventListener("command", e => {
    
    2008
    -          this.onRequestBridge();
    
    2009
    -        });
    
    2010
    -      }
    
    2011
    -      prefpane.querySelector(selectors.bridges.enterLabel).textContent =
    
    2012
    -        TorStrings.settings.bridgeEnterKnown;
    
    2013
    -      {
    
    2014
    -        const button = prefpane.querySelector(selectors.bridges.enterButton);
    
    2015
    -        button.setAttribute("label", TorStrings.settings.bridgeAddManually);
    
    2016
    -        button.addEventListener("command", e => {
    
    2017
    -          this.onAddBridgeManually();
    
    2018
    -        });
    
    2019
    -      }
    
    2020
    -
    
    2021 2175
           // Advanced setup
    
    2022 2176
           prefpane.querySelector(selectors.advanced.header).innerText =
    
    2023 2177
             TorStrings.settings.advancedHeading;
    
    ... ... @@ -2122,122 +2276,6 @@ const gConnectionPane = (function () {
    2122 2276
           this._showAutoconfiguration();
    
    2123 2277
         },
    
    2124 2278
     
    
    2125
    -    /**
    
    2126
    -     * Open a bridge dialog that will change the users bridges.
    
    2127
    -     *
    
    2128
    -     * @param {string} url - The url of the dialog to open.
    
    2129
    -     * @param {Function} onAccept - The method to call if the bridge dialog was
    
    2130
    -     *   accepted by the user. This will be passed a "result" object containing
    
    2131
    -     *   data set by the dialog. This should return a promise that resolves once
    
    2132
    -     *   the bridge settings have been set, or null if the settings have not
    
    2133
    -     *   been applied.
    
    2134
    -     */
    
    2135
    -    openBridgeDialog(url, onAccept) {
    
    2136
    -      const result = { accepted: false, connect: false };
    
    2137
    -      let savedSettings = null;
    
    2138
    -      gSubDialog.open(
    
    2139
    -        url,
    
    2140
    -        {
    
    2141
    -          features: "resizable=yes",
    
    2142
    -          closingCallback: () => {
    
    2143
    -            if (!result.accepted) {
    
    2144
    -              return;
    
    2145
    -            }
    
    2146
    -            savedSettings = onAccept(result);
    
    2147
    -            if (!savedSettings) {
    
    2148
    -              // No change in settings.
    
    2149
    -              return;
    
    2150
    -            }
    
    2151
    -            if (!result.connect) {
    
    2152
    -              // Do not open about:torconnect.
    
    2153
    -              return;
    
    2154
    -            }
    
    2155
    -
    
    2156
    -            // Wait until the settings are applied before bootstrapping.
    
    2157
    -            savedSettings.then(() => {
    
    2158
    -              // The bridge dialog button is "connect" when Tor is not
    
    2159
    -              // bootstrapped, so do the connect.
    
    2160
    -
    
    2161
    -              // Start Bootstrapping, which should use the configured bridges.
    
    2162
    -              // NOTE: We do this regardless of any previous TorConnect Error.
    
    2163
    -              if (TorConnect.canBeginBootstrap) {
    
    2164
    -                TorConnect.beginBootstrap();
    
    2165
    -              }
    
    2166
    -              // Open "about:torconnect".
    
    2167
    -              // FIXME: If there has been a previous bootstrapping error then
    
    2168
    -              // "about:torconnect" will be trying to get the user to use
    
    2169
    -              // AutoBootstrapping. It is not set up to handle a forced direct
    
    2170
    -              // entry to plain Bootstrapping from this dialog so the UI will
    
    2171
    -              // not be aligned. In particular the
    
    2172
    -              // AboutTorConnect.uiState.bootstrapCause will be aligned to
    
    2173
    -              // whatever was shown previously in "about:torconnect" instead.
    
    2174
    -              TorConnect.openTorConnect();
    
    2175
    -            });
    
    2176
    -          },
    
    2177
    -          // closedCallback should be called after gSubDialog has already
    
    2178
    -          // re-assigned focus back to the document.
    
    2179
    -          closedCallback: () => {
    
    2180
    -            if (!savedSettings) {
    
    2181
    -              return;
    
    2182
    -            }
    
    2183
    -            // Wait until the settings have changed, so that the UI could
    
    2184
    -            // respond, then move focus.
    
    2185
    -            savedSettings.then(() => gCurrentBridgesArea.takeFocus());
    
    2186
    -          },
    
    2187
    -        },
    
    2188
    -        result
    
    2189
    -      );
    
    2190
    -    },
    
    2191
    -
    
    2192
    -    onAddBuiltinBridge() {
    
    2193
    -      this.openBridgeDialog(
    
    2194
    -        "chrome://browser/content/torpreferences/builtinBridgeDialog.xhtml",
    
    2195
    -        result => {
    
    2196
    -          if (!result.type) {
    
    2197
    -            return null;
    
    2198
    -          }
    
    2199
    -          return setTorSettings(() => {
    
    2200
    -            TorSettings.bridges.enabled = true;
    
    2201
    -            TorSettings.bridges.source = TorBridgeSource.BuiltIn;
    
    2202
    -            TorSettings.bridges.builtin_type = result.type;
    
    2203
    -          });
    
    2204
    -        }
    
    2205
    -      );
    
    2206
    -    },
    
    2207
    -
    
    2208
    -    // called when the request bridge button is activated
    
    2209
    -    onRequestBridge() {
    
    2210
    -      this.openBridgeDialog(
    
    2211
    -        "chrome://browser/content/torpreferences/requestBridgeDialog.xhtml",
    
    2212
    -        result => {
    
    2213
    -          if (!result.bridges?.length) {
    
    2214
    -            return null;
    
    2215
    -          }
    
    2216
    -          return setTorSettings(() => {
    
    2217
    -            TorSettings.bridges.enabled = true;
    
    2218
    -            TorSettings.bridges.source = TorBridgeSource.BridgeDB;
    
    2219
    -            TorSettings.bridges.bridge_strings = result.bridges.join("\n");
    
    2220
    -          });
    
    2221
    -        }
    
    2222
    -      );
    
    2223
    -    },
    
    2224
    -
    
    2225
    -    onAddBridgeManually() {
    
    2226
    -      this.openBridgeDialog(
    
    2227
    -        "chrome://browser/content/torpreferences/provideBridgeDialog.xhtml",
    
    2228
    -        result => {
    
    2229
    -          if (!result.bridgeStrings) {
    
    2230
    -            return null;
    
    2231
    -          }
    
    2232
    -          return setTorSettings(() => {
    
    2233
    -            TorSettings.bridges.enabled = true;
    
    2234
    -            TorSettings.bridges.source = TorBridgeSource.UserProvided;
    
    2235
    -            TorSettings.bridges.bridge_strings = result.bridgeStrings;
    
    2236
    -          });
    
    2237
    -        }
    
    2238
    -      );
    
    2239
    -    },
    
    2240
    -
    
    2241 2279
         onAdvancedSettings() {
    
    2242 2280
           gSubDialog.open(
    
    2243 2281
             "chrome://browser/content/torpreferences/connectionSettingsDialog.xhtml",
    

  • browser/components/torpreferences/content/connectionPane.xhtml
    ... ... @@ -293,28 +293,102 @@
    293 293
             ></html:button>
    
    294 294
           </html:div>
    
    295 295
         </html:div>
    
    296
    -    <html:h2 id="torPreferences-addBridge-header"></html:h2>
    
    296
    +    <html:h2 id="tor-bridges-change-heading"></html:h2>
    
    297 297
         <hbox align="center">
    
    298
    -      <label id="torPreferences-addBridge-labelBuiltinBridge" flex="1" />
    
    299
    -      <button
    
    300
    -        id="torPreferences-addBridge-buttonBuiltinBridge"
    
    301
    -        class="accessory-button"
    
    298
    +      <description
    
    299
    +        flex="1"
    
    300
    +        data-l10n-id="tor-bridges-select-built-in-description"
    
    302 301
           />
    
    303
    -    </hbox>
    
    304
    -    <hbox align="center">
    
    305
    -      <label id="torPreferences-addBridge-labelRequestBridge" flex="1" />
    
    306
    -      <button
    
    307
    -        id="torPreferences-addBridge-buttonRequestBridge"
    
    302
    +      <html:button
    
    303
    +        id="tor-bridges-open-built-in-dialog-button"
    
    308 304
             class="accessory-button"
    
    309
    -      />
    
    305
    +        data-l10n-id="tor-bridges-select-built-in-button"
    
    306
    +      ></html:button>
    
    310 307
         </hbox>
    
    311 308
         <hbox align="center">
    
    312
    -      <label id="torPreferences-addBridge-labelEnterBridge" flex="1" />
    
    313
    -      <button
    
    314
    -        id="torPreferences-addBridge-buttonEnterBridge"
    
    309
    +      <description id="tor-bridges-user-provide-description" flex="1" />
    
    310
    +      <html:button
    
    311
    +        id="tor-bridges-open-user-provide-dialog-button"
    
    315 312
             class="accessory-button"
    
    316
    -      />
    
    313
    +      ></html:button>
    
    317 314
         </hbox>
    
    315
    +    <html:h3
    
    316
    +      id="tor-bridges-provider-heading"
    
    317
    +      data-l10n-id="tor-bridges-find-more-heading"
    
    318
    +    ></html:h3>
    
    319
    +    <description data-l10n-id="tor-bridges-find-more-description" />
    
    320
    +    <html:div id="tor-bridges-provider-area">
    
    321
    +      <html:ul id="tor-bridges-provider-list">
    
    322
    +        <html:li class="tor-bridges-provider-item">
    
    323
    +          <html:img
    
    324
    +            id="tor-bridges-provider-icon-telegram"
    
    325
    +            class="tor-bridges-provider-icon"
    
    326
    +            alt=""
    
    327
    +          />
    
    328
    +          <html:div
    
    329
    +            class="tor-bridges-provider-name"
    
    330
    +            data-l10n-id="tor-bridges-provider-telegram-name"
    
    331
    +          ></html:div>
    
    332
    +          <html:div
    
    333
    +            id="tor-bridges-provider-instruction-telegram"
    
    334
    +            class="tor-bridges-provider-instruction"
    
    335
    +          >
    
    336
    +            <html:a data-l10n-name="user"></html:a>
    
    337
    +          </html:div>
    
    338
    +        </html:li>
    
    339
    +        <html:li class="tor-bridges-provider-item">
    
    340
    +          <html:img
    
    341
    +            id="tor-bridges-provider-icon-web"
    
    342
    +            class="tor-bridges-provider-icon"
    
    343
    +            alt=""
    
    344
    +          />
    
    345
    +          <html:div
    
    346
    +            class="tor-bridges-provider-name"
    
    347
    +            data-l10n-id="tor-bridges-provider-web-name"
    
    348
    +          ></html:div>
    
    349
    +          <html:div
    
    350
    +            class="tor-bridges-provider-instruction"
    
    351
    +            data-l10n-id="tor-bridges-provider-web-instruction"
    
    352
    +            data-l10n-args='{ "url": "bridges.torproject.org" }'
    
    353
    +          >
    
    354
    +            <html:a
    
    355
    +              href="https://bridges.torproject.org"
    
    356
    +              data-l10n-name="url"
    
    357
    +            ></html:a>
    
    358
    +          </html:div>
    
    359
    +        </html:li>
    
    360
    +        <html:li class="tor-bridges-provider-item">
    
    361
    +          <html:img
    
    362
    +            id="tor-bridges-provider-icon-email"
    
    363
    +            class="tor-bridges-provider-icon"
    
    364
    +            alt=""
    
    365
    +          />
    
    366
    +          <html:div
    
    367
    +            class="tor-bridges-provider-name"
    
    368
    +            data-l10n-id="tor-bridges-provider-email-name"
    
    369
    +          ></html:div>
    
    370
    +          <html:div
    
    371
    +            class="tor-bridges-provider-instruction"
    
    372
    +            data-l10n-id="tor-bridges-provider-email-instruction"
    
    373
    +            data-l10n-args='{ "address": "bridges@xxxxxxxxxxxxxx" }'
    
    374
    +          ></html:div>
    
    375
    +        </html:li>
    
    376
    +      </html:ul>
    
    377
    +      <html:div id="tor-bridges-request-box">
    
    378
    +        <html:img
    
    379
    +          alt=""
    
    380
    +          src="chrome://browser/content/torpreferences/bridge-bot.svg"
    
    381
    +        ></html:img>
    
    382
    +        <html:div
    
    383
    +          id="tor-bridges-request-description"
    
    384
    +          data-l10n-id="tor-bridges-request-from-browser"
    
    385
    +        ></html:div>
    
    386
    +        <html:button
    
    387
    +          id="tor-bridges-open-request-dialog-button"
    
    388
    +          data-l10n-id="tor-bridges-request-button"
    
    389
    +        ></html:button>
    
    390
    +      </html:div>
    
    391
    +    </html:div>
    
    318 392
       </groupbox>
    
    319 393
     
    
    320 394
       <!-- Advanced -->
    

  • browser/components/torpreferences/content/provideBridgeDialog.js
    ... ... @@ -15,11 +15,24 @@ const { TorConnect, TorConnectTopics } = ChromeUtils.importESModule(
    15 15
     const gProvideBridgeDialog = {
    
    16 16
       init() {
    
    17 17
         this._result = window.arguments[0];
    
    18
    +    const mode = window.arguments[1].mode;
    
    19
    +
    
    20
    +    let titleId;
    
    21
    +    switch (mode) {
    
    22
    +      case "edit":
    
    23
    +        titleId = "user-provide-bridge-dialog-edit-title";
    
    24
    +        break;
    
    25
    +      case "add":
    
    26
    +        titleId = "user-provide-bridge-dialog-add-title";
    
    27
    +        break;
    
    28
    +      case "replace":
    
    29
    +      default:
    
    30
    +        titleId = "user-provide-bridge-dialog-replace-title";
    
    31
    +        break;
    
    32
    +    }
    
    33
    +
    
    34
    +    document.l10n.setAttributes(document.documentElement, titleId);
    
    18 35
     
    
    19
    -    document.documentElement.setAttribute(
    
    20
    -      "title",
    
    21
    -      TorStrings.settings.provideBridgeTitleAdd
    
    22
    -    );
    
    23 36
         const learnMore = document.createXULElement("label");
    
    24 37
         learnMore.className = "learnMore text-link";
    
    25 38
         learnMore.setAttribute("is", "text-link");
    

  • browser/components/torpreferences/content/provideBridgeDialog.xhtml
    ... ... @@ -9,6 +9,10 @@
    9 9
       xmlns:html="http://www.w3.org/1999/xhtml"
    
    10 10
     >
    
    11 11
       <dialog id="torPreferences-provideBridge-dialog" buttons="accept,cancel">
    
    12
    +    <linkset>
    
    13
    +      <html:link rel="localization" href="">"browser/tor-browser.ftl" />
    
    14
    +    </linkset>
    
    15
    +
    
    12 16
         <script src="">"chrome://browser/content/torpreferences/provideBridgeDialog.js" />
    
    13 17
     
    
    14 18
         <description>
    

  • browser/components/torpreferences/content/telegram-logo.svg
    1
    +<svg width="16" height="16" viewBox="0 0 16 16" fill="context-fill" xmlns="http://www.w3.org/2000/svg">
    
    2
    +  <path fill-rule="evenodd" clip-rule="evenodd" d="M13.5527 3.74072C13.6057 3.44502 13.3069 3.21007 13.0321 3.33143L2.46222 7.99865L5.04818 8.60316L10.1001 5.29184C10.8373 4.80861 11.6593 5.7727 11.0656 6.42426L7.88895 9.91029L11.9093 12.8968L13.5527 3.74072ZM12.5272 2.18794C13.7181 1.66208 15.013 2.68016 14.783 3.96155L13.104 13.3162C12.9564 14.1382 11.9962 14.5186 11.3258 14.0205L7.03263 10.8313C6.49819 10.4343 6.42353 9.66259 6.87195 9.17049L7.47872 8.50462L5.68862 9.67797C5.4311 9.84676 5.11564 9.90263 4.81582 9.83254L1.81371 9.13075C0.762034 8.8849 0.627375 7.4424 1.61537 7.00614L12.5272 2.18794Z"/>
    
    3
    +</svg>

  • browser/components/torpreferences/content/torPreferences.css
    ... ... @@ -447,6 +447,91 @@
    447 447
       fill: currentColor;
    
    448 448
     }
    
    449 449
     
    
    450
    +#tor-bridges-provider-heading {
    
    451
    +  font-size: 1.14em;
    
    452
    +  margin-block: 48px 8px;
    
    453
    +}
    
    454
    +
    
    455
    +#tor-bridges-provider-area {
    
    456
    +  display: grid;
    
    457
    +  grid-template-columns: 1fr 1fr;
    
    458
    +  gap: 16px;
    
    459
    +  align-items: start;
    
    460
    +  line-height: 1.8;
    
    461
    +  margin-block-start: 24px;
    
    462
    +}
    
    463
    +
    
    464
    +#tor-bridges-provider-list {
    
    465
    +  display: grid;
    
    466
    +  grid-template-columns: max-content max-content;
    
    467
    +  /* 16px gap between items. */
    
    468
    +  gap: 16px 12px;
    
    469
    +  margin-block: 16px;
    
    470
    +}
    
    471
    +
    
    472
    +.tor-bridges-provider-item {
    
    473
    +  grid-column: 1 / -1;
    
    474
    +  display: grid;
    
    475
    +  grid-template-columns: subgrid;
    
    476
    +  align-items: center;
    
    477
    +  justify-items: start;
    
    478
    +  /* No gap between the name and instruction. */
    
    479
    +  gap: 0 12px;
    
    480
    +}
    
    481
    +
    
    482
    +.tor-bridges-provider-icon {
    
    483
    +  width: 16px;
    
    484
    +  height: 16px;
    
    485
    +  -moz-context-properties: fill;
    
    486
    +  fill: var(--in-content-icon-color);
    
    487
    +}
    
    488
    +
    
    489
    +#tor-bridges-provider-icon-telegram {
    
    490
    +  content: url("chrome://browser/content/torpreferences/telegram-logo.svg");
    
    491
    +}
    
    492
    +
    
    493
    +#tor-bridges-provider-icon-web {
    
    494
    +  content: url("chrome://browser/content/torpreferences/network.svg");
    
    495
    +}
    
    496
    +
    
    497
    +#tor-bridges-provider-icon-email {
    
    498
    +  content: url("chrome://browser/skin/mail.svg");
    
    499
    +}
    
    500
    +
    
    501
    +.tor-bridges-provider-name {
    
    502
    +  font-weight: 600;
    
    503
    +  font-size: 0.85em;
    
    504
    +}
    
    505
    +
    
    506
    +.tor-bridges-provider-instruction {
    
    507
    +  grid-column: 2 / 3;
    
    508
    +}
    
    509
    +
    
    510
    +#tor-bridges-request-box {
    
    511
    +  /* Take up the full height in the container. */
    
    512
    +  align-self: stretch;
    
    513
    +  display: flex;
    
    514
    +  flex-direction: column;
    
    515
    +  align-items: center;
    
    516
    +  text-align: center;
    
    517
    +  padding: 16px;
    
    518
    +  background: var(--in-content-box-info-background);
    
    519
    +  border-radius: 4px;
    
    520
    +}
    
    521
    +
    
    522
    +#tor-bridges-request-box > * {
    
    523
    +  flex: 0 0 auto;
    
    524
    +}
    
    525
    +
    
    526
    +#tor-bridges-request-description {
    
    527
    +  margin-block: 12px 16px;
    
    528
    +}
    
    529
    +
    
    530
    +#tor-bridges-open-request-dialog-button {
    
    531
    +  margin: 0;
    
    532
    +  line-height: 1;
    
    533
    +}
    
    534
    +
    
    450 535
     #torPreferences-bridges-location {
    
    451 536
       width: 280px;
    
    452 537
     }
    

  • browser/components/torpreferences/jar.mn
    1 1
     browser.jar:
    
    2 2
         content/browser/torpreferences/bridge.svg                        (content/bridge.svg)
    
    3 3
         content/browser/torpreferences/bridge-qr.svg                     (content/bridge-qr.svg)
    
    4
    +    content/browser/torpreferences/telegram-logo.svg                 (content/telegram-logo.svg)
    
    5
    +    content/browser/torpreferences/bridge-bot.svg                    (content/bridge-bot.svg)
    
    4 6
         content/browser/torpreferences/bridgeQrDialog.xhtml              (content/bridgeQrDialog.xhtml)
    
    5 7
         content/browser/torpreferences/bridgeQrDialog.js                 (content/bridgeQrDialog.js)
    
    6 8
         content/browser/torpreferences/builtinBridgeDialog.xhtml         (content/builtinBridgeDialog.xhtml)
    

  • browser/locales/en-US/browser/tor-browser.ftl
    ... ... @@ -121,3 +121,58 @@ tor-bridges-share-description = Share your bridges with trusted contacts.
    121 121
     tor-bridges-copy-addresses-button = Copy addresses
    
    122 122
     tor-bridges-qr-addresses-button =
    
    123 123
         .title = Show QR code
    
    124
    +
    
    125
    +# Shown as a heading when the user has no current bridges.
    
    126
    +tor-bridges-add-bridges-heading = Add bridges
    
    127
    +# Shown as a heading when the user has existing bridges that can be replaced.
    
    128
    +tor-bridges-replace-bridges-heading = Replace your bridges
    
    129
    +
    
    130
    +tor-bridges-select-built-in-description = Choose from one of { -brand-short-name }’s built-in bridges
    
    131
    +tor-bridges-select-built-in-button = Select a built-in bridge…
    
    132
    +
    
    133
    +tor-bridges-add-addresses-description = Enter bridge addresses you already know
    
    134
    +# Shown when the user has no current bridges.
    
    135
    +# Opens a dialog where the user can provide a new bridge address or share code.
    
    136
    +tor-bridges-add-new-button = Add new bridges…
    
    137
    +# Shown when the user has existing bridges.
    
    138
    +# Opens a dialog where the user can provide a new bridge address or share code to replace their current bridges.
    
    139
    +tor-bridges-replace-button = Replace bridges…
    
    140
    +
    
    141
    +tor-bridges-find-more-heading = Find more bridges
    
    142
    +# "Tor Project" is the organisation name.
    
    143
    +tor-bridges-find-more-description = Since many bridge addresses aren’t public, you may need to request some from the Tor Project.
    
    144
    +
    
    145
    +# "Telegram" is the common brand name of the Telegram Messenger application
    
    146
    +tor-bridges-provider-telegram-name = Telegram
    
    147
    +# Here "Message" is a verb, short for "Send a message to". This is an instruction to send a message to the given Telegram Messenger user to receive a new bridge.
    
    148
    +# $telegramUserName (String) - The Telegram Messenger user name that should receive messages. Should be wrapped in '<a data-l10n-name="user">' and '</a>'.
    
    149
    +# E.g. in English, "Message GetBridgesBot".
    
    150
    +tor-bridges-provider-telegram-instruction = Message <a data-l10n-name="user">{ $telegramUserName }</a>
    
    151
    +
    
    152
    +# "Web" is the proper noun for the "World Wide Web".
    
    153
    +tor-bridges-provider-web-name = Web
    
    154
    +# Instructions to visit the given website.
    
    155
    +# $url (String) - The URL for Tor Project bridges. Should be wrapped in '<a data-l10n-name"url">' and '</a>'.
    
    156
    +tor-bridges-provider-web-instruction = Visit <a data-l10n-name="url">{ $url }</a>
    
    157
    +
    
    158
    +# "Gmail" is the Google brand name. "Riseup" refers to the Riseup organisation at riseup.net.
    
    159
    +tor-bridges-provider-email-name = Gmail or Riseup
    
    160
    +# Here "Email" is a verb, short for "Send an email to". This is an instruction to send an email to the given address to receive a new bridge.
    
    161
    +# $address (String) - The email address that should receive the email.
    
    162
    +# E.g. in English, "Email bridges@xxxxxxxxxxxxxx".
    
    163
    +tor-bridges-provider-email-instruction = Email { $address }
    
    164
    +
    
    165
    +tor-bridges-request-from-browser = You can also get bridges from the bridge bot without leaving { -brand-short-name }.
    
    166
    +tor-bridges-request-button = Request bridges…
    
    167
    +
    
    168
    +## User provided bridge dialog.
    
    169
    +
    
    170
    +# Used when the user is editing their existing bridge addresses.
    
    171
    +user-provide-bridge-dialog-edit-title =
    
    172
    +    .title = Edit your bridges
    
    173
    +# Used when the user has no existing bridges.
    
    174
    +user-provide-bridge-dialog-add-title =
    
    175
    +    .title = Add new bridges
    
    176
    +# Used when the user is replacing their existing bridges with new ones.
    
    177
    +user-provide-bridge-dialog-replace-title =
    
    178
    +    .title = Replace your bridges

  • toolkit/modules/TorStrings.sys.mjs
    ... ... @@ -105,14 +105,6 @@ const Loader = {
    105 105
           bridgeRemoveAllDialogTitle: "Remove all bridges?",
    
    106 106
           bridgeRemoveAllDialogDescription:
    
    107 107
             "If these bridges were received from torproject.org or added manually, this action cannot be undone",
    
    108
    -      bridgeAdd: "Add a New Bridge",
    
    109
    -      bridgeSelectBrowserBuiltin:
    
    110
    -        "Choose from one of Tor Browser’s built-in bridges",
    
    111
    -      bridgeSelectBuiltin: "Select a Built-In Bridge…",
    
    112
    -      bridgeRequestFromTorProject: "Request a bridge from torproject.org",
    
    113
    -      bridgeRequest: "Request a Bridge…",
    
    114
    -      bridgeEnterKnown: "Enter a bridge address you already know",
    
    115
    -      bridgeAddManually: "Add a Bridge Manually…",
    
    116 108
           // Advanced settings
    
    117 109
           advancedHeading: "Advanced",
    
    118 110
           advancedLabel: "Configure how Tor Browser connects to the internet",
    
    ... ... @@ -148,7 +140,6 @@ const Loader = {
    148 140
           captchaTextboxPlaceholder: "Enter the characters from the image",
    
    149 141
           incorrectCaptcha: "The solution is not correct. Please try again.",
    
    150 142
           // Provide bridge dialog
    
    151
    -      provideBridgeTitleAdd: "Add a Bridge Manually",
    
    152 143
           provideBridgeDescription:
    
    153 144
             "Add a bridge provided by a trusted organization or someone you know. If you don’t have a bridge, you can request one from the Tor Project. %S",
    
    154 145
           provideBridgePlaceholder: "type address:port (one per line)",
    

  • toolkit/torbutton/chrome/locale/en-US/settings.properties
    ... ... @@ -39,13 +39,6 @@ settings.bridgeDisableBuiltIn=Disable built-in bridges
    39 39
     settings.copied=Copied!
    
    40 40
     settings.bridgeRemoveAllDialogTitle=Remove all bridges?
    
    41 41
     settings.bridgeRemoveAllDialogDescription=If these bridges were received from torproject.org or added manually, this action cannot be undone
    
    42
    -settings.bridgeAdd=Add a New Bridge
    
    43
    -settings.bridgeSelectBrowserBuiltin=Choose from one of Tor Browser’s built-in bridges
    
    44
    -settings.bridgeSelectBuiltin=Select a Built-In Bridge…
    
    45
    -settings.bridgeRequestFromTorProject=Request a bridge from torproject.org
    
    46
    -settings.bridgeRequest=Request a Bridge…
    
    47
    -settings.bridgeEnterKnown=Enter a bridge address you already know
    
    48
    -settings.bridgeAddManually=Add a Bridge Manually…
    
    49 42
     
    
    50 43
     # Advanced settings
    
    51 44
     settings.advancedHeading=Advanced
    
    ... ... @@ -82,8 +75,6 @@ settings.solveTheCaptcha=Solve the CAPTCHA to request a bridge.
    82 75
     settings.captchaTextboxPlaceholder=Enter the characters from the image
    
    83 76
     settings.incorrectCaptcha=The solution is not correct. Please try again.
    
    84 77
     
    
    85
    -# Provide bridge dialog
    
    86
    -settings.provideBridgeTitleAdd=Add a Bridge Manually
    
    87 78
     # Translation note: %S is a Learn more link.
    
    88 79
     settings.provideBridgeDescription=Add a bridge provided by a trusted organization or someone you know. If you don’t have a bridge, you can request one from the Tor Project. %S
    
    89 80
     settings.provideBridgePlaceholder=type address:port (one per line)
    
    ... ... @@ -125,3 +116,13 @@ settings.bridgeShowAll=Show All Bridges
    125 116
     settings.bridgeShowFewer=Show Fewer Bridges
    
    126 117
     settings.allBridgesEnabled=Use current bridges
    
    127 118
     settings.bridgeRemoveAll=Remove All Bridges
    
    119
    +settings.bridgeAdd=Add a New Bridge
    
    120
    +settings.bridgeSelectBrowserBuiltin=Choose from one of Tor Browser’s built-in bridges
    
    121
    +settings.bridgeSelectBuiltin=Select a Built-In Bridge…
    
    122
    +settings.bridgeRequestFromTorProject=Request a bridge from torproject.org
    
    123
    +settings.bridgeRequest=Request a Bridge…
    
    124
    +settings.bridgeEnterKnown=Enter a bridge address you already know
    
    125
    +settings.bridgeAddManually=Add a Bridge Manually…
    
    126
    +
    
    127
    +# Provide bridge dialog
    
    128
    +settings.provideBridgeTitleAdd=Add a Bridge Manually

  • _______________________________________________
    tor-commits mailing list
    tor-commits@xxxxxxxxxxxxxxxxxxxx
    https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits