Refactor join, alias services
Split knock, user register from api into services Fix autojoin not working with v12 rooms Fix 'm.login.registration_token/validity' for reloaded registration tokens Change join servers order Move autojoin for ldap
This commit is contained in:
@@ -51,10 +51,10 @@ pub async fn set_dehydrated_device(&self, user_id: &UserId, request: Request) ->
|
||||
|
||||
self.create_device(
|
||||
user_id,
|
||||
&request.device_id,
|
||||
Some(&request.device_id),
|
||||
(None, None),
|
||||
None,
|
||||
request.initial_device_display_name.clone(),
|
||||
request.initial_device_display_name.as_deref(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -19,6 +19,9 @@ use tuwunel_core::{
|
||||
};
|
||||
use tuwunel_database::{Deserialized, Ignore, Interfix, Json, Map};
|
||||
|
||||
/// generated device ID length
|
||||
const DEVICE_ID_LENGTH: usize = 10;
|
||||
|
||||
/// generated user access token length
|
||||
pub const TOKEN_LENGTH: usize = 32;
|
||||
|
||||
@@ -28,12 +31,16 @@ pub const TOKEN_LENGTH: usize = 32;
|
||||
pub async fn create_device(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
device_id: Option<&DeviceId>,
|
||||
(access_token, expires_in): (Option<&str>, Option<Duration>),
|
||||
refresh_token: Option<&str>,
|
||||
initial_device_display_name: Option<String>,
|
||||
initial_device_display_name: Option<&str>,
|
||||
client_ip: Option<String>,
|
||||
) -> Result {
|
||||
) -> Result<OwnedDeviceId> {
|
||||
let device_id = device_id
|
||||
.map(ToOwned::to_owned)
|
||||
.unwrap_or_else(|| OwnedDeviceId::from(utils::random_string(DEVICE_ID_LENGTH)));
|
||||
|
||||
if !self.exists(user_id).await {
|
||||
return Err!(Request(InvalidParam(error!(
|
||||
"Called create_device for non-existent user {user_id}"
|
||||
@@ -42,18 +49,18 @@ pub async fn create_device(
|
||||
|
||||
let notify = true;
|
||||
self.put_device_metadata(user_id, notify, &Device {
|
||||
device_id: device_id.into(),
|
||||
device_id: device_id.clone(),
|
||||
display_name: initial_device_display_name.map(Into::into),
|
||||
last_seen_ip: client_ip.map(Into::into),
|
||||
last_seen_ts: Some(MilliSecondsSinceUnixEpoch::now()),
|
||||
});
|
||||
|
||||
if let Some(access_token) = access_token {
|
||||
self.set_access_token(user_id, device_id, access_token, expires_in, refresh_token)
|
||||
self.set_access_token(user_id, &device_id, access_token, expires_in, refresh_token)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(device_id)
|
||||
}
|
||||
|
||||
/// Removes a device from a user.
|
||||
|
||||
@@ -3,6 +3,7 @@ pub mod device;
|
||||
mod keys;
|
||||
mod ldap;
|
||||
mod profile;
|
||||
mod register;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -124,10 +125,8 @@ impl Service {
|
||||
password: Option<&str>,
|
||||
origin: Option<&str>,
|
||||
) -> Result {
|
||||
origin.map_or_else(
|
||||
|| self.db.userid_origin.insert(user_id, "password"),
|
||||
|origin| self.db.userid_origin.insert(user_id, origin),
|
||||
);
|
||||
let origin = origin.unwrap_or("password");
|
||||
self.db.userid_origin.insert(user_id, origin);
|
||||
self.set_password(user_id, password).await
|
||||
}
|
||||
|
||||
|
||||
156
src/service/users/register.rs
Normal file
156
src/service/users/register.rs
Normal file
@@ -0,0 +1,156 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
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;
|
||||
|
||||
/// Fully register a local user
|
||||
///
|
||||
/// Returns a device id and access token for the registered user
|
||||
#[implement(super::Service)]
|
||||
pub async fn full_register(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
password: Option<&str>,
|
||||
origin: Option<&str>,
|
||||
appservice_info: Option<&RegistrationInfo>,
|
||||
is_guest: bool,
|
||||
grant_admin: bool,
|
||||
) -> Result {
|
||||
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?;
|
||||
|
||||
// Default to pretty displayname
|
||||
let mut displayname = user_id.localpart().to_owned();
|
||||
|
||||
// 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
|
||||
if !self
|
||||
.services
|
||||
.config
|
||||
.new_user_displayname_suffix
|
||||
.is_empty()
|
||||
&& appservice_info.is_none()
|
||||
{
|
||||
write!(
|
||||
displayname,
|
||||
" {}",
|
||||
self.services
|
||||
.server
|
||||
.config
|
||||
.new_user_displayname_suffix
|
||||
)?;
|
||||
}
|
||||
|
||||
self.services
|
||||
.users
|
||||
.set_displayname(user_id, Some(displayname.clone()));
|
||||
|
||||
// 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_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(())
|
||||
}
|
||||
Reference in New Issue
Block a user