commit 55557c339c18cd3f190521369d5047bbd7ccf369 Author: Isis Lovecruft isis@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@example.com', 1, 3) + d.getBridges('abc@example.com', 1, 3) self.assertRaises(bridgedb.Dist.TooSoonEmail, - d.getBridgesForEmail, 'abc@example.com', 1, 3) + d.getBridges, 'abc@example.com', 1, 3) self.assertRaises(bridgedb.Dist.IgnoreEmail, - d.getBridgesForEmail, 'abc@example.com', 1, 3) + d.getBridges, 'abc@example.com', 1, 3)
def testUnsupportedDomain(self): db = self.db
tor-commits@lists.torproject.org