[tor-commits] [bridgedb/develop] Refactor getBridgesForEmail() to use EmailBridgeRequests.

isis at torproject.org isis at torproject.org
Thu Jun 25 07:10:54 UTC 2015


commit 55557c339c18cd3f190521369d5047bbd7ccf369
Author: Isis Lovecruft <isis at torproject.org>
Date:   Wed Apr 1 05:54:53 2015 +0000

    Refactor getBridgesForEmail() to use EmailBridgeRequests.
    
     * RENAME b.D.EmailBasedDistributor.getBridgesForEmail() →
       b.D.EmailBasedDistributor.getBridges().
    
     * CHANGE b.D.EmailBasedDistributor.getBridges() to use
       bridgedb.email.request.EmailBridgeRequest.
---
 lib/bridgedb/Dist.py                |   60 ++++++++++++++++-------------------
 lib/bridgedb/email/autoresponder.py |   16 ++++------
 lib/bridgedb/test/email_helpers.py  |   24 +++++++-------
 lib/bridgedb/test/legacy_Tests.py   |    6 ++--
 4 files changed, 48 insertions(+), 58 deletions(-)

diff --git a/lib/bridgedb/Dist.py b/lib/bridgedb/Dist.py
index 39e70be..26e952e 100644
--- a/lib/bridgedb/Dist.py
+++ b/lib/bridgedb/Dist.py
@@ -473,65 +473,63 @@ class EmailBasedDistributor(Distributor):
         """Assign a bridge to this distributor."""
         self.splitter.insert(bridge)
 
-    def getBridgesForEmail(self, emailaddress, epoch, N=1, parameters=None,
-                           countryCode=None, bridgeFilterRules=None):
+    def getBridges(self, bridgeRequest, epoch, N=1):
         """Return a list of bridges to give to a user.
 
-        :param str emailaddress: The user's email address, as given in a
-            :header:`From:` line.
+        :type bridgeRequest: :class:`~bridgedb.email.request.EmailBridgeRequest`
+        :param bridgeRequest: A :class:`~bridgedb.bridgerequest.BridgeRequestBase`
+            with the :data:`~bridgedb.bridgerequest.BridgeRequestBase.client`
+            attribute set to a string containing the client's full, canonicalized
+            email address.
         :param epoch: The time period when we got this request. This can be
             any string, so long as it changes with every period.
         :param int N: The number of bridges to try to give back.
-        :param parameters: DOCDOC
-        :param countryCode: DOCDOC
-        :param bridgeFilterRules: DOCDOC
         """
-        if not bridgeFilterRules:
-            bridgeFilterRules=[]
-        now = time.time()
-
         # All checks on the email address, such as checks for whitelisting and
         # canonicalization of domain name, are done in
         # :meth:`bridgedb.email.autoresponder.getMailTo` and
         # :meth:`bridgedb.email.autoresponder.SMTPAutoresponder.runChecks`.
-        if not emailaddress:
-            logging.error(("%s distributor can't get bridges for blank email "
-                           "address!") % (self.name, emailaddress))
-            return []
+        if (not bridgeRequest.client) or (bridgeRequest.client == 'default'):
+            raise addr.BadEmail(
+                ("%s distributor can't get bridges for invalid email email "
+                 " address: %s") % (self.name, bridgeRequest.client))
+
+        now = time.time()
 
         with bridgedb.Storage.getDB() as db:
-            wasWarned = db.getWarnedEmail(emailaddress)
-            lastSaw = db.getEmailTime(emailaddress)
+            wasWarned = db.getWarnedEmail(bridgeRequest.client)
+            lastSaw = db.getEmailTime(bridgeRequest.client)
 
             logging.info("Attempting to return for %d bridges for %s..."
-                         % (N, emailaddress))
+                         % (N, bridgeRequest.client))
 
             if lastSaw is not None:
