From 3719b63d73ee318bde1edcac734dbc5dab79b59a Mon Sep 17 00:00:00 2001 From: Ash Svitan Date: Thu, 30 Apr 2026 21:35:10 +0200 Subject: [PATCH] :sparkles: Adds creating logins Signed-off-by: Ash Svitan --- Cargo.lock | 39 ++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 60 +++++++++++++++++++++++++++++++++++------------------ src/pass.rs | 22 +++++++++++++++++--- 4 files changed, 99 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 627f975..7617843 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,10 +2,20 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + [[package]] name = "bitwarden-proton-sync" version = "0.1.0" dependencies = [ + "regex", "serde", "serde_json", ] @@ -40,6 +50,35 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + [[package]] name = "serde" version = "1.0.228" diff --git a/Cargo.toml b/Cargo.toml index b96e269..2cd03bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,4 @@ edition = "2024" [dependencies] serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" +regex = "1.12.3" diff --git a/src/main.rs b/src/main.rs index e658e12..62fc539 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,18 @@ 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()?; @@ -48,10 +60,11 @@ fn main() -> Result<(), Error> { let rbw_items = rbw::get_items()?; let mut rbw_logins = rbw::get_logins(rbw_items)?; + println!(); println!( - "Got {} pass logins and {} rbw logins...", - pass_logins.len(), - rbw_logins.len() + "Got {} rbw logins and {} pass logins...", + rbw_logins.len(), + pass_logins.len() ); for rbw_login in rbw_logins.clone().iter() { @@ -80,16 +93,12 @@ fn main() -> Result<(), Error> { let pass_user_is_actually_email = pass_user == pass_login.email; if rbw_user != pass_user || rbw_password != pass_password { - // TODO: need to update - println!("Attempting to update {}:", rbw_login.name); - println!("\t{} -> {}", pass_user, rbw_user.clone()); - println!("\t{} -> {}", pass_password, rbw_password.clone()); - print!("Proceed? [y/N] "); - io::stdout().flush()?; - let mut input = String::new(); - io::stdin().read_line(&mut input)?; - - if input.to_lowercase() == "y\n" { + 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(), @@ -97,7 +106,7 @@ fn main() -> Result<(), Error> { email: rbw_user.clone(), password: rbw_password, }; - pass::update(&vault, updated_pass_login, pass_user_is_actually_email)?; + pass::update(&vault, updated_pass_login, pass_user_is_actually_email); } } @@ -114,13 +123,24 @@ fn main() -> Result<(), Error> { pass_logins.remove(pass_index); } - // TODO: need to create these - println!("remaining {} rbw items", rbw_logins.len()); - println!("{:?}", rbw_logins); - // TODO: need to delete these - println!("remaining {} pass items", pass_logins.len()); - println!("{:?}", pass_logins); + 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); + } + } return Ok(()); } diff --git a/src/pass.rs b/src/pass.rs index b7f0449..0058477 100644 --- a/src/pass.rs +++ b/src/pass.rs @@ -1,8 +1,10 @@ use crate::sh; +use regex::Regex; use serde::Deserialize; use std::io::{Error, ErrorKind}; const EXECUTABLE: &str = "pass-cli"; +const EMAIL_REGEX: &str = r"^[\w\-\.]+@([\w-]+\.)+[\w-]{2,}$"; #[derive(Deserialize, Debug)] pub struct Vaults { @@ -124,7 +126,7 @@ pub fn get_logins(items: Items) -> Vec { .collect() } -pub fn update(vault: &String, item: LoginItem, user_is_actually_email: bool) -> Result<(), Error> { +pub fn update(vault: &String, item: LoginItem, user_is_actually_email: bool) { let user_field_update = if user_is_actually_email { format!("email={}", item.email) } else { @@ -135,6 +137,20 @@ pub fn update(vault: &String, item: LoginItem, user_is_actually_email: bool) -> EXECUTABLE, vault, item.id, item.password, user_field_update )); println!("> {}", output); - - return Ok(()); +} + +pub fn create(vault: &String, title: String, user: String, password: String) { + let re = Regex::new(EMAIL_REGEX).expect("Couldn't parse regex"); + let is_email = re.is_match(&user); + let user_arg = if is_email { + format!("--email '{}'", user) + } else { + format!("--username '{}'", user) + }; + + let output = sh::sh(format!( + "{} item create login --vault-name '{}' --title '{}' {} --password '{}'", + EXECUTABLE, vault, title, user_arg, password + )); + println!("> {}", output); }