Example #1
0
    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
Example #2
0
    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