zero4rs 2.0.0

zero4rs is a powerful, pragmatic, and extremely fast web framework for Rust
Documentation
use crate::prelude2::*;

use sqlx::MySql;
use sqlx::Pool;

use actix_web::http::header::HeaderMap;

// use secrecy::ExposeSecret;
// use secrecy::Secret;

use crate::commons;
use commons::verify_password;

use crate::services::user_service::get_stored_credentials;

use super::UserId;

pub struct Credentials {
    pub username: String,
    pub password: String,
}

impl Credentials {
    pub fn password(&self) -> String {
        self.password.to_string()
    }
}

pub fn basic_auth0(headers: &HeaderMap) -> Result<Credentials> {
    // The header value, if present, must be a valid UTF8 string
    let header_value = headers
        .get("Authorization")
        .ok_or_else(|| Error::invalid_request("The 'Authorization' header was missing."))?
        .to_str()
        .map_err(|_| {
            Error::invalid_request("The 'Authorization' header was not a valid UTF8 string.")
        })?;

    let base64encoded_segment = header_value
        .strip_prefix("Basic ")
        .ok_or_else(|| Error::invalid_request("The authorization scheme was not 'Basic'."))?;

    let decoded_credentials = commons::base64decode(base64encoded_segment)
        .map_err(|_| Error::invalid_request("Failed to base64-decode 'Basic' credentials."))?;

    // Split into two segments, using ':' as delimiter
    let mut credentials = decoded_credentials.splitn(2, ':');

    let username = credentials
        .next()
        .ok_or_else(|| Error::invalid_request("A username must be provided in 'Basic' auth."))?
        .to_string();

    let password = credentials
        .next()
        .ok_or_else(|| Error::invalid_request("A password must be provided in 'Basic' auth."))?
        .to_string();

    Ok(Credentials { username, password })
}

pub async fn validate_credentials(credentials: &Credentials, pool: &Pool<MySql>) -> Option<UserId> {
    let mut user_id = None;
    let mut expected_password_hash: String = "".to_string();

    match get_stored_credentials(&credentials.username, pool).await {
        Ok(credentials) => {
            if let Some((stored_user_id, stored_password_hash, _resource_id)) = credentials {
                user_id = Some(stored_user_id);
                expected_password_hash = stored_password_hash.clone().unwrap().to_string();
            }
        }
        Err(e) => {
            log::error!("validate_credentials-failed: error={:?}", e);
        }
    };

    if let Some(user_id) = user_id {
        let verifyed =
            verify_password(credentials.password(), expected_password_hash).unwrap_or(false);

        if verifyed {
            return Some(UserId(user_id));
        }
    }

    None
}