diff --git a/cli/Cargo.lock b/cli/Cargo.lock index a743542..75a0b5e 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -1246,6 +1246,7 @@ dependencies = [ "clap", "passphrasex_common", "reqwest 0.11.18", + "rpassword", "serde", "serde_json", "tokio", @@ -1552,6 +1553,17 @@ dependencies = [ "digest 0.10.6", ] +[[package]] +name = "rpassword" +version = "7.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.48.0", +] + [[package]] name = "rsa" version = "0.9.6" @@ -1572,6 +1584,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rtoolbox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "rust-argon2" version = "2.1.0" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 65bf7e9..f632981 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -14,6 +14,7 @@ app_dirs2 = "2.5.5" clap = { version = "4.2.7", features = ["derive"] } passphrasex_common = { version = "0.2.0", path = "../common" } reqwest = { version = "0.11.18", features = ["json"] } +rpassword = "7.3.1" serde = { version = "1.0.163", features = ["serde_derive"] } serde_json = "1.0.96" tokio = { version = "1.28.1", features = ["macros", "rt-multi-thread"] } diff --git a/cli/src/lib.rs b/cli/src/lib.rs index b9310c8..5e2ecbe 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -7,7 +7,10 @@ use std::string::String; use app_dirs2::AppInfo; -use crate::file::{read_app_data, read_private_key, read_signing_key, write_app_data, write_private_key, write_signing_key}; +use crate::file::{ + read_app_data, read_private_key, read_signing_key, write_app_data, write_private_key, + write_signing_key, +}; use passphrasex_common::crypto::asymmetric::{KeyPair, SeedPhrase}; use passphrasex_common::model::password::Password; @@ -80,7 +83,7 @@ impl App { let key_pair = KeyPair::try_from_private_keys( private_key_enc.as_slice(), signing_key_enc.as_slice(), - device_pass + device_pass, )?; let api = Api::new(key_pair.clone()); diff --git a/cli/src/main.rs b/cli/src/main.rs index dd12983..dfa3e6d 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -22,14 +22,14 @@ enum Commands { /// Create your credentials Register { #[clap(short, long)] - device_pass: String, + device_pass: Option, }, /// Authenticate device using your seed phrase Login { #[clap(short, long)] - seed_phrase: String, + seed_phrase: Option, #[clap(short, long)] - device_pass: String, + device_pass: Option, }, /// Add a new password Add { @@ -38,9 +38,9 @@ enum Commands { #[clap(short, long)] username: String, #[clap(short, long)] - password: String, + password: Option, #[clap(short, long)] - device_pass: String, + device_pass: Option, }, /// Get a password Get { @@ -49,7 +49,7 @@ enum Commands { #[clap(short, long)] username: Option, #[clap(short, long)] - device_pass: String, + device_pass: Option, }, /// Modify a password Edit { @@ -58,9 +58,9 @@ enum Commands { #[clap(short, long)] username: String, #[clap(short, long)] - password: String, + password: Option, #[clap(short, long)] - device_pass: String, + device_pass: Option, }, /// Delete a password Delete { @@ -69,7 +69,7 @@ enum Commands { #[clap(short, long)] username: String, #[clap(short, long)] - device_pass: String, + device_pass: Option, }, /// Generate a random password Generate { @@ -83,17 +83,24 @@ async fn main() -> Result<(), Box> { let args = Args::parse(); match args.command { - Commands::Register { device_pass } => match register(&device_pass).await { - Ok(seed_phrase) => println!( - "Successfully registered!\nYour seed phrase is: \n{}", - seed_phrase.get_phrase() - ), - Err(e) => println!("Failed to create user: {}", e), - }, + Commands::Register { device_pass } => { + match register(&get_or_prompt_device_password(device_pass)).await { + Ok(seed_phrase) => println!( + "Successfully registered!\nYour seed phrase is: \n{}", + seed_phrase.get_phrase() + ), + Err(e) => println!("Failed to create user: {}", e), + } + } Commands::Login { seed_phrase, device_pass, - } => match auth_device(&seed_phrase, &device_pass).await { + } => match auth_device( + &get_or_prompt_seed_phrase(seed_phrase), + &get_or_prompt_device_password(device_pass), + ) + .await + { Ok(_) => println!("Successfully authenticated!"), Err(e) => println!("Failed to authenticate: {}", e), }, @@ -103,9 +110,9 @@ async fn main() -> Result<(), Box> { password, device_pass, } => { - match App::new(&device_pass) + match App::new(&get_or_prompt_device_password(device_pass)) .await? - .add(site, username, password) + .add(site, username, get_or_prompt_password(password)) .await { Ok(_) => println!("Password added successfully"), @@ -116,7 +123,11 @@ async fn main() -> Result<(), Box> { site, username, device_pass, - } => match App::new(&device_pass).await?.get(site, username).await { + } => match App::new(&get_or_prompt_device_password(device_pass)) + .await? + .get(site, username) + .await + { Ok(passwords) => { for credential in passwords { println!( @@ -133,9 +144,9 @@ async fn main() -> Result<(), Box> { password, device_pass, } => { - match App::new(&device_pass) + match App::new(&get_or_prompt_device_password(device_pass)) .await? - .edit(site, username, password) + .edit(site, username, get_or_prompt_password(password)) .await { Ok(_) => println!("Password edited successfully"), @@ -146,7 +157,11 @@ async fn main() -> Result<(), Box> { site, username, device_pass, - } => match App::new(&device_pass).await?.delete(site, username).await { + } => match App::new(&get_or_prompt_device_password(device_pass)) + .await? + .delete(site, username) + .await + { Ok(_) => println!("Password deleted successfully"), Err(e) => println!("Failed to delete password: {}", e), }, @@ -157,3 +172,23 @@ async fn main() -> Result<(), Box> { Ok(()) } + +fn get_or_prompt(password: Option, name: &str) -> String { + if let Some(password) = password { + password + } else { + rpassword::prompt_password(format!("Enter {name}:")).expect("Failed to read password") + } +} + +fn get_or_prompt_device_password(password: Option) -> String { + get_or_prompt(password, "device password") +} + +fn get_or_prompt_seed_phrase(password: Option) -> String { + get_or_prompt(password, "seed phrase") +} + +fn get_or_prompt_password(password: Option) -> String { + get_or_prompt(password, "site password") +}