Transform events with client metadata before serialising in /event response. (#19340)
Some checks are pending
Build docker images / Build and push image for linux/amd64 (push) Waiting to run
Build docker images / Build and push image for linux/arm64 (push) Waiting to run
Build docker images / Push merged images to docker.io/matrixdotorg/synapse (push) Blocked by required conditions
Build docker images / Push merged images to ghcr.io/element-hq/synapse (push) Blocked by required conditions
Deploy the documentation / Calculate variables for GitHub Pages deployment (push) Waiting to run
Deploy the documentation / GitHub Pages (push) Blocked by required conditions
Build release artifacts / Calculate list of debian distros (push) Waiting to run
Build release artifacts / Build .deb packages (push) Blocked by required conditions
Build release artifacts / Build wheels on ubuntu-24.04 (push) Waiting to run
Build release artifacts / Build wheels on ubuntu-24.04-arm (push) Waiting to run
Build release artifacts / Build sdist (push) Waiting to run
Build release artifacts / Attach assets to release (push) Blocked by required conditions
Schema / Ensure Synapse config schema is valid (push) Waiting to run
Schema / Ensure generated documentation is up-to-date (push) Waiting to run
Tests / lint-crlf (push) Waiting to run
Tests / changes (push) Waiting to run
Tests / check-sampleconfig (push) Blocked by required conditions
Tests / check-schema-delta (push) Blocked by required conditions
Tests / check-lockfile (push) Waiting to run
Tests / lint (push) Blocked by required conditions
Tests / Typechecking (push) Blocked by required conditions
Tests / lint-newsfile (push) Waiting to run
Tests / lint-clippy (push) Blocked by required conditions
Tests / lint-clippy-nightly (push) Blocked by required conditions
Tests / lint-rust (push) Blocked by required conditions
Tests / lint-rustfmt (push) Blocked by required conditions
Tests / lint-readme (push) Blocked by required conditions
Tests / linting-done (push) Blocked by required conditions
Tests / calculate-test-jobs (push) Blocked by required conditions
Tests / trial (push) Blocked by required conditions
Tests / trial-olddeps (push) Blocked by required conditions
Tests / trial-pypy (all, pypy-3.10) (push) Blocked by required conditions
Tests / sytest (push) Blocked by required conditions
Tests / export-data (push) Blocked by required conditions
Tests / portdb (14, 3.10) (push) Blocked by required conditions
Tests / portdb (17, 3.14) (push) Blocked by required conditions
Tests / complement (monolith, Postgres) (push) Blocked by required conditions
Tests / complement (monolith, SQLite) (push) Blocked by required conditions
Tests / complement (workers, Postgres) (push) Blocked by required conditions
Tests / cargo-test (push) Blocked by required conditions
Tests / cargo-bench (push) Blocked by required conditions
Tests / tests-done (push) Blocked by required conditions

Fix /event/ endpoint not transforming event with per-requester metadata 

Pass notif_event through filter_events_for_client \
Not aware of an actual issue here, but seems silly to bypass it

Call it filter_and_transform_events_for_client to make it more obvious 

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
This commit is contained in:
Olivier 'reivilibre 2026-01-06 15:53:13 +00:00 committed by GitHub
parent 444bc56cda
commit cd252db3f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 50 additions and 45 deletions

1
changelog.d/19340.bugfix Normal file
View file

@ -0,0 +1 @@
Transform events with client metadata before serialising in /event response.

View file

@ -44,7 +44,7 @@ from synapse.types import (
UserInfo,
create_requester,
)
from synapse.visibility import filter_events_for_client
from synapse.visibility import filter_and_transform_events_for_client
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -251,7 +251,7 @@ class AdminHandler:
topological=last_event.depth,
)
events = await filter_events_for_client(
events = await filter_and_transform_events_for_client(
self._storage_controllers,
user_id,
events,

View file

@ -31,7 +31,7 @@ from synapse.handlers.presence import format_user_presence_state
from synapse.storage.databases.main.events_worker import EventRedactBehaviour
from synapse.streams.config import PaginationConfig
from synapse.types import JsonDict, Requester, UserID
from synapse.visibility import filter_events_for_client
from synapse.visibility import filter_and_transform_events_for_client
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -156,7 +156,9 @@ class EventHandler:
event_id: str,
show_redacted: bool = False,
) -> EventBase | None:
"""Retrieve a single specified event.
"""Retrieve a single specified event on behalf of a user.
The event will be transformed in a user-specific and time-specific way,
e.g. having unsigned metadata added or being erased depending on who is accessing.
Args:
user: The local user requesting the event
@ -188,7 +190,7 @@ class EventHandler:
# The user is peeking if they aren't in the room already
is_peeking = not is_user_in_room
filtered = await filter_events_for_client(
filtered = await filter_and_transform_events_for_client(
self._storage_controllers,
user.to_string(),
[event],
@ -198,4 +200,4 @@ class EventHandler:
if not filtered:
raise AuthError(403, "You don't have permission to access that event.")
return event
return filtered[0]

View file

@ -49,7 +49,7 @@ from synapse.types import (
from synapse.util import unwrapFirstError
from synapse.util.async_helpers import concurrently_execute, gather_results
from synapse.util.caches.response_cache import ResponseCache
from synapse.visibility import filter_events_for_client
from synapse.visibility import filter_and_transform_events_for_client
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -225,7 +225,7 @@ class InitialSyncHandler:
)
).addErrback(unwrapFirstError)
messages = await filter_events_for_client(
messages = await filter_and_transform_events_for_client(
self._storage_controllers,
user_id,
messages,
@ -382,7 +382,7 @@ class InitialSyncHandler:
room_id, limit=pagin_config.limit, end_token=stream_token
)
messages = await filter_events_for_client(
messages = await filter_and_transform_events_for_client(
self._storage_controllers,
requester.user.to_string(),
messages,
@ -496,7 +496,7 @@ class InitialSyncHandler:
).addErrback(unwrapFirstError)
)
messages = await filter_events_for_client(
messages = await filter_and_transform_events_for_client(
self._storage_controllers,
requester.user.to_string(),
messages,

View file

@ -46,7 +46,7 @@ from synapse.types.handlers import ShutdownRoomParams, ShutdownRoomResponse
from synapse.types.state import StateFilter
from synapse.util.async_helpers import ReadWriteLock
from synapse.util.duration import Duration
from synapse.visibility import filter_events_for_client
from synapse.visibility import filter_and_transform_events_for_client
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -684,7 +684,7 @@ class PaginationHandler:
events = await event_filter.filter(events)
if not use_admin_priviledge:
events = await filter_events_for_client(
events = await filter_and_transform_events_for_client(
self._storage_controllers,
user_id,
events,

View file

@ -40,7 +40,7 @@ from synapse.storage.databases.main.relations import ThreadsNextBatch, _RelatedE
from synapse.streams.config import PaginationConfig
from synapse.types import JsonDict, Requester, UserID
from synapse.util.async_helpers import gather_results
from synapse.visibility import filter_events_for_client
from synapse.visibility import filter_and_transform_events_for_client
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -154,7 +154,7 @@ class RelationsHandler:
[e.event_id for e in related_events]
)
events = await filter_events_for_client(
events = await filter_and_transform_events_for_client(
self._storage_controllers,
user_id,
events,
@ -599,7 +599,7 @@ class RelationsHandler:
# Limit the returned threads to those the user has participated in.
events = [event for event in events if participated[event.event_id]]
events = await filter_events_for_client(
events = await filter_and_transform_events_for_client(
self._storage_controllers,
user_id,
events,

View file

@ -95,7 +95,7 @@ from synapse.util.caches.response_cache import ResponseCache
from synapse.util.duration import Duration
from synapse.util.iterutils import batch_iter
from synapse.util.stringutils import parse_and_validate_server_name
from synapse.visibility import filter_events_for_client
from synapse.visibility import filter_and_transform_events_for_client
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -1919,7 +1919,7 @@ class RoomContextHandler:
async def filter_evts(events: list[EventBase]) -> list[EventBase]:
if use_admin_priviledge:
return events
return await filter_events_for_client(
return await filter_and_transform_events_for_client(
self._storage_controllers,
user.to_string(),
events,

View file

@ -33,7 +33,7 @@ from synapse.events import EventBase
from synapse.events.utils import SerializeEventConfig
from synapse.types import JsonDict, Requester, StrCollection, StreamKeyType, UserID
from synapse.types.state import StateFilter
from synapse.visibility import filter_events_for_client
from synapse.visibility import filter_and_transform_events_for_client
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -479,7 +479,7 @@ class SearchHandler:
filtered_events = await search_filter.filter([r["event"] for r in results])
events = await filter_events_for_client(
events = await filter_and_transform_events_for_client(
self._storage_controllers,
user.to_string(),
filtered_events,
@ -580,7 +580,7 @@ class SearchHandler:
filtered_events = await search_filter.filter([r["event"] for r in results])
events = await filter_events_for_client(
events = await filter_and_transform_events_for_client(
self._storage_controllers,
user.to_string(),
filtered_events,
@ -667,13 +667,13 @@ class SearchHandler:
len(res.events_after),
)
events_before = await filter_events_for_client(
events_before = await filter_and_transform_events_for_client(
self._storage_controllers,
user.to_string(),
res.events_before,
)
events_after = await filter_events_for_client(
events_after = await filter_and_transform_events_for_client(
self._storage_controllers,
user.to_string(),
res.events_after,

View file

@ -71,7 +71,7 @@ from synapse.types.handlers.sliding_sync import (
)
from synapse.types.state import StateFilter
from synapse.util.async_helpers import concurrently_execute
from synapse.visibility import filter_events_for_client
from synapse.visibility import filter_and_transform_events_for_client
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -755,7 +755,7 @@ class SlidingSyncHandler:
timeline_events.reverse()
# Make sure we don't expose any events that the client shouldn't see
timeline_events = await filter_events_for_client(
timeline_events = await filter_and_transform_events_for_client(
self.storage_controllers,
user.to_string(),
timeline_events,

View file

@ -78,7 +78,7 @@ from synapse.util.caches.expiringcache import ExpiringCache
from synapse.util.caches.lrucache import LruCache
from synapse.util.caches.response_cache import ResponseCache, ResponseCacheContext
from synapse.util.metrics import Measure
from synapse.visibility import filter_events_for_client
from synapse.visibility import filter_and_transform_events_for_client
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -679,7 +679,7 @@ class SyncHandler:
)
)
recents = await filter_events_for_client(
recents = await filter_and_transform_events_for_client(
self._storage_controllers,
sync_config.user.to_string(),
recents,
@ -789,7 +789,7 @@ class SyncHandler:
)
)
loaded_recents = await filter_events_for_client(
loaded_recents = await filter_and_transform_events_for_client(
self._storage_controllers,
sync_config.user.to_string(),
loaded_recents,

View file

@ -63,7 +63,7 @@ from synapse.util.async_helpers import (
)
from synapse.util.duration import Duration
from synapse.util.stringutils import shortstr
from synapse.visibility import filter_events_for_client
from synapse.visibility import filter_and_transform_events_for_client
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -783,7 +783,7 @@ class Notifier:
)
if keyname == StreamKeyType.ROOM:
new_events = await filter_events_for_client(
new_events = await filter_and_transform_events_for_client(
self._storage_controllers,
user.to_string(),
new_events,

View file

@ -49,7 +49,7 @@ from synapse.storage.databases.main.event_push_actions import EmailPushAction
from synapse.types import StateMap, UserID
from synapse.types.state import StateFilter
from synapse.util.async_helpers import concurrently_execute
from synapse.visibility import filter_events_for_client
from synapse.visibility import filter_and_transform_events_for_client
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -537,12 +537,11 @@ class Mailer:
"messages": [],
}
the_events = await filter_events_for_client(
the_events = await filter_and_transform_events_for_client(
self._storage_controllers,
user_id,
results.events_before,
results.events_before + [notif_event],
)
the_events.append(notif_event)
for event in the_events:
messagevars = await self._get_message_vars(notif, event, room_state_ids)

View file

@ -75,7 +75,7 @@ _HISTORY_VIS_KEY: Final[tuple[str, str]] = (EventTypes.RoomHistoryVisibility, ""
@trace
async def filter_events_for_client(
async def filter_and_transform_events_for_client(
storage: StorageControllers,
user_id: str,
events: list[EventBase],

View file

@ -28,7 +28,7 @@ from synapse.rest.client import login, room
from synapse.server import HomeServer
from synapse.types import JsonDict, create_requester
from synapse.util.clock import Clock
from synapse.visibility import filter_events_for_client
from synapse.visibility import filter_and_transform_events_for_client
from tests import unittest
from tests.unittest import override_config
@ -163,7 +163,7 @@ class RetentionTestCase(unittest.HomeserverTestCase):
)
self.assertEqual(2, len(events), "events retrieved from database")
filtered_events = self.get_success(
filter_events_for_client(
filter_and_transform_events_for_client(
storage_controllers,
self.user_id,
events,

View file

@ -31,7 +31,10 @@ from synapse.rest.client import login, room
from synapse.server import HomeServer
from synapse.types import create_requester
from synapse.util.clock import Clock
from synapse.visibility import filter_events_for_client, filter_events_for_server
from synapse.visibility import (
filter_and_transform_events_for_client,
filter_events_for_server,
)
from tests import unittest
from tests.test_utils.event_injection import inject_event, inject_member_event
@ -330,7 +333,7 @@ class FilterEventsForServerAdminsTestCase(HomeserverTestCase):
# Do filter & assert
filtered_events = self.get_success(
filter_events_for_client(
filter_and_transform_events_for_client(
self.hs.get_storage_controllers(),
"@admin:test",
events_to_filter,
@ -369,7 +372,7 @@ class FilterEventsForServerAdminsTestCase(HomeserverTestCase):
# Do filter & assert
filtered_events = self.get_success(
filter_events_for_client(
filter_and_transform_events_for_client(
self.hs.get_storage_controllers(),
"@admin:test",
events_to_filter,
@ -416,7 +419,7 @@ class FilterEventsForServerAdminsTestCase(HomeserverTestCase):
# Do filter & assert
filtered_events = self.get_success(
filter_events_for_client(
filter_and_transform_events_for_client(
self.hs.get_storage_controllers(),
"@admin:test",
events_to_filter,
@ -463,7 +466,7 @@ class FilterEventsForServerAdminsTestCase(HomeserverTestCase):
# Do filter & assert
filtered_events = self.get_success(
filter_events_for_client(
filter_and_transform_events_for_client(
self.hs.get_storage_controllers(),
"@admin:test",
events_to_filter,
@ -538,14 +541,14 @@ class FilterEventsForClientTestCase(HomeserverTestCase):
# accidentally serving the same event object (with the same unsigned.membership
# property) to both users.
joiner_filtered_events = self.get_success(
filter_events_for_client(
filter_and_transform_events_for_client(
self.hs.get_storage_controllers(),
"@joiner:test",
events_to_filter,
)
)
resident_filtered_events = self.get_success(
filter_events_for_client(
filter_and_transform_events_for_client(
self.hs.get_storage_controllers(),
"@resident:test",
events_to_filter,
@ -641,7 +644,7 @@ class FilterEventsOutOfBandEventsForClientTestCase(
# the invited user should be able to see both the invite and the rejection
filtered_events = self.get_success(
filter_events_for_client(
filter_and_transform_events_for_client(
self.hs.get_storage_controllers(),
"@user:test",
[invite_event, reject_event],
@ -662,7 +665,7 @@ class FilterEventsOutOfBandEventsForClientTestCase(
# other users should see neither
self.assertEqual(
self.get_success(
filter_events_for_client(
filter_and_transform_events_for_client(
self.hs.get_storage_controllers(),
"@other:test",
[invite_event, reject_event],