use arrayvec::ArrayString; use rand::{rngs::OsRng, seq::SliceRandom}; use std::array; const CHARS: &[u8] = br##"!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~"##; bitflags::bitflags! { struct PasswordFlags: u8 { const LOWERCASE = 0b0001; const UPPERCASE = 0b0010; const NUMBER = 0b0100; const SPECIAL_CHARACTER = 0b1000; } } /// Returns true if the generated master password is valid. /// It checks that it has at least one lowercase, one uppercase, one number and one punctuation char #[inline] fn check_generated_password(password: &[u8; 32]) -> bool { let mut flags = PasswordFlags::empty(); for &byte in password { match byte { b'a'..=b'z' => flags |= PasswordFlags::LOWERCASE, b'A'..=b'Z' => flags |= PasswordFlags::UPPERCASE, b'0'..=b'9' => flags |= PasswordFlags::NUMBER, b'!'..=b'/' | b':'..=b'@' | b'['..=b'`' | b'{'..=b'~' => { flags |= PasswordFlags::SPECIAL_CHARACTER } _ => (), } if flags.is_all() { return true; } } false } #[inline] fn generate_password() -> ArrayString<32> { loop { let password: [u8; 32] = array::from_fn(|_| *CHARS.choose(&mut OsRng).unwrap()); if check_generated_password(&password) { return ArrayString::from_byte_string(&password).unwrap(); } } } /// Continuously generates the password until it passes the checks #[inline] pub fn generate_passwords() -> [ArrayString<32>; 10] { array::from_fn(|_| generate_password()) }