fix(matrix): persist E2EE crypto store and fix decrypted event dedup

Address two bugs found by code review:

1. MemoryCryptoStore loses all E2EE keys on restart — now pickle the
   store to disk on disconnect and restore on connect, preserving
   Megolm sessions across restarts.

2. Encrypted events buffered for retry were silently dropped after
   decryption because _on_encrypted_event registered the event ID
   in the dedup set, then _on_room_message rejected it as a
   duplicate. Now clear the dedup entry before routing decrypted
   events.
This commit is contained in:
alt-glitch
2026-04-11 07:29:27 +05:30
committed by Teknium
parent d5be23aed7
commit 1f3f120042

View File

@@ -296,6 +296,20 @@ class MatrixAdapter(BasePlatformAdapter):
from mautrix.crypto.store import MemoryCryptoStore
crypto_store = MemoryCryptoStore()
# Restore persisted crypto state from a previous run.
pickle_path = _STORE_DIR / "crypto_store.pickle"
if pickle_path.exists():
try:
import pickle
with open(pickle_path, "rb") as f:
saved = pickle.load(f) # noqa: S301 — trusted local file
if isinstance(saved, MemoryCryptoStore):
crypto_store = saved
logger.info("Matrix: restored E2EE crypto store from %s", pickle_path)
except Exception as exc:
logger.warning("Matrix: could not restore crypto store: %s", exc)
olm = OlmMachine(client, crypto_store, state_store)
# Set trust policy: accept unverified devices so senders
@@ -371,6 +385,20 @@ class MatrixAdapter(BasePlatformAdapter):
except (asyncio.CancelledError, Exception):
pass
# Persist E2EE crypto store before closing so the next restart
# can decrypt events using sessions from this run.
if self._client and self._encryption and getattr(self._client, "crypto", None):
try:
import pickle
crypto_store = self._client.crypto.crypto_store
_STORE_DIR.mkdir(parents=True, exist_ok=True)
pickle_path = _STORE_DIR / "crypto_store.pickle"
with open(pickle_path, "wb") as f:
pickle.dump(crypto_store, f)
logger.info("Matrix: persisted E2EE crypto store to %s", pickle_path)
except Exception as exc:
logger.debug("Matrix: could not persist crypto store on disconnect: %s", exc)
if self._client:
try:
await self._client.api.session.close()
@@ -804,6 +832,11 @@ class MatrixAdapter(BasePlatformAdapter):
)
# Route to the appropriate handler.
# Remove from dedup set so _on_room_message doesn't drop it
# (the encrypted event ID was already registered by _on_encrypted_event).
decrypted_id = str(getattr(decrypted, "event_id", getattr(event, "event_id", "")))
if decrypted_id:
self._processed_events_set.discard(decrypted_id)
try:
await self._on_room_message(decrypted)
except Exception as exc: