1# Copyright 2018 New Vector Ltd 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. 14import logging 15from typing import Optional 16 17from synapse.api.room_versions import RoomVersions 18from synapse.events import EventBase 19from synapse.types import JsonDict 20from synapse.visibility import filter_events_for_server 21 22from tests import unittest 23from tests.utils import create_room 24 25logger = logging.getLogger(__name__) 26 27TEST_ROOM_ID = "!TEST:ROOM" 28 29 30class FilterEventsForServerTestCase(unittest.HomeserverTestCase): 31 def setUp(self) -> None: 32 super(FilterEventsForServerTestCase, self).setUp() 33 self.event_creation_handler = self.hs.get_event_creation_handler() 34 self.event_builder_factory = self.hs.get_event_builder_factory() 35 self.storage = self.hs.get_storage() 36 37 self.get_success(create_room(self.hs, TEST_ROOM_ID, "@someone:ROOM")) 38 39 def test_filtering(self) -> None: 40 # 41 # The events to be filtered consist of 10 membership events (it doesn't 42 # really matter if they are joins or leaves, so let's make them joins). 43 # One of those membership events is going to be for a user on the 44 # server we are filtering for (so we can check the filtering is doing 45 # the right thing). 46 # 47 48 # before we do that, we persist some other events to act as state. 49 self.get_success(self._inject_visibility("@admin:hs", "joined")) 50 for i in range(0, 10): 51 self.get_success(self._inject_room_member("@resident%i:hs" % i)) 52 53 events_to_filter = [] 54 55 for i in range(0, 10): 56 user = "@user%i:%s" % (i, "test_server" if i == 5 else "other_server") 57 evt = self.get_success( 58 self._inject_room_member(user, extra_content={"a": "b"}) 59 ) 60 events_to_filter.append(evt) 61 62 filtered = self.get_success( 63 filter_events_for_server(self.storage, "test_server", events_to_filter) 64 ) 65 66 # the result should be 5 redacted events, and 5 unredacted events. 67 for i in range(0, 5): 68 self.assertEqual(events_to_filter[i].event_id, filtered[i].event_id) 69 self.assertNotIn("a", filtered[i].content) 70 71 for i in range(5, 10): 72 self.assertEqual(events_to_filter[i].event_id, filtered[i].event_id) 73 self.assertEqual(filtered[i].content["a"], "b") 74 75 def test_erased_user(self) -> None: 76 # 4 message events, from erased and unerased users, with a membership 77 # change in the middle of them. 78 events_to_filter = [] 79 80 evt = self.get_success(self._inject_message("@unerased:local_hs")) 81 events_to_filter.append(evt) 82 83 evt = self.get_success(self._inject_message("@erased:local_hs")) 84 events_to_filter.append(evt) 85 86 evt = self.get_success(self._inject_room_member("@joiner:remote_hs")) 87 events_to_filter.append(evt) 88 89 evt = self.get_success(self._inject_message("@unerased:local_hs")) 90 events_to_filter.append(evt) 91 92 evt = self.get_success(self._inject_message("@erased:local_hs")) 93 events_to_filter.append(evt) 94 95 # the erasey user gets erased 96 self.get_success(self.hs.get_datastore().mark_user_erased("@erased:local_hs")) 97 98 # ... and the filtering happens. 99 filtered = self.get_success( 100 filter_events_for_server(self.storage, "test_server", events_to_filter) 101 ) 102 103 for i in range(0, len(events_to_filter)): 104 self.assertEqual( 105 events_to_filter[i].event_id, 106 filtered[i].event_id, 107 "Unexpected event at result position %i" % (i,), 108 ) 109 110 for i in (0, 3): 111 self.assertEqual( 112 events_to_filter[i].content["body"], 113 filtered[i].content["body"], 114 "Unexpected event content at result position %i" % (i,), 115 ) 116 117 for i in (1, 4): 118 self.assertNotIn("body", filtered[i].content) 119 120 def _inject_visibility(self, user_id: str, visibility: str) -> EventBase: 121 content = {"history_visibility": visibility} 122 builder = self.event_builder_factory.for_room_version( 123 RoomVersions.V1, 124 { 125 "type": "m.room.history_visibility", 126 "sender": user_id, 127 "state_key": "", 128 "room_id": TEST_ROOM_ID, 129 "content": content, 130 }, 131 ) 132 133 event, context = self.get_success( 134 self.event_creation_handler.create_new_client_event(builder) 135 ) 136 self.get_success(self.storage.persistence.persist_event(event, context)) 137 return event 138 139 def _inject_room_member( 140 self, 141 user_id: str, 142 membership: str = "join", 143 extra_content: Optional[JsonDict] = None, 144 ) -> EventBase: 145 content = {"membership": membership} 146 content.update(extra_content or {}) 147 builder = self.event_builder_factory.for_room_version( 148 RoomVersions.V1, 149 { 150 "type": "m.room.member", 151 "sender": user_id, 152 "state_key": user_id, 153 "room_id": TEST_ROOM_ID, 154 "content": content, 155 }, 156 ) 157 158 event, context = self.get_success( 159 self.event_creation_handler.create_new_client_event(builder) 160 ) 161 162 self.get_success(self.storage.persistence.persist_event(event, context)) 163 return event 164 165 def _inject_message( 166 self, user_id: str, content: Optional[JsonDict] = None 167 ) -> EventBase: 168 if content is None: 169 content = {"body": "testytest", "msgtype": "m.text"} 170 builder = self.event_builder_factory.for_room_version( 171 RoomVersions.V1, 172 { 173 "type": "m.room.message", 174 "sender": user_id, 175 "room_id": TEST_ROOM_ID, 176 "content": content, 177 }, 178 ) 179 180 event, context = self.get_success( 181 self.event_creation_handler.create_new_client_event(builder) 182 ) 183 184 self.get_success(self.storage.persistence.persist_event(event, context)) 185 return event 186