Stabilize support for MSC4326: Device masquerading for appservices (#19033)
Note: the code references MSC3202, which is what MSC4326 was split off from. Only MSC4326 was accepted, MSC3202 wasn't yet.
This commit is contained in:
parent
d2c582ef3c
commit
ec7554b768
1
changelog.d/19033.feature
Normal file
1
changelog.d/19033.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Stabilized support for [MSC4326](https://github.com/matrix-org/matrix-spec-proposals/pull/4326): Device masquerading for appservices. Contributed by @tulir @ Beeper.
|
||||||
@ -302,12 +302,9 @@ class BaseAuth:
|
|||||||
(the user_id URI parameter allows an application service to masquerade
|
(the user_id URI parameter allows an application service to masquerade
|
||||||
any applicable user in its namespace)
|
any applicable user in its namespace)
|
||||||
- what device the application service should be treated as controlling
|
- what device the application service should be treated as controlling
|
||||||
(the device_id[^1] URI parameter allows an application service to masquerade
|
(the device_id URI parameter allows an application service to masquerade
|
||||||
as any device that exists for the relevant user)
|
as any device that exists for the relevant user)
|
||||||
|
|
||||||
[^1] Unstable and provided by MSC3202.
|
|
||||||
Must use `org.matrix.msc3202.device_id` in place of `device_id` for now.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
the application service `Requester` of that request
|
the application service `Requester` of that request
|
||||||
|
|
||||||
@ -319,7 +316,8 @@ class BaseAuth:
|
|||||||
- The returned device ID, if present, has been checked to be a valid device ID
|
- The returned device ID, if present, has been checked to be a valid device ID
|
||||||
for the returned user ID.
|
for the returned user ID.
|
||||||
"""
|
"""
|
||||||
DEVICE_ID_ARG_NAME = b"org.matrix.msc3202.device_id"
|
# TODO: We can drop unstable support after 2026-01-01 (couple months after stable support)
|
||||||
|
UNSTABLE_DEVICE_ID_ARG_NAME = b"org.matrix.msc3202.device_id"
|
||||||
|
|
||||||
app_service = self.store.get_app_service_by_token(access_token)
|
app_service = self.store.get_app_service_by_token(access_token)
|
||||||
if app_service is None:
|
if app_service is None:
|
||||||
@ -341,13 +339,11 @@ class BaseAuth:
|
|||||||
else:
|
else:
|
||||||
effective_user_id = app_service.sender
|
effective_user_id = app_service.sender
|
||||||
|
|
||||||
effective_device_id: Optional[str] = None
|
effective_device_id_args = request.args.get(
|
||||||
|
b"device_id", request.args.get(UNSTABLE_DEVICE_ID_ARG_NAME)
|
||||||
if (
|
)
|
||||||
self.hs.config.experimental.msc3202_device_masquerading_enabled
|
if effective_device_id_args:
|
||||||
and DEVICE_ID_ARG_NAME in request.args
|
effective_device_id = effective_device_id_args[0].decode("utf8")
|
||||||
):
|
|
||||||
effective_device_id = request.args[DEVICE_ID_ARG_NAME][0].decode("utf8")
|
|
||||||
# We only just set this so it can't be None!
|
# We only just set this so it can't be None!
|
||||||
assert effective_device_id is not None
|
assert effective_device_id is not None
|
||||||
device_opt = await self.store.get_device(
|
device_opt = await self.store.get_device(
|
||||||
@ -359,6 +355,8 @@ class BaseAuth:
|
|||||||
f"Application service trying to use a device that doesn't exist ('{effective_device_id}' for {effective_user_id})",
|
f"Application service trying to use a device that doesn't exist ('{effective_device_id}' for {effective_user_id})",
|
||||||
Codes.UNKNOWN_DEVICE,
|
Codes.UNKNOWN_DEVICE,
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
effective_device_id = None
|
||||||
|
|
||||||
return create_requester(
|
return create_requester(
|
||||||
effective_user_id, app_service=app_service, device_id=effective_device_id
|
effective_user_id, app_service=app_service, device_id=effective_device_id
|
||||||
|
|||||||
@ -412,11 +412,6 @@ class ExperimentalConfig(Config):
|
|||||||
"msc2409_to_device_messages_enabled", False
|
"msc2409_to_device_messages_enabled", False
|
||||||
)
|
)
|
||||||
|
|
||||||
# The portion of MSC3202 which is related to device masquerading.
|
|
||||||
self.msc3202_device_masquerading_enabled: bool = experimental.get(
|
|
||||||
"msc3202_device_masquerading", False
|
|
||||||
)
|
|
||||||
|
|
||||||
# The portion of MSC3202 related to transaction extensions:
|
# The portion of MSC3202 related to transaction extensions:
|
||||||
# sending device list changes, one-time key counts and fallback key
|
# sending device list changes, one-time key counts and fallback key
|
||||||
# usage to application services.
|
# usage to application services.
|
||||||
|
|||||||
@ -42,7 +42,6 @@ from synapse.types import Requester, UserID
|
|||||||
from synapse.util.clock import Clock
|
from synapse.util.clock import Clock
|
||||||
|
|
||||||
from tests import unittest
|
from tests import unittest
|
||||||
from tests.unittest import override_config
|
|
||||||
from tests.utils import mock_getRawHeaders
|
from tests.utils import mock_getRawHeaders
|
||||||
|
|
||||||
|
|
||||||
@ -237,7 +236,6 @@ class AuthTestCase(unittest.HomeserverTestCase):
|
|||||||
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
|
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
|
||||||
self.get_failure(self.auth.get_user_by_req(request), AuthError)
|
self.get_failure(self.auth.get_user_by_req(request), AuthError)
|
||||||
|
|
||||||
@override_config({"experimental_features": {"msc3202_device_masquerading": True}})
|
|
||||||
def test_get_user_by_req_appservice_valid_token_valid_device_id(self) -> None:
|
def test_get_user_by_req_appservice_valid_token_valid_device_id(self) -> None:
|
||||||
"""
|
"""
|
||||||
Tests that when an application service passes the device_id URL parameter
|
Tests that when an application service passes the device_id URL parameter
|
||||||
@ -264,7 +262,7 @@ class AuthTestCase(unittest.HomeserverTestCase):
|
|||||||
request.getClientAddress.return_value.host = "127.0.0.1"
|
request.getClientAddress.return_value.host = "127.0.0.1"
|
||||||
request.args[b"access_token"] = [self.test_token]
|
request.args[b"access_token"] = [self.test_token]
|
||||||
request.args[b"user_id"] = [masquerading_user_id]
|
request.args[b"user_id"] = [masquerading_user_id]
|
||||||
request.args[b"org.matrix.msc3202.device_id"] = [masquerading_device_id]
|
request.args[b"device_id"] = [masquerading_device_id]
|
||||||
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
|
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
|
||||||
requester = self.get_success(self.auth.get_user_by_req(request))
|
requester = self.get_success(self.auth.get_user_by_req(request))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@ -272,7 +270,6 @@ class AuthTestCase(unittest.HomeserverTestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(requester.device_id, masquerading_device_id.decode("utf8"))
|
self.assertEqual(requester.device_id, masquerading_device_id.decode("utf8"))
|
||||||
|
|
||||||
@override_config({"experimental_features": {"msc3202_device_masquerading": True}})
|
|
||||||
def test_get_user_by_req_appservice_valid_token_invalid_device_id(self) -> None:
|
def test_get_user_by_req_appservice_valid_token_invalid_device_id(self) -> None:
|
||||||
"""
|
"""
|
||||||
Tests that when an application service passes the device_id URL parameter
|
Tests that when an application service passes the device_id URL parameter
|
||||||
@ -299,7 +296,7 @@ class AuthTestCase(unittest.HomeserverTestCase):
|
|||||||
request.getClientAddress.return_value.host = "127.0.0.1"
|
request.getClientAddress.return_value.host = "127.0.0.1"
|
||||||
request.args[b"access_token"] = [self.test_token]
|
request.args[b"access_token"] = [self.test_token]
|
||||||
request.args[b"user_id"] = [masquerading_user_id]
|
request.args[b"user_id"] = [masquerading_user_id]
|
||||||
request.args[b"org.matrix.msc3202.device_id"] = [masquerading_device_id]
|
request.args[b"device_id"] = [masquerading_device_id]
|
||||||
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
|
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
|
||||||
|
|
||||||
failure = self.get_failure(self.auth.get_user_by_req(request), AuthError)
|
failure = self.get_failure(self.auth.get_user_by_req(request), AuthError)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user