Add config option to allow appservices to use batch send with a real user

This commit is contained in:
Tulir Asokan 2021-10-26 16:30:47 +03:00
parent 5b8575b463
commit 088977f676
4 changed files with 27 additions and 9 deletions

View file

@ -244,7 +244,7 @@ class Auth:
raise MissingClientTokenError() raise MissingClientTokenError()
async def validate_appservice_can_control_user_id( async def validate_appservice_can_control_user_id(
self, app_service: ApplicationService, user_id: str self, app_service: ApplicationService, user_id: str, also_allow_user: Optional[str] = None
): ):
"""Validates that the app service is allowed to control """Validates that the app service is allowed to control
the given user. the given user.
@ -252,6 +252,7 @@ class Auth:
Args: Args:
app_service: The app service that controls the user app_service: The app service that controls the user
user_id: The author MXID that the app service is controlling user_id: The author MXID that the app service is controlling
also_allow_user: An additional user ID that the appservice can temporarily control
Raises: Raises:
AuthError: If the application service is not allowed to control the user AuthError: If the application service is not allowed to control the user
@ -263,7 +264,7 @@ class Auth:
if app_service.sender == user_id: if app_service.sender == user_id:
pass pass
# Check to make sure the app service is allowed to control the user # Check to make sure the app service is allowed to control the user
elif not app_service.is_interested_in_user(user_id): elif not app_service.is_interested_in_user(user_id) and user_id != also_allow_user:
raise AuthError( raise AuthError(
403, 403,
"Application service cannot masquerade as this user (%s)." % user_id, "Application service cannot masquerade as this user (%s)." % user_id,

View file

@ -30,6 +30,8 @@ class ExperimentalConfig(Config):
# MSC2716 (backfill existing history) # MSC2716 (backfill existing history)
self.msc2716_enabled: bool = experimental.get("msc2716_enabled", False) self.msc2716_enabled: bool = experimental.get("msc2716_enabled", False)
self.msc2716_also_allow_user: bool = experimental.get("com.beeper.msc2716_also_allow_user", False)
# MSC2285 (hidden read receipts) # MSC2285 (hidden read receipts)
self.msc2285_enabled: bool = experimental.get("msc2285_enabled", False) self.msc2285_enabled: bool = experimental.get("msc2285_enabled", False)

View file

@ -1,5 +1,5 @@
import logging import logging
from typing import TYPE_CHECKING, List, Tuple from typing import TYPE_CHECKING, List, Tuple, Optional
from synapse.api.constants import EventContentFields, EventTypes from synapse.api.constants import EventContentFields, EventTypes
from synapse.appservice import ApplicationService from synapse.appservice import ApplicationService
@ -103,7 +103,7 @@ class RoomBatchHandler:
return insertion_event return insertion_event
async def create_requester_for_user_id_from_app_service( async def create_requester_for_user_id_from_app_service(
self, user_id: str, app_service: ApplicationService self, user_id: str, app_service: ApplicationService, also_allow_user: Optional[str] = None,
) -> Requester: ) -> Requester:
"""Creates a new requester for the given user_id """Creates a new requester for the given user_id
and validates that the app service is allowed to control and validates that the app service is allowed to control
@ -112,12 +112,13 @@ class RoomBatchHandler:
Args: Args:
user_id: The author MXID that the app service is controlling user_id: The author MXID that the app service is controlling
app_service: The app service that controls the user app_service: The app service that controls the user
also_allow_user: An additional user ID that the appservice can temporarily control
Returns: Returns:
Requester object Requester object
""" """
await self.auth.validate_appservice_can_control_user_id(app_service, user_id) await self.auth.validate_appservice_can_control_user_id(app_service, user_id, also_allow_user)
return create_requester(user_id, app_service=app_service) return create_requester(user_id, app_service=app_service)
@ -155,6 +156,7 @@ class RoomBatchHandler:
room_id: str, room_id: str,
initial_auth_event_ids: List[str], initial_auth_event_ids: List[str],
app_service_requester: Requester, app_service_requester: Requester,
also_allow_user: Optional[str],
) -> List[str]: ) -> List[str]:
"""Takes all `state_events_at_start` event dictionaries and creates/persists """Takes all `state_events_at_start` event dictionaries and creates/persists
them as floating state events which don't resolve into the current room state. them as floating state events which don't resolve into the current room state.
@ -169,6 +171,7 @@ class RoomBatchHandler:
added to the list of auth events for the next state event added to the list of auth events for the next state event
created. created.
app_service_requester: The requester of an application service. app_service_requester: The requester of an application service.
also_allow_user: An additional user ID that the appservice can temporarily control
Returns: Returns:
List of state event ID's we just persisted List of state event ID's we just persisted
@ -209,7 +212,8 @@ class RoomBatchHandler:
membership = event_dict["content"].get("membership", None) membership = event_dict["content"].get("membership", None)
event_id, _ = await self.room_member_handler.update_membership( event_id, _ = await self.room_member_handler.update_membership(
await self.create_requester_for_user_id_from_app_service( await self.create_requester_for_user_id_from_app_service(
state_event["sender"], app_service_requester.app_service state_event["sender"], app_service_requester.app_service,
also_allow_user,
), ),
target=UserID.from_string(event_dict["state_key"]), target=UserID.from_string(event_dict["state_key"]),
room_id=room_id, room_id=room_id,
@ -231,7 +235,8 @@ class RoomBatchHandler:
_, _,
) = await self.event_creation_handler.create_and_send_nonmember_event( ) = await self.event_creation_handler.create_and_send_nonmember_event(
await self.create_requester_for_user_id_from_app_service( await self.create_requester_for_user_id_from_app_service(
state_event["sender"], app_service_requester.app_service state_event["sender"], app_service_requester.app_service,
also_allow_user,
), ),
event_dict, event_dict,
outlier=True, outlier=True,
@ -256,6 +261,7 @@ class RoomBatchHandler:
inherited_depth: int, inherited_depth: int,
auth_event_ids: List[str], auth_event_ids: List[str],
app_service_requester: Requester, app_service_requester: Requester,
also_allow_user: Optional[str],
) -> List[str]: ) -> List[str]:
"""Create and persists all events provided sequentially. Handles the """Create and persists all events provided sequentially. Handles the
complexity of creating events in chronological order so they can complexity of creating events in chronological order so they can
@ -276,6 +282,7 @@ class RoomBatchHandler:
auth_event_ids: Define which events allow you to create the given auth_event_ids: Define which events allow you to create the given
event in the room. event in the room.
app_service_requester: The requester of an application service. app_service_requester: The requester of an application service.
also_allow_user: An additional user ID that the appservice can temporarily control
Returns: Returns:
List of persisted event IDs List of persisted event IDs
@ -303,7 +310,7 @@ class RoomBatchHandler:
event, context = await self.event_creation_handler.create_event( event, context = await self.event_creation_handler.create_event(
await self.create_requester_for_user_id_from_app_service( await self.create_requester_for_user_id_from_app_service(
ev["sender"], app_service_requester.app_service ev["sender"], app_service_requester.app_service, also_allow_user,
), ),
event_dict, event_dict,
prev_event_ids=event_dict.get("prev_events"), prev_event_ids=event_dict.get("prev_events"),
@ -335,7 +342,7 @@ class RoomBatchHandler:
for (event, context) in reversed(events_to_persist): for (event, context) in reversed(events_to_persist):
await self.event_creation_handler.handle_new_client_event( await self.event_creation_handler.handle_new_client_event(
await self.create_requester_for_user_id_from_app_service( await self.create_requester_for_user_id_from_app_service(
event["sender"], app_service_requester.app_service event["sender"], app_service_requester.app_service, also_allow_user,
), ),
event=event, event=event,
context=context, context=context,
@ -352,6 +359,7 @@ class RoomBatchHandler:
inherited_depth: int, inherited_depth: int,
auth_event_ids: List[str], auth_event_ids: List[str],
app_service_requester: Requester, app_service_requester: Requester,
also_allow_user: Optional[str],
) -> Tuple[List[str], str]: ) -> Tuple[List[str], str]:
""" """
Handles creating and persisting all of the historical events as well Handles creating and persisting all of the historical events as well
@ -371,6 +379,7 @@ class RoomBatchHandler:
auth_event_ids: Define which events allow you to create the given auth_event_ids: Define which events allow you to create the given
event in the room. event in the room.
app_service_requester: The requester of an application service. app_service_requester: The requester of an application service.
also_allow_user: An additional user ID that the appservice can temporarily control
Returns: Returns:
Tuple containing a list of created events and the next_batch_id Tuple containing a list of created events and the next_batch_id
@ -418,6 +427,7 @@ class RoomBatchHandler:
inherited_depth=inherited_depth, inherited_depth=inherited_depth,
auth_event_ids=auth_event_ids, auth_event_ids=auth_event_ids,
app_service_requester=app_service_requester, app_service_requester=app_service_requester,
also_allow_user=also_allow_user,
) )
return event_ids, next_batch_id return event_ids, next_batch_id

