Skip to main content

tuwunel_api_admin/users/
username_available.rs

1use axum::extract::State;
2use ruma::UserId;
3use synapse_admin_api::username_available::v1 as username_available;
4use tuwunel_core::{Err, Result, err};
5
6use crate::{Ruma, require_admin};
7
8/// # `GET /_synapse/admin/v1/username_available`
9///
10/// Never returns `available: false`; an unavailable username is always an
11/// error, mirroring the client-server `/register/available` endpoint.
12pub(crate) async fn admin_username_available_route(
13	State(services): State<crate::State>,
14	body: Ruma<username_available::Request>,
15) -> Result<username_available::Response> {
16	require_admin(&services, body.sender_user()).await?;
17
18	if services
19		.config
20		.registration
21		.forbidden_usernames
22		.is_match(&body.username)
23	{
24		return Err!(Request(InvalidUsername("Username is forbidden")));
25	}
26
27	let user_id = UserId::parse_with_server_name(&body.username, services.globals.server_name())
28		.map_err(|_| err!(Request(InvalidUsername("Username is not a valid localpart"))))?;
29
30	if user_id.validate_strict().is_err() {
31		return Err!(Request(InvalidUsername("Username contains disallowed characters")));
32	}
33
34	if services.users.exists(&user_id).await {
35		return Err!(Request(UserInUse("Username is not available")));
36	}
37
38	if services
39		.appservice
40		.is_exclusive_user_id(&user_id)
41		.await
42	{
43		return Err!(Request(Exclusive("Username is reserved by an appservice")));
44	}
45
46	Ok(username_available::Response::new(true))
47}