@ -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) ]