mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 18:17:13 +08:00 
			
		
		
		
	refactor: extract email validation and PII utils to common_utils crate (#72)
				
					
				
			This commit is contained in:
		
							
								
								
									
										176
									
								
								crates/common_utils/src/pii.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								crates/common_utils/src/pii.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,176 @@ | ||||
| //! Personal Identifiable Information protection. | ||||
|  | ||||
| use std::{convert::AsRef, fmt}; | ||||
|  | ||||
| use masking::{Strategy, WithType}; | ||||
|  | ||||
| use crate::validation::validate_email; | ||||
|  | ||||
| /// Card number | ||||
| #[derive(Debug)] | ||||
| pub struct CardNumber; | ||||
|  | ||||
| impl<T> Strategy<T> for CardNumber | ||||
| where | ||||
|     T: AsRef<str>, | ||||
| { | ||||
|     fn fmt(val: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         let val_str: &str = val.as_ref(); | ||||
|  | ||||
|         if val_str.len() < 15 && val_str.len() > 19 { | ||||
|             return WithType::fmt(val, f); | ||||
|         } | ||||
|  | ||||
|         f.write_str(&format!( | ||||
|             "{}{}", | ||||
|             &val_str[..6], | ||||
|             "*".repeat(val_str.len() - 6) | ||||
|         )) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* | ||||
| /// Phone number | ||||
| #[derive(Debug)] | ||||
| pub struct PhoneNumber; | ||||
|  | ||||
| impl<T> Strategy<T> for PhoneNumber | ||||
| where | ||||
|     T: AsRef<str>, | ||||
| { | ||||
|     fn fmt(val: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         let val_str: &str = val.as_ref(); | ||||
|  | ||||
|         if val_str.len() < 10 || val_str.len() > 12 { | ||||
|             return WithType::fmt(val, f); | ||||
|         } | ||||
|  | ||||
|         f.write_str(&format!( | ||||
|             "{}{}{}", | ||||
|             &val_str[..2], | ||||
|             "*".repeat(val_str.len() - 5), | ||||
|             &val_str[(val_str.len() - 3)..] | ||||
|         )) | ||||
|     } | ||||
| } | ||||
| */ | ||||
|  | ||||
| /// Email address | ||||
| #[derive(Debug)] | ||||
| pub struct Email; | ||||
|  | ||||
| impl<T> Strategy<T> for Email | ||||
| where | ||||
|     T: AsRef<str>, | ||||
| { | ||||
|     fn fmt(val: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         let val_str: &str = val.as_ref(); | ||||
|         let is_valid = validate_email(val_str); | ||||
|  | ||||
|         if is_valid.is_err() { | ||||
|             return WithType::fmt(val, f); | ||||
|         } | ||||
|  | ||||
|         let parts: Vec<&str> = val_str.split('@').collect(); | ||||
|         if parts.len() != 2 { | ||||
|             return WithType::fmt(val, f); | ||||
|         } | ||||
|  | ||||
|         f.write_str(&format!("{}@{}", "*".repeat(parts[0].len()), parts[1])) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// IP address | ||||
| #[derive(Debug)] | ||||
| pub struct IpAddress; | ||||
|  | ||||
| impl<T> Strategy<T> for IpAddress | ||||
| where | ||||
|     T: AsRef<str>, | ||||
| { | ||||
|     fn fmt(val: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         let val_str: &str = val.as_ref(); | ||||
|         let segments: Vec<&str> = val_str.split('.').collect(); | ||||
|  | ||||
|         if segments.len() != 4 { | ||||
|             return WithType::fmt(val, f); | ||||
|         } | ||||
|  | ||||
|         for seg in segments.iter() { | ||||
|             if seg.is_empty() || seg.len() > 3 { | ||||
|                 return WithType::fmt(val, f); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         f.write_str(&format!("{}.**.**.**", segments[0])) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod pii_masking_strategy_tests { | ||||
|     use masking::Secret; | ||||
|  | ||||
|     use super::{CardNumber, Email, IpAddress}; | ||||
|  | ||||
|     #[test] | ||||
|     fn test_valid_card_number_masking() { | ||||
|         let secret: Secret<String, CardNumber> = Secret::new("1234567890987654".to_string()); | ||||
|         assert_eq!("123456**********", &format!("{:?}", secret)); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_invalid_card_number_masking() { | ||||
|         let secret: Secret<String, CardNumber> = Secret::new("1234567890".to_string()); | ||||
|         assert_eq!("123456****", &format!("{:?}", secret)); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|     #[test] | ||||
|     fn test_valid_phone_number_masking() { | ||||
|         let secret: Secret<String, PhoneNumber> = Secret::new("9922992299".to_string()); | ||||
|         assert_eq!("99*****299", &format!("{}", secret)); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_invalid_phone_number_masking() { | ||||
|         let secret: Secret<String, PhoneNumber> = Secret::new("99229922".to_string()); | ||||
|         assert_eq!("*** alloc::string::String ***", &format!("{}", secret)); | ||||
|  | ||||
|         let secret: Secret<String, PhoneNumber> = Secret::new("9922992299229922".to_string()); | ||||
|         assert_eq!("*** alloc::string::String ***", &format!("{}", secret)); | ||||
|     } | ||||
|     */ | ||||
|  | ||||
|     #[test] | ||||
|     fn test_valid_email_masking() { | ||||
|         let secret: Secret<String, Email> = Secret::new("myemail@gmail.com".to_string()); | ||||
|         assert_eq!("*******@gmail.com", &format!("{:?}", secret)); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_invalid_email_masking() { | ||||
|         let secret: Secret<String, Email> = Secret::new("myemailgmail.com".to_string()); | ||||
|         assert_eq!("*** alloc::string::String ***", &format!("{:?}", secret)); | ||||
|  | ||||
|         let secret: Secret<String, Email> = Secret::new("myemail@gmail@com".to_string()); | ||||
|         assert_eq!("*** alloc::string::String ***", &format!("{:?}", secret)); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_valid_ip_addr_masking() { | ||||
|         let secret: Secret<String, IpAddress> = Secret::new("123.23.1.78".to_string()); | ||||
|         assert_eq!("123.**.**.**", &format!("{:?}", secret)); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_invalid_ip_addr_masking() { | ||||
|         let secret: Secret<String, IpAddress> = Secret::new("123.4.56".to_string()); | ||||
|         assert_eq!("*** alloc::string::String ***", &format!("{:?}", secret)); | ||||
|  | ||||
|         let secret: Secret<String, IpAddress> = Secret::new("123.4567.12.4".to_string()); | ||||
|         assert_eq!("*** alloc::string::String ***", &format!("{:?}", secret)); | ||||
|  | ||||
|         let secret: Secret<String, IpAddress> = Secret::new("123..4.56".to_string()); | ||||
|         assert_eq!("*** alloc::string::String ***", &format!("{:?}", secret)); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Sanchith Hegde
					Sanchith Hegde