🔒️(backend) enhance participant ID serialization in lobby per audit
Improve participant ID handling in lobby serialization following security auditor recommendations to prevent potential data exposure.
This commit is contained in:
committed by
aleb_the_flash
parent
64eadadaef
commit
1cd8fd2fc6
@@ -1,5 +1,7 @@
|
||||
"""Client serializers for the Meet core app."""
|
||||
|
||||
import uuid
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from rest_framework import serializers
|
||||
@@ -219,6 +221,14 @@ class ParticipantEntrySerializer(serializers.Serializer):
|
||||
participant_id = serializers.CharField(required=True)
|
||||
allow_entry = serializers.BooleanField(required=True)
|
||||
|
||||
def validate_participant_id(self, value):
|
||||
"""Validate that the participant_id is a valid UUID hex string."""
|
||||
try:
|
||||
uuid.UUID(hex=value, version=4)
|
||||
except (ValueError, TypeError) as e:
|
||||
raise serializers.ValidationError("Invalid UUID hex format") from e
|
||||
return value
|
||||
|
||||
def create(self, validated_data):
|
||||
"""Not implemented as this is a validation-only serializer."""
|
||||
raise NotImplementedError("ParticipantEntrySerializer is validation-only")
|
||||
|
||||
@@ -132,18 +132,18 @@ def test_request_entry_with_existing_participants(settings):
|
||||
|
||||
# Add two participants already waiting in the lobby
|
||||
cache.set(
|
||||
f"mocked-cache-prefix_{room.id}_participant1",
|
||||
f"mocked-cache-prefix_{room.id}_2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
{
|
||||
"id": "participant1",
|
||||
"id": "2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
"username": "user1",
|
||||
"status": "waiting",
|
||||
"color": "#123456",
|
||||
},
|
||||
)
|
||||
cache.set(
|
||||
f"mocked-cache-prefix_{room.id}_participant2",
|
||||
f"mocked-cache-prefix_{room.id}_f4ca3ab8a6c04ad88097b8da33f60f10",
|
||||
{
|
||||
"id": "participant2",
|
||||
"id": "f4ca3ab8a6c04ad88097b8da33f60f10",
|
||||
"username": "user2",
|
||||
"status": "accepted",
|
||||
"color": "#654321",
|
||||
@@ -257,7 +257,9 @@ def test_request_entry_authenticated_user_public_room(settings):
|
||||
with (
|
||||
mock.patch.object(LobbyService, "notify_participants", return_value=None),
|
||||
mock.patch.object(
|
||||
LobbyService, "_get_or_create_participant_id", return_value="123"
|
||||
LobbyService,
|
||||
"_get_or_create_participant_id",
|
||||
return_value="2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
),
|
||||
mock.patch.object(
|
||||
utils, "generate_livekit_config", return_value={"token": "test-token"}
|
||||
@@ -274,11 +276,11 @@ def test_request_entry_authenticated_user_public_room(settings):
|
||||
# Verify the lobby cookie was set
|
||||
cookie = response.cookies.get("mocked-cookie")
|
||||
assert cookie is not None
|
||||
assert cookie.value == "123"
|
||||
assert cookie.value == "2f7f162fe7d1421b90e702bfbfbf8def"
|
||||
|
||||
# Verify response content matches expected structure and values
|
||||
assert response.json() == {
|
||||
"id": "123",
|
||||
"id": "2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
"username": "test_user",
|
||||
"status": "accepted",
|
||||
"color": "mocked-color",
|
||||
@@ -300,9 +302,9 @@ def test_request_entry_waiting_participant_public_room(settings):
|
||||
|
||||
# Add a waiting participant to the room's lobby cache
|
||||
cache.set(
|
||||
f"mocked-cache-prefix_{room.id}_participant1",
|
||||
f"mocked-cache-prefix_{room.id}_2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
{
|
||||
"id": "participant1",
|
||||
"id": "2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
"username": "user1",
|
||||
"status": "waiting",
|
||||
"color": "#123456",
|
||||
@@ -310,7 +312,7 @@ def test_request_entry_waiting_participant_public_room(settings):
|
||||
)
|
||||
|
||||
# Simulate a browser with existing participant cookie
|
||||
client.cookies.load({"mocked-cookie": "participant1"})
|
||||
client.cookies.load({"mocked-cookie": "2f7f162fe7d1421b90e702bfbfbf8def"})
|
||||
|
||||
with (
|
||||
mock.patch.object(LobbyService, "notify_participants", return_value=None),
|
||||
@@ -328,11 +330,11 @@ def test_request_entry_waiting_participant_public_room(settings):
|
||||
# Verify the lobby cookie was set
|
||||
cookie = response.cookies.get("mocked-cookie")
|
||||
assert cookie is not None
|
||||
assert cookie.value == "participant1"
|
||||
assert cookie.value == "2f7f162fe7d1421b90e702bfbfbf8def"
|
||||
|
||||
# Verify response content matches expected structure and values
|
||||
assert response.json() == {
|
||||
"id": "participant1",
|
||||
"id": "2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
"username": "user1",
|
||||
"status": "accepted",
|
||||
"color": "#123456",
|
||||
@@ -379,7 +381,7 @@ def test_allow_participant_to_enter_anonymous():
|
||||
|
||||
response = client.post(
|
||||
f"/api/v1.0/rooms/{room.id}/enter/",
|
||||
{"participant_id": "test-id", "allow_entry": True},
|
||||
{"participant_id": "2f7f162fe7d1421b90e702bfbfbf8def", "allow_entry": True},
|
||||
)
|
||||
|
||||
assert response.status_code == 401
|
||||
@@ -394,7 +396,7 @@ def test_allow_participant_to_enter_non_owner():
|
||||
|
||||
response = client.post(
|
||||
f"/api/v1.0/rooms/{room.id}/enter/",
|
||||
{"participant_id": "test-id", "allow_entry": True},
|
||||
{"participant_id": "2f7f162fe7d1421b90e702bfbfbf8def", "allow_entry": True},
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
@@ -412,7 +414,7 @@ def test_allow_participant_to_enter_public_room():
|
||||
|
||||
response = client.post(
|
||||
f"/api/v1.0/rooms/{room.id}/enter/",
|
||||
{"participant_id": "test-id", "allow_entry": True},
|
||||
{"participant_id": "2f7f162fe7d1421b90e702bfbfbf8def", "allow_entry": True},
|
||||
)
|
||||
|
||||
assert response.status_code == 404
|
||||
@@ -435,9 +437,9 @@ def test_allow_participant_to_enter_success(settings, allow_entry, updated_statu
|
||||
settings.LOBBY_KEY_PREFIX = "mocked-cache-prefix"
|
||||
|
||||
cache.set(
|
||||
f"mocked-cache-prefix_{room.id!s}_participant1",
|
||||
f"mocked-cache-prefix_{room.id!s}_2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
{
|
||||
"id": "test-id",
|
||||
"id": "2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
"status": "waiting",
|
||||
"username": "foo",
|
||||
"color": "123",
|
||||
@@ -446,13 +448,18 @@ def test_allow_participant_to_enter_success(settings, allow_entry, updated_statu
|
||||
|
||||
response = client.post(
|
||||
f"/api/v1.0/rooms/{room.id}/enter/",
|
||||
{"participant_id": "participant1", "allow_entry": allow_entry},
|
||||
{
|
||||
"participant_id": "2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
"allow_entry": allow_entry,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"message": "Participant was updated."}
|
||||
|
||||
participant_data = cache.get(f"mocked-cache-prefix_{room.id!s}_participant1")
|
||||
participant_data = cache.get(
|
||||
f"mocked-cache-prefix_{room.id!s}_2f7f162fe7d1421b90e702bfbfbf8def"
|
||||
)
|
||||
assert participant_data.get("status") == updated_status
|
||||
|
||||
|
||||
@@ -468,12 +475,14 @@ def test_allow_participant_to_enter_participant_not_found(settings):
|
||||
|
||||
settings.LOBBY_KEY_PREFIX = "mocked-cache-prefix"
|
||||
|
||||
participant_data = cache.get(f"mocked-cache-prefix_{room.id!s}_test-id")
|
||||
participant_data = cache.get(
|
||||
f"mocked-cache-prefix_{room.id!s}_2f7f162fe7d1421b90e702bfbfbf8def"
|
||||
)
|
||||
assert participant_data is None
|
||||
|
||||
response = client.post(
|
||||
f"/api/v1.0/rooms/{room.id}/enter/",
|
||||
{"participant_id": "test-id", "allow_entry": True},
|
||||
{"participant_id": "2f7f162fe7d1421b90e702bfbfbf8def", "allow_entry": True},
|
||||
)
|
||||
|
||||
assert response.status_code == 404
|
||||
@@ -563,18 +572,18 @@ def test_list_waiting_participants_success(settings):
|
||||
|
||||
# Add participants in the lobby
|
||||
cache.set(
|
||||
f"mocked-cache-prefix_{room.id}_participant1",
|
||||
f"mocked-cache-prefix_{room.id}_2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
{
|
||||
"id": "participant1",
|
||||
"id": "2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
"username": "user1",
|
||||
"status": "waiting",
|
||||
"color": "#123456",
|
||||
},
|
||||
)
|
||||
cache.set(
|
||||
f"mocked-cache-prefix_{room.id}_participant2",
|
||||
f"mocked-cache-prefix_{room.id}_f4ca3ab8a6c04ad88097b8da33f60f10",
|
||||
{
|
||||
"id": "participant2",
|
||||
"id": "f4ca3ab8a6c04ad88097b8da33f60f10",
|
||||
"username": "user2",
|
||||
"status": "waiting",
|
||||
"color": "#654321",
|
||||
@@ -588,13 +597,13 @@ def test_list_waiting_participants_success(settings):
|
||||
participants = response.json().get("participants")
|
||||
assert sorted(participants, key=lambda p: p["id"]) == [
|
||||
{
|
||||
"id": "participant1",
|
||||
"id": "2f7f162fe7d1421b90e702bfbfbf8def",
|
||||
"username": "user1",
|
||||
"status": "waiting",
|
||||
"color": "#123456",
|
||||
},
|
||||
{
|
||||
"id": "participant2",
|
||||
"id": "f4ca3ab8a6c04ad88097b8da33f60f10",
|
||||
"username": "user2",
|
||||
"status": "waiting",
|
||||
"color": "#654321",
|
||||
|
||||
Reference in New Issue
Block a user