From 15dd1722d4c07d96e825b346cf1dcc6f4e8b45aa Mon Sep 17 00:00:00 2001 From: Ash Svitan Date: Thu, 30 Apr 2026 20:16:43 +0200 Subject: [PATCH] :hammer: Refactors pass to generate LoginItem's Signed-off-by: Ash Svitan --- src/main.rs | 72 ++++++++++++++++++++++++++++++----------------------- src/pass.rs | 43 ++++++++++++++++++++++++++++++-- src/rbw.rs | 2 +- 3 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2a633ed..09e47b2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,47 +41,55 @@ fn main() -> Result<(), Error> { } }; - let mut pass_items = pass::get_items(&vault)?.items; - println!("{:?}", pass_items[0]); - println!("{}", pass_items.len()); + let pass_items = pass::get_items(&vault)?; + let mut pass_logins = pass::get_logins(pass_items); + println!("{:?}", pass_logins[0]); + println!("{}", pass_logins.len()); - let rbw_items_partial = rbw::get_items()?; - let mut rbw_items = rbw::get_login_items(rbw_items_partial)?; - println!("{:?}", rbw_items[0]); - println!("{}", rbw_items.len()); + let rbw_items = rbw::get_items()?; + let mut rbw_logins = rbw::get_logins(rbw_items)?; + println!("{:?}", rbw_logins[0]); + println!("{}", rbw_logins.len()); - for rbw_item in rbw_items.clone().iter() { - let mut pass_item: Option<&pass::Item> = None; + for rbw_login in rbw_logins.clone().iter() { + let mut pass_login: Option<&pass::LoginItem> = None; - 'inner: for pass_item_iter in pass_items.iter() { - if rbw_item.name == pass_item_iter.content.title { - println!("found match! {}", rbw_item.name); - pass_item = Some(pass_item_iter); + 'inner: for pass_login_iter in pass_logins.iter() { + if rbw_login.name == pass_login_iter.title { + println!("found match! {}", rbw_login.name); + pass_login = Some(pass_login_iter); break 'inner; } } - if let None = pass_item { - println!("no match found for {}!", rbw_item.name); + if let None = pass_login { + println!("no match found for {}!", rbw_login.name); continue; } - let pass_item = pass_item.unwrap(); + let pass_login = pass_login.unwrap(); + + let rbw_password = rbw_login.password.clone(); + let pass_password = pass_login.password.clone(); + + let rbw_user = rbw_login.user.clone(); + let pass_user = match pass_login.username.is_empty() { + true => pass_login.email.clone(), + false => pass_login.username.clone(), + }; + let pass_user_is_actually_email = pass_user == pass_login.email; - let rbw_password = rbw_item.password.clone(); - let pass_password = pass_item - .clone() - .content - .content - .login - .clone() - .unwrap() - .password; if rbw_password == pass_password { - let rbw_index = rbw_items.iter().position(|x| x.id == rbw_item.id).unwrap(); - rbw_items.remove(rbw_index); + let rbw_index = rbw_logins + .iter() + .position(|x| x.id == rbw_login.id) + .unwrap(); + rbw_logins.remove(rbw_index); - let pass_index = pass_items.iter().position(|x| x.id == pass_item.id).unwrap(); - pass_items.remove(pass_index); + let pass_index = pass_logins + .iter() + .position(|x| x.id == pass_login.id) + .unwrap(); + pass_logins.remove(pass_index); continue; } else { println!( @@ -91,8 +99,10 @@ fn main() -> Result<(), Error> { } } - println!("remaining {} rbw items", rbw_items.len()); - println!("remaining {} pass items", pass_items.len()); + println!("remaining {} rbw items", rbw_logins.len()); + println!("{:?}", rbw_logins); + println!("remaining {} pass items", pass_logins.len()); + println!("{:?}", pass_logins); return Ok(()); } diff --git a/src/pass.rs b/src/pass.rs index e9cbaa7..671bd53 100644 --- a/src/pass.rs +++ b/src/pass.rs @@ -25,19 +25,20 @@ pub struct Item { pub content: ItemContent, } -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug, Clone)] pub struct ItemContent { pub title: String, pub note: String, pub content: ItemContentContent, } -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug, Clone)] pub struct ItemContentContent { #[serde(rename = "Login")] pub login: Option, } +// pass-cli provided structure, this is what it's called inside the JSON data #[derive(Deserialize, Debug, Clone)] pub struct ItemLogin { pub email: String, @@ -47,6 +48,18 @@ pub struct ItemLogin { pub totp_uri: String, } +// our own custom structure, a counterpart to rbw::LoginItem +#[derive(Debug, Clone)] +pub struct LoginItem { + pub id: String, + pub title: String, + pub username: String, + pub email: String, + pub password: String, + pub urls: Vec, + pub totp_uri: String, +} + pub fn check_pass() -> Result<(), Error> { let which = sh::sh(format!("which {}", EXECUTABLE)); if which.is_empty() { @@ -88,3 +101,29 @@ pub fn get_items(vault: &String) -> Result { )), }; } + +pub fn get_logins(items: Items) -> Vec { + items + .items + .iter() + .filter(|item| { + if let None = item.content.content.login { + false + } else { + true + } + }) + .map(|item| { + let login = item.content.content.login.clone().unwrap(); + LoginItem { + id: item.id.clone(), + title: item.content.title.clone(), + username: login.username, + email: login.email, + password: login.password, + urls: login.urls, + totp_uri: login.totp_uri, + } + }) + .collect() +} diff --git a/src/rbw.rs b/src/rbw.rs index 0f4125c..3f2d166 100644 --- a/src/rbw.rs +++ b/src/rbw.rs @@ -56,7 +56,7 @@ pub fn get_items() -> Result, Error> { }; } -pub fn get_login_items(items: Vec) -> Result, Error> { +pub fn get_logins(items: Vec) -> Result, Error> { let items = items .iter() .filter(|item| item.type_ == "Login")