Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple entries with the same name confuse "get" #230

Open
sweharris opened this issue Jan 16, 2025 · 7 comments
Open

Multiple entries with the same name confuse "get" #230

sweharris opened this issue Jan 16, 2025 · 7 comments

Comments

@sweharris
Copy link

sweharris commented Jan 16, 2025

I have two entries for redhat; my RHN login and my bugzilla login

% rbw -V
rbw 1.13.2

% rbw search redhat
Business/<bugzilla_email>@redhat.com
Business/<rhn_email>@redhat.com

% rbw get redhat.com
rbw get: couldn't find entry for 'redhat.com': multiple entries found: <bugzilla_email>@redhat.com, <rhn_email>@redhat.com

% rbw get <rhn_email>@redhat.com                  
rbw get: couldn't find entry for '<rhn_email>@redhat.com': no entry found

% rbw get --folder Business <rhn_email>@redhat.com
rbw get: couldn't find entry for '<rhn_email>@redhat.com': no entry found

The only way I've been able to use "get" is to do an ls with the id field selected (% rbw ls --fields id,folder,user,name | grep redhat) and then get the entry by id. That would work in this case but may not work if I was searching for an entry, 'cos search just returns the name. Perhaps the "search" option should also have a --fields option similar to "ls", or maybe a --raw option to closer match bw list items --search redhat.com output?

But maybe I'm missing something?

@sedlund
Copy link

sedlund commented Jan 16, 2025

its a substring search

rbw get redhat.com bugzilla
rbw get redhat bug
rbw get redhat rhn

@sweharris
Copy link
Author

OK, so I can see how to programatically make that work (split on / to get the folder, split on last @ to get the name, the rest is the subsearch).

But that fails on another duplicate I have, which I just replicated with test entries; one is a login, and one is a credit card.

% rbw ls --fields=id,folder,name,user | grep Test
44ef6aae-b088-4fef-a0fa-0ef9586a21f3            Test
0315e272-b3d8-4dfa-a418-2b88a8599a96            Test    test1

%  rbw search test
test1@Test
Test

% rbw get --full Test
rbw get: couldn't find entry for 'Test': multiple entries found: test1@Test, Test

% rbw get --full Test test1
test
Username: test1

But I can't get the card details the same way because there's no second search parameter.

% rbw get --full 44ef6aae-b088-4fef-a0fa-0ef9586a21f3
12345
Name: test

@sedlund
Copy link

sedlund commented Jan 16, 2025

once you veer off of the basic use case you have to start using --raw to get what you want

@sweharris
Copy link
Author

Right, but search don't have the raw option (or even the ability to show the id), so how do I "address" the entry I want to get?

That's why I suggested that maybe search could have a --fields or a --raw option, which would work nicely (eg rbw search --raw test could return a JSON array of all matching entries; now it's up to the calling program to sort out what they need :-) ).

@sedlund
Copy link

sedlund commented Jan 16, 2025

in my case i changed the few entries to make them accessible

@sweharris
Copy link
Author

So I have never written a line of rust before in my life. But I think this diff might make sense?

It adds a --raw option to "search". In the search loop if we're in raw mode then we build a vector "json_entries" (and leave found_entries empty) and then display that as JSON at the end.

diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs
index 8433e66..b66f92a 100644
--- a/src/bin/rbw/commands.rs
+++ b/src/bin/rbw/commands.rs
@@ -1093,11 +1093,13 @@ pub fn get(
     Ok(())
 }
 
-pub fn search(term: &str, folder: Option<&str>) -> anyhow::Result<()> {
+pub fn search(term: &str, folder: Option<&str>, raw: bool) -> anyhow::Result<()> {
     unlock()?;
 
     let db = load_db()?;
 
+    let mut json_entries = vec![];
+
     let found_entries: Vec<_> = db
         .entries
         .iter()
@@ -1106,18 +1108,23 @@ pub fn search(term: &str, folder: Option<&str>) -> anyhow::Result<()> {
             entry
                 .map(|decrypted| {
                     if decrypted.search_match(term, folder) {
-                        let mut display = decrypted.name;
-                        if let DecryptedData::Login {
-                            username: Some(username),
-                            ..
-                        } = decrypted.data
-                        {
-                            display = format!("{username}@{display}");
-                        }
-                        if let Some(folder) = decrypted.folder {
-                            display = format!("{folder}/{display}");
+                        if raw {
+                            json_entries.push(decrypted);
+                            None
+                        } else {
+                            let mut display = decrypted.name;
+                            if let DecryptedData::Login {
+                                username: Some(username),
+                                ..
+                            } = decrypted.data
+                            {
+                                display = format!("{username}@{display}");
+                            }
+                            if let Some(folder) = decrypted.folder {
+                                display = format!("{folder}/{display}");
+                            }
+                            Some(display)
                         }
-                        Some(display)
                     } else {
                         None
                     }
@@ -1126,8 +1133,13 @@ pub fn search(term: &str, folder: Option<&str>) -> anyhow::Result<()> {
         })
         .collect::<Result<_, anyhow::Error>>()?;
 
-    for name in found_entries {
-        println!("{name}");
+    if raw {
+        let j = serde_json::to_string(&json_entries)?;
+        println!("{}",j);
+    } else {
+        for name in found_entries {
+            println!("{name}");
+        }
     }
 
     Ok(())
diff --git a/src/bin/rbw/main.rs b/src/bin/rbw/main.rs
index 6b58bd3..eb8b098 100644
--- a/src/bin/rbw/main.rs
+++ b/src/bin/rbw/main.rs
@@ -82,6 +82,8 @@ enum Opt {
         term: String,
         #[arg(long, help = "Folder name to search in")]
         folder: Option<String>,
+        #[structopt(long, help = "Display output as JSON")]
+	raw: bool,
     },
 
     #[command(
@@ -352,8 +354,8 @@ fn main() {
             false,
             *ignorecase,
         ),
-        Opt::Search { term, folder } => {
-            commands::search(term, folder.as_deref())
+        Opt::Search { term, folder, raw } => {
+            commands::search(term, folder.as_deref(), *raw)
         }
         Opt::Code {
             needle,

Example results:

% rbw search --raw nosuchentry
[]

% rbw search --raw test | jq .
[
  {
    "id": "0315e272-b3d8-4dfa-a418-2b88a8599a96",
    "folder": null,
    "name": "Test",
    "data": {
      "username": "test1",
      "password": "test",
      "totp": null,
      "uris": []
    },
    "fields": [],
    "notes": null,
    "history": []
  },
  {
    "id": "44ef6aae-b088-4fef-a0fa-0ef9586a21f3",
    "folder": null,
    "name": "Test",
    "data": {
      "cardholder_name": "test",
      "number": "12345",
      "brand": null,
      "exp_month": null,
      "exp_year": null,
      "code": null
    },
    "fields": [],
    "notes": null,
    "history": []
  }
]

Does this look sane? Should I propose it as a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
@sedlund @sweharris and others