1#![allow(unused)]
2#![forbid(unsafe_code)]
3
4use easy_base64::encode;
5use sha1_smol::Sha1;
6use sha256::digest;
7use uuid::Uuid;
8
9#[derive(Debug, Clone, PartialEq)]
10pub enum BasicTokenLength {
11 Basic112 = 112,
12 Basic156 = 156,
13}
14
15impl TryFrom<usize> for BasicTokenLength {
16 type Error = ();
17
18 fn try_from(value: usize) -> Result<Self, Self::Error> {
19 match value {
20 112 => Ok(BasicTokenLength::Basic112),
21 156 => Ok(BasicTokenLength::Basic156),
22 _ => Err(()),
23 }
24 }
25}
26
27#[derive(Debug, Clone, PartialEq)]
28pub struct BasicToken(String);
29
30impl BasicToken {
31 pub const CLIENT_ID: &str = "MsOIJ39Q28";
32 pub const CLIENT_SECRET: &str = "PTDc3H8a)Vi=UYap";
33 pub const DEFAULT_LENGTH: BasicTokenLength = BasicTokenLength::Basic112;
34
35 pub fn new(client_id: &str, client_secret: &str, length: BasicTokenLength) -> BasicToken {
36 let id = Uuid::new_v4().as_simple().to_string(); let hex = match length {
39 BasicTokenLength::Basic112 => id,
40 BasicTokenLength::Basic156 => sha256::digest(&id), }
42 .to_uppercase(); let prefix = format!("{hex}_{client_id}:");
45
46 let suffix = {
47 let mut hash = Sha1::new();
48 hash.update(format!("{hex}:{client_id}:{client_secret}").as_bytes());
49 format!("{}", hash.digest())
50 };
51
52 Self(encode(format!("{prefix}{suffix}").as_bytes()))
53 }
54}
55
56impl std::fmt::Display for BasicToken {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 write!(f, "{}", self.0)
59 }
60}
61
62impl Default for BasicToken {
63 fn default() -> Self {
64 Self::new(Self::CLIENT_ID, Self::CLIENT_SECRET, Self::DEFAULT_LENGTH)
65 }
66}
67
68impl From<String> for BasicToken {
69 fn from(token: String) -> Self {
70 BasicToken(token)
71 }
72}
73
74impl From<BasicToken> for String {
75 fn from(token: BasicToken) -> Self {
76 token.0
77 }
78}
79
80impl From<&str> for BasicToken {
81 fn from(token: &str) -> Self {
82 token.to_owned().into()
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn new_makes_112() {
92 let basic = BasicToken::new(
93 BasicToken::CLIENT_ID,
94 BasicToken::CLIENT_SECRET,
95 BasicTokenLength::Basic112,
96 );
97
98 assert_eq!(basic.0.len(), 112);
99 }
100
101 #[test]
102 fn new_makes_156() {
103 let basic = BasicToken::new("client_id", "client_secret", BasicTokenLength::Basic156);
104
105 assert_eq!(basic.0.len(), 156);
106 }
107
108 #[test]
109 fn default_is_unique() {
110 let basic = BasicToken::default();
111 let basic2 = BasicToken::default();
112
113 assert_ne!(basic, basic2);
114 }
115
116 #[test]
117 fn default_is_112() {
118 let basic = BasicToken::default();
119 assert_eq!(basic.0.len(), 112);
120 }
121
122 #[test]
123 fn clones_are_equal() {
124 let basic = BasicToken::default();
125 let basic2 = basic.clone();
126
127 assert_eq!(basic, basic2)
128 }
129
130 #[test]
131 fn debug_includes_token() {
132 let tokens = vec!["Yinkies", "Foo", "Bar"];
133
134 for token in tokens {
135 let basic = BasicToken::from(token);
136 assert_eq!(format!("{basic:?}"), format!("BasicToken(\"{basic}\")"))
137 }
138 }
139
140 #[test]
141 fn test_display() {
142 let basic = BasicToken::default();
143 let basic2 = format!("{}", basic);
144
145 assert_eq!(basic2, basic.0)
146 }
147
148 #[test]
149 fn test_from_string() {
150 assert_eq!(BasicToken::from("Yinkies".to_string()).0, "Yinkies");
151 }
152
153 #[test]
154 fn test_from_str() {
155 assert_eq!(BasicToken::from("Yinkies").0, "Yinkies");
156 }
157
158 #[test]
159 fn test_into_string() {
160 let basic: String = BasicToken::from("Yinkies").into();
161 assert_eq!(basic, "Yinkies");
162 }
163
164 #[test]
165 fn basic_length_try_from_usize_112() {
166 let basic = BasicTokenLength::try_from(112);
167
168 assert!(basic.is_ok());
169 }
170
171 #[test]
172 fn basic_length_try_from_usize_156() {
173 let basic = BasicTokenLength::try_from(156);
174
175 assert!(basic.is_ok());
176 }
177
178 #[test]
179 fn basic_length_try_from_usize_0() {
180 let basic = BasicTokenLength::try_from(0);
181
182 assert!(basic.is_err());
183 }
184
185 #[test]
186 fn basic_length_clone() {
187 let basic = BasicTokenLength::Basic112;
188 let basic2 = basic.clone();
189
190 assert_eq!(basic, basic2);
191 }
192
193 #[test]
194 fn basic_length_display() {
195 let basic = BasicTokenLength::Basic112;
196 let basic2 = format!("{basic:?}");
197
198 assert_eq!(basic2, "Basic112");
199 }
200}