fix(e2ee): switch to PR #921 Rust FFI branch for native HKDF (MAT-144)
PR #904 callback-based HKDF hack only fired for the first frame cryptor (audio), leaving video frame cryptors with PBKDF2 - DEC_FAILED oscillation. PR #921 integrates HKDF natively at the WebRTC C++ level, applying uniformly to all frame cryptors (audio + video). Also removes aggressive video re-keying workaround and adds 5s cooldown to DEC_FAILED re-keying handler to prevent tight loops. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
29
voice.py
29
voice.py
@@ -695,23 +695,6 @@ class VoiceSession:
|
||||
_derive_and_set_key(kp_local, caller_id, base_k, idx)
|
||||
logger.info("on_ts: set key[%d] for %s (%s track)",
|
||||
idx, caller_id, track_type)
|
||||
# MAT-144: Video frame cryptors may not be fully initialized
|
||||
# when set_key is first called. Schedule aggressive re-keying.
|
||||
if int(t.kind) == 2:
|
||||
async def _video_rekey(pid=caller_id):
|
||||
for delay in (0.3, 0.8, 2.0, 5.0):
|
||||
await asyncio.sleep(delay)
|
||||
if not self.lk_room:
|
||||
break
|
||||
try:
|
||||
kp_v = self.lk_room.e2ee_manager.key_provider
|
||||
for idx, base_k in sorted(self._caller_all_keys.items()):
|
||||
_derive_and_set_key(kp_v, pid, base_k, idx)
|
||||
logger.info("video_rekey: re-set %d keys for %s (delay=%.1fs)",
|
||||
len(self._caller_all_keys), pid, delay)
|
||||
except Exception as exc:
|
||||
logger.warning("video_rekey failed: %s", exc)
|
||||
asyncio.ensure_future(_video_rekey())
|
||||
else:
|
||||
logger.warning("on_ts: no caller keys yet — scheduling 0.5s retry")
|
||||
async def _brief_key_retry(pid=caller_id):
|
||||
@@ -731,19 +714,27 @@ class VoiceSession:
|
||||
logger.warning("on_ts: set_key failed: %s", exc)
|
||||
|
||||
_e2ee_state_names = {0:"NEW",1:"OK",2:"ENC_FAILED",3:"DEC_FAILED",4:"MISSING_KEY",5:"RATCHETED",6:"INTERNAL_ERR"}
|
||||
_last_rekey_time = {} # per-participant cooldown for DEC_FAILED re-keying
|
||||
@self.lk_room.on("e2ee_state_changed")
|
||||
def on_e2ee_state(participant, state):
|
||||
state_name = _e2ee_state_names.get(int(state), f"UNKNOWN_{state}")
|
||||
p_id = participant.identity if participant else "local"
|
||||
logger.info("E2EE_STATE: participant=%s state=%s", p_id, state_name)
|
||||
# When remote participant frame cryptor is NEW or MISSING_KEY → set their key
|
||||
# When remote participant needs key: NEW, MISSING_KEY, or DEC_FAILED (with cooldown)
|
||||
if participant and p_id != bot_identity and int(state) in (0, 3, 4):
|
||||
now = time.monotonic()
|
||||
# DEC_FAILED: only re-key every 5s to avoid tight loops
|
||||
if int(state) == 3:
|
||||
last = _last_rekey_time.get(p_id, 0)
|
||||
if (now - last) < 5.0:
|
||||
return
|
||||
_last_rekey_time[p_id] = now
|
||||
if self._caller_all_keys:
|
||||
try:
|
||||
kp_e = self.lk_room.e2ee_manager.key_provider
|
||||
for idx, base_k in sorted(self._caller_all_keys.items()):
|
||||
_derive_and_set_key(kp_e, p_id, base_k, idx)
|
||||
logger.info("e2ee_state: derived+set key[%d] for %s on %s",
|
||||
logger.info("e2ee_state: set key[%d] for %s on %s",
|
||||
idx, p_id, state_name)
|
||||
except Exception as exc:
|
||||
logger.warning("e2ee_state set_key failed: %s", exc)
|
||||
|
||||
Reference in New Issue
Block a user