diff options
Diffstat (limited to 'src/bin/rbw/commands.rs')
-rw-r--r-- | src/bin/rbw/commands.rs | 224 |
1 files changed, 223 insertions, 1 deletions
diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs index 0068efd..fd720cf 100644 --- a/src/bin/rbw/commands.rs +++ b/src/bin/rbw/commands.rs @@ -1,4 +1,6 @@ use anyhow::Context as _; +use std::io; +use std::io::prelude::Write; const MISSING_CONFIG_HELP: &str = "Before using rbw, you must configure the email address you would like to \ @@ -84,6 +86,215 @@ impl DecryptedCipher { } } + fn display_field(&self, desc: &str, field: &str) { + // Convert the field name to lowercase + let field = field.to_lowercase(); + let field = field.as_str(); + match &self.data { + DecryptedData::Login { + username, + totp, + uris, + .. + } => match field { + "notes" => { + if let Some(notes) = &self.notes { + println!("{}", notes); + } + } + "username" | "user" => { + display_field("Username", username.as_deref()); + } + "totp" | "code" => { + if let Some(totp) = totp { + if let Ok(code) = generate_totp(&totp) { + println!("{}", code); + } + } + } + "uris" | "urls" | "sites" => { + if let Some(uris) = uris { + for uri in uris { + display_field("URI", Some(uri.uri.as_str())); + } + } + } + "password" => { + self.display_short(&desc); + } + _ => { + for f in &self.fields { + if f.name + .as_ref() + .unwrap() + .to_lowercase() + .as_str() + .contains(field) + { + display_field( + f.name.as_deref().unwrap_or("(null)"), + Some(f.value.as_deref().unwrap_or("")), + ); + } + } + } + }, + DecryptedData::Card { + cardholder_name, + brand, + exp_month, + exp_year, + code, + .. + } => match field { + "number" | "card" => { + self.display_short(&desc); + } + "exp" => { + if let (Some(month), Some(year)) = (exp_month, exp_year) { + display_field( + "Exp", + Some(format!("{}/{}", month, year).as_str()), + ); + } + } + "exp_month" | "month" => { + display_field("Month", exp_month.as_deref()); + } + "exp_year" | "year" => { + display_field("Year", exp_year.as_deref()); + } + "cvv" => { + display_field("CVV", code.as_deref()); + } + "name" | "cardholder" => { + display_field("Name", cardholder_name.as_deref()); + } + "brand" | "type" => { + display_field("Brand", brand.as_deref()); + } + "notes" => { + if let Some(notes) = &self.notes { + println!("{}", notes); + } + } + _ => { + for f in &self.fields { + if f.name + .as_ref() + .unwrap() + .to_lowercase() + .as_str() + .contains(field) + { + display_field( + f.name.as_deref().unwrap_or("(null)"), + Some(f.value.as_deref().unwrap_or("")), + ); + } + } + } + }, + DecryptedData::Identity { + address1, + address2, + address3, + city, + state, + postal_code, + country, + phone, + email, + ssn, + license_number, + passport_number, + username, + .. + } => match field { + "name" => { + self.display_short(&desc); + } + "email" => { + display_field("Email", email.as_deref()); + } + "address" => { + display_field("Address", address1.as_deref()); + display_field("Address", address2.as_deref()); + display_field("Address", address3.as_deref()); + } + "city" => { + display_field("City", city.as_deref()); + } + "state" => { + display_field("State", state.as_deref()); + } + "postcode" | "zipcode" | "zip" => { + display_field("Zip", postal_code.as_deref()); + } + "country" => { + display_field("Country", country.as_deref()); + } + "phone" => { + display_field("Phone", phone.as_deref()); + } + "ssn" => { + display_field("SSN", ssn.as_deref()); + } + "license" => { + display_field("License", license_number.as_deref()); + } + "passport" => { + display_field("Passport", passport_number.as_deref()); + } + "username" => { + display_field("Username", username.as_deref()); + } + "notes" => { + if let Some(notes) = &self.notes { + println!("{}", notes); + } + } + _ => { + for f in &self.fields { + if f.name + .as_ref() + .unwrap() + .to_lowercase() + .as_str() + .contains(field) + { + display_field( + f.name.as_deref().unwrap_or("(null)"), + Some(f.value.as_deref().unwrap_or("")), + ); + } + } + } + }, + DecryptedData::SecureNote {} => match field { + "note" | "notes" => { + self.display_short(desc); + } + _ => { + for f in &self.fields { + if f.name + .as_ref() + .unwrap() + .to_lowercase() + .as_str() + .contains(field) + { + display_field( + f.name.as_deref().unwrap_or("(null)"), + Some(f.value.as_deref().unwrap_or("")), + ); + } + } + } + }, + } + } + fn display_long(&self, desc: &str) { match &self.data { DecryptedData::Login { @@ -405,6 +616,7 @@ pub fn config_set(key: &str, value: &str) -> anyhow::Result<()> { "email" => config.email = Some(value.to_string()), "base_url" => config.base_url = Some(value.to_string()), "identity_url" => config.identity_url = Some(value.to_string()), + "client_cert_path" => config.client_cert_path = Some(value.to_string()), "lock_timeout" => { let timeout = value .parse() @@ -437,6 +649,7 @@ pub fn config_unset(key: &str) -> anyhow::Result<()> { "email" => config.email = None, "base_url" => config.base_url = None, "identity_url" => config.identity_url = None, + "client_cert_path" => config.client_cert_path = None, "lock_timeout" => { config.lock_timeout = rbw::config::default_lock_timeout(); } @@ -530,7 +743,13 @@ pub fn list(fields: &[String]) -> anyhow::Result<()> { ), }) .collect(); - println!("{}", values.join("\t")); + + // write to stdout but don't panic when pipe get's closed + // this happens when piping stdout in a shell + match writeln!(&mut io::stdout(), "{}", values.join("\t")) { + Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => Ok(()), + res => res, + }?; } Ok(()) @@ -540,6 +759,7 @@ pub fn get( name: &str, user: Option<&str>, folder: Option<&str>, + field: Option<&str>, full: bool, ) -> anyhow::Result<()> { unlock()?; @@ -556,6 +776,8 @@ pub fn get( .with_context(|| format!("couldn't find entry for '{}'", desc))?; if full { decrypted.display_long(&desc); + } else if field != None { + decrypted.display_field(&desc, field.unwrap()); } else { decrypted.display_short(&desc); } |