Add ability to deliver cleartext when keys can't be loaded #135
|
@ -68,6 +68,11 @@ max_data_bytes = 33554432
|
||||||
# This should never be PII, but information like encoding, content types, etc.
|
# This should never be PII, but information like encoding, content types, etc.
|
||||||
log_headers = no
|
log_headers = no
|
||||||
|
|
||||||
|
# Sometimes we might fail to load keys and need to choose between delivering
|
||||||
|
# in cleartext or not delivering. The default is to deliver cleartext, but
|
||||||
|
# administrators can make this decision on their own.
|
||||||
|
bounce_on_keys_missing = no
|
||||||
|
|
||||||
[relay]
|
[relay]
|
||||||
# the relay settings to use for Postfix
|
# the relay settings to use for Postfix
|
||||||
# gpg-mailgate will submit email to this relay after it is done processing
|
# gpg-mailgate will submit email to this relay after it is done processing
|
||||||
|
|
|
@ -37,9 +37,7 @@ class MailEncryptionProxy:
|
||||||
with time_logger('Message delivery', LOG):
|
with time_logger('Message delivery', LOG):
|
||||||
try:
|
try:
|
||||||
keys = self._keyring.freeze_identities()
|
keys = self._keyring.freeze_identities()
|
||||||
LOG.debug('Parsing message: %s', self._beginning(envelope))
|
|
||||||
message = email.message_from_bytes(envelope.original_content, policy=SMTPUTF8)
|
message = email.message_from_bytes(envelope.original_content, policy=SMTPUTF8)
|
||||||
LOG.debug('Parsed into %s: %s', type(message), repr(message))
|
|
||||||
|
|
||||||
if message.defects:
|
if message.defects:
|
||||||
LOG.warning("Issues found: %d; %s", len(message.defects), repr(message.defects))
|
LOG.warning("Issues found: %d; %s", len(message.defects), repr(message.defects))
|
||||||
|
|
|
@ -4,6 +4,7 @@ from sqlalchemy import create_engine, select, delete, and_, func
|
||||||
from sqlalchemy.exc import OperationalError
|
from sqlalchemy.exc import OperationalError
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from lacre.config import flag_enabled
|
||||||
from lacre._keyringcommon import KeyRing, KeyCache
|
from lacre._keyringcommon import KeyRing, KeyCache
|
||||||
import lacre.dbschema as db
|
import lacre.dbschema as db
|
||||||
|
|
||||||
|
@ -13,6 +14,7 @@ LOG = logging.getLogger(__name__)
|
||||||
# Internal state
|
# Internal state
|
||||||
_engine = None
|
_engine = None
|
||||||
|
|
||||||
|
|
||||||
def connect(url):
|
def connect(url):
|
||||||
global _engine
|
global _engine
|
||||||
|
|
||||||
|
@ -78,13 +80,21 @@ class IdentityRepository(KeyRing):
|
||||||
self._conn.execute(delq)
|
self._conn.execute(delq)
|
||||||
|
|
||||||
def freeze_identities(self) -> KeyCache:
|
def freeze_identities(self) -> KeyCache:
|
||||||
"""Return a static, async-safe copy of the identity map."""
|
"""Return a static, async-safe copy of the identity map.
|
||||||
|
|
||||||
|
Depending on the value of [daemon]bounce_on_keys_missing value,
|
||||||
|
if we get a database exception, this method will either return
|
||||||
|
empty collection or let the exception be propagated.
|
||||||
|
"""
|
||||||
self._ensure_connected()
|
self._ensure_connected()
|
||||||
try:
|
try:
|
||||||
return self._load_identities()
|
return self._load_identities()
|
||||||
except OperationalError:
|
except OperationalError:
|
||||||
LOG.exception('Cannot retrieve identities')
|
if flag_enabled('daemon', 'bounce_on_keys_missing'):
|
||||||
return None
|
raise
|
||||||
|
else:
|
||||||
|
LOG.exception('Failed to load keys, returning empty collection')
|
||||||
|
return KeyCache({})
|
||||||
|
|
||||||
def _load_identities(self) -> KeyCache:
|
def _load_identities(self) -> KeyCache:
|
||||||
all_identities = select(self._identities.c.fingerprint, self._identities.c.email)
|
all_identities = select(self._identities.c.fingerprint, self._identities.c.email)
|
||||||
|
|
|
@ -65,10 +65,6 @@ class GnuPGUtilitiesTest(unittest.TestCase):
|
||||||
uid = GnuPG._parse_uid_line(sample_in)
|
uid = GnuPG._parse_uid_line(sample_in)
|
||||||
self.assertEqual(uid, 'alice@disposlab')
|
self.assertEqual(uid, 'alice@disposlab')
|
||||||
|
|
||||||
def test_exception_formatting(self):
|
|
||||||
e = GnuPG.EncryptionException('alice@disposlab', 'key expired', None, b'DEADBEEF')
|
|
||||||
self.assertEqual(str(e), 'To: alice@disposlab; Issue: key expired; Key: DEADBEEF')
|
|
||||||
|
|
||||||
def test_parse_statusfd_key_expired(self):
|
def test_parse_statusfd_key_expired(self):
|
||||||
key_expired = b"""
|
key_expired = b"""
|
||||||
[GNUPG:] KEYEXPIRED 1668272263
|
[GNUPG:] KEYEXPIRED 1668272263
|
||||||
|
|
Loading…
Reference in New Issue