forked from Disroot/gpg-lacre
Reload keyring on filesystem events
Subscribe to FS events from keyring directory using Python Watchdog and when a modification is observed, reload the key cache. Since we may receive more than one event about a single modification, keep directory's last modification to recognise 'false positives'.
This commit is contained in:
parent
386c23f9f8
commit
eb0d5a1326
|
@ -9,6 +9,7 @@ from aiosmtpd.smtp import Envelope
|
|||
import asyncio
|
||||
import email
|
||||
import time
|
||||
from watchdog.observers import Observer
|
||||
|
||||
# Mail status constants.
|
||||
#
|
||||
|
@ -59,6 +60,13 @@ def _init_controller(keys: kcache.KeyCache, tout: float = 2.5):
|
|||
return Controller(proxy, hostname=host, port=port, ready_timeout=tout)
|
||||
|
||||
|
||||
def _init_reloader(keyring_dir: str, reloader) -> kcache.KeyringModificationListener:
|
||||
listener = kcache.KeyringModificationListener(reloader)
|
||||
observer = Observer()
|
||||
observer.schedule(listener, keyring_dir, recursive=False)
|
||||
return observer
|
||||
|
||||
|
||||
def _validate_config():
|
||||
missing = conf.validate_config()
|
||||
if missing:
|
||||
|
@ -71,10 +79,9 @@ def _full_param_name(tup):
|
|||
return f"[{tup[0]}]{tup[1]}"
|
||||
|
||||
|
||||
async def _sleep(minutes, heartbeat_func):
|
||||
async def _sleep(minutes):
|
||||
while True:
|
||||
await asyncio.sleep(minutes * 60)
|
||||
heartbeat_func()
|
||||
|
||||
|
||||
def _main():
|
||||
|
@ -82,18 +89,26 @@ def _main():
|
|||
|
||||
refresh_min = float(conf.get_item('gpg', 'cache_refresh_minutes', 2))
|
||||
|
||||
keys = kcache.KeyCache(conf.get_item('gpg', 'keyhome'))
|
||||
keyring_path = conf.get_item('gpg', 'keyhome')
|
||||
keys = kcache.KeyCache(keyring_path)
|
||||
keys.load()
|
||||
controller = _init_controller(keys)
|
||||
reloader = _init_reloader(keyring_path, keys)
|
||||
|
||||
LOG.info("Starting the daemon...")
|
||||
LOG.info(f'Watching keyring directory {keyring_path}...')
|
||||
reloader.start()
|
||||
|
||||
LOG.info('Starting the daemon...')
|
||||
controller.start()
|
||||
|
||||
try:
|
||||
asyncio.run(_sleep(refresh_min, keys.load))
|
||||
asyncio.run(_sleep(refresh_min))
|
||||
except KeyboardInterrupt:
|
||||
LOG.info("Finishing...")
|
||||
|
||||
finally:
|
||||
LOG.info('Shutting down keyring watcher and the daemon...')
|
||||
reloader.stop()
|
||||
reloader.join()
|
||||
controller.stop()
|
||||
|
||||
LOG.info("Done")
|
||||
|
|
|
@ -7,6 +7,7 @@ module.
|
|||
import lacre.text as text
|
||||
import logging
|
||||
from os import stat
|
||||
from watchdog.events import FileSystemEventHandler
|
||||
|
||||
import GnuPG
|
||||
|
||||
|
@ -107,3 +108,21 @@ class KeyCache:
|
|||
MTIME = 8
|
||||
st = stat(self._keyring_dir)
|
||||
return st[MTIME]
|
||||
|
||||
|
||||
class KeyringModificationListener(FileSystemEventHandler):
|
||||
"""A filesystem event listener that triggers key cache reload."""
|
||||
|
||||
def __init__(self, cache: KeyCache):
|
||||
"""Initialise a listener with a callback to be executed upon each change."""
|
||||
self._cache = cache
|
||||
|
||||
def handle(self, event):
|
||||
"""Reload keys upon FS event."""
|
||||
LOG.debug(f'Reloading on event {event!r}')
|
||||
self._cache.reload()
|
||||
|
||||
# All methods should do the same: reload the key cache.
|
||||
# on_created = handle
|
||||
# on_deleted = handle
|
||||
on_modified = handle
|
||||
|
|
Loading…
Reference in a new issue