Ensure e2ee extension doesn't always return

This commit is contained in:
Erik Johnston
2026-05-20 14:09:37 +01:00
parent 0b910449ef
commit a5e6dd23da
2 changed files with 94 additions and 7 deletions
+4 -7
View File
@@ -301,15 +301,12 @@ class SlidingSyncResult:
# Also related:
# https://github.com/element-hq/element-android/issues/3725 and
# https://github.com/matrix-org/synapse/issues/10456
default_otk = self.device_one_time_keys_count.get("signed_curve25519")
more_than_default_otk = len(self.device_one_time_keys_count) > 1 or (
default_otk is not None and default_otk > 0
)
#
# This is why we don't incorporate `device_one_time_keys_count` into the
# `__bool__` check.
return bool(
more_than_default_otk
or self.device_list_updates
or self.device_unused_fallback_key_types
self.device_list_updates or self.device_unused_fallback_key_types
)
@attr.s(slots=True, frozen=True, auto_attribs=True)
@@ -290,6 +290,96 @@ class SlidingSyncE2eeExtensionTestCase(SlidingSyncBase):
[],
)
def test_wait_for_new_data_timeout_with_otks(self) -> None:
"""
Test that an incremental Sliding Sync with the e2ee extension enabled
does not return immediately when the user has uploaded one-time keys
(i.e. `device_one_time_keys_count` contains entries beyond the default
`signed_curve25519: 0`).
"""
test_device_id = "TESTDEVICE"
user1_id = self.register_user("user1", "pass")
user1_tok = self.login(user1_id, "pass", device_id=test_device_id)
# Upload one-time keys for the user/device so that
# `device_one_time_keys_count` is non-default in the response.
self.get_success(
self.e2e_keys_handler.upload_keys_for_user(
user1_id,
test_device_id,
{
"one_time_keys": {
"alg1:k1": "key1",
"alg2:k2": {"key": "key2", "signatures": {"k1": "sig1"}},
}
},
)
)
sync_body = {
"lists": {},
"extensions": {
"e2ee": {
"enabled": True,
}
},
}
_, from_token = self.do_sync(sync_body, tok=user1_tok)
# Make an incremental Sliding Sync request with a timeout
channel = self.make_request(
"POST",
self.sync_endpoint + f"?timeout=10000&pos={from_token}",
content=sync_body,
access_token=user1_tok,
await_result=False,
)
# Block for 5 seconds to make sure we are `notifier.wait_for_events(...)`
with self.assertRaises(TimedOutException):
channel.await_result(timeout_ms=5000)
# Wake-up `notifier.wait_for_events(...)` that will cause us to test
# `SlidingSyncResult.__bool__` for new results. The non-default
# `device_one_time_keys_count` must not be considered new data.
self._bump_notifier_wait_for_events(
user1_id, wake_stream_key=StreamKeyType.ACCOUNT_DATA
)
# Block for a little bit more to ensure we don't see any new results.
with self.assertRaises(TimedOutException):
channel.await_result(timeout_ms=4000)
# Wait for the sync to complete (wait for the rest of the 10 second timeout,
# 5000 + 4000 + 1200 > 10000)
channel.await_result(timeout_ms=1200)
self.assertEqual(channel.code, 200, channel.json_body)
# Device lists are present for incremental syncs but empty because no device changes
self.assertEqual(
channel.json_body["extensions"]["e2ee"]
.get("device_lists", {})
.get("changed"),
[],
)
self.assertEqual(
channel.json_body["extensions"]["e2ee"].get("device_lists", {}).get("left"),
[],
)
# The one-time key counts are present, but they should not have caused
# the sync to return early.
self.assertEqual(
channel.json_body["extensions"]["e2ee"]["device_one_time_keys_count"],
{
"alg1": 1,
"alg2": 1,
"signed_curve25519": 0,
},
)
self.assertEqual(
channel.json_body["extensions"]["e2ee"]["device_unused_fallback_key_types"],
[],
)
def test_device_lists(self) -> None:
"""
Test that device list updates are included in the response