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

Commit 753d1d9

Browse files
authored
Fix joining rooms you have been unbanned from (#15323)
* Fix joining rooms you have been unbanned from Since forever synapse did not allow you to join a room after you have been unbanned from it over federation. This was not actually because of the unban event not federating. Synapse simply used outdated state to validate the join transition. This skips the validation if we are not in the room and for that reason won't have the current room state. Fixes #1563 Signed-off-by: Nicolas Werner <[email protected]> * Add changelog Signed-off-by: Nicolas Werner <[email protected]> * Update changelog.d/15323.bugfix --------- Signed-off-by: Nicolas Werner <[email protected]>
1 parent 5282ba1 commit 753d1d9

File tree

3 files changed

+59
-53
lines changed

3 files changed

+59
-53
lines changed

changelog.d/15323.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a long-standing bug preventing users from joining rooms, that they had been unbanned from, over federation. Contributed by Nico.

synapse/handlers/federation_event.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ async def process_remote_join(
583583

584584
await self._check_event_auth(origin, event, context)
585585
if context.rejected:
586-
raise SynapseError(400, "Join event was rejected")
586+
raise SynapseError(403, "Join event was rejected")
587587

588588
# the remote server is responsible for sending our join event to the rest
589589
# of the federation. Indeed, attempting to do so will result in problems

synapse/handlers/room_member.py

Lines changed: 57 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -850,63 +850,68 @@ async def update_membership_locked(
850850
# `is_partial_state_room` also indicates whether `partial_state_before_join` is
851851
# partial.
852852

853-
# TODO: Refactor into dictionary of explicitly allowed transitions
854-
# between old and new state, with specific error messages for some
855-
# transitions and generic otherwise
856-
old_state_id = partial_state_before_join.get(
857-
(EventTypes.Member, target.to_string())
858-
)
859-
if old_state_id:
860-
old_state = await self.store.get_event(old_state_id, allow_none=True)
861-
old_membership = old_state.content.get("membership") if old_state else None
862-
if action == "unban" and old_membership != "ban":
863-
raise SynapseError(
864-
403,
865-
"Cannot unban user who was not banned"
866-
" (membership=%s)" % old_membership,
867-
errcode=Codes.BAD_STATE,
868-
)
869-
if old_membership == "ban" and action not in ["ban", "unban", "leave"]:
870-
raise SynapseError(
871-
403,
872-
"Cannot %s user who was banned" % (action,),
873-
errcode=Codes.BAD_STATE,
874-
)
875-
876-
if old_state:
877-
same_content = content == old_state.content
878-
same_membership = old_membership == effective_membership_state
879-
same_sender = requester.user.to_string() == old_state.sender
880-
if same_sender and same_membership and same_content:
881-
# duplicate event.
882-
# we know it was persisted, so must have a stream ordering.
883-
assert old_state.internal_metadata.stream_ordering
884-
return (
885-
old_state.event_id,
886-
old_state.internal_metadata.stream_ordering,
887-
)
853+
is_host_in_room = await self._is_host_in_room(partial_state_before_join)
888854

889-
if old_membership in ["ban", "leave"] and action == "kick":
890-
raise AuthError(403, "The target user is not in the room")
855+
# if we are not in the room, we won't have the current state
856+
if is_host_in_room:
857+
# TODO: Refactor into dictionary of explicitly allowed transitions
858+
# between old and new state, with specific error messages for some
859+
# transitions and generic otherwise
860+
old_state_id = partial_state_before_join.get(
861+
(EventTypes.Member, target.to_string())
862+
)
891863

892-
# we don't allow people to reject invites to the server notice
893-
# room, but they can leave it once they are joined.
894-
if (
895-
old_membership == Membership.INVITE
896-
and effective_membership_state == Membership.LEAVE
897-
):
898-
is_blocked = await self.store.is_server_notice_room(room_id)
899-
if is_blocked:
864+
if old_state_id:
865+
old_state = await self.store.get_event(old_state_id, allow_none=True)
866+
old_membership = (
867+
old_state.content.get("membership") if old_state else None
868+
)
869+
if action == "unban" and old_membership != "ban":
900870
raise SynapseError(
901-
HTTPStatus.FORBIDDEN,
902-
"You cannot reject this invite",
903-
errcode=Codes.CANNOT_LEAVE_SERVER_NOTICE_ROOM,
871+
403,
872+
"Cannot unban user who was not banned"
873+
" (membership=%s)" % old_membership,
874+
errcode=Codes.BAD_STATE,
875+
)
876+
if old_membership == "ban" and action not in ["ban", "unban", "leave"]:
877+
raise SynapseError(
878+
403,
879+
"Cannot %s user who was banned" % (action,),
880+
errcode=Codes.BAD_STATE,
904881
)
905-
else:
906-
if action == "kick":
907-
raise AuthError(403, "The target user is not in the room")
908882

909-
is_host_in_room = await self._is_host_in_room(partial_state_before_join)
883+
if old_state:
884+
same_content = content == old_state.content
885+
same_membership = old_membership == effective_membership_state
886+
same_sender = requester.user.to_string() == old_state.sender
887+
if same_sender and same_membership and same_content:
888+
# duplicate event.
889+
# we know it was persisted, so must have a stream ordering.
890+
assert old_state.internal_metadata.stream_ordering
891+
return (
892+
old_state.event_id,
893+
old_state.internal_metadata.stream_ordering,
894+
)
895+
896+
if old_membership in ["ban", "leave"] and action == "kick":
897+
raise AuthError(403, "The target user is not in the room")
898+
899+
# we don't allow people to reject invites to the server notice
900+
# room, but they can leave it once they are joined.
901+
if (
902+
old_membership == Membership.INVITE
903+
and effective_membership_state == Membership.LEAVE
904+
):
905+
is_blocked = await self.store.is_server_notice_room(room_id)
906+
if is_blocked:
907+
raise SynapseError(
908+
HTTPStatus.FORBIDDEN,
909+
"You cannot reject this invite",
910+
errcode=Codes.CANNOT_LEAVE_SERVER_NOTICE_ROOM,
911+
)
912+
else:
913+
if action == "kick":
914+
raise AuthError(403, "The target user is not in the room")
910915

911916
if effective_membership_state == Membership.JOIN:
912917
if requester.is_guest:

0 commit comments

Comments
 (0)