use crate::config::ConfigManager;
use crate::utils::error::{CarpError, CarpResult};
use colored::*;
pub struct AuthManager;
impl AuthManager {
pub async fn login() -> CarpResult<()> {
println!("{}", "Login to Carp Registry".bold().green());
println!("Enter your API key (input will be hidden):");
let api_key = rpassword::prompt_password("API Key: ")?;
if api_key.trim().is_empty() {
return Err(CarpError::Auth("API key cannot be empty".to_string()));
}
println!("Validating API key...");
ConfigManager::set_api_key_secure(api_key)?;
println!("{}", "API key saved successfully!".green().bold());
println!("You can now use authenticated commands.");
Ok(())
}
#[deprecated(note = "Use login instead. Username/password authentication is deprecated.")]
#[allow(dead_code)]
pub async fn deprecated_login() -> CarpResult<()> {
println!(
"{}",
"Username/password login is deprecated.".yellow().bold()
);
println!("Please use API key authentication instead:");
println!(" Run: carp auth login");
println!(" Or: set CARP_API_KEY environment variable");
println!(" Or: use --api-key command line option");
Err(CarpError::Auth(
"Please use API key authentication instead of username/password".to_string(),
))
}
pub async fn logout() -> CarpResult<()> {
ConfigManager::clear_api_key()?;
println!("{}", "Successfully logged out!".green().bold());
println!("API key has been removed from configuration.");
Ok(())
}
pub async fn check_auth() -> CarpResult<bool> {
let config = ConfigManager::load()?;
Ok(config.api_key.is_some())
}
pub async fn check_auth_with_key(api_key: Option<&str>) -> CarpResult<bool> {
if api_key.is_some() {
return Ok(true);
}
Self::check_auth().await
}
#[allow(dead_code)]
pub async fn status() -> CarpResult<()> {
Self::status_with_key(None).await
}
pub async fn status_with_key(runtime_api_key: Option<&str>) -> CarpResult<()> {
let config = ConfigManager::load()?;
let api_key = runtime_api_key.or(config.api_key.as_deref());
if api_key.is_some() {
println!("{}", "Authenticated".green().bold());
println!("Registry: {}", config.registry_url);
if let Some(key) = api_key {
let masked_key = if key.len() > 8 {
format!("{}...{}", &key[..4], &key[key.len() - 4..])
} else {
"****".to_string()
};
let source = if runtime_api_key.is_some() {
"command line/environment"
} else {
"config file"
};
println!("API Key: {masked_key} (masked, from {source})");
}
println!("Status: {}", "Ready to use authenticated commands".green());
} else {
println!("{}", "Not authenticated".red().bold());
println!("Authenticate using one of these methods:");
println!(" 1. Run: carp auth login");
println!(" 2. Set CARP_API_KEY environment variable");
println!(" 3. Use --api-key command line option");
}
Ok(())
}
pub async fn ensure_authenticated(api_key: Option<&str>) -> CarpResult<()> {
if !Self::check_auth_with_key(api_key).await? {
println!("{}", "Authentication required.".yellow().bold());
println!("You can authenticate by:");
println!(" 1. Setting CARP_API_KEY environment variable");
println!(" 2. Using --api-key command line option");
println!(" 3. Running 'carp auth login' to store API key in config");
return Err(CarpError::Auth(
"No API key configured. Please set your API key via command line, environment variable, or config file.".to_string(),
));
}
Ok(())
}
}