fix: handle Element X MSC4143 v2 encryption key format (memberships array)
Element X embeds E2EE keys inside memberships[].encryption_keys, not at the top level of the call.member state event content. Bot was only checking content.encryption_keys, so it never found the caller's key — causing 'Warten auf Medien' (waiting for media) because encrypted audio couldn't be decrypted. - Added _extract_enc_keys_from_content() helper handling both formats - Updated on_unknown handler, VoiceSession creation, and key fetch - Bot now publishes keys in both formats for compatibility - Updated voice.py state fetch to check memberships[] fallback Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
14
voice.py
14
voice.py
@@ -554,6 +554,7 @@ class VoiceSession:
|
||||
user_id = self.nio_client.user_id
|
||||
|
||||
# MSC4143: check call.member state events first
|
||||
# Handles both top-level encryption_keys and memberships[].encryption_keys (Element X)
|
||||
try:
|
||||
state_url = f"{homeserver}/_matrix/client/v3/rooms/{self.room_id}/state"
|
||||
async with httpx.AsyncClient(timeout=10.0) as http:
|
||||
@@ -566,7 +567,17 @@ class VoiceSession:
|
||||
if sender == user_id:
|
||||
continue
|
||||
content = evt.get("content", {})
|
||||
# Extract keys from both formats
|
||||
enc_keys = content.get("encryption_keys", [])
|
||||
# MSC4143 v2 / Element X: keys inside memberships array
|
||||
if not enc_keys:
|
||||
for m in content.get("memberships", []):
|
||||
m_keys = m.get("encryption_keys", [])
|
||||
if m_keys:
|
||||
enc_keys = m_keys
|
||||
# Use device_id from membership entry
|
||||
content = {**content, "device_id": m.get("device_id", content.get("device_id", ""))}
|
||||
break
|
||||
if enc_keys:
|
||||
device = content.get("device_id", "")
|
||||
import base64 as b64
|
||||
@@ -581,7 +592,8 @@ class VoiceSession:
|
||||
self.on_encryption_key(sender, device, key_bytes, key_index)
|
||||
max_idx = max(self._caller_all_keys.keys()) if self._caller_all_keys else key_index
|
||||
latest = self._caller_all_keys.get(max_idx, key_bytes)
|
||||
logger.info("Got key from call.member state (sender=%s, index=%d)", sender, key_index)
|
||||
logger.info("Got key from call.member state (sender=%s, device=%s, index=%d)",
|
||||
sender, device, key_index)
|
||||
return latest
|
||||
except Exception as e:
|
||||
logger.debug("call.member state key fetch failed: %s", e)
|
||||
|
||||
Reference in New Issue
Block a user