aboutsummaryrefslogtreecommitdiffstats
path: root/src/bin/rbw/commands.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/rbw/commands.rs')
-rw-r--r--src/bin/rbw/commands.rs224
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);
}