From 11bad7ea2411a43f1fba6785019ffd429939f384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20G=C3=B6tsch?= Date: Wed, 20 Mar 2024 22:40:00 +0100 Subject: [PATCH 1/2] Add CLI option for case-insensitive search. --- src/bin/rbw/commands.rs | 697 +++++++++++++++++++++++++++++++--------- src/bin/rbw/main.rs | 56 +++- 2 files changed, 594 insertions(+), 159 deletions(-) diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs index 6d36eb3..d64ea5a 100644 --- a/src/bin/rbw/commands.rs +++ b/src/bin/rbw/commands.rs @@ -521,10 +521,14 @@ impl DecryptedCipher { username: Option<&str>, folder: Option<&str>, try_match_folder: bool, + ignore_case: bool, ) -> bool { match needle { Needle::Name(name) => { - if &self.name != name { + if !((ignore_case + && name.to_lowercase() == self.name.to_lowercase()) + || *name == self.name) + { return false; } } @@ -591,8 +595,12 @@ impl DecryptedCipher { username: Option<&str>, folder: Option<&str>, try_match_folder: bool, + ignore_case: bool, ) -> bool { - if !self.name.contains(name) { + if !((ignore_case + && self.name.to_lowercase().contains(&name.to_lowercase())) + || self.name.contains(name)) + { return false; } @@ -991,6 +999,7 @@ pub fn get( full: bool, raw: bool, clipboard: bool, + ignore_case: bool, ) -> anyhow::Result<()> { unlock()?; @@ -1002,8 +1011,9 @@ pub fn get( needle ); - let (_, decrypted) = find_entry(&db, needle, user, folder) - .with_context(|| format!("couldn't find entry for '{desc}'"))?; + let (_, decrypted) = + find_entry(&db, needle, user, folder, ignore_case) + .with_context(|| format!("couldn't find entry for '{desc}'"))?; if raw { decrypted.display_json(&desc)?; } else if full { @@ -1022,6 +1032,7 @@ pub fn code( user: Option<&str>, folder: Option<&str>, clipboard: bool, + ignore_case: bool, ) -> anyhow::Result<()> { unlock()?; @@ -1033,8 +1044,9 @@ pub fn code( needle ); - let (_, decrypted) = find_entry(&db, needle, user, folder) - .with_context(|| format!("couldn't find entry for '{desc}'"))?; + let (_, decrypted) = + find_entry(&db, needle, user, folder, ignore_case) + .with_context(|| format!("couldn't find entry for '{desc}'"))?; if let DecryptedData::Login { totp, .. } = decrypted.data { if let Some(totp) = totp { @@ -1248,6 +1260,7 @@ pub fn edit( name: &str, username: Option<&str>, folder: Option<&str>, + ignore_case: bool, ) -> anyhow::Result<()> { unlock()?; @@ -1261,9 +1274,14 @@ pub fn edit( name ); - let (entry, decrypted) = - find_entry(&db, &Needle::Name(name.to_string()), username, folder) - .with_context(|| format!("couldn't find entry for '{desc}'"))?; + let (entry, decrypted) = find_entry( + &db, + &Needle::Name(name.to_string()), + username, + folder, + ignore_case, + ) + .with_context(|| format!("couldn't find entry for '{desc}'"))?; let (data, fields, notes, history) = match &decrypted.data { DecryptedData::Login { password, .. } => { @@ -1372,6 +1390,7 @@ pub fn remove( name: &str, username: Option<&str>, folder: Option<&str>, + ignore_case: bool, ) -> anyhow::Result<()> { unlock()?; @@ -1385,9 +1404,14 @@ pub fn remove( name ); - let (entry, _) = - find_entry(&db, &Needle::Name(name.to_string()), username, folder) - .with_context(|| format!("couldn't find entry for '{desc}'"))?; + let (entry, _) = find_entry( + &db, + &Needle::Name(name.to_string()), + username, + folder, + ignore_case, + ) + .with_context(|| format!("couldn't find entry for '{desc}'"))?; if let (Some(access_token), ()) = rbw::actions::remove(access_token, refresh_token, &entry.id)? @@ -1405,6 +1429,7 @@ pub fn history( name: &str, username: Option<&str>, folder: Option<&str>, + ignore_case: bool, ) -> anyhow::Result<()> { unlock()?; @@ -1416,9 +1441,14 @@ pub fn history( name ); - let (_, decrypted) = - find_entry(&db, &Needle::Name(name.to_string()), username, folder) - .with_context(|| format!("couldn't find entry for '{desc}'"))?; + let (_, decrypted) = find_entry( + &db, + &Needle::Name(name.to_string()), + username, + folder, + ignore_case, + ) + .with_context(|| format!("couldn't find entry for '{desc}'"))?; for history in decrypted.history { println!("{}: {}", history.last_used_date, history.password); } @@ -1516,6 +1546,7 @@ fn find_entry( needle: &Needle, username: Option<&str>, folder: Option<&str>, + ignore_case: bool, ) -> anyhow::Result<(rbw::db::Entry, DecryptedCipher)> { if let Needle::Uuid(uuid) = needle { for cipher in &db.entries { @@ -1533,7 +1564,7 @@ fn find_entry( decrypt_cipher(&entry).map(|decrypted| (entry, decrypted)) }) .collect::>()?; - find_entry_raw(&ciphers, needle, username, folder) + find_entry_raw(&ciphers, needle, username, folder, ignore_case) } } @@ -1542,11 +1573,18 @@ fn find_entry_raw( needle: &Needle, username: Option<&str>, folder: Option<&str>, + ignore_case: bool, ) -> anyhow::Result<(rbw::db::Entry, DecryptedCipher)> { let mut matches: Vec<(rbw::db::Entry, DecryptedCipher)> = entries .iter() .filter(|&(_, decrypted_cipher)| { - decrypted_cipher.exact_match(needle, username, folder, true) + decrypted_cipher.exact_match( + needle, + username, + folder, + true, + ignore_case, + ) }) .cloned() .collect(); @@ -1559,7 +1597,13 @@ fn find_entry_raw( matches = entries .iter() .filter(|&(_, decrypted_cipher)| { - decrypted_cipher.exact_match(needle, username, folder, false) + decrypted_cipher.exact_match( + needle, + username, + folder, + false, + ignore_case, + ) }) .cloned() .collect(); @@ -1573,7 +1617,13 @@ fn find_entry_raw( matches = entries .iter() .filter(|&(_, decrypted_cipher)| { - decrypted_cipher.partial_match(name, username, folder, true) + decrypted_cipher.partial_match( + name, + username, + folder, + true, + ignore_case, + ) }) .cloned() .collect(); @@ -1586,8 +1636,13 @@ fn find_entry_raw( matches = entries .iter() .filter(|&(_, decrypted_cipher)| { - decrypted_cipher - .partial_match(name, username, folder, false) + decrypted_cipher.partial_match( + name, + username, + folder, + false, + ignore_case, + ) }) .cloned() .collect(); @@ -2066,59 +2121,155 @@ mod test { ]; assert!( - one_match(entries, "github", Some("foo"), None, 0), + one_match(entries, "github", Some("foo"), None, 0, false), "foo@github" ); - assert!(one_match(entries, "github", None, None, 0), "github"); assert!( - one_match(entries, "gitlab", Some("foo"), None, 1), + one_match(entries, "GITHUB", Some("foo"), None, 0, true), + "foo@GITHUB" + ); + assert!(one_match(entries, "github", None, None, 0, false), "github"); + assert!(one_match(entries, "GITHUB", None, None, 0, true), "GITHUB"); + assert!( + one_match(entries, "gitlab", Some("foo"), None, 1, false), "foo@gitlab" ); - assert!(one_match(entries, "git", Some("bar"), None, 2), "bar@git"); assert!( - one_match(entries, "gitter", Some("ba"), None, 3), + one_match(entries, "GITLAB", Some("foo"), None, 1, true), + "foo@GITLAB" + ); + assert!( + one_match(entries, "git", Some("bar"), None, 2, false), + "bar@git" + ); + assert!( + one_match(entries, "GIT", Some("bar"), None, 2, true), + "bar@GIT" + ); + assert!( + one_match(entries, "gitter", Some("ba"), None, 3, false), "ba@gitter" ); - assert!(one_match(entries, "git", Some("foo"), None, 4), "foo@git"); - assert!(one_match(entries, "git", None, None, 4), "git"); - assert!(one_match(entries, "bitwarden", None, None, 5), "bitwarden"); assert!( - one_match(entries, "github", Some("foo"), Some("websites"), 6), + one_match(entries, "GITTER", Some("ba"), None, 3, true), + "ba@GITTER" + ); + assert!( + one_match(entries, "git", Some("foo"), None, 4, false), + "foo@git" + ); + assert!( + one_match(entries, "GIT", Some("foo"), None, 4, true), + "foo@GIT" + ); + assert!(one_match(entries, "git", None, None, 4, false), "git"); + assert!(one_match(entries, "GIT", None, None, 4, true), "GIT"); + assert!( + one_match(entries, "bitwarden", None, None, 5, false), + "bitwarden" + ); + assert!( + one_match(entries, "BITWARDEN", None, None, 5, true), + "BITWARDEN" + ); + assert!( + one_match( + entries, + "github", + Some("foo"), + Some("websites"), + 6, + false + ), "websites/foo@github" ); assert!( - one_match(entries, "github", Some("foo"), Some("ssh"), 7), + one_match( + entries, + "GITHUB", + Some("foo"), + Some("websites"), + 6, + true + ), + "websites/foo@GITHUB" + ); + assert!( + one_match(entries, "github", Some("foo"), Some("ssh"), 7, false), "ssh/foo@github" ); assert!( - one_match(entries, "github", Some("root"), None, 8), + one_match(entries, "GITHUB", Some("foo"), Some("ssh"), 7, true), + "ssh/foo@GITHUB" + ); + assert!( + one_match(entries, "github", Some("root"), None, 8, false), "ssh/root@github" ); + assert!( + one_match(entries, "GITHUB", Some("root"), None, 8, true), + "ssh/root@GITHUB" + ); assert!( - no_matches(entries, "gitlab", Some("baz"), None), + no_matches(entries, "gitlab", Some("baz"), None, false), "baz@gitlab" ); assert!( - no_matches(entries, "bitbucket", Some("foo"), None), + no_matches(entries, "GITLAB", Some("baz"), None, true), + "baz@" + ); + assert!( + no_matches(entries, "bitbucket", Some("foo"), None, false), "foo@bitbucket" ); assert!( - no_matches(entries, "github", Some("foo"), Some("bar")), + no_matches(entries, "BITBUCKET", Some("foo"), None, true), + "foo@BITBUCKET" + ); + assert!( + no_matches(entries, "github", Some("foo"), Some("bar"), false), "bar/foo@github" ); assert!( - no_matches(entries, "gitlab", Some("foo"), Some("bar")), + no_matches(entries, "GITHUB", Some("foo"), Some("bar"), true), + "bar/foo@" + ); + assert!( + no_matches(entries, "gitlab", Some("foo"), Some("bar"), false), "bar/foo@gitlab" ); + assert!( + no_matches(entries, "GITLAB", Some("foo"), Some("bar"), true), + "bar/foo@GITLAB" + ); - assert!(many_matches(entries, "gitlab", None, None), "gitlab"); - assert!(many_matches(entries, "gi", Some("foo"), None), "foo@gi"); - assert!(many_matches(entries, "git", Some("ba"), None), "ba@git"); + assert!(many_matches(entries, "gitlab", None, None, false), "gitlab"); + assert!(many_matches(entries, "gitlab", None, None, true), "GITLAB"); + assert!( + many_matches(entries, "gi", Some("foo"), None, false), + "foo@gi" + ); + assert!( + many_matches(entries, "GI", Some("foo"), None, true), + "foo@GI" + ); + assert!( + many_matches(entries, "git", Some("ba"), None, false), + "ba@git" + ); + assert!( + many_matches(entries, "GIT", Some("ba"), None, true), + "ba@GIT" + ); assert!( - many_matches(entries, "github", Some("foo"), Some("s")), + many_matches(entries, "github", Some("foo"), Some("s"), false), "s/foo@github" ); + assert!( + many_matches(entries, "GITHUB", Some("foo"), Some("s"), true), + "s/foo@GITHUB" + ); } #[test] @@ -2130,15 +2281,15 @@ mod test { ]; assert!( - one_match(entries, &entries[0].0.id, None, None, 0), + one_match(entries, &entries[0].0.id, None, None, 0, false), "foo@github" ); assert!( - one_match(entries, &entries[1].0.id, None, None, 1), + one_match(entries, &entries[1].0.id, None, None, 1, false), "foo@gitlab" ); assert!( - one_match(entries, &entries[2].0.id, None, None, 2), + one_match(entries, &entries[2].0.id, None, None, 2, false), "bar@gitlab" ); @@ -2148,7 +2299,8 @@ mod test { &entries[0].0.id.to_uppercase(), None, None, - 0 + 0, + false ), "foo@github" ); @@ -2158,7 +2310,8 @@ mod test { &entries[0].0.id.to_lowercase(), None, None, - 0 + 0, + false ), "foo@github" ); @@ -2185,51 +2338,94 @@ mod test { make_entry("six", None, None, &[("six.com:8080", None)]), ]; - assert!(one_match(entries, "https://one.com/", None, None, 0), "one"); assert!( - one_match(entries, "https://login.one.com/", None, None, 0), + one_match(entries, "https://one.com/", None, None, 0, false), "one" ); assert!( - one_match(entries, "https://one.com:443/", None, None, 0), + one_match( + entries, + "https://login.one.com/", + None, + None, + 0, + false + ), + "one" + ); + assert!( + one_match(entries, "https://one.com:443/", None, None, 0, false), + "one" + ); + assert!(no_matches(entries, "one.com", None, None, false), "one"); + assert!(no_matches(entries, "https", None, None, false), "one"); + assert!(no_matches(entries, "com", None, None, false), "one"); + assert!( + no_matches(entries, "https://com/", None, None, false), "one" ); - assert!(no_matches(entries, "one.com", None, None), "one"); - assert!(no_matches(entries, "https", None, None), "one"); - assert!(no_matches(entries, "com", None, None), "one"); - assert!(no_matches(entries, "https://com/", None, None), "one"); - assert!(one_match(entries, "https://two.com/", None, None, 1), "two"); assert!( - one_match(entries, "https://two.com/other-page", None, None, 1), + one_match(entries, "https://two.com/", None, None, 1, false), + "two" + ); + assert!( + one_match( + entries, + "https://two.com/other-page", + None, + None, + 1, + false + ), "two" ); assert!( - one_match(entries, "https://login.three.com/", None, None, 2), + one_match( + entries, + "https://login.three.com/", + None, + None, + 2, + false + ), "three" ); assert!( - no_matches(entries, "https://three.com/", None, None), + no_matches(entries, "https://three.com/", None, None, false), "three" ); assert!( - one_match(entries, "https://four.com/", None, None, 3), + one_match(entries, "https://four.com/", None, None, 3, false), "four" ); assert!( - one_match(entries, "https://five.com:8080/", None, None, 4), + one_match( + entries, + "https://five.com:8080/", + None, + None, + 4, + false + ), + "five" + ); + assert!( + no_matches(entries, "https://five.com/", None, None, false), "five" ); - assert!(no_matches(entries, "https://five.com/", None, None), "five"); assert!( - one_match(entries, "https://six.com:8080/", None, None, 5), + one_match(entries, "https://six.com:8080/", None, None, 5, false), + "six" + ); + assert!( + no_matches(entries, "https://six.com/", None, None, false), "six" ); - assert!(no_matches(entries, "https://six.com/", None, None), "six"); } #[test] @@ -2282,51 +2478,94 @@ mod test { ), ]; - assert!(one_match(entries, "https://one.com/", None, None, 0), "one"); assert!( - one_match(entries, "https://login.one.com/", None, None, 0), + one_match(entries, "https://one.com/", None, None, 0, false), + "one" + ); + assert!( + one_match( + entries, + "https://login.one.com/", + None, + None, + 0, + false + ), + "one" + ); + assert!( + one_match(entries, "https://one.com:443/", None, None, 0, false), "one" ); + assert!(no_matches(entries, "one.com", None, None, false), "one"); + assert!(no_matches(entries, "https", None, None, false), "one"); + assert!(no_matches(entries, "com", None, None, false), "one"); assert!( - one_match(entries, "https://one.com:443/", None, None, 0), + no_matches(entries, "https://com/", None, None, false), "one" ); - assert!(no_matches(entries, "one.com", None, None), "one"); - assert!(no_matches(entries, "https", None, None), "one"); - assert!(no_matches(entries, "com", None, None), "one"); - assert!(no_matches(entries, "https://com/", None, None), "one"); - assert!(one_match(entries, "https://two.com/", None, None, 1), "two"); assert!( - one_match(entries, "https://two.com/other-page", None, None, 1), + one_match(entries, "https://two.com/", None, None, 1, false), + "two" + ); + assert!( + one_match( + entries, + "https://two.com/other-page", + None, + None, + 1, + false + ), "two" ); assert!( - one_match(entries, "https://login.three.com/", None, None, 2), + one_match( + entries, + "https://login.three.com/", + None, + None, + 2, + false + ), "three" ); assert!( - no_matches(entries, "https://three.com/", None, None), + no_matches(entries, "https://three.com/", None, None, false), "three" ); assert!( - one_match(entries, "https://four.com/", None, None, 3), + one_match(entries, "https://four.com/", None, None, 3, false), "four" ); assert!( - one_match(entries, "https://five.com:8080/", None, None, 4), + one_match( + entries, + "https://five.com:8080/", + None, + None, + 4, + false + ), + "five" + ); + assert!( + no_matches(entries, "https://five.com/", None, None, false), "five" ); - assert!(no_matches(entries, "https://five.com/", None, None), "five"); assert!( - one_match(entries, "https://six.com:8080/", None, None, 5), + one_match(entries, "https://six.com:8080/", None, None, 5, false), + "six" + ); + assert!( + no_matches(entries, "https://six.com/", None, None, false), "six" ); - assert!(no_matches(entries, "https://six.com/", None, None), "six"); } #[test] @@ -2379,51 +2618,87 @@ mod test { ), ]; - assert!(one_match(entries, "https://one.com/", None, None, 0), "one"); assert!( - no_matches(entries, "https://login.one.com/", None, None), + one_match(entries, "https://one.com/", None, None, 0, false), + "one" + ); + assert!( + no_matches(entries, "https://login.one.com/", None, None, false), "one" ); assert!( - one_match(entries, "https://one.com:443/", None, None, 0), + one_match(entries, "https://one.com:443/", None, None, 0, false), + "one" + ); + assert!(no_matches(entries, "one.com", None, None, false), "one"); + assert!(no_matches(entries, "https", None, None, false), "one"); + assert!(no_matches(entries, "com", None, None, false), "one"); + assert!( + no_matches(entries, "https://com/", None, None, false), "one" ); - assert!(no_matches(entries, "one.com", None, None), "one"); - assert!(no_matches(entries, "https", None, None), "one"); - assert!(no_matches(entries, "com", None, None), "one"); - assert!(no_matches(entries, "https://com/", None, None), "one"); - assert!(one_match(entries, "https://two.com/", None, None, 1), "two"); assert!( - one_match(entries, "https://two.com/other-page", None, None, 1), + one_match(entries, "https://two.com/", None, None, 1, false), + "two" + ); + assert!( + one_match( + entries, + "https://two.com/other-page", + None, + None, + 1, + false + ), "two" ); assert!( - one_match(entries, "https://login.three.com/", None, None, 2), + one_match( + entries, + "https://login.three.com/", + None, + None, + 2, + false + ), "three" ); assert!( - no_matches(entries, "https://three.com/", None, None), + no_matches(entries, "https://three.com/", None, None, false), "three" ); assert!( - one_match(entries, "https://four.com/", None, None, 3), + one_match(entries, "https://four.com/", None, None, 3, false), "four" ); assert!( - one_match(entries, "https://five.com:8080/", None, None, 4), + one_match( + entries, + "https://five.com:8080/", + None, + None, + 4, + false + ), + "five" + ); + assert!( + no_matches(entries, "https://five.com/", None, None, false), "five" ); - assert!(no_matches(entries, "https://five.com/", None, None), "five"); assert!( - one_match(entries, "https://six.com:8080/", None, None, 5), + one_match(entries, "https://six.com:8080/", None, None, 5, false), + "six" + ); + assert!( + no_matches(entries, "https://six.com/", None, None, false), "six" ); - assert!(no_matches(entries, "https://six.com/", None, None), "six"); } #[test] @@ -2458,40 +2733,69 @@ mod test { ), ]; - assert!(one_match(entries, "https://one.com/", None, None, 0), "one"); assert!( - no_matches(entries, "https://login.one.com/", None, None), + one_match(entries, "https://one.com/", None, None, 0, false), + "one" + ); + assert!( + no_matches(entries, "https://login.one.com/", None, None, false), + "one" + ); + assert!( + one_match(entries, "https://one.com:443/", None, None, 0, false), "one" ); + assert!(no_matches(entries, "one.com", None, None, false), "one"); + assert!(no_matches(entries, "https", None, None, false), "one"); + assert!(no_matches(entries, "com", None, None, false), "one"); assert!( - one_match(entries, "https://one.com:443/", None, None, 0), + no_matches(entries, "https://com/", None, None, false), "one" ); - assert!(no_matches(entries, "one.com", None, None), "one"); - assert!(no_matches(entries, "https", None, None), "one"); - assert!(no_matches(entries, "com", None, None), "one"); - assert!(no_matches(entries, "https://com/", None, None), "one"); assert!( - one_match(entries, "https://two.com/login", None, None, 1), + one_match(entries, "https://two.com/login", None, None, 1, false), + "two" + ); + assert!( + one_match( + entries, + "https://two.com/login/sso", + None, + None, + 1, + false + ), "two" ); assert!( - one_match(entries, "https://two.com/login/sso", None, None, 1), + no_matches(entries, "https://two.com/", None, None, false), "two" ); - assert!(no_matches(entries, "https://two.com/", None, None), "two"); assert!( - no_matches(entries, "https://two.com/other-page", None, None), + no_matches( + entries, + "https://two.com/other-page", + None, + None, + false + ), "two" ); assert!( - one_match(entries, "https://login.three.com/", None, None, 2), + one_match( + entries, + "https://login.three.com/", + None, + None, + 2, + false + ), "three" ); assert!( - no_matches(entries, "https://three.com/", None, None), + no_matches(entries, "https://three.com/", None, None, false), "three" ); } @@ -2525,40 +2829,68 @@ mod test { ), ]; - assert!(one_match(entries, "https://one.com/", None, None, 0), "one"); assert!( - no_matches(entries, "https://login.one.com/", None, None), + one_match(entries, "https://one.com/", None, None, 0, false), + "one" + ); + assert!( + no_matches(entries, "https://login.one.com/", None, None, false), "one" ); assert!( - one_match(entries, "https://one.com:443/", None, None, 0), + one_match(entries, "https://one.com:443/", None, None, 0, false), + "one" + ); + assert!(no_matches(entries, "one.com", None, None, false), "one"); + assert!(no_matches(entries, "https", None, None, false), "one"); + assert!(no_matches(entries, "com", None, None, false), "one"); + assert!( + no_matches(entries, "https://com/", None, None, false), "one" ); - assert!(no_matches(entries, "one.com", None, None), "one"); - assert!(no_matches(entries, "https", None, None), "one"); - assert!(no_matches(entries, "com", None, None), "one"); - assert!(no_matches(entries, "https://com/", None, None), "one"); assert!( - one_match(entries, "https://two.com/login", None, None, 1), + one_match(entries, "https://two.com/login", None, None, 1, false), + "two" + ); + assert!( + no_matches( + entries, + "https://two.com/login/sso", + None, + None, + false + ), "two" ); assert!( - no_matches(entries, "https://two.com/login/sso", None, None), + no_matches(entries, "https://two.com/", None, None, false), "two" ); - assert!(no_matches(entries, "https://two.com/", None, None), "two"); assert!( - no_matches(entries, "https://two.com/other-page", None, None), + no_matches( + entries, + "https://two.com/other-page", + None, + None, + false + ), "two" ); assert!( - one_match(entries, "https://login.three.com/", None, None, 2), + one_match( + entries, + "https://login.three.com/", + None, + None, + 2, + false + ), "three" ); assert!( - no_matches(entries, "https://three.com/", None, None), + no_matches(entries, "https://three.com/", None, None, false), "three" ); } @@ -2595,48 +2927,77 @@ mod test { ), ]; - assert!(one_match(entries, "https://one.com/", None, None, 0), "one"); assert!( - no_matches(entries, "https://login.one.com/", None, None), + one_match(entries, "https://one.com/", None, None, 0, false), "one" ); assert!( - one_match(entries, "https://one.com:443/", None, None, 0), + no_matches(entries, "https://login.one.com/", None, None, false), + "one" + ); + assert!( + one_match(entries, "https://one.com:443/", None, None, 0, false), + "one" + ); + assert!(no_matches(entries, "one.com", None, None, false), "one"); + assert!(no_matches(entries, "https", None, None, false), "one"); + assert!(no_matches(entries, "com", None, None, false), "one"); + assert!( + no_matches(entries, "https://com/", None, None, false), "one" ); - assert!(no_matches(entries, "one.com", None, None), "one"); - assert!(no_matches(entries, "https", None, None), "one"); - assert!(no_matches(entries, "com", None, None), "one"); - assert!(no_matches(entries, "https://com/", None, None), "one"); assert!( - one_match(entries, "https://two.com/login", None, None, 1), + one_match(entries, "https://two.com/login", None, None, 1, false), + "two" + ); + assert!( + one_match(entries, "https://two.com/start", None, None, 1, false), "two" ); assert!( - one_match(entries, "https://two.com/start", None, None, 1), + one_match( + entries, + "https://two.com/login/sso", + None, + None, + 1, + false + ), "two" ); assert!( - one_match(entries, "https://two.com/login/sso", None, None, 1), + no_matches(entries, "https://two.com/", None, None, false), "two" ); - assert!(no_matches(entries, "https://two.com/", None, None), "two"); assert!( - no_matches(entries, "https://two.com/other-page", None, None), + no_matches( + entries, + "https://two.com/other-page", + None, + None, + false + ), "two" ); assert!( - one_match(entries, "https://login.three.com/", None, None, 2), + one_match( + entries, + "https://login.three.com/", + None, + None, + 2, + false + ), "three" ); assert!( - one_match(entries, "https://three.com/", None, None, 2), + one_match(entries, "https://three.com/", None, None, 2, false), "three" ); assert!( - no_matches(entries, "https://www.three.com/", None, None), + no_matches(entries, "https://www.three.com/", None, None, false), "three" ); } @@ -2691,48 +3052,78 @@ mod test { ), ]; - assert!(no_matches(entries, "https://one.com/", None, None), "one"); assert!( - no_matches(entries, "https://login.one.com/", None, None), + no_matches(entries, "https://one.com/", None, None, false), + "one" + ); + assert!( + no_matches(entries, "https://login.one.com/", None, None, false), + "one" + ); + assert!( + no_matches(entries, "https://one.com:443/", None, None, false), "one" ); + assert!(no_matches(entries, "one.com", None, None, false), "one"); + assert!(no_matches(entries, "https", None, None, false), "one"); + assert!(no_matches(entries, "com", None, None, false), "one"); assert!( - no_matches(entries, "https://one.com:443/", None, None), + no_matches(entries, "https://com/", None, None, false), "one" ); - assert!(no_matches(entries, "one.com", None, None), "one"); - assert!(no_matches(entries, "https", None, None), "one"); - assert!(no_matches(entries, "com", None, None), "one"); - assert!(no_matches(entries, "https://com/", None, None), "one"); - assert!(no_matches(entries, "https://two.com/", None, None), "two"); assert!( - no_matches(entries, "https://two.com/other-page", None, None), + no_matches(entries, "https://two.com/", None, None, false), + "two" + ); + assert!( + no_matches( + entries, + "https://two.com/other-page", + None, + None, + false + ), "two" ); assert!( - no_matches(entries, "https://login.three.com/", None, None), + no_matches( + entries, + "https://login.three.com/", + None, + None, + false + ), "three" ); assert!( - no_matches(entries, "https://three.com/", None, None), + no_matches(entries, "https://three.com/", None, None, false), "three" ); - assert!(no_matches(entries, "https://four.com/", None, None), "four"); + assert!( + no_matches(entries, "https://four.com/", None, None, false), + "four" + ); assert!( - no_matches(entries, "https://five.com:8080/", None, None), + no_matches(entries, "https://five.com:8080/", None, None, false), + "five" + ); + assert!( + no_matches(entries, "https://five.com/", None, None, false), "five" ); - assert!(no_matches(entries, "https://five.com/", None, None), "five"); assert!( - no_matches(entries, "https://six.com:8080/", None, None), + no_matches(entries, "https://six.com:8080/", None, None, false), + "six" + ); + assert!( + no_matches(entries, "https://six.com/", None, None, false), "six" ); - assert!(no_matches(entries, "https://six.com/", None, None), "six"); } #[track_caller] @@ -2742,6 +3133,7 @@ mod test { username: Option<&str>, folder: Option<&str>, idx: usize, + ignore_case: bool, ) -> bool { entries_eq( &find_entry_raw( @@ -2749,6 +3141,7 @@ mod test { &parse_needle(needle).unwrap(), username, folder, + ignore_case, ) .unwrap(), &entries[idx], @@ -2761,12 +3154,14 @@ mod test { needle: &str, username: Option<&str>, folder: Option<&str>, + ignore_case: bool, ) -> bool { let res = find_entry_raw( entries, &parse_needle(needle).unwrap(), username, folder, + ignore_case, ); if let Err(e) = res { format!("{e}").contains("no entry found") @@ -2781,12 +3176,14 @@ mod test { needle: &str, username: Option<&str>, folder: Option<&str>, + ignore_case: bool, ) -> bool { let res = find_entry_raw( entries, &parse_needle(needle).unwrap(), username, folder, + ignore_case, ); if let Err(e) = res { format!("{e}").contains("multiple entries found") diff --git a/src/bin/rbw/main.rs b/src/bin/rbw/main.rs index 2fb96bf..8e75404 100644 --- a/src/bin/rbw/main.rs +++ b/src/bin/rbw/main.rs @@ -85,6 +85,8 @@ enum Opt { raw: bool, #[structopt(long, help = "Copy result to clipboard")] clipboard: bool, + #[structopt(short, long, help = "Ignore case")] + ignorecase: bool, }, #[command( @@ -100,6 +102,8 @@ enum Opt { folder: Option, #[structopt(long, help = "Copy result to clipboard")] clipboard: bool, + #[arg(short, long, help = "Ignore case")] + ignorecase: bool, }, #[command( @@ -198,6 +202,8 @@ enum Opt { user: Option, #[arg(long, help = "Folder name to search in")] folder: Option, + #[arg(short, long, help = "Ignore case")] + ignorecase: bool, }, #[command(about = "Remove a given entry", visible_alias = "rm")] @@ -208,6 +214,8 @@ enum Opt { user: Option, #[arg(long, help = "Folder name to search in")] folder: Option, + #[arg(short, long, help = "Ignore case")] + ignorecase: bool, }, #[command(about = "View the password history for a given entry")] @@ -218,6 +226,8 @@ enum Opt { user: Option, #[arg(long, help = "Folder name to search in")] folder: Option, + #[arg(short, long, help = "Ignore case")] + ignorecase: bool, }, #[command(about = "Lock the password database")] @@ -330,6 +340,7 @@ fn main() { full, raw, clipboard, + ignorecase, } => commands::get( needle, user.as_deref(), @@ -338,17 +349,20 @@ fn main() { *full, *raw, *clipboard, + *ignorecase, ), Opt::Code { needle, user, folder, clipboard, + ignorecase, } => commands::code( needle, user.as_deref(), folder.as_deref(), *clipboard, + *ignorecase, ), Opt::Add { name, @@ -400,15 +414,39 @@ fn main() { ty, ) } - Opt::Edit { name, user, folder } => { - commands::edit(name, user.as_deref(), folder.as_deref()) - } - Opt::Remove { name, user, folder } => { - commands::remove(name, user.as_deref(), folder.as_deref()) - } - Opt::History { name, user, folder } => { - commands::history(name, user.as_deref(), folder.as_deref()) - } + Opt::Edit { + name, + user, + folder, + ignorecase, + } => commands::edit( + name, + user.as_deref(), + folder.as_deref(), + *ignorecase, + ), + Opt::Remove { + name, + user, + folder, + ignorecase, + } => commands::remove( + name, + user.as_deref(), + folder.as_deref(), + *ignorecase, + ), + Opt::History { + name, + user, + folder, + ignorecase, + } => commands::history( + name, + user.as_deref(), + folder.as_deref(), + *ignorecase, + ), Opt::Lock => commands::lock(), Opt::Purge => commands::purge(), Opt::StopAgent => commands::stop_agent(), From 84396e9506bbf297b8354411d1882f6445d86ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20G=C3=B6tsch?= Date: Wed, 20 Mar 2024 22:52:56 +0100 Subject: [PATCH 2/2] Ignore clippy warning. --- src/bin/rbw/commands.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs index d64ea5a..3939adf 100644 --- a/src/bin/rbw/commands.rs +++ b/src/bin/rbw/commands.rs @@ -991,6 +991,7 @@ pub fn list(fields: &[String]) -> anyhow::Result<()> { Ok(()) } +#[allow(clippy::fn_params_excessive_bools)] pub fn get( needle: &Needle, user: Option<&str>,