bridgedb.email
Servers for BridgeDB’s email bridge distributor.
Functionality for autoresponding to incoming emails.
bridgedb.email.autoresponder
| |_ createResponseBody - Parse lines from an incoming email and determine
| | how to respond.
| |_ generateResponse - Create an email response.
|
|_ EmailResponse - Holds information for generating a response to a request.
|_ SMTPAutoresponder - An SMTP autoresponder for incoming mail.
createResponseBody
(lines, context, client, lang=u'en')[source]¶Parse the lines from an incoming email request and determine how to respond.
Parameters: |
|
---|---|
Return type: | |
Returns: |
|
generateResponse
(fromAddress, client, body, subject=None, messageID=None, gpgSignFunc=None)[source]¶Create an EmailResponse
, which acts like an
io.StringIO
instance, by creating and writing all headers and the
email body into the file-like EmailResponse.mailfile
.
Parameters: |
|
---|---|
Returns: | An |
EmailResponse
(gpgSignFunc=None)[source]¶Bases: object
Holds information for generating a response email for a request.
Todo
At some point, we may want to change this class to optionally handle creating Multipart MIME encoding messages, so that we can include attachments. (This would be useful for attaching our GnuPG keyfile, for example, rather than simply pasting it into the body of the email.)
Variables: |
|
---|
Create a response to an email we have recieved.
This class deals with correctly formatting text for the response email
headers and the response body into an instance of mailfile
.
Parameters: | gpgSignFunc (callable) – If given, this should be a callable function for
signing messages. See bridgedb.crypto.initializeGnuPG() for
obtaining a pre-configured gpgSignFunc. |
---|
mailfile
¶alias of BytesIO
read
(size=None)[source]¶Read, at most, size bytes from our mailfile
.
Note
This method is required by Twisted’s SMTP system.
Parameters: | size (int) – The number of bytes to read. Defaults to None ,
which reads until EOF. |
---|---|
Return type: | str |
Returns: | The bytes read from the mailfile . |
readContents
()[source]¶Read the all the contents written thus far to the mailfile
,
and then seek()
to return to the original pointer position we
were at before this method was called.
Return type: | str |
---|---|
Returns: | The entire contents of the mailfile . |
write
(line)[source]¶Write the line to the mailfile
.
Any line written to me will have delimiter
appended to it
beforehand.
Parameters: | line (str) – Something to append into the mailfile . |
---|
writelines
(lines)[source]¶Calls write()
for each line in lines.
Line endings of '\r\n'
will be replaced with delimiter
(i.e. '\n'
). See twisted.mail.smtp.SMTPClient.getMailData
for the reason.
Parameters: | lines (basestring or list ) – The lines to write to the mailfile . |
---|
writeHeaders
(fromAddress, toAddress, subject=None, inReplyTo=None, includeMessageID=True, contentType=u'text/plain; charset="utf-8"', **kwargs)[source]¶Write all headers into the response email.
Parameters: |
|
---|---|
Kwargs: | If given, the key will become the name of the header, and the value will become the contents of that header. |
SMTPAutoresponder
[source]¶Bases: twisted.mail.smtp.SMTPClient
An twisted.mail.smtp.SMTPClient for responding to incoming mail.
The main worker in this class is the reply()
method, which functions
to dissect an incoming email from an incoming SMTPMessage
and
create a EmailResponse
email message in reply to it, and then,
finally, send it out.
Variables: |
|
---|
Handle responding (or not) to an incoming email.
debug
= True¶identity
= 'wintermute'¶getMailData
()[source]¶Gather all the data for building the response to the client.
This method must return a file-like object containing the data of the
message to be sent. Lines in the file should be delimited by \n
.
Return type: | None or EmailResponse |
---|---|
Returns: | An EmailResponse , if we have a response to send in reply
to the incoming email, otherwise, returns None . |
getMailTo
()[source]¶Attempt to get the client’s email address from an incoming email.
Return type: | list |
---|---|
Returns: | A list containing the client’s
normalized email
twisted.mail.smtp.Address, if it originated from
a domain that we accept and the address was well-formed. Otherwise,
returns None . Even though we’re likely to respond to only one
client at a time, the return value of this method must be a list
in order to hook into the rest of
twisted.mail.smtp.SMTPClient correctly. |
getMailFrom
()[source]¶Find our address in the recipients list of the incoming message.
Return type: | str |
---|---|
Returns: | Our address from the recipients list. If we can’t find it
return our default EMAIL_FROM_ADDRESS from the config file. |
sentMail
(success)[source]¶Callback for a twisted.mail.smtp.SMTPSenderFactory, called when an attempt to send an email is completed.
If some addresses were accepted, code and resp are the response to the DATA command. If no addresses were accepted, code is -1 and resp is an informative message.
Parameters: |
|
---|
sendError
(fail)[source]¶Errback for a twisted.mail.smtp.SMTPSenderFactory.
Parameters: | fail (twisted.python.failure.Failure or twisted.mail.smtp.SMTPClientError) – An exception which occurred during the transaction to send the outgoing email. |
---|
reply
()[source]¶Reply to an incoming email. Maybe.
If nothing is returned from either createResponseBody()
or
generateResponse()
, then the incoming email will not be
responded to at all. This can happen for several reasons, for example:
if the DKIM signature was invalid or missing, or if the incoming email
came from an unacceptable domain, or if there have been too many
emails from this client in the allotted time period.
Return type: | twisted.internet.defer.Deferred |
---|---|
Returns: | A Deferred which will callback when the response has
been successfully sent, or errback if an error occurred while
sending the email. |
runChecks
(client)[source]¶Run checks on the incoming message, and only reply if they pass.
2. If it’s not whitelisted, check that the domain names, taken from
the SMTP MAIL FROM:
command and the email 'From:'
header, can
be canonicalized
.
4. If the incoming message is from a domain which supports DKIM
signing, then run bridgedb.email.dkim.checkDKIM()
as well.
Note
Calling this method sets the
incoming.canonicalFromEmail
and
incoming.canonicalDomainRules
attributes of the
incoming
message.
Parameters: | client (twisted.mail.smtp.Address) – The client’s email address, extracted from the
'From:' header from the incoming email. |
---|---|
Return type: | bool |
Returns: | False if the checks didn’t pass, True otherwise. |
send
(response, retries=0, timeout=30, reaktor=<twisted.internet.epollreactor.EPollReactor object>)[source]¶Send our response in reply to incoming
.
Parameters: |
|
---|---|
Return type: | |
Returns: | Our |
A Distributor
which hands out bridges
to clients via an email interface.
MAX_EMAIL_RATE
= 10800¶The minimum amount of time (in seconds) which must pass before a client who has previously been given an email response must wait before being eligible to receive another response.
IgnoreEmail
(msg, email)[source]¶Bases: bridgedb.parse.addr.BadEmail
Raised when we get requests from this address after rate warning.
TooSoonEmail
(msg, email)[source]¶Bases: bridgedb.parse.addr.BadEmail
Raised when we got a request from this address too recently.
EmailRequestedHelp
[source]¶Bases: exceptions.Exception
Raised when a client has emailed requesting help.
EmailRequestedKey
[source]¶Bases: exceptions.Exception
Raised when an incoming email requested a copy of our GnuPG keys.
EmailDistributor
(key, domainmap, domainrules, answerParameters=None, whitelist=None)[source]¶Bases: bridgedb.distribute.Distributor
Object that hands out bridges based on the email address of an incoming request and the current time period.
Variables: | hashring – A hashring to hold all the bridges we hand out. |
---|
Create a bridge distributor which uses email.
Parameters: |
|
---|
emailRateMax
= 10800¶The minimum amount of time (in seconds) which must pass before a client who has previously been given an email response must wait before being eligible to receive another response.
getBridges
(bridgeRequest, interval, clock=None)[source]¶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
bridgedb.email.autoresponder.getMailTo()
and
bridgedb.email.autoresponder.SMTPAutoresponder.runChecks()
.
Parameters: |
|
---|---|
Return type: |
|
Returns: | A list of |
Functions for checking DKIM verification results in email headers.
bridgedb.email.dkim
|_ checkDKIM - Check the DKIM verification results header.
checkDKIM
(message, rules)[source]¶Check the DKIM verification results header.
This check is only run if the incoming email, message, originated from
a domain for which we’re configured (in the EMAIL_DOMAIN_RULES
dictionary in the config file) to check DKIM verification results for.
Returns False
if:
Otherwise, returns True
.
Parameters: |
|
---|---|
Return type: | |
Returns: |
|
Classes for parsing and storing information about requests for bridges which are sent to the email distributor.
bridgedb.email.request
| |_ determineBridgeRequestOptions - Figure out which filters to apply, or
| offer help.
|_ EmailBridgeRequest - A request for bridges which was received through
the email distributor.
TRANSPORT_REGEXP
= u'.*transport ([a-z][_a-z0-9]*)'¶A regular expression for matching the Pluggable Transport method TYPE in emailed requests for Pluggable Transports.
UNBLOCKED_REGEXP
= u'.*unblocked ([a-z]{2,4})'¶A regular expression that matches country codes in requests for unblocked bridges.
determineBridgeRequestOptions
(lines)[source]¶Figure out which filters
to apply, or offer help.
Note
If any 'transport TYPE'
was requested, or bridges not
blocked in a specific CC ('unblocked CC'
), then the TYPE
and/or CC
will always be stored as a lowercase string.
Parameters: | lines (list) – A list of lines from an email, including the headers. |
---|---|
Raises: |
|
Return type: | |
Returns: | A |
EmailBridgeRequest
[source]¶Bases: bridgedb.bridgerequest.BridgeRequestBase
We received a request for bridges through the email distributor.
Process a new bridge request received through the
EmailDistributor
.
wantsKey
(wantsKey=None)[source]¶Get or set whether this bridge request wanted our GnuPG key.
If called without parameters, this method will return the current state, otherwise (if called with the wantsKey parameter set), it will set the current state for whether or not this request wanted our key.
Parameters: | wantsKey (bool) – If given, set the validity state of this request. Otherwise, get the current state. |
---|
withoutBlockInCountry
(line)[source]¶This request was for bridges not blocked in country.
Add any country code found in the line to the list of
notBlockedIn
. Currently, a request for a transport is recognized
if the email line contains the 'unblocked'
command.
Parameters: | country (str) – The line from the email wherein the client requested some type of Pluggable Transport. |
---|
withPluggableTransportType
(line)[source]¶This request included a specific Pluggable Transport identifier.
Add any Pluggable Transport method TYPE found in the line to the
list of transports
. Currently, a request for a transport is
recognized if the email line contains the 'transport'
command.
Parameters: | line (str) – The line from the email wherein the client requested some type of Pluggable Transport. |
---|
Servers which interface with clients and distribute bridges over SMTP.
bridgedb.email.server
| |_ addServer - Set up a SMTP server which listens on the configured
| EMAIL_PORT for incoming connections, and responds as
| necessary to requests for bridges.
|
|_ MailServerContext - Helper object that holds information used by the
| email subsystem.
|_ SMTPMessage - Plugs into Twisted Mail and receives an incoming message.
|_ SMTPIncomingDelivery - Plugs into SMTPIncomingServerFactory and handles
| SMTP commands for incoming connections.
|_ SMTPIncomingDeliveryFactory - Factory for SMTPIncomingDeliverys.
|_ SMTPIncomingServerFactory - Plugs into twisted.mail.smtp.SMTPFactory;
creates a new SMTPMessageDelivery, which
handles response email automation, whenever
we get a incoming connection on the SMTP port.
MailServerContext
(config, distributor, schedule)[source]¶Bases: object
Helper object that holds information used by email subsystem.
Variables: |
|
---|
Create a context for storing configs for email bridge distribution.
Parameters: |
|
---|
buildCanonicalDomainMap
()[source]¶Build a map for all email provider domains from which we will accept emails to their canonical domain name.
Note
Be sure that MailServerContext.domainRules
and
MailServerContext.domainMap
are set appropriately before calling
this method.
This method is automatically called during initialisation, and the
resulting domain map is stored as MailServerContext.canon
.
Return type: | dict |
---|---|
Returns: | A dictionary which maps all domains and subdomains which we accept emails from to their second-level, canonical domain names. |
SMTPMessage
(context, canonicalFromSMTP=None)[source]¶Bases: object
Plugs into the Twisted Mail and receives an incoming message.
Variables: |
|
---|
Create a new SMTPMessage.
These are created automatically via
SMTPIncomingDelivery
.
Parameters: |
|
---|
getIncomingMessage
()[source]¶Create and parse an RFC 2822 message object for all lines
received thus far.
Return type: | twisted.mail.smtp.rfc822.Message |
---|---|
Returns: | A Message comprised of all lines received thus far. |
SMTPIncomingDelivery
(delivery=None, deliveryFactory=None)[source]¶Bases: twisted.mail.smtp.SMTP
Plugs into SMTPIncomingServerFactory
and handles SMTP commands
for incoming connections.
Variables: |
|
---|
context
= None¶deferred
= <Deferred>¶fromCanonicalSMTP
= None¶setContext
(context)[source]¶Set our context
to a new MailServerContext
.
receivedHeader
(helo, origin, recipients)[source]¶Create the Received:
header for an incoming email.
Parameters: |
|
---|
validateFrom
(helo, origin)[source]¶Validate the MAIL FROM:
address on the incoming SMTP connection.
This is done at the SMTP layer. Meaning that if a Postfix or other
email server is proxying emails from the outside world to BridgeDB,
the twisted.email.smtp.Address.domain will be
set to the local hostname. Therefore, if the SMTP MAIL FROM:
domain name is our own hostname (as returned from
socket.gethostname()
) or our own FQDN, allow the connection.
Otherwise, if the MAIL FROM:
domain has a canonical domain in our
mapping (taken from our context.canon
, which is taken in turn
from the EMAIL_DOMAIN_MAP
), then our fromCanonicalSMTP
is
set to that domain.
Parameters: |
|
---|---|
Raises: | twisted.mail.smtp.SMTPBadSender if the
|
Return type: | |
Returns: | The |
validateTo
(user)[source]¶Validate the SMTP RCPT TO:
address for the incoming connection.
The local username and domain name to which this SMTP message is
addressed, after being stripped of any '+'
aliases, must be
identical to those in the email address set our
EMAIL_SMTP_FROM_ADDR
configuration file option.
Parameters: | user (twisted.mail.smtp.User) – Information about the user this SMTP message was addressed to. |
---|---|
Raises: | A twisted.mail.smtp.SMTPBadRcpt if any of the above conditions weren’t met. |
Return type: | callable |
Returns: | A parameterless function which returns an instance of
SMTPMessage . |
SMTPIncomingDeliveryFactory
[source]¶Bases: object
Factory for SMTPIncomingDelivery
s.
This class is used to distinguish between different messages delivered over the same connection. This can be used to optimize delivery of a single message to multiple recipients, something which cannot be done by twisted.mail.smtp.IMessageDelivery implementors due to their lack of information.
Variables: |
|
---|
context
= None¶delivery
¶alias of SMTPIncomingDelivery
getMessageDelivery
()[source]¶Get a new SMTPIncomingDelivery
instance.
SMTPIncomingServerFactory
(**kwargs)[source]¶Bases: twisted.mail.smtp.SMTPFactory
Plugs into twisted.mail.smtp.SMTPFactory; creates a new
SMTPIncomingDeliveryFactory
, which handles response email
automation whenever we get a incoming connection on the SMTP port.
Warning
My context
isn’t an OpenSSL context, as is used for the
twisted.mail.smtp.ESMTPSender.
Variables: |
|
---|
context
= None¶deliveryFactory
¶alias of SMTPIncomingDeliveryFactory
setContext
(context)[source]¶Set context
and deliveryFactory
.context.
addServer
(config, distributor)[source]¶Set up a SMTP server which listens on the configured EMAIL_PORT
for
incoming connections, and responds as necessary to requests for bridges.
Parameters: |
|
---|
Templates for formatting emails sent out by the email distributor.
addCommands
(template)[source]¶Add some text telling a client about supported email command, as well as which Pluggable Transports are currently available.
addHowto
(template)[source]¶Add help text on how to add bridges to Tor Browser.
Parameters: | template (gettext.NullTranslation or gettext.GNUTranslation ) – A gettext translations instance, optionally with fallback
languages set. |
---|
Add a footer:
--
<3 BridgeDB
________________________________________________________________________
Public Keys: https://bridges.torproject.org/keys
This email was generated with rainbows, unicorns, and sparkles
for alice@example.com on Friday, 09 May, 2014 at 18:59:39.
Parameters: |
|
---|