-                if emailaddress in self.whitelist.keys():
+                if bridgeRequest.client in self.whitelist.keys():
                     logging.info(("Whitelisted email address %s was last seen "
                                   "%d seconds ago.")
-                                 % (emailaddress, now - lastSaw))
+                                 % (bridgeRequest.client, now - lastSaw))
                 elif (lastSaw + MAX_EMAIL_RATE) >= now:
                     wait = (lastSaw + MAX_EMAIL_RATE) - now
                     logging.info("Client %s must wait another %d seconds."
-                                 % (emailaddress, wait))
+                                 % (bridgeRequest.client, wait))
                     if wasWarned:
-                        raise IgnoreEmail("Client was warned.", emailaddress)
+                        raise IgnoreEmail("Client was warned.",
+                                          bridgeRequest.client)
                     else:
                         logging.info("Sending duplicate request warning.")
-                        db.setWarnedEmail(emailaddress, True, now)
+                        db.setWarnedEmail(bridgeRequest.client, True, now)
                         db.commit()
                         raise TooSoonEmail("Must wait %d seconds" % wait,
-                                           emailaddress)
+                                           bridgeRequest.client)
 
             # warning period is over
             elif wasWarned:
-                db.setWarnedEmail(emailaddress, False)
+                db.setWarnedEmail(bridgeRequest.client, False)
 
-            pos = self.emailHmac("<%s>%s" % (epoch, emailaddress))
+            pos = self.emailHmac("<%s>%s" % (epoch, bridgeRequest.client))
 
             ring = None
-            ruleset = frozenset(bridgeFilterRules)
+            ruleset = frozenset(bridgeRequest.filters)
             if ruleset in self.splitter.filterRings.keys():
                 logging.debug("Cache hit %s" % ruleset)
                 _, ring = self.splitter.filterRings[ruleset]
@@ -540,19 +538,17 @@ class EmailBasedDistributor(Distributor):
                 logging.debug("Cache miss %s" % ruleset)
 
                 # add new ring
-                key1 = getHMAC(self.splitter.key,
-                                                 "Order-Bridges-In-Ring")
+                key1 = getHMAC(self.splitter.key, "Order-Bridges-In-Ring")
                 ring = bridgedb.Bridges.BridgeRing(key1, self.answerParameters)
-                # debug log: cache miss
                 self.splitter.addRing(ring, ruleset,
-                                      filterBridgesByRules(bridgeFilterRules),
+                                      filterBridgesByRules(ruleset),
                                       populate_from=self.splitter.bridges)
 
             numBridgesToReturn = getNumBridgesPerAnswer(ring,
                                                         max_bridges_per_answer=N)
             result = ring.getBridges(pos, numBridgesToReturn)
 
-            db.setEmailTime(emailaddress, now)
+            db.setEmailTime(bridgeRequest.client, now)
             db.commit()
 
         return result
diff --git a/lib/bridgedb/email/autoresponder.py b/lib/bridgedb/email/autoresponder.py
index 0eeb14a..0ab04fa 100644
--- a/lib/bridgedb/email/autoresponder.py
+++ b/lib/bridgedb/email/autoresponder.py
@@ -87,6 +87,7 @@ def createResponseBody(lines, context, client, lang='en'):
     bridges = None
     try:
         bridgeRequest = request.determineBridgeRequestOptions(lines)
+        bridgeRequest.client = str(client)
 
         # The request was invalid, respond with a help email which explains
         # valid email commands:
@@ -96,12 +97,10 @@ def createResponseBody(lines, context, client, lang='en'):
 
         # Otherwise they must have requested bridges:
         interval = context.schedule.intervalStart(time.time())
-        bridges = context.distributor.getBridgesForEmail(
-            str(client),
+        bridges = context.distributor.getBridges(
+            bridgeRequest,
             interval,
-            context.nBridges,
-            countryCode=None,
-            bridgeFilterRules=bridgeRequest.filters)
+            context.nBridges)
     except EmailRequestedHelp as error:
         logging.info(error)
         return templates.buildWelcomeText(translator, client)
@@ -120,11 +119,8 @@ def createResponseBody(lines, context, client, lang='en'):
         answer = "(no bridges currently available)\r\n"
         if bridges:
             transport = bridgeRequest.justOnePTType()
