Use the STARTTLS command to upgrade SMTP connections where possible.
authorMatt Molyneaux <moggers87+git@moggers87.co.uk>
Mon, 24 Mar 2014 15:00:19 +0000 (15:00 +0000)
committerChristopher Allan Webber <cwebber@dustycloud.org>
Sat, 2 Aug 2014 21:23:22 +0000 (16:23 -0500)
Adds the option `email_smtp_force_tls` which will cause `send_email` to error
if it is unable to use the `STARTTLS` command (e.g. where the user knows the
SMTPd supports `STARTTLS` and wishes to protect themselves against a downgrade
attack)

Setting both `email_smtp_user_ssl` and `email_smtp_force_tls` may result in
undefined behaviour if the SMTPd has not been correctly configured.

TODO: Unit tests?
TODO: Documentation?

mediagoblin/config_spec.ini
mediagoblin/tools/mail.py

index c35b709da7b39af5bf9492e325fffb402b23c5ea..72993ed097889f9f74713231d8526cefea3ffedb 100644 (file)
@@ -24,6 +24,7 @@ direct_remote_path = string(default="/mgoblin_static/")
 # set to false to enable sending notices
 email_debug_mode = boolean(default=True)
 email_smtp_use_ssl = boolean(default=False)
+email_smtp_force_tls = boolean(default=False)
 email_sender_address = string(default="notice@mediagoblin.example.org")
 email_smtp_host = string(default='')
 email_smtp_port = integer(default=0)
index 0fabc5a9c3aa1f77a7c58b61fc228a0320209431..889a4420076b7bdf97460808c6c699b3847e0d08 100644 (file)
@@ -14,7 +14,9 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+import six
 import smtplib
+import sys
 from email.MIMEText import MIMEText
 from mediagoblin import mg_globals, messages
 from mediagoblin.tools import common
@@ -64,6 +66,8 @@ class FakeMhost(object):
              'to': to_addrs,
              'message': message})
 
+    def starttls(self):
+        raise smtplib.SMTPException("No STARTTLS here")
 
 def _clear_test_inboxes():
     global EMAIL_TEST_INBOX
@@ -103,6 +107,13 @@ def send_email(from_addr, to_addrs, subject, message_body):
         if not mg_globals.app_config['email_smtp_host']:  # e.g. host = ''
             mhost.connect()  # We SMTP.connect explicitly
 
+        try:
+            mhost.starttls()
+        except smtplib.SMTPException:
+            # Only raise an exception if we're forced to
+            if mg_globals.app_config['email_smtp_force_tls']:
+                six.reraise(*sys.exc_info())
+
     if ((not common.TESTS_ENABLED)
         and (mg_globals.app_config['email_smtp_user']
              or mg_globals.app_config['email_smtp_pass'])):