Beispiel #1
0
 def test_determineBridgeRequestOptions_get_ipv6(self):
     """An valid request for 'get ipv6'."""
     lines = ['',
              'get ipv6']
     reqvest = request.determineBridgeRequestOptions(lines)
     self.assertIs(reqvest.addressClass, ipaddr.IPv6Address)
     self.assertEqual(reqvest.isValid(), True)
Beispiel #2
0
 def test_determineBridgeRequestOptions_get_transport(self):
     """An invalid request for 'transport obfs3' (missing the 'get')."""
     lines = ['',
              'transport obfs3']
     reqvest = request.determineBridgeRequestOptions(lines)
     self.assertEqual(len(reqvest.transports), 1)
     self.assertEqual(reqvest.transports[0], 'obfs3')
     self.assertEqual(reqvest.isValid(), False)
Beispiel #3
0
 def test_determineBridgeRequestOptions_multiline_invalid(self):
     """Requests without a 'get' anywhere should be considered invalid."""
     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.assertFalse(reqvest.wantsKey())
     # Though they did request IPv6, technically.
     self.assertIs(reqvest.addressClass, ipaddr.IPv6Address)
     # And they did request a transport, technically.
     self.assertEqual(len(reqvest.transports), 1)
     self.assertEqual(reqvest.transports[0], 'obfs3')
Beispiel #4
0
 def test_determineBridgeRequestOptions_multiline_valid(self):
     """Though requests with a 'get' are considered valid."""
     lines = ['',
              'get transport obfs3',
              'vanilla bridges',
              'transport scramblesuit unblocked ca']
     reqvest = request.determineBridgeRequestOptions(lines)
     # It's valid because it included a 'get'.
     self.assertEqual(reqvest.isValid(), True)
     self.assertFalse(reqvest.wantsKey())
     # Though they didn't request IPv6, so it should default to IPv4.
     self.assertIs(reqvest.addressClass, ipaddr.IPv4Address)
     # And they requested two transports.
     self.assertEqual(len(reqvest.transports), 2)
     self.assertEqual(reqvest.transports[0], 'obfs3')
     self.assertEqual(reqvest.transports[1], 'scramblesuit')
     # And they wanted this stuff to not be blocked in Canada.
     self.assertEqual(len(reqvest.notBlockedIn), 1)
     self.assertEqual(reqvest.notBlockedIn[0], 'ca')
Beispiel #5
0
 def test_determineBridgeRequestOptions_multiline_valid_OMG_CAPSLOCK(self):
     """Though requests with a 'get' are considered valid, even if they
     appear to not know the difference between Capslock and Shift.
     """
     lines = ['',
              'get TRANSPORT obfs3',
              'vanilla bridges',
              'TRANSPORT SCRAMBLESUIT UNBLOCKED CA']
     reqvest = request.determineBridgeRequestOptions(lines)
     # It's valid because it included a 'get'.
     self.assertEqual(reqvest.isValid(), True)
     self.assertFalse(reqvest.wantsKey())
     # Though they didn't request IPv6, so it should default to IPv4.
     self.assertIs(reqvest.addressClass, ipaddr.IPv4Address)
     # And they requested two transports.
     self.assertEqual(len(reqvest.transports), 2)
     self.assertEqual(reqvest.transports[0], 'obfs3')
     self.assertEqual(reqvest.transports[1], 'scramblesuit')
     # And they wanted this stuff to not be blocked in Canada.
     self.assertEqual(len(reqvest.notBlockedIn), 1)
     self.assertEqual(reqvest.notBlockedIn[0], 'ca')
Beispiel #6
0
def createResponseBody(lines, context, clientAddress, lang='en'):
    """Parse the **lines** from an incoming email request and determine how to
    respond.

    :param list lines: The list of lines from the original request sent by the
        client.
    :type context: class:`MailContext`
    :param context: The context which contains settings for the email server.
    :type clientAddress: :api:`twisted.mail.smtp.Address`
    :param clientAddress: The client's email address which should be in the
        :header:`To:` header of the response email.
    :param str lang: The 2-5 character locale code to use for translating the
        email. This is obtained from a client sending a email to a valid plus
        address which includes the translation desired, i.e. by sending an
        email to ``[email protected]``, the client should receive a
        response in Farsi.
    :rtype: None or str
    :returns: None if we shouldn't respond to the client (i.e., if they have
        already received a rate-limiting warning email). Otherwise, returns a
        string containing the (optionally translated) body for the email
        response which we should send out.
    """
    clientAddr = '@'.join([clientAddress.local, clientAddress.domain])
    t = translations.installTranslations(lang)

    bridges = None
    try:
        bridgeRequest = request.determineBridgeRequestOptions(lines)

        # The request was invalid, respond with a help email which explains
        # valid email commands:
        if not bridgeRequest.isValid():
            raise EmailRequestedHelp("Email request from %r was invalid."
                                     % clientAddr)

        # Otherwise they must have requested bridges:
        interval = context.schedule.getInterval(time.time())
        bridges = context.distributor.getBridgesForEmail(
            clientAddr,
            interval,
            context.nBridges,
            countryCode=None,
            bridgeFilterRules=bridgeRequest.filters)
    except EmailRequestedHelp as error:
        logging.info(error)
        return templates.buildWelcomeText(t, clientAddress)
    except EmailRequestedKey as error:
        logging.info(error)
        return templates.buildKeyMessage(t, clientAddress)
    except TooSoonEmail as error:
        logging.info("Got a mail too frequently: %s." % error)
        return templates.buildSpamWarning(t, clientAddress)
    except (IgnoreEmail, BadEmail) as error:
        logging.info(error)
        # Don't generate a response if their email address is unparsable or
        # invalid, or if we've already warned them about rate-limiting:
        return None
    else:
        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=clientAddr) for b in bridges)
        return templates.buildAnswerMessage(t, clientAddress, answer)