Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Fix messages from multiple senders in historical chunk (MSC2716) #10276

Merged
merged 14 commits into from
Jul 13, 2021
Merged
Show file tree
Hide file tree
Changes from 13 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/10276.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix historical batch send endpoint (MSC2716) rejecting batches with messages from multiple senders.
62 changes: 55 additions & 7 deletions synapse/rest/client/v1/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
SynapseError,
)
from synapse.api.filtering import Filter
from synapse.appservice import ApplicationService
from synapse.events.utils import format_event_for_client_v2
from synapse.http.servlet import (
RestServlet,
Expand All @@ -47,11 +48,13 @@
from synapse.streams.config import PaginationConfig
from synapse.types import (
JsonDict,
Requester,
RoomAlias,
RoomID,
StreamToken,
ThirdPartyInstanceID,
UserID,
create_requester,
)
from synapse.util import json_decoder
from synapse.util.stringutils import parse_and_validate_server_name, random_string
Expand Down Expand Up @@ -309,7 +312,7 @@ def __init__(self, hs):
self.room_member_handler = hs.get_room_member_handler()
self.auth = hs.get_auth()

async def inherit_depth_from_prev_ids(self, prev_event_ids) -> int:
async def _inherit_depth_from_prev_ids(self, prev_event_ids) -> int:
(
most_recent_prev_event_id,
most_recent_prev_event_depth,
Expand Down Expand Up @@ -378,6 +381,38 @@ def _create_insertion_event_dict(

return insertion_event

async def _create_requester_from_app_service(
self, user_id: str, app_service: ApplicationService
) -> Requester:
"""Creates a new requester for the given user_id
and validates that the app service is allowed to control
the given user.

Args:
user_id: The author MXID that the app service is controlling
app_service: The app service that controls the user

Returns:
Requester object
"""

# It's ok if the app service is trying to use the sender from their registration
if app_service.sender == user_id:
pass
# Check to make sure the app service is allowed to control the user
elif not app_service.is_interested_in_user(user_id):
raise AuthError(
403,
"Application service cannot masquerade as this user (%s)." % user_id,
)
# Check to make sure the user is already registered on the homeserver
elif not (await self.store.get_user_by_id(user_id)):
raise AuthError(
403, "Application service has not registered this user (%s)" % user_id
)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This logic is based off of

synapse/synapse/api/auth.py

Lines 264 to 270 in d26094e

if app_service.sender == user_id:
return app_service.sender, app_service
if not app_service.is_interested_in_user(user_id):
raise AuthError(403, "Application service cannot masquerade as this user.")
if not (await self.store.get_user_by_id(user_id)):
raise AuthError(403, "Application service has not registered this user")


return create_requester(user_id, app_service=app_service)

async def on_POST(self, request, room_id):
requester = await self.auth.get_user_by_req(request, allow_guest=False)

Expand Down Expand Up @@ -443,7 +478,9 @@ async def on_POST(self, request, room_id):
if event_dict["type"] == EventTypes.Member:
membership = event_dict["content"].get("membership", None)
event_id, _ = await self.room_member_handler.update_membership(
requester,
await self._create_requester_from_app_service(
state_event["sender"], requester.app_service
),
target=UserID.from_string(event_dict["state_key"]),
room_id=room_id,
action=membership,
Expand All @@ -463,7 +500,9 @@ async def on_POST(self, request, room_id):
event,
_,
) = await self.event_creation_handler.create_and_send_nonmember_event(
requester,
await self._create_requester_from_app_service(
state_event["sender"], requester.app_service
),
event_dict,
outlier=True,
prev_event_ids=[fake_prev_event_id],
Expand All @@ -479,7 +518,9 @@ async def on_POST(self, request, room_id):
events_to_create = body["events"]

prev_event_ids = prev_events_from_query
inherited_depth = await self.inherit_depth_from_prev_ids(prev_events_from_query)
inherited_depth = await self._inherit_depth_from_prev_ids(
prev_events_from_query
)

# Figure out which chunk to connect to. If they passed in
# chunk_id_from_query let's use it. The chunk ID passed in comes
Expand Down Expand Up @@ -509,7 +550,10 @@ async def on_POST(self, request, room_id):
base_insertion_event,
_,
) = await self.event_creation_handler.create_and_send_nonmember_event(
requester,
await self._create_requester_from_app_service(
base_insertion_event_dict["sender"],
requester.app_service,
),
base_insertion_event_dict,
prev_event_ids=base_insertion_event_dict.get("prev_events"),
auth_event_ids=auth_event_ids,
Expand Down Expand Up @@ -558,7 +602,9 @@ async def on_POST(self, request, room_id):
}

event, context = await self.event_creation_handler.create_event(
requester,
await self._create_requester_from_app_service(
ev["sender"], requester.app_service
),
event_dict,
prev_event_ids=event_dict.get("prev_events"),
auth_event_ids=auth_event_ids,
Expand Down Expand Up @@ -588,7 +634,9 @@ async def on_POST(self, request, room_id):
# where topological_ordering is just depth.
for (event, context) in reversed(events_to_persist):
ev = await self.event_creation_handler.handle_new_client_event(
requester=requester,
await self._create_requester_from_app_service(
event["sender"], requester.app_service
),
event=event,
context=context,
)
Expand Down