From c248016ea7ebc20551913cc1dfb5dc022fa3440d Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 17 Apr 2021 02:02:18 -0400 Subject: choose characters from alphabet with replacement for pwgen --- src/pwgen.rs | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/pwgen.rs b/src/pwgen.rs index dc6808f..cf63bb2 100644 --- a/src/pwgen.rs +++ b/src/pwgen.rs @@ -56,8 +56,50 @@ pub fn pwgen(ty: Type, len: usize) -> String { let mut rng = rand::thread_rng(); let mut pass = vec![]; - pass.extend(alphabet.choose_multiple(&mut rng, len).copied()); + pass.extend( + std::iter::repeat_with(|| alphabet.choose(&mut rng).unwrap()) + .take(len), + ); // unwrap is safe because the method of generating passwords guarantees // valid utf8 String::from_utf8(pass).unwrap() } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_pwgen() { + let pw = pwgen(Type::AllChars, 50); + assert_eq!(pw.len(), 50); + // technically this could fail, but the chances are incredibly low + // (around 0.000009%) + assert_duplicates(&pw); + + let pw = pwgen(Type::AllChars, 100); + assert_eq!(pw.len(), 100); + assert_duplicates(&pw); + + let pw = pwgen(Type::NoSymbols, 100); + assert_eq!(pw.len(), 100); + assert_duplicates(&pw); + + let pw = pwgen(Type::Numbers, 100); + assert_eq!(pw.len(), 100); + assert_duplicates(&pw); + + let pw = pwgen(Type::NonConfusables, 100); + assert_eq!(pw.len(), 100); + assert_duplicates(&pw); + } + + #[track_caller] + fn assert_duplicates(s: &str) { + let mut set = std::collections::HashSet::new(); + for c in s.chars() { + set.insert(c); + } + assert!(set.len() < s.len()) + } +} -- cgit v1.2.3-54-g00ecf