diff options
-rw-r--r-- | synapse/events/__init__.py | 18 | ||||
-rw-r--r-- | synapse/federation/federation_server.py | 23 | ||||
-rw-r--r-- | synapse/handlers/federation.py | 26 | ||||
-rw-r--r-- | tests/handlers/test_federation.py | 20 |
4 files changed, 60 insertions, 27 deletions
diff --git a/synapse/events/__init__.py b/synapse/events/__init__.py index 99b9d61847..f2f8e1a935 100644 --- a/synapse/events/__init__.py +++ b/synapse/events/__init__.py @@ -629,6 +629,24 @@ class FrozenLinearizedEvent(FrozenEventV3): pdu.pop("prev_events") return pdu + def get_templated_pdu_json(self) -> JsonDict: + """ + Return a JSON object suitable for a templated event, as used in the + make_{join,leave,knock} workflow. + """ + # By using _dict directly we don't pull in signatures/unsigned. + template_json = dict(self._dict) + # The hashes (similar to the signature) need to be recalculated by the + # joining/leaving/knocking server after (potentially) modifying the + # event. + template_json.pop("hashes") + + # Linearized Matrix servers don't know about auth/prev events. + template_json.pop("auth_events") + template_json.pop("prev_events") + + return template_json + def _event_type_from_format_version( format_version: int, diff --git a/synapse/federation/federation_server.py b/synapse/federation/federation_server.py index 61ed41c903..6e5fa82a10 100644 --- a/synapse/federation/federation_server.py +++ b/synapse/federation/federation_server.py @@ -675,12 +675,14 @@ class FederationServer(FederationBase): origin_host, _ = parse_server_name(origin) await self.check_server_matches_acl(origin_host, room_id) - room_version = await self.store.get_room_version_id(room_id) - if room_version not in supported_versions: + # checking the room version will check that we've actually heard of the room + # (and return a 404 otherwise) + room_version_id = await self.store.get_room_version_id(room_id) + if room_version_id not in supported_versions: logger.warning( - "Room version %s not in %s", room_version, supported_versions + "Room version %s not in %s", room_version_id, supported_versions ) - raise IncompatibleRoomVersionError(room_version=room_version) + raise IncompatibleRoomVersionError(room_version=room_version_id) # Refuse the request if that room has seen too many joins recently. # This is in addition to the HS-level rate limiting applied by @@ -691,8 +693,10 @@ class FederationServer(FederationBase): key=room_id, update=False, ) - pdu = await self.handler.on_make_join_request(origin, room_id, user_id) - return {"event": pdu.get_templated_pdu_json(), "room_version": room_version} + pdu = await self.handler.on_make_join_request( + origin, room_id, KNOWN_ROOM_VERSIONS[room_version_id], user_id + ) + return {"event": pdu.get_templated_pdu_json(), "room_version": room_version_id} async def on_invite_request( self, origin: str, content: JsonDict, room_version_id: str @@ -960,7 +964,12 @@ class FederationServer(FederationBase): errcode=Codes.FORBIDDEN, ) - event = event_from_pdu_json(content, room_version) + # Linearized Matrix requires building the event (i.e. adding auth/prev + # events). The input content is an LPDU. + if room_version.linearized_matrix: + event = await self._on_lpdu_event(content, room_version) + else: + event = event_from_pdu_json(content, room_version) if event.type != EventTypes.Member or not event.is_state(): raise SynapseError(400, "Not an m.room.member event", Codes.BAD_JSON) diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py index d90a14788d..84ad276ebd 100644 --- a/synapse/handlers/federation.py +++ b/synapse/handlers/federation.py @@ -899,7 +899,7 @@ class FederationHandler: ) async def on_make_join_request( - self, origin: str, room_id: str, user_id: str + self, origin: str, room_id: str, room_version: RoomVersion, user_id: str ) -> EventBase: """We've received a /make_join/ request, so we create a partial join event for the room and return that. We do *not* persist or @@ -908,6 +908,7 @@ class FederationHandler: Args: origin: The (verified) server name of the requesting server. room_id: Room to create join event in + room_version: The room's room version. user_id: The user to create the join for """ if get_domain_from_id(user_id) != origin: @@ -918,10 +919,6 @@ class FederationHandler: ) raise SynapseError(403, "User not from origin", Codes.FORBIDDEN) - # checking the room version will check that we've actually heard of the room - # (and return a 404 otherwise) - room_version = await self.store.get_room_version(room_id) - if await self.store.is_partial_state_room(room_id): # If our server is still only partially joined, we can't give a complete # response to /make_join, so return a 404 as we would if we weren't in the @@ -997,16 +994,15 @@ class FederationHandler: state_ids, ) - builder = self.event_builder_factory.for_room_version( - room_version, - { - "type": EventTypes.Member, - "content": event_content, - "room_id": room_id, - "sender": user_id, - "state_key": user_id, - }, - ) + event_dict = { + "type": EventTypes.Member, + "content": event_content, + "room_id": room_id, + "sender": user_id, + "state_key": user_id, + } + + builder = self.event_builder_factory.for_room_version(room_version, event_dict) try: ( diff --git a/tests/handlers/test_federation.py b/tests/handlers/test_federation.py index bf0862ed54..e5f67693b8 100644 --- a/tests/handlers/test_federation.py +++ b/tests/handlers/test_federation.py @@ -27,7 +27,7 @@ from synapse.api.errors import ( NotFoundError, SynapseError, ) -from synapse.api.room_versions import RoomVersions +from synapse.api.room_versions import RoomVersion, RoomVersions from synapse.events import EventBase, make_event_from_dict from synapse.federation.federation_base import event_from_pdu_json from synapse.federation.federation_client import SendJoinResult @@ -124,7 +124,9 @@ class FederationTestCase(unittest.FederatingHomeserverTestCase): room_version = self.get_success(self.store.get_room_version(room_id)) # pretend that another server has joined - join_event = self._build_and_send_join_event(OTHER_SERVER, OTHER_USER, room_id) + join_event = self._build_and_send_join_event( + OTHER_SERVER, OTHER_USER, room_id, room_version + ) # check the state group sg = self.get_success( @@ -177,7 +179,9 @@ class FederationTestCase(unittest.FederatingHomeserverTestCase): room_version = self.get_success(self.store.get_room_version(room_id)) # pretend that another server has joined - join_event = self._build_and_send_join_event(OTHER_SERVER, OTHER_USER, room_id) + join_event = self._build_and_send_join_event( + OTHER_SERVER, OTHER_USER, room_id, room_version + ) # check the state group sg = self.get_success( @@ -479,10 +483,16 @@ class FederationTestCase(unittest.FederatingHomeserverTestCase): ) def _build_and_send_join_event( - self, other_server: str, other_user: str, room_id: str + self, + other_server: str, + other_user: str, + room_id: str, + room_version: RoomVersion, ) -> EventBase: join_event = self.get_success( - self.handler.on_make_join_request(other_server, room_id, other_user) + self.handler.on_make_join_request( + other_server, room_id, room_version, other_user + ) ) # the auth code requires that a signature exists, but doesn't check that # signature... go figure. |