use entroll_core::Faces;
use entroll_dictionaries::{AsciiDictionary, AsciiDictionaryWrapper, WordList};
use itertools::Itertools;
use rand::distributions::Distribution;
pub trait Mkpasswd<S>: Faces + rand::distributions::Distribution<S>
where
Self: Sized,
S: core::fmt::Display,
{
fn mkpasswd<Rng: rand::CryptoRng + rand::Rng + ?Sized>(
&self,
len: usize,
rng: &mut Rng,
) -> String {
self.sample_iter(rng).take(len).join("")
}
fn mkpasswd_entropy_bits<Rng: rand::CryptoRng + rand::Rng + ?Sized>(
&self,
bits: f64,
rng: &mut Rng,
) -> String {
let len = self.needs_faces(bits);
self.mkpasswd(len, rng)
}
}
fn camel_case(mut s: String) -> String {
let last = s.split_off(1);
s.to_uppercase() + &last
}
impl<const N: usize> Mkpasswd<String> for WordList<N> {
fn mkpasswd<Rng: rand::CryptoRng + rand::Rng + ?Sized>(
&self,
len: usize,
rng: &mut Rng,
) -> String {
self.sample_iter(rng).take(len).map(camel_case).join("")
}
}
impl<T> Mkpasswd<u8> for AsciiDictionaryWrapper<T>
where
T: AsciiDictionary,
{
fn mkpasswd<Rng: rand::CryptoRng + rand::Rng + ?Sized>(
&self,
len: usize,
rng: &mut Rng,
) -> String {
self.sample_iter(rng).take(len).map(|c| c as char).collect()
}
}
pub trait ErasedMkpasswd {
fn mkpasswd(&self, len: usize, rng: &mut rand::rngs::OsRng) -> String;
fn mkpasswd_entropy_bits(&self, bits: f64, rng: &mut rand::rngs::OsRng) -> String;
}
impl<const N: usize> ErasedMkpasswd for WordList<N> {
fn mkpasswd(&self, len: usize, rng: &mut rand::rngs::OsRng) -> String {
Mkpasswd::<String>::mkpasswd(self, len, rng)
}
fn mkpasswd_entropy_bits(&self, bits: f64, rng: &mut rand::rngs::OsRng) -> String {
Mkpasswd::<String>::mkpasswd_entropy_bits(self, bits, rng)
}
}
impl<T> ErasedMkpasswd for AsciiDictionaryWrapper<T>
where
T: AsciiDictionary,
{
fn mkpasswd(&self, len: usize, rng: &mut rand::rngs::OsRng) -> String {
Mkpasswd::<u8>::mkpasswd(self, len, rng)
}
fn mkpasswd_entropy_bits(&self, bits: f64, rng: &mut rand::rngs::OsRng) -> String {
Mkpasswd::<u8>::mkpasswd_entropy_bits(self, bits, rng)
}
}