feat: Add support for logging in with an email address

This commit is contained in:
Ginger
2026-03-31 02:20:59 +00:00
committed by Ellis Git
parent 0b04757bef
commit 717d319708
2 changed files with 32 additions and 21 deletions
+30 -19
View File
@@ -10,6 +10,7 @@ use conduwuit::{
use conduwuit_core::{debug_error, debug_warn}; use conduwuit_core::{debug_error, debug_warn};
use conduwuit_service::Services; use conduwuit_service::Services;
use futures::StreamExt; use futures::StreamExt;
use lettre::Address;
use ruma::{ use ruma::{
OwnedUserId, UserId, OwnedUserId, UserId,
api::client::{ api::client::{
@@ -26,7 +27,7 @@ use ruma::{
}, },
logout, logout_all, logout, logout_all,
}, },
uiaa, uiaa::UserIdentifier,
}, },
}; };
use service::uiaa::Identity; use service::uiaa::Identity;
@@ -81,7 +82,7 @@ pub(crate) async fn password_login(
.password_hash(lowercased_user_id) .password_hash(lowercased_user_id)
.await .await
.map(|hash| (hash, lowercased_user_id)) .map(|hash| (hash, lowercased_user_id))
.map_err(|_| err!(Request(Forbidden("Wrong username or password."))))?, .map_err(|_| err!(Request(Forbidden("Invalid identifier or password."))))?,
}; };
if hash.is_empty() { if hash.is_empty() {
@@ -90,7 +91,7 @@ pub(crate) async fn password_login(
hash::verify_password(password, &hash) hash::verify_password(password, &hash)
.inspect_err(|e| debug_error!("{e}")) .inspect_err(|e| debug_error!("{e}"))
.map_err(|_| err!(Request(Forbidden("Wrong username or password."))))?; .map_err(|_| err!(Request(Forbidden("Invalid identifier or password."))))?;
Ok(user_id.to_owned()) Ok(user_id.to_owned())
} }
@@ -162,28 +163,38 @@ pub(super) async fn ldap_login(
pub(crate) async fn handle_login( pub(crate) async fn handle_login(
services: &Services, services: &Services,
body: &Ruma<login::v3::Request>, identifier: Option<&UserIdentifier>,
identifier: Option<&uiaa::UserIdentifier>,
password: &str, password: &str,
user: Option<&String>, user: Option<&String>,
) -> Result<OwnedUserId> { ) -> Result<OwnedUserId> {
debug!("Got password login type"); debug!("Got password login type");
let user_id_or_localpart = match (identifier, user) {
| (Some(UserIdentifier::UserIdOrLocalpart(localpart)), _) => localpart,
| (Some(UserIdentifier::Email { address }), _) => {
let email = Address::try_from(address.to_owned())
.map_err(|_| err!(Request(InvalidParam("Email is malformed"))))?;
&services
.threepid
.get_localpart_for_email(&email)
.await
.ok_or_else(|| err!(Request(Forbidden("Invalid identifier or password"))))?
},
| (None, Some(user)) => user,
| _ => {
return Err!(Request(InvalidParam("Identifier type not recognized")));
},
};
let user_id = let user_id =
if let Some(uiaa::UserIdentifier::UserIdOrLocalpart(user_id)) = identifier { UserId::parse_with_server_name(user_id_or_localpart, &services.config.server_name)
UserId::parse_with_server_name(user_id, &services.config.server_name) .map_err(|_| err!(Request(InvalidUsername("User ID is malformed"))))?;
} else if let Some(user) = user {
UserId::parse_with_server_name(user, &services.config.server_name)
} else {
return Err!(Request(Unknown(
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}")))))?;
let lowercased_user_id = UserId::parse_with_server_name( let lowercased_user_id = UserId::parse_with_server_name(
user_id.localpart().to_lowercase(), user_id.localpart().to_lowercase(),
&services.config.server_name, &services.config.server_name,
)?; )
.unwrap();
if !services.globals.user_is_local(&user_id) if !services.globals.user_is_local(&user_id)
|| !services.globals.user_is_local(&lowercased_user_id) || !services.globals.user_is_local(&lowercased_user_id)
@@ -245,7 +256,7 @@ pub(crate) async fn login_route(
password, password,
user, user,
.. ..
}) => handle_login(&services, &body, identifier.as_ref(), password, user.as_ref()).await?, }) => handle_login(&services, identifier.as_ref(), password, user.as_ref()).await?,
| login::v3::LoginInfo::Token(login::v3::Token { token }) => { | login::v3::LoginInfo::Token(login::v3::Token { token }) => {
debug!("Got token login type"); debug!("Got token login type");
if !services.server.config.login_via_existing_session { if !services.server.config.login_via_existing_session {
@@ -265,7 +276,7 @@ pub(crate) async fn login_route(
}; };
let user_id = let user_id =
if let Some(uiaa::UserIdentifier::UserIdOrLocalpart(user_id)) = identifier { if let Some(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)
} else if let Some(user) = user { } else if let Some(user) = user {
UserId::parse_with_server_name(user, &services.config.server_name) UserId::parse_with_server_name(user, &services.config.server_name)
@@ -274,7 +285,7 @@ pub(crate) async fn login_route(
debug_warn!(?body.login_info, "Valid identifier or username was not provided (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(|_| err!(Request(InvalidUsername(warn!("User ID is malformed")))))?;
if !services.globals.user_is_local(&user_id) { if !services.globals.user_is_local(&user_id) {
return Err!(Request(Unknown("User ID does not belong to this homeserver"))); return Err!(Request(Unknown("User ID does not belong to this homeserver")));
+2 -2
View File
@@ -341,7 +341,7 @@ impl Service {
let Ok(email) = Address::try_from(address.to_owned()) else { let Ok(email) = Address::try_from(address.to_owned()) else {
return Err(StandardErrorBody { return Err(StandardErrorBody {
kind: ErrorKind::InvalidParam, kind: ErrorKind::InvalidParam,
message: "Email is invalid".to_owned(), message: "Email is malformed".to_owned(),
}); });
}; };
@@ -371,7 +371,7 @@ impl Service {
) else { ) else {
return Err(StandardErrorBody { return Err(StandardErrorBody {
kind: ErrorKind::InvalidParam, kind: ErrorKind::InvalidParam,
message: "User ID is invalid".to_owned(), message: "User ID is malformed".to_owned(),
}); });
}; };