Continue refactoring

- Add more encryption strategies.
- Replace tuples (email + key) with dedicated objects.
This commit is contained in:
Piotr F. Mieszkowski 2022-09-27 22:35:38 +02:00 committed by Gitea
parent 8963eee47f
commit ce6a0c5466
2 changed files with 50 additions and 24 deletions

View file

@ -34,7 +34,7 @@ from M2Crypto import BIO, SMIME, X509
import logging import logging
import lacre.text as text import lacre.text as text
import lacre.config as conf import lacre.config as conf
from lacre.mailop import KeepIntact, OpenPGPEncrypt from lacre.mailop import KeepIntact, InlineOpenPGPEncrypt, MimeOpenPGPEncrypt
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -93,26 +93,31 @@ def _sort_gpg_recipients(gpg_to):
gpg_to_cmdline_inline.extend(rcpt.key().split(',')) gpg_to_cmdline_inline.extend(rcpt.key().split(','))
else: else:
# Log message only if an unknown style is defined # Log message only if an unknown style is defined
if conf.config_item_set('pgp_style', rcpt[0]): if conf.config_item_set('pgp_style', rcpt.email()):
LOG.debug("Style %s for recipient %s is not known. Use default as fallback." % (conf.get_item("pgp_style", rcpt[0]), rcpt[0])) LOG.debug("Style %s for recipient %s is not known. Use default as fallback." % (conf.get_item("pgp_style", rcpt.email()), rcpt.email()))
# If no style is in settings defined for recipient, use default from settings # If no style is in settings defined for recipient, use default from settings
if default_to_pgp_mime: if default_to_pgp_mime:
gpg_to_smtp_mime.append(rcpt[0]) gpg_to_smtp_mime.append(rcpt.email())
gpg_to_cmdline_mime.extend(rcpt[1].split(',')) gpg_to_cmdline_mime.extend(rcpt.key().split(','))
else: else:
gpg_to_smtp_inline.append(rcpt[0]) gpg_to_smtp_inline.append(rcpt.email())
gpg_to_cmdline_inline.extend(rcpt[1].split(',')) gpg_to_cmdline_inline.extend(rcpt.key().split(','))
return gpg_to_smtp_mime, gpg_to_cmdline_mime, gpg_to_smtp_inline, gpg_to_cmdline_inline return gpg_to_smtp_mime, gpg_to_cmdline_mime, gpg_to_smtp_inline, gpg_to_cmdline_inline
def _gpg_encrypt_and_deliver(message, cmdline, to, encrypt_f): def _gpg_encrypt_and_return(message, cmdline, to, encrypt_f):
msg_copy = copy.deepcopy(message) msg_copy = copy.deepcopy(message)
_customise_headers(msg_copy) _customise_headers(msg_copy)
encrypted_payloads = encrypt_f(msg_copy, cmdline) encrypted_payloads = encrypt_f(msg_copy, cmdline)
msg_copy.set_payload(encrypted_payloads) msg_copy.set_payload(encrypted_payloads)
send_msg(msg_copy.as_string(), to) return msg_copy.as_string()
def _gpg_encrypt_and_deliver(message, cmdline, to, encrypt_f):
out = _gpg_encrypt_and_return(message, cmdline, to, encrypt_f)
send_msg(out, to)
def _customise_headers(msg_copy): def _customise_headers(msg_copy):
@ -179,7 +184,7 @@ def _identify_gpg_recipients(recipients):
# GnuPG keys found in our keyring. # GnuPG keys found in our keyring.
keys = _load_keys() keys = _load_keys()
LOG.info(f'Processisng recipients: {recipients!r}') LOG.info(f'Processisng recipients: {recipients!r}; keys: {keys!r}')
for to in recipients: for to in recipients:
LOG.info(f"At to={to!r}") LOG.info(f"At to={to!r}")
own_key = _try_configured_key(to, keys) own_key = _try_configured_key(to, keys)
@ -515,8 +520,8 @@ def delivery_plan(recipients):
keyhome = conf.get_item('gpg', 'keyhome') keyhome = conf.get_item('gpg', 'keyhome')
return [OpenPGPEncrypt(gpg_mime_to, gpg_mime_cmd, keyhome), return [MimeOpenPGPEncrypt(gpg_mime_to, gpg_mime_cmd, keyhome),
OpenPGPEncrypt(gpg_inline_to, gpg_inline_cmd, keyhome), InlineOpenPGPEncrypt(gpg_inline_to, gpg_inline_cmd, keyhome),
KeepIntact(ungpg_to)] KeepIntact(ungpg_to)]

View file

@ -14,7 +14,7 @@ There are 3 operations available:
""" """
import logging import logging
import GnuPG import lacre.mailgate as mailgate
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -52,20 +52,41 @@ class OpenPGPEncrypt(MailOperation):
self._key = key self._key = key
self._keyhome = keyhome self._keyhome = keyhome
def perform(self, message): def extend_keys(self, keys):
"""Encrypt MESSAGE with the given key.""" """Register GPG keys to encrypt this message for."""
enc = GnuPG.GPGEncryptor(self._keyhome) self._keys.extend(keys)
enc.update(message)
encrypted, err = enc.encrypt()
if err:
LOG.error(f"Unable to encrypt message, delivering cleartext (gpg exit code: {err})")
return message
else:
return encrypted
def __repr__(self): def __repr__(self):
"""Generate a representation with just method and key.""" """Generate a representation with just method and key."""
return f"<OpenPGP {self._recipients} {self._key}>" return f"<{type(self).__name__} {self._recipients} {self._key}>"
class InlineOpenPGPEncrypt(OpenPGPEncrypt):
"""Inline encryption strategy."""
def perform(self, msg):
"""Encrypt with PGP Inline."""
LOG.debug('Sending PGP/Inline...')
return mailgate._gpg_encrypt_and_return(msg,
self._keys, self._recipients,
mailgate._encrypt_all_payloads_inline)
class MimeOpenPGPEncrypt(OpenPGPEncrypt):
"""MIME encryption strategy."""
def __init__(self, recipients, keys, keyhome):
"""Initialise strategy object."""
super().__init__(recipients)
self._keys = keys
self._keyhome = keyhome
def perform(self, msg):
"""Encrypt with PGP MIME."""
LOG.debug('Sending PGP/MIME...')
return mailgate._gpg_encrypt_and_return(msg,
self._keys, self._recipients,
mailgate._encrypt_all_payloads_mime)
class SMimeEncrypt(MailOperation): class SMimeEncrypt(MailOperation):