aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2023-02-18 14:13:42 -0500
committerGitHub <noreply@github.com>2023-02-18 14:13:42 -0500
commitf872957519187cb40e9edff823475d3a980c2d10 (patch)
tree4935d62013db05ca10238bc07cffc669aff2680d
parent68d78e98747a5f69fcfa9094976dc28a290e5e3c (diff)
parent60c9065393c093abf4a23b837655dc9d3be99abd (diff)
downloadrbw-f872957519187cb40e9edff823475d3a980c2d10.tar.gz
rbw-f872957519187cb40e9edff823475d3a980c2d10.zip
Merge pull request #95 from shadowwolf899/master
Added a field flag to the get command
-rw-r--r--README.md3
-rw-r--r--src/bin/rbw/commands.rs212
-rw-r--r--src/bin/rbw/main.rs11
3 files changed, 224 insertions, 2 deletions
diff --git a/README.md b/README.md
index 7a7a794..ac3b4ed 100644
--- a/README.md
+++ b/README.md
@@ -82,7 +82,8 @@ out by running `rbw purge`, and you can explicitly lock the database by running
functionality.
Run `rbw get <name>` to get your passwords. If you also want to get the username
-or the note associated, you can use the flag `--full`.
+or the note associated, you can use the flag `--full`. You can also use the flag
+`--field={field}` to get whatever default or custom field you want.
*Note to users of the official Bitwarden server (at bitwarden.com)*: The
official server has a tendency to detect command line traffic as bot traffic
diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs
index 45f9e0b..fd720cf 100644
--- a/src/bin/rbw/commands.rs
+++ b/src/bin/rbw/commands.rs
@@ -86,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 {
@@ -550,6 +759,7 @@ pub fn get(
name: &str,
user: Option<&str>,
folder: Option<&str>,
+ field: Option<&str>,
full: bool,
) -> anyhow::Result<()> {
unlock()?;
@@ -566,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);
}
diff --git a/src/bin/rbw/main.rs b/src/bin/rbw/main.rs
index 5730298..f56a5b1 100644
--- a/src/bin/rbw/main.rs
+++ b/src/bin/rbw/main.rs
@@ -75,6 +75,8 @@ enum Opt {
user: Option<String>,
#[structopt(long, help = "Folder name to search in")]
folder: Option<String>,
+ #[structopt(short, long, help = "Field to get")]
+ field: Option<String>,
#[structopt(
long,
help = "Display the notes in addition to the password"
@@ -317,8 +319,15 @@ fn main(opt: Opt) {
name,
user,
folder,
+ field,
full,
- } => commands::get(name, user.as_deref(), folder.as_deref(), *full),
+ } => commands::get(
+ name,
+ user.as_deref(),
+ folder.as_deref(),
+ field.as_deref(),
+ *full,
+ ),
Opt::Code { name, user, folder } => {
commands::code(name, user.as_deref(), folder.as_deref())
}