-            answer = "".join("  %s\r\n" % b.getConfigLine(
-                includeFingerprint=context.includeFingerprints,
-                addressClass=bridgeRequest.addressClass,
-                transport=transport,
-                request=str(client)) for b in bridges)
+            answer = "".join("  %s\r\n" % b.getBridgeLine(
+                bridgeRequest, context.includeFingerprints) for b in bridges)
         return templates.buildAnswerMessage(translator, client, answer)
 
 def generateResponse(fromAddress, client, body, subject=None,
diff --git a/lib/bridgedb/test/email_helpers.py b/lib/bridgedb/test/email_helpers.py
index c80e2ea..28ece91 100644
--- a/lib/bridgedb/test/email_helpers.py
+++ b/lib/bridgedb/test/email_helpers.py
@@ -136,8 +136,7 @@ class DummyEmailDistributor(object):
         self.domainrules = domainrules
         self.answerParameters = answerParameters
 
-    def getBridgesForEmail(self, emailaddress, epoch, N=1, parameters=None,
-                           countryCode=None, bridgeFilterRules=None):
+    def getBridges(self, bridgeRequest, epoch, N=1):
         return [DummyBridge() for _ in xrange(N)]
 
     def cleanDatabase(self):
@@ -160,22 +159,21 @@ class DummyEmailDistributorWithState(DummyEmailDistributor):
         super(DummyEmailDistributorWithState, self).__init__()
         self.alreadySeen = {}
 
-    def getBridgesForEmail(self, emailaddress, epoch, N=1, parameters=None,
-                           countryCode=None, bridgeFilterRules=None):
+    def getBridges(self, bridgeRequest, epoch, N=1):
         # Keep track of the number of times we've seen a client.
-        if not emailaddress in self.alreadySeen.keys():
-            self.alreadySeen[emailaddress] = 0
-        self.alreadySeen[emailaddress] += 1
+        if not bridgeRequest.client in self.alreadySeen.keys():
+            self.alreadySeen[bridgeRequest.client] = 0
+        self.alreadySeen[bridgeRequest.client] += 1
 
-        if self.alreadySeen[emailaddress] <= 1:
+        if self.alreadySeen[bridgeRequest.client] <= 1:
             return [DummyBridge() for _ in xrange(N)]
-        elif self.alreadySeen[emailaddress] == 2:
+        elif self.alreadySeen[bridgeRequest.client] == 2:
             raise TooSoonEmail(
                 "Seen client '%s' %d times"
-                % (emailaddress, self.alreadySeen[emailaddress]),
-                emailaddress)
+                % (bridgeRequest.client, self.alreadySeen[bridgeRequest.client]),
+                bridgeRequest.client)
         else:
             raise IgnoreEmail(
                 "Seen client '%s' %d times"
-                % (emailaddress, self.alreadySeen[emailaddress]),
-                emailaddress)
+                % (bridgeRequest.client, self.alreadySeen[bridgeRequest.client]),
+                bridgeRequest.client)
diff --git a/lib/bridgedb/test/legacy_Tests.py b/lib/bridgedb/test/legacy_Tests.py
index 0d2512c..2e4d56f 100644
--- a/lib/bridgedb/test/legacy_Tests.py
+++ b/lib/bridgedb/test/legacy_Tests.py
@@ -169,11 +169,11 @@ class EmailBridgeDistTests(unittest.TestCase):
                 {'example.com': [], 'dkim.example.com': ['dkim']})
         for _ in xrange(256):
             d.insert(fakeBridge())
-        d.getBridgesForEmail('abc at example.com', 1, 3)
+        d.getBridges('abc at example.com', 1, 3)
         self.assertRaises(bridgedb.Dist.TooSoonEmail,
-                d.getBridgesForEmail, 'abc at example.com', 1, 3)
+                d.getBridges, 'abc at example.com', 1, 3)
         self.assertRaises(bridgedb.Dist.IgnoreEmail,
-                d.getBridgesForEmail, 'abc at example.com', 1, 3)
+                d.getBridges, 'abc at example.com', 1, 3)
 
     def testUnsupportedDomain(self):
         db = self.db





More information about the tor-commits mailing list