From bf9ab2f2e061a690efeb29c4829004909aa74b21 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 9 Jul 2026 17:41:17 -0500 Subject: [PATCH] Refactor to include `inviter_user_id` as part of stripped state See: - https://github.com/element-hq/synapse/pull/19723#discussion_r3318830203 - https://github.com/matrix-org/sytest/pull/1425#discussion_r3319446010 --- synapse/federation/federation_client.py | 4 +- synapse/federation/federation_server.py | 8 +-- synapse/handlers/message.py | 12 +++-- .../storage/databases/main/events_worker.py | 51 ++++++++++++------- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/synapse/federation/federation_client.py b/synapse/federation/federation_client.py index 3ccaf6614d..57bee8a9d4 100644 --- a/synapse/federation/federation_client.py +++ b/synapse/federation/federation_client.py @@ -144,7 +144,6 @@ class FederationClient(FederationBase): self.server_name = hs.hostname self.signing_key = hs.signing_key - self._room_prejoin_state_types = hs.config.api.room_prejoin_state # Cache mapping `event_id` to a tuple of the event itself and the `pull_origin` # (which server we pulled the event from) @@ -1367,7 +1366,8 @@ class FederationClient(FederationBase): # # Find the full events based on the state at the time of the invite state_ids = await self.store.get_stripped_room_state_ids_from_event_context( - context, self._room_prejoin_state_types + context, + self.store.calculate_stripped_state_filter(inviter_user_id=pdu.sender), ) state_events = await self.store.get_events(state_ids) assert set(state_ids) == set(state_events.keys()), ( diff --git a/synapse/federation/federation_server.py b/synapse/federation/federation_server.py index 9cb5b9f8e5..dfd7c19983 100644 --- a/synapse/federation/federation_server.py +++ b/synapse/federation/federation_server.py @@ -194,8 +194,6 @@ class FederationServer(FederationBase): hs.config.federation.federation_metrics_domains ) - self._room_prejoin_state_types = hs.config.api.room_prejoin_state - # Whether we have started handling old events in the staging area. self._started_handling_of_staged_events = False @@ -1031,7 +1029,11 @@ class FederationServer(FederationBase): # # Find the full events based on the state at the time of the knock state_ids = await self.store.get_stripped_room_state_ids_from_event_context( - context, self._room_prejoin_state_types + context, + self.store.calculate_stripped_state_filter( + # None as this is a knock, not an invite + inviter_user_id=None + ), ) state_events = await self.store.get_events(state_ids) assert set(state_ids) == set(state_events.keys()), ( diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py index 491e6d8789..fe58462e17 100644 --- a/synapse/handlers/message.py +++ b/synapse/handlers/message.py @@ -509,8 +509,6 @@ class EventCreationHandler: self._worker_lock_handler = hs.get_worker_locks_handler() self._policy_handler = hs.get_room_policy_handler() - self.room_prejoin_state_types = self.hs.config.api.room_prejoin_state - self.send_events = ReplicationSendEventsRestServlet.make_client(hs) self.request_ratelimiter = hs.get_request_ratelimiter() @@ -2079,8 +2077,9 @@ class EventCreationHandler: "invite_room_state", await self.store.get_stripped_room_state_from_event_context( context, - self.room_prejoin_state_types, - membership_user_id=event.sender, + self.store.calculate_stripped_state_filter( + inviter_user_id=event.sender + ), ), ) @@ -2104,7 +2103,10 @@ class EventCreationHandler: "knock_room_state", await self.store.get_stripped_room_state_from_event_context( context, - self.room_prejoin_state_types, + self.store.calculate_stripped_state_filter( + # None as this is a knock, not an invite + inviter_user_id=None + ), ), ) diff --git a/synapse/storage/databases/main/events_worker.py b/synapse/storage/databases/main/events_worker.py index 9d1ef617d0..2cc4538b59 100644 --- a/synapse/storage/databases/main/events_worker.py +++ b/synapse/storage/databases/main/events_worker.py @@ -385,6 +385,8 @@ class EventsWorkerStore(SQLBaseStore): finished (so we don't have to keep querying it every time) """ + self._room_prejoin_state_types = hs.config.api.room_prejoin_state + def get_un_partial_stated_events_token(self, instance_name: str) -> int: return ( self._un_partial_stated_events_stream_id_gen.get_current_token_for_writer( @@ -1125,16 +1127,42 @@ class EventsWorkerStore(SQLBaseStore): return event_map + def calculate_stripped_state_filter( + self, + *, + inviter_user_id: str | None = None, + ) -> StateFilter: + """ + Calculate the stripped state filter necessary for an event + + Args: + inviter_user_id: An optional user ID to include the stripped membership state + 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. + """ + state_filter = self._room_prejoin_state_types + + # Include the state for `inviter_user_id` if specified + # + # FIXME: Doesn't seem to be in the spec + if inviter_user_id: + types = chain( + self._room_prejoin_state_types.to_types(), + [(EventTypes.Member, inviter_user_id)], + ) + state_filter = StateFilter.from_types(types) + + return state_filter + async def get_stripped_room_state_from_event_context( self, context: EventContext, state_keys_to_include: StateFilter, - membership_user_id: str | None = None, ) -> list[JsonDict]: """ Retrieve the stripped state from a room, given an event context to retrieve state - from as well as the state types to include. Optionally, include the membership - events from a specific user. + from as well as the state types to include. "Stripped" state means that only the `type`, `state_key`, `content` and `sender` keys are included from each state event. @@ -1142,25 +1170,13 @@ class EventsWorkerStore(SQLBaseStore): Args: context: The event context to retrieve state of the room from. state_keys_to_include: The state events to include, for each event type. - membership_user_id: An optional user ID to include the stripped membership state - 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. Returns: A list of dictionaries, each representing a stripped state event from the room. """ - if membership_user_id: - types = chain( - state_keys_to_include.to_types(), - [(EventTypes.Member, membership_user_id)], - ) - filter = StateFilter.from_types(types) - else: - filter = state_keys_to_include selected_state_ids = await self.get_stripped_room_state_ids_from_event_context( - context, filter + context, state_keys_to_include ) state_to_include = await self.get_events(selected_state_ids) @@ -1174,8 +1190,7 @@ class EventsWorkerStore(SQLBaseStore): ) -> list[str]: """ Retrieve the stripped state IDs for an event, given an event context to retrieve state - from as well as the state types to include. Optionally, include the membership - events from a specific user. + from as well as the state types to include. "Stripped" state means that only the `type`, `state_key`, `content` and `sender` keys are included from each state event.