Add `password_hints_allowed` config option

Disabling password hints is mainly useful for admins who are concerned that
their users might provide password hints that are too revealing.
This commit is contained in:
Jeremy Lin 2022-06-30 20:46:17 -07:00
parent 60b339f450
commit 5e13b1a7cb
3 changed files with 32 additions and 9 deletions

View File

@ -270,6 +270,9 @@
## The change only applies when the password is changed
# PASSWORD_ITERATIONS=100000
## Controls whether users can set password hints. This setting applies globally to all users.
# PASSWORD_HINTS_ALLOWED=true
## Controls whether a password hint should be shown directly in the web page if
## SMTP service is not configured. Not recommended for publicly-accessible instances
## as this provides unauthenticated access to potentially sensitive data.

View File

@ -62,6 +62,24 @@ struct KeysData {
PublicKey: String,
}
/// Trims whitespace from password hints, and converts blank password hints to `None`.
fn clean_password_hint(password_hint: &Option<String>) -> Option<String> {
match password_hint {
None => None,
Some(h) => match h.trim() {
"" => None,
ht => Some(ht.to_string()),
},
}
}
fn enforce_password_hint_setting(password_hint: &Option<String>) -> EmptyResult {
if password_hint.is_some() && !CONFIG.password_hints_allowed() {
err!("Password hints have been disabled by the administrator. Remove the hint and try again.");
}
Ok(())
}
#[post("/accounts/register", data = "<data>")]
async fn register(data: JsonUpcase<RegisterData>, conn: DbConn) -> EmptyResult {
let data: RegisterData = data.into_inner().data;
@ -75,6 +93,11 @@ async fn register(data: JsonUpcase<RegisterData>, conn: DbConn) -> EmptyResult {
}
}
// Check against the password hint setting here so if it fails, the user
// can retry without losing their invitation below.
let password_hint = clean_password_hint(&data.MasterPasswordHint);
enforce_password_hint_setting(&password_hint)?;
let mut user = match User::find_by_mail(&email, &conn).await {
Some(user) => {
if !user.password_hash.is_empty() {
@ -131,16 +154,13 @@ async fn register(data: JsonUpcase<RegisterData>, conn: DbConn) -> EmptyResult {
user.set_password(&data.MasterPasswordHash, None);
user.akey = data.Key;
user.password_hint = password_hint;
// Add extra fields if present
if let Some(name) = data.Name {
user.name = name;
}
if let Some(hint) = data.MasterPasswordHint {
user.password_hint = Some(hint);
}
if let Some(keys) = data.Keys {
user.private_key = Some(keys.EncryptedPrivateKey);
user.public_key = Some(keys.PublicKey);
@ -191,12 +211,10 @@ async fn post_profile(data: JsonUpcase<ProfileData>, headers: Headers, conn: DbC
}
let mut user = headers.user;
user.name = data.Name;
user.password_hint = match data.MasterPasswordHint {
Some(ref h) if h.is_empty() => None,
_ => data.MasterPasswordHint,
};
user.password_hint = clean_password_hint(&data.MasterPasswordHint);
enforce_password_hint_setting(&user.password_hint)?;
user.save(&conn).await?;
Ok(Json(user.to_json(&conn).await))
}

View File

@ -436,6 +436,8 @@ make_config! {
/// 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
password_iterations: i32, true, def, 100_000;
/// Allow password hints |> Controls whether users can set password hints. This setting applies globally to all users.
password_hints_allowed: bool, true, def, true;
/// Show password hint |> Controls whether a password hint should be shown directly in the web page
/// if SMTP service is not configured. Not recommended for publicly-accessible instances as this
/// provides unauthenticated access to potentially sensitive data.