summary refs log tree commit diff
path: root/synapse
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--synapse/federation/federation_client.py20
-rw-r--r--synapse/federation/federation_server.py14
-rw-r--r--synapse/federation/transport/client.py7
-rw-r--r--synapse/handlers/federation.py14
4 files changed, 46 insertions, 9 deletions
diff --git a/synapse/federation/federation_client.py b/synapse/federation/federation_client.py
index ffd1781252..b32b548500 100644
--- a/synapse/federation/federation_client.py
+++ b/synapse/federation/federation_client.py
@@ -881,7 +881,7 @@ class FederationClient(FederationBase):
         # content.
         return resp[1]
 
-    async def send_knock(self, destinations: List[str], pdu: EventBase):
+    async def send_knock(self, destinations: List[str], pdu: EventBase) -> JsonDict:
         """Attempts to send a knock event to given a list of servers. Iterates
         through the list until one attempt succeeds.
 
@@ -893,6 +893,14 @@ class FederationClient(FederationBase):
                 participating in the room.
             pdu: The event to be sent.
 
+        Returns:
+            The remote homeserver return some state from the room. The response
+            dictionary is in the form:
+
+            {"knock_state_events": [<state event dict>, ...]}
+
+            The list of state events may be empty.
+
         Raises:
             SynapseError: If the chosen remote server returns a 3xx/4xx code.
             RuntimeError: If no servers were reachable.
@@ -905,12 +913,20 @@ class FederationClient(FederationBase):
             "send_knock", destinations, send_request
         )
 
-    async def _do_send_knock(self, destination: str, pdu: EventBase):
+    async def _do_send_knock(self, destination: str, pdu: EventBase) -> JsonDict:
         """Send a knock event to a remote homeserver.
 
         Args:
             destination: The homeserver to send to.
             pdu: The event to send.
+
+        Returns:
+            The remote homeserver can optionally return some state from the room. The response
+            dictionary is in the form:
+
+            {"knock_state_events": [<state event dict>, ...]}
+
+            The list of state events may be empty.
         """
         time_now = self._clock.time_msec()
 
diff --git a/synapse/federation/federation_server.py b/synapse/federation/federation_server.py
index 50c8a64aa8..3417f62916 100644
--- a/synapse/federation/federation_server.py
+++ b/synapse/federation/federation_server.py
@@ -118,6 +118,8 @@ class FederationServer(FederationBase):
             hs, "fed_txn_handler", timeout_ms=30000
         )  # type: ResponseCache[Tuple[str, str]]
 
+        self._room_knock_state_types = hs.config.room_knock_state_types
+
         self.transaction_actions = TransactionActions(self.store)
 
         self.registry = hs.get_federation_registry()
@@ -588,10 +590,16 @@ class FederationServer(FederationBase):
 
         pdu = await self._check_sigs_and_hash(room_version, pdu)
 
-        # Handle the event
-        await self.handler.on_send_knock_request(origin, pdu)
+        # Handle the event, and retrieve the EventContext
+        event_context = await self.handler.on_send_knock_request(origin, pdu)
 
-        return {}
+        # Retrieve stripped state events from the room and send them back to the remote
+        # server. This will allow the remote server's clients to display information
+        # related to the room while the knock request is pending.
+        stripped_room_state = await self.store.get_stripped_room_state_from_event_context(
+            event_context, self._room_knock_state_types
+        )
+        return {"knock_state_events": stripped_room_state}
 
     async def on_event_auth(
         self, origin: str, room_id: str, event_id: str
diff --git a/synapse/federation/transport/client.py b/synapse/federation/transport/client.py
index 4650c009f9..ca369af2de 100644
--- a/synapse/federation/transport/client.py
+++ b/synapse/federation/transport/client.py
@@ -313,7 +313,12 @@ class TransportLayerClient:
                 itself represented as a JSON dict.
 
         Returns:
-            An empty JSON dictionary.
+            The remote homeserver can optionally return some state from the room. The response
+            dictionary is in the form:
+
+            {"knock_state_events": [<state event dict>, ...]}
+
+            The list of state events may be empty.
         """
         path = _create_v1_path("/send_knock/%s/%s", room_id, event_id)
 
diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py
index c89b5d61d4..377180886f 100644
--- a/synapse/handlers/federation.py
+++ b/synapse/handlers/federation.py
@@ -1484,10 +1484,18 @@ class FederationHandler(BaseHandler):
         except ValueError:
             pass
 
-        # Send the signed event back to the room
-        await self.federation_client.send_knock(target_hosts, event)
+        # Send the signed event back to the room, and potentially receive some
+        # further information about the room in the form of partial state events
+        stripped_room_state = await self.federation_client.send_knock(
+            target_hosts, event
+        )
+
+        # Store any stripped room state events in the "unsigned" key of the event.
+        # This is a bit of a hack and is cribbing off of invites. Basically we
+        # store the room state here and retrieve it again when this event appears
+        # in the invitee's sync stream. It is stripped out for all other local users.
+        event.unsigned["knock_room_state"] = stripped_room_state["knock_state_events"]
 
-        # Store the event locally
         context = await self.state_handler.compute_event_context(event)
         stream_id = await self.persist_events_and_notify(
             event.room_id, [(event, context)]