#![warn(clippy::pedantic)]
#![warn(missing_docs)]
mod passwordmaker;
mod url_parsing;
use passwordmaker::{PasswordPartParameters, PasswordAssemblyParameters};
use passwordmaker::leet::LeetReplacementTable;
use std::error::Error;
use std::fmt::Display;
use std::marker::PhantomData;
pub trait Hasher {
type Output;
fn hash(input : &[u8]) -> Self::Output;
}
pub trait Md4 : Hasher<Output = [u8;16]> {}
pub trait Md5 : Hasher<Output = [u8;16]> {}
pub trait Sha1 : Hasher<Output = [u8;20]> {}
pub trait Sha256 : Hasher<Output = [u8;32]> {}
pub trait Ripemd160 : Hasher<Output = [u8;20]> {}
pub trait HasherList {
type MD4 : Md4;
type MD5 : Md5;
type SHA1 : Sha1;
type SHA256 : Sha256;
type RIPEMD160 : Ripemd160;
}
pub struct PasswordMaker<'a, T : HasherList>{
username : &'a str,
modifier : &'a str,
password_part_parameters : PasswordPartParameters<'a>, post_leet : Option<LeetReplacementTable>, assembly_settings : PasswordAssemblyParameters<'a>,
_hashers : PhantomData<T>,
}
impl<'a, T : HasherList> PasswordMaker<'a, T>{
#[allow(clippy::too_many_arguments)]
pub fn new(
hash_algorithm : HashAlgorithm,
use_leet : UseLeetWhenGenerating,
characters : &'a str,
username : &'a str,
modifier: &'a str,
password_length : usize,
prefix : &'a str,
suffix : &'a str,
) -> Result<Self, SettingsError> {
if Self::is_suitable_as_output_characters(characters) {
let post_leet = match &use_leet {
UseLeetWhenGenerating::NotAtAll
| UseLeetWhenGenerating::Before { .. }
=> None,
UseLeetWhenGenerating::After { level }
| UseLeetWhenGenerating::BeforeAndAfter { level }
=> Some(LeetReplacementTable::get(*level)),
};
Ok(PasswordMaker {
username,
modifier,
password_part_parameters: PasswordPartParameters::from_public_parameters(hash_algorithm, use_leet, characters),
post_leet,
assembly_settings: PasswordAssemblyParameters::from_public_parameters(prefix, suffix, password_length),
_hashers: PhantomData,
})
} else {
Err(SettingsError::InsufficientCharset)
}
}
pub fn generate(&self, data: String, key: String) -> Result<String, GenerationError> {
if data.is_empty() {
Err(GenerationError::MissingTextToUse)
} else if key.is_empty(){
Err(GenerationError::MissingMasterPassword)
} else {
Ok(self.generate_password_verified_input(data, key))
}
}
}
#[cfg_attr(test, derive(strum_macros::EnumIter))]
#[derive(Debug,Clone, Copy)]
pub enum LeetLevel {
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
}
#[derive(Debug,Clone, Copy)]
pub enum HashAlgorithm {
Md4,
HmacMd4,
Md5,
Md5Version06,
HmacMd5,
HmacMd5Version06,
Sha1,
HmacSha1,
Sha256,
HmacSha256,
Ripemd160,
HmacRipemd160,
}
#[derive(Debug,Clone, Copy)]
pub enum UseLeetWhenGenerating {
NotAtAll,
Before {
level : LeetLevel,
},
After {
level : LeetLevel,
},
BeforeAndAfter {
level : LeetLevel,
},
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Clone)]
pub struct UrlParsing {
use_protocol : ProtocolUsageMode,
use_userinfo : bool,
use_subdomains : bool,
use_domain : bool,
use_port_path : bool,
}
#[allow(clippy::fn_params_excessive_bools)]
impl UrlParsing {
#[must_use]
pub fn new(
use_protocol : ProtocolUsageMode,
use_userinfo : bool,
use_subdomains : bool,
use_domain : bool,
use_port_path : bool,
) -> Self{
UrlParsing{ use_protocol, use_userinfo, use_subdomains, use_domain, use_port_path, }
}
#[must_use]
pub fn parse(&self, input : &str) -> String{
self.make_used_text_from_url(input)
}
}
#[derive(Debug, Clone, Copy)]
pub enum ProtocolUsageMode{
Ignored,
Used,
UsedWithUndefinedIfEmpty,
}
#[derive(Debug, Clone, Copy)]
pub enum GenerationError {
MissingMasterPassword,
MissingTextToUse,
}
impl Display for GenerationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GenerationError::MissingMasterPassword => write!(f, "No master password given."),
GenerationError::MissingTextToUse => write!(f, "No text to use. Would just hash the master password."),
}
}
}
impl Error for GenerationError{}
#[derive(Debug, Clone, Copy)]
pub enum SettingsError {
InsufficientCharset,
}
impl Display for SettingsError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SettingsError::InsufficientCharset => write!(f, "Charset needs to have at least 2 characters."),
}
}
}
impl Error for SettingsError{}