use crate::errors::{ConfigError, VetisError};
use futures_util::future::BoxFuture;
use http::HeaderMap;
use serde::Deserialize;
use std::{collections::HashMap, path::Path};
#[derive(Clone, Debug, Deserialize, PartialEq)]
pub enum Algorithm {
BCrypt,
Argon2,
}
pub trait Auth {
fn authenticate(&self, headers: &HeaderMap) -> BoxFuture<'_, Result<bool, VetisError>>;
}
pub struct BasicAuthConfigBuilder {
users: HashMap<String, String>,
algorithm: Algorithm,
htpasswd: Option<String>,
}
impl BasicAuthConfigBuilder {
pub fn users(mut self, users: HashMap<String, String>) -> Self {
self.users = users;
self
}
pub fn algorithm(mut self, algorithm: Algorithm) -> Self {
self.algorithm = algorithm;
self
}
pub fn htpasswd(mut self, htpasswd: &str) -> Self {
self.htpasswd = Some(htpasswd.to_owned());
self
}
pub fn cache_users(mut self) -> Self {
if self
.htpasswd
.is_none()
{
return self;
}
if let Some(htpasswd) = &self.htpasswd {
let htpasswd = Path::new(htpasswd);
if !htpasswd.exists() {
return self;
}
let htpasswd = std::fs::read_to_string(htpasswd);
match htpasswd {
Ok(file) => {
file.lines()
.for_each(|line| {
let credentials = line.split_once(':');
if let Some(credentials) = credentials {
self.users.insert(
credentials
.0
.to_string(),
credentials
.1
.to_string(),
);
}
});
}
Err(e) => {
log::error!("Failed to read htpasswd file: {}", e);
}
}
}
self
}
pub fn build(self) -> Result<BasicAuthConfig, VetisError> {
if let Some(htpasswd) = &self.htpasswd {
let htpasswd = Path::new(htpasswd);
if !htpasswd.exists() {
return Err(VetisError::Config(ConfigError::Auth(
".htpasswd file not found".to_string(),
)));
}
}
Ok(BasicAuthConfig {
users: self.users,
algorithm: self.algorithm,
htpasswd: self.htpasswd,
})
}
}
#[cfg(feature = "auth")]
#[derive(Clone, Deserialize)]
pub struct BasicAuthConfig {
users: HashMap<String, String>,
algorithm: Algorithm,
htpasswd: Option<String>,
}
#[cfg(feature = "auth")]
impl BasicAuthConfig {
pub fn builder() -> BasicAuthConfigBuilder {
BasicAuthConfigBuilder {
users: HashMap::new(),
algorithm: Algorithm::BCrypt,
htpasswd: None,
}
}
pub fn users(&self) -> &HashMap<String, String> {
&self.users
}
pub fn algorithm(&self) -> &Algorithm {
&self.algorithm
}
pub fn htpasswd(&self) -> &Option<String> {
&self.htpasswd
}
}