From c7aacb1df6ee9806fc86d5120cc7a9244fd16a2d Mon Sep 17 00:00:00 2001 From: Ash Svitan Date: Mon, 20 Jul 2026 10:41:53 +0200 Subject: [PATCH] :bug: Fixes parsing bw output --- src/bw.rs | 8 ++++---- src/main.rs | 36 ++++++++++++++++++++++++++++++------ src/pass.rs | 29 +++++++++++++++++++++++++++-- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/bw.rs b/src/bw.rs index 7b1a41c..6d0e333 100644 --- a/src/bw.rs +++ b/src/bw.rs @@ -1,6 +1,6 @@ use crate::sh; use serde::Deserialize; -use std::io::{Error, ErrorKind, Write, stdin, stdout}; +use std::io::{Error, ErrorKind}; const EXECUTABLE: &str = "bw"; @@ -20,7 +20,7 @@ pub struct Item { pub notes: Option, pub favorite: bool, pub fields: Vec, - pub login: Login, + pub login: Option, } #[derive(Deserialize, Clone)] @@ -41,7 +41,7 @@ pub struct ItemField { #[derive(Deserialize, Clone)] pub struct Login { pub uris: Vec, - pub username: String, + pub username: Option, pub password: Option, pub totp: Option, #[serde(rename = "passwordRevisionDate")] @@ -77,7 +77,7 @@ pub struct Fido2Credential { #[serde(rename = "rpName")] pub rp_name: String, #[serde(rename = "userDisplayName")] - pub user_display_name: String, + pub user_display_name: Option, pub discoverable: String, #[serde(rename = "creationDate")] pub creation_date: String, diff --git a/src/main.rs b/src/main.rs index 2148888..f306943 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,9 +59,11 @@ fn sync() -> Result<(), Error> { } }; + println!("getting pass logins"); let pass_items = pass::get_items(&vault)?; let mut pass_logins = pass::get_logins(pass_items); + println!("getting bw logins"); let mut bw_items = bw::get_items()?; println!(); @@ -72,6 +74,11 @@ fn sync() -> Result<(), Error> { ); for bw_item in bw_items.clone().iter() { + if let None = bw_item.login { + continue; + } + let bw_login = bw_item.login.clone().unwrap(); + let mut pass_login: Option<&pass::LoginItem> = None; 'inner: for pass_login_iter in pass_logins.iter() { @@ -86,7 +93,7 @@ fn sync() -> Result<(), Error> { } let pass_login = pass_login.unwrap(); - let bw_password = bw_item.login.password.clone(); + let bw_password = bw_login.password.clone(); // TODO: fix this if let None = bw_password { continue; @@ -95,7 +102,12 @@ fn sync() -> Result<(), Error> { let pass_password = pass_login.password.clone(); - let bw_user = bw_item.login.username.clone(); + let bw_user = bw_login.username.clone(); + if let None = bw_user { + continue; + } + let bw_user = bw_user.unwrap(); + let pass_user = match pass_login.username.is_empty() { true => pass_login.email.clone(), false => pass_login.username.clone(), @@ -115,6 +127,9 @@ fn sync() -> Result<(), Error> { username: bw_user.clone(), email: bw_user.clone(), password: bw_password, + notes: pass_login.notes.clone(), + urls: pass_login.urls.clone(), + totp: pass_login.totp.clone(), }; pass::update(&vault, updated_pass_login, pass_user_is_actually_email); } @@ -138,17 +153,26 @@ fn sync() -> Result<(), Error> { ); for bw_item in bw_items { + if let None = bw_item.login { + continue; + } + + let login = bw_item.login.unwrap(); + if let None = login.username { + continue; + } + let consent = ask_consent( format!("Attempting to create {}:", bw_item.name), - format!("{}", bw_item.login.username), - format!("{:?}", bw_item.login.password), + format!("{}", login.username.clone().unwrap()), + format!("{:?}", login.password), )?; if consent { pass::create( &vault, bw_item.name, - bw_item.login.username, - bw_item.login.password.unwrap_or("".to_string()), + login.username.unwrap(), + login.password.unwrap_or("".to_string()), ); } } diff --git a/src/pass.rs b/src/pass.rs index b88a59c..014093f 100644 --- a/src/pass.rs +++ b/src/pass.rs @@ -31,6 +31,7 @@ pub struct Item { #[derive(Deserialize, Debug, Clone)] pub struct ItemContent { pub title: String, + pub note: String, pub content: ItemContentContent, } @@ -46,6 +47,8 @@ pub struct ItemLogin { pub email: String, pub username: String, pub password: String, + pub urls: Vec, + pub totp_uri: Option, } // our own custom structure, a counterpart to rbw::LoginItem @@ -56,6 +59,9 @@ pub struct LoginItem { pub username: String, pub email: String, pub password: String, + pub urls: Option>, + pub notes: String, + pub totp: Option, } pub fn check_pass() -> Result<(), Error> { @@ -124,6 +130,9 @@ pub fn get_logins(items: Items) -> Vec { username: login.username, email: login.email, password: login.password, + notes: item.content.note.clone(), + urls: Some(login.urls), + totp: login.totp_uri, } }) .collect() @@ -135,9 +144,25 @@ pub fn update(vault: &String, item: LoginItem, user_is_actually_email: bool) { } else { format!("usename={}", item.username) }; + + let maybe_urls = if let Some(urls) = item.urls { + let mut it = "".to_string(); + for url in urls { + it = format!("{} --field 'url={}'", it, url); + } + it + } else { + "".to_string() + }; + let maybe_notes = if item.notes.is_empty() { + "".to_string() + } else { + format!("--field 'note={}'", item.notes) + }; + let output = sh::sh(format!( - "{} item update --vault-name '{}' --item-id '{}' --field 'password={}' --field '{}'", - EXECUTABLE, vault, item.id, item.password, user_field_update + "{} item update --vault-name '{}' --item-id '{}' --field 'password={}' --field '{}' {} {}", + EXECUTABLE, vault, item.id, item.password, user_field_update, maybe_urls, maybe_notes )); println!("> {}", output); }