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

Update MSC3083 support per changes in the MSC. #10189

Merged
merged 2 commits into from
Jun 17, 2021
Merged
Show file tree
Hide file tree
Changes from all 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/10189.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update MSC3083 support for modifications in the MSC.
6 changes: 6 additions & 0 deletions synapse/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ class JoinRules:
MSC3083_RESTRICTED = "restricted"


class RestrictedJoinRuleTypes:
"""Understood types for the allow rules in restricted join rules."""

ROOM_MEMBERSHIP = "m.room_membership"


class LoginType:
PASSWORD = "m.login.password"
EMAIL_IDENTITY = "m.login.email.identity"
Expand Down
45 changes: 27 additions & 18 deletions synapse/handlers/event_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@
# limitations under the License.
from typing import TYPE_CHECKING, Collection, Optional

from synapse.api.constants import EventTypes, JoinRules, Membership
from synapse.api.constants import (
EventTypes,
JoinRules,
Membership,
RestrictedJoinRuleTypes,
)
from synapse.api.errors import AuthError
from synapse.api.room_versions import RoomVersion
from synapse.events import EventBase
Expand Down Expand Up @@ -42,7 +47,7 @@ async def check_restricted_join_rules(
Check whether a user can join a room without an invite due to restricted join rules.

When joining a room with restricted joined rules (as defined in MSC3083),
the membership of spaces must be checked during a room join.
the membership of rooms must be checked during a room join.

Args:
state_ids: The state of the room as it currently is.
Expand All @@ -67,20 +72,20 @@ async def check_restricted_join_rules(
if not await self.has_restricted_join_rules(state_ids, room_version):
return

# Get the spaces which allow access to this room and check if the user is
# Get the rooms which allow access to this room and check if the user is
# in any of them.
allowed_spaces = await self.get_spaces_that_allow_join(state_ids)
if not await self.is_user_in_rooms(allowed_spaces, user_id):
allowed_rooms = await self.get_rooms_that_allow_join(state_ids)
if not await self.is_user_in_rooms(allowed_rooms, user_id):
raise AuthError(
403,
"You do not belong to any of the required spaces to join this room.",
"You do not belong to any of the required rooms to join this room.",
)

async def has_restricted_join_rules(
self, state_ids: StateMap[str], room_version: RoomVersion
) -> bool:
"""
Return if the room has the proper join rules set for access via spaces.
Return if the room has the proper join rules set for access via rooms.

Args:
state_ids: The state of the room as it currently is.
Expand All @@ -102,17 +107,17 @@ async def has_restricted_join_rules(
join_rules_event = await self._store.get_event(join_rules_event_id)
return join_rules_event.content.get("join_rule") == JoinRules.MSC3083_RESTRICTED

async def get_spaces_that_allow_join(
async def get_rooms_that_allow_join(
self, state_ids: StateMap[str]
) -> Collection[str]:
"""
Generate a list of spaces which allow access to a room.
Generate a list of rooms in which membership allows access to a room.

Args:
state_ids: The state of the room as it currently is.
state_ids: The current state of the room the user wishes to join

Returns:
A collection of spaces which provide membership to the room.
A collection of room IDs. Membership in any of the rooms in the list grants the ability to join the target room.
"""
# If there's no join rule, then it defaults to invite (so this doesn't apply).
join_rules_event_id = state_ids.get((EventTypes.JoinRules, ""), None)
Expand All @@ -123,21 +128,25 @@ async def get_spaces_that_allow_join(
join_rules_event = await self._store.get_event(join_rules_event_id)

# If allowed is of the wrong form, then only allow invited users.
allowed_spaces = join_rules_event.content.get("allow", [])
if not isinstance(allowed_spaces, list):
allow_list = join_rules_event.content.get("allow", [])
if not isinstance(allow_list, list):
return ()

# Pull out the other room IDs, invalid data gets filtered.
result = []
for space in allowed_spaces:
if not isinstance(space, dict):
for allow in allow_list:
if not isinstance(allow, dict):
continue

# If the type is unexpected, skip it.
if allow.get("type") != RestrictedJoinRuleTypes.ROOM_MEMBERSHIP:
continue

space_id = space.get("space")
if not isinstance(space_id, str):
room_id = allow.get("room_id")
if not isinstance(room_id, str):
continue

result.append(space_id)
result.append(room_id)

return result

Expand Down
26 changes: 13 additions & 13 deletions synapse/handlers/space_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,14 @@ async def get_space_summary(

# Check if the user is a member of any of the allowed spaces
# from the response.
allowed_spaces = room.get("allowed_spaces")
allowed_rooms = room.get("allowed_spaces")
if (
not include_room
and allowed_spaces
and isinstance(allowed_spaces, list)
and allowed_rooms
and isinstance(allowed_rooms, list)
):
include_room = await self._event_auth_handler.is_user_in_rooms(
allowed_spaces, requester
allowed_rooms, requester
)

# Finally, if this isn't the requested room, check ourselves
Expand Down Expand Up @@ -455,11 +455,11 @@ async def _is_room_accessible(
if self._event_auth_handler.has_restricted_join_rules(
state_ids, room_version
):
allowed_spaces = (
await self._event_auth_handler.get_spaces_that_allow_join(state_ids)
allowed_rooms = (
await self._event_auth_handler.get_rooms_that_allow_join(state_ids)
)
if await self._event_auth_handler.is_user_in_rooms(
allowed_spaces, requester
allowed_rooms, requester
):
return True

Expand All @@ -475,10 +475,10 @@ async def _is_room_accessible(
if await self._event_auth_handler.has_restricted_join_rules(
state_ids, room_version
):
allowed_spaces = (
await self._event_auth_handler.get_spaces_that_allow_join(state_ids)
allowed_rooms = (
await self._event_auth_handler.get_rooms_that_allow_join(state_ids)
)
for space_id in allowed_spaces:
for space_id in allowed_rooms:
if await self._auth.check_host_in_room(space_id, origin):
return True

Expand Down Expand Up @@ -512,11 +512,11 @@ async def _build_room_entry(self, room_id: str) -> JsonDict:
)

room_version = await self._store.get_room_version(room_id)
allowed_spaces = None
allowed_rooms = None
if await self._event_auth_handler.has_restricted_join_rules(
current_state_ids, room_version
):
allowed_spaces = await self._event_auth_handler.get_spaces_that_allow_join(
allowed_rooms = await self._event_auth_handler.get_rooms_that_allow_join(
current_state_ids
)

Expand All @@ -533,7 +533,7 @@ async def _build_room_entry(self, room_id: str) -> JsonDict:
"guest_can_join": stats["guest_access"] == "can_join",
"creation_ts": create_event.origin_server_ts,
"room_type": create_event.content.get(EventContentFields.ROOM_TYPE),
"allowed_spaces": allowed_spaces,
"allowed_spaces": allowed_rooms,
Copy link
Member Author

Choose a reason for hiding this comment

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

I should have mentioned that I left this at allowed_spaces for now since the form of this API is somewhat unrelated to the restricted rooms MSC.

}

# Filter out Nones – rather omit the field altogether
Expand Down