fix(e2ee): extend key rotation wait to 10s, debug late key events

EC rotates encryption key when bot joins LiveKit room. The rotated
key arrives via Matrix sync 3-5s later. Previous 2s wait was too
short - DEC_FAILED before new key arrived.

Extended wait to 10s. Added logging to bot.py to trace why late
key events were not being processed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Christian Gick
2026-02-22 21:54:27 +02:00
parent 230c083b7b
commit 4b4a150fbf
2 changed files with 39 additions and 12 deletions

View File

@@ -520,19 +520,38 @@ class VoiceSession:
# and call on_encryption_key(), which updates self._caller_all_keys.
# NOTE: HTTP fetch is useless here — keys are Matrix-E2EE encrypted (m.room.encrypted).
pre_max_idx = max(self._caller_all_keys.keys()) if self._caller_all_keys else -1
logger.info("Waiting for EC key rotation via nio sync (current max_idx=%d)...", pre_max_idx)
for _attempt in range(4): # up to 2s (4 × 0.5s)
pre_key_count = len(self._caller_all_keys)
logger.info("Waiting for EC key rotation via nio sync (current max_idx=%d, keys=%d)...",
pre_max_idx, pre_key_count)
for _attempt in range(20): # up to 10s (20 × 0.5s)
await asyncio.sleep(0.5)
new_max = max(self._caller_all_keys.keys()) if self._caller_all_keys else -1
if new_max > pre_max_idx:
new_count = len(self._caller_all_keys)
# Detect rotation: new index OR new key bytes at existing index
if new_max > pre_max_idx or new_count > pre_key_count:
self._caller_key = self._caller_all_keys[new_max]
logger.info("Key rotated: index %d%d (%d bytes)",
pre_max_idx, new_max, len(self._caller_key))
logger.info("Key rotated: index %d%d, count %d%d (%d bytes, raw=%s)",
pre_max_idx, new_max, pre_key_count, new_count,
len(self._caller_key), self._caller_key.hex())
# Re-set all keys on the frame cryptor
if self._caller_identity:
for p in self.lk_room.remote_participants.values():
if p.identity == self._caller_identity:
try:
kp_rot = self.lk_room.e2ee_manager.key_provider
for idx, k in sorted(self._caller_all_keys.items()):
kp_rot.set_key(p.identity, k, idx)
logger.info("Rotation set_key[%d] for %s (%d bytes, raw=%s)",
idx, p.identity, len(k), k.hex())
except Exception as e:
logger.warning("Rotation set_key failed: %s", e)
break
break
if _attempt % 2 == 1: # log every 1s
logger.info("Key rotation wait %0.1fs: max_idx still %d", (_attempt + 1) * 0.5, new_max)
if _attempt % 4 == 3: # log every 2s
logger.info("Key rotation wait %0.1fs: max_idx still %d, keys=%d",
(_attempt + 1) * 0.5, new_max, new_count)
else:
logger.warning("No key rotation after 2s — using pre-join key[%d]", pre_max_idx)
logger.warning("No key rotation after 10s — using pre-join key[%d]", pre_max_idx)
# Find the remote participant, wait up to 10s if not yet connected
remote_identity = None