|
|
@@ -576,24 +576,45 @@ struct PasswordHintData {
|
|
|
|
|
|
#[post("/accounts/password-hint", data = "<data>")]
|
|
|
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) {
|
|
|
- Some(user) => user.password_hint,
|
|
|
- None => return Ok(()),
|
|
|
- };
|
|
|
+ const NO_HINT: &str = "Sorry, you have no password hint...";
|
|
|
|
|
|
- if CONFIG.mail_enabled() {
|
|
|
- mail::send_password_hint(&data.Email, hint)?;
|
|
|
- } else if CONFIG.show_password_hint() {
|
|
|
- if let Some(hint) = hint {
|
|
|
- err!(format!("Your password hint is: {}", &hint));
|
|
|
- } else {
|
|
|
- err!("Sorry, you have no password hint...");
|
|
|
+ let data: PasswordHintData = data.into_inner().data;
|
|
|
+ let email = &data.Email;
|
|
|
+
|
|
|
+ match User::find_by_mail(email, &conn) {
|
|
|
+ None => {
|
|
|
+ // To prevent user enumeration, act as if the user exists.
|
|
|
+ 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)]
|