server,app: Add support for resetting your password with email

Instead of just username

Fixes #267
This commit is contained in:
Valentin Tolmer 2022-10-26 09:54:01 +02:00 committed by nitnelave
parent 234cb70b97
commit e81c87f288
5 changed files with 45 additions and 15 deletions

12
Cargo.lock generated
View File

@ -2163,7 +2163,7 @@ dependencies = [
"tracing-log",
"tracing-subscriber",
"uuid",
"webpki-roots 0.21.1",
"webpki-roots 0.22.4",
]
[[package]]
@ -2182,6 +2182,7 @@ dependencies = [
"rand 0.8.5",
"serde",
"serde_json",
"url-escape",
"validator",
"validator_derive",
"wasm-bindgen",
@ -4205,6 +4206,15 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "url-escape"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44e0ce4d1246d075ca5abec4b41d33e87a6054d08e2366b63205665e950db218"
dependencies = [
"percent-encoding",
]
[[package]]
name = "uuid"
version = "0.8.2"

View File

@ -22,6 +22,7 @@ yew-router = "0.15"
# Needed because of https://github.com/tkaitchuck/aHash/issues/95
indexmap = "=1.6.2"
url-escape = "0.1.1"
[dependencies.web-sys]
version = "0.3"

View File

@ -97,7 +97,7 @@ impl Component for ResetPasswordStep1Form {
class_valid="has-success"
form=&self.form
field_name="username"
placeholder="Username"
placeholder="Username or email"
autocomplete="username"
oninput=self.common.callback(|_| Msg::Update) />
</div>

View File

@ -268,7 +268,7 @@ impl HostService {
callback: Callback<Result<()>>,
) -> Result<FetchTask> {
call_server_empty_response_with_error_message(
&format!("/auth/reset/step1/{}", username),
&format!("/auth/reset/step1/{}", url_escape::encode_query(username)),
yew::format::Nothing,
callback,
"Could not initiate password reset",

View File

@ -22,6 +22,7 @@ use tracing::{debug, instrument, warn};
use lldap_auth::{login, password_reset, registration, JWTClaims};
use crate::domain::handler::UserRequestFilter;
use crate::{
domain::{
error::DomainError,
@ -139,21 +140,39 @@ async fn get_password_reset_step1<Backend>(
where
Backend: TcpBackendHandler + BackendHandler + 'static,
{
let user_id = match request.match_info().get("user_id") {
None => return Err(TcpError::BadRequest("Missing user ID".to_string())),
Some(id) => UserId::new(id),
};
let token = match data.backend_handler.start_password_reset(&user_id).await? {
let user_string = request
.match_info()
.get("user_id")
.ok_or_else(|| TcpError::BadRequest("Missing user ID".to_string()))?;
let user_results = data
.backend_handler
.list_users(
Some(UserRequestFilter::Or(vec![
UserRequestFilter::UserId(UserId::new(user_string)),
UserRequestFilter::Equality(
crate::domain::sql_tables::UserColumn::Email,
user_string.to_owned(),
),
])),
false,
)
.await?;
if user_results.is_empty() {
return Ok(());
} else if user_results.len() > 1 {
return Err(TcpError::InternalServerError(
"Ambiguous user id or email".to_owned(),
));
}
let user = &user_results[0].user;
let token = match data
.backend_handler
.start_password_reset(&user.user_id)
.await?
{
None => return Ok(()),
Some(token) => token,
};
let user = match data.backend_handler.get_user_details(&user_id).await {
Err(e) => {
warn!("Error getting used details: {:#?}", e);
return Ok(());
}
Ok(u) => u,
};
if let Err(e) = super::mail::send_password_reset_email(
&user.display_name,
&user.email,