aboutsummaryrefslogtreecommitdiff
path: root/rofi/bin/rofi_pass.sh
diff options
context:
space:
mode:
Diffstat (limited to 'rofi/bin/rofi_pass.sh')
-rw-r--r--rofi/bin/rofi_pass.sh92
1 files changed, 92 insertions, 0 deletions
diff --git a/rofi/bin/rofi_pass.sh b/rofi/bin/rofi_pass.sh
new file mode 100644
index 00000000..fb31a454
--- /dev/null
+++ b/rofi/bin/rofi_pass.sh
@@ -0,0 +1,92 @@
+# 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"