diff --git a/src/admin/room/room_alias_commands.rs b/src/admin/room/room_alias_commands.rs index 7312b0f6f..bde13e531 100644 --- a/src/admin/room/room_alias_commands.rs +++ b/src/admin/room/room_alias_commands.rs @@ -1,13 +1,12 @@ use std::fmt::Write; -use ruma::{events::room::message::RoomMessageEventContent, RoomAliasId, UserId}; +use ruma::{events::room::message::RoomMessageEventContent, RoomAliasId}; use super::RoomAliasCommand; use crate::{escape_html, services, Result}; pub(crate) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Result { - let server_user = UserId::parse_with_server_name(String::from("conduit"), services().globals.server_name()) - .expect("server's username is valid"); + let server_user = &services().globals.server_user; match command { RoomAliasCommand::Set { @@ -34,7 +33,7 @@ pub(crate) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Resu (true, Ok(Some(id))) => match services() .rooms .alias - .set_alias(&room_alias, &room_id, &server_user) + .set_alias(&room_alias, &room_id, server_user) { Ok(()) => Ok(RoomMessageEventContent::text_plain(format!( "Successfully overwrote alias (formerly {id})" @@ -47,7 +46,7 @@ pub(crate) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Resu (_, Ok(None)) => match services() .rooms .alias - .set_alias(&room_alias, &room_id, &server_user) + .set_alias(&room_alias, &room_id, server_user) { Ok(()) => Ok(RoomMessageEventContent::text_plain("Successfully set alias")), Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Failed to remove alias: {err}"))), @@ -60,7 +59,7 @@ pub(crate) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Resu Ok(Some(id)) => match services() .rooms .alias - .remove_alias(&room_alias, &server_user) + .remove_alias(&room_alias, server_user) .await { Ok(()) => Ok(RoomMessageEventContent::text_plain(format!("Removed alias from {id}"))), diff --git a/src/admin/room/room_moderation_commands.rs b/src/admin/room/room_moderation_commands.rs index 9886756b6..5989ff736 100644 --- a/src/admin/room/room_moderation_commands.rs +++ b/src/admin/room/room_moderation_commands.rs @@ -33,12 +33,10 @@ async fn ban_room( ) -> Result { debug!("Got room alias or ID: {}", room); - let admin_room_alias: Box = format!("#admins:{}", services().globals.server_name()) - .try_into() - .expect("#admins:server_name is a valid alias name"); + let admin_room_alias = &services().globals.admin_alias; - if let Some(admin_room_id) = Service::get_admin_room().await? { - if room.to_string().eq(&admin_room_id) || room.to_string().eq(&admin_room_alias) { + if let Some(admin_room_id) = Service::get_admin_room()? { + if room.to_string().eq(&admin_room_id) || room.to_string().eq(admin_room_alias) { return Ok(RoomMessageEventContent::text_plain("Not allowed to ban the admin room.")); } } @@ -192,9 +190,7 @@ async fn ban_list_of_rooms(body: Vec<&str>, force: bool, disable_federation: boo let rooms_s = body.clone().drain(1..body.len() - 1).collect::>(); - let admin_room_alias: Box = format!("#admins:{}", services().globals.server_name()) - .try_into() - .expect("#admins:server_name is a valid alias name"); + let admin_room_alias = &services().globals.admin_alias; let mut room_ban_count: usize = 0; let mut room_ids: Vec = Vec::new(); @@ -202,8 +198,8 @@ async fn ban_list_of_rooms(body: Vec<&str>, force: bool, disable_federation: boo for &room in &rooms_s { match <&RoomOrAliasId>::try_from(room) { Ok(room_alias_or_id) => { - if let Some(admin_room_id) = Service::get_admin_room().await? { - if room.to_owned().eq(&admin_room_id) || room.to_owned().eq(&admin_room_alias) { + if let Some(admin_room_id) = Service::get_admin_room()? { + if room.to_owned().eq(&admin_room_id) || room.to_owned().eq(admin_room_alias) { info!("User specified admin room in bulk ban list, ignoring"); continue; } diff --git a/src/admin/user/user_commands.rs b/src/admin/user/user_commands.rs index aba324179..cada50227 100644 --- a/src/admin/user/user_commands.rs +++ b/src/admin/user/user_commands.rs @@ -8,7 +8,7 @@ use ruma::{ tag::{TagEvent, TagEventContent, TagInfo}, RoomAccountDataEventType, }, - OwnedRoomId, OwnedUserId, RoomId, UserId, + OwnedRoomId, OwnedUserId, RoomId, }; use tracing::{error, info, warn}; @@ -134,9 +134,7 @@ pub(crate) async fn deactivate( let user_id = parse_local_user_id(&user_id)?; // don't deactivate the server service account - if user_id - == UserId::parse_with_server_name("conduit", services().globals.server_name()).expect("conduit user exists") - { + if user_id == services().globals.server_user { return Ok(RoomMessageEventContent::text_plain( "Not allowed to deactivate the server service account.", )); @@ -171,9 +169,7 @@ pub(crate) async fn deactivate( pub(crate) async fn reset_password(_body: Vec<&str>, username: String) -> Result { let user_id = parse_local_user_id(&username)?; - if user_id - == UserId::parse_with_server_name("conduit", services().globals.server_name()).expect("conduit user exists") - { + if user_id == services().globals.server_user { return Ok(RoomMessageEventContent::text_plain( "Not allowed to set the password for the server account. Please use the emergency password config option.", )); @@ -223,10 +219,7 @@ pub(crate) async fn deactivate_all( } // don't deactivate the server service account - if user_id - == UserId::parse_with_server_name("conduit", services().globals.server_name()) - .expect("server user exists") - { + if user_id == services().globals.server_user { services() .admin .send_message(RoomMessageEventContent::text_plain(format!( diff --git a/src/api/client/account.rs b/src/api/client/account.rs index 5521bdff6..d7868e212 100644 --- a/src/api/client/account.rs +++ b/src/api/client/account.rs @@ -347,7 +347,7 @@ pub(crate) async fn register_route( // If this is the first real user, grant them admin privileges except for guest // users Note: the server user, @conduit:servername, is generated first if !is_guest { - if let Some(admin_room) = service::admin::Service::get_admin_room().await? { + if let Some(admin_room) = service::admin::Service::get_admin_room()? { if services() .rooms .state_cache diff --git a/src/api/client/state.rs b/src/api/client/state.rs index 7445cc409..32e0fb68f 100644 --- a/src/api/client/state.rs +++ b/src/api/client/state.rs @@ -216,7 +216,7 @@ async fn allowed_to_send_state_event( }, // admin room is a sensitive room, it should not ever be made public StateEventType::RoomJoinRules => { - if let Some(admin_room_id) = service::admin::Service::get_admin_room().await? { + if let Some(admin_room_id) = service::admin::Service::get_admin_room()? { if admin_room_id == room_id { if let Ok(join_rule) = serde_json::from_str::(json.json().get()) { if join_rule.join_rule == JoinRule::Public { @@ -231,7 +231,7 @@ async fn allowed_to_send_state_event( }, // admin room is a sensitive room, it should not ever be made world readable StateEventType::RoomHistoryVisibility => { - if let Some(admin_room_id) = service::admin::Service::get_admin_room().await? { + if let Some(admin_room_id) = service::admin::Service::get_admin_room()? { if admin_room_id == room_id { if let Ok(visibility_content) = serde_json::from_str::(json.json().get()) diff --git a/src/service/admin.rs b/src/service/admin.rs index 37a07a582..6c2eb8df5 100644 --- a/src/service/admin.rs +++ b/src/service/admin.rs @@ -19,7 +19,7 @@ use ruma::{ }, TimelineEventType, }, - EventId, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomAliasId, RoomId, RoomVersionId, UserId, + EventId, OwnedRoomId, OwnedUserId, RoomId, RoomVersionId, UserId, }; use serde_json::value::to_raw_value; use tokio::{sync::Mutex, task::JoinHandle}; @@ -69,18 +69,17 @@ impl Service { async fn handler(self: &Arc) -> Result<()> { let receiver = self.receiver.lock().await; - let Ok(Some(admin_room)) = Self::get_admin_room().await else { + let Ok(Some(admin_room)) = Self::get_admin_room() else { return Ok(()); }; - let server_user = UserId::parse_with_server_name(String::from("conduit"), services().globals.server_name()) - .expect("server's username is valid"); + let server_user = &services().globals.server_user; loop { debug_assert!(!receiver.is_closed(), "channel closed"); tokio::select! { event = receiver.recv_async() => match event { - Ok(event) => self.receive(event, &admin_room, &server_user).await?, + Ok(event) => self.receive(event, &admin_room, server_user).await?, Err(_e) => return Ok(()), } } @@ -130,15 +129,11 @@ impl Service { /// /// Errors are propagated from the database, and will have None if there is /// no admin room - pub async fn get_admin_room() -> Result> { - let admin_room_alias: Box = format!("#admins:{}", services().globals.server_name()) - .try_into() - .expect("#admins:server_name is a valid alias name"); - + pub fn get_admin_room() -> Result> { services() .rooms .alias - .resolve_local_alias(&admin_room_alias) + .resolve_local_alias(&services().globals.admin_alias) } /// Create the admin room. @@ -162,10 +157,9 @@ impl Service { let state_lock = mutex_state.lock().await; // Create a user for the server - let server_user = UserId::parse_with_server_name("conduit", services().globals.server_name()) - .expect("@conduit:server_name is valid"); + let server_user = &services().globals.server_user; - services().users.create(&server_user, None)?; + services().users.create(server_user, None)?; let room_version = services().globals.default_room_version(); let mut content = match room_version { @@ -205,7 +199,7 @@ impl Service { state_key: Some(String::new()), redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ) @@ -233,7 +227,7 @@ impl Service { state_key: Some(server_user.to_string()), redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ) @@ -258,7 +252,7 @@ impl Service { state_key: Some(String::new()), redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ) @@ -277,7 +271,7 @@ impl Service { state_key: Some(String::new()), redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ) @@ -296,7 +290,7 @@ impl Service { state_key: Some(String::new()), redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ) @@ -315,7 +309,7 @@ impl Service { state_key: Some(String::new()), redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ) @@ -335,7 +329,7 @@ impl Service { state_key: Some(String::new()), redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ) @@ -355,16 +349,14 @@ impl Service { state_key: Some(String::new()), redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ) .await?; // 6. Room alias - let alias: OwnedRoomAliasId = format!("#admins:{}", services().globals.server_name()) - .try_into() - .expect("#admins:server_name is a valid alias name"); + let alias = &services().globals.admin_alias; services() .rooms @@ -381,7 +373,7 @@ impl Service { state_key: Some(String::new()), redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ) @@ -390,7 +382,7 @@ impl Service { services() .rooms .alias - .set_alias(&alias, &room_id, &server_user)?; + .set_alias(alias, &room_id, server_user)?; // 7. (ad-hoc) Disable room previews for everyone by default services() @@ -407,7 +399,7 @@ impl Service { state_key: Some(String::new()), redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ) @@ -420,7 +412,7 @@ impl Service { /// /// In conduit, this is equivalent to granting admin privileges. pub async fn make_user_admin(&self, user_id: &UserId, displayname: String) -> Result<()> { - if let Some(room_id) = Self::get_admin_room().await? { + if let Some(room_id) = Self::get_admin_room()? { let mutex_state = Arc::clone( services() .globals @@ -433,8 +425,7 @@ impl Service { let state_lock = mutex_state.lock().await; // Use the server user to grant the new admin's power level - let server_user = UserId::parse_with_server_name("conduit", services().globals.server_name()) - .expect("@conduit:server_name is valid"); + let server_user = &services().globals.server_user; // Invite and join the real user services() @@ -458,7 +449,7 @@ impl Service { state_key: Some(user_id.to_string()), redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ) @@ -510,7 +501,7 @@ impl Service { state_key: Some(String::new()), redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ) @@ -529,7 +520,7 @@ impl Service { state_key: None, redacts: None, }, - &server_user, + server_user, &room_id, &state_lock, ).await?; @@ -540,7 +531,7 @@ impl Service { /// Checks whether a given user is an admin of this server pub async fn user_is_admin(&self, user_id: &UserId) -> Result { - let Ok(Some(admin_room)) = Self::get_admin_room().await else { + let Ok(Some(admin_room)) = Self::get_admin_room() else { return Ok(false); }; diff --git a/src/service/globals/emerg_access.rs b/src/service/globals/emerg_access.rs index fdf803cfa..001c3e51c 100644 --- a/src/service/globals/emerg_access.rs +++ b/src/service/globals/emerg_access.rs @@ -2,7 +2,6 @@ use conduit::Result; use ruma::{ events::{push_rules::PushRulesEventContent, GlobalAccountDataEvent, GlobalAccountDataEventType}, push::Ruleset, - UserId, }; use tracing::{error, warn}; @@ -18,21 +17,20 @@ pub(crate) fn init_emergency_access() { /// Sets the emergency password and push rules for the @conduit account in case /// emergency password is set fn set_emergency_access() -> Result { - let conduit_user = UserId::parse_with_server_name("conduit", services().globals.server_name()) - .expect("@conduit:server_name is a valid UserId"); + let conduit_user = &services().globals.server_user; services() .users - .set_password(&conduit_user, services().globals.emergency_password().as_deref())?; + .set_password(conduit_user, services().globals.emergency_password().as_deref())?; let (ruleset, pwd_set) = match services().globals.emergency_password() { - Some(_) => (Ruleset::server_default(&conduit_user), true), + Some(_) => (Ruleset::server_default(conduit_user), true), None => (Ruleset::new(), false), }; services().account_data.update( None, - &conduit_user, + conduit_user, GlobalAccountDataEventType::PushRules.to_string().into(), &serde_json::to_value(&GlobalAccountDataEvent { content: PushRulesEventContent { diff --git a/src/service/globals/migrations.rs b/src/service/globals/migrations.rs index d8936de7b..83b3be994 100644 --- a/src/service/globals/migrations.rs +++ b/src/service/globals/migrations.rs @@ -22,10 +22,9 @@ pub(crate) async fn migrations(db: &KeyValueDatabase, config: &Config) -> Result // Matrix resource ownership is based on the server name; changing it // requires recreating the database from scratch. if services().users.count()? > 0 { - let conduit_user = - UserId::parse_with_server_name("conduit", &config.server_name).expect("@conduit:server_name is valid"); + let conduit_user = &services().globals.server_user; - if !services().users.exists(&conduit_user)? { + if !services().users.exists(conduit_user)? { error!("The {} server user does not exist, and the database is not new.", conduit_user); return Err(Error::bad_database( "Cannot reuse an existing database after changing the server name, please delete the old one first.", diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs index 9327ecaac..317a0d561 100644 --- a/src/service/globals/mod.rs +++ b/src/service/globals/mod.rs @@ -24,8 +24,8 @@ use ruma::{ federation::discovery::{ServerSigningKeys, VerifyKey}, }, serde::Base64, - DeviceId, OwnedEventId, OwnedRoomId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId, RoomVersionId, - ServerName, UserId, + DeviceId, OwnedEventId, OwnedRoomAliasId, OwnedRoomId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId, + RoomAliasId, RoomVersionId, ServerName, UserId, }; use tokio::{ sync::{Mutex, RwLock}, @@ -58,6 +58,8 @@ pub struct Service { pub roomid_federationhandletime: RwLock>, pub updates_handle: Mutex>>, pub stateres_mutex: Arc>, + pub server_user: OwnedUserId, + pub admin_alias: OwnedRoomAliasId, } impl Service { @@ -118,6 +120,10 @@ impl Service { roomid_federationhandletime: RwLock::new(HashMap::new()), updates_handle: Mutex::new(None), stateres_mutex: Arc::new(Mutex::new(())), + admin_alias: RoomAliasId::parse(format!("#admins:{}", &config.server_name)) + .expect("#admins:server_name is valid alias name"), + server_user: UserId::parse_with_server_name(String::from("conduit"), &config.server_name) + .expect("@conduit:server_name is valid"), }; fs::create_dir_all(s.get_media_folder())?; diff --git a/src/service/rooms/alias/mod.rs b/src/service/rooms/alias/mod.rs index 311456fe3..18d513a9c 100644 --- a/src/service/rooms/alias/mod.rs +++ b/src/service/rooms/alias/mod.rs @@ -58,8 +58,7 @@ impl Service { return Err(Error::BadRequest(ErrorKind::NotFound, "Alias not found.")); }; - let server_user = - UserId::parse_with_server_name(String::from("conduit"), services().globals.server_name()).unwrap(); + let server_user = &services().globals.server_user; // The creator of an alias can remove it if self diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 82f5f1bff..1addd5673 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -477,24 +477,24 @@ impl Service { .search .index_pdu(shortroomid, &pdu_id, &body)?; - let server_user = format!("@conduit:{}", services().globals.server_name()); + let server_user = &services().globals.server_user; let to_conduit = body.starts_with(&format!("{server_user}: ")) || body.starts_with(&format!("{server_user} ")) || body.starts_with("!admin") || body == format!("{server_user}:") - || body == server_user; + || body == *server_user; // This will evaluate to false if the emergency password is set up so that // the administrator can execute commands as conduit - let from_conduit = pdu.sender == server_user && services().globals.emergency_password().is_none(); - if let Some(admin_room) = service::admin::Service::get_admin_room().await? { + let from_conduit = pdu.sender == *server_user && services().globals.emergency_password().is_none(); + if let Some(admin_room) = service::admin::Service::get_admin_room()? { if to_conduit && !from_conduit && admin_room == pdu.room_id && services() .rooms .state_cache - .is_joined(&UserId::parse(server_user).unwrap(), &admin_room)? + .is_joined(server_user, &admin_room)? { services() .admin @@ -795,7 +795,7 @@ impl Service { state_lock: &MutexGuard<'_, ()>, // Take mutex guard to make sure users get the room state mutex ) -> Result> { let (pdu, pdu_json) = self.create_hash_and_sign_event(pdu_builder, sender, room_id, state_lock)?; - if let Some(admin_room) = service::admin::Service::get_admin_room().await? { + if let Some(admin_room) = service::admin::Service::get_admin_room()? { if admin_room == room_id { match pdu.event_type() { TimelineEventType::RoomEncryption => { @@ -810,8 +810,8 @@ impl Service { .state_key() .filter(|v| v.starts_with('@')) .unwrap_or(sender.as_str()); - let server_name = services().globals.server_name(); - let server_user = format!("@conduit:{server_name}"); + let server_user = &services().globals.server_user.to_string(); + let content = serde_json::from_str::(pdu.content.get()) .map_err(|_| Error::bad_database("Invalid content in pdu."))?; diff --git a/src/service/users/mod.rs b/src/service/users/mod.rs index b326078b2..c3de86a03 100644 --- a/src/service/users/mod.rs +++ b/src/service/users/mod.rs @@ -9,7 +9,6 @@ use data::Data; use ruma::{ api::client::{ device::Device, - error::ErrorKind, filter::FilterDefinition, sync::sync_events::{ self, @@ -20,10 +19,10 @@ use ruma::{ events::AnyToDeviceEvent, serde::Raw, DeviceId, DeviceKeyAlgorithm, DeviceKeyId, OwnedDeviceId, OwnedDeviceKeyId, OwnedMxcUri, OwnedRoomId, OwnedUserId, - RoomAliasId, UInt, UserId, + UInt, UserId, }; -use crate::{services, Error, Result}; +use crate::{service, services, Error, Result}; pub struct SlidingSyncCache { lists: BTreeMap, @@ -234,18 +233,14 @@ impl Service { /// Check if a user is an admin pub fn is_admin(&self, user_id: &UserId) -> Result { - let admin_room_alias_id = RoomAliasId::parse(format!("#admins:{}", services().globals.server_name())) - .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid alias."))?; - let admin_room_id = services() - .rooms - .alias - .resolve_local_alias(&admin_room_alias_id)? - .unwrap(); - - services() - .rooms - .state_cache - .is_joined(user_id, &admin_room_id) + if let Some(admin_room_id) = service::admin::Service::get_admin_room()? { + services() + .rooms + .state_cache + .is_joined(user_id, &admin_room_id) + } else { + Ok(false) + } } /// Create a new user account on this homeserver.