From adadafa88f318a75b2981889b5e0d2cdef1b11ff Mon Sep 17 00:00:00 2001 From: dasha_uwu Date: Tue, 9 Sep 2025 00:08:19 +0500 Subject: [PATCH] Fix alias resolution logic; element-web v1.11.111 compat element-hq/element-web#30641 element-hq/element-web#30611 Signed-off-by: Jason Volk --- src/api/client/directory.rs | 20 ++++----- src/service/globals/mod.rs | 10 ++++- src/service/rooms/alias/mod.rs | 79 +++++++++++++++------------------- 3 files changed, 54 insertions(+), 55 deletions(-) diff --git a/src/api/client/directory.rs b/src/api/client/directory.rs index 2e57b917..2c55c354 100644 --- a/src/api/client/directory.rs +++ b/src/api/client/directory.rs @@ -403,18 +403,18 @@ async fn public_rooms_chunk(services: &Services, room_id: OwnedRoomId) -> Public let canonical_alias = services .state_accessor .get_canonical_alias(&room_id) - .and_then(async |alias| { - if services - .globals - .server_is_ours(alias.server_name()) - && !services.alias.local_alias_exists(&alias).await + .ok() + .then(async |alias| { + if let Some(alias) = alias + && services.globals.alias_is_local(&alias) + && let Ok(alias_room_id) = services.alias.resolve_local_alias(&alias).await + && alias_room_id == room_id { - return Err!(Request(NotFound("Canonical alias not found."))); + Some(alias) + } else { + None } - - Ok(alias) - }) - .ok(); + }); let avatar_url = services .state_accessor diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs index 12a36aa3..ffa08892 100644 --- a/src/service/globals/mod.rs +++ b/src/service/globals/mod.rs @@ -11,7 +11,9 @@ use std::{ use async_trait::async_trait; use data::Data; use regex::RegexSet; -use ruma::{OwnedEventId, OwnedRoomAliasId, OwnedServerName, OwnedUserId, ServerName, UserId}; +use ruma::{ + OwnedEventId, OwnedRoomAliasId, OwnedServerName, OwnedUserId, RoomAliasId, ServerName, UserId, +}; use tuwunel_core::{Result, Server, error, utils::bytes::pretty}; use crate::service; @@ -250,6 +252,12 @@ impl Service { self.server_is_ours(user_id.server_name()) } + #[inline] + #[must_use] + pub fn alias_is_local(&self, alias: &RoomAliasId) -> bool { + self.server_is_ours(alias.server_name()) + } + #[inline] #[must_use] pub fn server_is_ours(&self, server_name: &ServerName) -> bool { diff --git a/src/service/rooms/alias/mod.rs b/src/service/rooms/alias/mod.rs index 92a84d38..36005408 100644 --- a/src/service/rooms/alias/mod.rs +++ b/src/service/rooms/alias/mod.rs @@ -125,33 +125,30 @@ impl Service { room_alias: &RoomAliasId, servers: Option>, ) -> Result<(OwnedRoomId, Vec)> { - let server_name = room_alias.server_name(); - let server_is_ours = self.services.globals.server_is_ours(server_name); - let servers_contains_ours = || { - servers - .as_ref() - .is_some_and(|servers| servers.contains(&self.services.server.name)) - }; + if self + .services + .globals + .server_is_ours(room_alias.server_name()) + { + if let Ok(room_id) = self.resolve_local_alias(room_alias).await { + return Ok((room_id, Vec::new())); + } - if !server_is_ours && !servers_contains_ours() { - return self - .remote_resolve(room_alias, servers.unwrap_or_default()) - .await; + if let Ok(room_id) = self.resolve_appservice_alias(room_alias).await { + return Ok((room_id, Vec::new())); + } + + return Err!(Request(NotFound("Room with alias not found."))); } - let room_id = match self.resolve_local_alias(room_alias).await { - | Ok(r) => Some(r), - | Err(_) => self.resolve_appservice_alias(room_alias).await?, - }; - - room_id.map_or_else( - || Err!(Request(NotFound("Room with alias not found."))), - |room_id| Ok((room_id, Vec::new())), - ) + return self + .remote_resolve(room_alias, servers.unwrap_or_default()) + .await; } #[tracing::instrument(skip(self), level = "trace")] pub async fn resolve_local_alias(&self, alias: &RoomAliasId) -> Result { + self.check_alias_local(alias)?; self.db .alias_roomid .get(alias.alias()) @@ -159,15 +156,6 @@ impl Service { .deserialized() } - #[tracing::instrument(skip(self), level = "trace")] - pub async fn local_alias_exists(&self, alias: &RoomAliasId) -> bool { - self.db - .alias_roomid - .exists(alias.alias()) - .await - .is_ok() - } - #[tracing::instrument(skip(self), level = "debug")] pub fn local_aliases_for_room<'a>( &'a self, @@ -191,6 +179,8 @@ impl Service { } async fn user_can_remove_alias(&self, alias: &RoomAliasId, user_id: &UserId) -> Result { + self.check_alias_local(alias)?; + let room_id = self .resolve_local_alias(alias) .await @@ -237,6 +227,8 @@ impl Service { } async fn who_created_alias(&self, alias: &RoomAliasId) -> Result { + self.check_alias_local(alias)?; + self.db .alias_userid .get(alias.alias()) @@ -244,12 +236,11 @@ impl Service { .deserialized() } - async fn resolve_appservice_alias( - &self, - room_alias: &RoomAliasId, - ) -> Result> { + async fn resolve_appservice_alias(&self, room_alias: &RoomAliasId) -> Result { use ruma::api::appservice::query::query_room_alias; + self.check_alias_local(room_alias)?; + for appservice in self.services.appservice.read().await.values() { if appservice.aliases.is_match(room_alias.as_str()) && matches!( @@ -265,12 +256,19 @@ impl Service { return self .resolve_local_alias(room_alias) .await - .map_err(|_| err!(Request(NotFound("Room does not exist.")))) - .map(Some); + .map_err(|_| err!(Request(NotFound("Room does not exist.")))); } } - Ok(None) + Err!(Request(NotFound("Room does not exist."))) + } + + fn check_alias_local(&self, alias: &RoomAliasId) -> Result { + if !self.services.globals.alias_is_local(alias) { + return Err!(Request(InvalidParam("Alias is from another server."))); + } + + Ok(()) } #[tracing::instrument(skip(self, appservice_info), level = "trace")] @@ -279,14 +277,7 @@ impl Service { room_alias: &RoomAliasId, appservice_info: &Option, ) -> Result { - if !self - .services - .globals - .server_is_ours(room_alias.server_name()) - { - return Err!(Request(InvalidParam("Alias is from another server."))); - } - + self.check_alias_local(room_alias)?; if let Some(info) = appservice_info { if !info.aliases.is_match(room_alias.as_str()) { return Err!(Request(Exclusive("Room alias is not in namespace.")));