cleanup+refactor admin room alias and server account accessing to globals

Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
strawberry 2024-06-12 02:10:59 -04:00 committed by June 🍓🦴
parent f712c0cefb
commit 8fff7ea706
12 changed files with 77 additions and 101 deletions

View file

@ -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<Self>) -> 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<Option<OwnedRoomId>> {
let admin_room_alias: Box<RoomAliasId> = format!("#admins:{}", services().globals.server_name())
.try_into()
.expect("#admins:server_name is a valid alias name");
pub fn get_admin_room() -> Result<Option<OwnedRoomId>> {
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<bool> {
let Ok(Some(admin_room)) = Self::get_admin_room().await else {
let Ok(Some(admin_room)) = Self::get_admin_room() else {
return Ok(false);
};

View file

@ -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<bool> {
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 {

View file

@ -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.",

View file

@ -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<HashMap<OwnedRoomId, (OwnedEventId, Instant)>>,
pub updates_handle: Mutex<Option<JoinHandle<()>>>,
pub stateres_mutex: Arc<Mutex<()>>,
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())?;

View file

@ -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

View file

@ -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<Arc<EventId>> {
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::<RoomMemberEventContent>(pdu.content.get())
.map_err(|_| Error::bad_database("Invalid content in pdu."))?;

View file

@ -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<String, SyncRequestList>,
@ -234,18 +233,14 @@ impl Service {
/// Check if a user is an admin
pub fn is_admin(&self, user_id: &UserId) -> Result<bool> {
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.