1pub mod genoptions;
3
4use rand::prelude::*;
7use rand::distributions::Alphanumeric;
8
9use crate::genoptions::GenOptions;
11
12pub fn gen_password(opts: &GenOptions) -> String {
13 const ALLOWED_SYMBOLS: [char; 32] = ['{', '}', '|', '\\', '/', '?', '\'', '"', '<', '>', ',', '.', '[', ']',
14 ';', ':', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+', '~', '`'];
15 let mut password: String = "".to_string();
16 let mut rng = rand::thread_rng();
17
18 let mut cur: u32 = 0;
19 let mut attempts: u32 = 0;
20
21 loop {
22 if cur == opts.length {
23 break;
24 }
25
26 if attempts >= opts.max_attempts {
27 eprintln!("Exceeded maximum attempts.");
28 std::process::exit(127);
29 }
30
31 if rng.gen_bool(0.5) {
32 if opts.use_symbols {
34 let chosen_char = ALLOWED_SYMBOLS.choose(&mut rng).unwrap_or(&'~');
35
36 if !password.contains(&chosen_char.to_string()) || opts.use_duplicate_chars {
37 password.push(*ALLOWED_SYMBOLS.choose(&mut rng).unwrap_or(&'~'));
38 cur += 1;
39 } else {
40 attempts += 1;
41 }
42 }
43 } else {
44 let char_gen: String = rng.clone().sample_iter(&Alphanumeric)
45 .take(1)
46 .map(char::from)
47 .collect();
48
49 if !password.contains(&char_gen) || opts.use_duplicate_chars {
50 password.push_str(&char_gen);
51 cur += 1;
52 } else {
53 attempts += 1;
54 }
55 }
56 }
57
58 password
59}