homepage - tags - github - site code
Jun 18 2020
With increasing frequency of corporate hacks and password dumps, using a password manager has become more and more important recently. While many "password manager as a service" tools like Dashlane or 1Password exist, there are also open-source options like KeePass, gopass, and pass.
I personally use pass
to manage passwords. While there are many tutorials out there on setting up GPG keys, using pass
, using its git integration, and using apps built for pass
, this post focuses more on some of the minor "quality of life" tweaks I've done to make using it easier.
I use a nested hierarchy to keep my passwords and sensitive codes somewhat organized:
$ pass list
Password Store
├── social
│ ├── discord
│ ├── irc
│ └── keybase
├── banks
│ ├── bank1
│ ├── cc1
│ └── cc2
/* snipped */
But attempting to tab-complete for passwords when I don't immediately remember which directory they're in can be tedious. Enter fzf, a command-line fuzzy finder. If you're not using this already, you should check it out, but one of the things I used it for is fuzzy tab completion of passwords. Based off of a snippet in fzf's wiki, I dropped this snippet in a file sourced by my shell startup:
# $XDG_CONFIG_HOME/fzf/fzf_aliases
# pass completion suggested by @d4ndo (#362) (slightly modified)
_fzf_complete_pass() {
_fzf_complete '+m' "$@" < <(
local pwdir=${PASSWORD_STORE_DIR-~/.password-store/}
find "$pwdir" -name "*.gpg" -print |
sed -e "s#${pwdir}/\{0,1\}##" |
sed -e 's/\(.*\)\.gpg/\1/'
)
}
And now I can simply use fzf's default trigger **
for fuzzy tab-completion:
$ pass show gith**[TAB]
$ pass show gith**
> gith
2/215
> backups/github1
social/github.com
pinentry-curses
for CLI usageSince I use browserpass
- which I highly recommend - for web page logins, I need pass
to be able to query a GUI pinentry program for my master password (you need to enter this every time you query a password from your password store). However, many times I'll copy or show a password using the command-line, and in those cases I'd prefer pass
to fall back to using pinentry-curses
, rather than a GUI pop-up.
I found this post by Kevin Locke a while back detailing this problem. Relevant post text copied here:
As a result of Task 799, GnuPG 2.08 and later pass the
PINENTRY_USER_DATA
environment
variable from the calling environment to gpg-agent to pinentry. The format of this variable
is not specified (and not used by any programs in the standard pinentry collection that I can
find). pinentry-mac assumes it is a comma-separated sequence of NAME=VALUE pairs with no quoting
or escaping and recognizes USE_CURSES=1 to control curses fallback. I adopted this convention
for a simple pinentry script which chooses the UI based on the presence ofUSE_TTY=1
in$PINENTRY_USER_DATA
:
The original post includes a script which I have slightly modified for my use on macOS:
#! /usr/bin/env bash
# Based on:
# https://kevinlocke.name/bits/2019/07/31/prefer-terminal-for-gpg-pinentry
set -Ceu
case "${PINENTRY_USER_DATA-}" in
*USE_TTY=1*)
exec /usr/local/bin/pinentry-curses "$@"
;;
*)
# fallback
exec /usr/local/bin/pinentry-mac "$@"
;;
esac
On Linux, similar to the original post, you would use pinentry-x11
rather than pinentry-mac
for the GUI fallback.
Note - the paths may have to be edited somewhat if you've installed these binaries to different locations.
And to use it (re-copied for posterity from post):
To use this script for pinentry:
- Save the script (e.g. as
~/bin/pinentry-auto
).- Make it executable (
chmod +x pinentry-auto
).- Add
pinentry-program /path/to/pinentry-auto
to~/.gnupg/gpg-agent.conf
.export PINENTRY_USER_DATA=USE_TTY=1
in environments where prompting via TTY is desired (e.g. alongside$GPG_TTY
in~/.bashrc
).
When testing pass
with this updated pinentry, make sure to execute gpgconf --kill gpg-agent
after editing ~/.gnupg/gpg-agent.conf
.
I like to have my tools and scripts easily installable, so I screwed around a little and made a homebrew formula for slightly easier install of this script on macOS.
The introductory commit can be seen in my homebrew tap. This formula utilizes some common patterns for formulae, such as the use of inreplace
and using the fully-qualified path of a formula with #{Formula["pinentry"].opt_bin}
.
Check out homebrew's formula cookbook for more information, or take a look at the homebrew formula files - usually found in $(brew --prefix)/Homebrew/Library/Taps/homebrew/homebrew-core/Formula
.