mirror of
https://mau.dev/maunium/synapse.git
synced 2024-12-13 22:13:29 +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")
|
room = res.get("room")
|
||||||
if not isinstance(room, dict):
|
if not isinstance(room, dict):
|
||||||
raise InvalidResponseError("'room' must be a 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.
|
# Validate children_state of the room.
|
||||||
children_state = room.pop("children_state", [])
|
children_state = room.pop("children_state", [])
|
||||||
|
|
|
@ -105,6 +105,7 @@ class RoomSummaryHandler:
|
||||||
hs.get_clock(),
|
hs.get_clock(),
|
||||||
"get_room_hierarchy",
|
"get_room_hierarchy",
|
||||||
)
|
)
|
||||||
|
self._msc3266_enabled = hs.config.experimental.msc3266_enabled
|
||||||
|
|
||||||
async def get_room_hierarchy(
|
async def get_room_hierarchy(
|
||||||
self,
|
self,
|
||||||
|
@ -630,7 +631,7 @@ class RoomSummaryHandler:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def _is_remote_room_accessible(
|
async def _is_remote_room_accessible(
|
||||||
self, requester: str, room_id: str, room: JsonDict
|
self, requester: Optional[str], room_id: str, room: JsonDict
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Calculate whether the room received over federation should be shown to the requester.
|
Calculate whether the room received over federation should be shown to the requester.
|
||||||
|
@ -645,7 +646,8 @@ class RoomSummaryHandler:
|
||||||
due to an invite, etc.
|
due to an invite, etc.
|
||||||
|
|
||||||
Args:
|
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_id: The room ID returned over federation.
|
||||||
room: The summary of the room 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
|
or room.get("world_readable") is True
|
||||||
):
|
):
|
||||||
return True
|
return True
|
||||||
|
elif not requester:
|
||||||
|
return False
|
||||||
|
|
||||||
# Check if the user is a member of any of the allowed rooms from the response.
|
# Check if the user is a member of any of the allowed rooms from the response.
|
||||||
allowed_rooms = room.get("allowed_room_ids")
|
allowed_rooms = room.get("allowed_room_ids")
|
||||||
|
@ -715,6 +719,10 @@ class RoomSummaryHandler:
|
||||||
"room_type": create_event.content.get(EventContentFields.ROOM_TYPE),
|
"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
|
# Federation requests need to provide additional information so the
|
||||||
# requested server is able to filter the response appropriately.
|
# requested server is able to filter the response appropriately.
|
||||||
if for_federation:
|
if for_federation:
|
||||||
|
@ -812,9 +820,45 @@ class RoomSummaryHandler:
|
||||||
|
|
||||||
room_summary["membership"] = membership or "leave"
|
room_summary["membership"] = membership or "leave"
|
||||||
else:
|
else:
|
||||||
# TODO federation API, descoped from initial unstable implementation
|
# Reuse the hierarchy query over federation
|
||||||
# as MSC needs more maturing on that side.
|
if remote_room_hosts is None:
|
||||||
raise SynapseError(400, "Federation is not currently supported.")
|
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
|
return room_summary
|
||||||
|
|
||||||
|
|
|
@ -1092,3 +1092,29 @@ class RoomSummaryTestCase(unittest.HomeserverTestCase):
|
||||||
)
|
)
|
||||||
result = self.get_success(self.handler.get_room_summary(user2, self.room))
|
result = self.get_success(self.handler.get_room_summary(user2, self.room))
|
||||||
self.assertEqual(result.get("room_id"), 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