1use std::{borrow::Cow, str};
2
3use crate::{
4 traits::{AuthValue, Scheme, User},
5 Error,
6};
7use async_trait::async_trait;
8
9pub struct Basic {
10 basic: Option<Cow<'static, str>>,
11}
12
13unsafe impl Send for Basic {}
14
15unsafe impl Sync for Basic {}
16
17impl Default for Basic {
18 fn default() -> Self {
19 Basic { basic: None }
20 }
21}
22
23impl Basic {
24 pub fn new<T: Into<String>>(basic: T) -> Self {
25 let basic: String = basic.into();
26
27 Basic {
28 basic: Some(basic.into()),
29 }
30 }
31}
32
33#[async_trait]
34impl Scheme for Basic {
35 fn header_name() -> http_types::headers::HeaderName {
36 http_types::headers::AUTHORIZATION
37 }
38
39 async fn parse(
40 &self,
41 header_value: &http_types::headers::HeaderValue,
42 ) -> crate::Result<crate::traits::AuthValue> {
43 let basic = if let Some(ref basic) = self.basic {
44 basic.to_string()
45 } else {
46 "Basic".to_string()
47 };
48
49 if header_value.as_str().len() < basic.len() + 2 {
50 return Err(Error::Invalid);
51 }
52
53 let mut parts = header_value.as_str().splitn(2, ' ');
54
55 match parts.next() {
56 Some(scheme) if scheme == basic => {}
57 _ => return Err(Error::MissingScheme),
58 }
59 let inner_str = parts.next().ok_or(Error::Invalid)?;
60 let decode = base64::decode(inner_str)?;
61 let mut inner = str::from_utf8(&decode)?.splitn(2, ':');
62
63 let username = match inner.next() {
64 Some(username) => username,
65 _ => return Err(Error::MissingField("username")),
66 }
67 .to_string();
68 let password = match inner.next() {
69 Some(password) => password,
70 _ => return Err(Error::MissingField("password")),
71 }
72 .to_string();
73
74 Ok(AuthValue::Basic(User { username, password }))
75 }
76}