nsg_cli/commands/
login.rs1use crate::client::NsgClient;
2use crate::config::Credentials;
3use anyhow::Result;
4use clap::Args;
5use colored::Colorize;
6use std::io::{self, Write};
7
8#[derive(Debug, Args)]
9pub struct LoginCommand {
10 #[arg(short, long, help = "NSG username")]
11 username: Option<String>,
12
13 #[arg(short, long, help = "NSG password")]
14 password: Option<String>,
15
16 #[arg(short, long, help = "NSG application key")]
17 app_key: Option<String>,
18
19 #[arg(long, help = "Skip connection test")]
20 no_verify: bool,
21}
22
23impl LoginCommand {
24 pub fn execute(self) -> Result<()> {
25 println!("{}", "NSG Login".bold().cyan());
26 println!("{}", "=".repeat(60).cyan());
27 println!();
28
29 let username = self.get_or_prompt_username()?;
30 let password = self.get_or_prompt_password()?;
31 let app_key = self.get_or_prompt_app_key()?;
32
33 println!();
34 println!("{} Saving credentials...", "→".cyan());
35
36 let credentials = Credentials::new(username, password, app_key);
37
38 if !self.no_verify {
39 println!("{} Testing connection to NSG...", "→".cyan());
40 let client = NsgClient::new(credentials.clone())?;
41
42 match client.test_connection() {
43 Ok(_) => {
44 println!("{} Connection successful!", "✓".green().bold());
45 }
46 Err(e) => {
47 eprintln!();
48 eprintln!("{} {}", "✗".red().bold(), "Authentication failed!".red());
49 eprintln!();
50 eprintln!("Error: {}", e);
51 eprintln!();
52 eprintln!("Please check your credentials:");
53 eprintln!(" 1. Username and password are correct");
54 eprintln!(" 2. Application key is valid");
55 eprintln!(" 3. Your NSG account is active");
56 eprintln!();
57 eprintln!(
58 "Get credentials at: {}",
59 "https://www.nsgportal.org/".cyan()
60 );
61 anyhow::bail!("Login failed");
62 }
63 }
64 }
65
66 credentials.save()?;
67
68 println!();
69 println!("{}", "=".repeat(60).green());
70 println!(
71 "{} {}",
72 "✓".green().bold(),
73 "Login successful!".green().bold()
74 );
75 println!("{}", "=".repeat(60).green());
76 println!();
77 println!(
78 "Credentials saved to: {}",
79 Credentials::credentials_location().cyan()
80 );
81 println!();
82 println!("You can now use:");
83 println!(" {} - List your NSG jobs", "nsg list".cyan());
84 println!(" {} - Check job status", "nsg status <job_id>".cyan());
85 println!(
86 " {} - Submit a new job",
87 "nsg submit <zip_file> --tool <tool>".cyan()
88 );
89 println!(
90 " {} - Download job results",
91 "nsg download <job_id>".cyan()
92 );
93 println!();
94
95 Ok(())
96 }
97
98 fn get_or_prompt_username(&self) -> Result<String> {
99 if let Some(username) = &self.username {
100 return Ok(username.clone());
101 }
102
103 print!("NSG Username: ");
104 io::stdout().flush()?;
105
106 let mut input = String::new();
107 io::stdin().read_line(&mut input)?;
108 let username = input.trim().to_string();
109
110 if username.is_empty() {
111 anyhow::bail!("Username cannot be empty");
112 }
113
114 Ok(username)
115 }
116
117 fn get_or_prompt_password(&self) -> Result<String> {
118 if let Some(password) = &self.password {
119 return Ok(password.clone());
120 }
121
122 print!("NSG Password: ");
123 io::stdout().flush()?;
124 let password = rpassword::read_password()?;
125
126 if password.is_empty() {
127 anyhow::bail!("Password cannot be empty");
128 }
129
130 Ok(password)
131 }
132
133 fn get_or_prompt_app_key(&self) -> Result<String> {
134 if let Some(app_key) = &self.app_key {
135 return Ok(app_key.clone());
136 }
137
138 print!("NSG Application Key: ");
139 io::stdout().flush()?;
140
141 let mut input = String::new();
142 io::stdin().read_line(&mut input)?;
143 let app_key = input.trim().to_string();
144
145 if app_key.is_empty() {
146 anyhow::bail!("Application key cannot be empty");
147 }
148
149 Ok(app_key)
150 }
151}