flowerypassgen/
lib.rs

1// Label the modules used
2pub mod genoptions;
3
4// Imports
5/// Standard
6use rand::prelude::*;
7use rand::distributions::Alphanumeric;
8
9/// Flowery Pass Gen
10use 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			// Symbol
33			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}