use crate::sh; use serde::Deserialize; use std::io::{Error, ErrorKind}; const EXECUTABLE: &str = "rbw"; #[derive(Deserialize, Debug)] pub struct Item { pub id: String, pub name: String, pub user: Option, #[serde(rename = "type")] pub type_: String, } #[derive(Deserialize, Debug, Clone)] pub struct LoginItem { pub id: String, pub name: String, pub user: String, pub password: String, } pub fn check_rbw() -> Result<(), Error> { let which = sh::sh(format!("which {}", EXECUTABLE)); if which.is_empty() { return Err(Error::new( ErrorKind::Other, format!("{} is not installed", EXECUTABLE), )); } let unlocked = sh::sh(format!("{} unlocked", EXECUTABLE)); if !unlocked.is_empty() { return Err(Error::new( ErrorKind::Other, format!("{} database not unlocked", EXECUTABLE), )); } return Ok(()); } pub fn get_items() -> Result, Error> { let items_raw = sh::sh(format!("{} list --raw", EXECUTABLE)); return match serde_json::from_str(items_raw.as_str()) { Ok(val) => Ok(val), Err(e) => Err(Error::new( ErrorKind::Other, format!("Couldn't get items: {e}"), )), }; } pub fn get_logins(items: Vec) -> Result, Error> { let items = items .iter() .filter(|item| item.type_.to_lowercase() == "login") .collect::>(); let mut login_items = Vec::::new(); for item in items { let password = sh::sh(format!("{} get '{}'", EXECUTABLE, item.id)); if let None = item.user { println!("WARNING: user not found for {}", item.name); } login_items.push(LoginItem { id: item.id.clone(), name: item.name.clone(), user: match item.user.clone() { Some(val) => val, None => "".to_string(), }, password: match password.strip_suffix("\n") { Some(s) => s.to_string(), None => password, }, }); } return Ok(login_items); }