refactor!: optimize loops BREAKING CHANGE: the signature for `register_key` has changed - `item_id` replaced with `item` for debug purposes - searching for items now uses `iter()` with `find()` and `filter()`
Diff
src/bwutil.rs | 2 +-
src/main.rs | 51 +++++++++++++++++++++++++++++++--------------------
2 files changed, 32 insertions(+), 21 deletions(-)
@@ -26,7 +26,7 @@ pub struct BitwardenItem {
#[serde(rename_all = "camelCase")]
pub struct BitwardenFieldItem {
pub name: String,
pub value: String
pub value: Option<String>
}
@@ -3,6 +3,7 @@ use std::str::FromStr;
use gumdrop::Options;
use anyhow::{Result, Context};
use colored::*;
use crate::bwutil::BitwardenItem;
mod util;
mod bwutil;
@@ -59,8 +60,13 @@ fn main() -> Result<()> {
debug_println!("Found {} folder(s) named `{}`", folders.len().to_string().cyan(), args.folder.cyan());
for folder in folders {
let folder_items = bwutil::exec_list_folder_items(&session_token, &folder.id)?;
let folder_items: Vec<BitwardenItem> = bwutil::exec_list_folder_items(&session_token, &folder.id)?;
let folder_items: Vec<&BitwardenItem> = folder_items
.iter()
.filter(|&item| item.fields.is_some() && item.attachments.is_some())
.collect();
debug_println!("Found {} item(s) in folder `{}` id({}) with at least one custom field and attachment", folder_items.len().to_string().cyan(), folder.name.cyan(), folder.id.cyan());
@@ -72,22 +78,24 @@ fn main() -> Result<()> {
if let Some(fields) = &item.fields {
let mut key_filename = String::new();
let mut key_passphrase = String::new();
for field in fields {
if field.name.to_lowercase().eq(&args.key.to_lowercase()) {
key_filename.push_str(&field.value);
}
if field.name.to_lowercase().eq(&args.passphrase.to_lowercase()) {
key_passphrase.push_str(&field.value);
}
}
if let Some(attachments) = &item.attachments {
for attachment in attachments {
if attachment.file_name.eq(&key_filename) {
let _key = register_key(&item.id, &attachment.id, &key_passphrase, &session_token)?;
}
let key_filename: String = fields
.iter()
.find(|field| field.name.to_lowercase().eq(&args.key.to_lowercase()) && field.value.is_some())
.map(|field| field.value.as_ref().unwrap().clone())
.unwrap_or_default();
if !&key_filename.is_empty() {
let key_passphrase: String = fields
.iter()
.find(|field| field.name.to_lowercase().eq(&args.passphrase.to_lowercase()) && field.value.is_some())
.map(|field| field.value.as_ref().unwrap().clone())
.unwrap_or_default();
if let Some(attachments) = &item.attachments {
attachments
.iter()
.filter(|attachment| attachment.file_name.eq(&key_filename))
.for_each(|attachment| register_key(&item, &attachment.id, &key_passphrase, &session_token).unwrap());
}
}
}
@@ -138,20 +146,23 @@ fn check_session_token(args: &util::Cli) -> Result<String> {
Ok(session_token)
}
fn register_key(item_id: &str, attachment_id: &str, passphrase: &str, session_token: &str) -> Result<()> {
fn register_key(item: &BitwardenItem, attachment_id: &str, passphrase: &str, session_token: &str) -> Result<()> {
debug_println!("Item `{}` id({}) meets all requirements. Adding to `{}`", item.name.cyan(), item.id.to_string().cyan(), "ssh-agent".cyan());
let bw_command = Command::new("bw")
.arg("get")
.arg("attachment")
.arg(attachment_id)
.arg("--itemid")
.arg(item_id)
.arg(&item.id)
.arg("--raw")
.arg("--session")
.arg(session_token)
.stdout(Stdio::piped())
.spawn()
.with_context(||
format!("Error running command:\n `bw get attachment {} --itemid {} --raw --session **REDACTED**`", attachment_id, item_id)
format!("Error running command:\n `bw get attachment {} --itemid {} --raw --session **REDACTED**`", attachment_id, item.id)
)?;
let app_path = env::current_exe()?;