1use vitaminc_protected::Protected;
2use vitaminc_random::{Generatable, RandomError, SafeRand};
3
4const STANDARD_CHARS: [char; 94] = [
5 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
6 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'e', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
7 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
8 '5', '6', '7', '8', '9', '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '-',
9 '+', '=', '{', '[', '}', ']', '|', '\\', ':', ';', '"', '\'', '<', ',', '>', '.', '?', '/',
10];
11
12pub struct Password<const N: usize>(Protected<[char; N]>); pub struct AlphaNumericPassword<const N: usize>(Password<N>);
20pub struct AlphaPassword<const N: usize>(Password<N>);
21
22impl<const N: usize> Password<N> {
23 pub fn new(password: [char; N]) -> Self {
25 Self(Protected::new(password))
26 }
27 pub fn into_unprotected_string(self) -> String {
31 unimplemented!()
33 }
34
35 pub fn into_protected_string(self) -> Protected<String> {
36 unimplemented!("Paranoid string conversion")
37 }
38}
39
40impl<const N: usize> AlphaNumericPassword<N> {
41 pub fn into_unprotected_string(self) -> String {
45 self.0.into_unprotected_string()
46 }
47
48 pub fn into_protected_string(self) -> Protected<String> {
49 self.0.into_protected_string()
50 }
51}
52
53impl<const N: usize> AlphaPassword<N> {
54 pub fn into_unprotected_string(self) -> String {
58 self.0.into_unprotected_string()
59 }
60
61 pub fn into_protected_string(self) -> Protected<String> {
62 self.0.into_protected_string()
63 }
64}
65
66impl<const N: usize> Generatable for Password<N> {
67 fn random(rng: &mut SafeRand) -> Result<Self, RandomError> {
68 let mut password: [char; N] = [0x00 as char; N];
69 (0..N).for_each(|i| {
70 let char = rng.next_bounded_u32(STANDARD_CHARS.len() as u32);
71 password[i] = STANDARD_CHARS[char as usize];
72 });
73 Ok(Password::new(password))
74 }
75}
76
77impl<const N: usize> Generatable for AlphaNumericPassword<N> {
78 fn random(rng: &mut SafeRand) -> Result<Self, RandomError> {
79 let mut password: [char; N] = [0x00 as char; N];
80 (0..N).for_each(|i| {
81 let char = rng.next_bounded_u32(62);
82 password[i] = STANDARD_CHARS[char as usize];
83 });
84 Ok(Self(Password::new(password)))
85 }
86}
87
88impl<const N: usize> Generatable for AlphaPassword<N> {
89 fn random(rng: &mut SafeRand) -> Result<Self, RandomError> {
90 let mut password: [char; N] = [0x00 as char; N];
91 (0..N).for_each(|i| {
92 let char = rng.next_bounded_u32(52);
93 password[i] = STANDARD_CHARS[char as usize];
94 });
95 Ok(Self(Password::new(password)))
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use crate::{AlphaNumericPassword, AlphaPassword};
102
103 use super::Password;
104 use vitaminc_random::{Generatable, SafeRand, SeedableRng};
105
106 #[ignore = "wip"]
107 #[test]
108 fn test_generate_password() -> Result<(), crate::RandomError> {
109 let mut rng = SafeRand::from_entropy();
110 let value: Password<16> = Generatable::random(&mut rng)?;
111 dbg!(value.into_unprotected_string());
112
113 Ok(())
114 }
115
116 #[ignore = "wip"]
117 #[test]
118 fn test_generate_alphanumeric_password() -> Result<(), crate::RandomError> {
119 let mut rng = SafeRand::from_entropy();
120 let value: AlphaNumericPassword<16> = Generatable::random(&mut rng)?;
121 dbg!(value.into_unprotected_string());
122
123 Ok(())
124 }
125
126 #[ignore = "wip"]
127 #[test]
128 fn test_generate_alpha_password() -> Result<(), crate::RandomError> {
129 let mut rng = SafeRand::from_entropy();
130 let value: AlphaPassword<16> = Generatable::random(&mut rng)?;
131 dbg!(value.into_unprotected_string());
132
133 Ok(())
134 }
135}