carp_cli/auth/
manager.rs

1use crate::api::ApiClient;
2use crate::config::{Config, ConfigManager};
3use crate::utils::error::{CarpError, CarpResult};
4use colored::*;
5use std::io::{self, Write};
6
7/// Authentication manager for handling login/logout
8pub struct AuthManager;
9
10impl AuthManager {
11    /// Prompt user for credentials and authenticate
12    pub async fn login() -> CarpResult<()> {
13        let config = ConfigManager::load()?;
14        let client = ApiClient::new(&config)?;
15
16        println!("{}", "Login to Carp Registry".bold().green());
17        println!("Enter your credentials:");
18
19        print!("Username: ");
20        io::stdout().flush()?;
21        let mut username = String::new();
22        io::stdin().read_line(&mut username)?;
23        let username = username.trim();
24
25        let password = rpassword::prompt_password("Password: ")?;
26
27        println!("Authenticating...");
28
29        match client.authenticate(username, &password).await {
30            Ok(auth_response) => {
31                ConfigManager::set_api_token(auth_response.token)?;
32                println!("{}", "Successfully logged in!".green().bold());
33                println!("Token expires: {}", auth_response.expires_at.format("%Y-%m-%d %H:%M:%S UTC"));
34                Ok(())
35            }
36            Err(e) => {
37                println!("{} {}", "Login failed:".red().bold(), e);
38                Err(e)
39            }
40        }
41    }
42
43    /// Logout by clearing the stored API token
44    pub async fn logout() -> CarpResult<()> {
45        ConfigManager::clear_api_token()?;
46        println!("{}", "Successfully logged out!".green().bold());
47        Ok(())
48    }
49
50    /// Check if user is currently authenticated
51    pub async fn check_auth() -> CarpResult<bool> {
52        let config = ConfigManager::load()?;
53        Ok(config.api_token.is_some())
54    }
55
56    /// Get current authentication status
57    pub async fn status() -> CarpResult<()> {
58        if Self::check_auth().await? {
59            println!("{}", "Authenticated".green().bold());
60            
61            let config = ConfigManager::load()?;
62            println!("Registry: {}", config.registry_url);
63            
64            // Try to validate token by making a test request
65            let client = ApiClient::new(&config)?;
66            match client.search("", Some(1), false).await {
67                Ok(_) => println!("Token: {}", "Valid".green()),
68                Err(_) => {
69                    println!("Token: {}", "Invalid or expired".red());
70                    println!("Run 'carp login' to authenticate again.");
71                }
72            }
73        } else {
74            println!("{}", "Not authenticated".red().bold());
75            println!("Run 'carp login' to authenticate.");
76        }
77        Ok(())
78    }
79
80    /// Ensure user is authenticated, prompt to login if not
81    pub async fn ensure_authenticated() -> CarpResult<()> {
82        if !Self::check_auth().await? {
83            println!("{}", "Authentication required.".yellow().bold());
84            Self::login().await
85        } else {
86            Ok(())
87        }
88    }
89}