def getMailFrom(self): """Find our address in the recipients list of the **incoming** message. :rtype: str :return: Our address from the recipients list. If we can't find it return our default ``EMAIL_FROM_ADDRESS`` from the config file. """ logging.debug("Searching for our email address in 'To:' header...") ours = None try: ourAddress = smtp.Address(self.incoming.context.fromAddr) allRecipients = self.incoming.message.get_all("To") for address in allRecipients: recipient = smtp.Address(address) if not ourAddress.domain in recipient.domain: logging.debug(("Not our domain (%s) or subdomain, skipping" " email address: %s") % (ourAddress.domain, str(recipient))) continue # The recipient's username should at least start with ours, # but it still might be a '+' address. if not recipient.local.startswith(ourAddress.local): logging.debug(("Username doesn't begin with ours, skipping" " email address: %s") % str(recipient)) continue # Only check the username before the first '+': beforePlus = recipient.local.split(b'+', 1)[0] if beforePlus == ourAddress.local: ours = str(recipient) if not ours: raise addr.BadEmail( 'No email address accepted, please see log', allRecipients) except Exception as error: logging.error(("Couldn't find our email address in incoming email " "headers: %r" % error)) # Just return the email address that we're configured to use: ours = self.incoming.context.fromAddr logging.debug("Found our email address: %s." % ours) return ours
def getBridges(self, bridgeRequest, interval, clock=None): """Return a list of bridges to give to a user. .. hint:: All checks on the email address (which should be stored in the ``bridgeRequest.client`` attribute), such as checks for whitelisting and canonicalization of domain name, are done in :meth:`bridgedb.distributors.email.autoresponder.getMailTo` and :meth:`bridgedb.distributors.email.autoresponder.SMTPAutoresponder.runChecks`. :type bridgeRequest: :class:`~bridgedb.distributors.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. :type interval: str :param interval: The time period when we got this request. This can be any string, so long as it changes with every period. :type clock: :api:`twisted.internet.task.Clock` :param clock: If given, use the clock to ask what time it is, rather than :api:`time.time`. This should likely only be used for testing. :rtype: :any:`list` or ``None`` :returns: A list of :class:`~bridgedb.bridges.Bridge` for the ``bridgeRequest.client``, if allowed. Otherwise, returns ``None``. """ if (not bridgeRequest.client) or (bridgeRequest.client == 'default'): raise addr.BadEmail( ("%s distributor can't get bridges for invalid email address: " "%s") % (self.name, bridgeRequest.client), bridgeRequest.client) logging.info("Attempting to get bridges for %s..." % bridgeRequest.client) now = time.time() if clock: now = clock.seconds() with bridgedb.Storage.getDB() as db: wasWarned = db.getWarnedEmail(bridgeRequest.client) lastSaw = db.getEmailTime(bridgeRequest.client) if lastSaw is not None: if bridgeRequest.client in self.whitelist: logging.info( "Whitelisted address %s was last seen %d seconds ago." % (bridgeRequest.client, now - lastSaw)) elif (lastSaw + self.emailRateMax) >= now: wait = (lastSaw + self.emailRateMax) - now logging.info("Client %s must wait another %d seconds." % (bridgeRequest.client, wait)) if wasWarned: raise IgnoreEmail( "Client %s was warned." % bridgeRequest.client, bridgeRequest.client) else: logging.info("Sending duplicate request warning.") db.setWarnedEmail(bridgeRequest.client, True, now) db.commit() raise TooSoonEmail("Must wait %d seconds" % wait, bridgeRequest.client) # warning period is over elif wasWarned: db.setWarnedEmail(bridgeRequest.client, False) pos = self.emailHmac("<%s>%s" % (interval, bridgeRequest.client)) ring = None filtres = frozenset(bridgeRequest.filters) if filtres in self.hashring.filterRings: logging.debug("Cache hit %s" % filtres) _, ring = self.hashring.filterRings[filtres] else: logging.debug("Cache miss %s" % filtres) key = getHMAC(self.key, "Order-Bridges-In-Ring") ring = BridgeRing(key, self.answerParameters) self.hashring.addRing(ring, filtres, byFilters(filtres), populate_from=self.hashring.bridges) returnNum = self.bridgesPerResponse(ring) result = ring.getBridges(pos, returnNum, filterBySubnet=False) db.setEmailTime(bridgeRequest.client, now) db.commit() return result