From f5cff3292a3587bd1af8f933c3a1ad20f190b818 Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Tue, 11 Oct 2022 21:50:51 +0200 Subject: [PATCH] Reload key cache periodically Use [default]cache_refresh_minutes configuration parameter to define periods between cache reloads. After this number of minutes cache will be reloaded. --- lacre/daemon.py | 19 +++++++++---------- lacre/keycache.py | 14 +++++++++++--- lacre/mailgate.py | 2 +- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lacre/daemon.py b/lacre/daemon.py index 1077e30..23f5730 100644 --- a/lacre/daemon.py +++ b/lacre/daemon.py @@ -3,7 +3,6 @@ import logging import lacre import lacre.config as conf -import lacre.keycache as kcache import sys from aiosmtpd.controller import Controller from aiosmtpd.smtp import Envelope @@ -24,6 +23,7 @@ lacre.init_logging(conf.get_item("logging", "config")) LOG = logging.getLogger(__name__) import lacre.mailgate as gate +import lacre.keycache as kcache class MailEncryptionProxy: @@ -48,11 +48,11 @@ class MailEncryptionProxy: return RESULT_NOT_IMPLEMENTED -def _init_controller(keys: kcache.KeyCache): +def _init_controller(keys: kcache.KeyCache, tout: float = 2.5): proxy = MailEncryptionProxy(keys) host, port = conf.daemon_params() LOG.info(f"Initialising a mail Controller at {host}:{port}") - return Controller(proxy, hostname=host, port=port) + return Controller(proxy, hostname=host, port=port, ready_timeout=tout) def _validate_config(): @@ -67,27 +67,26 @@ def _full_param_name(tup): return f"[{tup[0]}]{tup[1]}" -async def _sleep(): +async def _sleep(minutes, heartbeat_func): while True: - await asyncio.sleep(5) + await asyncio.sleep(minutes * 60) + heartbeat_func() def _main(): _validate_config() + refresh_min = float(conf.get_item('gpg', 'cache_refresh_minutes', 2)) + keys = kcache.KeyCache(conf.get_item('gpg', 'keyhome')) keys.load() controller = _init_controller(keys) LOG.info("Starting the daemon...") - # starts the controller in a new thread controller.start() - # _this_ thread now continues operation, so it may be used to control key - # and certificate cache - try: - asyncio.run(_sleep()) + asyncio.run(_sleep(refresh_min, keys.load)) except KeyboardInterrupt: LOG.info("Finishing...") diff --git a/lacre/keycache.py b/lacre/keycache.py index 5104077..9d5e0f9 100644 --- a/lacre/keycache.py +++ b/lacre/keycache.py @@ -8,6 +8,10 @@ import GnuPG LOG = logging.getLogger(__name__) +class KeyCacheMisconfiguration(Exception): + """Exception used to signal that KeyCache is misconfigured.""" + + class KeyCache: """A store for OpenPGP keys. @@ -44,11 +48,15 @@ class KeyCache: def load(self): """Load keyring, replacing any previous contents of the cache.""" + LOG.debug('Reloading keys...') + if self._keyring_dir is None: + LOG.error('Keyringn directory not set!') + raise KeyCacheMisconfiguration("Keyring directory not configured") self.replace_keyring(self._load_keyring_from(self._keyring_dir)) reload = load - def load_keyring(self, keyhome: str): + def load_keyring_from(self, keyhome: str): """Add all identities from keyring stored in KEYHOME.""" self.extend_keyring(self._load_keyring_from(keyhome)) @@ -60,7 +68,7 @@ class KeyCache: for fingerprint in keys: keys[fingerprint] = text.sanitize_case_sense(keys[fingerprint]) - LOG.info(f'Loaded {len(keys)} keys') + LOG.info(f'Storing {len(keys)} keys') self._keys = keys def extend_keyring(self, keys: dict): @@ -68,5 +76,5 @@ class KeyCache: for fingerprint in keys: keys[fingerprint] = text.sanitize_case_sense(keys[fingerprint]) - LOG.info(f'Loaded {len(keys)} keys') + LOG.info(f'Adding {len(keys)} keys') self._keys.update(keys) diff --git a/lacre/mailgate.py b/lacre/mailgate.py index 35ae9ec..a77220a 100644 --- a/lacre/mailgate.py +++ b/lacre/mailgate.py @@ -132,7 +132,7 @@ def _customise_headers(msg_copy): def _load_keys(): """Return a map from a key's fingerprint to email address.""" keys = kcache.KeyCache() - keys.load_keyring(conf.get_item('gpg', 'keyhome')) + keys.load_keyring_from(conf.get_item('gpg', 'keyhome')) return keys