Use PDUs for stripped state over federation

As per MSC4311 updates.
This commit is contained in:
Travis Ralston
2025-08-14 19:11:40 -06:00
parent 5c20a60f0b
commit b3ac429043
6 changed files with 35 additions and 15 deletions

View File

@@ -870,7 +870,7 @@ def maybe_upsert_event_field(
return upsert_okay
def strip_event(event: EventBase) -> JsonDict:
def strip_event(event: EventBase, for_federation: Optional[bool] = False) -> JsonDict:
"""
Used for "stripped state" events which provide a simplified view of the state of a
room intended to help a potential joiner identify the room (relevant when the user
@@ -879,13 +879,10 @@ def strip_event(event: EventBase) -> JsonDict:
Stripped state events can only have the `sender`, `type`, `state_key` and `content`
properties present.
"""
# MSC4311: Ensure the create event is available on invites and knocks.
# TODO: Implement the rest of MSC4311
if (
event.room_version.msc4291_room_ids_as_hashes
and event.type == EventTypes.Create
and event.get_state_key() == ""
):
# MSC4311 makes all stripped state events fully-formed PDUs over federation,
# especially the `m.room.create` event.
# TODO: Implement the validation component of MSC4311
if for_federation:
return event.get_pdu_json()
return {

View File

@@ -1336,10 +1336,16 @@ class FederationClient(FederationBase):
room_id: str,
event_id: str,
pdu: EventBase,
stripped_state: List[JsonDict],
) -> EventBase:
room_version = await self.store.get_room_version(room_id)
content = await self._do_send_invite(destination, pdu, room_version)
content = await self._do_send_invite(
destination,
pdu,
room_version,
stripped_state,
)
pdu_dict = content["event"]
@@ -1360,7 +1366,11 @@ class FederationClient(FederationBase):
return pdu
async def _do_send_invite(
self, destination: str, pdu: EventBase, room_version: RoomVersion
self,
destination: str,
pdu: EventBase,
room_version: RoomVersion,
stripped_state: List[JsonDict],
) -> JsonDict:
"""Actually sends the invite, first trying v2 API and falling back to
v1 API if necessary.
@@ -1383,7 +1393,7 @@ class FederationClient(FederationBase):
content={
"event": pdu.get_pdu_json(time_now),
"room_version": room_version.identifier,
"invite_room_state": pdu.unsigned.get("invite_room_state", []),
"invite_room_state": stripped_state,
},
)
except HttpResponseException as e:

View File

@@ -907,7 +907,7 @@ class FederationServer(FederationBase):
# related to the room while the knock request is pending.
stripped_room_state = (
await self.store.get_stripped_room_state_from_event_context(
context, self._room_prejoin_state_types
context, self._room_prejoin_state_types, for_federation=True,
)
)
return {"knock_room_state": stripped_room_state}

View File

@@ -547,7 +547,7 @@ class FederationHandler:
return False
async def send_invite(self, target_host: str, event: EventBase) -> EventBase:
async def send_invite(self, target_host: str, event: EventBase, stripped_state: List[JsonDict]) -> EventBase:
"""Sends the invite to the remote server for signing.
Invites must be signed by the invitee's server before distribution.
@@ -558,6 +558,7 @@ class FederationHandler:
room_id=event.room_id,
event_id=event.event_id,
pdu=event,
stripped_state=stripped_state,
)
except RequestSendFailed:
raise SynapseError(502, f"Can't connect to server {target_host}")

View File

@@ -1973,8 +1973,17 @@ class EventCreationHandler:
# way? If we have been invited by a remote server, we need
# to get them to sign the event.
# As of MSC4311, "stripped" state events are formatted differently
# over federation.
stripped_state_fed = await self.store.get_stripped_room_state_from_event_context(
context,
self.room_prejoin_state_types,
membership_user_id=event.sender,
for_federation=True,
)
returned_invite = await federation_handler.send_invite(
invitee.domain, event
invitee.domain, event, stripped_state_fed,
)
event.unsigned.pop("room_state", None)

View File

@@ -1094,6 +1094,7 @@ class EventsWorkerStore(SQLBaseStore):
context: EventContext,
state_keys_to_include: StateFilter,
membership_user_id: Optional[str] = None,
for_federation: Optional[bool] = False,
) -> List[JsonDict]:
"""
Retrieve the stripped state from a room, given an event context to retrieve state
@@ -1110,6 +1111,8 @@ class EventsWorkerStore(SQLBaseStore):
events of. This is useful when generating the stripped state of a room for
invites. We want to send membership events of the inviter, so that the
invitee can display the inviter's profile information if the room lacks any.
for_federation: When True, the stripped state events will be returned as PDUs
as per MSC4311. When False, the stripped client format is used.
Returns:
A list of dictionaries, each representing a stripped state event from the room.
@@ -1134,7 +1137,7 @@ class EventsWorkerStore(SQLBaseStore):
state_to_include = await self.get_events(selected_state_ids.values())
return [strip_event(e) for e in state_to_include.values()]
return [strip_event(e, for_federation) for e in state_to_include.values()]
def _maybe_start_fetch_thread(self) -> None:
"""Starts an event fetch thread if we are not yet at the maximum number."""