poobrains/poobrains/mailing.py

96 lines
3.2 KiB
Python

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.application import MIMEApplication
from email.utils import formatdate
import smtplib
from pretty_bad_protocol import gnupg
import flask
#import poobrains
from poobrains import app
def getgpg():
return gnupg.GPG(binary=app.config['GPG_BINARY'], homedir=app.config['GPG_HOME'])
class MailError(Exception):
pass
class Mail(MIMEMultipart):
fingerprint = None
crypto = None
def __init__(self, fingerprint=None, **kwargs):
MIMEMultipart.__init__(self, **kwargs)
self.fingerprint = fingerprint
self.crypto = getgpg()
self['From'] = app.config['SMTP_FROM']
self['Date'] = formatdate()
def as_string(self, unixfrom=False):
fingerprint = str(self.fingerprint) # TODO: enforce str by implementing __setattr__?
wrapper_msg = MIMEMultipart(_subtype='encrypted', protocol='application/pgp-encrypted')
wrapper_msg['From'] = self['From']
wrapper_msg['To'] = self['To']
wrapper_msg['Subject'] = self['Subject']
wrapper_msg['Date'] = self['Date']
pgp_info = MIMEApplication(b"Version: 1\n", _subtype='pgp-encrypted', _encoder=lambda x: str(x))
pgp_info['Content-Disposition'] = 'attachment'
wrapper_msg.attach(pgp_info)
self_string = MIMEMultipart.as_string(self, unixfrom=unixfrom)
crypto_kw = {
'symmetric': False # IIUC symmetric=True makes us at risk for leaking private keys
}
if app.config['GPG_PASSPHRASE'] is not None and \
app.config['GPG_SIGNKEY'] is not None:
crypto_kw['passphrase'] = app.config['GPG_PASSPHRASE']
crypto_kw['default_key'] = app.config['GPG_SIGNKEY']
ciphertext = str(self.crypto.encrypt(self_string, str(self.fingerprint), **crypto_kw))
if ciphertext != '':
pgp_attachment = MIMEApplication(ciphertext, _encoder=lambda x: str(x))#, _subtype='octet-stream')
wrapper_msg.attach(pgp_attachment)
return wrapper_msg.as_string(unixfrom=unixfrom)
if hasattr(cryptinfo.stderr):
app.logger.error("Problem encrypting mail. stderr follows.")
app.logger.error(cryptinfo.stderr)
else:
app.logger.error("Problem encrypting mail. No further information.")
raise MailError("Problem encrypting mail.")
def send(self):
if not isinstance(self.fingerprint, str):
raise MailError('Trying to send mail without selecting public key fingerprint.')
if self['To'] is None:
raise MailError('Recipient for mail not set!')
if app.config['SMTP_STARTTLS']:
smtp = smtplib.SMTP(app.config['SMTP_HOST'], port=app.config['SMTP_PORT'])
smtp.starttls() # FIXME: We'll want to check if this actually worked
else:
smtp = smtplib.SMTP_SSL(app.config['SMTP_HOST'], port=app.config['SMTP_PORT'])
smtp.ehlo()
smtp.login(app.config['SMTP_ACCOUNT'], app.config['SMTP_PASSWORD'])
smtp.sendmail(self['From'], self['To'], self.as_string())