diff --git a/README.md b/README.md index 0f6b28a..8990919 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -A search provider for GNOME Shell that adds support for searching in zx2c4/[pass](https://www.passwordstore.org/). +A search provider for GNOME Shell that adds support for searching passwords in zx2c4/[pass](https://www.passwordstore.org/) or in the [rbw](https://github.com/doy/rbw) Bitwarden/Vaultwarden client. Names of passwords will show up in GNOME Shell searches, choosing one will copy the corresponding content to the clipboard. -Supports OTP, fields and can use GPaste. +Supports OTP, fields (pass only) and can use GPaste (pass or rbw). ![Sreencapture](misc/screencapture.gif) @@ -29,7 +29,7 @@ dnf install gnome-pass-search-provider ## Manual -Ensure that python>=3.5 as well as the dbus, gobject, fuzzywuzzy Python modules are installed. They should all be packaged under python-name or python3-name depending on your distribution. +Ensure that python>=3.7 as well as the dbus, gobject and fuzzywuzzy Python modules are installed. They should all be packaged under python-name or python3-name depending on your distribution. Clone this repository and run the installation script as root: ``` @@ -62,6 +62,10 @@ To copy the pin start the search with `:pin` and for the username with `:user`. The [pass-otp](https://github.com/tadfisher/pass-otp) extension is supported. Searches starting with `otp` will copy the otp token to the clipboard. +# Bitwarden/Vaultwarden + +If [rbw](https://github.com/doy/rbw) is installed, it can be used instead of pass by prefixing a search with `bw`. Non prefixed searches will still go through pass if present. + # Environment variables If you are configuring `pass` through environment variables, such as `PASSWORD_STORE_DIR`, make sure to set them in a way that will propagate to the search provider executable, not just in your shell. diff --git a/gnome-pass-search-provider.py b/gnome-pass-search-provider.py index 8524d9c..3230772 100755 --- a/gnome-pass-search-provider.py +++ b/gnome-pass-search-provider.py @@ -51,6 +51,7 @@ class SearchPassService(dbus.service.Object): bus_name = "org.gnome.Pass.SearchProvider" _object_path = "/" + bus_name.replace(".", "/") + use_bw = False def __init__(self): self.session_bus = dbus.SessionBus() @@ -66,7 +67,14 @@ class SearchPassService(dbus.service.Object): @dbus.service.method(in_signature="as", out_signature="as", **sbn) def GetInitialResultSet(self, terms): - return self.get_result_set(terms) + try: + if terms[0] == "bw": + self.use_bw = True + return self.get_bw_result_set(terms) + except NameError: + pass + self.use_bw = False + return self.get_pass_result_set(terms) @dbus.service.method(in_signature="as", out_signature="aa{sv}", **sbn) def GetResultMetas(self, ids): @@ -81,13 +89,31 @@ class SearchPassService(dbus.service.Object): @dbus.service.method(in_signature="asas", out_signature="as", **sbn) def GetSubsearchResultSet(self, previous_results, new_terms): - return self.get_result_set(new_terms) + if self.use_bw: + return self.get_bw_result_set(new_terms) + else: + return self.get_pass_result_set(new_terms) @dbus.service.method(in_signature="asu", terms="as", timestamp="u", **sbn) def LaunchSearch(self, terms, timestamp): pass - def get_result_set(self, terms): + def get_bw_result_set(self, terms): + name = "".join(terms[1:]) + + password_list = subprocess.check_output( + ["rbw", "list"], stderr=subprocess.STDOUT, universal_newlines=True + ).split("\n")[:-1] + + results = [ + e[0] + for e in process.extract( + name, password_list, limit=5, scorer=fuzz.partial_ratio + ) + ] + return results + + def get_pass_result_set(self, terms): if terms[0] == "otp": field = terms[0] elif terms[0].startswith(":"): @@ -180,7 +206,9 @@ class SearchPassService(dbus.service.Object): def send_password_to_clipboard(self, name): field = None - if name.startswith("otp "): + if self.use_bw: + base_args = ["rbw", "get"] + elif name.startswith("otp "): base_args = ["pass", "otp", "code"] name = name[4:] else: