From 42f43f2eed79e6c0a9569a823d148ad1ea1ad3af Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 11 Nov 2013 13:44:54 -0200 Subject: add a fqdn as the local domain, always --- src/leap/mail/smtp/gateway.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/leap/mail/smtp') diff --git a/src/leap/mail/smtp/gateway.py b/src/leap/mail/smtp/gateway.py index 06405b4..6367c0d 100644 --- a/src/leap/mail/smtp/gateway.py +++ b/src/leap/mail/smtp/gateway.py @@ -71,6 +71,8 @@ generator.Generator = RFC3156CompliantGenerator # Helper utilities # +LOCAL_FQDN = "bitmask.local" + def validate_address(address): """ Validate C{address} as defined in RFC 2822. @@ -96,10 +98,18 @@ def validate_address(address): # SMTPFactory # +class SMTPHeloLocalhost(smtp.SMTP): + + def __init__(self, *args): + smtp.SMTP.__init__(self, *args) + self.host = LOCAL_FQDN + + class SMTPFactory(ServerFactory): """ Factory for an SMTP server with encrypted gatewaying capabilities. """ + domain = LOCAL_FQDN def __init__(self, userid, keymanager, host, port, cert, key, encrypted_only): @@ -152,7 +162,7 @@ class SMTPFactory(ServerFactory): @return: The protocol. @rtype: SMTPDelivery """ - smtpProtocol = smtp.SMTP(SMTPDelivery( + smtpProtocol = SMTPHeloLocalhost(SMTPDelivery( self._userid, self._km, self._host, self._port, self._cert, self._key, self._encrypted_only)) smtpProtocol.factory = self @@ -451,8 +461,10 @@ class EncryptedMessage(object): self._user.dest.addrstr, StringIO(msg), d, + heloFallback=True, requireAuthentication=False, requireTransportSecurity=True) + factory.domain = LOCAL_FQDN signal(proto.SMTP_SEND_MESSAGE_START, self._user.dest.addrstr) reactor.connectSSL( self._host, self._port, factory, -- cgit v1.2.3 From 80f0e428065f84292f20954845500028a77a96e0 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 11 Nov 2013 13:45:14 -0200 Subject: refactor callbacks so we properly catch remote errors --- src/leap/mail/smtp/gateway.py | 49 +++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 13 deletions(-) (limited to 'src/leap/mail/smtp') diff --git a/src/leap/mail/smtp/gateway.py b/src/leap/mail/smtp/gateway.py index 6367c0d..7e9e420 100644 --- a/src/leap/mail/smtp/gateway.py +++ b/src/leap/mail/smtp/gateway.py @@ -14,7 +14,6 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . - """ LEAP SMTP encrypted gateway. @@ -32,7 +31,6 @@ The following classes comprise the SMTP gateway service: """ - import re from StringIO import StringIO from email.Header import Header @@ -46,6 +44,7 @@ from twisted.mail import smtp from twisted.internet.protocol import ServerFactory from twisted.internet import reactor, ssl from twisted.internet import defer +from twisted.internet.threads import deferToThread from twisted.python import log from leap.common.check import leap_assert, leap_assert_type @@ -415,6 +414,15 @@ class EncryptedMessage(object): # unexpected loss of connection; don't save self.lines = [] + def sendQueued(self, r): + """ + Callback for the queued message. + + @param r: The result from the last previous callback in the chain. + @type r: anything + """ + log.msg(r) + def sendSuccess(self, r): """ Callback for a successful send. @@ -425,33 +433,51 @@ class EncryptedMessage(object): log.msg(r) signal(proto.SMTP_SEND_MESSAGE_SUCCESS, self._user.dest.addrstr) - def sendError(self, e): + def sendError(self, failure): """ Callback for an unsuccessfull send. :param e: The result from the last errback. :type e: anything """ - log.msg(e) - log.err() signal(proto.SMTP_SEND_MESSAGE_ERROR, self._user.dest.addrstr) + err = failure.value + log.err(err) + raise err def sendMessage(self): """ - Send the message. - - This method will prepare the message (headers and possibly encrypted - body) and send it using the ESMTPSenderFactory. - + Sends the message. @return: A deferred with callbacks for error and success of this message send. @rtype: twisted.internet.defer.Deferred """ + # FIXME this should not be blocking the main ui, since it returns + # a deferred and it has its own cb set. ???! + d = deferToThread(self._sendMessage) + d.addCallbacks(self._route_msg, self.sendError) + d.addCallbacks(self.sendQueued, self.sendError) + return d + + def _sendMessage(self): + """ + Send the message. + + This method will prepare the message (headers and possibly encrypted + body) + """ msg = self._msg.as_string(False) + return msg + def _route_msg(self, msg): + """ + Sends the msg using the ESMTPSenderFactory. + """ log.msg("Connecting to SMTP server %s:%s" % (self._host, self._port)) + # we construct a defer to pass to the ESMTPSenderFactory d = defer.Deferred() + d.addCallbacks(self.sendSuccess, self.sendError) # we don't pass an ssl context factory to the ESMTPSenderFactory # because ssl will be handled by reactor.connectSSL() below. factory = smtp.ESMTPSenderFactory( @@ -469,9 +495,6 @@ class EncryptedMessage(object): reactor.connectSSL( self._host, self._port, factory, contextFactory=SSLContextFactory(self._cert, self._key)) - d.addCallback(self.sendSuccess) - d.addErrback(self.sendError) - return d # # encryption methods -- cgit v1.2.3 From acd5c93f916be7c7509d49f3fa24f4ba0d1d52f7 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 11 Nov 2013 18:01:13 -0200 Subject: use deferToThread in the sendMail. Closes: #3937 --- src/leap/mail/smtp/gateway.py | 80 +++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 34 deletions(-) (limited to 'src/leap/mail/smtp') diff --git a/src/leap/mail/smtp/gateway.py b/src/leap/mail/smtp/gateway.py index 7e9e420..f6366af 100644 --- a/src/leap/mail/smtp/gateway.py +++ b/src/leap/mail/smtp/gateway.py @@ -72,6 +72,7 @@ generator.Generator = RFC3156CompliantGenerator LOCAL_FQDN = "bitmask.local" + def validate_address(address): """ Validate C{address} as defined in RFC 2822. @@ -98,6 +99,13 @@ def validate_address(address): # class SMTPHeloLocalhost(smtp.SMTP): + """ + An SMTP class that ensures a proper FQDN + for localhost. + + This avoids a problem in which unproperly configured providers + would complain about the helo not being a fqdn. + """ def __init__(self, *args): smtp.SMTP.__init__(self, *args) @@ -388,21 +396,14 @@ class EncryptedMessage(object): Handle end of message. This method will encrypt and send the message. + + :returns: a deferred """ log.msg("Message data complete.") self.lines.append('') # add a trailing newline - try: - self._maybe_encrypt_and_sign() - return self.sendMessage() - except KeyNotFound: - return None - - def parseMessage(self): - """ - Separate message headers from body. - """ - parser = Parser() - return parser.parsestr('\r\n'.join(self.lines)) + d = deferToThread(self._maybe_encrypt_and_sign) + d.addCallbacks(self.sendMessage, self.skipNoKeyErrBack) + return d def connectionLost(self): """ @@ -414,12 +415,34 @@ class EncryptedMessage(object): # unexpected loss of connection; don't save self.lines = [] + # ends IMessage implementation + + def skipNoKeyErrBack(self, failure): + """ + Errback that ignores a KeyNotFound + + :param failure: the failure + :type Failure: Failure + """ + err = failure.value + if failure.check(KeyNotFound): + pass + else: + raise err + + def parseMessage(self): + """ + Separate message headers from body. + """ + parser = Parser() + return parser.parsestr('\r\n'.join(self.lines)) + def sendQueued(self, r): """ Callback for the queued message. - @param r: The result from the last previous callback in the chain. - @type r: anything + :param r: The result from the last previous callback in the chain. + :type r: anything """ log.msg(r) @@ -445,35 +468,24 @@ class EncryptedMessage(object): log.err(err) raise err - def sendMessage(self): + def sendMessage(self, *args): """ Sends the message. - @return: A deferred with callbacks for error and success of this - message send. - @rtype: twisted.internet.defer.Deferred - """ - # FIXME this should not be blocking the main ui, since it returns - # a deferred and it has its own cb set. ???! - d = deferToThread(self._sendMessage) - d.addCallbacks(self._route_msg, self.sendError) - d.addCallbacks(self.sendQueued, self.sendError) - return d - def _sendMessage(self): + :return: A deferred with callbacks for error and success of this + #message send. + :rtype: twisted.internet.defer.Deferred """ - Send the message. - - This method will prepare the message (headers and possibly encrypted - body) - """ - msg = self._msg.as_string(False) - return msg + d = deferToThread(self._route_msg) + d.addCallbacks(self.sendQueued, self.sendError) + return - def _route_msg(self, msg): + def _route_msg(self): """ Sends the msg using the ESMTPSenderFactory. """ log.msg("Connecting to SMTP server %s:%s" % (self._host, self._port)) + msg = self._msg.as_string(False) # we construct a defer to pass to the ESMTPSenderFactory d = defer.Deferred() -- cgit v1.2.3