|
@@ -850,63 +850,68 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
|
|
|
# `is_partial_state_room` also indicates whether `partial_state_before_join` is
|
|
|
# partial.
|
|
|
|
|
|
- # TODO: Refactor into dictionary of explicitly allowed transitions
|
|
|
- # between old and new state, with specific error messages for some
|
|
|
- # transitions and generic otherwise
|
|
|
- old_state_id = partial_state_before_join.get(
|
|
|
- (EventTypes.Member, target.to_string())
|
|
|
- )
|
|
|
- if old_state_id:
|
|
|
- old_state = await self.store.get_event(old_state_id, allow_none=True)
|
|
|
- old_membership = old_state.content.get("membership") if old_state else None
|
|
|
- if action == "unban" and old_membership != "ban":
|
|
|
- raise SynapseError(
|
|
|
- 403,
|
|
|
- "Cannot unban user who was not banned"
|
|
|
- " (membership=%s)" % old_membership,
|
|
|
- errcode=Codes.BAD_STATE,
|
|
|
- )
|
|
|
- if old_membership == "ban" and action not in ["ban", "unban", "leave"]:
|
|
|
- raise SynapseError(
|
|
|
- 403,
|
|
|
- "Cannot %s user who was banned" % (action,),
|
|
|
- errcode=Codes.BAD_STATE,
|
|
|
- )
|
|
|
-
|
|
|
- if old_state:
|
|
|
- same_content = content == old_state.content
|
|
|
- same_membership = old_membership == effective_membership_state
|
|
|
- same_sender = requester.user.to_string() == old_state.sender
|
|
|
- if same_sender and same_membership and same_content:
|
|
|
- # duplicate event.
|
|
|
- # we know it was persisted, so must have a stream ordering.
|
|
|
- assert old_state.internal_metadata.stream_ordering
|
|
|
- return (
|
|
|
- old_state.event_id,
|
|
|
- old_state.internal_metadata.stream_ordering,
|
|
|
- )
|
|
|
+ is_host_in_room = await self._is_host_in_room(partial_state_before_join)
|
|
|
|
|
|
- if old_membership in ["ban", "leave"] and action == "kick":
|
|
|
- raise AuthError(403, "The target user is not in the room")
|
|
|
+ # if we are not in the room, we won't have the current state
|
|
|
+ if is_host_in_room:
|
|
|
+ # TODO: Refactor into dictionary of explicitly allowed transitions
|
|
|
+ # between old and new state, with specific error messages for some
|
|
|
+ # transitions and generic otherwise
|
|
|
+ old_state_id = partial_state_before_join.get(
|
|
|
+ (EventTypes.Member, target.to_string())
|
|
|
+ )
|
|
|
|
|
|
- # we don't allow people to reject invites to the server notice
|
|
|
- # room, but they can leave it once they are joined.
|
|
|
- if (
|
|
|
- old_membership == Membership.INVITE
|
|
|
- and effective_membership_state == Membership.LEAVE
|
|
|
- ):
|
|
|
- is_blocked = await self.store.is_server_notice_room(room_id)
|
|
|
- if is_blocked:
|
|
|
+ if old_state_id:
|
|
|
+ old_state = await self.store.get_event(old_state_id, allow_none=True)
|
|
|
+ old_membership = (
|
|
|
+ old_state.content.get("membership") if old_state else None
|
|
|
+ )
|
|
|
+ if action == "unban" and old_membership != "ban":
|
|
|
raise SynapseError(
|
|
|
- HTTPStatus.FORBIDDEN,
|
|
|
- "You cannot reject this invite",
|
|
|
- errcode=Codes.CANNOT_LEAVE_SERVER_NOTICE_ROOM,
|
|
|
+ 403,
|
|
|
+ "Cannot unban user who was not banned"
|
|
|
+ " (membership=%s)" % old_membership,
|
|
|
+ errcode=Codes.BAD_STATE,
|
|
|
+ )
|
|
|
+ if old_membership == "ban" and action not in ["ban", "unban", "leave"]:
|
|
|
+ raise SynapseError(
|
|
|
+ 403,
|
|
|
+ "Cannot %s user who was banned" % (action,),
|
|
|
+ errcode=Codes.BAD_STATE,
|
|
|
)
|
|
|
- else:
|
|
|
- if action == "kick":
|
|
|
- raise AuthError(403, "The target user is not in the room")
|
|
|
|
|
|
- is_host_in_room = await self._is_host_in_room(partial_state_before_join)
|
|
|
+ if old_state:
|
|
|
+ same_content = content == old_state.content
|
|
|
+ same_membership = old_membership == effective_membership_state
|
|
|
+ same_sender = requester.user.to_string() == old_state.sender
|
|
|
+ if same_sender and same_membership and same_content:
|
|
|
+ # duplicate event.
|
|
|
+ # we know it was persisted, so must have a stream ordering.
|
|
|
+ assert old_state.internal_metadata.stream_ordering
|
|
|
+ return (
|
|
|
+ old_state.event_id,
|
|
|
+ old_state.internal_metadata.stream_ordering,
|
|
|
+ )
|
|
|
+
|
|
|
+ if old_membership in ["ban", "leave"] and action == "kick":
|
|
|
+ raise AuthError(403, "The target user is not in the room")
|
|
|
+
|
|
|
+ # we don't allow people to reject invites to the server notice
|
|
|
+ # room, but they can leave it once they are joined.
|
|
|
+ if (
|
|
|
+ old_membership == Membership.INVITE
|
|
|
+ and effective_membership_state == Membership.LEAVE
|
|
|
+ ):
|
|
|
+ is_blocked = await self.store.is_server_notice_room(room_id)
|
|
|
+ if is_blocked:
|
|
|
+ raise SynapseError(
|
|
|
+ HTTPStatus.FORBIDDEN,
|
|
|
+ "You cannot reject this invite",
|
|
|
+ errcode=Codes.CANNOT_LEAVE_SERVER_NOTICE_ROOM,
|
|
|
+ )
|
|
|
+ else:
|
|
|
+ if action == "kick":
|
|
|
+ raise AuthError(403, "The target user is not in the room")
|
|
|
|
|
|
if effective_membership_state == Membership.JOIN:
|
|
|
if requester.is_guest:
|