use std::{borrow::Cow, str};
use crate::{
traits::{AuthValue, Scheme, User},
Error,
};
use async_trait::async_trait;
pub struct Basic {
basic: Option<Cow<'static, str>>,
}
unsafe impl Send for Basic {}
unsafe impl Sync for Basic {}
impl Default for Basic {
fn default() -> Self {
Basic { basic: None }
}
}
impl Basic {
pub fn new<T: Into<String>>(basic: T) -> Self {
let basic: String = basic.into();
Basic {
basic: Some(basic.into()),
}
}
}
#[async_trait]
impl Scheme for Basic {
fn header_name() -> http_types::headers::HeaderName {
http_types::headers::AUTHORIZATION
}
async fn parse(
&self,
header_value: &http_types::headers::HeaderValue,
) -> crate::Result<crate::traits::AuthValue> {
let basic = if let Some(ref basic) = self.basic {
basic.to_string()
} else {
"Basic".to_string()
};
if header_value.as_str().len() < basic.len() + 2 {
return Err(Error::Invalid);
}
let mut parts = header_value.as_str().splitn(2, ' ');
match parts.next() {
Some(scheme) if scheme == basic => {}
_ => return Err(Error::MissingScheme),
}
let inner_str = parts.next().ok_or(Error::Invalid)?;
let decode = base64::decode(inner_str)?;
let mut inner = str::from_utf8(&decode)?.splitn(2, ':');
let username = match inner.next() {
Some(username) => username,
_ => return Err(Error::MissingField("username")),
}
.to_string();
let password = match inner.next() {
Some(password) => password,
_ => return Err(Error::MissingField("password")),
}
.to_string();
Ok(AuthValue::Basic(User { username, password }))
}
}