use std::fs::File;
use std::io::Read;
pub const CHARS_NO_SPECIAL: &str = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZZYXWVUTSRQPONMLKJIHGFEDCBA9876543210zyxwvutsrqponmlkjihgfedcba";
pub const CHARS_SPECIAL: &str =
"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ!§$%&/()=?´`-_.,:;#'+*<>°^^°><*+'#;:,._-`´?=)(&%$§!ZYXWVUTSRQPONMLKJIHGFEDCBA9876543210zyxwvutsrqponmlkjihgfedcba";
pub struct Passt {}
impl Passt {
pub fn choose_random_char(char_set: &str) -> String {
#[cfg(target_os = "windows")]
let mut f = File::open("file:/dev/urandom").unwrap();
#[cfg(not(target_os = "windiws"))]
let mut f = File::open("/dev/urandom").unwrap();
let mut buf = [0u8; 32];
f.read_exact(&mut buf).unwrap();
let char_len_i64 = char_set.len() as i64;
let mut total: i64 = 0;
for n in buf.iter() {
total = (total + (*n as i64)) * 2;
}
let mut index: i64 = total % (char_len_i64) / 2;
if index > char_len_i64 {
index = index / char_len_i64;
}
let mut ret = String::from("");
let mut idx = 0;
for c in char_set.chars() {
ret = format!("{}", c);
idx = idx + 1;
if idx == index {
break;
}
}
if ret == String::from("") {
String::from("A");
}
return ret.to_string();
}
pub fn random_password(length: i32, with_special_chars: Option<bool>) -> String {
let char_set: &str = match with_special_chars {
Some(use_special) => {
if use_special {
CHARS_SPECIAL
} else {
CHARS_NO_SPECIAL
}
}
_ => CHARS_NO_SPECIAL,
};
let pass = Self::random_password_with_custom_set(length, char_set);
return pass;
}
pub fn random_password_with_custom_set(length: i32, char_set: &str) -> String {
let mut len = length;
let len_usize = length as usize;
let mut pass = String::from("");
while len > 0 {
pass = format!("{}{}", pass, Passt::choose_random_char(char_set));
len = len - 1;
}
if pass.len() != len_usize {
while pass.len() < len_usize {
pass = format!("{}{}", pass, Passt::choose_random_char(char_set));
}
};
pass.chars().take(len_usize).collect()
}
}
mod test {
#[test]
fn test_random_password() {
use super::*;
use std::collections::HashMap;
let mut cases: HashMap<usize, usize> = HashMap::new();
cases.insert(12, Passt::random_password(12, Some(false)).chars().count());
cases.insert(18, Passt::random_password(18, None).chars().count());
cases.insert(36, Passt::random_password(36, Some(true)).chars().count());
cases.insert(
125,
Passt::random_password(125, Some(false)).chars().count(),
);
cases.insert(2, Passt::random_password(2, Some(true)).chars().count());
cases.insert(255, Passt::random_password(255, Some(true)).chars().count());
for case in cases.iter() {
assert_eq!(case.0, case.1);
}
}
#[test]
fn test_random_password_with_custom_set() {
use super::*;
use std::collections::HashMap;
let mut cases: HashMap<usize, usize> = HashMap::new();
cases.insert(
12,
Passt::random_password_with_custom_set(
12,
"oqeqkobhwrio0ß3ri249ßt9ßjskfbnkfpfbneob?)()&/(/!wkvhoqvkpwnbö56185d465q4wf646ew",
)
.chars()
.count(),
);
cases.insert(
18,
Passt::random_password_with_custom_set(18, "hs")
.chars()
.count(),
);
cases.insert(
36,
Passt::random_password_with_custom_set(
36,
"qwifqpehveqpviqpevqepvbqivakjfiowhet9823ur9ß13rhfeiqwafjvdsiohg2iw",
)
.chars()
.count(),
);
cases.insert(
125,
Passt::random_password_with_custom_set(
125,
"qwifqpehveqpviqpevqepvbqivakjfiowhet9823ur9ß13rhfeiqwafjvdsiohg2iw",
)
.chars()
.count(),
);
cases.insert(
2,
Passt::random_password_with_custom_set(
2,
"qwifqpehveqpviqpevqepvbqivakjfiowhet9823ur9ß13rhfeiqwafjvdsiohg2iw",
)
.chars()
.count(),
);
cases.insert(
12,
Passt::random_password_with_custom_set(12, "0123456789abc")
.chars()
.count(),
);
cases.insert(
6,
Passt::random_password_with_custom_set(6, "äöüÄÖÜáéóúÁÉÓÚàèòùÀÈÒÙß$§")
.chars()
.count(),
);
cases.insert(
7,
Passt::random_password_with_custom_set(7, "abc")
.chars()
.count(),
);
cases.insert(
7,
Passt::random_password_with_custom_set(7, "🤷♀️🥨🥇")
.chars()
.count(),
);
for case in cases.iter() {
assert_eq!(case.0, case.1);
}
}
#[test]
fn test_1000_random_passwords() {
use super::*;
let mut i = 0;
let max = 10000;
while i < max {
i = i + 1;
let expected: i32 = max / i;
assert_eq!(
expected,
Passt::random_password(expected, Some(false))
.chars()
.count() as i32
);
}
}
#[test]
fn test_1000_random_passwords_with_special() {
use super::*;
let mut i = 0;
let max = 1000;
while i < max {
i = i + 1;
let expected: i32 = max / i;
assert_eq!(
expected,
Passt::random_password(expected, Some(true)).chars().count() as i32
);
}
}
#[test]
fn test_10000_random_passwords() {
use super::*;
let mut i = 0;
let max = 10000;
while i < max {
i = i + 1;
let expected: i32 = max / i;
assert_eq!(
expected,
Passt::random_password(expected, Some(true)).chars().count() as i32
);
}
}
#[test]
fn test_10000_random_password_with_special() {
use super::*;
let mut i = 0;
let max = 10000;
while i < max {
i = i + 1;
let expected: i32 = max / i;
assert_eq!(
expected,
Passt::random_password(expected, Some(true)).chars().count() as i32
);
}
}
}