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