diff --git a/Cargo.toml b/Cargo.toml index 8100f0a..0aa9390 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +arboard = "3.6.1" argon2 = { version = "0.5.3", features = ["std", "password-hash"] } chacha20poly1305 = "0.10.1" clap = { version = "4.5", features = ["derive"] } diff --git a/src/args.rs b/src/args.rs index ed76a82..16f2db0 100644 --- a/src/args.rs +++ b/src/args.rs @@ -18,6 +18,9 @@ pub enum Commands { Delete(DeletePass), /// Lists the names of all created passwords List, + /// Internal use only: clears clipboard after delay + #[command(hide = true)] + CleanupClipboard { delay: u64 }, } #[derive(Args)] @@ -30,6 +33,9 @@ pub struct AddPass { pub struct GetPass { /// The name of the password to get pub name: String, + /// Copy the password to the clipboard instead of printing it + #[arg(short, long)] + pub copy: bool, } #[derive(Args)] diff --git a/src/main.rs b/src/main.rs index 6c4cc1d..e0558de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,15 @@ use zeroize::Zeroize; fn main() { let cli: Cli = Cli::parse(); + + if let Commands::CleanupClipboard { delay } = cli.command { + std::thread::sleep(std::time::Duration::from_secs(delay)); + if let Ok(mut cb) = arboard::Clipboard::new() { + let _ = cb.set_text(""); + } + return; + } + let master_hash_path = "master.hash"; let file_path = "passwords.enc"; let salt_path = "salt.bin"; @@ -73,7 +82,34 @@ fn main() { p2.zeroize(); } Commands::Get(args) => match passwords.get(&args.name) { - Some(pw) => println!("Password for {} : {}", args.name, pw), + Some(pw) => { + if args.copy { + match arboard::Clipboard::new() { + Ok(mut clipboard) => { + let mut temp_pw = pw.clone(); + if clipboard.set_text(&temp_pw).is_ok() { + println!("Password for '{}' copied to clipboard!", args.name); + println!("Clipboard will be cleared in 15 seconds..."); + temp_pw.zeroize(); + + let exe_path = + std::env::current_exe().expect("Failed to get exe path"); + std::process::Command::new(exe_path) + .arg("cleanup-clipboard") + .arg("15") + .spawn() + .expect("Failed to start background cleanup"); + } else { + temp_pw.zeroize(); + println!("❌ Failed to copy to clipboard."); + } + } + Err(_) => println!("❌ Failed to access clipboard."), + } + } else { + println!("Password for {} : {}", args.name, pw); + } + } None => println!("No password found for '{}'", args.name), }, Commands::Delete(args) => { @@ -90,6 +126,7 @@ fn main() { println!("-----------------------"); } } + Commands::CleanupClipboard { .. } => {} } encryption_key.zeroize();