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 e921bb15 authored by Kathleen Brade's avatar Kathleen Brade
Browse files

Bug 23136: Moat integration (fetch bridges for the user)

Modify the setup wizard and Network Settings window to allow automated
retrieval of bridges using Moat, a BridgeDB service which works
over a meek transport and requires the user to solve a CAPTCHA to
obtain bridges.

The new tl-bridgedb.jsm JavaScript module handles all communication
with BridgeDB, and it functions by starting a copy of
meek-client-torbrowser and operating as a PT client parent process
(see https://gitweb.torproject.org/torspec.git/tree/pt-spec.txt).

This feature can be disabled (and the Moat-related Tor Launcher UI
hidden) by setting the pref extensions.torlauncher.moat_service to
an empty string.
parent e61d0522
<?xml version="1.0"?>
<!--
- Copyright (c) 2017, The Tor Project, Inc.
- Copyright (c) 2018, The Tor Project, Inc.
- See LICENSE for licensing information.
- vim: set sw=2 sts=2 ts=8 et syntax=xml:
-->
......@@ -93,11 +93,11 @@
oncommand="toggleElemUI(this);"/>
<groupbox id="bridgeSpecificSettings">
<hbox align="end" pack="end">
<radiogroup id="bridgeTypeRadioGroup" flex="1" style="margin: 0px"
oncommand="onBridgeTypeRadioChange()">
<hbox align="center">
<radiogroup id="bridgeTypeRadioGroup" flex="1" style="margin: 0px">
<hbox class="bridgeRadioContainer">
<radio id="bridgeRadioDefault"
label="&torsettings.useBridges.default;" selected="true"/>
label="&torsettings.useBridges.default;" selected="true"
oncommand="onBridgeTypeRadioChange()"/>
<button class="helpButton"
oncommand="onOpenHelp('bridgeHelpContent')"/>
<spacer style="width: 3em"/>
......@@ -108,8 +108,24 @@
<spring/>
</hbox>
<radio align="start" id="bridgeRadioCustom"
label="&torsettings.useBridges.custom;"/>
<vbox id="bridgeDBSettings">
<hbox class="bridgeRadioContainer">
<radio id="bridgeRadioBridgeDB"
label="&torsettings.useBridges.bridgeDB;"
oncommand="onBridgeTypeRadioChange()"/>
</hbox>
<vbox id="bridgeDBContainer" align="start">
<description id="bridgeDBResult"/>
<button id="bridgeDBRequestButton"
oncommand="onOpenBridgeDBRequestPrompt()"/>
</vbox>
</vbox>
<hbox class="bridgeRadioContainer">
<radio align="start" id="bridgeRadioCustom"
label="&torsettings.useBridges.custom;"
oncommand="onBridgeTypeRadioChange()"/>
</hbox>
</radiogroup>
</hbox>
<vbox id="bridgeCustomEntry">
......@@ -153,6 +169,36 @@
</hbox>
</vbox>
<vbox id="bridgeDBRequestOverlayContent" align="center">
<vbox>
<label id="bridgeDBPrompt"/>
<image id="bridgeDBCaptchaImage"/>
<hbox>
<spacer id="bridgeDBReloadSpacer"/>
<spacer flex="1"/>
<textbox id="bridgeDBCaptchaSolution" size="35"
placeholder="&torsettings.useBridges.captchaSolution.placeholder;"
oninput="onCaptchaSolutionChange()"/>
<spacer flex="1"/>
<deck id="bridgeDBReloadDeck">
<button id="bridgeDBReloadCaptchaButton"
tooltiptext="&torsettings.useBridges.reloadCaptcha.tooltip;"
oncommand="onReloadCaptcha()"/>
<image id="bridgeDBNetworkActivity"/>
</deck>
</hbox>
<label id="bridgeDBCaptchaError"/>
<separator/>
<hbox pack="center">
<button id="bridgeDBCancelButton"
oncommand="onCancelBridgeDBRequestPrompt()"/>
<button id="bridgeDBSubmitButton" disabled="true"
label="&torsettings.useBridges.captchaSubmit;"
oncommand="onCaptchaSolutionSubmit()"/>
</hbox>
</vbox>
</vbox>
<vbox id="errorOverlayContent">
<hbox pack="center">
<description errorElemId="message" flex="1"/>
......
<?xml version="1.0"?>
<!--
- Copyright (c) 2017, The Tor Project, Inc.
- Copyright (c) 2018, The Tor Project, Inc.
- See LICENSE for licensing information.
- vim: set sw=2 sts=2 ts=8 et syntax=xml:
-->
......@@ -33,7 +33,6 @@
<image class="tbb-logo"/>
</hbox>
<separator class="tall"/>
<vbox class="firstResponses" align="center">
<label>&torSettings.connectPrompt;</label>
<label>&torSettings.configurePrompt;</label>
......@@ -52,11 +51,13 @@
torShowNavButtons="true">
<stack flex="1">
<vbox>
<separator class="tall"/>
<vbox id="bridgeSettings"/>
<separator/>
<vbox id="proxySettings"/>
</vbox>
<vbox id="bridgeDBRequestOverlay" class="messagePanel" pack="center"
hidden="true">
<vbox id="bridgeDBRequestOverlayContent"/>
</vbox>
<vbox id="configErrorOverlay" class="messagePanel" pack="center"
hidden="true">
<vbox id="errorOverlayContent"/>
......
This diff is collapsed.
<?xml version="1.0"?>
<!--
- Copyright (c) 2017, The Tor Project, Inc.
- Copyright (c) 2018, The Tor Project, Inc.
- See LICENSE for licensing information.
- vim: set sw=2 sts=2 ts=8 et syntax=xml:
-->
......@@ -74,6 +74,11 @@
<panel id="copyLogFeedbackPanel"/>
</vbox>
<vbox id="bridgeDBRequestOverlay" class="messagePanel" pack="center"
hidden="true">
<vbox id="bridgeDBRequestOverlayContent"/>
</vbox>
<vbox id="errorOverlay" class="messagePanel" pack="center" hidden="true">
<vbox id="errorOverlayContent"/>
</vbox>
......
......@@ -41,6 +41,10 @@
<!ENTITY torsettings.useBridges.checkbox "Tor is censored in my country">
<!ENTITY torsettings.useBridges.default "Select a built-in bridge">
<!ENTITY torsettings.useBridges.default.placeholder "select a bridge">
<!ENTITY torsettings.useBridges.bridgeDB "Request a bridge from torproject.org">
<!ENTITY torsettings.useBridges.captchaSolution.placeholder "Enter the characters from the image">
<!ENTITY torsettings.useBridges.reloadCaptcha.tooltip "Get a new challenge">
<!ENTITY torsettings.useBridges.captchaSubmit "Submit">
<!ENTITY torsettings.useBridges.custom "Provide a bridge I know">
<!ENTITY torsettings.useBridges.label "Enter bridge information from a trusted source.">
<!ENTITY torsettings.useBridges.placeholder "type address:port (one per line)">
......
......@@ -26,11 +26,21 @@ torlauncher.error_proxy_addr_missing=You must specify both an IP address or host
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 provided bridges.
torlauncher.error_bridgedb_bridges_missing=Please request a bridge.
torlauncher.error_bridge_bad_default_type=No provided bridges that have the transport type %S are available. Please adjust your settings.
torlauncher.bridge_suffix.meek-amazon=(works in China)
torlauncher.bridge_suffix.meek-azure=(works in China)
torlauncher.request_a_bridge=Request a Bridge…
torlauncher.request_a_new_bridge=Request a New Bridge…
torlauncher.contacting_bridgedb=Contacting BridgeDB. Please wait.
torlauncher.captcha_prompt=Solve the CAPTCHA to request a bridge.
torlauncher.bad_captcha_solution=The solution is not correct. Please try again.
torlauncher.unable_to_get_bridge=Unable to obtain a bridge from BridgeDB.\n\n%S
torlauncher.no_meek=This browser is not configured for meek, which is needed to obtain bridges.
torlauncher.no_bridges_available=No bridges are available at this time. Sorry.
torlauncher.connect=Connect
torlauncher.restart_tor=Restart Tor
torlauncher.quit=Quit
......@@ -62,3 +72,7 @@ torlauncher.bootstrapWarning.timeout=connection timeout
torlauncher.bootstrapWarning.noroute=no route to host
torlauncher.bootstrapWarning.ioerror=read/write error
torlauncher.bootstrapWarning.pt_missing=missing pluggable transport
torlauncher.nsresult.NS_ERROR_NET_RESET=The connection to the server was lost.
torlauncher.nsresult.NS_ERROR_CONNECTION_REFUSED=Could not connect to the server.
torlauncher.nsresult.NS_ERROR_PROXY_CONNECTION_REFUSED=Could not connect to the proxy.
<!-- Based on http://goo.gl/7AJzbL By Sam Herbert -->
<svg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg" stroke="#000">
<g fill="none" fill-rule="evenodd">
<g transform="translate(1 1)" stroke-width="6">
<circle stroke-opacity=".4" cx="18" cy="18" r="16"/>
<path d="M34 18c0-9.94-8.06-18-18-16">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="1s"
repeatCount="indefinite"/>
</path>
</g>
</g>
</svg>
\ No newline at end of file
/*
* Copyright (c) 2017, The Tor Project, Inc.
* Copyright (c) 2018, The Tor Project, Inc.
* See LICENSE for licensing information.
*
* vim: set sw=2 sts=2 ts=8 et syntax=css:
......@@ -18,14 +18,14 @@ dialog.os-windows {
wizard {
width: 45em;
height: 36em;
height: 38em;
font: -moz-dialog;
padding-top: 0px;
}
wizard.os-windows {
width: 49em;
height: 42em;
height: 44em;
}
.wizard-page-box {
......@@ -67,8 +67,15 @@ wizard radiogroup {
margin: 9px 40px;
}
separator.tall {
height: 2.1em;
.firstResponses,
wizard #bridgeSettings,
wizard #proxySettings {
margin-top: 15px;
}
.bridgeRadioContainer {
min-height: 30px; /* ensure no height change when dropdown menu is hidden */
vertical-align: middle;
}
.help .heading,
......@@ -105,6 +112,7 @@ wizard#TorLauncherLocalePicker button[dlgtype="next"] {
#bridgeNote,
#bridgeDefaultEntry,
#bridgeDBContainer,
#bridgeCustomEntry {
margin-left: 1.8em;
}
......@@ -114,6 +122,15 @@ wizard.os-mac #bridgeList {
font-size: 90%;
}
#bridgeDBResult {
font-size: 90%;
white-space: pre;
}
#bridgeDBResult[value=""] {
display: none;
}
/* reuse Mozilla's help button from the Firefox hamburger menu */
.helpButton {
list-style-image: url(chrome://browser/skin/menuPanel-help.png);
......@@ -171,6 +188,7 @@ wizardpage[pageid="restartPanel"] description,
text-align: start;
}
#bridgeDBRequestOverlayContent,
#errorOverlayContent {
margin: 50px;
min-height: 12em;
......@@ -178,6 +196,62 @@ wizardpage[pageid="restartPanel"] description,
box-shadow: 0px 0px 50px rgba(0,0,0,0.9);
}
#bridgeDBRequestOverlayContent > vbox {
margin: 20px;
}
#bridgeDBPrompt {
text-align: center;
}
#bridgeDBCaptchaImage {
margin: 16px 0px;
width: 400px;
/* height is set via code so it can be animated. */
}
#bridgeDBReloadSpacer {
width: 20px; /* matches the width of #bridgeDBReloadCaptchaButton */
}
#bridgeDBReloadCaptchaButton {
list-style-image: url("chrome://torlauncher/skin/reload.svg");
-moz-appearance: none;
width: 20px; /* matches the width of #bridgeDBReloadSpacer */
height: 20px;
min-height: 20px;
min-width: 20px;
margin: 0;
background: none;
border: none;
box-shadow: none;
}
#bridgeDBNetworkActivity {
list-style-image: url("chrome://torlauncher/skin/activity.svg");
width: 20px;
height: 20px;
}
#bridgeDBCaptchaError {
color: red;
font-weight: bold;
text-align: center;
}
/* Hide BridgeDB overlay elements based on the state attribute. */
#bridgeDBRequestOverlay[state="fetchingCaptcha"] #bridgeDBReloadCaptchaButton,
#bridgeDBRequestOverlay[state="checkingSolution"] #bridgeDBReloadCaptchaButton,
#bridgeDBRequestOverlay[state="fetchingCaptcha"] #bridgeDBCaptchaSolution {
visibility: hidden;
}
#bridgeDBRequestOverlay[state="fetchingCaptcha"] #bridgeDBCaptchaError,
#bridgeDBRequestOverlay[state="fetchingCaptcha"] #bridgeDBSubmitButton,
#bridgeDBRequestOverlay[state="checkingSolution"] #bridgeDBSubmitButton {
display: none;
}
#errorOverlayContent button[errorElemId="dismissButton"] {
margin-bottom: 20px;
}
......
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#000000" d="M15 8H8l2.8-2.8a3.691 3.691 0 0 0-2.3-.7 4 4 0 0 0 0 8 3.9 3.9 0 0 0 3.4-1.9l2.3 1A6.5 6.5 0 1 1 8.5 2a6.773 6.773 0 0 1 4.1 1.4L15 1z"/>
</svg>
......@@ -45,6 +45,12 @@ pref("extensions.torlauncher.tor_path", "");
pref("extensions.torlauncher.torrc_path", "");
pref("extensions.torlauncher.tordatadir_path", "");
// BridgeDB-related preferences (used for Moat).
pref("extensions.torlauncher.bridgedb_front", "www.google.com");
pref("extensions.torlauncher.bridgedb_reflector", "https://tor-bridges-hyphae-channel.appspot.com");
pref("extensions.torlauncher.moat_service", "https://bridges.torproject.org/moat");
pref("extensions.torlauncher.bridgedb_bridge_type", "obfs4");
// Recommended default bridge type (can be set per localized bundle).
// pref("extensions.torlauncher.default_bridge_recommended_type", "obfs3");
......
This diff is collapsed.
// Copyright (c) 2017, The Tor Project, Inc.
// Copyright (c) 2018, The Tor Project, Inc.
// See LICENSE for licensing information.
//
// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
......@@ -12,8 +12,10 @@ let EXPORTED_SYMBOLS = [ "TorLauncherUtil" ];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
const kPropBundleURI = "chrome://torlauncher/locale/torlauncher.properties";
const kPropNamePrefix = "torlauncher.";
const kPrefBranchDefaultBridge = "extensions.torlauncher.default_bridge.";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TorLauncherLogger",
......@@ -161,6 +163,24 @@ let TorLauncherUtil = // Public
return aStringName;
},
getLocalizedStringForError: function(aNSResult)
{
for (let prop in Cr)
{
if (Cr[prop] == aNSResult)
{
let key = "nsresult." + prop;
let rv = this.getLocalizedString(key);
if (rv !== key)
return rv;
return prop; // As a fallback, return the NS_ERROR... name.
}
}
return undefined;
},
getLocalizedBootstrapStatus: function(aStatusObj, aKeyword)
{
if (!aStatusObj || !aKeyword)
......@@ -276,6 +296,13 @@ let TorLauncherUtil = // Public
} catch (e) {}
},
getPrefBranch: function(aBranchName)
{
return Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService)
.getBranch(aBranchName);
},
// Currently, this returns a random permutation of an array, bridgeArray.
// Later, we might want to change this function to weight based on the
// bridges' bandwidths.
......@@ -361,9 +388,7 @@ let TorLauncherUtil = // Public
{
try
{
var prefBranch = Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService)
.getBranch("extensions.torlauncher.default_bridge.");
var prefBranch = this.getPrefBranch(kPrefBranchDefaultBridge);
var childPrefs = prefBranch.getChildList("", []);
var typeArray = [];
for (var i = 0; i < childPrefs.length; ++i)
......@@ -390,9 +415,7 @@ let TorLauncherUtil = // Public
try
{
var prefBranch = Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService)
.getBranch("extensions.torlauncher.default_bridge.");
var prefBranch = this.getPrefBranch(kPrefBranchDefaultBridge);
var childPrefs = prefBranch.getChildList("", []);
var bridgeArray = [];
// The pref service seems to return the values in reverse order, so
......@@ -430,11 +453,13 @@ let TorLauncherUtil = // Public
let isRelativePath = false;
let isUserData = (aTorFileType != "tor") &&
(aTorFileType != "pt-startup-dir") &&
(aTorFileType != "torrc-defaults");
let isControlIPC = ("control_ipc" == aTorFileType);
let isSOCKSIPC = ("socks_ipc" == aTorFileType);
let isIPC = isControlIPC || isSOCKSIPC;
let checkIPCPathLen = true;
let useAppDir = false;
const kControlIPCFileName = "control.socket";
const kSOCKSIPCFileName = "socks.socket";
......@@ -523,6 +548,8 @@ let TorLauncherUtil = // Public
{
if ("tor" == aTorFileType)
path = "TorBrowser\\Tor\\tor.exe";
else if ("pt-startup-dir" == aTorFileType)
useAppDir = true;
else if ("torrc-defaults" == aTorFileType)
path = "TorBrowser\\Tor\\torrc-defaults";
else if ("torrc" == aTorFileType)
......@@ -534,6 +561,8 @@ let TorLauncherUtil = // Public
{
if ("tor" == aTorFileType)
path = "Contents/Resources/TorBrowser/Tor/tor";
else if ("pt-startup-dir" == aTorFileType)
path = "Contents/MacOS/Tor";
else if ("torrc-defaults" == aTorFileType)
path = "Contents/Resources/TorBrowser/Tor/torrc-defaults";
else if ("torrc" == aTorFileType)
......@@ -547,6 +576,8 @@ let TorLauncherUtil = // Public
{
if ("tor" == aTorFileType)
path = "TorBrowser/Tor/tor";
else if ("pt-startup-dir" == aTorFileType)
useAppDir = true;
else if ("torrc-defaults" == aTorFileType)
path = "TorBrowser/Tor/torrc-defaults";
else if ("torrc" == aTorFileType)
......@@ -562,6 +593,8 @@ let TorLauncherUtil = // Public
// This block is used for the non-TorBrowser-Data/ case.
if ("tor" == aTorFileType)
path = "Tor\\tor.exe";
else if ("pt-startup-dir" == aTorFileType)
useAppDir = true;
else if ("torrc-defaults" == aTorFileType)
path = "Data\\Tor\\torrc-defaults";
else if ("torrc" == aTorFileType)
......@@ -574,6 +607,8 @@ let TorLauncherUtil = // Public
// This block is also used for the non-TorBrowser-Data/ case.
if ("tor" == aTorFileType)
path = "Tor/tor";
else if ("pt-startup-dir" == aTorFileType)
useAppDir = true;
else if ("torrc-defaults" == aTorFileType)
path = "Data/Tor/torrc-defaults";
else if ("torrc" == aTorFileType)
......@@ -584,13 +619,17 @@ let TorLauncherUtil = // Public
path = "Data/Tor/" + ipcFileName;
}
if (!path)
if (!path && !useAppDir)
return null;
}
try
{
if (path)
if (useAppDir)
{
torFile = TLUtilInternal._appDir.clone();
}
else if (path)
{
if (isRelativePath)
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment