From bc543e4f26d3e29fe88a61457a924ab6ab238535 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sun, 19 Apr 2020 21:23:08 -0400 Subject: allow listing various different fields --- src/bin/rbw/commands.rs | 41 +++++++++++++++++++++++++++++++++++++++-- src/bin/rbw/main.rs | 18 ++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs index 2385163..ff267eb 100644 --- a/src/bin/rbw/commands.rs +++ b/src/bin/rbw/commands.rs @@ -18,6 +18,25 @@ struct DecryptedHistoryEntry { password: String, } +enum ListField { + Name, + Id, + User, +} + +impl std::convert::TryFrom<&str> for ListField { + type Error = anyhow::Error; + + fn try_from(s: &str) -> anyhow::Result { + Ok(match s { + "name" => Self::Name, + "id" => Self::Id, + "user" => Self::User, + _ => return Err(anyhow::anyhow!("unknown field {}", s)), + }) + } +} + const HELP: &str = r#" # The first line of this file will be the password, and the remainder of the # file (after any blank lines after the password) will be stored as a note. @@ -76,7 +95,13 @@ pub fn sync() -> anyhow::Result<()> { Ok(()) } -pub fn list() -> anyhow::Result<()> { +pub fn list(fields: &[&str]) -> anyhow::Result<()> { + let fields: Vec = fields + .iter() + .copied() + .map(std::convert::TryFrom::try_from) + .collect::>()?; + unlock()?; let email = config_email()?; @@ -92,7 +117,19 @@ pub fn list() -> anyhow::Result<()> { ciphers.sort_unstable_by(|a, b| a.name.cmp(&b.name)); for cipher in ciphers { - println!("{}", cipher.name); + let values: Vec = fields + .iter() + .map(|field| match field { + ListField::Name => cipher.name.clone(), + ListField::Id => cipher.id.clone(), + ListField::User => cipher + .username + .as_ref() + .map(std::string::ToString::to_string) + .unwrap_or_else(|| "".to_string()), + }) + .collect(); + println!("{}", values.join("\t")); } Ok(()) diff --git a/src/bin/rbw/main.rs b/src/bin/rbw/main.rs index 051a7bc..c95e319 100644 --- a/src/bin/rbw/main.rs +++ b/src/bin/rbw/main.rs @@ -26,7 +26,15 @@ fn main() { .subcommand(clap::SubCommand::with_name("login")) .subcommand(clap::SubCommand::with_name("unlock")) .subcommand(clap::SubCommand::with_name("sync")) - .subcommand(clap::SubCommand::with_name("list")) + .subcommand( + clap::SubCommand::with_name("list").arg( + clap::Arg::with_name("fields") + .long("fields") + .takes_value(true) + .use_delimiter(true) + .multiple(true), + ), + ) .subcommand( clap::SubCommand::with_name("get") .arg(clap::Arg::with_name("name").required(true)) @@ -115,7 +123,13 @@ fn main() { ("login", Some(_)) => commands::login().context("login"), ("unlock", Some(_)) => commands::unlock().context("unlock"), ("sync", Some(_)) => commands::sync().context("sync"), - ("list", Some(_)) => commands::list().context("list"), + ("list", Some(smatches)) => commands::list( + &smatches + .values_of("fields") + .map(|it| it.collect()) + .unwrap_or_else(|| vec!["name"]), + ) + .context("list"), // this unwrap is safe because name is marked .required(true) ("get", Some(smatches)) => commands::get( smatches.value_of("name").unwrap(), -- cgit v1.2.3-54-g00ecf