diff --git a/synapse/api/auth/base.py b/synapse/api/auth/base.py index 93f579c69a..2e926d6447 100644 --- a/synapse/api/auth/base.py +++ b/synapse/api/auth/base.py @@ -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 diff --git a/synapse/app/generic_worker.py b/synapse/app/generic_worker.py index 6014d328ba..bddc3334e3 100644 --- a/synapse/app/generic_worker.py +++ b/synapse/app/generic_worker.py @@ -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.