diff --git a/changelog.d/20154.bugfix b/changelog.d/20154.bugfix new file mode 100644 index 00000000000..50de48799f7 --- /dev/null +++ b/changelog.d/20154.bugfix @@ -0,0 +1 @@ +Return `allowed_room_ids` in the client [`GET /_matrix/client/v1/rooms/{roomId}/hierarchy`](https://spec.matrix.org/v1.19/client-server-api/#get_matrixclientv1roomsroomidhierarchy) response, as required since Matrix 1.15. diff --git a/synapse/handlers/room_summary.py b/synapse/handlers/room_summary.py index 4afd449292c..9dcdc8e2ad4 100644 --- a/synapse/handlers/room_summary.py +++ b/synapse/handlers/room_summary.py @@ -368,7 +368,7 @@ async def _get_room_hierarchy( # inaccessible to the requesting user. if room_entry: # Add the room (including the stripped m.space.child events). - rooms_result.append(room_entry.as_json(for_client=True)) + rooms_result.append(room_entry.as_json()) # If this room is not at the max-depth, check if there are any # children to process. @@ -872,7 +872,8 @@ async def get_room_summary( remote_room_hosts: list[str] | None = None, ) -> JsonDict: """ - Implementation of the room summary C-S API from MSC3266 + Implementation of the room summary C-S API, see + https://spec.matrix.org/v1.19/client-server-api/#get_matrixclientv1room_summaryroomidoralias Args: requester: user id of the user making this request, will be None @@ -980,25 +981,14 @@ class _RoomEntry: # This may not include all children. children_state_events: Sequence[JsonDict] = () - def as_json(self, for_client: bool = False) -> JsonDict: + def as_json(self) -> JsonDict: """ Returns a JSON dictionary suitable for the room hierarchy endpoint. It returns the room summary including the stripped m.space.child events as a sub-key. - - Args: - for_client: If true, any server-server only fields are stripped from - the result. - """ result = dict(self.room) - - # Before returning to the client, remove the allowed_room_ids key, if it - # exists. - if for_client: - result.pop("allowed_room_ids", False) - result["children_state"] = self.children_state_events return result diff --git a/tests/handlers/test_room_summary.py b/tests/handlers/test_room_summary.py index 0f8de6e7b92..bb6284b2fc7 100644 --- a/tests/handlers/test_room_summary.py +++ b/tests/handlers/test_room_summary.py @@ -31,6 +31,7 @@ JoinRules, Membership, RestrictedJoinRuleTypes, + RoomEncryptionAlgorithms, RoomTypes, ) from synapse.api.errors import AuthError, NotFoundError, SynapseError @@ -184,9 +185,6 @@ def _assert_hierarchy( result_room_ids = [] result_children_ids = [] for result_room in result["rooms"]: - # Ensure federation results are not leaking over the client-server API. - self.assertNotIn("allowed_room_ids", result_room) - result_room_ids.append(result_room["room_id"]) result_children_ids.append( [ @@ -489,6 +487,44 @@ def test_filtering(self) -> None: ) self._assert_hierarchy(result, expected) + def test_summary_fields(self) -> None: + """ + The room entries returned to clients include the `room_version`, + `encryption` and `allowed_room_ids` fields, added to the client + `/hierarchy` API in Matrix 1.15. + + See https://spec.matrix.org/v1.19/client-server-api/#get_matrixclientv1roomsroomidhierarchy + """ + restricted_room = self._create_room_with_join_rule( + JoinRules.RESTRICTED, + room_version=RoomVersions.V8.identifier, + allow=[ + { + "type": RestrictedJoinRuleTypes.ROOM_MEMBERSHIP, + "room_id": self.space, + "via": [self.hs.hostname], + } + ], + ) + self.helper.send_state( + restricted_room, + event_type=EventTypes.RoomEncryption, + body={"algorithm": RoomEncryptionAlgorithms.DEFAULT}, + tok=self.token, + ) + + result = self.get_success( + self.handler.get_room_hierarchy(create_requester(self.user), self.space) + ) + room_entries = {entry["room_id"]: entry for entry in result["rooms"]} + entry = room_entries[restricted_room] + self.assertEqual(entry["room_version"], RoomVersions.V8.identifier) + self.assertEqual(entry["encryption"], RoomEncryptionAlgorithms.DEFAULT) + self.assertEqual(entry["allowed_room_ids"], [self.space]) + + # Rooms without restricted join rules should not have the field at all. + self.assertNotIn("allowed_room_ids", room_entries[self.room]) + def test_complex_space(self) -> None: """ Create a "complex" space to see how it handles things like loops and subspaces. @@ -960,6 +996,13 @@ async def summarize_remote_room_hierarchy( ) self._assert_hierarchy(result, expected) + # `allowed_room_ids` returned over federation should be passed through + # to the client. + room_entries = {entry["room_id"]: entry for entry in result["rooms"]} + self.assertEqual( + room_entries[restricted_accessible_room]["allowed_room_ids"], [self.room] + ) + def test_fed_invited(self) -> None: """ A room which the user was invited to should be included in the response.