jasonwryan.com

Miscellaneous ephemera…

pass{,word} manager

After posting last week about KeePassC as a password manager, a couple of people immediately commented about a utility billed as “the standard Unix password manager.” This is definitely one of the reasons I continue to write up my experiences with free and open source software: as soon as you think that you have learned something, someone will either offer a correction or encourage you to explore something else that is similar, related or interesting for some other tangential reason.

So, I was off down that path… Called simply pass, it is a 600 line bash script that uses GPG encryption and some other standard tools and scripts to organize and manage your password files. I had never heard of it but, based on Cayetano and Bigby’s recommendations, I thought it would be worth a look.

On of the reasons that I had not come across it before was that, after using KeePassX for so long, I had assumed that I would need to continue to use that database format; so when I was looking for an alternative, KeePassC was a natural fit (and a fine application). The question of migrating my data hadn’t even occurred to me…

It turns out that the migration process to pass is extraordinarily well catered for: there are 10 migration scripts for a range of different formats, including keepassx2pass.py, which takes the exported XML KeePassX database file and creates your pass files,ordered by the schema you had used in that application. You just need to make sure you amend the shebang to python2 before running the script, otherwise it will fail with an unhelpful error message.

After using KeePassX to dump my database, before I could use the script to create my pass directories, I had to export the PASSWORD_STORE_DIR environment variable to place the top level pass directory in an alternate location. This way, instead of initializing a git repository, I could have the store synced by Syncthing. The git idea is a good one, but I’m not particularly interested in version controlling these directories, and I have no intention, encrypted or not, of pushing them to someone else’s server.

That constitutes the basic setup. It took a grand total of five minutes. The real strength of pass, however, is in its integration with two other fantastic tools: keychain and dmenu. Together with pass, these constitute a secure, convenient and effortless workflow for managing your passwords. With your GPG key loaded into keychain, you are only prompted for your master passphrase once1 and with Chris Down’s excellent passmenu script, you can use dmenu to sort through your password files, Tab complete the one you are looking for and have it copied to your clipboard with a couple of keystrokes.

After using Chris' script for a couple of days, I made a few alterations to suit my setup: removed the xdotool stuff (as I don’t need it), included dmenu formatting options to match my dwm statusbar and, most significantly, changed the way that the files are printed in dmenu to remove the visual clutter of the parent directories, ie., print archwiki as opposed to internet/archwiki:

dpass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env bash
# based on: https://github.com/cdown/passmenu

shopt -s nullglob globstar

nb='#121212'
nf='#696969'
sb='#121212'
sf='#914E89'
font="Dejavu Sans Mono:medium:size=7.5"
dmenucmd=( dmenu -i -fn "$font" -nb "$nb" -nf "$nf" -sb "$sb" -sf "$sf" )

prefix=${PASSWORD_STORE_DIR:-~/.password-store}
files=( "$prefix"/**/*.gpg )
files=( "${files[@]#"$prefix"/}" )
files=( "${files[@]%.gpg}" )
fbase=( "${files[@]##*/}" )

word=$(printf '%s\n' "${fbase[@]}" | "${dmenucmd[@]}" "$@")

if [[ -n $word ]]; then
  for match in "${files[@]}"; do  
    if [[ $word == ${match#*/} ]]; then
      /usr/bin/pass show -c "$match" 2>/dev/null
    fi  
  done
fi

It does introduce some more complexity into the script, but it makes it a lot easier for me to identify the desired password when reading it in dmenu.

Now, when I need a to enter a password, I hit my dmenu hotkey, type dpass Enter and the first couple of letters of the desired password filename, TabEnter and the password is loaded and ready to go. There are also completion scripts for the main shells, and even one for fish2 for the iconoclasts…

While I have no complaints at all with KeePassC, I have found this pass setup to be a lot less intrusive to use, it seamlessly integrates with my workflow, and the passwords themselves are much simpler to manage. Short of someone else popping up in the comments with another compelling proposition, I’m content with the way this has worked out. Many thanks to Cayetano Santos and Bigby James for the push.

Notes

  1. There is a very annoying bug open for keychain that means if, as I do, you start keychain from your $HOME/.profile or $ZDOTDIR/.zprofile you will need to enter the same passphrase to unlock a sub-key before you can use pass (the same thing applies to Mutt). This gets really ugly if you attempt to use dmenu before unlocking your key…
  2. Finally, a command line shell for the 90s… Indeed.

Creative Commons image by Intel Free Press on Flickr.

Comments