use crate::prelude_internal::*;
pub trait ExtractPassword {
fn extract_password_v1(&self) -> Result<String>;
fn extract_password_v2(&self) -> Result<String>;
}
impl ExtractPassword for Secret {
fn extract_password_v1(&self) -> Result<String> {
const SALT: &[u8] = b"\x00Password_v1";
let mut msecret = self.clone();
let mut ret = String::new();
const NUMCAP_LIST: &[char] = &[
'3', '4', '5', '6', '7', '8', '9', 'A', 'C', 'E', 'G', 'H', 'J', 'K', 'L', 'M', 'N',
'P', 'Q', 'R', 'U', 'W', 'X', 'Y',
];
for i in 0..20 {
msecret.mutate_with_salt(SALT)?;
ret.insert(
ret.len(),
NUMCAP_LIST
[msecret.extract_u32(u32::try_from(NUMCAP_LIST.len()).unwrap() - 1)? as usize],
);
if (i % 4 == 3) && i != 19 {
ret.insert(ret.len(), '-');
}
}
Ok(ret)
}
fn extract_password_v2(&self) -> Result<String> {
const SALT: &[u8] = b"\x00Password_v2";
let mut msecret = self.clone();
let mut ret = String::new();
const LETTER_LIST: &[char] = &[
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'm', 'o', 'p', 'q', 'r', 's', 't',
'u', 'w', 'x', 'y', 'z',
];
const CAP_LIST: &[char] = &[
'A', 'C', 'E', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'U', 'W', 'X', 'Y',
];
const NUMSYM_LIST: &[char] = &[
'2', '3', '4', '5', '6', '7', '8', '9', '-', '/', ':', '\'', '$', '&', '.', '?', '!',
'@',
];
let len = 14usize;
let minbeforeswap = 3;
loop {
msecret.mutate_with_salt(SALT)?;
let swap_point = msecret.extract_usize(len - 1 - minbeforeswap * 2)? + minbeforeswap;
if msecret.extract_bool()? {
for _ in 0..swap_point {
msecret.mutate_with_salt(SALT)?;
ret.insert(
ret.len(),
LETTER_LIST[msecret.extract_usize(LETTER_LIST.len() - 1)?],
);
}
msecret.mutate_with_salt(SALT)?;
ret.insert(
ret.len(),
CAP_LIST[msecret.extract_usize(CAP_LIST.len() - 1)?],
);
for _ in 0..(len - 1 - swap_point) {
msecret.mutate_with_salt(SALT)?;
ret.insert(
ret.len(),
NUMSYM_LIST[msecret.extract_usize(NUMSYM_LIST.len() - 1)?],
);
}
} else {
for _ in 0..swap_point {
msecret.mutate_with_salt(SALT)?;
ret.insert(
ret.len(),
NUMSYM_LIST[msecret.extract_usize(NUMSYM_LIST.len() - 1)?],
);
}
msecret.mutate_with_salt(SALT)?;
ret.insert(
ret.len(),
CAP_LIST[msecret.extract_usize(CAP_LIST.len() - 1)?],
);
for _ in 0..(len - 1 - swap_point) {
msecret.mutate_with_salt(SALT)?;
ret.insert(
ret.len(),
LETTER_LIST[msecret.extract_usize(LETTER_LIST.len() - 1)?],
);
}
}
if ret.contains(|x: char| x.is_ascii_digit())
&& ret.contains(|x: char| x.is_ascii_punctuation())
{
break;
}
ret.clear();
}
assert!(ret.contains(|x: char| x.is_ascii_uppercase()));
assert!(ret.contains(|x: char| x.is_ascii_lowercase()));
Ok(ret)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_password_v1() {
assert_eq!(
&Secret::ZERO.extract_password_v1().unwrap(),
"XMMQ-KJK9-PEWC-578C-KLL3"
);
assert_eq!(
&Secret::ZERO
.subsecret_from_label("1")
.unwrap()
.extract_password_v1()
.unwrap(),
"YCCQ-WLCX-QUNX-CULR-WQAW"
);
}
#[test]
fn test_password_v2() {
assert_eq!(
&Secret::ZERO.extract_password_v2().unwrap(),
"4.92692/Gmwwfw"
);
assert_eq!(
&Secret::ZERO
.subsecret_from_label("0")
.unwrap()
.extract_password_v2()
.unwrap(),
"?:&.$:4/Hifteo"
);
assert_eq!(
&Secret::ZERO
.subsecret_from_label("5")
.unwrap()
.extract_password_v2()
.unwrap(),
"uzfpxskA&8?9'@"
);
}
}