mod pass; mod rbw; mod sh; use std::env; use std::io; use std::io::{Error, ErrorKind, Write}; const ENV_VAR_DEFAULT_VAULT: &str = "PASS_VAULT"; fn ask_consent(question: String, line1: String, line2: String) -> Result { println!("{}", question); println!("\t{}", line1); println!("\t{}", line2); print!("Proceed? [y/N] "); io::stdout().flush()?; let mut input = String::new(); io::stdin().read_line(&mut input)?; return Ok(input.to_lowercase() == "y\n"); } fn main() -> Result<(), Error> { pass::check_pass()?; rbw::check_rbw()?; let vaults = pass::get_vaults()?.vaults; if vaults.len() <= 0 { return Err(Error::new(ErrorKind::Other, "No vaults found")); } let vault_names = vaults .iter() .map(|vault| vault.name.clone()) .collect::>(); let vault; match env::var(ENV_VAR_DEFAULT_VAULT) { Ok(default_vault) => { if vault_names.contains(&default_vault) { vault = default_vault; } else { return Err(Error::new( ErrorKind::Other, format!("Vault {} does not exist", default_vault), )); } } Err(_) => { vault = vault_names.get(0).unwrap().clone(); println!( "No default vault found (you can set it with {}), using {}...", ENV_VAR_DEFAULT_VAULT, vault ); } }; let pass_items = pass::get_items(&vault)?; let mut pass_logins = pass::get_logins(pass_items); let rbw_items = rbw::get_items()?; let mut rbw_logins = rbw::get_logins(rbw_items)?; println!(); println!( "Got {} rbw logins and {} pass logins...", rbw_logins.len(), pass_logins.len() ); for rbw_login in rbw_logins.clone().iter() { let mut pass_login: Option<&pass::LoginItem> = None; 'inner: for pass_login_iter in pass_logins.iter() { if rbw_login.name == pass_login_iter.title { pass_login = Some(pass_login_iter); break 'inner; } } if let None = pass_login { continue; } 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; if rbw_user != pass_user || rbw_password != pass_password { let consent = ask_consent( format!("Attempting to update {}:", rbw_login.name), format!("{} -> {}", pass_user, rbw_user.clone()), format!("{} -> {}", pass_password, rbw_password.clone()), )?; if consent { let updated_pass_login = pass::LoginItem { id: pass_login.id.clone(), title: pass_login.title.clone(), username: rbw_user.clone(), email: rbw_user.clone(), password: rbw_password, }; pass::update(&vault, updated_pass_login, pass_user_is_actually_email); } } let rbw_index = rbw_logins .iter() .position(|x| x.id == rbw_login.id) .unwrap(); rbw_logins.remove(rbw_index); let pass_index = pass_logins .iter() .position(|x| x.id == pass_login.id) .unwrap(); pass_logins.remove(pass_index); } // TODO: need to delete these println!(); println!( "Remaining {} rbw logins and {} pass logins...", rbw_logins.len(), pass_logins.len() ); for rbw_login in rbw_logins { let consent = ask_consent( format!("Attempting to create {}:", rbw_login.name), format!("{}", rbw_login.user), format!("{}", rbw_login.password), )?; if consent { pass::create(&vault, rbw_login.name, rbw_login.user, rbw_login.password); } } for pass_login in pass_logins { let consent = ask_consent( format!("Attempting to delete {}:", pass_login.title), format!( "{}", if pass_login.username.is_empty() { pass_login.email } else { pass_login.username } ), format!("{}", pass_login.password), )?; if consent { pass::trash(&vault, pass_login.id); } } return Ok(()); }