Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/19002.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix bug where ephemeral events were not filtered by room ID. Contributed by @frastefanini.
22 changes: 10 additions & 12 deletions synapse/handlers/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ async def ephemeral_by_room(
Returns:
A tuple of the now StreamToken, updated to reflect the which typing
events are included, and a dict mapping from room_id to a list of
typing events for that room.
ephemeral events for that room.
"""

sync_config = sync_result_builder.sync_config
Expand All @@ -578,12 +578,8 @@ async def ephemeral_by_room(
ephemeral_by_room: JsonDict = {}

for event in typing:
# we want to exclude the room_id from the event, but modifying the
# result returned by the event source is poor form (it might cache
# the object)
room_id = event["room_id"]
event_copy = {k: v for (k, v) in event.items() if k != "room_id"}
ephemeral_by_room.setdefault(room_id, []).append(event_copy)
ephemeral_by_room.setdefault(room_id, []).append(event)

receipt_key = (
since_token.receipt_key
Expand All @@ -603,9 +599,7 @@ async def ephemeral_by_room(

for event in receipts:
room_id = event["room_id"]
# exclude room id, as above
event_copy = {k: v for (k, v) in event.items() if k != "room_id"}
ephemeral_by_room.setdefault(room_id, []).append(event_copy)
ephemeral_by_room.setdefault(room_id, []).append(event)

return now_token, ephemeral_by_room

Expand Down Expand Up @@ -2734,9 +2728,13 @@ async def _generate_room_entry(
)
)

ephemeral = await sync_config.filter_collection.filter_room_ephemeral(
ephemeral
)
ephemeral = [
# copy fields from each `event` into a new dict, excluding `room_id`
Copy link
Copy Markdown
Contributor

@MadLittleMods MadLittleMods Oct 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we want to exclude the room_id? (feels like some comment context is missing)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is explained in the Complement tests -> matrix-org/complement#807

	// Receipt events include a `room_id` field over federation, but they should
	// not do so down `/sync` to clients. Ensure homeservers strip that field out.

	// Typing events include a `room_id` field over federation, but they should
	// not do so down `/sync` to clients. Ensure homeservers strip that field out.

We should explain this in the comments here as well

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve added more context to the comment. Let me know if it’s enough.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was updated to the following:

# per spec, ephemeral events (typing notifications and read receipts)
# should not have a `room_id` field when sent to clients
# refs:
# - https://spec.matrix.org/v1.16/client-server-api/#mtyping
# - https://spec.matrix.org/v1.16/client-server-api/#mreceipt

I think we could explain more about where room_id is coming from in the first place since it isn't desired when passing it back to the client.

Suggested change
# copy fields from each `event` into a new dict, excluding `room_id`
# Over federation, read receipt and typing notification EDU's include a
# `room_id` field (because xxx if there is a reason), but the `room_id`
# should be stripped out before passing it back to the client (according
# to the spec). See:
# - https://spec.matrix.org/v1.16/client-server-api/#mtyping
# - https://spec.matrix.org/v1.16/client-server-api/#mreceipt

Are we sure this even needs to happen? The server spec says EDU's don't include a room_id:

EDUs, by comparison to PDUs, do not have an ID, a room ID, or a list of “previous” IDs. They are intended to be non-persistent data such as user presence, typing notifications, etc.

-- https://spec.matrix.org/v1.15/server-server-api/#edus

Overall, EDU's are just not clear to me.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anoadragon453 responded below (threading problems) -> #19002 (comment)

Comment thread
MadLittleMods marked this conversation as resolved.
Outdated
{k: v for (k, v) in event.items() if k != "room_id"}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main difference I see from the previous implementation is that we previously we only removed the room_id from typing and receipt EDU.

But now we filter room_id from everything. I don't really see context for whether that is actually desired.


The other fix where we pass in the the full EDU to filter_room_ephemeral(...) makes sense

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ephemeral_by_room should only return typing and receipt events that are tied to a room. If we introduce a new room-linked EDU type, then I suspect that will also need the room_id field removed before being sent down /sync.

I don't see a functional change, and I think the conceptual change is OK?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explaining 👍 I didn't pick up on the tenuous connection.

for event in await sync_config.filter_collection.filter_room_ephemeral(
ephemeral
)
]

if not (
always_include
Expand Down
Loading