Deliver cleartext if Unicode encoding or message serialisation fail

This commit is contained in:
Piotr F. Mieszkowski 2024-03-02 18:36:41 +01:00
parent 3138864d32
commit 110ea885f2
Signed by: pfm
GPG Key ID: BDE5BC1FA5DC53D5
4 changed files with 17 additions and 6 deletions

View File

@ -40,7 +40,7 @@ import lacre.keyring as kcache
import lacre.recipients as recpt import lacre.recipients as recpt
import lacre.smime as smime import lacre.smime as smime
from lacre.transport import send_msg, register_sender, SendFrom from lacre.transport import send_msg, register_sender, SendFrom
from lacre.mailop import KeepIntact, InlineOpenPGPEncrypt, MimeOpenPGPEncrypt from lacre.mailop import KeepIntact, InlineOpenPGPEncrypt, MimeOpenPGPEncrypt, MailSerialisationException
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -127,7 +127,10 @@ def _gpg_encrypt_copy(message: EmailMessage, keys, recipients, encrypt_f):
def _gpg_encrypt_to_bytes(message: EmailMessage, keys, recipients, encrypt_f) -> bytes: def _gpg_encrypt_to_bytes(message: EmailMessage, keys, recipients, encrypt_f) -> bytes:
msg_copy = _gpg_encrypt_copy(message, keys, recipients, encrypt_f) msg_copy = _gpg_encrypt_copy(message, keys, recipients, encrypt_f)
return msg_copy.as_bytes(policy=SMTPUTF8) try:
return msg_copy.as_bytes(policy=SMTPUTF8)
except IndexError:
raise MailSerialisationException()
def _gpg_encrypt_to_str(message: EmailMessage, keys, recipients, encrypt_f) -> str: def _gpg_encrypt_to_str(message: EmailMessage, keys, recipients, encrypt_f) -> str:

View File

@ -22,7 +22,7 @@ from GnuPG import EncryptionException
import lacre.core as gate import lacre.core as gate
import lacre.keyring as kcache import lacre.keyring as kcache
import lacre.transport as xport import lacre.transport as xport
from lacre.mailop import KeepIntact from lacre.mailop import KeepIntact, MailSerialisationException
class MailEncryptionProxy: class MailEncryptionProxy:
@ -48,7 +48,7 @@ class MailEncryptionProxy:
try: try:
new_message = operation.perform(message) new_message = operation.perform(message)
send(new_message, operation.recipients()) send(new_message, operation.recipients())
except EncryptionException as e: except (EncryptionException, MailSerialisationException, UnicodeEncodeError) as e:
# If the message can't be encrypted, deliver cleartext. # If the message can't be encrypted, deliver cleartext.
LOG.error('Unable to encrypt message, delivering in cleartext: %s', e) LOG.error('Unable to encrypt message, delivering in cleartext: %s', e)
if not isinstance(operation, KeepIntact): if not isinstance(operation, KeepIntact):

View File

@ -22,6 +22,11 @@ from email.policy import SMTP, SMTPUTF8
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class MailSerialisationException(BaseException):
"""We can't turn an EmailMessage into sequence of bytes."""
pass
class MailOperation: class MailOperation:
"""Contract for an operation to be performed on a message.""" """Contract for an operation to be performed on a message."""
@ -124,7 +129,10 @@ class KeepIntact(MailOperation):
def perform(self, message: Message) -> bytes: def perform(self, message: Message) -> bytes:
"""Return MESSAGE unmodified.""" """Return MESSAGE unmodified."""
return message.as_bytes(policy=SMTPUTF8) try:
return message.as_bytes(policy=SMTPUTF8)
except IndexError as e:
raise MailSerialisationException(e)
def __repr__(self): def __repr__(self):
"""Return representation with just method and email.""" """Return representation with just method and email."""

View File

@ -33,6 +33,6 @@ class ExecutionTimeLoggerTest(unittest.TestCase):
self.assertEqual(handler.logged_records[1], 'Doing something') self.assertEqual(handler.logged_records[1], 'Doing something')
# Exception record should include the timing result and the traceback... # Exception record should include the timing result and the traceback...
self.assertRegex(handler.logged_records[2], '^Just a test took 0 ms, raised exception\nTraceback.*') self.assertRegex(handler.logged_records[2], '^Just a test took \\d ms, raised exception\nTraceback.*')
# ...as well as the original exception # ...as well as the original exception
self.assertRegex(handler.logged_records[2], 'Exception: this is a test$') self.assertRegex(handler.logged_records[2], 'Exception: this is a test$')