passay_rs/
password_generator.rs1use crate::rule::character::CharacterRule;
2
3use rand::SeedableRng;
4use rand::distr::Distribution;
5use rand::distr::Uniform;
6use rand::rngs::StdRng;
7
8pub struct PasswordGenerator {
26 random: StdRng,
27}
28
29impl PasswordGenerator {
30 pub fn new() -> Self {
31 Self {
32 random: StdRng::from_os_rng(),
33 }
34 }
35
36 pub fn generate_password(
37 &mut self,
38 len: usize,
39 rules: &Vec<CharacterRule>,
40 ) -> Result<String, String> {
41 if len == 0 {
42 return Err("length must be greater than 0".into());
43 }
44 let mut target = String::new();
45 let mut all_chars = String::new();
46 for rule in rules {
47 target = self.fill_random_char(
48 rule.valid_characters(),
49 len.min(rule.num_characters()),
50 target,
51 )?;
52 all_chars.push_str(rule.valid_characters());
53 }
54 target = self.fill_random_char(&all_chars, len - target.chars().count(), target)?;
55 target = self.randomize(target)?;
56 Ok(target)
57 }
58
59 fn fill_random_char(
60 &mut self,
61 source: &str,
62 size: usize,
63 mut target: String,
64 ) -> Result<String, String> {
65 let result = Uniform::try_from(0..source.chars().count());
66 let uni = match result {
67 Ok(x) => x,
68 Err(e) => {
69 return Err(e.to_string());
70 }
71 };
72
73 for _ in 0..size {
74 let src_chars = source.chars().collect::<Vec<char>>();
75 let index = uni.sample(&mut self.random);
76 let char = src_chars[index];
77 target.push(char);
78 }
79 Ok(target)
80 }
81
82 fn randomize(&mut self, str: String) -> Result<String, String> {
83 let mut c: char;
84 let mut n: usize;
85 let mut chars: Vec<char> = str.chars().collect();
86 let result = Uniform::try_from(0..chars.len());
87 let uni = match result {
88 Ok(x) => x,
89 Err(e) => {
90 return Err(e.to_string());
91 }
92 };
93
94 for i in 0..chars.len() {
95 n = uni.sample(&mut self.random);
96 c = chars[n];
97 chars[n] = chars[i];
98 chars[i] = c;
99 }
100 Ok(chars.iter().collect())
101 }
102}
103
104impl Default for PasswordGenerator {
105 fn default() -> Self {
106 Self::new()
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use crate::password_generator::PasswordGenerator;
113 use crate::rule::character::CharacterRule;
114 use crate::rule::character_characteristics::CharacterCharacteristics;
115 use crate::rule::character_data::EnglishCharacterData;
116 use crate::rule::{PasswordData, Rule};
117 use std::ops::Not;
118
119 #[test]
120 fn test_generator() {
121 let passwords = random_passwords();
122 for pass in passwords {
123 let password_data = PasswordData::with_password(pass);
124 assert!(gen_fail_rule().validate(&password_data).valid().not());
125 assert!(gen_verify_rule().validate(&password_data).valid());
126 }
127 }
128
129 #[test]
130 fn test_buffer_overflow() {
131 let _output = PasswordGenerator::new()
132 .generate_password(
133 5,
134 &vec![CharacterRule::new(Box::new(EnglishCharacterData::Digit), 10).unwrap()],
135 )
136 .unwrap();
137 let _output = PasswordGenerator::new()
138 .generate_password(
139 10,
140 &vec![CharacterRule::new(Box::new(EnglishCharacterData::Digit), 5).unwrap()],
141 )
142 .unwrap();
143 let _output = PasswordGenerator::new()
144 .generate_password(
145 10,
146 &vec![CharacterRule::new(Box::new(EnglishCharacterData::Digit), 10).unwrap()],
147 )
148 .unwrap();
149 }
150 fn random_passwords() -> Vec<String> {
151 let mut passwords = Vec::with_capacity(100);
152 const LEN: usize = 10;
153
154 let mut password_generator = PasswordGenerator::new();
155
156 let rule = gen_rule();
157 for _ in 0..100 {
158 let password = password_generator.generate_password(LEN, &rule).unwrap();
159 assert!(password.chars().count() >= LEN);
160 passwords.push(password);
161 }
162 passwords
163 }
164 fn gen_rule() -> Vec<CharacterRule> {
165 vec![
166 CharacterRule::new(Box::new(EnglishCharacterData::Digit), 2).unwrap(),
167 CharacterRule::new(Box::new(EnglishCharacterData::Special), 2).unwrap(),
168 CharacterRule::new(Box::new(EnglishCharacterData::UpperCase), 1).unwrap(),
169 CharacterRule::new(Box::new(EnglishCharacterData::LowerCase), 1).unwrap(),
170 ]
171 }
172 fn gen_verify_rule() -> CharacterCharacteristics {
173 CharacterCharacteristics::with_rules_and_characteristics(gen_rule(), 3).unwrap()
174 }
175 fn gen_fail_rule() -> CharacterCharacteristics {
176 let char_rules = vec![
177 CharacterRule::new(Box::new(EnglishCharacterData::Digit), 3).unwrap(),
178 CharacterRule::new(Box::new(EnglishCharacterData::Special), 3).unwrap(),
179 CharacterRule::new(Box::new(EnglishCharacterData::UpperCase), 3).unwrap(),
180 CharacterRule::new(Box::new(EnglishCharacterData::LowerCase), 3).unwrap(),
181 ];
182
183 CharacterCharacteristics::with_rules_and_characteristics(char_rules, 4).unwrap()
184 }
185}