aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2023-03-09 01:06:03 -0600
committerGitHub <noreply@github.com>2023-03-09 01:06:03 -0600
commit5f4fe0b55d92de36922af372811abf548608edd1 (patch)
treeae2068a5607d7a7bf87bd72885c6081312a5e290
parenta54f18f445e5bb13231ab3c716a32d1706119b5f (diff)
parent9f76d171f0b567deb5571ac33b2548e024cc8f51 (diff)
downloadrbw-5f4fe0b55d92de36922af372811abf548608edd1.tar.gz
rbw-5f4fe0b55d92de36922af372811abf548608edd1.zip
Merge pull request #97 from classabbyamp/json-output
add support for raw json output
-rw-r--r--README.md3
-rw-r--r--src/bin/rbw/commands.rs25
-rw-r--r--src/bin/rbw/main.rs4
3 files changed, 25 insertions, 7 deletions
diff --git a/README.md b/README.md
index 386c0f2..5efe1f8 100644
--- a/README.md
+++ b/README.md
@@ -83,7 +83,8 @@ 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`. You can also use the flag
-`--field={field}` to get whatever default or custom field you want.
+`--field={field}` to get whatever default or custom field you want. The `--raw`
+flag will show the output as JSON.
*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 93f00da..ad083eb 100644
--- a/src/bin/rbw/commands.rs
+++ b/src/bin/rbw/commands.rs
@@ -1,6 +1,7 @@
use anyhow::Context as _;
use std::io;
use std::io::prelude::Write;
+use serde::Serialize;
const MISSING_CONFIG_HELP: &str =
"Before using rbw, you must configure the email address you would like to \
@@ -12,7 +13,7 @@ const MISSING_CONFIG_HELP: &str =
and, if your server has a non-default identity url:\n\n \
rbw config set identity_url <url>\n";
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Serialize)]
#[cfg_attr(test, derive(Eq, PartialEq))]
struct DecryptedCipher {
id: String,
@@ -421,6 +422,14 @@ impl DecryptedCipher {
}
}
+ fn display_json(&self, desc: &str) -> anyhow::Result<()> {
+ serde_json::to_writer_pretty(std::io::stdout(), &self)
+ .context(format!("failed to write entry '{desc}' to stdout"))?;
+ println!();
+
+ Ok(())
+ }
+
fn exact_match(
&self,
name: &str,
@@ -512,7 +521,8 @@ impl DecryptedCipher {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Serialize)]
+#[serde(untagged)]
#[cfg_attr(test, derive(Eq, PartialEq))]
enum DecryptedData {
Login {
@@ -551,21 +561,21 @@ enum DecryptedData {
SecureNote,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Serialize)]
#[cfg_attr(test, derive(Eq, PartialEq))]
struct DecryptedField {
name: Option<String>,
value: Option<String>,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Serialize)]
#[cfg_attr(test, derive(Eq, PartialEq))]
struct DecryptedHistoryEntry {
last_used_date: String,
password: String,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Serialize)]
#[cfg_attr(test, derive(Eq, PartialEq))]
struct DecryptedUri {
uri: String,
@@ -763,6 +773,7 @@ pub fn get(
folder: Option<&str>,
field: Option<&str>,
full: bool,
+ raw: bool,
) -> anyhow::Result<()> {
unlock()?;
@@ -776,7 +787,9 @@ pub fn get(
let (_, decrypted) = find_entry(&db, name, user, folder)
.with_context(|| format!("couldn't find entry for '{desc}'"))?;
- if full {
+ if raw {
+ decrypted.display_json(&desc)?;
+ } else if full {
decrypted.display_long(&desc);
} else if field.is_some() {
decrypted.display_field(&desc, field.unwrap());
diff --git a/src/bin/rbw/main.rs b/src/bin/rbw/main.rs
index 822819a..fd34d11 100644
--- a/src/bin/rbw/main.rs
+++ b/src/bin/rbw/main.rs
@@ -81,6 +81,8 @@ enum Opt {
field: Option<String>,
#[arg(long, help = "Display the notes in addition to the password")]
full: bool,
+ #[structopt(long, help = "Display output as JSON")]
+ raw: bool,
},
#[command(about = "Display the authenticator code for a given entry")]
@@ -319,12 +321,14 @@ fn main() {
folder,
field,
full,
+ raw,
} => commands::get(
name,
user.as_deref(),
folder.as_deref(),
field.as_deref(),
*full,
+ *raw,
),
Opt::Code { name, user, folder } => {
commands::code(name, user.as_deref(), folder.as_deref())