From df8f4f2791ee25cd4bdad07cdec8b9837b72ffb3 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 30 Dec 2021 13:53:22 +0800 Subject: [PATCH] feat: added min_password_strength validator --- Cargo.toml | 2 ++ derive/src/validators.rs | 8 ++++++ src/validators/min_password_strength.rs | 34 +++++++++++++++++++++++++ src/validators/mod.rs | 2 ++ 4 files changed, 46 insertions(+) create mode 100644 src/validators/min_password_strength.rs diff --git a/Cargo.toml b/Cargo.toml index b7c3dc18..e38ad786 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ tracing = ["tracinglib", "tracing-futures"] decimal = ["rust_decimal"] cbor = ["serde_cbor"] chrono-duration = ["chrono", "iso8601-duration"] +password-strength-validator = ["zxcvbn"] [dependencies] async-graphql-derive = { path = "derive", version = "3.0.19" } @@ -63,6 +64,7 @@ uuid = { version = "0.8.2", optional = true, features = ["v4", "serde"] } rust_decimal = { version = "1.14.3", optional = true } url = { version = "2.2.1", optional = true } smol_str = { version = "0.1.21", optional = true } +zxcvbn = { version = "2.1.2", optional = true } # Non-feature optional dependencies blocking = { version = "1.0.2", optional = true } diff --git a/derive/src/validators.rs b/derive/src/validators.rs index 17eb7dfe..ed50eb28 100644 --- a/derive/src/validators.rs +++ b/derive/src/validators.rs @@ -34,6 +34,8 @@ pub struct Validators { #[darling(default)] multiple_of: Option, #[darling(default)] + min_password_strength: Option, + #[darling(default)] maximum: Option, #[darling(default)] minimum: Option, @@ -93,6 +95,12 @@ impl Validators { }); } + if let Some(n) = &self.min_password_strength { + elem_validators.push(quote! { + #crate_name::validators::min_password_strength(__raw_value, #n) + }); + } + if let Some(n) = &self.maximum { elem_validators.push(quote! { #crate_name::validators::maximum(__raw_value, #n) diff --git a/src/validators/min_password_strength.rs b/src/validators/min_password_strength.rs new file mode 100644 index 00000000..510a6dfd --- /dev/null +++ b/src/validators/min_password_strength.rs @@ -0,0 +1,34 @@ +use crate::{InputType, InputValueError}; +use zxcvbn::{zxcvbn, ZxcvbnError}; + +pub fn min_password_strength + InputType>( + value: &T, + min_score: u8, +) -> Result<(), InputValueError> { + match zxcvbn(value.as_ref(), &[]) { + Ok(password_strength) => { + if password_strength.score() < min_score { + Err("password is too weak".into()) + } else { + Ok(()) + } + } + Err(ZxcvbnError::BlankPassword) => Err("password is too weak".into()), + _ => Err("error processing password strength".into()), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_min_password_strength() { + assert!(min_password_strength(&"password".to_string(), 3).is_err()); + assert!(min_password_strength(&"query".to_string(), 3).is_err()); + assert!(min_password_strength(&"P@ssword1".to_string(), 3).is_err()); + assert!(min_password_strength(&"".to_string(), 3).is_err()); + + assert!(min_password_strength(&"Some!Secure!Password".to_string(), 3).is_ok()); + } +} diff --git a/src/validators/mod.rs b/src/validators/mod.rs index 4270dd4c..6cb55de2 100644 --- a/src/validators/mod.rs +++ b/src/validators/mod.rs @@ -7,6 +7,8 @@ mod max_length; mod maximum; mod min_items; mod min_length; +#[cfg(feature = "password-strength-validator")] +mod min_password_strength; mod minimum; mod multiple_of; mod regex;