tide-auth 0.1.0

This is the library for tide parsing the auth field
Documentation
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 }))
    }
}