mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-08-15 22:50:18 -04:00
Merge remote-tracking branch 'upstream/release-v1.61'
This commit is contained in:
commit
1543a3643e
235 changed files with 5079 additions and 14896 deletions
|
@ -28,6 +28,7 @@ from synapse.api.constants import (
|
|||
EventContentFields,
|
||||
EventTypes,
|
||||
GuestAccess,
|
||||
HistoryVisibility,
|
||||
Membership,
|
||||
RelationTypes,
|
||||
UserTypes,
|
||||
|
@ -54,12 +55,19 @@ from synapse.metrics.background_process_metrics import run_as_background_process
|
|||
from synapse.replication.http.send_event import ReplicationSendEventRestServlet
|
||||
from synapse.storage.databases.main.events_worker import EventRedactBehaviour
|
||||
from synapse.storage.state import StateFilter
|
||||
from synapse.types import Requester, RoomAlias, StreamToken, UserID, create_requester
|
||||
from synapse.types import (
|
||||
MutableStateMap,
|
||||
Requester,
|
||||
RoomAlias,
|
||||
StreamToken,
|
||||
UserID,
|
||||
create_requester,
|
||||
)
|
||||
from synapse.util import json_decoder, json_encoder, log_failure, unwrapFirstError
|
||||
from synapse.util.async_helpers import Linearizer, gather_results
|
||||
from synapse.util.caches.expiringcache import ExpiringCache
|
||||
from synapse.util.metrics import measure_func
|
||||
from synapse.visibility import filter_events_for_client
|
||||
from synapse.visibility import get_effective_room_visibility_from_state
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from synapse.events.third_party_rules import ThirdPartyEventRules
|
||||
|
@ -76,8 +84,8 @@ class MessageHandler:
|
|||
self.clock = hs.get_clock()
|
||||
self.state = hs.get_state_handler()
|
||||
self.store = hs.get_datastores().main
|
||||
self.storage = hs.get_storage()
|
||||
self.state_store = self.storage.state
|
||||
self._storage_controllers = hs.get_storage_controllers()
|
||||
self._state_storage_controller = self._storage_controllers.state
|
||||
self._event_serializer = hs.get_event_client_serializer()
|
||||
self._ephemeral_events_enabled = hs.config.server.enable_ephemeral_messages
|
||||
|
||||
|
@ -117,14 +125,16 @@ class MessageHandler:
|
|||
)
|
||||
|
||||
if membership == Membership.JOIN:
|
||||
data = await self.state.get_current_state(room_id, event_type, state_key)
|
||||
data = await self._storage_controllers.state.get_current_state_event(
|
||||
room_id, event_type, state_key
|
||||
)
|
||||
elif membership == Membership.LEAVE:
|
||||
key = (event_type, state_key)
|
||||
# If the membership is not JOIN, then the event ID should exist.
|
||||
assert (
|
||||
membership_event_id is not None
|
||||
), "check_user_in_room_or_world_readable returned invalid data"
|
||||
room_state = await self.state_store.get_state_for_events(
|
||||
room_state = await self._state_storage_controller.get_state_for_events(
|
||||
[membership_event_id], StateFilter.from_types([key])
|
||||
)
|
||||
data = room_state[membership_event_id].get(key)
|
||||
|
@ -175,49 +185,31 @@ class MessageHandler:
|
|||
state_filter = state_filter or StateFilter.all()
|
||||
|
||||
if at_token:
|
||||
last_event = await self.store.get_last_event_in_room_before_stream_ordering(
|
||||
room_id,
|
||||
end_token=at_token.room_key,
|
||||
last_event_id = (
|
||||
await self.store.get_last_event_in_room_before_stream_ordering(
|
||||
room_id,
|
||||
end_token=at_token.room_key,
|
||||
)
|
||||
)
|
||||
|
||||
if not last_event:
|
||||
if not last_event_id:
|
||||
raise NotFoundError("Can't find event for token %s" % (at_token,))
|
||||
|
||||
# check whether the user is in the room at that time to determine
|
||||
# whether they should be treated as peeking.
|
||||
state_map = await self.state_store.get_state_for_event(
|
||||
last_event.event_id,
|
||||
StateFilter.from_types([(EventTypes.Member, user_id)]),
|
||||
)
|
||||
|
||||
joined = False
|
||||
membership_event = state_map.get((EventTypes.Member, user_id))
|
||||
if membership_event:
|
||||
joined = membership_event.membership == Membership.JOIN
|
||||
|
||||
is_peeking = not joined
|
||||
|
||||
visible_events = await filter_events_for_client(
|
||||
self.storage,
|
||||
user_id,
|
||||
[last_event],
|
||||
filter_send_to_client=False,
|
||||
is_peeking=is_peeking,
|
||||
)
|
||||
|
||||
if visible_events:
|
||||
room_state_events = await self.state_store.get_state_for_events(
|
||||
[last_event.event_id], state_filter=state_filter
|
||||
)
|
||||
room_state: Mapping[Any, EventBase] = room_state_events[
|
||||
last_event.event_id
|
||||
]
|
||||
else:
|
||||
if not await self._user_can_see_state_at_event(
|
||||
user_id, room_id, last_event_id
|
||||
):
|
||||
raise AuthError(
|
||||
403,
|
||||
"User %s not allowed to view events in room %s at token %s"
|
||||
% (user_id, room_id, at_token),
|
||||
)
|
||||
|
||||
room_state_events = (
|
||||
await self._state_storage_controller.get_state_for_events(
|
||||
[last_event_id], state_filter=state_filter
|
||||
)
|
||||
)
|
||||
room_state: Mapping[Any, EventBase] = room_state_events[last_event_id]
|
||||
else:
|
||||
(
|
||||
membership,
|
||||
|
@ -227,7 +219,7 @@ class MessageHandler:
|
|||
)
|
||||
|
||||
if membership == Membership.JOIN:
|
||||
state_ids = await self.store.get_filtered_current_state_ids(
|
||||
state_ids = await self._state_storage_controller.get_current_state_ids(
|
||||
room_id, state_filter=state_filter
|
||||
)
|
||||
room_state = await self.store.get_events(state_ids.values())
|
||||
|
@ -236,8 +228,10 @@ class MessageHandler:
|
|||
assert (
|
||||
membership_event_id is not None
|
||||
), "check_user_in_room_or_world_readable returned invalid data"
|
||||
room_state_events = await self.state_store.get_state_for_events(
|
||||
[membership_event_id], state_filter=state_filter
|
||||
room_state_events = (
|
||||
await self._state_storage_controller.get_state_for_events(
|
||||
[membership_event_id], state_filter=state_filter
|
||||
)
|
||||
)
|
||||
room_state = room_state_events[membership_event_id]
|
||||
|
||||
|
@ -245,6 +239,65 @@ class MessageHandler:
|
|||
events = self._event_serializer.serialize_events(room_state.values(), now)
|
||||
return events
|
||||
|
||||
async def _user_can_see_state_at_event(
|
||||
self, user_id: str, room_id: str, event_id: str
|
||||
) -> bool:
|
||||
# check whether the user was in the room, and the history visibility,
|
||||
# at that time.
|
||||
state_map = await self._state_storage_controller.get_state_for_event(
|
||||
event_id,
|
||||
StateFilter.from_types(
|
||||
[
|
||||
(EventTypes.Member, user_id),
|
||||
(EventTypes.RoomHistoryVisibility, ""),
|
||||
]
|
||||
),
|
||||
)
|
||||
|
||||
membership = None
|
||||
membership_event = state_map.get((EventTypes.Member, user_id))
|
||||
if membership_event:
|
||||
membership = membership_event.membership
|
||||
|
||||
# if the user was a member of the room at the time of the event,
|
||||
# they can see it.
|
||||
if membership == Membership.JOIN:
|
||||
return True
|
||||
|
||||
# otherwise, it depends on the history visibility.
|
||||
visibility = get_effective_room_visibility_from_state(state_map)
|
||||
|
||||
if visibility == HistoryVisibility.JOINED:
|
||||
# we weren't a member at the time of the event, so we can't see this event.
|
||||
return False
|
||||
|
||||
# otherwise *invited* is good enough
|
||||
if membership == Membership.INVITE:
|
||||
return True
|
||||
|
||||
if visibility == HistoryVisibility.INVITED:
|
||||
# we weren't invited, so we can't see this event.
|
||||
return False
|
||||
|
||||
if visibility == HistoryVisibility.WORLD_READABLE:
|
||||
return True
|
||||
|
||||
# So it's SHARED, and the user was not a member at the time. The user cannot
|
||||
# see history, unless they have *subsequently* joined the room.
|
||||
#
|
||||
# XXX: if the user has subsequently joined and then left again,
|
||||
# ideally we would share history up to the point they left. But
|
||||
# we don't know when they left. We just treat it as though they
|
||||
# never joined, and restrict access.
|
||||
|
||||
(
|
||||
current_membership,
|
||||
_,
|
||||
) = await self.store.get_local_current_membership_for_user_in_room(
|
||||
user_id, event_id
|
||||
)
|
||||
return current_membership == Membership.JOIN
|
||||
|
||||
async def get_joined_members(self, requester: Requester, room_id: str) -> dict:
|
||||
"""Get all the joined members in the room and their profile information.
|
||||
|
||||
|
@ -394,7 +447,7 @@ class EventCreationHandler:
|
|||
self.auth = hs.get_auth()
|
||||
self._event_auth_handler = hs.get_event_auth_handler()
|
||||
self.store = hs.get_datastores().main
|
||||
self.storage = hs.get_storage()
|
||||
self._storage_controllers = hs.get_storage_controllers()
|
||||
self.state = hs.get_state_handler()
|
||||
self.clock = hs.get_clock()
|
||||
self.validator = EventValidator()
|
||||
|
@ -889,6 +942,22 @@ class EventCreationHandler:
|
|||
|
||||
spam_check_result = await self.spam_checker.check_event_for_spam(event)
|
||||
if spam_check_result != self.spam_checker.NOT_SPAM:
|
||||
if isinstance(spam_check_result, tuple):
|
||||
try:
|
||||
[code, dict] = spam_check_result
|
||||
raise SynapseError(
|
||||
403,
|
||||
"This message had been rejected as probable spam",
|
||||
code,
|
||||
dict,
|
||||
)
|
||||
except ValueError:
|
||||
logger.error(
|
||||
"Spam-check module returned invalid error value. Expecting [code, dict], got %s",
|
||||
spam_check_result,
|
||||
)
|
||||
spam_check_result = Codes.FORBIDDEN
|
||||
|
||||
if isinstance(spam_check_result, Codes):
|
||||
raise SynapseError(
|
||||
403,
|
||||
|
@ -1023,7 +1092,7 @@ class EventCreationHandler:
|
|||
# after it is created
|
||||
if builder.internal_metadata.outlier:
|
||||
event.internal_metadata.outlier = True
|
||||
context = EventContext.for_outlier(self.storage)
|
||||
context = EventContext.for_outlier(self._storage_controllers)
|
||||
elif (
|
||||
event.type == EventTypes.MSC2716_INSERTION
|
||||
and state_event_ids
|
||||
|
@ -1035,8 +1104,35 @@ class EventCreationHandler:
|
|||
#
|
||||
# TODO(faster_joins): figure out how this works, and make sure that the
|
||||
# old state is complete.
|
||||
old_state = await self.store.get_events_as_list(state_event_ids)
|
||||
context = await self.state.compute_event_context(event, old_state=old_state)
|
||||
metadata = await self.store.get_metadata_for_events(state_event_ids)
|
||||
|
||||
state_map_for_event: MutableStateMap[str] = {}
|
||||
for state_id in state_event_ids:
|
||||
data = metadata.get(state_id)
|
||||
if data is None:
|
||||
# We're trying to persist a new historical batch of events
|
||||
# with the given state, e.g. via
|
||||
# `RoomBatchSendEventRestServlet`. The state can be inferred
|
||||
# by Synapse or set directly by the client.
|
||||
#
|
||||
# Either way, we should have persisted all the state before
|
||||
# getting here.
|
||||
raise Exception(
|
||||
f"State event {state_id} not found in DB,"
|
||||
" Synapse should have persisted it before using it."
|
||||
)
|
||||
|
||||
if data.state_key is None:
|
||||
raise Exception(
|
||||
f"Trying to set non-state event {state_id} as state"
|
||||
)
|
||||
|
||||
state_map_for_event[(data.event_type, data.state_key)] = state_id
|
||||
|
||||
context = await self.state.compute_event_context(
|
||||
event,
|
||||
state_ids_before_event=state_map_for_event,
|
||||
)
|
||||
else:
|
||||
context = await self.state.compute_event_context(event)
|
||||
|
||||
|
@ -1416,7 +1512,7 @@ class EventCreationHandler:
|
|||
"""
|
||||
extra_users = extra_users or []
|
||||
|
||||
assert self.storage.persistence is not None
|
||||
assert self._storage_controllers.persistence is not None
|
||||
assert self._events_shard_config.should_handle(
|
||||
self._instance_name, event.room_id
|
||||
)
|
||||
|
@ -1653,7 +1749,7 @@ class EventCreationHandler:
|
|||
event,
|
||||
event_pos,
|
||||
max_stream_token,
|
||||
) = await self.storage.persistence.persist_event(
|
||||
) = await self._storage_controllers.persistence.persist_event(
|
||||
event, context=context, backfilled=backfilled
|
||||
)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue