Skip to main content

tuwunel_service/users/
register.rs

1use futures::FutureExt;
2use ruma::{UserId, events::GlobalAccountDataEventType, push};
3use tuwunel_core::{Err, Result, error, implement, info, is_equal_to, warn};
4
5#[derive(Debug, Default)]
6pub struct Register<'a> {
7	pub user_id: Option<&'a UserId>,
8	pub username: Option<&'a str>,
9	pub password: Option<&'a str>,
10	pub origin: Option<&'a str>,
11	pub is_appservice: bool,
12	pub is_guest: bool,
13	pub grant_first_user_admin: bool,
14	pub displayname: Option<&'a str>,
15	pub omit_displayname_suffix: bool,
16}
17
18/// Fully register a local user
19///
20/// Returns a device id and access token for the registered user
21#[implement(super::Service)]
22#[tracing::instrument(level = "info", skip(self, password))]
23pub async fn full_register(
24	&self,
25	Register {
26		username,
27		user_id,
28		password,
29		origin,
30		is_appservice,
31		is_guest,
32		grant_first_user_admin,
33		displayname,
34		omit_displayname_suffix,
35	}: Register<'_>,
36) -> Result {
37	let ref user_id = user_id
38		.map(ToOwned::to_owned)
39		.map(Ok)
40		.or_else(|| {
41			username.map(|username| {
42				UserId::parse_with_server_name(username, self.services.globals.server_name())
43			})
44		})
45		.transpose()?
46		.expect("Caller failed to supply either user_id or username parameter");
47
48	if !self.services.globals.user_is_local(user_id) {
49		return Err!("Cannot register remote user");
50	}
51
52	if self.services.users.exists(user_id).await {
53		return Err!(Request(UserInUse("User ID is not available.")));
54	}
55
56	// Create user
57	self.services
58		.users
59		.create(user_id, password, origin)
60		.await?;
61
62	let displayname_suffix = self
63		.services
64		.config
65		.new_user_displayname_suffix
66		.as_str();
67
68	let mut displayname = displayname.unwrap_or_else(|| user_id.localpart());
69
70	let displayname_with_suffix;
71	if !displayname_suffix.is_empty() && !omit_displayname_suffix {
72		displayname_with_suffix = format!("{displayname} {displayname_suffix}");
73		displayname = &displayname_with_suffix;
74	}
75
76	self.services
77		.users
78		.set_displayname(user_id, Some(displayname));
79
80	// Initial account data
81	self.services
82		.account_data
83		.update(
84			None,
85			user_id,
86			GlobalAccountDataEventType::PushRules
87				.to_string()
88				.into(),
89			&serde_json::to_value(ruma::events::push_rules::PushRulesEvent {
90				content: ruma::events::push_rules::PushRulesEventContent {
91					global: push::Ruleset::server_default(user_id),
92				},
93			})?,
94		)
95		.await?;
96
97	// If this is the first real user, grant them admin privileges except for guest
98	// users
99	// Note: the server user is generated first
100	if !is_guest
101		&& !is_appservice
102		&& grant_first_user_admin
103		&& self.services.config.grant_admin_to_first_user
104		&& let Ok(admin_room) = self.services.admin.get_admin_room().await
105		&& self
106			.services
107			.state_cache
108			.room_joined_count(&admin_room)
109			.await
110			.is_ok_and(is_equal_to!(1))
111	{
112		self.services
113			.admin
114			.make_user_admin(user_id)
115			.boxed()
116			.await?;
117		warn!("Granting {user_id} admin privileges as the first user");
118	}
119
120	if !is_appservice && (self.services.config.allow_guests_auto_join_rooms || !is_guest) {
121		for room in &self.services.server.config.auto_join_rooms {
122			let Ok(room_id) = self.services.alias.maybe_resolve(room).await else {
123				error!(
124					"Failed to resolve room alias to room ID when attempting to auto join \
125					 {room}, skipping"
126				);
127				continue;
128			};
129
130			if !self
131				.services
132				.state_cache
133				.server_in_room(self.services.globals.server_name(), &room_id)
134				.await
135			{
136				warn!(
137					"Skipping room {room} to automatically join as we have never joined before."
138				);
139				continue;
140			}
141
142			match self
143				.services
144				.membership
145				.join(
146					user_id,
147					&room_id,
148					Some(room),
149					Some("Automatically joining this room upon registration".to_owned()),
150					&[],
151					false,
152				)
153				.boxed()
154				.await
155			{
156				| Err(e) => {
157					// don't return this error so we don't fail registrations
158					error!("Failed to automatically join room {room} for user {user_id}: {e}");
159				},
160				| _ => {
161					info!("Automatically joined room {room} for user {user_id}");
162				},
163			}
164		}
165	}
166
167	Ok(())
168}