From 44088bd4af49411febf0a80b1571e2f6174fd25c Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 6 Jun 2024 17:40:16 -0500 Subject: [PATCH] Add `is_encrypted` filtering to Sliding Sync `/sync` Based on [MSC3575](https://github.com/matrix-org/matrix-spec-proposals/pull/3575): Sliding Sync --- changelog.d/17249.feature | 1 + synapse/handlers/sliding_sync.py | 21 ++++++++-- tests/handlers/test_sliding_sync.py | 65 +++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 changelog.d/17249.feature diff --git a/changelog.d/17249.feature b/changelog.d/17249.feature new file mode 100644 index 0000000000..fce512692c --- /dev/null +++ b/changelog.d/17249.feature @@ -0,0 +1 @@ +Add `is_encrypted` filtering to experimental [MSC3575](https://github.com/matrix-org/matrix-spec-proposals/pull/3575) Sliding Sync `/sync` endpoint. diff --git a/synapse/handlers/sliding_sync.py b/synapse/handlers/sliding_sync.py index 08c6aadff6..ecd41d3ece 100644 --- a/synapse/handlers/sliding_sync.py +++ b/synapse/handlers/sliding_sync.py @@ -31,7 +31,7 @@ if TYPE_CHECKING or HAS_PYDANTIC_V2: else: from pydantic import Extra -from synapse.api.constants import AccountDataTypes, Membership +from synapse.api.constants import AccountDataTypes, EventTypes, Membership from synapse.events import EventBase from synapse.rest.client.models import SlidingSyncBody from synapse.types import JsonMapping, Requester, RoomStreamToken, StreamToken, UserID @@ -661,8 +661,23 @@ class SlidingSyncHandler: if filters.spaces: raise NotImplementedError() - if filters.is_encrypted: - raise NotImplementedError() + # Filter for encrypted rooms + if filters.is_encrypted is not None: + # Make a copy so we don't run into an error: `Set changed size during iteration` + for room_id in list(filtered_room_id_set): + # TODO: Is there a good method to look up all rooms at once? (N+1 query problem) + is_encrypted = ( + await self.storage_controllers.state.get_current_state_event( + room_id, EventTypes.RoomEncryption, "" + ) + ) + + # If we're looking for encrypted rooms, filter out rooms that are not + # encrypted and vice versa + if (filters.is_encrypted and not is_encrypted) or ( + not filters.is_encrypted and is_encrypted + ): + filtered_room_id_set.remove(room_id) if filters.is_invite: raise NotImplementedError() diff --git a/tests/handlers/test_sliding_sync.py b/tests/handlers/test_sliding_sync.py index 621b554be6..599e3dbc10 100644 --- a/tests/handlers/test_sliding_sync.py +++ b/tests/handlers/test_sliding_sync.py @@ -1246,3 +1246,68 @@ class FilterRoomsTestCase(HomeserverTestCase): ) self.assertEqual(falsy_filtered_room_ids, {room_id}) + + def test_filter_encrypted_rooms(self) -> None: + """ + Test `filter.is_encrypted` for encrypted rooms + """ + user1_id = self.register_user("user1", "pass") + user1_tok = self.login(user1_id, "pass") + + # Create a normal room + room_id = self.helper.create_room_as( + user1_id, + is_public=False, + tok=user1_tok, + ) + + # Create an encrypted room + encrypted_room_id = self.helper.create_room_as( + user1_id, + is_public=False, + tok=user1_tok, + ) + self.helper.send_state( + encrypted_room_id, + EventTypes.RoomEncryption, + {"algorithm": "m.megolm.v1.aes-sha2"}, + tok=user1_tok, + ) + + # TODO: Better way to avoid the circular import? (see + # https://github.com/element-hq/synapse/pull/17187#discussion_r1619492779) + from synapse.handlers.sliding_sync import SlidingSyncConfig + + # Try with `is_encrypted=True` + # ----------------------------- + truthy_filters = SlidingSyncConfig.SlidingSyncList.Filters( + is_encrypted=True, + ) + + # Filter the rooms + truthy_filtered_room_ids = self.get_success( + self.sliding_sync_handler.filter_rooms( + UserID.from_string(user1_id), + {room_id, encrypted_room_id}, + truthy_filters, + ) + ) + + self.assertEqual(truthy_filtered_room_ids, {encrypted_room_id}) + + # Try with `is_encrypted=False` + # ----------------------------- + falsy_filters = SlidingSyncConfig.SlidingSyncList.Filters( + is_encrypted=False, + ) + + # Filter the rooms + falsy_filtered_room_ids = self.get_success( + self.sliding_sync_handler.filter_rooms( + UserID.from_string(user1_id), + {room_id, encrypted_room_id}, + falsy_filters, + ) + ) + + self.assertEqual(falsy_filtered_room_ids, {room_id})