You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-08-07 17:03:01 +03:00
Check for username availability upon registration
This commit is contained in:
@@ -320,6 +320,7 @@ where
|
||||
PasswordManager: FromRef<S>,
|
||||
MetadataCache: FromRef<S>,
|
||||
SiteConfig: FromRef<S>,
|
||||
BoxHomeserverConnection: FromRef<S>,
|
||||
BoxClock: FromRequestParts<S>,
|
||||
BoxRng: FromRequestParts<S>,
|
||||
Policy: FromRequestParts<S>,
|
||||
|
@@ -26,6 +26,7 @@ use mas_axum_utils::{
|
||||
};
|
||||
use mas_data_model::{User, UserAgent};
|
||||
use mas_jose::jwt::Jwt;
|
||||
use mas_matrix::BoxHomeserverConnection;
|
||||
use mas_policy::Policy;
|
||||
use mas_router::UrlBuilder;
|
||||
use mas_storage::{
|
||||
@@ -94,6 +95,9 @@ pub(crate) enum RouteError {
|
||||
#[error("Invalid form action")]
|
||||
InvalidFormAction,
|
||||
|
||||
#[error("Homeserver connection error")]
|
||||
HomeserverConnection(#[source] anyhow::Error),
|
||||
|
||||
#[error(transparent)]
|
||||
Internal(Box<dyn std::error::Error + Send + Sync + 'static>),
|
||||
}
|
||||
@@ -196,6 +200,7 @@ pub(crate) async fn get(
|
||||
PreferredLanguage(locale): PreferredLanguage,
|
||||
State(templates): State<Templates>,
|
||||
State(url_builder): State<UrlBuilder>,
|
||||
State(homeserver): State<BoxHomeserverConnection>,
|
||||
cookie_jar: CookieJar,
|
||||
user_agent: Option<TypedHeader<headers::UserAgent>>,
|
||||
Path(link_id): Path<Ulid>,
|
||||
@@ -406,10 +411,17 @@ pub(crate) async fn get(
|
||||
// form, but this lead to poor UX. This is why we do
|
||||
// it ahead of time here.
|
||||
let maybe_existing_user = repo.user().find_by_username(&localpart).await?;
|
||||
if let Some(existing_user) = maybe_existing_user {
|
||||
// The mapper returned a username which already exists, but isn't linked
|
||||
// to this upstream user.
|
||||
warn!(username = %localpart, user_id = %existing_user.id, "Localpart template returned an existing username");
|
||||
let is_available = homeserver
|
||||
.is_localpart_available(&localpart)
|
||||
.await
|
||||
.map_err(RouteError::HomeserverConnection)?;
|
||||
|
||||
if maybe_existing_user.is_some() || !is_available {
|
||||
if let Some(existing_user) = maybe_existing_user {
|
||||
// The mapper returned a username which already exists, but isn't
|
||||
// linked to this upstream user.
|
||||
warn!(username = %localpart, user_id = %existing_user.id, "Localpart template returned an existing username");
|
||||
}
|
||||
|
||||
// TODO: translate
|
||||
let ctx = ErrorContext::new()
|
||||
@@ -476,6 +488,7 @@ pub(crate) async fn post(
|
||||
mut policy: Policy,
|
||||
PreferredLanguage(locale): PreferredLanguage,
|
||||
State(templates): State<Templates>,
|
||||
State(homeserver): State<BoxHomeserverConnection>,
|
||||
State(url_builder): State<UrlBuilder>,
|
||||
State(site_config): State<SiteConfig>,
|
||||
Path(link_id): Path<Ulid>,
|
||||
@@ -682,7 +695,14 @@ pub(crate) async fn post(
|
||||
|
||||
// Check if there is an existing user
|
||||
let existing_user = repo.user().find_by_username(&username).await?;
|
||||
if let Some(_existing_user) = existing_user {
|
||||
|
||||
// Ask the homeserver to make sure the username is valid
|
||||
let is_available = homeserver
|
||||
.is_localpart_available(&username)
|
||||
.await
|
||||
.map_err(RouteError::HomeserverConnection)?;
|
||||
|
||||
if existing_user.is_some() || !is_available {
|
||||
// If there is an existing user, we can't create a new one
|
||||
// with the same username, show an error
|
||||
|
||||
|
@@ -28,6 +28,7 @@ use mas_axum_utils::{
|
||||
};
|
||||
use mas_data_model::UserAgent;
|
||||
use mas_i18n::DataLocale;
|
||||
use mas_matrix::BoxHomeserverConnection;
|
||||
use mas_policy::Policy;
|
||||
use mas_router::UrlBuilder;
|
||||
use mas_storage::{
|
||||
@@ -111,6 +112,7 @@ pub(crate) async fn post(
|
||||
State(templates): State<Templates>,
|
||||
State(url_builder): State<UrlBuilder>,
|
||||
State(site_config): State<SiteConfig>,
|
||||
State(homeserver): State<BoxHomeserverConnection>,
|
||||
mut policy: Policy,
|
||||
mut repo: BoxRepository,
|
||||
activity_tracker: BoundActivityTracker,
|
||||
@@ -135,6 +137,16 @@ pub(crate) async fn post(
|
||||
if form.username.is_empty() {
|
||||
state.add_error_on_field(RegisterFormField::Username, FieldError::Required);
|
||||
} else if repo.user().exists(&form.username).await? {
|
||||
// The user already exists in the database
|
||||
state.add_error_on_field(RegisterFormField::Username, FieldError::Exists);
|
||||
} else if !homeserver.is_localpart_available(&form.username).await? {
|
||||
// The user already exists on the homeserver
|
||||
// XXX: we may want to return different errors like "this username is reserved"
|
||||
tracing::warn!(
|
||||
username = &form.username,
|
||||
"User tried to register with a reserved username"
|
||||
);
|
||||
|
||||
state.add_error_on_field(RegisterFormField::Username, FieldError::Exists);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user