Skip to content

Commit 7ac0649

Browse files
committed
Handle rescinding invites over federation
We should send events that rescind invites over federation. Similiarly, we should handle receiving such events. Unfortunately, the protocol doesn't make it possible to fully auth such events, and so we can only handle the case where the original inviter rescinded the invite (rather than a room admin).
1 parent 6dd6bb4 commit 7ac0649

File tree

2 files changed

+67
-3
lines changed

2 files changed

+67
-3
lines changed

synapse/federation/sender/__init__.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@
150150
from twisted.internet import defer
151151

152152
import synapse.metrics
153+
from synapse.api.constants import EventTypes, Membership
153154
from synapse.api.presence import UserPresenceState
154155
from synapse.events import EventBase
155156
from synapse.federation.sender.per_destination_queue import (
@@ -644,6 +645,31 @@ async def handle_event(event: EventBase) -> None:
644645
)
645646
return
646647

648+
# If we've rescinded an invite then we want to tell the
649+
# other server.
650+
if (
651+
event.type == EventTypes.Member
652+
and event.membership == Membership.LEAVE
653+
and event.sender != event.state_key
654+
):
655+
# We check if this leave event is rescinding an invite
656+
# by looking if there is an invite event for the user in
657+
# the auth events. It could otherwise be a kick or
658+
# unban, which we don't want to send (if the user wasn't
659+
# already in the room).
660+
auth_events = await self.store.get_events_as_list(
661+
event.auth_event_ids()
662+
)
663+
for auth_event in auth_events:
664+
if (
665+
auth_event.type == EventTypes.Member
666+
and auth_event.state_key == event.state_key
667+
and auth_event.membership == Membership.INVITE
668+
):
669+
destinations = set(destinations)
670+
destinations.add(get_domain_from_id(event.state_key))
671+
break
672+
647673
sharded_destinations = {
648674
d
649675
for d in destinations

synapse/handlers/federation_event.py

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,16 +244,54 @@ async def on_receive_pdu(self, origin: str, pdu: EventBase) -> None:
244244
self.room_queues[room_id].append((pdu, origin))
245245
return
246246

247-
# If we're not in the room just ditch the event entirely. This is
248-
# probably an old server that has come back and thinks we're still in
249-
# the room (or we've been rejoined to the room by a state reset).
247+
# If we're not in the room just ditch the event entirely (and not
248+
# invited). This is probably an old server that has come back and thinks
249+
# we're still in the room (or we've been rejoined to the room by a state
250+
# reset).
250251
#
251252
# Note that if we were never in the room then we would have already
252253
# dropped the event, since we wouldn't know the room version.
253254
is_in_room = await self._event_auth_handler.is_host_in_room(
254255
room_id, self.server_name
255256
)
256257
if not is_in_room:
258+
# Check if this is a leave event rescinding an invite
259+
if (
260+
pdu.type == EventTypes.Member
261+
and pdu.membership == Membership.LEAVE
262+
and pdu.state_key != pdu.sender
263+
and self._is_mine_id(pdu.state_key)
264+
):
265+
(
266+
membership,
267+
membership_event_id,
268+
) = await self._store.get_local_current_membership_for_user_in_room(
269+
pdu.state_key, pdu.room_id
270+
)
271+
if (
272+
membership == Membership.INVITE
273+
and membership_event_id
274+
and membership_event_id
275+
in pdu.auth_event_ids() # The invite should be in the auth events of the rescission.
276+
):
277+
invite_event = await self._store.get_event(
278+
membership_event_id, allow_none=True
279+
)
280+
281+
# We cannot fully auth the rescission event, but we can
282+
# check if the sender of the leave event is the same as the
283+
# invite.
284+
#
285+
# Technically, a room admin could rescind the invite, but we
286+
# have no way of knowing who is and isn't a room admin.
287+
if invite_event and pdu.sender == invite_event.sender:
288+
# Handle the rescission event
289+
pdu.internal_metadata.outlier = True
290+
pdu.internal_metadata.out_of_band_membership = True
291+
context = EventContext.for_outlier(self._storage_controllers)
292+
await self.persist_events_and_notify(room_id, [(pdu, context)])
293+
return
294+
257295
logger.info(
258296
"Ignoring PDU from %s as we're not in the room",
259297
origin,

0 commit comments

Comments
 (0)