Skip to main content

htb_cli/cli/
auth.rs

1use std::sync::Arc;
2
3use clap::Subcommand;
4
5use crate::api::HtbClient;
6use crate::cache::Cache;
7use crate::output::OutputFormat;
8
9#[derive(Subcommand)]
10pub enum AuthCommand {
11    /// Save your HTB API token
12    Login,
13    /// Show current authentication status
14    Status,
15    /// Remove stored token
16    Logout,
17}
18
19pub async fn handle(
20    cmd: AuthCommand,
21    format: OutputFormat,
22    cache: &Arc<Cache>,
23) -> anyhow::Result<()> {
24    match cmd {
25        AuthCommand::Login => login(cache).await,
26        AuthCommand::Status => status(format).await,
27        AuthCommand::Logout => logout(cache),
28    }
29}
30
31async fn login(cache: &Cache) -> anyhow::Result<()> {
32    println!("Enter your HTB API token (from https://app.hackthebox.com/account-settings):");
33    let token = rpassword::read_password()?;
34    let token = token.trim().to_string();
35
36    if token.is_empty() {
37        anyhow::bail!("Token cannot be empty");
38    }
39
40    let client = HtbClient::new(token.clone());
41    let user = client.user().current().await?;
42
43    crate::config::save_token(&token)?;
44    cache.clear();
45    println!(
46        "Authenticated as {} ({})",
47        user.name,
48        if user.is_vip { "VIP" } else { "Free" }
49    );
50    Ok(())
51}
52
53async fn status(format: OutputFormat) -> anyhow::Result<()> {
54    let token = crate::config::read_token()?;
55    let client = HtbClient::new(token);
56    let user = client.user().current().await?;
57
58    let fields = vec![
59        ("Username", user.name.clone()),
60        ("ID", user.id.to_string()),
61        (
62            "Subscription",
63            user.subscription_type
64                .clone()
65                .unwrap_or_else(|| "Free".into()),
66        ),
67        ("VIP", if user.is_vip { "Yes" } else { "No" }.into()),
68        ("Verified", if user.verified { "Yes" } else { "No" }.into()),
69    ];
70
71    crate::output::print_detail(&user, format, &fields);
72    Ok(())
73}
74
75fn logout(cache: &Cache) -> anyhow::Result<()> {
76    crate::config::remove_token()?;
77    cache.clear();
78    println!("Token removed.");
79    Ok(())
80}