From 612334ae8d54d9bcd886df4fcaa6c3ac5e7b601b Mon Sep 17 00:00:00 2001 From: s3lph <1375407-s3lph@users.noreply.gitlab.com> Date: Mon, 25 Apr 2022 23:06:08 +0200 Subject: [PATCH] Do not send unencrypted admin reports --- multischleuder/processor.py | 13 +++++++---- multischleuder/reporting.py | 23 ++++++++++++------- multischleuder/test/test_multilist.py | 7 +++--- multischleuder/test/test_reporting.py | 33 ++++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 17 deletions(-) diff --git a/multischleuder/processor.py b/multischleuder/processor.py index 3e7921d..f15624b 100644 --- a/multischleuder/processor.py +++ b/multischleuder/processor.py @@ -84,11 +84,14 @@ class MultiList: logging.info(f'No changes for {self._target}') else: for admin in target_admins: - report = AdminReport(self._target, admin.email, self._mail_from, - admin.key.blob if admin.key is not None else None, - to_subscribe, to_unsubscribe, to_update, to_add, to_remove, - conflicts) - self._reporter.add_message(report) + try: + report = AdminReport(self._target, admin.email, self._mail_from, + admin.key.blob if admin.key is not None else None, + to_subscribe, to_unsubscribe, to_update, to_add, to_remove, + conflicts) + self._reporter.add_message(report) + except BaseException: + logging.exception(f'Encryption to {admin.email} failed, not sending report') logging.info(f'Finished processing: {self._target}') def _lists_by_name(self) -> Tuple[SchleuderList, List[SchleuderList]]: diff --git a/multischleuder/reporting.py b/multischleuder/reporting.py index b98ed5c..bebd203 100644 --- a/multischleuder/reporting.py +++ b/multischleuder/reporting.py @@ -27,24 +27,29 @@ class Message(abc.ABC): mail_from: str, mail_to: str, content: str, - encrypt_to: List[str]): + encrypt_to: List[str], + encrypt_may_fail: bool = False): self._schleuder: str = schleuder self._from: str = mail_from self._to: str = mail_to self._keys: List[str] = encrypt_to - self._mime: email.mime.base.MIMEBase = self._make_mime(content) + self._mime: email.mime.base.MIMEBase = self._make_mime(content, encrypt_may_fail) @property def mime(self) -> email.mime.base.MIMEBase: return self._mime - def _make_mime(self, content: str) -> email.mime.base.MIMEBase: + def _make_mime(self, content: str, encrypt_may_fail: bool) -> email.mime.base.MIMEBase: # Encrypt to all keys, if possible. Fall back to unencrypted otherwise try: self._mime = self._encrypt_message(content) - except Exception: - logging.exception('Encryption failed; falling back to unencrypted message') - self._mime = email.mime.text.MIMEText(content, _subtype='plain', _charset='utf-8') + except Exception as e: + if encrypt_may_fail: + logging.exception('Encryption failed; falling back to unencrypted message') + self._mime = email.mime.text.MIMEText(content, _subtype='plain', _charset='utf-8') + else: + logging.exception('Encryption failed; Not sending this message') + raise e # Set all the email headers self._mime['From'] = self._from self._mime['Reply-To'] = self._from @@ -124,7 +129,8 @@ class KeyConflictMessage(Message): mail_from=mail_from, mail_to=chosen.email, content=content, - encrypt_to=[s.key.blob for s in affected if s.key is not None] + encrypt_to=[s.key.blob for s in affected if s.key is not None], + encrypt_may_fail=True # Permit unencrypted fallback so the user gets notified of the conflict anyway ) self.mime['Subject'] = f'MultiSchleuder {self._schleuder} - Key Conflict' self.mime['X-MultiSchleuder-Digest'] = digest @@ -174,7 +180,8 @@ class UserConflictMessage(Message): mail_from=mail_from, mail_to=subscriber, content=content, - encrypt_to=[chosen.key.blob] + encrypt_to=[chosen.key.blob], + encrypt_may_fail=True # Permit unencrypted fallback so the user gets notified of the conflict anyway ) self.mime['Subject'] = f'MultiSchleuder {self._schleuder} - Subscriber Conflict' self.mime['X-MultiSchleuder-Digest'] = digest diff --git a/multischleuder/test/test_multilist.py b/multischleuder/test/test_multilist.py index 57c1e2a..aeeb5f4 100644 --- a/multischleuder/test/test_multilist.py +++ b/multischleuder/test/test_multilist.py @@ -9,6 +9,7 @@ from dateutil.tz import tzutc from multischleuder.processor import MultiList from multischleuder.reporting import Message +from multischleuder.test.test_conflict import _PRIVKEY_1 from multischleuder.types import SchleuderKey, SchleuderList, SchleuderSubscriber @@ -38,7 +39,7 @@ def _list_lists(): def _get_key(fpr: str, schleuder: SchleuderList): key1 = SchleuderKey('966842467B3254143F994D5E5C408C012D216471', - 'admin@example.org', 'BEGIN PGP 2D216471', schleuder.id) + 'admin@example.org', str(_PRIVKEY_1.pubkey), schleuder.id) key2 = SchleuderKey('6449FFB6EE68187962FA013B5CA2F4F51791BAF6', 'ada.lovelace@example.org', 'BEGIN PGP 1791BAF6', schleuder.id) key3 = SchleuderKey('414D3960D34730F63C74D5190EBC5A16716DEC79', @@ -72,7 +73,7 @@ def _get_admins(schleuder: SchleuderList): if schleuder.id != 2: return [] key = SchleuderKey('966842467B3254143F994D5E5C408C012D216471', - 'admin@example.org', 'BEGIN PGP 2D216471', schleuder.id) + 'admin@example.org', str(_PRIVKEY_1.pubkey), schleuder.id) date = datetime(2022, 4, 15, 5, 23, 42, 0, tzinfo=tzutc()) admin = SchleuderSubscriber(0, 'admin@example.org', key, schleuder.id, date) return [admin] @@ -80,7 +81,7 @@ def _get_admins(schleuder: SchleuderList): def _get_subs(schleuder: SchleuderList): key1 = SchleuderKey('966842467B3254143F994D5E5C408C012D216471', - 'admin@example.org', 'BEGIN PGP 2D216471', schleuder.id) + 'admin@example.org', str(_PRIVKEY_1.pubkey), schleuder.id) key2 = SchleuderKey('6449FFB6EE68187962FA013B5CA2F4F51791BAF6', 'ada.lovelace@example.org', 'BEGIN PGP 1791BAF6', schleuder.id) key3 = SchleuderKey('414D3960D34730F63C74D5190EBC5A16716DEC79', diff --git a/multischleuder/test/test_reporting.py b/multischleuder/test/test_reporting.py index 048a8ce..b0994bc 100644 --- a/multischleuder/test/test_reporting.py +++ b/multischleuder/test/test_reporting.py @@ -3,11 +3,27 @@ import unittest from datetime import datetime +import pgpy.errors + from multischleuder.reporting import KeyConflictMessage, AdminReport, Reporter, UserConflictMessage from multischleuder.types import SchleuderKey, SchleuderList, SchleuderSubscriber from multischleuder.test.test_conflict import _PRIVKEY_1 +BROKENKEY = ''' +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mDMEYmcMbxYJKwYBBAHaRw8BAQdAKUohRdnuTSldKwawfLdwwUvOJjz/pHx3fXS2 +v2dUQx+0SU11bHRpc2NobGV1ZGVyIEJyb2tlbiBBZG1pbiBLZXkgKFRFU1QgS0VZ +IERPIE5PVCBVU0UpIDxhZG1pbkBleGFtcGxlLm9yZz6IkAQTFggAOBYhBGtuFOnz +PJOCOdfv6OuAwhfh1Uj8BQJiZwxvAhsBBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheA +AAoJEOuAwhfh1Uj8PnkBAM6PfYUZbvvYEkSdwzmZXDwhPRsSA0bhjL5aVwIeCCdp +AQDeImNI6czSLVAuwObKv8FnpmbFi3HxTNzakp44DoD8Aw== +=JtdI +-----END PGP PUBLIC KEY BLOCK----- +''' + + def one_of_each_kind(): sub = SchleuderSubscriber(1, 'foo@example.org', None, 1, datetime.utcnow()) key = SchleuderKey(_PRIVKEY_1.fingerprint.replace(' ', ''), 'foo@example.org', str(_PRIVKEY_1.pubkey), 1) @@ -24,7 +40,7 @@ def one_of_each_kind(): schleuder='test@example.org', mail_to='admin@example.org', mail_from='test-owner@example.org', - encrypt_to=None, + encrypt_to=str(_PRIVKEY_1.pubkey), subscribed={}, unsubscribed={sub}, updated={}, @@ -94,3 +110,18 @@ class TestReporting(unittest.TestCase): r.add_messages([None]) self.assertEqual(0, len(Reporter.get_messages())) Reporter.clear_messages() + + def test_admin_report_nokey(self): + sub = SchleuderSubscriber(1, 'foo@example.org', None, 1, datetime.utcnow()) + with self.assertRaises(pgpy.errors.PGPError): + AdminReport( + schleuder='test@example.org', + mail_to='admin@example.org', + mail_from='test-owner@example.org', + encrypt_to=BROKENKEY, + subscribed={sub}, + unsubscribed={}, + updated={}, + added={}, + removed={}, + conflicts=[])