Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 87c230c

Browse files
authored
Update client-visibility filtering for outlier events (#12155)
Avoid trying to get the state for outliers, which isn't a sensible thing to do.
1 parent d56202b commit 87c230c

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

changelog.d/12155.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Avoid trying to calculate the state at outlier events.

synapse/visibility.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,9 @@ async def filter_events_for_client(
8181

8282
types = ((EventTypes.RoomHistoryVisibility, ""), (EventTypes.Member, user_id))
8383

84+
# we exclude outliers at this point, and then handle them separately later
8485
event_id_to_state = await storage.state.get_state_for_events(
85-
frozenset(e.event_id for e in events),
86+
frozenset(e.event_id for e in events if not e.internal_metadata.outlier),
8687
state_filter=StateFilter.from_types(types),
8788
)
8889

@@ -154,6 +155,17 @@ def allowed(event: EventBase) -> Optional[EventBase]:
154155
if event.event_id in always_include_ids:
155156
return event
156157

158+
# we need to handle outliers separately, since we don't have the room state.
159+
if event.internal_metadata.outlier:
160+
# Normally these can't be seen by clients, but we make an exception for
161+
# for out-of-band membership events (eg, incoming invites, or rejections of
162+
# said invite) for the user themselves.
163+
if event.type == EventTypes.Member and event.state_key == user_id:
164+
logger.debug("Returning out-of-band-membership event %s", event)
165+
return event
166+
167+
return None
168+
157169
state = event_id_to_state[event.event_id]
158170

159171
# get the room_visibility at the time of the event.
@@ -198,6 +210,9 @@ def allowed(event: EventBase) -> Optional[EventBase]:
198210

199211
# Always allow the user to see their own leave events, otherwise
200212
# they won't see the room disappear if they reject the invite
213+
#
214+
# (Note this doesn't work for out-of-band invite rejections, which don't
215+
# have prev_state populated. They are handled above in the outlier code.)
201216
if membership == "leave" and (
202217
prev_membership == "join" or prev_membership == "invite"
203218
):

tests/test_visibility.py

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
# limitations under the License.
1414
import logging
1515
from typing import Optional
16+
from unittest.mock import patch
1617

1718
from synapse.api.room_versions import RoomVersions
18-
from synapse.events import EventBase
19-
from synapse.types import JsonDict
20-
from synapse.visibility import filter_events_for_server
19+
from synapse.events import EventBase, make_event_from_dict
20+
from synapse.types import JsonDict, create_requester
21+
from synapse.visibility import filter_events_for_client, filter_events_for_server
2122

2223
from tests import unittest
2324
from tests.utils import create_room
@@ -185,3 +186,72 @@ def _inject_message(
185186

186187
self.get_success(self.storage.persistence.persist_event(event, context))
187188
return event
189+
190+
191+
class FilterEventsForClientTestCase(unittest.FederatingHomeserverTestCase):
192+
def test_out_of_band_invite_rejection(self):
193+
# this is where we have received an invite event over federation, and then
194+
# rejected it.
195+
invite_pdu = {
196+
"room_id": "!room:id",
197+
"depth": 1,
198+
"auth_events": [],
199+
"prev_events": [],
200+
"origin_server_ts": 1,
201+
"sender": "@someone:" + self.OTHER_SERVER_NAME,
202+
"type": "m.room.member",
203+
"state_key": "@user:test",
204+
"content": {"membership": "invite"},
205+
}
206+
self.add_hashes_and_signatures(invite_pdu)
207+
invite_event_id = make_event_from_dict(invite_pdu, RoomVersions.V9).event_id
208+
209+
self.get_success(
210+
self.hs.get_federation_server().on_invite_request(
211+
self.OTHER_SERVER_NAME,
212+
invite_pdu,
213+
"9",
214+
)
215+
)
216+
217+
# stub out do_remotely_reject_invite so that we fall back to a locally-
218+
# generated rejection
219+
with patch.object(
220+
self.hs.get_federation_handler(),
221+
"do_remotely_reject_invite",
222+
side_effect=Exception(),
223+
):
224+
reject_event_id, _ = self.get_success(
225+
self.hs.get_room_member_handler().remote_reject_invite(
226+
invite_event_id,
227+
txn_id=None,
228+
requester=create_requester("@user:test"),
229+
content={},
230+
)
231+
)
232+
233+
invite_event, reject_event = self.get_success(
234+
self.hs.get_datastores().main.get_events_as_list(
235+
[invite_event_id, reject_event_id]
236+
)
237+
)
238+
239+
# the invited user should be able to see both the invite and the rejection
240+
self.assertEqual(
241+
self.get_success(
242+
filter_events_for_client(
243+
self.hs.get_storage(), "@user:test", [invite_event, reject_event]
244+
)
245+
),
246+
[invite_event, reject_event],
247+
)
248+
249+
# other users should see neither
250+
self.assertEqual(
251+
self.get_success(
252+
filter_events_for_client(
253+
self.hs.get_storage(), "@other:test", [invite_event, reject_event]
254+
)
255+
),
256+
[],
257+
)

0 commit comments

Comments
 (0)