1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use std::str::FromStr;
use crate::error::AuthBasicError;
#[derive(Debug, PartialEq)]
pub struct Credentials {
pub user_id: String,
pub password: String,
}
impl Credentials {
pub fn new(user_id: &str, password: &str) -> Self {
Self {
user_id: user_id.to_string(),
password: password.to_string(),
}
}
pub fn decode(auth_header_value: String) -> Result<Self, AuthBasicError> {
let decoded = base64::decode(auth_header_value)?;
let as_utf8 = String::from_utf8(decoded)?;
if let Some((user_id, password)) = as_utf8.split_once(':') {
return Ok(Self::new(user_id, password));
}
Err(AuthBasicError::InvalidAuthorizationHeader)
}
pub fn encode(&self) -> String {
let credentials = format!("{}:{}", self.user_id, self.password);
base64::encode(credentials.as_bytes())
}
pub fn from_header(auth_header: String) -> Result<Credentials, AuthBasicError> {
if let Some((auth_type, encoded_credentials)) = auth_header.split_once(' ') {
if encoded_credentials.contains(' ') {
return Err(AuthBasicError::InvalidAuthorizationHeader);
}
if auth_type.to_lowercase() != "basic" {
return Err(AuthBasicError::InvalidScheme(auth_type.to_string()));
}
let credentials = Credentials::decode(encoded_credentials.to_string())?;
return Ok(credentials);
}
Err(AuthBasicError::InvalidAuthorizationHeader)
}
pub fn as_http_header(&self) -> String {
let as_base64 = self.encode();
format!("Basic {}", as_base64)
}
}
impl FromStr for Credentials {
type Err = AuthBasicError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.contains(' ') {
return Self::from_header(s.into());
}
Self::decode(s.into())
}
}