Skip to content
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
2 changes: 2 additions & 0 deletions changelog.d/19762.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Include `allowed_room_ids` in the `/summary` client-server API response for rooms with restricted join rules, as required by Matrix 1.15.
Contributed by @FrenchGithubUser @Famedly.
43 changes: 23 additions & 20 deletions synapse/handlers/room_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ async def _summarize_local_room(
):
return None

room_entry = await self._build_room_entry(room_id, for_federation=bool(origin))
room_entry = await self._build_room_entry(room_id)

# If the room is not a space return just the room information.
if room_entry.get("room_type") != RoomTypes.SPACE or not include_children:
Expand Down Expand Up @@ -769,14 +769,12 @@ async def _is_remote_room_accessible(
# pending invite, etc.
return await self._is_local_room_accessible(room_id, requester)

async def _build_room_entry(self, room_id: str, for_federation: bool) -> JsonDict:
async def _build_room_entry(self, room_id: str) -> JsonDict:
"""
Generate en entry summarising a single room.

Args:
room_id: The room ID to summarize.
for_federation: True if this is a summary requested over federation
(which includes additional fields).

Returns:
The JSON dictionary for the room.
Expand Down Expand Up @@ -805,24 +803,30 @@ async def _build_room_entry(self, room_id: str, for_federation: bool) -> JsonDic
"encryption": stats.encryption,
}

# Federation requests need to provide additional information so the
# requested server is able to filter the response appropriately.
if for_federation:
current_state_ids = (
await self._storage_controllers.state.get_current_state_ids(room_id)
# Include allowed_room_ids for rooms with restricted join rules so that
# clients can determine which memberships grant access.
# Only the join rules event is needed for both has_restricted_join_rules
# and get_rooms_that_allow_join, so avoid fetching full state.
join_rules_state_ids = (
await self._storage_controllers.state.get_current_state_ids(
room_id,
state_filter=StateFilter.from_types([(EventTypes.JoinRules, "")]),
)
)

try:
room_version = await self._store.get_room_version(room_id)
except UnsupportedRoomVersionError:
room_version = None

if await self._event_auth_handler.has_restricted_join_rules(
current_state_ids, room_version
):
allowed_rooms = (
await self._event_auth_handler.get_rooms_that_allow_join(
current_state_ids
)
)
if allowed_rooms:
entry["allowed_room_ids"] = allowed_rooms
if room_version and await self._event_auth_handler.has_restricted_join_rules(
join_rules_state_ids, room_version
):
allowed_rooms = await self._event_auth_handler.get_rooms_that_allow_join(
join_rules_state_ids
)
if allowed_rooms:
entry["allowed_room_ids"] = allowed_rooms

Comment thread
FrenchGithubUser marked this conversation as resolved.
# Filter out Nones – rather omit the field altogether
room_entry = {k: v for k, v in entry.items() if v is not None}
Expand Down Expand Up @@ -932,7 +936,6 @@ async def get_room_summary(
raise NotFoundError("Room not found or is not accessible")

room = dict(room_entry.room)
room.pop("allowed_room_ids", None)

# If there was a requester, add their membership.
# We keep the membership in the local membership table unless the
Expand Down
54 changes: 54 additions & 0 deletions tests/handlers/test_room_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -1219,6 +1219,60 @@ def test_visibility(self) -> None:
result = self.get_success(self.handler.get_room_summary(user2, self.room))
self.assertEqual(result.get("room_id"), self.room)

def test_allowed_room_ids_local(self) -> None:
"""allowed_room_ids is returned for a local room with restricted join rules."""
# Create a space that the restricted room will allow membership from.
space = self.helper.create_room_as(
self.user,
tok=self.token,
extra_content={
"creation_content": {"type": RoomTypes.SPACE},
"initial_state": [
{
"type": EventTypes.JoinRules,
"state_key": "",
"content": {"join_rule": JoinRules.PUBLIC},
}
],
},
)

# Create a room version 8 room with join_rule=restricted allowing members
# of the space above.
restricted_room = self.helper.create_room_as(
self.user,
room_version=RoomVersions.V8.identifier,
tok=self.token,
extra_content={
"initial_state": [
{
"type": EventTypes.JoinRules,
"state_key": "",
"content": {
"join_rule": JoinRules.RESTRICTED,
"allow": [
{
"type": RestrictedJoinRuleTypes.ROOM_MEMBERSHIP,
"room_id": space,
}
],
},
}
]
},
)

result = self.get_success(
self.handler.get_room_summary(self.user, restricted_room)
)
self.assertEqual(result.get("room_id"), restricted_room)
self.assertEqual(result.get("allowed_room_ids"), [space])

def test_allowed_room_ids_absent_without_restricted_join_rules(self) -> None:
"""allowed_room_ids is absent for rooms that do not use restricted join rules."""
result = self.get_success(self.handler.get_room_summary(self.user, self.room))
self.assertNotIn("allowed_room_ids", result)

def test_fed(self) -> None:
"""
Return data over federation and ensure that it is handled properly.
Expand Down
Loading