user_password.rs 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. use crate::errors::ErrorCode;
  2. use fancy_regex::Regex;
  3. use lazy_static::lazy_static;
  4. use unicode_segmentation::UnicodeSegmentation;
  5. #[derive(Debug)]
  6. pub struct UserPassword(pub String);
  7. impl UserPassword {
  8. pub fn parse(s: String) -> Result<UserPassword, ErrorCode> {
  9. if s.trim().is_empty() {
  10. return Err(ErrorCode::PasswordIsEmpty);
  11. }
  12. if s.graphemes(true).count() > 100 {
  13. return Err(ErrorCode::PasswordTooLong);
  14. }
  15. let forbidden_characters = ['/', '(', ')', '"', '<', '>', '\\', '{', '}'];
  16. let contains_forbidden_characters = s.chars().any(|g| forbidden_characters.contains(&g));
  17. if contains_forbidden_characters {
  18. return Err(ErrorCode::PasswordContainsForbidCharacters);
  19. }
  20. if !validate_password(&s) {
  21. return Err(ErrorCode::PasswordFormatInvalid);
  22. }
  23. Ok(Self(s))
  24. }
  25. }
  26. impl AsRef<str> for UserPassword {
  27. fn as_ref(&self) -> &str {
  28. &self.0
  29. }
  30. }
  31. lazy_static! {
  32. // Test it in https://regex101.com/
  33. // https://stackoverflow.com/questions/2370015/regular-expression-for-password-validation/2370045
  34. // Hell1!
  35. // [invalid, greater or equal to 6]
  36. // Hel1!
  37. //
  38. // Hello1!
  39. // [invalid, must include number]
  40. // Hello!
  41. //
  42. // Hello12!
  43. // [invalid must include upper case]
  44. // hello12!
  45. static ref PASSWORD: Regex = Regex::new("((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\\W]).{6,20})").unwrap();
  46. }
  47. pub fn validate_password(password: &str) -> bool {
  48. match PASSWORD.is_match(password) {
  49. Ok(is_match) => is_match,
  50. Err(e) => {
  51. log::error!("validate_password fail: {:?}", e);
  52. false
  53. }
  54. }
  55. }