passay_rs/rule/
digest_source.rs1use crate::hash::Hasher;
2use crate::rule::reference::Reference;
3use crate::rule::rule_result::RuleResult;
4use crate::rule::source::{SourceReference, validate_with_source_references};
5use crate::rule::{PasswordData, Rule};
6
7pub struct DigestSourceRule<H>
48where
49 H: Hasher<String>,
50{
51 hasher: H,
52 report_all: bool,
53}
54
55impl<H> DigestSourceRule<H>
56where
57 H: Hasher<String>,
58{
59 pub fn new(hasher: H, report_all: bool) -> Self {
60 Self { hasher, report_all }
61 }
62}
63
64impl<H> Rule for DigestSourceRule<H>
65where
66 H: Hasher<String>,
67{
68 fn validate(&self, password_data: &PasswordData) -> RuleResult {
69 let matcher = |password: &str, rf: &SourceReference| {
70 let pass = password.to_string();
71 let undigested = match rf.salt() {
72 None => pass,
73 Some(salt) => salt.apply_to(pass),
74 };
75 let h = &self.hasher;
76 h.compare(rf.password().as_bytes(), undigested.as_bytes()).unwrap_or(false)
77 };
78 validate_with_source_references(self.report_all, password_data, matcher)
79 }
80}
81
82#[cfg(test)]
83mod test {
84 use crate::rule::PasswordData;
85 use crate::rule::digest_history::test::Sha1Hasher;
86 use crate::rule::digest_source::DigestSourceRule;
87 use crate::rule::reference::Reference;
88 use crate::rule::source::{ERROR_CODE, SourceReference};
89 use crate::test::{RulePasswordTestItem, check_messages, check_passwords};
90
91 #[test]
92 fn test_passwords() {
93 let test_cases: Vec<RulePasswordTestItem> = vec![
94 RulePasswordTestItem(
95 Box::new(create_digest_rule()),
96 PasswordData::new(
97 "t3stUs3r01".to_string(),
98 Some("testuser".to_string()),
99 create_sources(),
100 ),
101 vec![],
102 ),
103 RulePasswordTestItem(
104 Box::new(create_digest_rule()),
105 PasswordData::new(
106 "t3stUs3r04".to_string(),
107 Some("testuser".to_string()),
108 create_sources(),
109 ),
110 vec![ERROR_CODE],
111 ),
112 RulePasswordTestItem(
114 Box::new(create_digest_rule()),
115 PasswordData::with_password_and_user(
116 "t3stUs3r01".to_string(),
117 Some("testuser".to_string()),
118 ),
119 vec![],
120 ),
121 RulePasswordTestItem(
123 Box::new(create_digest_rule()),
124 PasswordData::with_password_and_user(
125 "t3stUs3r04".to_string(),
126 Some("testuser".to_string()),
127 ),
128 vec![],
129 ),
130 ];
131 check_passwords(test_cases);
132 }
133 #[test]
134 fn test_messages() {
135 let test_cases: Vec<RulePasswordTestItem> = vec![RulePasswordTestItem(
136 Box::new(create_digest_rule()),
137 PasswordData::new(
138 "t3stUs3r04".to_string(),
139 Some("testuser".to_string()),
140 create_sources(),
141 ),
142 vec!["SOURCE_VIOLATION,System B"],
143 )];
144 check_messages(test_cases);
145 }
146 fn create_sources() -> Vec<Box<dyn Reference>> {
147 vec![Box::new(SourceReference::with_password_label(
148 "CJGTDMQRP+rmHApkcijC80aDV0o=".to_string(),
149 "System B".to_string(),
150 ))]
151 }
152 fn create_digest_rule() -> DigestSourceRule<Sha1Hasher> {
153 DigestSourceRule::new(Sha1Hasher, true)
154 }
155}