53 lines
1.6 KiB
Rust
53 lines
1.6 KiB
Rust
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())
|
|
}
|