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 all 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.
37 changes: 33 additions & 4 deletions synapse/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,37 @@ async def get_user_by_req(
except KeyError:
raise MissingClientTokenError()

async def validate_appservice_can_control_user_id(
self, app_service: ApplicationService, user_id: str
):
"""Validates that the app service is allowed to control
the given user.

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

Raises:
AuthError: If the application service is not allowed to control the user
(user namespace regex does not match, wrong homeserver, etc)
or if the user has not been registered yet.
"""

# 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
)

async def _get_appservice_user_id(
self, request: Request
) -> Tuple[Optional[str], Optional[ApplicationService]]:
Expand All @@ -261,13 +292,11 @@ async def _get_appservice_user_id(
return app_service.sender, app_service

user_id = request.args[b"user_id"][0].decode("utf8")
await self.validate_appservice_can_control_user_id(app_service, user_id)

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 user_id, app_service

async def get_user_by_access_token(
Expand Down
49 changes: 42 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,25 @@ def _create_insertion_event_dict(

return insertion_event

async def _create_requester_for_user_id_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
"""

await self.auth.validate_appservice_can_control_user_id(app_service, user_id)

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 +465,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_for_user_id_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 +487,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_for_user_id_from_app_service(
state_event["sender"], requester.app_service
),
event_dict,
outlier=True,
prev_event_ids=[fake_prev_event_id],
Expand All @@ -479,7 +505,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 +537,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_for_user_id_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 +589,9 @@ async def on_POST(self, request, room_id):
}

event, context = await self.event_creation_handler.create_event(
requester,
await self._create_requester_for_user_id_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 +621,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_for_user_id_from_app_service(
event["sender"], requester.app_service
),
event=event,
context=context,
)
Expand Down