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

Check for space membership during a remote join of a restricted room. #9763

Merged
merged 20 commits into from
Apr 14, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/9763.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add experimental support for [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083): restricting room access via group membership.
71 changes: 65 additions & 6 deletions synapse/handlers/federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1667,16 +1667,52 @@ async def on_send_join_request(self, origin: str, pdu: EventBase) -> JsonDict:
# would introduce the danger of backwards-compatibility problems.
event.internal_metadata.send_on_behalf_of = origin

context = await self._handle_new_event(origin, event)
# Calculate the event context.
context = await self._prep_event(
origin, event, state=None, auth_events=None, backfilled=False
)
clokep marked this conversation as resolved.
Show resolved Hide resolved

# Get the state before the new event.
prev_state_ids = await context.get_prev_state_ids()

# Check if the user is already in the room or invited to the room.
user_id = event.state_key
prev_member_event_id = prev_state_ids.get((EventTypes.Member, user_id), None)
newly_joined = True
is_invite = False
if prev_member_event_id:
prev_member_event = await self.store.get_event(prev_member_event_id)
newly_joined = prev_member_event.membership != Membership.JOIN
is_invite = prev_member_event.membership == Membership.INVITE
Comment on lines +1684 to +1692
Copy link
Member Author

@clokep clokep Apr 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much of this logic (and the if-statement below) is now duplicated between this and local joins in RoomMemberHandler._local_membership_update. I wonder if we should instead update can_join_without_invite to raise a SynapseError and try to push some of this logic in there?

The local join logic has a couple of interleaved bits though (it needs prev_member_event_id and newly_joined for something else and it seems gross to return those from this).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it would be the end of the world to have this logic in both _local_membership_update and can_join_without_invite, to save us from duplicating the if newly_joined and not is_invite condition. I don't think it matters too much though.


# We retrieve the room member handler here as to not cause a cyclic dependency
clokep marked this conversation as resolved.
Show resolved Hide resolved
member_handler = self.hs.get_room_member_handler()

# If the member is not already in the room, and not invited, check if
# they should be allowed access via membership in a space.
if (
newly_joined
and not is_invite
and not await member_handler.can_join_without_invite(
prev_state_ids,
event.room_version,
user_id,
)
):
raise SynapseError(
400,
"You do not belong to any of the required spaces to join this room.",
)

# Persist the event.
await self._handle_new_event(origin, event, context)

logger.debug(
"on_send_join_request: After _handle_new_event: %s, sigs: %s",
event.event_id,
event.signatures,
)

prev_state_ids = await context.get_prev_state_ids()

state_ids = list(prev_state_ids.values())
auth_chain = await self.store.get_auth_chain(event.room_id, state_ids)

Expand Down Expand Up @@ -1994,13 +2030,36 @@ async def _handle_new_event(
self,
origin: str,
event: EventBase,
context: Optional[EventContext] = None,
state: Optional[Iterable[EventBase]] = None,
auth_events: Optional[MutableStateMap[EventBase]] = None,
backfilled: bool = False,
) -> EventContext:
context = await self._prep_event(
origin, event, state=state, auth_events=auth_events, backfilled=backfilled
)
"""
Process an event.

Args:
origin: The host the event originates from.
event: The event itself.
context: The event context, if available. Otherwise this is calculated
from state and auth_events.
state: The state events to calculate the event context from. This is
ignored if context is provided.
auth_events: The auth events to calculate the event context from. This is
ignored if context is provided.
backfilled: True if the event was backfilled.

Returns:
The event context.
"""
if not context:
clokep marked this conversation as resolved.
Show resolved Hide resolved
context = await self._prep_event(
origin,
event,
state=state,
auth_events=auth_events,
backfilled=backfilled,
)

try:
if (
Expand Down
4 changes: 2 additions & 2 deletions synapse/handlers/room_member.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ async def ratelimit_invite(

await self._invites_per_user_limiter.ratelimit(requester, invitee_user_id)

async def _can_join_without_invite(
async def can_join_without_invite(
self, state_ids: StateMap[str], room_version: RoomVersion, user_id: str
) -> bool:
"""
Expand Down Expand Up @@ -303,7 +303,7 @@ async def _local_membership_update(
if (
newly_joined
and not user_is_invited
and not await self._can_join_without_invite(
and not await self.can_join_without_invite(
prev_state_ids, event.room_version, user_id
)
):
Expand Down