Fix MIME content sub-type handling for non-plain text messages
This commit is contained in:
parent
bc92d7a31c
commit
61cf50effe
|
@ -179,35 +179,42 @@ def _encrypt_all_payloads_mime(message: EmailMessage, gpg_to_cmdline):
|
||||||
boundary = _make_boundary()
|
boundary = _make_boundary()
|
||||||
|
|
||||||
if isinstance(message.get_payload(), str):
|
if isinstance(message.get_payload(), str):
|
||||||
|
LOG.debug('Rewrapping a flat, text-only message')
|
||||||
wrapped_payload = _rewrap_payload(message)
|
wrapped_payload = _rewrap_payload(message)
|
||||||
encrypted_part.set_payload(wrapped_payload.as_string())
|
encrypted_part.set_payload(wrapped_payload.as_string())
|
||||||
|
|
||||||
_set_type_and_boundary(message, boundary)
|
_set_type_and_boundary(message, boundary)
|
||||||
|
|
||||||
return [pgp_ver_part, _encrypt_payload(encrypted_part, gpg_to_cmdline, True)]
|
check_nested = True
|
||||||
else:
|
else:
|
||||||
processed_payloads = _generate_message_from_payloads(message)
|
processed_payloads = _generate_message_from_payloads(message)
|
||||||
encrypted_part.set_payload(processed_payloads.as_string())
|
encrypted_part.set_payload(processed_payloads.as_string())
|
||||||
|
|
||||||
_set_type_and_boundary(message, boundary)
|
_set_type_and_boundary(message, boundary)
|
||||||
|
|
||||||
return [pgp_ver_part, _encrypt_payload(encrypted_part, gpg_to_cmdline, False)]
|
check_nested = False
|
||||||
|
|
||||||
|
return [pgp_ver_part, _encrypt_payload(encrypted_part, gpg_to_cmdline, check_nested)]
|
||||||
|
|
||||||
|
|
||||||
def _rewrap_payload(message: EmailMessage) -> MIMEPart:
|
def _rewrap_payload(message: EmailMessage) -> MIMEPart:
|
||||||
# In PGP/MIME (RFC 3156), the payload has to be a valid MIME entity. In
|
# In PGP/MIME (RFC 3156), the payload has to be a valid MIME entity. In
|
||||||
# other words, we need to wrap text/plain message's payload in a new MIME
|
# other words, we need to wrap text/* message's payload in a new MIME
|
||||||
# entity.
|
# entity.
|
||||||
|
|
||||||
pld = MIMEPart()
|
wrapper = MIMEPart(policy=SMTPUTF8)
|
||||||
pld.set_type(message.get_content_type())
|
content = message.get_content()
|
||||||
pld.set_content(message.get_content())
|
wrapper.set_content(content)
|
||||||
|
|
||||||
# Make sure all Content-Type parameters are included.
|
wrapper.set_type(message.get_content_type())
|
||||||
for (k, v) in message.get_params():
|
|
||||||
pld.set_param(k, v)
|
|
||||||
|
|
||||||
return pld
|
# Copy all Content-Type parameters.
|
||||||
|
for (pname, pvalue) in message.get_params():
|
||||||
|
# Skip MIME type that's also returned by get_params().
|
||||||
|
if not '/' in pname:
|
||||||
|
wrapper.set_param(pname, pvalue)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
def _make_boundary():
|
def _make_boundary():
|
||||||
|
@ -242,8 +249,6 @@ def _encrypt_payload(payload: EmailMessage, recipients, check_nested=True, **kwa
|
||||||
|
|
||||||
if isAttachment:
|
if isAttachment:
|
||||||
_append_gpg_extension(payload)
|
_append_gpg_extension(payload)
|
||||||
if not (payload.get('Content-Transfer-Encoding') is None):
|
|
||||||
payload.replace_header('Content-Transfer-Encoding', "7bit")
|
|
||||||
|
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
|
|
@ -90,12 +90,10 @@ class RecipientList:
|
||||||
|
|
||||||
def emails(self):
|
def emails(self):
|
||||||
"""Return list of recipients."""
|
"""Return list of recipients."""
|
||||||
LOG.debug('Recipient emails from: %s', self._recipients)
|
|
||||||
return [r.email() for r in self._recipients]
|
return [r.email() for r in self._recipients]
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
"""Return list of GPG identities."""
|
"""Return list of GPG identities."""
|
||||||
LOG.debug('Recipient keys from: %s', self._recipients)
|
|
||||||
return [r.key() for r in self._recipients]
|
return [r.key() for r in self._recipients]
|
||||||
|
|
||||||
def __iadd__(self, recipient: GpgRecipient):
|
def __iadd__(self, recipient: GpgRecipient):
|
||||||
|
@ -116,6 +114,10 @@ class RecipientList:
|
||||||
"""
|
"""
|
||||||
return len(self._recipients)
|
return len(self._recipients)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
"""Returns textual object representation."""
|
||||||
|
return '<RecipientList %d %s>' % (len(self._recipients), ','.join(self.emails()))
|
||||||
|
|
||||||
|
|
||||||
def identify_gpg_recipients(recipients, keys: kcache.KeyCache):
|
def identify_gpg_recipients(recipients, keys: kcache.KeyCache):
|
||||||
"""Split recipient list into GPG and non-GPG ones."""
|
"""Split recipient list into GPG and non-GPG ones."""
|
||||||
|
|
|
@ -173,6 +173,14 @@ class EmailTest(unittest.TestCase):
|
||||||
_ = mp.as_string()
|
_ = mp.as_string()
|
||||||
self.assertFalse(mp.get_boundary() is None)
|
self.assertFalse(mp.get_boundary() is None)
|
||||||
|
|
||||||
|
def test_content_type_params_include_mime_type(self):
|
||||||
|
p = email.message.MIMEPart()
|
||||||
|
p.set_type('text/plain')
|
||||||
|
p.set_param('charset', 'UTF-8')
|
||||||
|
p.set_param('format', 'flowed')
|
||||||
|
|
||||||
|
self.assertIn(('text/plain', ''), p.get_params())
|
||||||
|
|
||||||
|
|
||||||
class RawConfigParserTest(unittest.TestCase):
|
class RawConfigParserTest(unittest.TestCase):
|
||||||
def test_config_parser_returns_str(self):
|
def test_config_parser_returns_str(self):
|
||||||
|
|
|
@ -36,5 +36,7 @@ class LacreCoreTest(unittest.TestCase):
|
||||||
|
|
||||||
rewrapped = lacre.core._rewrap_payload(m)
|
rewrapped = lacre.core._rewrap_payload(m)
|
||||||
|
|
||||||
self.assertFalse('Subject' in rewrapped)
|
self.assertFalse('Subject' in rewrapped,
|
||||||
self.assertEqual(rewrapped.get_content_type(), m.get_content_type())
|
'only content and content-type should be copied')
|
||||||
|
self.assertEqual(rewrapped.get_content_type(), 'text/plain',
|
||||||
|
'rewrapped part should have initial message\'s content-type')
|
||||||
|
|
Loading…
Reference in New Issue