Explorar o código

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.
Jeremy Lin %!s(int64=3) %!d(string=hai) anos
pai
achega
5e13b1a7cb
Modificáronse 3 ficheiros con 32 adicións e 9 borrados
  1. 3 0
      .env.template
  2. 27 9
      src/api/core/accounts.rs
  3. 2 0
      src/config.rs

+ 3 - 0
.env.template

@@ -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.

+ 27 - 9
src/api/core/accounts.rs

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

+ 2 - 0
src/config.rs

@@ -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.