GitLab is used only for code review, issue tracking and project management. Canonical locations for source code are still https://gitweb.torproject.org/ https://git.torproject.org/ and git-rw.torproject.org.

Commit f3804aad authored by Kathleen Brade's avatar Kathleen Brade
Browse files

Bug #10418: Provide "Use Default Bridges" option.

To enable this feature, add one or more preference values like:
  extensions.torlauncher.default_bridge.TYPE.1
  extensions.torlauncher.default_bridge.TYPE.2
Other new preferences:
  extensions.torlauncher.default_bridge_type (stores chosen type)
  extensions.torlauncher.default_bridge_recommended_type
The text "(recommended)" is displayed next to the recommended type, and
it is selected by default.  The default bridges are reconfigured each
time the browser starts up; if no default bridges of the configured type
are available, an error message is displayed and the user is placed on
the bridge settings panel within the network configuration wizard.
parent a232915e
<?xml version="1.0"?>
<!--
- Copyright (c) 2013, The Tor Project, Inc.
- Copyright (c) 2014, The Tor Project, Inc.
- See LICENSE for licensing information.
- vim: set sw=2 sts=2 ts=8 et syntax=xml:
-->
......@@ -74,24 +74,32 @@
</groupbox>
<groupbox id="bridgeSpecificSettings">
<hbox>
<vbox flex="1">
<hbox pack="end">
<radiogroup id="bridgeTypeRadioGroup" flex="1" style="margin: 0px">
<hbox align="center">
<button dlgtype="help" oncommand="onOpenHelp()" />
<label value="&torsettings.useBridges.label;" control="bridgeList"/>
<radio id="bridgeRadioDefault"
label="&torsettings.useBridges.default;" selected="true" />
<menulist id="defaultBridgeType" oncommand="onBridgeTypeChange()">
<menupopup id="defaultBridgeType_menuPopup" />
</menulist>
<spring/>
</hbox>
<textbox id="bridgeList" multiline="true" rows="3"
placeholder="&torsettings.useBridges.placeholder;" />
</vbox>
<!--
<vbox>
<button id="copyBridgeList" label="Copy TODO" style="width: 20px"
oncommand="copyBridgeList();"/>
<button id="pasteBridgeList" label="Paste TODO" style="width: 20px"
oncommand="pasteBridgeList();"/>
<spacer style="height: 0.5em" />
<radio id="bridgeRadioCustom" label="&torsettings.useBridges.custom;"
oncommand="onCustomBridges()" />
</radiogroup>
<vbox pack="start">
<button dlgtype="help" oncommand="onOpenHelp()" />
</vbox>
-->
</hbox>
<vbox id="bridgeCustomEntry">
<label style="margin-top:0px;"
value="&torsettings.useBridges.label;" control="bridgeList"/>
<textbox id="bridgeList" multiline="true" rows="3"
oninput="onCustomBridgesTextInput();"
placeholder="&torsettings.useBridges.placeholder;" />
</vbox>
</groupbox>
<vbox id="bridgeHelpContent">
......@@ -115,4 +123,3 @@
</vbox>
</overlay>
......@@ -27,7 +27,7 @@
src="chrome://torlauncher/content/network-settings.js"/>
<wizardpage label=" " pageid="first" next="proxy" onextra2="onCopyLog();"
onpageshow="setTimeout(function() { showWizardNavButtons(false); }, 0);">
onpageshow="setTimeout(function() { showWizardNavButtons(); }, 0);">
<hbox class="tbb-header">
<vbox class="tbb-logo-box" align="start">
<image class="tbb-logo" />
......@@ -52,7 +52,7 @@
</wizardpage>
<wizardpage label=" " pageid="proxy" next="firewall" onextra2="onCopyLog();"
onpageshow="showWizardNavButtons(true);"
onpageshow="showWizardNavButtons();"
onpageadvanced="return onWizardProxyNext(this);">
<vbox class="tbb-logo-box" align="start">
<image class="tbb-logo" />
......@@ -113,14 +113,34 @@
</vbox>
</wizardpage>
<wizardpage label=" " pageid="bridges" onextra2="onCopyLog();"
onpageshow="showOrHideButton('finish', true, true)">
<wizardpage pageid="bridges" onextra2="onCopyLog();"
onpageshow="onWizardUseBridgesRadioChange(this)">
<vbox class="tbb-logo-box" align="start">
<image class="tbb-logo" />
</vbox>
<separator />
<hbox>
<vbox flex="1">
<label class="question">&torSettings.bridgeQuestion;</label>
<radiogroup id="useBridgesRadioGroup"
oncommand="onWizardUseBridgesRadioChange()">
<radio id="bridgesRadioYes" label="&torSettings.yes;" />
<radio id="bridgesRadioNo" label="&torSettings.no;" selected="true" />
</radiogroup>
<description class="questionHelp">&torSettings.bridgeHelp;
</description>
</vbox>
</hbox>
</wizardpage>
<wizardpage label=" " pageid="bridgeSettings" onextra2="onCopyLog();"
onpageshow="onWizardBridgeSettingsShow()">
<vbox class="tbb-logo-box" align="start">
<image class="tbb-logo" />
</vbox>
<separator />
<vbox>
<label class="question">&torSettings.bridgeQuestion;</label>
<label class="question">&torSettings.bridgeSettingsPrompt;</label>
<groupbox id="bridgeSpecificSettings" />
</vbox>
</wizardpage>
......
// Copyright (c) 2013, The Tor Project, Inc.
// Copyright (c) 2014, The Tor Project, Inc.
// See LICENSE for licensing information.
//
// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
......@@ -15,6 +15,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "TorLauncherUtil",
XPCOMUtils.defineLazyModuleGetter(this, "TorLauncherLogger",
"resource://torlauncher/modules/tl-logger.jsm");
const kPrefDefaultBridgeRecommendedType =
"extensions.torlauncher.default_bridge_recommended_type";
const kPrefDefaultBridgeType = "extensions.torlauncher.default_bridge_type";
const kSupportAddr = "help@rt.torproject.org";
......@@ -26,6 +29,7 @@ const kTorLogHasWarnOrErrTopic = "TorLogHasWarnOrErr";
const kWizardProxyRadioGroup = "proxyRadioGroup";
const kWizardFirewallRadioGroup = "firewallRadioGroup";
const kWizardUseBridgesRadioGroup = "useBridgesRadioGroup";
const kUseProxyCheckbox = "useProxy";
const kProxyTypeMenulist = "proxyType";
......@@ -36,6 +40,8 @@ const kProxyPassword = "proxyPassword";
const kUseFirewallPortsCheckbox = "useFirewallPorts";
const kFirewallAllowedPorts = "firewallAllowedPorts";
const kUseBridgesCheckbox = "useBridges";
const kDefaultBridgeTypeMenuList = "defaultBridgeType";
const kCustomBridgesRadio = "bridgeRadioCustom";
const kBridgeList = "bridgeList";
const kTorConfKeyDisableNetwork = "DisableNetwork";
......@@ -72,6 +78,11 @@ function initDialog()
var cancelBtn = document.documentElement.getButton("cancel");
gIsInitialBootstrap = window.arguments[0];
var startAtPanel;
if (window.arguments.length > 1)
startAtPanel = window.arguments[1];
if (gIsInitialBootstrap)
{
if (cancelBtn)
......@@ -142,6 +153,8 @@ function initDialog()
}
}
initDefaultBridgeTypeMenu();
gObsService.addObserver(gObserver, kTorBootstrapErrorTopic, false);
gObsService.addObserver(gObserver, kTorLogHasWarnOrErrTopic, false);
gObsService.addObserver(gObserver, kTorProcessExitedTopic, false);
......@@ -156,8 +169,12 @@ function initDialog()
}
else
{
showPanel("settings");
readTorSettings();
if (startAtPanel)
advanceToWizardPanel(startAtPanel);
else
showPanel();
}
TorLauncherLogger.log(2, "initDialog done");
......@@ -201,10 +218,55 @@ function onWizardFirewallNext(aWizPage)
}
function showWizardNavButtons(aShow)
function onWizardUseBridgesRadioChange(aWizPage)
{
var wizard = getWizard();
if (!aWizPage)
aWizPage = wizard.currentPage;
if (aWizPage)
{
var useBridges = getElemValue("bridgesRadioYes", false);
aWizPage.next = (useBridges) ? "bridgeSettings" : "";
wizard.setAttribute("lastpage", !useBridges);
wizard._wizardButtons.onPageChange();
}
}
function onWizardBridgeSettingsShow()
{
var wizard = getWizard();
wizard.setAttribute("lastpage", true);
wizard._wizardButtons.onPageChange();
var btn = document.documentElement.getButton("finish");
if (btn)
btn.focus();
}
function onCustomBridgesTextInput()
{
var customBridges = document.getElementById(kCustomBridgesRadio);
if (customBridges)
customBridges.control.selectedItem = customBridges;
}
function onCustomBridges()
{
var bridgeList = document.getElementById(kBridgeList);
if (bridgeList)
bridgeList.focus();
}
function showWizardNavButtons()
{
showOrHideButton("back", aShow, false);
showOrHideButton("next", aShow, false);
var curPage = getWizard().currentPage;
var isFirstPage = ("first" == curPage.pageid);
showOrHideButton("back", !isFirstPage, false);
showOrHideButton("next", !isFirstPage && curPage.next, false);
}
......@@ -222,7 +284,7 @@ var gObserver = {
{
gObsService.removeObserver(gObserver, kTorProcessReadyTopic);
var haveWizard = (getWizard() != null);
showPanel(haveWizard ? "first" : "settings");
showPanel();
if (haveWizard)
{
showOrHideButton("back", true, false);
......@@ -277,21 +339,47 @@ function readTorSettings()
}
// If aPanelID is undefined, the first panel is displayed.
function showPanel(aPanelID)
{
var wizard = getWizard();
if (!aPanelID)
aPanelID = (wizard) ? "first" : "settings";
var deckElem = document.getElementById("deck");
if (deckElem)
{
deckElem.selectedPanel = document.getElementById(aPanelID);
showOrHideButton("extra2", (aPanelID != "bridgeHelp"), false);
}
else
getWizard().goTo(aPanelID);
else if (wizard.currentPage.pageid != aPanelID)
wizard.goTo(aPanelID);
showOrHideButton("accept", (aPanelID == "settings"), true);
}
// This function assumes that you are starting on the first page.
function advanceToWizardPanel(aPanelID)
{
var wizard = getWizard();
if (!wizard)
return;
onWizardConfigure(); // Equivalent to pressing "Configure"
const kMaxTries = 10;
for (var count = 0;
((count < kMaxTries) &&
(wizard.currentPage.pageid != aPanelID) &&
wizard.canAdvance);
++count)
{
wizard.advance();
}
}
function showStartingTorPanel(aTorExited)
{
if (aTorExited)
......@@ -672,17 +760,50 @@ function initFirewallSettings()
// Returns true if successful.
function initBridgeSettings()
{
var reply = gProtocolSvc.TorGetConfBool(kTorConfKeyUseBridges, false);
if (!gProtocolSvc.TorCommandSucceeded(reply))
return false;
var typeList = TorLauncherUtil.defaultBridgeTypes;
var canUseDefaultBridges = (typeList && (typeList.length > 0));
var defaultType = TorLauncherUtil.getCharPref(kPrefDefaultBridgeType);
var useDefault = canUseDefaultBridges && !!defaultType;
// If not configured to use a default set of bridges, get UseBridges setting
// from tor.
var useBridges = useDefault;
if (!useDefault)
{
var reply = gProtocolSvc.TorGetConfBool(kTorConfKeyUseBridges, false);
if (!gProtocolSvc.TorCommandSucceeded(reply))
return false;
setElemValue(kUseBridgesCheckbox, reply.retVal);
useBridges = reply.retVal;
var bridgeReply = gProtocolSvc.TorGetConf(kTorConfKeyBridgeList);
if (!gProtocolSvc.TorCommandSucceeded(bridgeReply))
return false;
// Get bridge list from tor.
var bridgeReply = gProtocolSvc.TorGetConf(kTorConfKeyBridgeList);
if (!gProtocolSvc.TorCommandSucceeded(bridgeReply))
return false;
setBridgeListElemValue(bridgeReply.lineArray);
if (!setBridgeListElemValue(bridgeReply.lineArray))
{
if (canUseDefaultBridges)
useDefault = true; // We have no custom values... back to default.
else
useBridges = false; // No custom or default bridges are available.
}
}
setElemValue(kUseBridgesCheckbox, useBridges);
setYesNoRadioValue(kWizardUseBridgesRadioGroup, useBridges);
if (!canUseDefaultBridges)
{
var radioGroup = document.getElementById("bridgeTypeRadioGroup");
if (radioGroup)
radioGroup.setAttribute("hidden", true);
}
var radioID = (useDefault) ? "bridgeRadioDefault" : "bridgeRadioCustom";
var radio = document.getElementById(radioID);
if (radio)
radio.control.selectedItem = radio;
return true;
}
......@@ -713,7 +834,7 @@ function applySettings()
function useSettings()
{
var settings = {};
settings[kTorConfKeyDisableNetwork] = "0";
settings[kTorConfKeyDisableNetwork] = false;
this.setConfAndReportErrors(settings, null);
gProtocolSvc.TorSendCommand("SAVECONF");
......@@ -868,6 +989,42 @@ function getAndValidateFirewallSettings()
}
function initDefaultBridgeTypeMenu()
{
var menu = document.getElementById(kDefaultBridgeTypeMenuList);
if (!menu)
return;
menu.removeAllItems();
var typeArray = TorLauncherUtil.defaultBridgeTypes;
if (!typeArray || typeArray.length == 0)
return;
var recommendedType = TorLauncherUtil.getCharPref(
kPrefDefaultBridgeRecommendedType, null);
var selectedType = TorLauncherUtil.getCharPref(kPrefDefaultBridgeType, null);
if (!selectedType)
selectedType = recommendedType;
for (var i=0; i < typeArray.length; i++)
{
var bridgeType = typeArray[i];
var menuItemLabel = bridgeType;
if (bridgeType == recommendedType)
{
const key = "recommended_bridge";
menuItemLabel += " " + TorLauncherUtil.getLocalizedString(key);
}
var mi = menu.appendItem(menuItemLabel, bridgeType);
if (bridgeType == selectedType)
menu.selectedItem = mi;
}
}
// Returns true if settings were successfully applied.
function applyBridgeSettings()
{
......@@ -875,7 +1032,7 @@ function applyBridgeSettings()
if (!settings)
return false;
return this.setConfAndReportErrors(settings, "bridges");
return this.setConfAndReportErrors(settings, "bridgeSettings");
}
......@@ -886,18 +1043,43 @@ function getAndValidateBridgeSettings()
settings[kTorConfKeyUseBridges] = null;
settings[kTorConfKeyBridgeList] = null;
var bridgeStr = getElemValue(kBridgeList, null);
var useBridges = (getWizard()) ? (bridgeStr && (0 != bridgeStr.length))
: getElemValue(kUseBridgesCheckbox, false);
var useBridges = (getWizard()) ? getElemValue("bridgesRadioYes", false)
: getElemValue(kUseBridgesCheckbox, false);
var bridgeList = parseAndValidateBridges(bridgeStr);
if (useBridges && !bridgeList)
var defaultBridgeType;
var bridgeList;
if (useBridges)
{
reportValidationError("error_bridges_missing");
return null;
var useCustom = getElemValue(kCustomBridgesRadio, false);
if (useCustom)
{
var bridgeStr = getElemValue(kBridgeList, null);
bridgeList = parseAndValidateBridges(bridgeStr);
if (!bridgeList)
{
reportValidationError("error_bridges_missing");
return null;
}
setBridgeListElemValue(bridgeList);
}
else
{
defaultBridgeType = getElemValue(kDefaultBridgeTypeMenuList, null);
if (!defaultBridgeType)
{
reportValidationError("error_default_bridges_type_missing");
return null;
}
}
}
setBridgeListElemValue(bridgeList);
// Since it returns a filterd list of bridges, TorLauncherUtil.defaultBridges
// must be called after setting the kPrefDefaultBridgeType pref.
TorLauncherUtil.setCharPref(kPrefDefaultBridgeType, defaultBridgeType);
if (defaultBridgeType)
bridgeList = TorLauncherUtil.defaultBridges;
if (useBridges && bridgeList)
{
settings[kTorConfKeyUseBridges] = true;
......@@ -935,21 +1117,10 @@ function parseAndValidateBridges(aStr)
// Returns true if successful.
function setConfAndReportErrors(aSettingsObj, aShowOnErrorPanelID)
{
var reply = gProtocolSvc.TorSetConf(aSettingsObj);
var didSucceed = gProtocolSvc.TorCommandSucceeded(reply);
var errObj = {};
var didSucceed = gProtocolSvc.TorSetConfWithReply(aSettingsObj, errObj);
if (!didSucceed)
{
var details = "";
if (reply && reply.lineArray)
{
for (var i = 0; i < reply.lineArray.length; ++i)
{
if (i > 0)
details += '\n';
details += reply.lineArray[i];
}
}
if (aShowOnErrorPanelID)
{
var wizardElem = getWizard();
......@@ -967,7 +1138,7 @@ function setConfAndReportErrors(aSettingsObj, aShowOnErrorPanelID)
} catch (e) {}
}
showSaveSettingsAlert(details);
showSaveSettingsAlert(errObj.details);
}
return didSucceed;
......@@ -976,13 +1147,7 @@ function setConfAndReportErrors(aSettingsObj, aShowOnErrorPanelID)
function showSaveSettingsAlert(aDetails)
{
if (!aDetails)
aDetails = TorLauncherUtil.getLocalizedString("ensure_tor_is_running");
var s = TorLauncherUtil.getFormattedLocalizedString(
"failed_to_save_settings", [aDetails], 1);
TorLauncherUtil.showAlert(window, s);
TorLauncherUtil.showSaveSettingsAlert(window, aDetails);
showOrHideButton("extra2", true, false);
gWizIsCopyLogBtnShowing = true;
}
......@@ -1020,6 +1185,7 @@ function setElemValue(aID, aValue)
}
// Returns true if one or more values were set.
function setBridgeListElemValue(aBridgeArray)
{
// To be consistent with bridges.torproject.org, pre-pend "bridge" to
......@@ -1040,6 +1206,7 @@ function setBridgeListElemValue(aBridgeArray)
}
setElemValue(kBridgeList, bridgeList);
return (bridgeList.length > 0);
}
......
......@@ -22,7 +22,9 @@
<!ENTITY torSettings.firewallQuestion "Does this computer's Internet connection go through a firewall that only allows connections to certain ports?">
<!ENTITY torSettings.firewallHelp "If you are not sure how to answer this question, choose No. If you encounter problems connecting to the Tor network, change this setting.">
<!ENTITY torSettings.enterFirewall "Enter a comma-separated list of ports that are allowed by the firewall.">
<!ENTITY torSettings.bridgeQuestion "If this computer's Internet connection is censored, you will need to obtain and use bridge relays.&#160; If not, just click Connect.">
<!ENTITY torSettings.bridgeQuestion "Does your Internet Service Provider (ISP) block or otherwise censor connections to the Tor Network?">
<!ENTITY torSettings.bridgeHelp "If you are not sure how to answer this question, choose No.&#160; If you choose Yes, you will be asked to configure Tor Bridges, which are unlisted relays that make it more difficult to block connections to the Tor Network.">
<!ENTITY torSettings.bridgeSettingsPrompt "You may use the default set of bridges or you may obtain and enter a custom set of bridges.">
<!-- Other: -->
......@@ -44,13 +46,15 @@
<!ENTITY torsettings.firewall.checkbox "This computer goes through a firewall that only allows connections to certain ports">
<!ENTITY torsettings.firewall.allowedPorts "Allowed Ports:">
<!ENTITY torsettings.useBridges.checkbox "My Internet Service Provider (ISP) blocks connections to the Tor network">
<!ENTITY torsettings.useBridges.default "Use Default Bridges of Type">
<!ENTITY torsettings.useBridges.custom "Use Custom Bridges">
<!ENTITY torsettings.useBridges.label "Enter one or more bridge relays (one per line).">
<!ENTITY torsettings.useBridges.placeholder "address:port OR transport address:port">
<!ENTITY torsettings.useBridges.placeholder "type address:port">
<!ENTITY torsettings.copyLog "Copy Tor Log To Clipboard">
<!ENTITY torsettings.bridgeHelpTitle "Bridge Relay Help">
<!ENTITY torsettings.bridgeHelp1 "If you are unable to connect to the Tor network, it could be that your Internet Service Provider (ISP) or another agency is blocking Tor.&#160; Often, you can work around this problem by using Tor Bridges, which are unlisted relays that are more difficult to block.">
<!ENTITY torsettings.bridgeHelp1B "Here are three ways to obtain bridge addresses:">
<!ENTITY torsettings.bridgeHelp1B "You may use the preconfigured, default set of bridge addresses or you may obtain a custom set of addresses by using one of these three methods:">
<!ENTITY torsettings.bridgeHelp2Heading "Through the Web">
<!ENTITY torsettings.bridgeHelp2 "Use a web browser to visit https://bridges.torproject.org">
<!ENTITY torsettings.bridgeHelp3Heading "Through the Email Autoresponder">
......
......@@ -24,6 +24,10 @@ torlauncher.ensure_tor_is_running=Please ensure that Tor is running.
torlauncher.error_proxy_addr_missing=You must specify both an IP address or hostname and a port number to configure Tor to use a proxy to access the Internet.
torlauncher.error_proxy_type_missing=You must select the proxy type.
torlauncher.error_bridges_missing=You must specify one or more bridges.
torlauncher.error_default_bridges_type_missing=You must select a transport type for the default bridges.
torlauncher.error_bridge_bad_default_type=No default bridges that have the transport type %S are available. Please adjust your settings.
torlauncher.recommended_bridge=(recommended)
torlauncher.connect=Connect
torlauncher.quit=Quit
......
......@@ -7,7 +7,7 @@
dialog {
width: 45em;
height: 36em;
height: 39em;
font: -moz-dialog;
}
......@@ -29,7 +29,7 @@ wizard.os-windows {
.wizard-page-box {
padding: 0px;
margin: 20px;
margin: 14px 20px 18px 20px;
}
wizard .wizard-header { display: none; }
......@@ -92,6 +92,10 @@ button.firstAnswer {
height: 70px;
}
#bridgeCustomEntry {
margin-left: 30px;
}
#startingTor {
min-height: 300px;
}
......
......@@ -35,6 +35,8 @@ TorProcessService.prototype =
kTorLauncherExtPath: "tor-launcher@torproject.org", // This could vary.
kPrefPromptAtStartup: "extensions.torlauncher.prompt_at_startup",
kPrefDefaultBridgeType: "extensions.torlauncher.default_bridge_type",
kInitialControlConnDelayMS: 25,
kMaxControlConnRetryMS: 500,
kControlConnTimeoutMS: 30000, // Wait at most 30 seconds for tor to start.
......@@ -44,6 +46,10 @@ TorProcessService.prototype =
kStatusRunning: 2,
kStatusExited: 3, // Exited or failed to start.
kDefaultBridgesStatus_NotInUse: 0,
kDefaultBridgesStatus_InUse: 1,
kDefaultBridgesStatus_BadConfig: 2,