From 23638cd7141c0f34959c353f917f42b16aceb7ee Mon Sep 17 00:00:00 2001 From: Jade Ellis Date: Sat, 21 Feb 2026 23:21:58 +0000 Subject: [PATCH] feat(appservices): MSC3202 Device masquerading for appservices --- src/api/router/auth.rs | 28 ++++++++++++++++++++++++++-- src/api/router/request.rs | 4 ++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/api/router/auth.rs b/src/api/router/auth.rs index 60f8860f..afd05d1b 100644 --- a/src/api/router/auth.rs +++ b/src/api/router/auth.rs @@ -14,7 +14,8 @@ use futures::{ pin_mut, }; use ruma::{ - CanonicalJsonObject, CanonicalJsonValue, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId, + CanonicalJsonObject, CanonicalJsonValue, DeviceId, OwnedDeviceId, OwnedServerName, + OwnedUserId, UserId, api::{ AuthScheme, IncomingRequest, Metadata, client::{ @@ -234,10 +235,33 @@ async fn auth_appservice( return Err!(Request(Exclusive("User is not in namespace."))); } + // MSC3202/MSC4190: Handle device_id masquerading for appservices. + // The device_id can be provided via `device_id` or + // `org.matrix.msc3202.device_id` query parameter. + let sender_device = if let Some(ref device_id_str) = request.query.device_id { + let device_id: &DeviceId = device_id_str.as_str().into(); + + // Verify the device exists for this user + if services + .users + .get_device_metadata(&user_id, device_id) + .await + .is_err() + { + return Err!(Request(Forbidden( + "Device does not exist for user or appservice cannot masquerade as this device." + ))); + } + + Some(device_id.to_owned()) + } else { + None + }; + Ok(Auth { origin: None, sender_user: Some(user_id), - sender_device: None, + sender_device, appservice_info: Some(*info), }) } diff --git a/src/api/router/request.rs b/src/api/router/request.rs index 926b17bf..96a78c0e 100644 --- a/src/api/router/request.rs +++ b/src/api/router/request.rs @@ -11,6 +11,10 @@ use service::Services; pub(super) struct QueryParams { pub(super) access_token: Option, pub(super) user_id: Option, + /// Device ID for appservice device masquerading (MSC3202/MSC4190). + /// Can be provided as `device_id` or `org.matrix.msc3202.device_id`. + #[serde(alias = "org.matrix.msc3202.device_id")] + pub(super) device_id: Option, } pub(super) struct Request {