Skip to content

Commit ec7554b

Browse files
authored
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.
1 parent d2c582e commit ec7554b

File tree

4 files changed

+13
-22
lines changed

4 files changed

+13
-22
lines changed

changelog.d/19033.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Stabilized support for [MSC4326](https://github.com/matrix-org/matrix-spec-proposals/pull/4326): Device masquerading for appservices. Contributed by @tulir @ Beeper.

synapse/api/auth/base.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -302,12 +302,9 @@ async def get_appservice_user(
302302
(the user_id URI parameter allows an application service to masquerade
303303
any applicable user in its namespace)
304304
- what device the application service should be treated as controlling
305-
(the device_id[^1] URI parameter allows an application service to masquerade
305+
(the device_id URI parameter allows an application service to masquerade
306306
as any device that exists for the relevant user)
307307
308-
[^1] Unstable and provided by MSC3202.
309-
Must use `org.matrix.msc3202.device_id` in place of `device_id` for now.
310-
311308
Returns:
312309
the application service `Requester` of that request
313310
@@ -319,7 +316,8 @@ async def get_appservice_user(
319316
- The returned device ID, if present, has been checked to be a valid device ID
320317
for the returned user ID.
321318
"""
322-
DEVICE_ID_ARG_NAME = b"org.matrix.msc3202.device_id"
319+
# TODO: We can drop unstable support after 2026-01-01 (couple months after stable support)
320+
UNSTABLE_DEVICE_ID_ARG_NAME = b"org.matrix.msc3202.device_id"
323321

324322
app_service = self.store.get_app_service_by_token(access_token)
325323
if app_service is None:
@@ -341,13 +339,11 @@ async def get_appservice_user(
341339
else:
342340
effective_user_id = app_service.sender
343341

344-
effective_device_id: Optional[str] = None
345-
346-
if (
347-
self.hs.config.experimental.msc3202_device_masquerading_enabled
348-
and DEVICE_ID_ARG_NAME in request.args
349-
):
350-
effective_device_id = request.args[DEVICE_ID_ARG_NAME][0].decode("utf8")
342+
effective_device_id_args = request.args.get(
343+
b"device_id", request.args.get(UNSTABLE_DEVICE_ID_ARG_NAME)
344+
)
345+
if effective_device_id_args:
346+
effective_device_id = effective_device_id_args[0].decode("utf8")
351347
# We only just set this so it can't be None!
352348
assert effective_device_id is not None
353349
device_opt = await self.store.get_device(
@@ -359,6 +355,8 @@ async def get_appservice_user(
359355
f"Application service trying to use a device that doesn't exist ('{effective_device_id}' for {effective_user_id})",
360356
Codes.UNKNOWN_DEVICE,
361357
)
358+
else:
359+
effective_device_id = None
362360

363361
return create_requester(
364362
effective_user_id, app_service=app_service, device_id=effective_device_id

synapse/config/experimental.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -412,11 +412,6 @@ def read_config(
412412
"msc2409_to_device_messages_enabled", False
413413
)
414414

415-
# The portion of MSC3202 which is related to device masquerading.
416-
self.msc3202_device_masquerading_enabled: bool = experimental.get(
417-
"msc3202_device_masquerading", False
418-
)
419-
420415
# The portion of MSC3202 related to transaction extensions:
421416
# sending device list changes, one-time key counts and fallback key
422417
# usage to application services.

tests/api/test_auth.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
from synapse.util.clock import Clock
4343

4444
from tests import unittest
45-
from tests.unittest import override_config
4645
from tests.utils import mock_getRawHeaders
4746

4847

@@ -237,7 +236,6 @@ def test_get_user_by_req_appservice_valid_token_bad_user_id(self) -> None:
237236
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
238237
self.get_failure(self.auth.get_user_by_req(request), AuthError)
239238

240-
@override_config({"experimental_features": {"msc3202_device_masquerading": True}})
241239
def test_get_user_by_req_appservice_valid_token_valid_device_id(self) -> None:
242240
"""
243241
Tests that when an application service passes the device_id URL parameter
@@ -264,15 +262,14 @@ def test_get_user_by_req_appservice_valid_token_valid_device_id(self) -> None:
264262
request.getClientAddress.return_value.host = "127.0.0.1"
265263
request.args[b"access_token"] = [self.test_token]
266264
request.args[b"user_id"] = [masquerading_user_id]
267-
request.args[b"org.matrix.msc3202.device_id"] = [masquerading_device_id]
265+
request.args[b"device_id"] = [masquerading_device_id]
268266
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
269267
requester = self.get_success(self.auth.get_user_by_req(request))
270268
self.assertEqual(
271269
requester.user.to_string(), masquerading_user_id.decode("utf8")
272270
)
273271
self.assertEqual(requester.device_id, masquerading_device_id.decode("utf8"))
274272

275-
@override_config({"experimental_features": {"msc3202_device_masquerading": True}})
276273
def test_get_user_by_req_appservice_valid_token_invalid_device_id(self) -> None:
277274
"""
278275
Tests that when an application service passes the device_id URL parameter
@@ -299,7 +296,7 @@ def test_get_user_by_req_appservice_valid_token_invalid_device_id(self) -> None:
299296
request.getClientAddress.return_value.host = "127.0.0.1"
300297
request.args[b"access_token"] = [self.test_token]
301298
request.args[b"user_id"] = [masquerading_user_id]
302-
request.args[b"org.matrix.msc3202.device_id"] = [masquerading_device_id]
299+
request.args[b"device_id"] = [masquerading_device_id]
303300
request.requestHeaders.getRawHeaders = mock_getRawHeaders()
304301

305302
failure = self.get_failure(self.auth.get_user_by_req(request), AuthError)

0 commit comments

Comments
 (0)