use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AuthError {
#[error("Authentication failed: {0}")]
AuthenticationFailed(String),
#[error("Invalid token")]
InvalidToken,
#[error("Token expired")]
TokenExpired,
#[error("MFA required")]
MfaRequired,
#[error("Invalid MFA code")]
InvalidMfaCode,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Credentials {
pub username: String,
pub password: String,
pub mfa_code: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthResult {
pub success: bool,
pub token: Option<String>,
pub user_id: Option<String>,
pub mfa_required: bool,
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Token {
pub token: String,
pub user_id: String,
pub expires_at: SystemTime,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct User {
pub id: String,
pub username: String,
pub roles: Vec<String>,
pub mfa_enabled: bool,
}
#[derive(Debug)]
pub struct MultiFactorAuth {
secret_key: String,
backup_codes: Vec<String>,
}
impl MultiFactorAuth {
pub fn new() -> Self {
Self {
secret_key: "default-secret-key".to_string(), backup_codes: vec!["123456".to_string(), "789012".to_string()],
}
}
pub async fn verify_code(&self, code: &str) -> Result<bool, AuthError> {
if self.backup_codes.contains(&code.to_string()) {
Ok(true)
} else {
Err(AuthError::InvalidMfaCode)
}
}
}
#[derive(Debug)]
pub struct TokenManager {
tokens: Arc<std::sync::Mutex<HashMap<String, Token>>>,
}
impl TokenManager {
pub fn new() -> Self {
Self {
tokens: Arc::new(Mutex::new(HashMap::new())),
}
}
pub async fn generate_token(&self, user: &User) -> Result<Token, AuthError> {
let token_string: _ = format!(
"amberjs-token-{}-{}",
user.id,
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
);
let expires_at: _ = SystemTime::now() + Duration::from_secs(3600); let token: _ = Token {
token: token_string,
user_id: user.id.clone(),
expires_at,
};
{
let mut tokens = self.tokens.lock().unwrap();
tokens.insert(token.token.clone(), token.clone());
}
Ok(token)
}
pub async fn validate_token(&self, token_str: &str) -> Result<User, AuthError> {
let tokens: _ = self.tokens.lock().unwrap();
if let Some(token) = tokens.get(token_str) {
if token.expires_at > SystemTime::now() {
return Ok(User {
id: token.user_id.clone(),
username: "user".to_string(),
roles: vec!["user".to_string()],
mfa_enabled: true,
});
} else {
return Err(AuthError::TokenExpired);
}
}
Err(AuthError::InvalidToken)
}
pub async fn revoke_token(&self, token_str: &str) -> Result<(), AuthError> {
let mut tokens = self.tokens.lock().unwrap();
tokens.remove(token_str);
Ok(())
}
}
#[derive(Debug)]
pub struct AuthenticationService {
pub mfa_service: Arc<MultiFactorAuth>,
pub token_manager: Arc<TokenManager>,
users: Arc<std::sync::Mutex<HashMap<String, User>>>,
}
impl AuthenticationService {
pub fn new() -> Self {
let mut users = HashMap::new();
users.insert(
"admin".to_string(),
User {
id: "1".to_string(),
username: "admin".to_string(),
roles: vec!["admin".to_string(), "user".to_string()],
mfa_enabled: true,
},
);
Self {
mfa_service: Arc::new(MultiFactorAuth::new()),
token_manager: Arc::new(TokenManager::new()),
users: Arc::new(Mutex::new(users)),
}
}
pub async fn authenticate(&self, credentials: &Credentials) -> Result<AuthResult, AuthError> {
let users: _ = self.users.lock().unwrap();
if let Some(user) = users.get(&credentials.username) {
if credentials.password == "password" || credentials.password == "admin" {
if user.mfa_enabled {
if let Some(mfa_code) = &credentials.mfa_code {
let mfa_valid: _ =
self.mfa_service.verify_code(mfa_code).await.map_err(|_| {
AuthError::AuthenticationFailed("Invalid MFA code".to_string())
})?;
if !mfa_valid {
return Ok(AuthResult {
success: false,
token: None,
user_id: None,
mfa_required: true,
error: Some("Invalid MFA code".to_string()),
});
}
} else {
return Ok(AuthResult {
success: false,
token: None,
user_id: None,
mfa_required: true,
error: Some("MFA code required".to_string()),
});
}
}
let token: _ = self.token_manager.generate_token(user).await?;
return Ok(AuthResult {
success: true,
token: Some(token.token),
user_id: Some(user.id.clone()),
mfa_required: false,
error: None,
});
}
}
Ok(AuthResult {
success: false,
token: None,
user_id: None,
mfa_required: false,
error: Some("Invalid credentials".to_string()),
})
}
pub async fn verify_mfa(&self, username: &str, code: &str) -> Result<AuthResult, AuthError> {
let users: _ = self.users.lock().unwrap();
if let Some(user) = users.get(username) {
let mfa_valid: _ = self
.mfa_service
.verify_code(code)
.await
.map_err(|_| AuthError::AuthenticationFailed("Invalid MFA code".to_string()))?;
if mfa_valid {
let token: _ = self.token_manager.generate_token(user).await?;
return Ok(AuthResult {
success: true,
token: Some(token.token),
user_id: Some(user.id.clone()),
mfa_required: false,
error: None,
});
}
}
Err(AuthError::InvalidMfaCode)
}
}
impl Default for MultiFactorAuth {
fn default() -> Self {
Self::new()
}
}
impl Default for TokenManager {
fn default() -> Self {
Self::new()
}
}
impl Default for AuthenticationService {
fn default() -> Self {
Self::new()
}
}