Skip to content

Commit 3b2d92d

Browse files
fix the e2ee missing fields problems
1 parent a143eb3 commit 3b2d92d

5 files changed

Lines changed: 236 additions & 1 deletion

File tree

livekit-rtc/livekit/rtc/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"""
2020

2121
from ._proto import stats_pb2 as stats
22-
from ._proto.e2ee_pb2 import EncryptionState, EncryptionType
22+
from ._proto.e2ee_pb2 import EncryptionState, EncryptionType, KeyDerivationFunction
2323
from ._proto.participant_pb2 import ParticipantKind, ParticipantState, DisconnectReason
2424
from ._proto.room_pb2 import (
2525
ConnectionQuality,
@@ -129,6 +129,7 @@
129129
"IceServer",
130130
"EncryptionType",
131131
"EncryptionState",
132+
"KeyDerivationFunction",
132133
"StreamState",
133134
"TrackKind",
134135
"TrackSource",

livekit-rtc/livekit/rtc/e2ee.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
DEFAULT_RATCHET_SALT = b"LKFrameEncryptionKey"
2323
DEFAULT_RATCHET_WINDOW_SIZE = 16
2424
DEFAULT_FAILURE_TOLERANCE = -1
25+
DEFAULT_KEY_RING_SIZE = 16
2526

2627

2728
@dataclass
@@ -30,6 +31,10 @@ class KeyProviderOptions:
3031
ratchet_salt: bytes = DEFAULT_RATCHET_SALT
3132
ratchet_window_size: int = DEFAULT_RATCHET_WINDOW_SIZE
3233
failure_tolerance: int = DEFAULT_FAILURE_TOLERANCE
34+
key_ring_size: int = DEFAULT_KEY_RING_SIZE
35+
key_derivation_function: proto_e2ee.KeyDerivationFunction.ValueType = (
36+
proto_e2ee.KeyDerivationFunction.PBKDF2
37+
)
3338

3439

3540
@dataclass

livekit-rtc/livekit/rtc/room.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,12 @@ def on_participant_connected(participant):
472472
req.connect.options.e2ee.key_provider_options.ratchet_window_size = (
473473
options.e2ee.key_provider_options.ratchet_window_size
474474
)
475+
req.connect.options.e2ee.key_provider_options.key_ring_size = (
476+
options.e2ee.key_provider_options.key_ring_size
477+
)
478+
req.connect.options.e2ee.key_provider_options.key_derivation_function = (
479+
options.e2ee.key_provider_options.key_derivation_function
480+
)
475481

476482
if options.encryption:
477483
req.connect.options.encryption.encryption_type = options.encryption.encryption_type
@@ -487,6 +493,12 @@ def on_participant_connected(participant):
487493
req.connect.options.encryption.key_provider_options.ratchet_window_size = (
488494
options.encryption.key_provider_options.ratchet_window_size
489495
)
496+
req.connect.options.encryption.key_provider_options.key_ring_size = (
497+
options.encryption.key_provider_options.key_ring_size
498+
)
499+
req.connect.options.encryption.key_provider_options.key_derivation_function = (
500+
options.encryption.key_provider_options.key_derivation_function
501+
)
490502

491503
if options.rtc_config:
492504
req.connect.options.rtc_config.ice_transport_type = (

livekit-rtc/tests/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2023 LiveKit, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.

livekit-rtc/tests/test_e2ee.py

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# Copyright 2023 LiveKit, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Unit tests for E2EE functionality."""
16+
17+
import pytest
18+
19+
20+
class TestKeyProviderOptions:
21+
"""Tests for KeyProviderOptions dataclass."""
22+
23+
def test_default_values(self):
24+
"""Test that KeyProviderOptions has correct default values."""
25+
from livekit.rtc.e2ee import (
26+
KeyProviderOptions,
27+
DEFAULT_RATCHET_SALT,
28+
DEFAULT_RATCHET_WINDOW_SIZE,
29+
DEFAULT_FAILURE_TOLERANCE,
30+
DEFAULT_KEY_RING_SIZE,
31+
)
32+
from livekit.rtc._proto import e2ee_pb2 as proto_e2ee
33+
34+
options = KeyProviderOptions()
35+
36+
assert options.shared_key is None
37+
assert options.ratchet_salt == DEFAULT_RATCHET_SALT
38+
assert options.ratchet_window_size == DEFAULT_RATCHET_WINDOW_SIZE
39+
assert options.failure_tolerance == DEFAULT_FAILURE_TOLERANCE
40+
assert options.key_ring_size == DEFAULT_KEY_RING_SIZE
41+
assert options.key_derivation_function == proto_e2ee.KeyDerivationFunction.PBKDF2
42+
43+
def test_custom_values(self):
44+
"""Test KeyProviderOptions with custom values."""
45+
from livekit.rtc.e2ee import KeyProviderOptions
46+
from livekit.rtc._proto import e2ee_pb2 as proto_e2ee
47+
48+
options = KeyProviderOptions(
49+
shared_key=b"my-secret-key",
50+
ratchet_salt=b"custom-salt",
51+
ratchet_window_size=32,
52+
failure_tolerance=5,
53+
key_ring_size=8,
54+
key_derivation_function=proto_e2ee.KeyDerivationFunction.HKDF,
55+
)
56+
57+
assert options.shared_key == b"my-secret-key"
58+
assert options.ratchet_salt == b"custom-salt"
59+
assert options.ratchet_window_size == 32
60+
assert options.failure_tolerance == 5
61+
assert options.key_ring_size == 8
62+
assert options.key_derivation_function == proto_e2ee.KeyDerivationFunction.HKDF
63+
64+
def test_various_key_lengths(self):
65+
"""Test that shared_key accepts various lengths."""
66+
from livekit.rtc.e2ee import KeyProviderOptions
67+
68+
# Short key
69+
options_short = KeyProviderOptions(shared_key=b"short")
70+
assert options_short.shared_key == b"short"
71+
72+
# Medium key
73+
options_medium = KeyProviderOptions(shared_key=b"medium-length-key-here")
74+
assert options_medium.shared_key == b"medium-length-key-here"
75+
76+
# Long key
77+
long_key = b"a" * 256
78+
options_long = KeyProviderOptions(shared_key=long_key)
79+
assert options_long.shared_key == long_key
80+
81+
# Binary key
82+
binary_key = bytes(range(256))
83+
options_binary = KeyProviderOptions(shared_key=binary_key)
84+
assert options_binary.shared_key == binary_key
85+
86+
87+
class TestE2EEOptions:
88+
"""Tests for E2EEOptions dataclass."""
89+
90+
def test_default_values(self):
91+
"""Test E2EEOptions default values."""
92+
from livekit.rtc.e2ee import E2EEOptions, KeyProviderOptions
93+
from livekit.rtc._proto import e2ee_pb2 as proto_e2ee
94+
95+
options = E2EEOptions()
96+
97+
assert isinstance(options.key_provider_options, KeyProviderOptions)
98+
assert options.encryption_type == proto_e2ee.EncryptionType.GCM
99+
100+
def test_with_shared_key(self):
101+
"""Test E2EEOptions with a shared key."""
102+
from livekit.rtc.e2ee import E2EEOptions, KeyProviderOptions
103+
104+
key_options = KeyProviderOptions(shared_key=b"test-key")
105+
options = E2EEOptions(key_provider_options=key_options)
106+
107+
assert options.key_provider_options.shared_key == b"test-key"
108+
109+
110+
class TestProtoMessageBuilding:
111+
"""Tests for proto message building with E2EE options."""
112+
113+
def test_proto_key_provider_options_fields(self):
114+
"""Test that proto KeyProviderOptions has all required fields."""
115+
from livekit.rtc._proto import e2ee_pb2 as proto_e2ee
116+
117+
proto_options = proto_e2ee.KeyProviderOptions()
118+
119+
# Set all fields that should be present
120+
proto_options.shared_key = b"test-key"
121+
proto_options.ratchet_window_size = 16
122+
proto_options.ratchet_salt = b"LKFrameEncryptionKey"
123+
proto_options.failure_tolerance = -1
124+
proto_options.key_ring_size = 16
125+
proto_options.key_derivation_function = proto_e2ee.KeyDerivationFunction.PBKDF2
126+
127+
# Verify fields are set correctly
128+
assert proto_options.shared_key == b"test-key"
129+
assert proto_options.ratchet_window_size == 16
130+
assert proto_options.ratchet_salt == b"LKFrameEncryptionKey"
131+
assert proto_options.failure_tolerance == -1
132+
assert proto_options.key_ring_size == 16
133+
assert proto_options.key_derivation_function == proto_e2ee.KeyDerivationFunction.PBKDF2
134+
135+
def test_proto_serialization(self):
136+
"""Test that proto message can be serialized without errors."""
137+
from livekit.rtc._proto import e2ee_pb2 as proto_e2ee
138+
139+
proto_options = proto_e2ee.KeyProviderOptions()
140+
proto_options.ratchet_window_size = 16
141+
proto_options.ratchet_salt = b"LKFrameEncryptionKey"
142+
proto_options.failure_tolerance = -1
143+
proto_options.key_ring_size = 16
144+
proto_options.key_derivation_function = proto_e2ee.KeyDerivationFunction.PBKDF2
145+
146+
# This should not raise an EncodeError
147+
serialized = proto_options.SerializeToString()
148+
assert len(serialized) > 0
149+
150+
# Verify we can deserialize it back
151+
parsed = proto_e2ee.KeyProviderOptions()
152+
parsed.ParseFromString(serialized)
153+
assert parsed.key_ring_size == 16
154+
assert parsed.key_derivation_function == proto_e2ee.KeyDerivationFunction.PBKDF2
155+
156+
def test_e2ee_options_proto_serialization(self):
157+
"""Test full E2eeOptions proto serialization."""
158+
from livekit.rtc._proto import e2ee_pb2 as proto_e2ee
159+
160+
e2ee_opts = proto_e2ee.E2eeOptions()
161+
e2ee_opts.encryption_type = proto_e2ee.EncryptionType.GCM
162+
e2ee_opts.key_provider_options.shared_key = b"my-shared-key"
163+
e2ee_opts.key_provider_options.ratchet_window_size = 16
164+
e2ee_opts.key_provider_options.ratchet_salt = b"LKFrameEncryptionKey"
165+
e2ee_opts.key_provider_options.failure_tolerance = -1
166+
e2ee_opts.key_provider_options.key_ring_size = 16
167+
e2ee_opts.key_provider_options.key_derivation_function = (
168+
proto_e2ee.KeyDerivationFunction.PBKDF2
169+
)
170+
171+
# This should not raise an EncodeError
172+
serialized = e2ee_opts.SerializeToString()
173+
assert len(serialized) > 0
174+
175+
176+
class TestPublicExports:
177+
"""Tests for public API exports."""
178+
179+
def test_key_derivation_function_exported(self):
180+
"""Test that KeyDerivationFunction is exported from the package."""
181+
from livekit.rtc import KeyDerivationFunction
182+
183+
# Verify enum values are accessible
184+
assert KeyDerivationFunction.PBKDF2 == 0
185+
assert KeyDerivationFunction.HKDF == 1
186+
187+
def test_encryption_type_exported(self):
188+
"""Test that EncryptionType is exported from the package."""
189+
from livekit.rtc import EncryptionType
190+
191+
assert EncryptionType.NONE == 0
192+
assert EncryptionType.GCM == 1
193+
assert EncryptionType.CUSTOM == 2
194+
195+
def test_e2ee_classes_exported(self):
196+
"""Test that E2EE classes are exported from the package."""
197+
from livekit.rtc import E2EEOptions, KeyProviderOptions
198+
199+
# Should be able to instantiate without errors
200+
key_opts = KeyProviderOptions()
201+
e2ee_opts = E2EEOptions()
202+
203+
assert key_opts is not None
204+
assert e2ee_opts is not None

0 commit comments

Comments
 (0)