From 7a3493d1acdf39ee981f92935c1e3540e267ec34 Mon Sep 17 00:00:00 2001 From: Tom Foster Date: Sun, 10 Aug 2025 12:27:27 +0100 Subject: [PATCH] fix(appservice): Ensure appservice sender user is created on registration and authentication Fixes #813 where appservice sender users were not being created, causing bridges like mautrix-telegram to fail on startup. This fix addresses the issue in two places: 1. During appservice registration - creates the sender_localpart user if it doesn't exist when the appservice is first registered 2. During authentication requests - only when authenticating AS the sender_localpart user, ensures it exists (for appservices registered before this fix) This matches the expected Matrix appservice behaviour where the appservice's sender user should be automatically created and available for use, while: - Avoiding unnecessary checks when authenticating as puppet users - Preventing inadvertent creation of puppet users during double-puppeting - Minimizing performance impact by only checking when needed --- src/api/router/auth.rs | 7 +++++++ src/service/appservice/mod.rs | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/api/router/auth.rs b/src/api/router/auth.rs index 01254c32..ef3a6130 100644 --- a/src/api/router/auth.rs +++ b/src/api/router/auth.rs @@ -220,6 +220,13 @@ async fn auth_appservice( return Err!(Request(Exclusive("User is not in namespace."))); } + // Only check/create the sender_localpart user if that's who is authenticating + if user_id.localpart() == info.registration.sender_localpart.as_str() { + if !services.users.exists(&user_id).await { + services.users.create(&user_id, None)?; + } + } + Ok(Auth { origin: None, sender_user: Some(user_id), diff --git a/src/service/appservice/mod.rs b/src/service/appservice/mod.rs index 7be8a471..8fb952ca 100644 --- a/src/service/appservice/mod.rs +++ b/src/service/appservice/mod.rs @@ -11,7 +11,7 @@ use ruma::{RoomAliasId, RoomId, UserId, api::appservice::Registration}; use tokio::sync::{RwLock, RwLockReadGuard}; pub use self::{namespace_regex::NamespaceRegex, registration_info::RegistrationInfo}; -use crate::{Dep, sending}; +use crate::{Dep, globals, sending, users}; pub struct Service { registration_info: RwLock, @@ -20,7 +20,9 @@ pub struct Service { } struct Services { + globals: Dep, sending: Dep, + users: Dep, } struct Data { @@ -35,7 +37,9 @@ impl crate::Service for Service { Ok(Arc::new(Self { registration_info: RwLock::new(BTreeMap::new()), services: Services { + globals: args.depend::("globals"), sending: args.depend::("sending"), + users: args.depend::("users"), }, db: Data { id_appserviceregistrations: args.db["id_appserviceregistrations"].clone(), @@ -68,6 +72,16 @@ impl Service { appservice_config_body: &str, ) -> Result { //TODO: Check for collisions between exclusive appservice namespaces + + let appservice_user_id = UserId::parse_with_server_name( + registration.sender_localpart.as_str(), + self.services.globals.server_name(), + )?; + + if !self.services.users.exists(&appservice_user_id).await { + self.services.users.create(&appservice_user_id, None)?; + } + self.registration_info .write() .await