Merge branch 'jjlin-password-hints' into main

pull/1829/head^2
Daniel García 3 years ago
commit 8d6e62e18b
No known key found for this signature in database
GPG Key ID: FC8A7D14C3CD543A

@ -210,8 +210,10 @@
## The change only applies when the password is changed ## The change only applies when the password is changed
# PASSWORD_ITERATIONS=100000 # PASSWORD_ITERATIONS=100000
## Whether password hint should be sent into the error response when the client request it ## Controls whether a password hint should be shown directly in the web page if
# SHOW_PASSWORD_HINT=true ## SMTP service is not configured. Not recommended for publicly-accessible instances
## as this provides unauthenticated access to potentially sensitive data.
# SHOW_PASSWORD_HINT=false
## Domain settings ## Domain settings
## The domain must match the address from where you access the server ## The domain must match the address from where you access the server

@ -576,24 +576,45 @@ struct PasswordHintData {
#[post("/accounts/password-hint", data = "<data>")] #[post("/accounts/password-hint", data = "<data>")]
fn password_hint(data: JsonUpcase<PasswordHintData>, conn: DbConn) -> EmptyResult { fn password_hint(data: JsonUpcase<PasswordHintData>, conn: DbConn) -> EmptyResult {
let data: PasswordHintData = data.into_inner().data; if !CONFIG.mail_enabled() && !CONFIG.show_password_hint() {
err!("This server is not configured to provide password hints.");
}
let hint = match User::find_by_mail(&data.Email, &conn) { const NO_HINT: &str = "Sorry, you have no password hint...";
Some(user) => user.password_hint,
None => return Ok(()),
};
if CONFIG.mail_enabled() { let data: PasswordHintData = data.into_inner().data;
mail::send_password_hint(&data.Email, hint)?; let email = &data.Email;
} else if CONFIG.show_password_hint() {
if let Some(hint) = hint { match User::find_by_mail(email, &conn) {
err!(format!("Your password hint is: {}", &hint)); None => {
} else { // To prevent user enumeration, act as if the user exists.
err!("Sorry, you have no password hint..."); if CONFIG.mail_enabled() {
// There is still a timing side channel here in that the code
// paths that send mail take noticeably longer than ones that
// don't. Add a randomized sleep to mitigate this somewhat.
use rand::{thread_rng, Rng};
let mut rng = thread_rng();
let base = 1000;
let delta: i32 = 100;
let sleep_ms = (base + rng.gen_range(-delta..=delta)) as u64;
std::thread::sleep(std::time::Duration::from_millis(sleep_ms));
Ok(())
} else {
err!(NO_HINT);
}
}
Some(user) => {
let hint: Option<String> = user.password_hint;
if CONFIG.mail_enabled() {
mail::send_password_hint(email, hint)?;
Ok(())
} else if let Some(hint) = hint {
err!(format!("Your password hint is: {}", hint));
} else {
err!(NO_HINT);
}
} }
} }
Ok(())
} }
#[derive(Deserialize)] #[derive(Deserialize)]

@ -388,9 +388,10 @@ make_config! {
/// Password iterations |> Number of server-side passwords hashing iterations. /// Password iterations |> Number of server-side passwords hashing iterations.
/// The changes only apply when a user changes their password. Not recommended to lower the value /// The changes only apply when a user changes their password. Not recommended to lower the value
password_iterations: i32, true, def, 100_000; password_iterations: i32, true, def, 100_000;
/// Show password hints |> Controls if the password hint should be shown directly in the web page. /// Show password hint |> Controls whether a password hint should be shown directly in the web page
/// Otherwise, if email is disabled, there is no way to see the password hint /// if SMTP service is not configured. Not recommended for publicly-accessible instances as this
show_password_hint: bool, true, def, true; /// provides unauthenticated access to potentially sensitive data.
show_password_hint: bool, true, def, false;
/// Admin page token |> The token used to authenticate in this very same page. Changing it here won't deauthorize the current session /// Admin page token |> The token used to authenticate in this very same page. Changing it here won't deauthorize the current session
admin_token: Pass, true, option; admin_token: Pass, true, option;

Loading…
Cancel
Save