Add support for setting executable name through environment variables,

thus allowing to use gopass or other pass-compatible alternatives.

Make bitwarden support work without the need for prefixing queries and
without requiring GPaste.

Improve README, in particular to show how to configure behavior with env
vars.
This commit is contained in:
Jonathan Lestrelin 2022-07-01 17:55:19 +02:00
parent 2acdad58c0
commit 42508b271f
3 changed files with 100 additions and 48 deletions

View File

@ -1,8 +1,16 @@
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.
A search provider for GNOME Shell that adds support for searching in:
Names of passwords will show up in GNOME Shell searches, choosing one will copy the corresponding content to the clipboard.
* zx2c4/[pass](https://www.passwordstore.org/)
* compatible alternatives such as [gopass](https://www.gopass.pw/)
* or the [rbw](https://github.com/doy/rbw) Bitwarden/Vaultwarden client
Can use the [GPaste](https://github.com/Keruspe/GPaste) clipboard manager, supports OTP and fields (pass only, requires GPaste).
Names of entries will show up in GNOME Shell searches, choosing one will copy the corresponding content to the clipboard.
Supports:
* using the [GPaste](https://github.com/Keruspe/GPaste) clipboard manager
* OTP with the [pass-otp](https://github.com/tadfisher/pass-otp) extension
* fields (cf below for syntax)
![Sreencapture](misc/screencapture.gif)
@ -49,7 +57,13 @@ The search provider will be loaded automatically when doing a search.
You should see it enabled in GNOME Settings, in the Search pane. This is also where you can move it up or down in the list of results relatively to other search providers.
# Fields
# Advanced usage
## OTP
The [pass-otp](https://github.com/tadfisher/pass-otp) extension is supported. Searches starting with `otp` will copy the otp token to the clipboard.
## Fields
To copy other values than the password in the first line from a pass file, start the search with `:NAME search...`. The field name must be a full but case insensitive match. This requires `GPaste`.
@ -62,38 +76,72 @@ pin: 123456
To copy the pin start the search with `:pin` and for the username with `:user`.
# OTP
# Alternative password providers
The [pass-otp](https://github.com/tadfisher/pass-otp) extension is supported. Searches starting with `otp` will copy the otp token to the clipboard.
## Gopass and other pass-compatible tools
# Bitwarden/Vaultwarden
If you want to use [gopass](https://www.gopass.pw/) or another `pass` compatible tool instead of `pass`, you need to set the proper environment variables to point to the executable and password store directory to use.
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.
For example, on a systemd-based OS, you can run `systemctl --user edit org.gnome.Pass.SearchProvider.service` and add in the file:
# Environment variables
```
[Service]
Environment=PASSWORD_EXECUTABLE=gopass
Environment=PASSWORD_STORE_DIR=/home/jonathan/.local/share/gopass/stores/root
```
(be careful not leave a trailing "/" at the end of the `PASSWORD_STORE_DIR` path)
Then save and restart the service with `systemctl --user restart org.gnome.Pass.SearchProvider.service`.
On other systems, you might want to use `~/.profile` or another mechanism to set these environment variables.
## Bitwarden/Vaultwarden
To search in Bitwarden/Vaultwarden instead of `pass`, you will need to setup [rbw](https://github.com/doy/rbw). You'll also need to install `wl-clipboard` or another clipboard utility (such as `xclip`), unless you use GPaste.
You need to set the proper environment variables to point to the executables and specify to operate in Bitwarden mode.
For example, on a systemd-based OS, you can run `systemctl --user edit org.gnome.Pass.SearchProvider.service` and add in the file:
```
[Service]
Environment=PASSWORD_EXECUTABLE=rbw
Environment=PASSWORD_MODE=bw
Environment=CLIPBOARD_EXECUTABLE=wl-copy
```
Then save and restart the service with `systemctl --user restart org.gnome.Pass.SearchProvider.service`.
On other systems, you might want to use `~/.profile` or another mechanism to set these environment variables.
# Clipboard managers
By default, passwords are sent to the clipboard using `pass -c`, which defaults to expiration after 45 seconds.
If [GPaste](https://github.com/Keruspe/GPaste) is installed, passwords be sent to it marked as passwords through its API, thus ensuring they are not visible in the UI.
# Compatibility
This implements the `org.gnome.Shell.SearchProvider2` D-Bus API and has been tested with GNOME Shell 3.22 to 42. This uses the `org.gnome.GPaste1` or `org.gnome.GPaste2` versions of the GPaste D-Bus API to add passwords to GPaste.
# Troubleshooting
## Environment variables have no effect
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.
Setting them in `~/.profile` (or `~/.pam_environment` if supported by your OS) should be sufficient, but stuff in shell-specific files such as `~/.bashrc` will not be picked up by gnome-shell.
Setting them in `~/.profile` should be sufficient, but keep in mind that stuff in shell-specific files such as `~/.bashrc` only affects the command-line shell and will not propagate to the script. On systemd-based OSes, you can also directly set them in `~/.config/environment.d/*.conf` (see `man environment.d`).
If your values have no effect, make sure they propagate to the script environment. You can check this with ps:
If your values have no effect, make sure they propagate to the script environment. You can check this by displaying the process environment with `ps` and looking for your values here:
```
ps auxeww | grep [g]nome-pass-search-provider.py
```
# Clipboard managers
If you are using GPaste, passwords will be sent to it marked as passwords, thus ensuring they are not visible.
Otherwise they are sent to the clipboard using `pass -c` which defaults to expiration after 45 seconds.
# Compatibility
This implements the `org.gnome.Shell.SearchProvider2` D-Bus API and has been tested with GNOME Shell 3.22 to 40. This uses the `org.gnome.GPaste1` or `org.gnome.GPaste2` versions of the GPaste D-Bus API to add passwords to GPaste.
# Troubleshooting
## Passphrase is not requested to unlock store
If you don't see passphrase prompts when your key is locked, it might be because GPG is not using the right pinentry program. You can force gpg-agent to use pinentry-gnome3 by adding `pinentry-program /usr/bin/pinentry-gnome3` to `~/.gnupg/gpg-agent.conf`.
## Other problems
If you encounter problems, make sure to look in the logs of GNOME and D-Bus. On systems that use systemd, you can do this using `journalctl --user`.
Don't hesitate to open an issue.

View File

@ -56,7 +56,6 @@ 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()
@ -65,6 +64,9 @@ class SearchPassService(dbus.service.Object):
self.password_store = getenv("PASSWORD_STORE_DIR") or expanduser(
"~/.password-store"
)
self.password_executable = getenv("PASSWORD_EXECUTABLE") or "pass"
self.password_mode = getenv("PASSWORD_MODE") or "pass"
self.clipboard_executable = getenv("CLIPBOARD_EXECUTABLE") or "wl-copy"
@dbus.service.method(in_signature="sasu", **sbn)
def ActivateResult(self, id, terms, timestamp):
@ -72,14 +74,10 @@ class SearchPassService(dbus.service.Object):
@dbus.service.method(in_signature="as", out_signature="as", **sbn)
def GetInitialResultSet(self, 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)
if self.password_mode == "bw":
return self.get_bw_result_set(terms)
else:
return self.get_pass_result_set(terms)
@dbus.service.method(in_signature="as", out_signature="aa{sv}", **sbn)
def GetResultMetas(self, ids):
@ -94,7 +92,7 @@ class SearchPassService(dbus.service.Object):
@dbus.service.method(in_signature="asas", out_signature="as", **sbn)
def GetSubsearchResultSet(self, previous_results, new_terms):
if self.use_bw:
if self.password_mode == "bw":
return self.get_bw_result_set(new_terms)
else:
return self.get_pass_result_set(new_terms)
@ -104,10 +102,10 @@ class SearchPassService(dbus.service.Object):
pass
def get_bw_result_set(self, terms):
name = "".join(terms[1:])
name = "".join(terms)
password_list = subprocess.check_output(
["rbw", "list"], universal_newlines=True
[self.password_executable, "list"], universal_newlines=True
).split("\n")[:-1]
results = [
@ -158,12 +156,10 @@ class SearchPassService(dbus.service.Object):
"org.gnome.GPaste.Daemon", "/org/gnome/GPaste"
)
output = subprocess.check_output(
base_args + [name], universal_newlines=True
)
output = subprocess.check_output(base_args + [name], universal_newlines=True)
if field is not None:
match = re.search(
fr"^{field}:\s*(?P<value>.+?)$", output, flags=re.I | re.M
rf"^{field}:\s*(?P<value>.+?)$", output, flags=re.I | re.M
)
if match:
password = match.group("value")
@ -177,24 +173,32 @@ class SearchPassService(dbus.service.Object):
gpaste.AddPassword(name, password, dbus_interface="org.gnome.GPaste2")
def send_password_to_native_clipboard(self, base_args, name, field=None):
if field is not None or self.use_bw:
if field is not None:
raise RuntimeError("This feature requires GPaste.")
result = subprocess.run(base_args + ["-c", name])
if result.returncode:
raise RuntimeError(
f"Error while running pass: got return code {result.returncode}."
)
if self.password_mode == "bw":
p1 = subprocess.Popen(base_args + [name], stdout=subprocess.PIPE)
p2 = subprocess.run(self.clipboard_executable, stdin=p1.stdout)
if p1.returncode or p2.returncode:
raise RuntimeError(
f"Error while running rbw: got return codes: {p1.returncode} {p2.returncode}."
)
else:
result = subprocess.run(base_args + ["-c", name])
if result.returncode:
raise RuntimeError(
f"Error while running pass: got return code: {result.returncode}."
)
def send_password_to_clipboard(self, name):
field = None
if self.use_bw:
base_args = ["rbw", "get"]
if self.password_mode == "bw":
base_args = [self.password_executable, "get"]
elif name.startswith("otp "):
base_args = ["pass", "otp", "code"]
base_args = [self.password_executable, "otp", "code"]
name = name[4:]
else:
base_args = ["pass", "show"]
base_args = [self.password_executable, "show"]
if name.startswith(":"):
field, name = name.split(" ", 1)
field = field[1:]

View File

@ -16,7 +16,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-build
%global debug_package %{nil}
%description
A Gnome Shell passwords search provider for zx2c4/pass (passwordstore.org) and Bitwarden/Vaultwarden that sends passwords to clipboard (or GPaste).
A Gnome Shell passwords search provider for zx2c4/pass (passwordstore.org) or compatibles and Bitwarden/Vaultwarden that sends passwords to clipboard (or GPaste).
%prep
%setup -q -n %{name}-%{version}