diff --git a/gpg-mailgate.conf.sample b/gpg-mailgate.conf.sample index 154597f..ab12739 100644 --- a/gpg-mailgate.conf.sample +++ b/gpg-mailgate.conf.sample @@ -51,6 +51,14 @@ dec_regex = None # i.e. have mode 700. keyhome = /var/gpgmailgate/.gnupg +# Number of minutes between key cache refreshes. +# +# Lacre daemon keeps a cache of known keys to reduce number of OS processes +# needed to perform a single email. Keyring is going to be modified during +# daemon's lifetime, so with this simple mechanism we ensure that new keys +# will eventually be recognised and loaded. +cache_refresh_minutes = 5 + [smime] # the directory for the S/MIME certificate files cert_path = /var/gpgmailgate/smime diff --git a/lacre/daemon.py b/lacre/daemon.py index aca0d21..1077e30 100644 --- a/lacre/daemon.py +++ b/lacre/daemon.py @@ -75,8 +75,8 @@ async def _sleep(): def _main(): _validate_config() - keys = kcache.KeyCache() - keys.load_keyring(conf.get_item('gpg', 'keyhome')) + keys = kcache.KeyCache(conf.get_item('gpg', 'keyhome')) + keys.load() controller = _init_controller(keys) LOG.info("Starting the daemon...") diff --git a/lacre/keycache.py b/lacre/keycache.py index 7ec3de5..5104077 100644 --- a/lacre/keycache.py +++ b/lacre/keycache.py @@ -1,9 +1,12 @@ """A cache of OpenPGP keys known to Lacre.""" import lacre.text as text +import logging import GnuPG +LOG = logging.getLogger(__name__) + class KeyCache: """A store for OpenPGP keys. @@ -13,15 +16,21 @@ class KeyCache: [default]. """ - def __init__(self): - """Initialise an empty cache.""" + def __init__(self, keyring_dir: str = None): + """Initialise an empty cache. + + With keyring_dir given, set location of the directory from which keys should be loaded. + """ self._keys = dict() + self._keyring_dir = keyring_dir - def __getitem__(self, email): - return self._keys[email] + def __getitem__(self, fingerpring): + """Look up email assigned to the given fingerprint.""" + return self._keys[fingerpring] - def __setitem__(self, email, fingerprint): - self._keys[email] = fingerprint + def __setitem__(self, fingerprint, email): + """Assign an email to a fingerpring, overwriting it if it was already present.""" + self._keys[fingerprint] = email def __contains__(self, fingerprint): """Check if the given fingerprint is assigned to an email.""" @@ -30,17 +39,28 @@ class KeyCache: return fingerprint in self._keys def has_email(self, email): + """Check if cache contains a key assigned to the given email.""" return email in self._keys.values() + def load(self): + """Load keyring, replacing any previous contents of the cache.""" + self.replace_keyring(self._load_keyring_from(self._keyring_dir)) + + reload = load + def load_keyring(self, keyhome: str): """Add all identities from keyring stored in KEYHOME.""" - self.extend_keyring(GnuPG.public_keys(keyhome)) + self.extend_keyring(self._load_keyring_from(keyhome)) + + def _load_keyring_from(self, keyring_dir): + return GnuPG.public_keys(keyring_dir) def replace_keyring(self, keys: dict): """Overwrite previously stored key cache with KEYS.""" for fingerprint in keys: keys[fingerprint] = text.sanitize_case_sense(keys[fingerprint]) + LOG.info(f'Loaded {len(keys)} keys') self._keys = keys def extend_keyring(self, keys: dict): @@ -48,4 +68,5 @@ class KeyCache: for fingerprint in keys: keys[fingerprint] = text.sanitize_case_sense(keys[fingerprint]) + LOG.info(f'Loaded {len(keys)} keys') self._keys.update(keys) diff --git a/test/gpg-mailgate-daemon-test.conf b/test/gpg-mailgate-daemon-test.conf index 0ba4a52..303d3f3 100644 --- a/test/gpg-mailgate-daemon-test.conf +++ b/test/gpg-mailgate-daemon-test.conf @@ -6,6 +6,7 @@ date_format = ISO [gpg] keyhome = test/keyhome +cache_refresh_minutes = 1 [smime] cert_path = test/certs