use std::default::Default;
use base64ct::{Base64, Encoding};
use digest::DynDigest;
pub use vigenere::Vigenere;
pub use xor::Xor;
use crate::prelude::*;
pub mod vigenere;
pub mod xor;
pub static ALPHABET: [char; 26] = [
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
't', 'u', 'v', 'w', 'x', 'y', 'z',
];
#[derive(Default, Clone, Debug)]
pub struct NoContext;
#[derive(Clone, Debug)]
pub struct Context(Box<str>);
#[derive(Default, Clone, Debug)]
pub struct NoService;
#[derive(Clone, Debug)]
pub struct Service(Box<str>);
#[derive(Default, Clone, Debug)]
pub struct NoEncrypt;
#[derive(Default, Clone, Debug)]
pub struct Encrypt(Box<[u8]>);
#[derive(Default, Clone, Debug)]
pub struct Hashed(String);
#[derive(Default, Clone, Debug)]
pub struct NoHashed;
#[derive(Clone, Default, Debug)]
pub struct PasswordBuilder<C, S, B, H> {
context: C,
service: S,
encrypt: B,
hashed: H,
repeat: Option<u8>,
}
pub trait Encrypter {
fn encrypt(self, context_word: &[u8], service_word: &[u8]) -> Result<Box<[u8]>>;
}
impl PasswordBuilder<NoContext, NoService, NoEncrypt, NoHashed> {
pub fn new() -> Self {
Default::default()
}
}
impl<C, S> PasswordBuilder<C, S, NoEncrypt, NoHashed> {
pub fn context(
self,
word: impl Into<String>,
) -> PasswordBuilder<Context, S, NoEncrypt, NoHashed> {
PasswordBuilder {
context: Context(Box::from(word.into())),
service: self.service,
encrypt: self.encrypt,
hashed: self.hashed,
repeat: self.repeat,
}
}
pub fn service(
self,
word: impl Into<String>,
) -> PasswordBuilder<C, Service, NoEncrypt, NoHashed> {
PasswordBuilder {
context: self.context,
service: Service(Box::from(word.into())),
encrypt: self.encrypt,
hashed: self.hashed,
repeat: self.repeat,
}
}
}
impl PasswordBuilder<Context, Service, NoEncrypt, NoHashed> {
pub fn encrypt(
self,
encrypt_method: impl Encrypter,
) -> Result<PasswordBuilder<Context, Service, Encrypt, NoHashed>> {
let encrypted_result =
encrypt_method.encrypt(self.context.0.as_bytes(), self.service.0.as_bytes())?;
Ok(PasswordBuilder {
context: self.context,
service: self.service,
encrypt: Encrypt(encrypted_result),
hashed: self.hashed,
repeat: self.repeat,
})
}
}
type HasherArg<'a> = &'a mut dyn DynDigest;
impl<H> PasswordBuilder<Context, Service, Encrypt, H> {
pub fn hash(self, hasher: HasherArg) -> PasswordBuilder<Context, Service, Encrypt, Hashed> {
hasher.update(&self.encrypt.0);
let mut hash = hasher.finalize_reset();
let mut encoded_hash = Base64::encode_string(&hash);
if let Some(r) = self.repeat {
for _ in 1..=r {
encoded_hash = Base64::encode_string(&hash);
hasher.update(encoded_hash.as_bytes());
hash = hasher.finalize_reset();
}
}
PasswordBuilder {
hashed: Hashed(encoded_hash),
context: self.context,
service: self.service,
encrypt: self.encrypt,
repeat: None,
}
}
pub fn repeat(self, number: impl Into<u8>) -> Self {
PasswordBuilder {
repeat: Some(number.into()),
..self
}
}
}
impl PasswordBuilder<Context, Service, Encrypt, Hashed> {
pub fn encode(self) -> String {
self.hashed.0
}
}