diff --git a/synapse/config/experimental.py b/synapse/config/experimental.py index dc5e096791..76ca9b46c7 100644 --- a/synapse/config/experimental.py +++ b/synapse/config/experimental.py @@ -3,6 +3,7 @@ # # Copyright 2021 The Matrix.org Foundation C.I.C. # Copyright (C) 2023 New Vector, Ltd +# Copyright (C) 2025 Element Creations Ltd # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -533,6 +534,9 @@ class ExperimentalConfig(Config): "msc4108_delegation_endpoint", None ) + # MSC4370: Get extremities federation endpoint + self.msc4370_enabled = experimental.get("msc4370_enabled", False) + auth_delegated = self.msc3861.enabled or ( config.get("matrix_authentication_service") or {} ).get("enabled", False) diff --git a/synapse/federation/federation_server.py b/synapse/federation/federation_server.py index b909f1e595..53b422bb94 100644 --- a/synapse/federation/federation_server.py +++ b/synapse/federation/federation_server.py @@ -4,6 +4,7 @@ # Copyright 2019-2021 Matrix.org Federation C.I.C # Copyright 2015, 2016 OpenMarket Ltd # Copyright (C) 2023 New Vector, Ltd +# Copyright (C) 2025 Element Creations Ltd # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -683,6 +684,16 @@ class FederationServer(FederationBase): resp = await self.registry.on_query(query_type, args) return 200, resp + async def on_get_extremities_request(self, origin: str, room_id: str) -> JsonDict: + origin_host, _ = parse_server_name(origin) + await self.check_server_matches_acl(origin_host, room_id) + + await self._event_auth_handler.assert_host_in_room(room_id, origin) + + extremities = await self.store.get_forward_extremities_for_room(room_id) + prev_event_ids = list(e[0] for e in extremities) + return {"prev_events": prev_event_ids} + async def on_make_join_request( self, origin: str, room_id: str, user_id: str, supported_versions: list[str] ) -> dict[str, Any]: diff --git a/synapse/federation/transport/server/__init__.py b/synapse/federation/transport/server/__init__.py index 6d92d00523..0eff49cf73 100644 --- a/synapse/federation/transport/server/__init__.py +++ b/synapse/federation/transport/server/__init__.py @@ -4,6 +4,7 @@ # Copyright 2020 Sorunome # Copyright 2014-2021 The Matrix.org Foundation C.I.C. # Copyright (C) 2023 New Vector, Ltd +# Copyright (C) 2025 Element Creations Ltd # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -33,6 +34,7 @@ from synapse.federation.transport.server.federation import ( FederationMediaDownloadServlet, FederationMediaThumbnailServlet, FederationUnstableClientKeysClaimServlet, + FederationUnstableGetExtremitiesServlet, ) from synapse.http.server import HttpServer, JsonResource from synapse.http.servlet import ( @@ -326,6 +328,12 @@ def register_servlets( if not hs.config.media.can_load_media_repo: continue + if ( + servletclass == FederationUnstableGetExtremitiesServlet + and not hs.config.experimental.msc4370_enabled + ): + continue + servletclass( hs=hs, authenticator=authenticator, diff --git a/synapse/federation/transport/server/federation.py b/synapse/federation/transport/server/federation.py index a7c297c0b7..d783e6da51 100644 --- a/synapse/federation/transport/server/federation.py +++ b/synapse/federation/transport/server/federation.py @@ -1,8 +1,9 @@ # # This file is licensed under the Affero General Public License (AGPL) version 3. # -# Copyright 2021 The Matrix.org Foundation C.I.C. +# Copyright 2021 The Matrix.org Foundation C.I.C. # Copyright (C) 2023 New Vector, Ltd +# Copyright (C) 2025 Element Creations Ltd # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -273,6 +274,22 @@ class FederationQueryServlet(BaseFederationServerServlet): return await self.handler.on_query_request(query_type, args) +class FederationUnstableGetExtremitiesServlet(BaseFederationServerServlet): + PREFIX = FEDERATION_UNSTABLE_PREFIX + "/org.matrix.msc4370" + PATH = "/extremities/(?P[^/]*)" + CATEGORY = "Federation requests" + + async def on_GET( + self, + origin: str, + content: Literal[None], + query: dict[bytes, list[bytes]], + room_id: str, + ) -> tuple[int, JsonDict]: + result = await self.handler.on_get_extremities_request(origin, room_id) + return 200, result + + class FederationMakeJoinServlet(BaseFederationServerServlet): PATH = "/make_join/(?P[^/]*)/(?P[^/]*)" CATEGORY = "Federation requests" @@ -884,6 +901,7 @@ FEDERATION_SERVLET_CLASSES: tuple[type[BaseFederationServlet], ...] = ( FederationBackfillServlet, FederationTimestampLookupServlet, FederationQueryServlet, + FederationUnstableGetExtremitiesServlet, FederationMakeJoinServlet, FederationMakeLeaveServlet, FederationEventServlet,