# Pick password from local or remote password-store with rofi's dmenu emulation # mode, and write it to the active X11 window. Optionally, prefix it with the # username, being the last part of the slash-delimited password's name, and # a TAB press to move to the next field in a form. # self=rofi_pass # Abstraction to handle running shell commands (args or stdin) in either # a remote or local shell. If the environment variable PASSWORD_STORE_HOST is # set, it's used as the destination SSH hostname to the password store. # pass_shell() { [ "$#" -le 1 ] || return if [ -n "$PASSWORD_STORE_HOST" ] ; then ssh -o StrictHostKeyChecking=yes -T -X -- \ "$PASSWORD_STORE_HOST" "$@" elif [ "$#" -eq 1 ] ; then "${SHELL:-/bin/sh}" -c "$1" else "${SHELL:-/bin/sh}" -s fi } # Get a list of all the password paths, relative to the password store root, # including leading dot-slash and trailing .gpg extension. # get_paths() { pass_shell <<-'EOF' dir=${PASSWORD_STORE_DIR:-"$HOME"/.password-store} cd -- "$dir" || exit find . -name \*.gpg -type f || exit EOF } # Get a list of all the password names, bytewise-sorted, with leading dot-slash # and trailing .gpg extension removed. # get_names() { get_paths | sed -e 's_^[.]/__' -e 's_[.]gpg$__' | LC_COLLATE=C sort -f } # Write a password name to a shell to retrieve it, and read its first line; # write the name safely to the shell's input rather than as an argument. # get_password() { name=$1 [ -n "$name" ] || return printf '%s\n' "$name" | pass_shell 'IFS= read -r name ; pass show "$name"' | head -n 1 } # Check for --login/-l option to paste a username-password combo, not just the # password (defaults to the latter). # login=0 case $1 in --login|-l) login=1 ;; esac # Apply rofi -dmenu to pick a password name. Use case-insensitive matching, # and don't accept arbitrary input. # name=$(get_names | rofi -dmenu -i -no-lazy-grab -only_match -p pass) || exit [ -n "$name" ] || exit # Retrieve the username for the chosen password, and then the secret itself; # check that we actually got more than an empty string back in both cases. # username=${name##*/} [ -n "$username" ] || exit password=$(get_password "$name") || exit [ -n "$password" ] || exit # Have xdotool type either the username-TAB-password, or just the password; # receiving it on its standard input rather than its arguments, for security. # if [ "$login" -eq 1 ] ; then printf '%s\t%s' \ "$username" "$password" else printf '%s' \ "$password" fi | xdotool type --clearmodifiers --delay=0 --file - || exit # Tell the user we wrote the password out, in case they're typing a password # into a field with echo turned off. # notify-send --app-name="$self" --icon=gcr-password -- \ 'Password typed' "$name"