mod list;
mod login;
mod logout;
use crate::config::AppConfig;
use clap::Subcommand;
use stakpak_shared::auth_manager::AuthManager;
use stakpak_shared::models::auth::ProviderAuth;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
#[derive(Subcommand, PartialEq, Debug)]
pub enum AuthCommands {
Login {
#[arg(long, default_value = "stakpak")]
provider: String,
#[arg(long, short)]
profile: Option<String>,
#[arg(long)]
api_key: Option<String>,
#[arg(long)]
endpoint: Option<String>,
#[arg(long)]
region: Option<String>,
#[arg(long)]
profile_name: Option<String>,
#[arg(long)]
access: Option<String>,
#[arg(long, default_value = "")]
refresh: String,
#[arg(long, default_value_t = i64::MAX)]
expiry: i64,
},
Logout {
#[arg(long)]
provider: Option<String>,
#[arg(long, short)]
profile: Option<String>,
},
List {
#[arg(long, short)]
profile: Option<String>,
},
}
impl AuthCommands {
pub async fn run(self, config: AppConfig) -> Result<(), String> {
let config_dir = get_config_dir(&config)?;
match self {
AuthCommands::Login {
provider,
profile,
api_key,
endpoint,
region,
profile_name,
access,
refresh,
expiry,
} => {
login::handle_login(
&config_dir,
&provider,
profile.as_deref(),
api_key,
endpoint,
login::AwsLoginParams {
region,
aws_profile_name: profile_name,
},
login::OAuthTokenParams {
access,
refresh,
expiry,
},
)
.await
}
AuthCommands::Logout { provider, profile } => {
logout::handle_logout(&config_dir, provider.as_deref(), profile.as_deref())
}
AuthCommands::List { profile } => list::handle_list(&config_dir, profile.as_deref()),
}
}
}
#[derive(Clone, Copy, PartialEq)]
pub(super) enum CredentialSource {
ConfigToml,
AuthToml,
}
pub(super) fn collect_all_credentials(
config_dir: &Path,
) -> HashMap<String, HashMap<String, (ProviderAuth, CredentialSource)>> {
let mut all_credentials: HashMap<String, HashMap<String, (ProviderAuth, CredentialSource)>> =
HashMap::new();
let config_path = config_dir.join("config.toml");
if let Ok(config_file) = AppConfig::load_config_file(&config_path) {
for (profile_name, profile_config) in &config_file.profiles {
for (provider_name, provider_config) in &profile_config.providers {
if let Some(auth) = provider_config.get_auth() {
all_credentials
.entry(profile_name.clone())
.or_default()
.insert(provider_name.clone(), (auth, CredentialSource::ConfigToml));
}
}
}
}
if let Ok(auth_manager) = AuthManager::new(config_dir) {
for (profile_name, providers) in auth_manager.list() {
for (provider_name, auth) in providers {
let profile_creds = all_credentials.entry(profile_name.clone()).or_default();
if !profile_creds.contains_key(provider_name.as_str()) {
profile_creds.insert(
provider_name.clone(),
(auth.clone(), CredentialSource::AuthToml),
);
}
}
}
}
all_credentials
}
fn get_config_dir(config: &AppConfig) -> Result<PathBuf, String> {
if !config.config_path.is_empty() {
let path = PathBuf::from(&config.config_path);
if let Some(parent) = path.parent() {
return Ok(parent.to_path_buf());
}
}
dirs::home_dir()
.map(|h| h.join(".stakpak"))
.ok_or_else(|| "Could not determine home directory".to_string())
}