mirror of
https://github.com/element-hq/synapse.git
synced 2024-11-28 07:00:51 +03:00
Fix appservices being unable to handle to_device messages for multiple users (#16251)
This commit is contained in:
parent
b1d71c687a
commit
1e571cd664
3 changed files with 127 additions and 1 deletions
1
changelog.d/16251.bugfix
Normal file
1
changelog.d/16251.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fix a long-standing bug where appservices using MSC2409 to receive to_device messages, would only get messages for one user.
|
|
@ -349,7 +349,7 @@ class DeviceInboxWorkerStore(SQLBaseStore):
|
||||||
table="devices",
|
table="devices",
|
||||||
column="user_id",
|
column="user_id",
|
||||||
iterable=user_ids_to_query,
|
iterable=user_ids_to_query,
|
||||||
keyvalues={"user_id": user_id, "hidden": False},
|
keyvalues={"hidden": False},
|
||||||
retcols=("device_id",),
|
retcols=("device_id",),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -422,6 +422,18 @@ class ApplicationServicesHandlerSendEventsTestCase(unittest.HomeserverTestCase):
|
||||||
"exclusive_as_user", "password", self.exclusive_as_user_device_id
|
"exclusive_as_user", "password", self.exclusive_as_user_device_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.exclusive_as_user_2_device_id = "exclusive_as_device_2"
|
||||||
|
self.exclusive_as_user_2 = self.register_user("exclusive_as_user_2", "password")
|
||||||
|
self.exclusive_as_user_2_token = self.login(
|
||||||
|
"exclusive_as_user_2", "password", self.exclusive_as_user_2_device_id
|
||||||
|
)
|
||||||
|
|
||||||
|
self.exclusive_as_user_3_device_id = "exclusive_as_device_3"
|
||||||
|
self.exclusive_as_user_3 = self.register_user("exclusive_as_user_3", "password")
|
||||||
|
self.exclusive_as_user_3_token = self.login(
|
||||||
|
"exclusive_as_user_3", "password", self.exclusive_as_user_3_device_id
|
||||||
|
)
|
||||||
|
|
||||||
def _notify_interested_services(self) -> None:
|
def _notify_interested_services(self) -> None:
|
||||||
# This is normally set in `notify_interested_services` but we need to call the
|
# This is normally set in `notify_interested_services` but we need to call the
|
||||||
# internal async version so the reactor gets pushed to completion.
|
# internal async version so the reactor gets pushed to completion.
|
||||||
|
@ -849,6 +861,119 @@ class ApplicationServicesHandlerSendEventsTestCase(unittest.HomeserverTestCase):
|
||||||
for count in service_id_to_message_count.values():
|
for count in service_id_to_message_count.values():
|
||||||
self.assertEqual(count, number_of_messages)
|
self.assertEqual(count, number_of_messages)
|
||||||
|
|
||||||
|
@unittest.override_config(
|
||||||
|
{"experimental_features": {"msc2409_to_device_messages_enabled": True}}
|
||||||
|
)
|
||||||
|
def test_application_services_receive_local_to_device_for_many_users(self) -> None:
|
||||||
|
"""
|
||||||
|
Test that when a user sends a to-device message to many users
|
||||||
|
in an application service's user namespace, the
|
||||||
|
application service will receive all of them.
|
||||||
|
"""
|
||||||
|
interested_appservice = self._register_application_service(
|
||||||
|
namespaces={
|
||||||
|
ApplicationService.NS_USERS: [
|
||||||
|
{
|
||||||
|
"regex": "@exclusive_as_user:.+",
|
||||||
|
"exclusive": True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"regex": "@exclusive_as_user_2:.+",
|
||||||
|
"exclusive": True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"regex": "@exclusive_as_user_3:.+",
|
||||||
|
"exclusive": True,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Have local_user send a to-device message to exclusive_as_users
|
||||||
|
message_content = {"some_key": "some really interesting value"}
|
||||||
|
chan = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
"/_matrix/client/r0/sendToDevice/m.room_key_request/3",
|
||||||
|
content={
|
||||||
|
"messages": {
|
||||||
|
self.exclusive_as_user: {
|
||||||
|
self.exclusive_as_user_device_id: message_content
|
||||||
|
},
|
||||||
|
self.exclusive_as_user_2: {
|
||||||
|
self.exclusive_as_user_2_device_id: message_content
|
||||||
|
},
|
||||||
|
self.exclusive_as_user_3: {
|
||||||
|
self.exclusive_as_user_3_device_id: message_content
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
access_token=self.local_user_token,
|
||||||
|
)
|
||||||
|
self.assertEqual(chan.code, 200, chan.result)
|
||||||
|
|
||||||
|
# Have exclusive_as_user send a to-device message to local_user
|
||||||
|
for user_token in [
|
||||||
|
self.exclusive_as_user_token,
|
||||||
|
self.exclusive_as_user_2_token,
|
||||||
|
self.exclusive_as_user_3_token,
|
||||||
|
]:
|
||||||
|
chan = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
"/_matrix/client/r0/sendToDevice/m.room_key_request/4",
|
||||||
|
content={
|
||||||
|
"messages": {
|
||||||
|
self.local_user: {self.local_user_device_id: message_content}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
access_token=user_token,
|
||||||
|
)
|
||||||
|
self.assertEqual(chan.code, 200, chan.result)
|
||||||
|
|
||||||
|
# Check if our application service - that is interested in exclusive_as_user - received
|
||||||
|
# the to-device message as part of an AS transaction.
|
||||||
|
# Only the local_user -> exclusive_as_user to-device message should have been forwarded to the AS.
|
||||||
|
#
|
||||||
|
# The uninterested application service should not have been notified at all.
|
||||||
|
self.send_mock.assert_called_once()
|
||||||
|
(
|
||||||
|
service,
|
||||||
|
_events,
|
||||||
|
_ephemeral,
|
||||||
|
to_device_messages,
|
||||||
|
_otks,
|
||||||
|
_fbks,
|
||||||
|
_device_list_summary,
|
||||||
|
) = self.send_mock.call_args[0]
|
||||||
|
|
||||||
|
# Assert that this was the same to-device message that local_user sent
|
||||||
|
self.assertEqual(service, interested_appservice)
|
||||||
|
|
||||||
|
# Assert expected number of messages
|
||||||
|
self.assertEqual(len(to_device_messages), 3)
|
||||||
|
|
||||||
|
for device_msg in to_device_messages:
|
||||||
|
self.assertEqual(device_msg["type"], "m.room_key_request")
|
||||||
|
self.assertEqual(device_msg["sender"], self.local_user)
|
||||||
|
self.assertEqual(device_msg["content"], message_content)
|
||||||
|
|
||||||
|
self.assertEqual(to_device_messages[0]["to_user_id"], self.exclusive_as_user)
|
||||||
|
self.assertEqual(
|
||||||
|
to_device_messages[0]["to_device_id"],
|
||||||
|
self.exclusive_as_user_device_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(to_device_messages[1]["to_user_id"], self.exclusive_as_user_2)
|
||||||
|
self.assertEqual(
|
||||||
|
to_device_messages[1]["to_device_id"],
|
||||||
|
self.exclusive_as_user_2_device_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(to_device_messages[2]["to_user_id"], self.exclusive_as_user_3)
|
||||||
|
self.assertEqual(
|
||||||
|
to_device_messages[2]["to_device_id"],
|
||||||
|
self.exclusive_as_user_3_device_id,
|
||||||
|
)
|
||||||
|
|
||||||
def _register_application_service(
|
def _register_application_service(
|
||||||
self,
|
self,
|
||||||
namespaces: Optional[Dict[str, Iterable[Dict]]] = None,
|
namespaces: Optional[Dict[str, Iterable[Dict]]] = None,
|
||||||
|
|
Loading…
Reference in a new issue