1mod error;
2
3use error::ParseError;
4
5#[derive(Debug, PartialEq)]
6pub struct Credential {
7 pub user_id: String,
8 pub password: String
9}
10
11pub fn decode(s: &str) -> Result<Credential, ParseError> {
12 match s {
13 s if s.starts_with("Basic ") => {
14 let decoded = base64::decode(&s[6..])?;
15 let decoded = std::str::from_utf8(&decoded)?;
16 let parts: Vec<&str> = decoded.splitn(2, ":").collect();
17 match &parts.as_slice() {
18 [user, pass] => Ok(Credential { user_id: user.to_string(), password: pass.to_string() }),
19 _ => Err(ParseError::Format)
20 }
21 }
22 _ => Err(ParseError::Scheme)
23 }
24}
25
26impl std::str::FromStr for Credential {
27 type Err = ParseError;
28 fn from_str(s: &str) -> Result<Self, Self::Err> {
29 decode(s)
30 }
31}
32
33#[cfg(test)]
34mod test {
35 use super::*;
36
37 fn encode(c: &Credential) -> String {
38 let unencoded = format!("{}:{}", c.user_id, c.password);
39 let encoded = base64::encode(unencoded);
40 format!("Basic {}", encoded)
41 }
42
43 fn encode_str(s: &str) -> String {
44 let encoded = base64::encode(s);
45 format!("Basic {}", encoded)
46 }
47
48 #[test]
49 fn identify_scheme() {
50 let c = Credential {
51 user_id: "Aladdin".to_string(),
52 password: "open sesame".to_string()
53 };
54 let s = encode(&c);
55 let c2 = decode(&s);
56 assert_eq!(Ok(c), c2);
57 }
58
59 #[test]
60 fn no_colon() {
61 let s = encode_str("john");
62 let c = decode(&s);
63 assert_eq!(Err(ParseError::Format), c);
64 }
65
66 #[test]
67 fn allow_empty_password() {
68 let s = encode_str("john:");
69 let c = decode(&s);
70 assert_ne!(Err(ParseError::Format), c);
71 }
72
73 #[test]
74 fn bad_base64() {
75 let s = "Basic abcdefg";
76 let c = decode(&s);
77 assert_eq!(Err(ParseError::Decode), c);
78 }
79
80 #[test]
81 fn bad_scheme() {
82 let c = Credential {
83 user_id: "john".to_string(),
84 password: "hunter2".to_string(),
85 };
86 let unencoded = format!("{}:{}", c.user_id, c.password);
87 let encoded = base64::encode(unencoded);
88 let formatted = format!("Bearer {}", encoded);
89 let c = decode(&formatted);
90 assert_eq!(Err(ParseError::Scheme), c);
91 }
92}