mirror of
https://mau.dev/maunium/synapse.git
synced 2024-12-13 17:43:16 +01:00
Support MSC3266 room summaries over federation (#11507)
Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de>
This commit is contained in:
parent
ef86cf3d28
commit
a377a43386
4 changed files with 78 additions and 5 deletions
1
changelog.d/11507.feature
Normal file
1
changelog.d/11507.feature
Normal file
|
@ -0,0 +1 @@
|
|||
Support [MSC3266](https://github.com/matrix-org/matrix-doc/pull/3266) room summaries over federation.
|
|
@ -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", [])
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue