🔒️(backend) verify participant presence before mute operations

Ensure the participant requesting a mute action is still present
in the room before processing the request.

This mitigates scenarios where a previously issued token could be
reused after the meeting has ended.

Current token lifetime is intentionally long-lived and will be
refactored in the future to better align with LiveKit session
constraints. In the meantime, add this extra validation step to
reduce the attack surface.
This commit is contained in:
lebaudantoine
2026-05-17 23:18:08 +02:00
committed by aleb_the_flash
parent 81e3483f28
commit 385da86759
3 changed files with 199 additions and 1 deletions
@@ -15,6 +15,7 @@ from livekit.api import (
TwirpError,
UpdateParticipantRequest,
)
from livekit.protocol.models import ParticipantInfo
from core import utils
@@ -154,3 +155,44 @@ class ParticipantsManagement:
finally:
await lkapi.aclose()
@async_to_sync
async def check_if_in_meeting(self, room_name: str, identity: str) -> bool:
"""Check whether `identity` is currently a participant in `room_name`.
Raises ParticipantsManagementException for unexpected LiveKit errors
so callers can fail closed rather than silently allowing the action.
"""
if not room_name or not identity:
return False
lkapi = utils.create_livekit_client()
try:
participant = await lkapi.room.get_participant(
RoomParticipantIdentity(
room=room_name,
identity=identity,
)
)
except TwirpError as e:
if e.code == "not_found":
raise ParticipantNotFoundException("Participant does not exist") from e
logger.exception(
"Unexpected error checking participant %s in room %s",
identity,
room_name,
)
raise ParticipantsManagementException(
"Could not verify participant presence"
) from e
finally:
await lkapi.aclose()
return (
participant is not None
and participant.state != ParticipantInfo.State.DISCONNECTED
)