comparison mercurial/mail.py @ 18886:14a60a0f7122

smtp: add the class to verify the certificate of the SMTP server for SMTPS Original "smtplib.SMTP_SSL" has no route to pass "ca_certs" and "cert_reqs" arguments to underlying SSL socket creation. This causes that "getpeercert()" on SSL socket returns empty dict, so the peer certificate for SMTPS can't be verified. This patch introduces the "SMTPS" class derived from "smtplib.SMTP" to pass "ca_certs" and "cert_reqs" arguments to underlying SSL socket creation. "SMTPS" class is derived directly from "smtplib.SMTP", because amount of "smtplib.SMTP_SSL" definition derived from "smtplib.SMTP" is as same as one needed to override it. This patch defines "SMTPS" class, only when "smtplib.SMTP" class has "_get_socket()" method, because this makes using SSL socket instead of normal socket easy. "smtplib.SMTP" class of Python 2.5.x or earlier doesn't have this method. Omitting SMTPS support for them is reasonable, because "smtplib.SMTP_SSL" is already unavailable for them before this patch. Almost all code of "SMTPS" class is imported from "smtplib.SMTP_SSL" of Python 2.7.3, but it differs from original code in point below: - "ssl.wrap_socket()" is replaced by "sslutil.ssl_wrap_socket()" for compatibility between Python versions
author FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
date Tue, 26 Mar 2013 02:27:43 +0900
parents cf1304fbc184
children 19d489404d79
comparison
equal deleted inserted replaced
18885:cf1304fbc184 18886:14a60a0f7122
54 self.helo_resp = None 54 self.helo_resp = None
55 self.ehlo_resp = None 55 self.ehlo_resp = None
56 self.esmtp_features = {} 56 self.esmtp_features = {}
57 self.does_esmtp = 0 57 self.does_esmtp = 0
58 return (resp, reply) 58 return (resp, reply)
59
60 if util.safehasattr(smtplib.SMTP, '_get_socket'):
61 class SMTPS(smtplib.SMTP):
62 '''Derived class to verify the peer certificate for SMTPS.
63
64 This class allows to pass any keyword arguments to SSL socket creation.
65 '''
66 def __init__(self, sslkwargs, keyfile=None, certfile=None, **kwargs):
67 self.keyfile = keyfile
68 self.certfile = certfile
69 smtplib.SMTP.__init__(self, **kwargs)
70 self.default_port = smtplib.SMTP_SSL_PORT
71 self._sslkwargs = sslkwargs
72
73 def _get_socket(self, host, port, timeout):
74 if self.debuglevel > 0:
75 print >> stderr, 'connect:', (host, port)
76 new_socket = socket.create_connection((host, port), timeout)
77 new_socket = sslutil.ssl_wrap_socket(new_socket,
78 self.keyfile, self.certfile,
79 **self._sslkwargs)
80 self.file = smtplib.SSLFakeFile(new_socket)
81 return new_socket
82 else:
83 def SMTPS(sslkwargs, keyfile=None, certfile=None, **kwargs):
84 raise util.Abort(_('SMTPS requires Python 2.6 or later'))
59 85
60 def _smtp(ui): 86 def _smtp(ui):
61 '''build an smtp connection and return a function to send mail''' 87 '''build an smtp connection and return a function to send mail'''
62 local_hostname = ui.config('smtp', 'local_hostname') 88 local_hostname = ui.config('smtp', 'local_hostname')
63 tls = ui.config('smtp', 'tls', 'none') 89 tls = ui.config('smtp', 'tls', 'none')