diff --git a/src/main.rs b/src/main.rs index a2b1ce2..fc2c1f6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,9 @@ mod ipc; mod log; mod storage; +use std::fs; +use std::path::PathBuf; + use clap::Parser; use sha2::{Digest, Sha256}; use zeroize::Zeroize; @@ -18,7 +21,7 @@ use storage::get_backend; #[command(about = "Bitwarden desktop bridge agent")] struct Args { #[arg(long)] - email: String, + email: Option, #[arg(long)] password: Option, @@ -39,6 +42,27 @@ struct Args { remove: bool, } +fn config_dir() -> PathBuf { + let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".into()); + PathBuf::from(home).join(".cache").join("com.bitwarden.desktop") +} + +fn config_path() -> PathBuf { + config_dir().join("agent.conf") +} + +fn save_email(email: &str) { + fs::create_dir_all(config_dir()).ok(); + fs::write(config_path(), email).ok(); +} + +fn load_email() -> Option { + fs::read_to_string(config_path()) + .ok() + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()) +} + fn user_hash(email: &str) -> String { let mut hasher = Sha256::new(); hasher.update(email.to_lowercase().trim().as_bytes()); @@ -48,7 +72,14 @@ fn user_hash(email: &str) -> String { fn main() { let args = Args::parse(); - let uid = user_hash(&args.email); + + let email = args + .email + .clone() + .or_else(load_email) + .unwrap_or_else(|| log::fatal("no email provided (use --email on first run)")); + + let uid = user_hash(&email); let store = get_backend(args.backend.as_deref()); let prompt = get_prompter(args.askpass.as_deref()); log::info(&format!("backend: {}", store.name())); @@ -56,9 +87,9 @@ fn main() { if args.remove { if store.has_key(&uid) { store.remove(&uid); - log::info(&format!("key removed for {}", args.email)); + log::info(&format!("key removed for {email}")); } else { - log::info(&format!("no key found for {}", args.email)); + log::info(&format!("no key found for {email}")); } return; } @@ -76,8 +107,8 @@ fn main() { .or_else(|| prompt("master password:")) .unwrap_or_else(|| log::fatal("no password provided")); - log::info(&format!("logging in as {}", args.email)); - let (mut key_bytes, server_uid) = auth::login(&args.email, &pw, &args.server, &prompt); + log::info(&format!("logging in as {email}")); + let (mut key_bytes, server_uid) = auth::login(&email, &pw, &args.server, &prompt); log::info(&format!("authenticated, uid={server_uid}")); let auth = prompt(&format!("choose {} password:", store.name())) @@ -92,10 +123,11 @@ fn main() { .store(&uid, &key_bytes, &auth) .unwrap_or_else(|e| log::fatal(&format!("store failed: {e}"))); key_bytes.zeroize(); + save_email(&email); log::info(&format!("key sealed via {}", store.name())); log::info("wiped key from memory"); } else { - log::info(&format!("key ready for {}", args.email)); + log::info(&format!("key ready for {email}")); } let mut bridge = BiometricBridge::new(store, uid, prompt);