[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [bridgedb/master] Make our email autoresponder more usable.
commit 1958bbb7e95df0f810e219955595f353933e1302
Author: Philipp Winter <phw@xxxxxxxxx>
Date: Tue Mar 31 09:37:37 2020 -0700
Make our email autoresponder more usable.
So far, our autoresponder would only send you bridges if your request
was valid. Unfortunately, it's not very easy to figure out what a
correct request looks like. This patch returns bridges regardless of if
the request was valid or not. We also remove the "help" autoresponse
because there's no longer a need for it, and we simplify BridgeDB's auto
response, hopefully making it less frustrating for users.
This fixes <https://bugs.torproject.org/30941>.
---
CHANGELOG | 6 ++
bridgedb/distributors/email/autoresponder.py | 10 --
bridgedb/distributors/email/distributor.py | 6 +-
bridgedb/distributors/email/request.py | 20 ++--
bridgedb/distributors/email/templates.py | 83 +++++-----------
bridgedb/i18n/templates/bridgedb.pot | 143 +++++++++++----------------
bridgedb/metrics.py | 7 +-
bridgedb/strings.py | 49 ++++-----
bridgedb/test/test_email_autoresponder.py | 5 +-
bridgedb/test/test_email_request.py | 46 ++++-----
bridgedb/test/test_email_templates.py | 31 +-----
11 files changed, 151 insertions(+), 255 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 3e179e1..f85283b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,9 @@
+ * FIXES https://bugs.torproject.org/30941
+ Make our email responder more usable. This patch removes the concept of
+ "valid" email commands and returns bridges (obfs4, for now) no matter
+ what the user sends. BridgeDB still supports email commands in case the
+ user needs a vanilla or IPv6 bridge.
+
* FIXES https://bugs.torproject.org/29686
Rename files that contain "Bridges" to "bridgerings", to eliminate
headache on file systems that are case insensitive.
diff --git a/bridgedb/distributors/email/autoresponder.py b/bridgedb/distributors/email/autoresponder.py
index 3711eae..5e1fcd0 100644
--- a/bridgedb/distributors/email/autoresponder.py
+++ b/bridgedb/distributors/email/autoresponder.py
@@ -55,7 +55,6 @@ from bridgedb import safelog
from bridgedb.distributors.email import dkim
from bridgedb.distributors.email import request
from bridgedb.distributors.email import templates
-from bridgedb.distributors.email.distributor import EmailRequestedHelp
from bridgedb.distributors.email.distributor import EmailRequestedKey
from bridgedb.distributors.email.distributor import TooSoonEmail
from bridgedb.distributors.email.distributor import IgnoreEmail
@@ -98,18 +97,9 @@ def createResponseBody(lines, context, client, lang='en'):
bridgeRequest = request.determineBridgeRequestOptions(lines)
bridgeRequest.client = str(client)
- # The request was invalid, respond with a help email which explains
- # valid email commands:
- if not bridgeRequest.isValid():
- raise EmailRequestedHelp("Email request from '%s' was invalid."
- % str(client))
-
# Otherwise they must have requested bridges:
interval = context.schedule.intervalStart(time.time())
bridges = context.distributor.getBridges(bridgeRequest, interval)
- except EmailRequestedHelp as error:
- logging.info(error)
- return templates.buildWelcomeText(translator, client)
except EmailRequestedKey as error:
logging.info(error)
return templates.buildKeyMessage(translator, client)
diff --git a/bridgedb/distributors/email/distributor.py b/bridgedb/distributors/email/distributor.py
index a90e725..c6ac2fd 100644
--- a/bridgedb/distributors/email/distributor.py
+++ b/bridgedb/distributors/email/distributor.py
@@ -20,7 +20,7 @@ bridgedb.distributors.email.autoresponder
A :class:`~bridgedb.distribute.Distributor` which hands out :class:`bridges
<bridgedb.bridges.Bridge>` to clients via an email interface.
-.. inheritance-diagram:: IgnoreEmail TooSoonEmail EmailRequestedHelp EmailRequestedKey EmailDistributor
+.. inheritance-diagram:: IgnoreEmail TooSoonEmail EmailRequestedKey EmailDistributor
:parts: 1
"""
@@ -55,10 +55,6 @@ class TooSoonEmail(addr.BadEmail):
"""Raised when we got a request from this address too recently."""
-class EmailRequestedHelp(Exception):
- """Raised when a client has emailed requesting help."""
-
-
class EmailRequestedKey(Exception):
"""Raised when an incoming email requested a copy of our GnuPG keys."""
diff --git a/bridgedb/distributors/email/request.py b/bridgedb/distributors/email/request.py
index 83c203d..90576c1 100644
--- a/bridgedb/distributors/email/request.py
+++ b/bridgedb/distributors/email/request.py
@@ -43,8 +43,8 @@ from __future__ import unicode_literals
import logging
import re
+from bridgedb import strings
from bridgedb import bridgerequest
-from bridgedb.distributors.email.distributor import EmailRequestedHelp
from bridgedb.distributors.email.distributor import EmailRequestedKey
@@ -61,7 +61,6 @@ UNBLOCKED_PATTERN = re.compile(UNBLOCKED_REGEXP)
#: Regular expressions that we use to match for email commands. Any command is
#: valid as long as it wasn't quoted, i.e., the line didn't start with a '>'
#: character.
-HELP_LINE = re.compile("([^>].*)?h[ae]lp")
GET_LINE = re.compile("([^>].*)?get")
KEY_LINE = re.compile("([^>].*)?key")
IPV6_LINE = re.compile("([^>].*)?ipv6")
@@ -69,14 +68,13 @@ TRANSPORT_LINE = re.compile("([^>].*)?transport")
UNBLOCKED_LINE = re.compile("([^>].*)?unblocked")
def determineBridgeRequestOptions(lines):
- """Figure out which :mod:`~bridgedb.filters` to apply, or offer help.
+ """Figure out which :mod:`~bridgedb.filters` to apply.
.. note:: If any ``'transport TYPE'`` was requested, or bridges not
blocked in a specific CC (``'unblocked CC'``), then the ``TYPE``
and/or ``CC`` will *always* be stored as a *lowercase* string.
:param list lines: A list of lines from an email, including the headers.
- :raises EmailRequestedHelp: if the client requested help.
:raises EmailRequestedKey: if the client requested our GnuPG key.
:rtype: :class:`EmailBridgeRequest`
:returns: A :class:`~bridgerequest.BridgeRequest` with all of the requested
@@ -92,9 +90,6 @@ def determineBridgeRequestOptions(lines):
if not line: skippedHeaders = True
if not skippedHeaders: continue
- if HELP_LINE.match(line) is not None:
- raise EmailRequestedHelp("Client requested help.")
-
if GET_LINE.match(line) is not None:
request.isValid(True)
logging.debug("Email request was valid.")
@@ -108,6 +103,17 @@ def determineBridgeRequestOptions(lines):
if UNBLOCKED_LINE.match(line) is not None:
request.withoutBlockInCountry(line)
+ # We cannot expect all users to understand BridgeDB's commands, so we will
+ # return bridges even if the request was invalid.
+ if not request.isValid():
+ logging.debug("Email request was invalid.")
+ request.isValid(True)
+ # We will respond with our default transport protocol.
+ if not len(request.transports):
+ # Note that this variable must satisfy TRANSPORT_PATTERN.
+ default_transport = "transport %s" % strings._getDefaultTransport()
+ request.withPluggableTransportType(default_transport)
+
logging.debug("Generating hashring filters for request.")
request.generateFilters()
return request
diff --git a/bridgedb/distributors/email/templates.py b/bridgedb/distributors/email/templates.py
index d618c37..2eb0a31 100644
--- a/bridgedb/distributors/email/templates.py
+++ b/bridgedb/distributors/email/templates.py
@@ -21,9 +21,6 @@ bridgedb.distributors.email.templates
Templates for formatting emails sent out by the email distributor.
"""
-from __future__ import print_function
-from __future__ import unicode_literals
-
import logging
import os
@@ -34,12 +31,17 @@ from bridgedb.distributors.email.distributor import MAX_EMAIL_RATE
def addCommands(template):
- """Add some text telling a client about supported email command, as well as
- which Pluggable Transports are currently available.
+ """Add text telling a client about supported email command.
+
+ :type template: ``gettext.NullTranslation`` or ``gettext.GNUTranslation``
+ :param template: A gettext translations instance, optionally with fallback
+ languages set.
+ :rtype: str
+ :returns: A string explaining email commands.
"""
# Tell them about the various email commands:
cmdlist = []
- cmdlist.append(template.gettext(strings.EMAIL_MISC_TEXT.get(3)))
+ cmdlist.append(template.gettext(strings.EMAIL_MISC_TEXT.get(3)) + "\n")
for cmd, desc in strings.EMAIL_COMMANDS.items():
command = ' '
command += cmd
@@ -48,29 +50,20 @@ def addCommands(template):
command += template.gettext(desc)
cmdlist.append(command)
- commands = "\n".join(cmdlist) + "\n\n"
- # And include the currently supported transports:
- commands += template.gettext(strings.EMAIL_MISC_TEXT.get(5))
- commands += "\n"
- for pt in strings._getSupportedTransports():
- commands += ' ' + pt + "\n"
+ return "\n".join(cmdlist) + "\n\n"
- return commands
+def addGreeting(template):
+ """Our "greeting" clarifies that this is an automated email response.
-def addGreeting(template, clientName=None, welcome=False):
- greeting = ""
- clientName = clientName.decode('utf-8') if isinstance(clientName, bytes) else clientName
-
- if not clientName:
- greeting = template.gettext(strings.EMAIL_MISC_TEXT[7])
- else:
- greeting = template.gettext(strings.EMAIL_MISC_TEXT[6]) % clientName
+ :type template: ``gettext.NullTranslation`` or ``gettext.GNUTranslation``
+ :param template: A gettext translations instance, optionally with fallback
+ languages set.
+ :rtype: str
+ :returns: A string containing our "greeting".
+ """
- if greeting:
- if welcome:
- greeting += u' '
- greeting += template.gettext(strings.EMAIL_MISC_TEXT[4])
- greeting += u'\n\n'
+ greeting = template.gettext(strings.EMAIL_MISC_TEXT[0])
+ greeting += u"\n\n"
return greeting
@@ -79,11 +72,10 @@ def addKeyfile(template):
def addBridgeAnswer(template, answer):
# Give the user their bridges, i.e. the `answer`:
- bridgeLines = template.gettext(strings.EMAIL_MISC_TEXT[0])
- bridgeLines += u"\n\n"
+ bridgeLines = u""
bridgeLines += template.gettext(strings.EMAIL_MISC_TEXT[1])
bridgeLines += u"\n\n"
- bridgeLines += u"%s\n\n" % answer
+ bridgeLines += u"%s\n" % answer
return bridgeLines
@@ -94,40 +86,15 @@ def addHowto(template):
:param template: A gettext translations instance, optionally with fallback
languages set.
"""
- howToTBB = template.gettext(strings.HOWTO_TBB[1]) % strings.EMAIL_SPRINTF["HOWTO_TBB1"]
- howToTBB += u'\n\n'
- howToTBB += strings.EMAIL_REFERENCE_LINKS.get("HOWTO_TBB1")
- howToTBB += strings.EMAIL_REFERENCE_LINKS.get("HOWTO_TBB2")
- howToTBB += strings.EMAIL_REFERENCE_LINKS.get("HOWTO_TBB3")
- howToTBB += u'\n\n'
- return howToTBB
+ return template.gettext(strings.HOWTO_TBB[2])
def buildKeyMessage(template, clientAddress=None):
message = addKeyfile(template)
return message
-def buildWelcomeText(template, clientAddress=None):
- sections = []
- sections.append(addGreeting(template, clientAddress.local, welcome=True))
-
- commands = addCommands(template)
- sections.append(commands)
-
- # Include the same messages as the homepage of the HTTPS distributor:
- welcome = template.gettext(strings.WELCOME[0]) % strings.EMAIL_SPRINTF["WELCOME0"]
- welcome += template.gettext(strings.WELCOME[1])
- welcome += template.gettext(strings.WELCOME[2]) % strings.EMAIL_SPRINTF["WELCOME2"]
- sections.append(welcome)
-
- message = u"\n\n".join(sections)
- # Add the markdown links at the end:
- message += strings.EMAIL_REFERENCE_LINKS.get("WELCOME0")
-
- return message
-
def buildAnswerMessage(template, clientAddress=None, answer=None):
try:
- message = addGreeting(template, clientAddress.local)
+ message = addGreeting(template)
message += addBridgeAnswer(template, answer)
message += addHowto(template)
message += u'\n\n'
@@ -139,11 +106,9 @@ def buildAnswerMessage(template, clientAddress=None, answer=None):
return message
def buildSpamWarning(template, clientAddress=None):
- message = addGreeting(template, clientAddress.local)
+ message = addGreeting(template)
try:
- message += template.gettext(strings.EMAIL_MISC_TEXT[0])
- message += u"\n\n"
message += template.gettext(strings.EMAIL_MISC_TEXT[2]) \
% str(MAX_EMAIL_RATE / 3600)
except Exception as error: # pragma: no cover
diff --git a/bridgedb/i18n/templates/bridgedb.pot b/bridgedb/i18n/templates/bridgedb.pot
index 8fa69c6..65f8ca6 100644
--- a/bridgedb/i18n/templates/bridgedb.pot
+++ b/bridgedb/i18n/templates/bridgedb.pot
@@ -5,11 +5,11 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: bridgedb 0.9.4+8.g5afd164.dirty\n"
+"Project-Id-Version: bridgedb 0.10.0+8.g97621c0\n"
"Report-Msgid-Bugs-To: "
"'https://trac.torproject.org/projects/tor/newticket?component=BridgeDB&keywords"
"=bridgedb-reported,msgid&cc=isis,sysrqb&owner=isis'\n"
-"POT-Creation-Date: 2020-03-24 10:22-0700\n"
+"POT-Creation-Date: 2020-04-06 13:53-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@xxxxxx>\n"
@@ -66,6 +66,10 @@ msgstr ""
msgid "Changelog"
msgstr ""
+#: bridgedb/distributors/https/templates/base.html:102
+msgid "Public Keys"
+msgstr ""
+
#: bridgedb/distributors/https/templates/bridges.html:35
msgid "Select All"
msgstr ""
@@ -83,7 +87,7 @@ msgstr ""
#. for Italian, you might translate this into "Mama mia!",
#. or for French: "Sacrebleu!". :)
#: bridgedb/distributors/https/templates/bridges.html:67
-#: bridgedb/distributors/https/templates/bridges.html:125
+#: bridgedb/distributors/https/templates/bridges.html:119
msgid "Uh oh, spaghettios!"
msgstr ""
@@ -97,12 +101,12 @@ msgid ""
"your bridge lines onto mobile and other devices."
msgstr ""
-#: bridgedb/distributors/https/templates/bridges.html:131
+#: bridgedb/distributors/https/templates/bridges.html:125
msgid "There currently aren't any bridges available..."
msgstr ""
-#: bridgedb/distributors/https/templates/bridges.html:133
-#: bridgedb/distributors/https/templates/bridges.html:137
+#: bridgedb/distributors/https/templates/bridges.html:127
+#: bridgedb/distributors/https/templates/bridges.html:131
#, python-format
msgid " Perhaps you should try %s going back %s and choosing a different bridge type!"
msgstr ""
@@ -176,15 +180,15 @@ msgstr ""
msgid "%sG%set Bridges"
msgstr ""
-#: bridgedb/strings.py:43
-msgid "[This is an automated message; please do not reply.]"
+#: bridgedb/strings.py:42
+msgid "[This is an automated email.]"
msgstr ""
-#: bridgedb/strings.py:45
+#: bridgedb/strings.py:44
msgid "Here are your bridges:"
msgstr ""
-#: bridgedb/strings.py:47
+#: bridgedb/strings.py:46
#, python-format
msgid ""
"You have exceeded the rate limit. Please slow down! The minimum time between\n"
@@ -192,48 +196,17 @@ msgid ""
"ignored."
msgstr ""
-#: bridgedb/strings.py:50
-msgid "COMMANDs: (combine COMMANDs to specify multiple options simultaneously)"
-msgstr ""
-
-#. TRANSLATORS: Please DO NOT translate the word "BridgeDB".
-#: bridgedb/strings.py:53
-msgid "Welcome to BridgeDB!"
-msgstr ""
-
-#. TRANSLATORS: Please DO NOT translate the words "transport" or "TYPE".
-#: bridgedb/strings.py:55
-msgid "Currently supported transport TYPEs:"
-msgstr ""
-
-#: bridgedb/strings.py:56
-#, python-format
-msgid "Hey, %s!"
-msgstr ""
-
-#: bridgedb/strings.py:57
-msgid "Hello, friend!"
-msgstr ""
-
-#: bridgedb/distributors/https/templates/base.html:102 bridgedb/strings.py:58
-msgid "Public Keys"
-msgstr ""
-
-#. TRANSLATORS: This string will end up saying something like:
-#. "This email was generated with rainbows, unicorns, and sparkles
-#. for alice@xxxxxxxxxxx on Friday, 09 May, 2014 at 18:59:39."
-#: bridgedb/strings.py:62
-#, python-format
+#: bridgedb/strings.py:49
msgid ""
-"This email was generated with rainbows, unicorns, and sparkles\n"
-"for %s on %s at %s."
+"If these bridges are not what you need, reply to this email with one of\n"
+"the following commands in the message body:"
msgstr ""
#. TRANSLATORS: Please DO NOT translate "BridgeDB".
#. TRANSLATORS: Please DO NOT translate "Pluggable Transports".
#. TRANSLATORS: Please DO NOT translate "Tor".
#. TRANSLATORS: Please DO NOT translate "Tor Network".
-#: bridgedb/strings.py:72
+#: bridgedb/strings.py:59
#, python-format
msgid ""
"BridgeDB can provide bridges with several %stypes of Pluggable Transports%s,\n"
@@ -245,7 +218,7 @@ msgid ""
msgstr ""
#. TRANSLATORS: Please DO NOT translate "Pluggable Transports".
-#: bridgedb/strings.py:79
+#: bridgedb/strings.py:66
msgid ""
"Some bridges with IPv6 addresses are also available, though some Pluggable\n"
"Transports aren't IPv6 compatible.\n"
@@ -257,7 +230,7 @@ msgstr ""
#. regular, or unexciting". Like vanilla ice cream. It refers to bridges
#. which do not have Pluggable Transports, and only speak the regular,
#. boring Tor protocol. Translate it as you see fit. Have fun with it.
-#: bridgedb/strings.py:88
+#: bridgedb/strings.py:75
#, python-format
msgid ""
"Additionally, BridgeDB has plenty of plain-ol'-vanilla bridges %s without any"
@@ -268,21 +241,21 @@ msgid ""
"\n"
msgstr ""
-#: bridgedb/strings.py:101 bridgedb/test/test_https.py:356
+#: bridgedb/strings.py:87 bridgedb/test/test_https.py:356
msgid "What are bridges?"
msgstr ""
-#: bridgedb/strings.py:102
+#: bridgedb/strings.py:88
#, python-format
msgid "%s Bridges %s are Tor relays that help you circumvent censorship."
msgstr ""
-#: bridgedb/strings.py:107
+#: bridgedb/strings.py:93
msgid "I need an alternative way of getting bridges!"
msgstr ""
#. TRANSLATORS: Please DO NOT translate "get transport obfs4".
-#: bridgedb/strings.py:109
+#: bridgedb/strings.py:95
#, python-format
msgid ""
"Another way to get bridges is to send an email to %s. Leave the email subject"
@@ -294,32 +267,32 @@ msgid ""
"providers: %s or %s."
msgstr ""
-#: bridgedb/strings.py:117
+#: bridgedb/strings.py:103
msgid "My bridges don't work! I need help!"
msgstr ""
#. TRANSLATORS: Please DO NOT translate "Tor Browser".
#. TRANSLATORS: The two '%s' are substituted with "Tor Browser Manual" and
#. "Support Portal", respectively.
-#: bridgedb/strings.py:121
+#: bridgedb/strings.py:107
#, python-format
msgid "If your Tor Browser cannot connect, please take a look at the %s and our %s."
msgstr ""
-#: bridgedb/strings.py:125
+#: bridgedb/strings.py:111
msgid "Here are your bridge lines:"
msgstr ""
-#: bridgedb/strings.py:126
+#: bridgedb/strings.py:112
msgid "Get Bridges!"
msgstr ""
-#: bridgedb/strings.py:130
+#: bridgedb/strings.py:116
msgid "Bridge distribution mechanisms"
msgstr ""
#. TRANSLATORS: Please DO NOT translate "BridgeDB", "HTTPS", and "Moat".
-#: bridgedb/strings.py:132
+#: bridgedb/strings.py:118
#, python-format
msgid ""
"BridgeDB implements four mechanisms to distribute bridges: \"HTTPS\", "
@@ -333,7 +306,7 @@ msgid ""
"mechanisms is."
msgstr ""
-#: bridgedb/strings.py:138
+#: bridgedb/strings.py:124
#, python-format
msgid ""
"The \"HTTPS\" distribution mechanism hands out bridges over this website. To"
@@ -343,7 +316,7 @@ msgid ""
"solve the subsequent CAPTCHA."
msgstr ""
-#: bridgedb/strings.py:142
+#: bridgedb/strings.py:128
#, python-format
msgid ""
"The \"Moat\" distribution mechanism is part of Tor Browser, allowing users to"
@@ -356,7 +329,7 @@ msgid ""
"bridges."
msgstr ""
-#: bridgedb/strings.py:148
+#: bridgedb/strings.py:134
#, python-format
msgid ""
"Users can request bridges from the \"Email\" distribution mechanism by "
@@ -366,11 +339,11 @@ msgid ""
"email body."
msgstr ""
-#: bridgedb/strings.py:152
+#: bridgedb/strings.py:138
msgid "Reserved"
msgstr ""
-#: bridgedb/strings.py:153
+#: bridgedb/strings.py:139
#, python-format
msgid ""
"BridgeDB maintains a small number of bridges that are not distributed\n"
@@ -384,11 +357,11 @@ msgid ""
"called \"Unallocated\" in %sbridge pool assignment%s files."
msgstr ""
-#: bridgedb/strings.py:160
+#: bridgedb/strings.py:146
msgid "None"
msgstr ""
-#: bridgedb/strings.py:161
+#: bridgedb/strings.py:147
msgid ""
"Bridges whose distribution mechanism is \"None\" are not distributed by "
"BridgeDB.\n"
@@ -399,33 +372,33 @@ msgid ""
"it will then change to the bridge's actual distribution mechanism.\n"
msgstr ""
-#: bridgedb/strings.py:171
+#: bridgedb/strings.py:157
msgid "Please select options for bridge type:"
msgstr ""
-#: bridgedb/strings.py:172
+#: bridgedb/strings.py:158
msgid "Do you need IPv6 addresses?"
msgstr ""
-#: bridgedb/strings.py:173
+#: bridgedb/strings.py:159
#, python-format
msgid "Do you need a %s?"
msgstr ""
-#: bridgedb/strings.py:177
+#: bridgedb/strings.py:163
msgid "Your browser is not displaying images properly."
msgstr ""
-#: bridgedb/strings.py:178
+#: bridgedb/strings.py:164
msgid "Enter the characters from the image above..."
msgstr ""
-#: bridgedb/strings.py:182
+#: bridgedb/strings.py:168
msgid "How to start using your bridges"
msgstr ""
#. TRANSLATORS: Please DO NOT translate "Tor Browser".
-#: bridgedb/strings.py:184
+#: bridgedb/strings.py:170
#, python-format
msgid ""
" First, you need to %sdownload Tor Browser%s. Our Tor Browser User\n"
@@ -434,29 +407,29 @@ msgid ""
" are using Android, %sclick here%s."
msgstr ""
-#: bridgedb/strings.py:192
-msgid "Displays this message."
+#: bridgedb/strings.py:175
+msgid ""
+"Add these bridges to your Tor Browser by opening your browser\n"
+"preferences, clicking on \"Tor\", and then adding them to the \"Provide a\n"
+"bridge\" field."
msgstr ""
-#. TRANSLATORS: Please try to make it clear that "vanilla" here refers to the
-#. same non-Pluggable Transport bridges described above as being
-#. "plain-ol'-vanilla" bridges.
-#: bridgedb/strings.py:196
-msgid "Request vanilla bridges."
+#: bridgedb/strings.py:182
+msgid "(Request unobfuscated Tor bridges.)"
msgstr ""
-#: bridgedb/strings.py:197
-msgid "Request IPv6 bridges."
+#: bridgedb/strings.py:183
+msgid "(Request IPv6 bridges.)"
msgstr ""
-#. TRANSLATORS: Please DO NOT translate the word the word "TYPE".
-#: bridgedb/strings.py:199
-msgid "Request a Pluggable Transport by TYPE."
+#. TRANSLATORS: Please DO NOT translate the word "TYPE".
+#: bridgedb/strings.py:185
+msgid "(Request obfuscated bridges. Replace TYPE with 'obfs4'.)"
msgstr ""
#. TRANSLATORS: Please DO NOT translate "BridgeDB".
#. TRANSLATORS: Please DO NOT translate "GnuPG".
-#: bridgedb/strings.py:202
-msgid "Get a copy of BridgeDB's public GnuPG key."
+#: bridgedb/strings.py:189
+msgid "(Get a copy of BridgeDB's public GnuPG key.)"
msgstr ""
diff --git a/bridgedb/metrics.py b/bridgedb/metrics.py
index bb888d9..48713f0 100644
--- a/bridgedb/metrics.py
+++ b/bridgedb/metrics.py
@@ -22,7 +22,6 @@ import datetime
from bridgedb import geo
from bridgedb.distributors.common.http import getClientIP
from bridgedb.distributors.email import request
-from bridgedb.distributors.email.distributor import EmailRequestedHelp
from twisted.mail.smtp import Address
@@ -387,11 +386,7 @@ class EmailMetrics(Metrics):
emailAddr = emailAddrs[0]
# Get the requested transport protocol.
- try:
- br = request.determineBridgeRequestOptions(
- smtpAutoresp.incoming.lines)
- except EmailRequestedHelp:
- return
+ br = request.determineBridgeRequestOptions( smtpAutoresp.incoming.lines)
bridgeType = "vanilla" if not len(br.transports) else br.transports[0]
# Over email, transports are requested by typing them. Typos happen
diff --git a/bridgedb/strings.py b/bridgedb/strings.py
index b6a7f1f..f3ea849 100644
--- a/bridgedb/strings.py
+++ b/bridgedb/strings.py
@@ -38,30 +38,17 @@ def _(text):
return text
-# TRANSLATORS: Please do not translate the word "TYPE".
EMAIL_MISC_TEXT = {
0: _("""\
-[This is an automated message; please do not reply.]"""),
+[This is an automated email.]"""),
1: _("""\
Here are your bridges:"""),
2: _("""\
You have exceeded the rate limit. Please slow down! The minimum time between
emails is %s hours. All further emails during this time period will be ignored."""),
3: _("""\
-COMMANDs: (combine COMMANDs to specify multiple options simultaneously)"""),
- # TRANSLATORS: Please DO NOT translate the word "BridgeDB".
- 4: _("Welcome to BridgeDB!"),
- # TRANSLATORS: Please DO NOT translate the words "transport" or "TYPE".
- 5: _("Currently supported transport TYPEs:"),
- 6: _("Hey, %s!"),
- 7: _("Hello, friend!"),
- 8: _("Public Keys"),
- # TRANSLATORS: This string will end up saying something like:
- # "This email was generated with rainbows, unicorns, and sparkles
- # for alice@xxxxxxxxxxx on Friday, 09 May, 2014 at 18:59:39."
- 9: _("""\
-This email was generated with rainbows, unicorns, and sparkles
-for %s on %s at %s."""),
+If these bridges are not what you need, reply to this email with one of
+the following commands in the message body:"""),
}
WELCOME = {
@@ -90,11 +77,10 @@ Additionally, BridgeDB has plenty of plain-ol'-vanilla bridges %s without any
Pluggable Transports %s which maybe doesn't sound as cool, but they can still
help to circumvent internet censorship in many cases.\n\n"""),
}
-"""These strings should go on the first "Welcome" email sent by the
-:mod:`~bridgedb.EmailServer`, as well as on the ``index.html`` template used
-by the :mod:`~bridgedb.distributors.https.server`. They are used as an introduction to
-explain what Tor bridges are, what bridges do, and why someone might want to
-use bridges.
+"""These strings should go on the ``options.html`` template used by the
+:mod:`~bridgedb.distributors.https.server`. They are used as an
+introduction to explain what Tor bridges are, what bridges do, and why
+someone might want to use bridges.
"""
FAQ = {
@@ -186,22 +172,21 @@ HOWTO_TBB = {
Manual explains how you can add your bridges to Tor Browser. If you are
using Windows, Linux, or OS X, %sclick here%s to learn more. If you
are using Android, %sclick here%s."""),
+ 2: _("""\
+Add these bridges to your Tor Browser by opening your browser
+preferences, clicking on "Tor", and then adding them to the "Provide a
+bridge" field."""),
}
EMAIL_COMMANDS = {
- "get help": _("Displays this message."),
-# TRANSLATORS: Please try to make it clear that "vanilla" here refers to the
-# same non-Pluggable Transport bridges described above as being
-# "plain-ol'-vanilla" bridges.
- "get bridges": _("Request vanilla bridges."),
- "get ipv6": _("Request IPv6 bridges."),
- # TRANSLATORS: Please DO NOT translate the word the word "TYPE".
- "get transport [TYPE]": _("Request a Pluggable Transport by TYPE."),
+ "get bridges": _("(Request unobfuscated Tor bridges.)"),
+ "get ipv6": _("(Request IPv6 bridges.)"),
+ # TRANSLATORS: Please DO NOT translate the word "TYPE".
+ "get transport TYPE": _("(Request obfuscated bridges. Replace TYPE with "
+ "'obfs4'.)"),
# TRANSLATORS: Please DO NOT translate "BridgeDB".
# TRANSLATORS: Please DO NOT translate "GnuPG".
- "get key": _("Get a copy of BridgeDB's public GnuPG key."),
- #"subscribe": _("Subscribe to receive new bridges once per week"),
- #"unsubscribe": _("Cancel a subscription to new bridges"),
+ "get key": _("(Get a copy of BridgeDB's public GnuPG key.)"),
}
#-----------------------------------------------------------------------------
diff --git a/bridgedb/test/test_email_autoresponder.py b/bridgedb/test/test_email_autoresponder.py
index c8e9624..d5023e0 100644
--- a/bridgedb/test/test_email_autoresponder.py
+++ b/bridgedb/test/test_email_autoresponder.py
@@ -70,11 +70,12 @@ class CreateResponseBodyTests(unittest.TestCase):
self.assertSubstring('-----BEGIN PGP PUBLIC KEY BLOCK-----', ret)
def test_createResponseBody_bridges_invalid(self):
- """An invalid request for 'transport obfs3' should get help text."""
+ """An invalid request for 'transport obfs3' should still return
+ bridges."""
lines = self._getIncomingLines("testing@localhost")
lines[4] = "transport obfs3"
ret = autoresponder.createResponseBody(lines, self.ctx, self.toAddress)
- self.assertSubstring("COMMANDs", ret)
+ self.assertSubstring("Here are your bridges:", ret)
def test_createResponseBody_bridges_obfs3(self):
"""A request for 'get transport obfs3' should receive a response."""
diff --git a/bridgedb/test/test_email_request.py b/bridgedb/test/test_email_request.py
index 0c87d36..e0bb642 100644
--- a/bridgedb/test/test_email_request.py
+++ b/bridgedb/test/test_email_request.py
@@ -17,26 +17,25 @@ import ipaddr
from twisted.trial import unittest
+from bridgedb import strings
from bridgedb.distributors.email import request
class DetermineBridgeRequestOptionsTests(unittest.TestCase):
"""Unittests for :func:`b.e.request.determineBridgeRequestOptions`."""
- def test_determineBridgeRequestOptions_get_help(self):
- """Requesting 'get help' should raise EmailRequestedHelp."""
- lines = ['',
- 'get help']
- self.assertRaises(request.EmailRequestedHelp,
- request.determineBridgeRequestOptions, lines)
-
- def test_determineBridgeRequestOptions_get_halp(self):
- """Requesting 'get halp' should raise EmailRequestedHelp."""
+ def test_determineBridgeRequestOptions_multiline_invalid(self):
lines = ['',
- 'get halp']
- self.assertRaises(request.EmailRequestedHelp,
- request.determineBridgeRequestOptions, lines)
-
+ 'help',
+ 'i need bridges',
+ 'give me your gpgs']
+ reqvest = request.determineBridgeRequestOptions(lines)
+ # We consider every request valid...
+ self.assertEqual(reqvest.isValid(), True)
+ self.assertFalse(reqvest.wantsKey())
+ # ...so by default, we return a bridge.
+ self.assertEqual(len(reqvest.transports), 1)
+
def test_determineBridgeRequestOptions_get_key(self):
"""Requesting 'get key' should raise EmailRequestedKey."""
lines = ['',
@@ -45,14 +44,14 @@ class DetermineBridgeRequestOptionsTests(unittest.TestCase):
request.determineBridgeRequestOptions, lines)
def test_determineBridgeRequestOptions_multiline_invalid(self):
- """Requests without a 'get' anywhere should be considered invalid."""
+ """Requests without a 'get' are incorrect but still valid, and should
+ return bridges."""
lines = ['',
'transport obfs3',
'ipv6 vanilla bridges',
'give me your gpgs']
reqvest = request.determineBridgeRequestOptions(lines)
- # It's invalid because it didn't include a 'get' anywhere.
- self.assertEqual(reqvest.isValid(), False)
+ self.assertEqual(reqvest.isValid(), True)
self.assertFalse(reqvest.wantsKey())
# Though they did request IPv6, technically.
self.assertIs(reqvest.ipVersion, 6)
@@ -61,9 +60,8 @@ class DetermineBridgeRequestOptionsTests(unittest.TestCase):
self.assertEqual(reqvest.transports[0], 'obfs3')
def test_determineBridgeRequestOptions_multiline_valid(self):
- """Though requests with a 'get' are considered valid."""
lines = ['',
- 'get transport obfs3',
+ 'transport obfs3',
'vanilla bridges',
'transport scramblesuit unblocked ca']
reqvest = request.determineBridgeRequestOptions(lines)
@@ -73,6 +71,7 @@ class DetermineBridgeRequestOptionsTests(unittest.TestCase):
# Though they didn't request IPv6, so it should default to IPv4.
self.assertIs(reqvest.ipVersion, 4)
# And they requested two transports.
+ print(reqvest.transports)
self.assertEqual(len(reqvest.transports), 2)
self.assertEqual(reqvest.transports[0], 'obfs3')
self.assertEqual(reqvest.transports[1], 'scramblesuit')
@@ -103,13 +102,16 @@ class DetermineBridgeRequestOptionsTests(unittest.TestCase):
self.assertEqual(reqvest.notBlockedIn[0], 'ca')
def test_determineBridgeRequestOptions_get_transport(self):
- """An invalid request for 'transport obfs3' (missing the 'get')."""
+ """An invalid request for 'transprot obfs3' (typo) should return our
+ default bridge."""
+ default_transport = "obfs4"
+ strings._setDefaultTransport(default_transport)
lines = ['',
- 'transport obfs3']
+ 'transprot obfs3']
reqvest = request.determineBridgeRequestOptions(lines)
self.assertEqual(len(reqvest.transports), 1)
- self.assertEqual(reqvest.transports[0], 'obfs3')
- self.assertEqual(reqvest.isValid(), False)
+ self.assertEqual(reqvest.transports[0], default_transport)
+ self.assertEqual(reqvest.isValid(), True)
def test_determineBridgeRequestOptions_get_ipv6(self):
"""An valid request for 'get ipv6'."""
diff --git a/bridgedb/test/test_email_templates.py b/bridgedb/test/test_email_templates.py
index 1d55dd9..4a5979d 100644
--- a/bridgedb/test/test_email_templates.py
+++ b/bridgedb/test/test_email_templates.py
@@ -36,7 +36,7 @@ class EmailTemplatesTests(unittest.TestCase):
self.offlineFingerprint = '7B78437015E63DF47BB1270ACBD97AA24E8E472E'
def shouldIncludeCommands(self, text):
- self.assertSubstring('COMMANDs', text)
+ self.assertSubstring('commands', text)
def shouldIncludeInstructions(self, text):
self.assertSubstring('Tor Browser', text)
@@ -46,10 +46,10 @@ class EmailTemplatesTests(unittest.TestCase):
self.assertSubstring('Here are your bridges:', text)
def shouldIncludeGreeting(self, text):
- self.assertSubstring('Hey, blackhole!', text)
+ self.assertSubstring('This is an automated email', text)
def shouldIncludeAutomationNotice(self, text):
- self.assertSubstring('automated message', text)
+ self.assertSubstring('automated email', text)
def shouldIncludeKey(self, text):
self.assertSubstring('-----BEGIN PGP PUBLIC KEY BLOCK-----', text)
@@ -59,26 +59,9 @@ class EmailTemplatesTests(unittest.TestCase):
self.shouldIncludeCommands(text)
def test_templates_addGreeting(self):
- text = templates.addGreeting(self.t, self.client.local)
+ text = templates.addGreeting(self.t)
self.shouldIncludeGreeting(text)
- def test_templates_addGreeting_noClient(self):
- text = templates.addGreeting(self.t, None)
- self.assertSubstring('Hello, friend!', text)
-
- def test_templates_addGreeting_withWelcome(self):
- text = templates.addGreeting(self.t, self.client.local, welcome=True)
- self.shouldIncludeGreeting(text)
- self.assertSubstring('Welcome to BridgeDB!', text)
-
- def test_templates_addGreeting_trueClient(self):
- text = templates.addGreeting(self.t, True)
- self.assertSubstring('Hey', text)
-
- def test_templates_addGreeting_23Client(self):
- text = templates.addGreeting(self.t, 23)
- self.assertSubstring('Hey', text)
-
def test_templates_addHowto(self):
text = templates.addHowto(self.t)
self.shouldIncludeInstructions(text)
@@ -97,12 +80,6 @@ class EmailTemplatesTests(unittest.TestCase):
text = templates.buildKeyMessage(self.t, self.client)
self.assertSubstring(self.offlineFingerprint, text)
- def test_templates_buildWelcomeText(self):
- text = templates.buildWelcomeText(self.t, self.client)
- self.shouldIncludeGreeting(text)
- self.assertSubstring('Welcome to BridgeDB!', text)
- self.shouldIncludeCommands(text)
-
def test_templates_buildSpamWarning(self):
text = templates.buildSpamWarning(self.t, self.client)
self.shouldIncludeGreeting(text)
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits