Support MSC3266 room summaries over federation (#11507)

Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de>
This commit is contained in:
DeepBlueV7.X 2022-05-05 14:25:00 +00:00 committed by GitHub
parent ef86cf3d28
commit a377a43386
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 5 deletions

View File

@ -0,0 +1 @@
Support [MSC3266](https://github.com/matrix-org/matrix-doc/pull/3266) room summaries over federation.

View File

@ -1426,6 +1426,8 @@ class FederationClient(FederationBase):
room = res.get("room")
if not isinstance(room, dict):
raise InvalidResponseError("'room' must be a dict")
if room.get("room_id") != room_id:
raise InvalidResponseError("wrong room returned in hierarchy response")
# Validate children_state of the room.
children_state = room.pop("children_state", [])

View File

@ -105,6 +105,7 @@ class RoomSummaryHandler:
hs.get_clock(),
"get_room_hierarchy",
)
self._msc3266_enabled = hs.config.experimental.msc3266_enabled
async def get_room_hierarchy(
self,
@ -630,7 +631,7 @@ class RoomSummaryHandler:
return False
async def _is_remote_room_accessible(
self, requester: str, room_id: str, room: JsonDict
self, requester: Optional[str], room_id: str, room: JsonDict
) -> bool:
"""
Calculate whether the room received over federation should be shown to the requester.
@ -645,7 +646,8 @@ class RoomSummaryHandler:
due to an invite, etc.
Args:
requester: The user requesting the summary.
requester: The user requesting the summary. If not passed only world
readability is checked.
room_id: The room ID returned over federation.
room: The summary of the room returned over federation.
@ -659,6 +661,8 @@ class RoomSummaryHandler:
or room.get("world_readable") is True
):
return True
elif not requester:
return False
# Check if the user is a member of any of the allowed rooms from the response.
allowed_rooms = room.get("allowed_room_ids")
@ -715,6 +719,10 @@ class RoomSummaryHandler:
"room_type": create_event.content.get(EventContentFields.ROOM_TYPE),
}
if self._msc3266_enabled:
entry["im.nheko.summary.version"] = stats["version"]
entry["im.nheko.summary.encryption"] = stats["encryption"]
# Federation requests need to provide additional information so the
# requested server is able to filter the response appropriately.
if for_federation:
@ -812,9 +820,45 @@ class RoomSummaryHandler:
room_summary["membership"] = membership or "leave"
else:
# TODO federation API, descoped from initial unstable implementation
# as MSC needs more maturing on that side.
raise SynapseError(400, "Federation is not currently supported.")
# Reuse the hierarchy query over federation
if remote_room_hosts is None:
raise SynapseError(400, "Missing via to query remote room")
(
room_entry,
children_room_entries,
inaccessible_children,
) = await self._summarize_remote_room_hierarchy(
_RoomQueueEntry(room_id, remote_room_hosts),
suggested_only=True,
)
# The results over federation might include rooms that we, as the
# requesting server, are allowed to see, but the requesting user is
# not permitted to see.
#
# Filter the returned results to only what is accessible to the user.
if not room_entry or not await self._is_remote_room_accessible(
requester, room_entry.room_id, room_entry.room
):
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
# room is purged even for remote rooms.
if requester:
(
membership,
_,
) = await self._store.get_local_current_membership_for_user_in_room(
requester, room_id
)
room["membership"] = membership or "leave"
return room
return room_summary

View File

@ -1092,3 +1092,29 @@ class RoomSummaryTestCase(unittest.HomeserverTestCase):
)
result = self.get_success(self.handler.get_room_summary(user2, self.room))
self.assertEqual(result.get("room_id"), self.room)
def test_fed(self):
"""
Return data over federation and ensure that it is handled properly.
"""
fed_hostname = self.hs.hostname + "2"
fed_room = "#fed_room:" + fed_hostname
requested_room_entry = _RoomEntry(
fed_room,
{"room_id": fed_room, "world_readable": True},
)
async def summarize_remote_room_hierarchy(_self, room, suggested_only):
return requested_room_entry, {}, set()
with mock.patch(
"synapse.handlers.room_summary.RoomSummaryHandler._summarize_remote_room_hierarchy",
new=summarize_remote_room_hierarchy,
):
result = self.get_success(
self.handler.get_room_summary(
self.user, fed_room, remote_room_hosts=[fed_hostname]
)
)
self.assertEqual(result.get("room_id"), fed_room)