diff --git a/synapse/handlers/sync.py b/synapse/handlers/sync.py index 17f0467deb..b4b01c9257 100644 --- a/synapse/handlers/sync.py +++ b/synapse/handlers/sync.py @@ -2255,22 +2255,28 @@ class SyncHandler: lazy_load_members = sync_config.filter_collection.lazy_load_members() include_users = None if lazy_load_members: - # Collect members from the existing `sync_result_builder` data + # Collect members from the existing `sync_result_builder` data. + # Ensure we filter out any remove users until we support profile + # updates for federated users. include_users = set() # invited for invited in sync_result_builder.invited: - include_users.add(invited.invite.sender) + if self._is_mine_id(invited.invite.sender): + include_users.add(invited.invite.sender) # joined for joined in sync_result_builder.joined: for timeline_event in joined.timeline.events: - include_users.add(timeline_event.event.sender) + if self._is_mine_id(timeline_event.event.sender): + include_users.add(timeline_event.event.sender) # knocked for knocked in sync_result_builder.knocked: - include_users.add(knocked.knock.sender) + if self._is_mine_id(knocked.knock.sender): + include_users.add(knocked.knock.sender) # archived for archived in sync_result_builder.archived: for timeline_event in archived.timeline.events: - include_users.add(timeline_event.event.sender) + if self._is_mine_id(timeline_event.event.sender): + include_users.add(timeline_event.event.sender) if since_token is None: await self._generate_initial_sync_entry_for_profile_updates( diff --git a/tests/handlers/test_sync.py b/tests/handlers/test_sync.py index cd59fc6147..86f7b43166 100644 --- a/tests/handlers/test_sync.py +++ b/tests/handlers/test_sync.py @@ -55,6 +55,7 @@ from synapse.util.duration import Duration import tests.unittest import tests.utils from tests.test_utils.event_builders import make_test_pdu_event +from tests.test_utils.event_injection import inject_member_event from tests.unittest import override_config _request_key = 0 @@ -1523,6 +1524,15 @@ class SyncProfileUpdatesTestCase(tests.unittest.HomeserverTestCase): self.helper.send_messages( room_id=self.joined_room, num_events=10, tok=third_tok ) + # Join a federated user to the room + self.get_success( + inject_member_event( + self.hs, + self.joined_room, + "@federateduser:federatedhs", + "join", + ) + ) incremental_result = self.get_success( self.sync_handler.wait_for_sync_for_user( requester, @@ -1546,6 +1556,12 @@ class SyncProfileUpdatesTestCase(tests.unittest.HomeserverTestCase): request_key=generate_request_key(), ) ) + + # Ensure our federated user is filtered out, even though they have an + # event in the joined room timeline + self.assertFalse( + "@federateduser:federatedhs" in incremental_result.profile_updates.keys() + ) # Lazy loading only filters initial sync profile updates. Incremental syncs # should include all tracked profile updates for the syncing user. self.assertCountEqual( @@ -1577,6 +1593,100 @@ class SyncProfileUpdatesTestCase(tests.unittest.HomeserverTestCase): "third_user", ) + @parameterized.expand( + [ + True, + False, + ] + ) + @override_config({"include_profile_updates_in_sync": True}) + def test_lazy_loading_sync_filters_out_profile_updates_from_federated_users( + self, + is_initial: bool, + ) -> None: + """Test that with MSC4429 enabled lazy loading sync response + doesn't contain federated users even if there are timeline events from them. + """ + # Join a federated user to the room, causing a membership event into + # the joined rooms sync response + self.get_success( + inject_member_event( + self.hs, + self.joined_room, + "@federateduser1:federatedhs", + "join", + ) + ) + requester = create_requester(self.user) + initial_result = self.get_success( + self.sync_handler.wait_for_sync_for_user( + requester, + sync_config=generate_sync_config( + user_id=self.user, + filter_collection=FilterCollection( + hs=self.hs, + filter_json={ + "org.matrix.msc4429.profile_fields": { + "ids": ["m.status", "displayname", "avatar_url"] + }, + "room": { + "state": { + "lazy_load_members": True, + }, + }, + }, + ), + ), + request_key=generate_request_key(), + ) + ) + # Ensure our federated user is filtered out, even though they have an + # event in the joined room timeline + self.assertFalse( + "@federateduser1:federatedhs" in initial_result.profile_updates.keys() + ) + if not is_initial: + # Join another federated user to the room, causing a membership event into + # the joined rooms sync response + self.get_success( + inject_member_event( + self.hs, + self.joined_room, + "@federateduser2:federatedhs", + "join", + ) + ) + incremental_result = self.get_success( + self.sync_handler.wait_for_sync_for_user( + requester, + since_token=initial_result.next_batch, + sync_config=generate_sync_config( + user_id=self.user, + filter_collection=FilterCollection( + hs=self.hs, + filter_json={ + "org.matrix.msc4429.profile_fields": { + "ids": ["m.status", "displayname", "avatar_url"] + }, + "room": { + "state": { + "lazy_load_members": True, + }, + }, + }, + ), + ), + request_key=generate_request_key(), + ) + ) + + # Ensure our federated user is filtered out, even though they have an + # event in the joined room timeline + self.assertFalse( + "@federateduser2:federatedhs" + in incremental_result.profile_updates.keys() + ) + @override_config({"include_profile_updates_in_sync": True}) def test_incremental_sync_lazy_loading_cache_filters_recently_sent_profiles( self,