1use crate::config::ConfigManager;
2use crate::utils::error::{CarpError, CarpResult};
3use colored::*;
4
5pub struct AuthManager;
7
8impl AuthManager {
9 pub async fn login() -> CarpResult<()> {
11 println!("{}", "Login to Carp Registry".bold().green());
12 println!("Enter your API key (input will be hidden):");
13
14 let api_key = rpassword::prompt_password("API Key: ")?;
15
16 if api_key.trim().is_empty() {
17 return Err(CarpError::Auth("API key cannot be empty".to_string()));
18 }
19
20 println!("Validating API key...");
21
22 ConfigManager::set_api_key_secure(api_key)?;
24
25 println!("{}", "API key saved successfully!".green().bold());
26 println!("You can now use authenticated commands.");
27 Ok(())
28 }
29
30 #[deprecated(note = "Use login instead. Username/password authentication is deprecated.")]
32 #[allow(dead_code)]
33 pub async fn deprecated_login() -> CarpResult<()> {
34 println!(
35 "{}",
36 "Username/password login is deprecated.".yellow().bold()
37 );
38 println!("Please use API key authentication instead:");
39 println!(" Run: carp auth login");
40 println!(" Or: set CARP_API_KEY environment variable");
41 println!(" Or: use --api-key command line option");
42
43 Err(CarpError::Auth(
44 "Please use API key authentication instead of username/password".to_string(),
45 ))
46 }
47
48 pub async fn logout() -> CarpResult<()> {
50 ConfigManager::clear_api_key()?;
51 println!("{}", "Successfully logged out!".green().bold());
52 println!("API key has been removed from configuration.");
53 Ok(())
54 }
55
56 pub async fn check_auth() -> CarpResult<bool> {
58 let config = ConfigManager::load()?;
59 Ok(config.api_key.is_some())
60 }
61
62 pub async fn check_auth_with_key(api_key: Option<&str>) -> CarpResult<bool> {
64 if api_key.is_some() {
65 return Ok(true);
66 }
67 Self::check_auth().await
68 }
69
70 #[allow(dead_code)]
72 pub async fn status() -> CarpResult<()> {
73 Self::status_with_key(None).await
74 }
75
76 pub async fn status_with_key(runtime_api_key: Option<&str>) -> CarpResult<()> {
78 let config = ConfigManager::load()?;
79
80 let api_key = runtime_api_key.or(config.api_key.as_deref());
82
83 if api_key.is_some() {
84 println!("{}", "Authenticated".green().bold());
85 println!("Registry: {}", config.registry_url);
86
87 if let Some(key) = api_key {
88 let masked_key = if key.len() > 8 {
90 format!("{}...{}", &key[..4], &key[key.len() - 4..])
91 } else {
92 "****".to_string()
93 };
94
95 let source = if runtime_api_key.is_some() {
96 "command line/environment"
97 } else {
98 "config file"
99 };
100 println!("API Key: {masked_key} (masked, from {source})");
101 }
102
103 println!("Status: {}", "Ready to use authenticated commands".green());
104 } else {
105 println!("{}", "Not authenticated".red().bold());
106 println!("Authenticate using one of these methods:");
107 println!(" 1. Run: carp auth login");
108 println!(" 2. Set CARP_API_KEY environment variable");
109 println!(" 3. Use --api-key command line option");
110 }
111 Ok(())
112 }
113
114 pub async fn ensure_authenticated(api_key: Option<&str>) -> CarpResult<()> {
116 if !Self::check_auth_with_key(api_key).await? {
117 println!("{}", "Authentication required.".yellow().bold());
118 println!("You can authenticate by:");
119 println!(" 1. Setting CARP_API_KEY environment variable");
120 println!(" 2. Using --api-key command line option");
121 println!(" 3. Running 'carp auth login' to store API key in config");
122 return Err(CarpError::Auth(
123 "No API key configured. Please set your API key via command line, environment variable, or config file.".to_string(),
124 ));
125 }
126 Ok(())
127 }
128}