typed_headers/impls/
credentials.rs1use base64;
2use std::fmt;
3use std::str::FromStr;
4
5use crate::Error;
6use super::{AuthScheme, Token68};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9enum Info {
10 None,
11 Token68(Token68),
12 }
14
15#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Credentials {
20 scheme: AuthScheme,
21 info: Info,
22}
23
24impl Credentials {
25 #[inline]
27 pub fn from_auth_scheme(scheme: AuthScheme) -> Credentials {
28 Credentials {
29 scheme,
30 info: Info::None,
31 }
32 }
33
34 #[inline]
36 pub fn from_token68(scheme: AuthScheme, token: Token68) -> Credentials {
37 Credentials {
38 scheme,
39 info: Info::Token68(token),
40 }
41 }
42
43 #[inline]
47 pub fn bearer(token: Token68) -> Credentials {
48 Credentials::from_token68(AuthScheme::BEARER, token)
49 }
50
51 #[inline]
55 pub fn basic(user_id: &str, password: &str) -> Result<Credentials, Error> {
56 if user_id.contains(':') || has_ctr(user_id) {
57 return Err(Error::invalid_value());
58 }
59
60 if has_ctr(password) {
61 return Err(Error::invalid_value());
62 }
63
64 let token = format!("{}:{}", user_id, password);
65 let token = base64::encode(token.as_bytes());
66 let token = Token68(token);
67
68 Ok(Credentials::from_token68(AuthScheme::BASIC, token))
69 }
70
71 #[inline]
73 pub fn scheme(&self) -> &AuthScheme {
74 &self.scheme
75 }
76
77 #[inline]
79 pub fn token68(&self) -> Option<&Token68> {
80 match self.info {
81 Info::None => None,
82 Info::Token68(ref token) => Some(token),
83 }
84 }
85
86 #[inline]
88 pub fn as_bearer(&self) -> Option<&Token68> {
89 if self.scheme != AuthScheme::BEARER {
90 return None;
91 }
92
93 self.token68()
94 }
95}
96
97impl fmt::Display for Credentials {
98 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
99 match self.info {
100 Info::None => fmt.write_str(self.scheme.as_str()),
101 Info::Token68(ref token) => write!(fmt, "{} {}", self.scheme, token),
102 }
103 }
104}
105
106impl FromStr for Credentials {
107 type Err = Error;
108
109 fn from_str(s: &str) -> Result<Credentials, Error> {
110 let mut it = s.splitn(2, ' ');
111 let auth_scheme = it
112 .next()
113 .unwrap()
114 .parse::<AuthScheme>()
115 .map_err(|_| Error::invalid_value())?;
116
117 let info = match it.next() {
118 Some(info) => info,
119 None => return Ok(Credentials::from_auth_scheme(auth_scheme)),
120 };
121
122 let info = info.trim_start_matches(' ');
123
124 match info.parse::<Token68>() {
125 Ok(token) => Ok(Credentials::from_token68(auth_scheme, token)),
126 Err(_) => return Err(Error::invalid_value()),
128 }
129 }
130}
131
132fn has_ctr(s: &str) -> bool {
133 s.as_bytes().iter().any(u8::is_ascii_control)
134}