simple_password_generator/lib.rs
1//! # Simple Password Generator
2//!
3//! A library for generating passwords
4
5use rand::Rng;
6use std::char;
7
8static DEFAULT_LENGTH: u8 = 8;
9static ALPHABET: [char; 26] = [
10 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
11 't', 'u', 'v', 'w', 'x', 'y', 'z',
12];
13static NUMBERS: [char; 10] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
14static SPECIAL_CHARS: [char; 11] = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '~'];
15
16/// PasswordGenerator struct for generatoring passwords
17pub struct PasswordGenerator {
18 /// Array of lowercase chars used when generating a password.
19 lowercase_char_set: [char; 26],
20 /// Array of uppercase chars used when generating a password.
21 uppercase_char_set: [char; 26],
22 /// Array of number chars used when generating a password.
23 number_set: [char; 10],
24 /// Array of special chars used when generating a password.
25 spec_char_set: [char; 11],
26 /// Array of composition codes used when generating a password.
27 composition_codes: [CompositionCodes; 4],
28 /// Length of password to be generated.
29 ///
30 /// Default `8`
31 length: u8,
32 /// Bool used to exclude uppercase composition code when generating a password.
33 ///
34 /// Default `false`
35 lowercase_only: bool,
36 /// Bool used to exclude lowercase composition code when generating a password.
37 ///
38 /// Default `false`
39 uppercase_only: bool,
40 /// Bool used to exclude number composition code when generating a password.
41 ///
42 /// Default `false`
43 exclude_numbers: bool,
44 /// Bool used to special character composition code when generating a password.
45 ///
46 /// Default `false`
47 exclude_special_chars: bool,
48}
49
50/// The primary character types used when generating the composition of the password
51pub enum CompositionCodes {
52 Lowercase,
53 Uppercase,
54 Number,
55 SpecialCharacter,
56}
57
58impl CompositionCodes {
59 /// Outputs all compositions code in a array
60 pub fn all_to_array() -> [CompositionCodes; 4] {
61 [
62 CompositionCodes::Lowercase,
63 CompositionCodes::Uppercase,
64 CompositionCodes::Number,
65 CompositionCodes::SpecialCharacter,
66 ]
67 }
68}
69
70impl PasswordGenerator {
71 /// PasswordGenerator Constructor
72 pub fn new() -> PasswordGenerator {
73 let lowercase_char_set = ALPHABET;
74 let uppercase_char_set = lowercase_char_set.map(|lower_char| {
75 let uppered: Vec<char> = lower_char.to_uppercase().collect();
76 uppered[0]
77 });
78
79 PasswordGenerator {
80 lowercase_char_set,
81 uppercase_char_set,
82 number_set: NUMBERS,
83 spec_char_set: SPECIAL_CHARS,
84 composition_codes: CompositionCodes::all_to_array(),
85 length: DEFAULT_LENGTH,
86 lowercase_only: false,
87 uppercase_only: false,
88 exclude_numbers: false,
89 exclude_special_chars: false,
90 }
91 }
92
93 /// Builder function for setting password length
94 ///
95 /// # Examples
96 ///
97 /// ```
98 /// use simple_password_generator::PasswordGenerator;
99 ///
100 /// let expected_length = 16;
101 /// let result = PasswordGenerator::new().length(expected_length).generate();
102 ///
103 /// assert_eq!(expected_length as usize, result.chars().count());
104 /// ```
105 pub fn length(mut self, length: u8) -> Self {
106 self.length = length;
107
108 self
109 }
110
111 /// Builder function for setting lowercase characters only
112 ///
113 /// # Examples
114 ///
115 /// ```
116 /// use simple_password_generator::PasswordGenerator;
117 ///
118 /// let test_password = PasswordGenerator::new().lowercase_only(true).generate();
119 /// let mut contains_uppercase = false;
120 ///
121 /// for c in test_password.chars() {
122 /// if c.is_alphabetic() {
123 /// if c.is_uppercase() {
124 /// contains_uppercase = true
125 /// }
126 /// }
127 /// }
128 ///
129 /// assert_eq!(false, contains_uppercase);
130 /// ```
131 pub fn lowercase_only(mut self, lowercase_only: bool) -> Self {
132 self.lowercase_only = lowercase_only;
133
134 self
135 }
136
137 /// Builder function for setting uppercase characters only
138 ///
139 /// # Examples
140 ///
141 /// ```
142 /// use simple_password_generator::PasswordGenerator;
143 ///
144 /// let test_password = PasswordGenerator::new().uppercase_only(true).generate();
145 /// let mut contains_lowercase = false;
146 ///
147 /// for c in test_password.chars() {
148 /// if c.is_alphabetic() {
149 /// if c.is_lowercase() {
150 /// contains_lowercase = true
151 /// }
152 /// }
153 /// }
154 ///
155 /// assert_eq!(false, contains_lowercase);
156 /// ```
157 pub fn uppercase_only(mut self, uppercase_only: bool) -> Self {
158 self.uppercase_only = uppercase_only;
159
160 self
161 }
162
163 /// Builder function for excluding any numbers from password
164 ///
165 /// # Examples
166 ///
167 /// ```
168 /// use simple_password_generator::PasswordGenerator;
169 ///
170 /// let test_password = PasswordGenerator::new().exclude_numbers(true).generate();
171 /// let mut contains_numbers = false;
172 ///
173 /// for c in test_password.chars() {
174 /// if c.is_numeric() {
175 /// contains_numbers = true
176 /// }
177 /// }
178 ///
179 /// assert_eq!(false, contains_numbers);
180 /// ```
181 pub fn exclude_numbers(mut self, exclude_numbers: bool) -> Self {
182 self.exclude_numbers = exclude_numbers;
183
184 self
185 }
186
187 /// Builder function for excluding any special characters from password
188 ///
189 /// # Examples
190 ///
191 /// ```
192 /// use simple_password_generator::PasswordGenerator;
193 ///
194 /// let test_password = PasswordGenerator::new()
195 /// .exclude_special_chars(true)
196 /// .generate();
197 /// let spec_char_vec: Vec<char> = vec!['!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '~'];
198 /// let mut contains_special_chars = false;
199 ///
200 /// for c in test_password.chars() {
201 /// if spec_char_vec.contains(&c) {
202 /// contains_special_chars = true;
203 /// }
204 /// }
205 ///
206 /// assert_eq!(false, contains_special_chars);
207 /// ```
208 pub fn exclude_special_chars(mut self, exclude_special_chars: bool) -> Self {
209 self.exclude_special_chars = exclude_special_chars;
210
211 self
212 }
213
214 /// Returns a random lowercase char
215 fn get_random_lowercase_char(&self) -> char {
216 let mut rng = rand::thread_rng();
217 let rnd_index = rng.gen_range(0..=self.lowercase_char_set.len() - 1);
218
219 self.lowercase_char_set[rnd_index]
220 }
221
222 /// Returns a random uppercase char
223 fn get_random_uppercase_char(&self) -> char {
224 let mut rng = rand::thread_rng();
225 let rnd_index = rng.gen_range(0..=self.uppercase_char_set.len() - 1);
226
227 self.uppercase_char_set[rnd_index]
228 }
229
230 /// Returns a random number char
231 fn get_random_number(&self) -> char {
232 let mut rng = rand::thread_rng();
233 let rnd_index = rng.gen_range(0..=self.number_set.len() - 1);
234
235 self.number_set[rnd_index]
236 }
237
238 /// Returns a random special character char
239 fn get_random_special_character(&self) -> char {
240 let mut rng = rand::thread_rng();
241 let rnd_index = rng.gen_range(0..=self.spec_char_set.len() - 1);
242
243 self.spec_char_set[rnd_index]
244 }
245
246 /// Generates a random composition vec
247 fn generate_random_composition(&self) -> Vec<&CompositionCodes> {
248 let mut result: Vec<&CompositionCodes> = Vec::new();
249 let mut rng = rand::thread_rng();
250 let filtered_comp_codes = self
251 .composition_codes
252 .iter()
253 .filter(|code| match code {
254 CompositionCodes::Lowercase => {
255 if self.uppercase_only {
256 false
257 } else {
258 true
259 }
260 }
261 CompositionCodes::Uppercase => {
262 if self.lowercase_only {
263 false
264 } else {
265 true
266 }
267 }
268 CompositionCodes::Number => {
269 if self.exclude_numbers {
270 false
271 } else {
272 true
273 }
274 }
275 CompositionCodes::SpecialCharacter => {
276 if self.exclude_special_chars {
277 false
278 } else {
279 true
280 }
281 }
282 })
283 .collect::<Vec<_>>();
284
285 for _i in 0..self.length {
286 let rnd_index = rng.gen_range(0..=filtered_comp_codes.len() - 1);
287 let comp_char = filtered_comp_codes[rnd_index];
288
289 result.push(comp_char)
290 }
291
292 result
293 }
294
295 /// Generates a random string following the input composition vec
296 fn generate_random_string_from_composition(
297 &self,
298 composition: Vec<&CompositionCodes>,
299 ) -> String {
300 let mut password: Vec<char> = Vec::new();
301
302 for code in composition {
303 match code {
304 CompositionCodes::Lowercase => {
305 let value = self.get_random_lowercase_char();
306 password.push(value);
307 }
308 CompositionCodes::Uppercase => {
309 let value = self.get_random_uppercase_char();
310 password.push(value);
311 }
312 CompositionCodes::Number => {
313 let value = self.get_random_number();
314 password.push(value);
315 }
316 CompositionCodes::SpecialCharacter => {
317 let value = self.get_random_special_character();
318 password.push(value);
319 }
320 }
321 }
322
323 password.into_iter().collect()
324 }
325
326 /// Generates a password
327 ///
328 /// # Examples
329 ///
330 /// ```
331 /// use simple_password_generator::PasswordGenerator;
332 ///
333 /// let password = PasswordGenerator::new().generate();
334 /// ```
335 pub fn generate(&self) -> String {
336 let comp_code = self.generate_random_composition();
337 let password = self.generate_random_string_from_composition(comp_code);
338
339 password
340 }
341}