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.
This commit is contained in:
Piotr F. Mieszkowski 2022-10-11 21:50:51 +02:00 committed by Gitea
parent d7e4947afd
commit f5cff3292a
3 changed files with 21 additions and 14 deletions

View file

@ -3,7 +3,6 @@
import logging import logging
import lacre import lacre
import lacre.config as conf import lacre.config as conf
import lacre.keycache as kcache
import sys import sys
from aiosmtpd.controller import Controller from aiosmtpd.controller import Controller
from aiosmtpd.smtp import Envelope from aiosmtpd.smtp import Envelope
@ -24,6 +23,7 @@ lacre.init_logging(conf.get_item("logging", "config"))
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
import lacre.mailgate as gate import lacre.mailgate as gate
import lacre.keycache as kcache
class MailEncryptionProxy: class MailEncryptionProxy:
@ -48,11 +48,11 @@ class MailEncryptionProxy:
return RESULT_NOT_IMPLEMENTED return RESULT_NOT_IMPLEMENTED
def _init_controller(keys: kcache.KeyCache): def _init_controller(keys: kcache.KeyCache, tout: float = 2.5):
proxy = MailEncryptionProxy(keys) proxy = MailEncryptionProxy(keys)
host, port = conf.daemon_params() host, port = conf.daemon_params()
LOG.info(f"Initialising a mail Controller at {host}:{port}") 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(): def _validate_config():
@ -67,27 +67,26 @@ def _full_param_name(tup):
return f"[{tup[0]}]{tup[1]}" return f"[{tup[0]}]{tup[1]}"
async def _sleep(): async def _sleep(minutes, heartbeat_func):
while True: while True:
await asyncio.sleep(5) await asyncio.sleep(minutes * 60)
heartbeat_func()
def _main(): def _main():
_validate_config() _validate_config()
refresh_min = float(conf.get_item('gpg', 'cache_refresh_minutes', 2))
keys = kcache.KeyCache(conf.get_item('gpg', 'keyhome')) keys = kcache.KeyCache(conf.get_item('gpg', 'keyhome'))
keys.load() keys.load()
controller = _init_controller(keys) controller = _init_controller(keys)
LOG.info("Starting the daemon...") LOG.info("Starting the daemon...")
# starts the controller in a new thread
controller.start() controller.start()
# _this_ thread now continues operation, so it may be used to control key
# and certificate cache
try: try:
asyncio.run(_sleep()) asyncio.run(_sleep(refresh_min, keys.load))
except KeyboardInterrupt: except KeyboardInterrupt:
LOG.info("Finishing...") LOG.info("Finishing...")

View file

@ -8,6 +8,10 @@ import GnuPG
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class KeyCacheMisconfiguration(Exception):
"""Exception used to signal that KeyCache is misconfigured."""
class KeyCache: class KeyCache:
"""A store for OpenPGP keys. """A store for OpenPGP keys.
@ -44,11 +48,15 @@ class KeyCache:
def load(self): def load(self):
"""Load keyring, replacing any previous contents of the cache.""" """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)) self.replace_keyring(self._load_keyring_from(self._keyring_dir))
reload = load reload = load
def load_keyring(self, keyhome: str): def load_keyring_from(self, keyhome: str):
"""Add all identities from keyring stored in KEYHOME.""" """Add all identities from keyring stored in KEYHOME."""
self.extend_keyring(self._load_keyring_from(keyhome)) self.extend_keyring(self._load_keyring_from(keyhome))
@ -60,7 +68,7 @@ class KeyCache:
for fingerprint in keys: for fingerprint in keys:
keys[fingerprint] = text.sanitize_case_sense(keys[fingerprint]) 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 self._keys = keys
def extend_keyring(self, keys: dict): def extend_keyring(self, keys: dict):
@ -68,5 +76,5 @@ class KeyCache:
for fingerprint in keys: for fingerprint in keys:
keys[fingerprint] = text.sanitize_case_sense(keys[fingerprint]) 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) self._keys.update(keys)

View file

@ -132,7 +132,7 @@ def _customise_headers(msg_copy):
def _load_keys(): def _load_keys():
"""Return a map from a key's fingerprint to email address.""" """Return a map from a key's fingerprint to email address."""
keys = kcache.KeyCache() keys = kcache.KeyCache()
keys.load_keyring(conf.get_item('gpg', 'keyhome')) keys.load_keyring_from(conf.get_item('gpg', 'keyhome'))
return keys return keys