allow both lowercase and uppercase usernames to login

Signed-off-by: June Clementine Strawberry <june@3.dog>
This commit is contained in:
June Clementine Strawberry 2025-03-05 21:31:49 -05:00
parent 408f5bd30c
commit 2c1ec3fb02
No known key found for this signature in database

View file

@ -3,7 +3,7 @@ use std::time::Duration;
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::InsecureClientIp;
use conduwuit::{Err, debug, err, info, utils::ReadyExt}; use conduwuit::{Err, debug, err, info, utils::ReadyExt};
use futures::StreamExt; use futures::{StreamExt, TryFutureExt};
use ruma::{ use ruma::{
UserId, UserId,
api::client::{ api::client::{
@ -86,29 +86,40 @@ pub(crate) async fn login_route(
UserId::parse_with_server_name(user, &services.config.server_name) UserId::parse_with_server_name(user, &services.config.server_name)
} else { } else {
return Err!(Request(Unknown( return Err!(Request(Unknown(
warn!(?body.login_info, "Invalid or unsupported login type") debug_warn!(?body.login_info, "Valid identifier or username was not provided (invalid or unsupported login type?)")
))); )));
} }
.map_err(|e| err!(Request(InvalidUsername(warn!("Username is invalid: {e}")))))?; .map_err(|e| err!(Request(InvalidUsername(warn!("Username is invalid: {e}")))))?;
let lowercased_user_id = UserId::parse_with_server_name(
user_id.localpart().to_lowercase(),
&services.config.server_name,
)?;
assert!( assert!(
services.globals.user_is_local(&user_id), services.globals.user_is_local(&user_id),
"User ID does not belong to this homeserver" "User ID does not belong to this homeserver"
); );
assert!(
services.globals.user_is_local(&lowercased_user_id),
"User ID does not belong to this homeserver"
);
let hash = services let hash = services
.users .users
.password_hash(&user_id) .password_hash(&user_id)
.or_else(|_| services.users.password_hash(&lowercased_user_id))
.await .await
.inspect_err(|e| debug!("{e}"))
.map_err(|_| err!(Request(Forbidden("Wrong username or password."))))?; .map_err(|_| err!(Request(Forbidden("Wrong username or password."))))?;
if hash.is_empty() { if hash.is_empty() {
return Err!(Request(UserDeactivated("The user has been deactivated"))); return Err!(Request(UserDeactivated("The user has been deactivated")));
} }
if hash::verify_password(password, &hash).is_err() { hash::verify_password(password, &hash)
return Err!(Request(Forbidden("Wrong username or password."))); .inspect_err(|e| debug!("{e}"))
} .map_err(|_| err!(Request(Forbidden("Wrong username or password."))))?;
user_id user_id
}, },
@ -125,6 +136,11 @@ pub(crate) async fn login_route(
user, user,
}) => { }) => {
debug!("Got appservice login type"); debug!("Got appservice login type");
let Some(ref info) = body.appservice_info else {
return Err!(Request(MissingToken("Missing appservice token.")));
};
let user_id = let user_id =
if let Some(uiaa::UserIdentifier::UserIdOrLocalpart(user_id)) = identifier { if let Some(uiaa::UserIdentifier::UserIdOrLocalpart(user_id)) = identifier {
UserId::parse_with_server_name(user_id, &services.config.server_name) UserId::parse_with_server_name(user_id, &services.config.server_name)
@ -132,26 +148,30 @@ pub(crate) async fn login_route(
UserId::parse_with_server_name(user, &services.config.server_name) UserId::parse_with_server_name(user, &services.config.server_name)
} else { } else {
return Err!(Request(Unknown( return Err!(Request(Unknown(
warn!(?body.login_info, "Invalid or unsupported login type") debug_warn!(?body.login_info, "Valid identifier or username was not provided (invalid or unsupported login type?)")
))); )));
} }
.map_err(|e| err!(Request(InvalidUsername(warn!("Username is invalid: {e}")))))?; .map_err(|e| err!(Request(InvalidUsername(warn!("Username is invalid: {e}")))))?;
let lowercased_user_id = UserId::parse_with_server_name(
user_id.localpart().to_lowercase(),
&services.config.server_name,
)?;
assert!( assert!(
services.globals.user_is_local(&user_id), services.globals.user_is_local(&user_id),
"User ID does not belong to this homeserver" "User ID does not belong to this homeserver"
); );
assert!(
services.globals.user_is_local(&lowercased_user_id),
"User ID does not belong to this homeserver"
);
match body.appservice_info { if !info.is_user_match(&user_id)
| Some(ref info) => && !info.is_user_match(&lowercased_user_id)
if !info.is_user_match(&user_id) && !emergency_mode_enabled { && !emergency_mode_enabled
return Err!(Request(Exclusive( {
"Username is not in an appservice namespace." return Err!(Request(Exclusive("Username is not in an appservice namespace.")));
)));
},
| _ => {
return Err!(Request(MissingToken("Missing appservice token.")));
},
} }
user_id user_id
@ -159,7 +179,7 @@ pub(crate) async fn login_route(
| _ => { | _ => {
debug!("/login json_body: {:?}", &body.json_body); debug!("/login json_body: {:?}", &body.json_body);
return Err!(Request(Unknown( return Err!(Request(Unknown(
warn!(?body.login_info, "Invalid or unsupported login type") debug_warn!(?body.login_info, "Invalid or unsupported login type")
))); )));
}, },
}; };