mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-11-15 13:16:56 +00:00
187 lines
4.4 KiB
Rust
187 lines
4.4 KiB
Rust
use futures::FutureExt;
|
|
use ruma::{UserId, events::GlobalAccountDataEventType, push};
|
|
use tuwunel_core::{Err, Result, error, implement, info, is_equal_to, warn};
|
|
|
|
use crate::appservice::RegistrationInfo;
|
|
|
|
#[derive(Debug, Default)]
|
|
pub struct Register<'a> {
|
|
pub user_id: Option<&'a UserId>,
|
|
pub username: Option<&'a str>,
|
|
pub password: Option<&'a str>,
|
|
pub origin: Option<&'a str>,
|
|
pub appservice_info: Option<&'a RegistrationInfo>,
|
|
pub is_guest: bool,
|
|
pub grant_first_user_admin: bool,
|
|
pub displayname: Option<&'a str>,
|
|
pub omit_displayname_suffix: bool,
|
|
}
|
|
|
|
/// Fully register a local user
|
|
///
|
|
/// Returns a device id and access token for the registered user
|
|
#[implement(super::Service)]
|
|
#[tracing::instrument(level = "info", skip(self))]
|
|
pub async fn full_register(
|
|
&self,
|
|
Register {
|
|
username,
|
|
user_id,
|
|
password,
|
|
origin,
|
|
appservice_info,
|
|
is_guest,
|
|
grant_first_user_admin,
|
|
displayname,
|
|
omit_displayname_suffix,
|
|
}: Register<'_>,
|
|
) -> Result {
|
|
let ref user_id = user_id
|
|
.map(ToOwned::to_owned)
|
|
.map(Ok)
|
|
.or_else(|| {
|
|
username.map(|username| {
|
|
UserId::parse_with_server_name(username, self.services.globals.server_name())
|
|
})
|
|
})
|
|
.transpose()?
|
|
.expect("Caller failed to supply either user_id or username parameter");
|
|
|
|
if !self.services.globals.user_is_local(user_id) {
|
|
return Err!("Cannot register remote user");
|
|
}
|
|
|
|
if self.services.users.exists(user_id).await {
|
|
return Err!(Request(UserInUse("User ID is not available.")));
|
|
}
|
|
|
|
// Create user
|
|
self.services
|
|
.users
|
|
.create(user_id, password, origin)
|
|
.await?;
|
|
|
|
let displayname_suffix = self
|
|
.services
|
|
.config
|
|
.new_user_displayname_suffix
|
|
.as_str();
|
|
|
|
let add_displayname_suffix = !displayname_suffix.is_empty() && !omit_displayname_suffix;
|
|
|
|
if let Some(displayname) =
|
|
displayname.or_else(|| add_displayname_suffix.then(|| user_id.localpart()))
|
|
{
|
|
// If `new_user_displayname_suffix` is set, registration will push whatever
|
|
// content is set to the user's display name with a space before it
|
|
let displayname = format!(
|
|
"{displayname}{}{}",
|
|
add_displayname_suffix
|
|
.then_some(" ")
|
|
.unwrap_or(""),
|
|
add_displayname_suffix
|
|
.then_some(displayname_suffix)
|
|
.unwrap_or("")
|
|
);
|
|
|
|
self.services
|
|
.users
|
|
.set_displayname(user_id, Some(displayname));
|
|
}
|
|
|
|
// Initial account data
|
|
self.services
|
|
.account_data
|
|
.update(
|
|
None,
|
|
user_id,
|
|
GlobalAccountDataEventType::PushRules
|
|
.to_string()
|
|
.into(),
|
|
&serde_json::to_value(ruma::events::push_rules::PushRulesEvent {
|
|
content: ruma::events::push_rules::PushRulesEventContent {
|
|
global: push::Ruleset::server_default(user_id),
|
|
},
|
|
})?,
|
|
)
|
|
.await?;
|
|
|
|
// If this is the first real user, grant them admin privileges except for guest
|
|
// users
|
|
// Note: the server user is generated first
|
|
if !is_guest
|
|
&& grant_first_user_admin
|
|
&& self.services.config.grant_admin_to_first_user
|
|
&& let Ok(admin_room) = self.services.admin.get_admin_room().await
|
|
&& self
|
|
.services
|
|
.state_cache
|
|
.room_joined_count(&admin_room)
|
|
.await
|
|
.is_ok_and(is_equal_to!(1))
|
|
{
|
|
self.services
|
|
.admin
|
|
.make_user_admin(user_id)
|
|
.boxed()
|
|
.await?;
|
|
warn!("Granting {user_id} admin privileges as the first user");
|
|
}
|
|
|
|
if appservice_info.is_none()
|
|
&& (self.services.config.allow_guests_auto_join_rooms || !is_guest)
|
|
{
|
|
for room in &self.services.server.config.auto_join_rooms {
|
|
let Ok(room_id) = self.services.alias.maybe_resolve(room).await else {
|
|
error!(
|
|
"Failed to resolve room alias to room ID when attempting to auto join \
|
|
{room}, skipping"
|
|
);
|
|
continue;
|
|
};
|
|
|
|
if !self
|
|
.services
|
|
.state_cache
|
|
.server_in_room(self.services.globals.server_name(), &room_id)
|
|
.await
|
|
{
|
|
warn!(
|
|
"Skipping room {room} to automatically join as we have never joined before."
|
|
);
|
|
continue;
|
|
}
|
|
|
|
let state_lock = self.services.state.mutex.lock(&room_id).await;
|
|
|
|
match self
|
|
.services
|
|
.membership
|
|
.join(
|
|
user_id,
|
|
&room_id,
|
|
Some(room),
|
|
Some("Automatically joining this room upon registration".to_owned()),
|
|
&[],
|
|
false,
|
|
&state_lock,
|
|
)
|
|
.boxed()
|
|
.await
|
|
{
|
|
| Err(e) => {
|
|
// don't return this error so we don't fail registrations
|
|
error!("Failed to automatically join room {room} for user {user_id}: {e}");
|
|
},
|
|
| _ => {
|
|
info!("Automatically joined room {room} for user {user_id}");
|
|
},
|
|
}
|
|
|
|
drop(state_lock);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|