View file

@ -81,6 +81,7 @@ class RoomBatchSendEventRestServlet(RestServlet):
self.auth = hs.get_auth() self.auth = hs.get_auth()
self.room_batch_handler = hs.get_room_batch_handler() self.room_batch_handler = hs.get_room_batch_handler()
self.txns = HttpTransactionCache(hs) self.txns = HttpTransactionCache(hs)
self.enable_also_allow_user = hs.config.experimental.msc2716_also_allow_user
async def on_POST( async def on_POST(
self, request: SynapseRequest, room_id: str self, request: SynapseRequest, room_id: str
@ -101,6 +102,8 @@ class RoomBatchSendEventRestServlet(RestServlet):
request.args, "prev_event_id" request.args, "prev_event_id"
) )
batch_id_from_query = parse_string(request, "batch_id") batch_id_from_query = parse_string(request, "batch_id")
also_allow_from_query = (parse_string(request, "com.beeper.also_allow_user")
if self.enable_also_allow_user else None)
if prev_event_ids_from_query is None: if prev_event_ids_from_query is None:
raise SynapseError( raise SynapseError(
@ -141,6 +144,7 @@ class RoomBatchSendEventRestServlet(RestServlet):
room_id=room_id, room_id=room_id,
initial_auth_event_ids=auth_event_ids, initial_auth_event_ids=auth_event_ids,
app_service_requester=requester, app_service_requester=requester,
also_allow_user=also_allow_from_query,
) )
) )
# Update our ongoing auth event ID list with all of the new state we # Update our ongoing auth event ID list with all of the new state we
@ -213,6 +217,7 @@ class RoomBatchSendEventRestServlet(RestServlet):
inherited_depth=inherited_depth, inherited_depth=inherited_depth,
auth_event_ids=auth_event_ids, auth_event_ids=auth_event_ids,
app_service_requester=requester, app_service_requester=requester,
also_allow_user=also_allow_from_query,
) )
insertion_event_id = event_ids[0] insertion_event_id = event_ids[0]