1. 04 Jun, 2014 2 commits
  2. 02 Jun, 2014 16 commits
  3. 29 May, 2014 5 commits
    • Isis Lovecruft's avatar
      e34c3f21
    • Isis Lovecruft's avatar
    • Isis Lovecruft's avatar
    • Isis Lovecruft's avatar
      Fix #12086; disallow emails not to our domain. · 5e625804
      Isis Lovecruft authored
      At the SMTP layer, we previously only checked that the email address
      within the SMTP 'RCPT TO:' command (after being stripped of any '+'
      aliases) as well as the email address in the 'To:' header both had a
      username equal to the configured EMAIL_USERNAME. It didn't check that
      these email addresses were the same, nor did it check the domain at all.
      
      This refactors the ``bridgedb.email.server.MailDelivery.validateTo()``
      method to check that the domain name in the SMTP 'RCPT TO:' command is
      either our domain or a subdomain of it.
      
      At the email layer, we now check that the email was sent to a domain
      which is either our domain or a subdomain of it. We also check that the
      username matches our configured username (after '+' aliases have been
      removed).
      
       * FIXES #12086, a bug where BridgeDB would accept emails addressed to
         addresses such as 'givemebridges@serious.ly'.
       * CHANGES MailDelivery.validateTo() to check domain names and usernames
         in the SMTP 'RCPT TO' command that an incoming email was received
         for.
       * RENAME MailMessage.getRecipient() → MailMessage.getMailFrom() in
         bridgedb.email.server module.
       * CHANGES MailMessage.getMailFrom() to check domain names and usernames
         in the 'To:' header of an incoming email.
      5e625804
    • Isis Lovecruft's avatar
      ec15fd95
  4. 28 May, 2014 17 commits
    • Isis Lovecruft's avatar
      Simplify client parameter in b.e.server.createResponseBody(). · 8a4d6c9e
      Isis Lovecruft authored
      We can use the str() method on ``twisted.mail.smtp.Address`` objects to
      recreate the full email address. In other words, these are equivalent:
      
        clientAddr = '@'.join([client.local, client.domain])
      
      and
      
        clientAddr = str(client)
      
      except that the latter looks nicer, so we should use that instead.
      8a4d6c9e
    • Isis Lovecruft's avatar
      Add unittest for MailMessage.getRecipient() which exposes 2.5 bugs. · f1b7d03c
      Isis Lovecruft authored
      Bug #1:
      -------
      BridgeDB's current code will accept an incoming email with a
          'To: givemebridges@serious.ly'
      header. However, BridgeDB's reply will still contain:
          'From: bridges@torproject.org'
      
      Obviously, it *shouldn't* be possible for any email whose SMTP RCPT TO
      domain is 'serious.ly' to actually end up in BridgeDB's mail
      queue. Though, if the outside SMTP layer is sent to
      '[bridges|ponticum].torproject.org' (with MAIL FROM a gmail/yahoo
      address), these messages still end up in BridgeDB's mail queue.
      
      The following netcat session demonstrates that this is possible:
      
        ∃!isisⒶwintermute:(master *$=)~ ∴ torsocks nc bridges.torproject.org 25
        220 ponticum.torproject.org ESMTP Postfix (Debian/GNU)
        HELO ponticum.torproject.org
        250 ponticum.torproject.org
        MAIL FROM: isisgrimalkin@gmail.com
        250 2.1.0 Ok
        RCPT TO: bridges@bridges.torproject.org
        250 2.1.5 Ok
        DATA
        354 End data with <CR><LF>.<CR><LF>
        From: isislovecruft@gmail.com
        To: givemebridgesrightnow@serious.ly
        Subject: mwhahaha
      
        get transport obfs3
        .
        250 2.0.0 Ok: queued as F03972834F
        QUIT
        221 2.0.0 Bye
      
      This request resulted in the following debug logs:
      _______________________________________________________________________________
      15:30:31 DEBUG    L690:server.validateFrom()    ORIGIN: "'<bridgedb@ponticum>'"
      15:30:31 DEBUG    L699:server.validateFrom()    Got canonical domain: 'ponticum'
      15:30:31 DEBUG    L495:server.lineReceived()    > Received: from ponticum (ponticum [127.0.0.1]) for <bridges@bridgedb>; Wed, 21 May 2014 15:30:31 +0000
      15:30:31 DEBUG    L495:server.lineReceived()    > From isisgrimalkin@gmail.com  Wed May 21 15:30:31 2014
      15:30:31 DEBUG    L495:server.lineReceived()    > X-Original-To: bridges@bridges.torproject.org
      15:30:31 DEBUG    L495:server.lineReceived()    > Delivered-To: bridgedb@ponticum.torproject.org
      15:30:31 DEBUG    L495:server.lineReceived()    > Received: from ponticum.torproject.org (kpebetka.net [95.79.25.182])
      15:30:31 DEBUG    L495:server.lineReceived()    >       by ponticum.torproject.org (Postfix) with SMTP id F03972834F
      15:30:31 DEBUG    L495:server.lineReceived()    >       for <bridges@bridges.torproject.org>; Wed, 21 May 2014 15:29:18 +0000 (UTC)
      15:30:31 DEBUG    L495:server.lineReceived()    > From: isislovecruft@gmail.com
      15:30:31 DEBUG    L495:server.lineReceived()    > To: givemebridgesrightnow@serious.ly
      15:30:31 DEBUG    L495:server.lineReceived()    > Subject: mwhahaha
      15:30:31 DEBUG    L495:server.lineReceived()    > X-DKIM-Authentication-Results: dunno
      15:30:31 DEBUG    L495:server.lineReceived()    > Date: Wed, 21 May 2014 15:30:31 -0000
      15:30:31 DEBUG    L495:server.lineReceived()    > Message-Id: <1400686231.135135.6548@ponticum>
      15:30:31 DEBUG    L495:server.lineReceived()    >
      15:30:31 DEBUG    L495:server.lineReceived()    > get transport obfs3
      15:30:31 DEBUG    L495:server.lineReceived()    >
      15:30:31 INFO     L611:server.reply()           Got an email; deciding whether to reply.
      15:30:31 INFO     L646:server.reply()           Client requested email translation: en
      15:30:31 DEBUG     L70:request.determineBridg() Email request was valid.
      15:30:31 DEBUG    L160:request.withPluggableT() Parsing 'transport' line: 'get transport obfs3'
      15:30:31 INFO     L169:request.withPluggableT() Email requested transport type: 'obfs3'
      15:30:31 DEBUG     L81:request.determineBridg() Generating hashring filters for request.
      15:30:31 INFO     L420:Dist.getBridgesForEmai() Attempting to return for 3 bridges for isislovecruft@gmail.com...
      15:30:31 DEBUG    L445:Dist.getBridgesForEmai() Cache hit frozenset([<function filterBridgesByTransport(obfs3,<class 'ipaddr.IPv4Address'>)>])
      15:30:31 DEBUG     L75:Dist.getNumBridgesPerA() Returning 3 bridges from ring of len: 492
      15:30:31 DEBUG   L1034:Bridges.getBridges()     Got duplicate bridge 'edfa2fd66533da52f40424bbe917bd03c8378c2d' in main hashring for position 'eda7f69f7c08bd80861c3afa2921168a007d9ae5'.
      15:30:31 DEBUG   L1034:Bridges.getBridges()     Got duplicate bridge 'ed0b2fd66f398afbf10424bb911790faca9ddb8e' in main hashring for position 'eda7f69f7c08bd80861c3afa2921168a007d9ae5'.
      15:30:31 DEBUG    L183:server.generateRespons() Email contents:
      From: bridges@torproject.org
      To: isislovecruft@gmail.com
      Message-ID: <20140521153031.21456.73227139.10726@ponticum.torproject.org>
      In-Reply-To: <1400686231.135135.6548@ponticum>
      Content-Type: text/plain; charset="utf-8"
      Date: Wed, 21 May 2014 15:30:31 +0000
      Subject: Re: mwhahaha
      
      Hey, isislovecruft!
      
      [This is an automated message; please do not reply.]
      
      Here are your bridges:
      
        obfs3 10.1.1.1:1111 d14133856abbba8a65607baebf692162c567bf41
        obfs3 10.2.2.2:2222 86f45ab5dcef80a4b1abfcc43579e76f1d0b25a4
        obfs3 10.3.3.3:3333 5d55daabd91e041e74f62dcfab1a29c8bb32f0b2
      
      To enter bridges into Tor Browser, follow the instructions on the  Tor
      Browser download page [0] to start Tor Browser.
      
      When the 'Tor Network Settings' dialogue pops up, click 'Configure' and follow
      the wizard until it asks:
      
      > Does your Internet Service Provider (ISP) block or otherwise censor connections
      > to the Tor network?
      
      Select 'Yes' and then click 'Next'. To configure your new bridges, copy and
      paste the bridge lines into the text input box. Finally, click 'Connect', and
      you should be good to go! If you experience trouble, try clicking the 'Help'
      button in the 'Tor Network Settings' wizard for further assistance.
      
      [0]: https://www.torproject.org/projects/torbrowser.html.en#downloads-beta
      
      COMMANDs: (combine COMMANDs to specify multiple options simultaneously)
        get bridges            Request vanilla bridges.
        get transport [TYPE]   Request a Pluggable Transport by TYPE.
        get help               Displays this message.
        get key                Get a copy of BridgeDB's public GnuPG key.
        get ipv6               Request IPv6 bridges.
      
      Currently supported transport TYPEs:
        obfs2
        obfs3
        scramblesuit
      
      --
       <3 BridgeDB
      
      ----------------------------------------------------------------------
      Public Keys: https://bridges.torproject.org/keys
      This email was generated with rainbows, unicorns, and sparkles
      for isislovecruft@gmail.com on Wednesday, 21 May, 2014 at 15:30:31.
      
      15:30:31 INFO     L655:server.reply()           Sending reply to isislovecruft@gmail.com
      _______________________________________________________________________________
      
      Which obviously brings us to the other bug.
      
      Bug #2:
      -------
      BridgeDB will accept an email from an arbitrary gmail/yahoo email
      address at the SMTP layer, and then send the reply to a *different*
      arbitrary gmail/yahoo email address taken from the contents of the email
      headers.
      
      As you can see in the example above, the SMTP command
        'MAIL FROM: isisgrimalkin@gmail.com'
      combined with a 'From: isislovecruft@gmail.com' in the email headers
      within the SMTP DATA segment caused the reply to be sent the reply to
      the later, when it came from the former. The person reading the response
      from BridgeDB also has no way to know who originally emailed BridgeDB to
      cause this email to end up in her inbox.
      
      I'm not exactly certain if this is a bug or a feature. While it could be
      used for sending some junk to an arbitrary gmail/yahoo address, it could
      also be used as a sort of
      
       "Dear BridgeDB, can I have some bridges? Asking for a friend."
      
      mechanism.
      
      Bug #2.5:
      ---------
      Also, "dunno" certainly isn't a valid DKIM signature.
      f1b7d03c
    • Isis Lovecruft's avatar
      Add unittest for MailMessage.getRecipient() w/ a bad email address. · 3fda7f63
      Isis Lovecruft authored
      This should still return our configured EMAIL_SMTP_FROM_ADDR email
      address.
      3fda7f63
    • Isis Lovecruft's avatar
      Add unittest for MailMessage.getRecipient() w/ email address that isn't ours. · 27107de9
      Isis Lovecruft authored
      An email sent to 'notbridgedb@yikezors.net' that somehow ends up in our
      queue should return the EMAIL_SMTP_FROM_ADDRESS that we're configured to
      use.
      27107de9
    • Isis Lovecruft's avatar
      Add 'pragma:' directive to MailMessage.reply() errback function. · 8a71b50e
      Isis Lovecruft authored
      We can't really test it, since it's a nested function. However, we
      shouldn't need to, all it does is log the
      twisted.python.failure.Failure.
      8a71b50e
    • Isis Lovecruft's avatar
      3e34dfdc
    • Isis Lovecruft's avatar
      Fix bug in MailResponse.write() multiline string handling. · 212d6dfe
      Isis Lovecruft authored
      The bridgedb.email.server.MailResponse.write() method wasn't properly
      converting '\n' newlines in multiline strings to SMTP-formatted '\r\n'
      newlines.
      
       * FIXES multiline string newline replacement bug in
         bridgedb.email.server.MailResponse.write() method.
      212d6dfe
    • Isis Lovecruft's avatar
      Simplify MailResponse by removing extra file I/O methods. · cc3b6085
      Isis Lovecruft authored
      The only one we really need is MailResponse.close(), the utility methods
      (i.e. MailResponse.rewind()) handle other important functionality for
      us.
      
       * REMOVE bridgedb.email.server.MailResponse.flush()
       * REMOVE bridgedb.email.server.MailResponse.read()
       * REMOVE bridgedb.email.server.MailResponse.readline()
       * REMOVE bridgedb.email.server.MailResponse.readlines()
       * REMOVE bridgedb.email.server.MailResponse.seek()
       * REMOVE bridgedb.email.server.MailResponse.tell()
       * REMOVE bridgedb.email.server.MailResponse.truncate()
      cc3b6085
    • Isis Lovecruft's avatar
      Simplify MailResponse class by not implementing smtp.IMessage. · cbbbbf8a
      Isis Lovecruft authored
      We aren't using it as an SMTP message delivery class anywhere, so
      there's no need to have the extra methods.
      
       * REMOVE bridgedb.email.server.MailResponse.lineReceived()
       * REMOVE bridgedb.email.server.MailResponse.eomReceived()
       * REMOVE bridgedb.email.server.MailResponse.connectionLost()
       * REMOVE zope.interface implementation declaration of
         twisted.mail.smtp.IMessage by b.e.s.MailResponse.
      cbbbbf8a
    • Isis Lovecruft's avatar
    • Isis Lovecruft's avatar
    • Isis Lovecruft's avatar
      Refactor bridgedb.email.server.MailMessage.getRecipient(). · 1c8c02ea
      Isis Lovecruft authored
       * CHANGE to using only one try/except block for
         `smtp.AddressError`s. We should probably assume that our
         EMAIL_SMTP_FROM_ADDR in the config file is correctly formed, and not
         bother logging the special case if it is not. Instead, just log all
         `smtp.AddressError`s in the same manner.
       * CHANGE variable names to make code clearer.
      1c8c02ea
    • Isis Lovecruft's avatar
    • Isis Lovecruft's avatar
    • Isis Lovecruft's avatar
    • Isis Lovecruft's avatar
    • Isis Lovecruft's avatar