Let removed senders read server announcement history

A user who left a configured server announcement room, such as a sender
removed from its config, is now treated like a user who has never been
in it. Since the room is world-readable, they read its current history
and state instead of the room as it was when they left.

Add the server announcements store to workers, which now look rooms up
in it when checking room access.
This commit is contained in:
Paul Chobert committed 2026-10-28 11:06:16 +01:00
1 parent aa994e6b37
commit 2ee7b32a0b
2 files changed
+36 -14

No files matched your search

+32 -14
View File
@@ -129,7 +129,9 @@ class BaseAuth(ABC):
Returns:
Resolves to the current membership of the user in the room and the
membership event ID of the user. If the user is not in the room and
never has been, then `(Membership.JOIN, None)` is returned.
never has been, then `(Membership.JOIN, None)` is returned. The same
is returned for a user who left a configured server announcement
room, so that they keep reading it like a user who never joined.
"""
try:
@@ -138,24 +140,40 @@ class BaseAuth(ABC):
# * The user is a non-guest user, and was ever in the room
# * The user is a guest user, and has joined the room
# else it will throw.
return await self.check_user_in_room(
membership, member_event_id = await self.check_user_in_room(
room_id, requester, allow_departed_users=allow_departed_users
)
except AuthError:
visibility = await self._storage_controllers.state.get_current_state_event(
room_id, EventTypes.RoomHistoryVisibility, ""
)
pass
else:
if (
visibility
and visibility.content.get("history_visibility")
== HistoryVisibility.WORLD_READABLE
membership == Membership.JOIN
or not await self._is_server_announcement_room(room_id)
):
return Membership.JOIN, None
raise AuthError(
403,
"User %r not in room %s, and room previews are disabled"
% (requester.user, room_id),
)
return membership, member_event_id
visibility = await self._storage_controllers.state.get_current_state_event(
room_id, EventTypes.RoomHistoryVisibility, ""
)
if (
visibility
and visibility.content.get("history_visibility")
== HistoryVisibility.WORLD_READABLE
):
return Membership.JOIN, None
raise AuthError(
403,
"User %r not in room %s, and room previews are disabled"
% (requester.user, room_id),
)
async def _is_server_announcement_room(self, room_id: str) -> bool:
"""Whether the room is the room of a configured server announcement."""
config_id = await self.store.get_server_announcement_id(room_id)
return config_id is not None and any(
room.config_id == config_id
for room in self.hs.config.serverannouncements.rooms
)
async def validate_appservice_can_control_user_id(
self, app_service: ApplicationService, user_id: str
+4
View File
@@ -98,6 +98,9 @@ from synapse.storage.databases.main.relations import RelationsWorkerStore
from synapse.storage.databases.main.room import RoomWorkerStore
from synapse.storage.databases.main.roommember import RoomMemberWorkerStore
from synapse.storage.databases.main.search import SearchStore
from synapse.storage.databases.main.server_announcements import (
ServerAnnouncementsStore,
)
from synapse.storage.databases.main.session import SessionStore
from synapse.storage.databases.main.signatures import SignatureWorkerStore
from synapse.storage.databases.main.sliding_sync import SlidingSyncStore
@@ -171,6 +174,7 @@ class GenericWorkerStore(
ExperimentalFeaturesStore,
SlidingSyncStore,
DelayedEventsStore,
ServerAnnouncementsStore,
):
# Properties that multiple storage classes define. Tell mypy what the
# expected type is.