[gopass] Enable clipboard paste and entry submenu

Added opening individual gopass entries in a rofi submenu (default
Alt+Return). Allows copying any individual field to the clipboard, or
directly autofilling them individually as well.

Quick fill/copy is enabled from the main menu for usernames and
passwords individually.
This commit is contained in:
Marty Oehme 2020-05-14 17:43:10 +02:00
parent 03e8b3b9b5
commit c241352a7b
No known key found for this signature in database
GPG key ID: 0CCB0526EFB9611A

View file

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Code originally inspired by https://github.com/carnager/rofi-pass/ # Original inspiration from https://github.com/carnager/rofi-pass/
# DEFAULT OPTIONS # DEFAULT OPTIONS
@ -26,7 +26,20 @@
# default key bindings # default key bindings
# Automatically enter username and password # Automatically enter username and password
# KEY_AUTOENTRY="Return" # KEY_AUTOFILL="Return"
# Automatically enter username only
# KEY_FILL_USER="Alt+u"
# Add username to clipboard
# KEY_CLIP_USER="Ctrl+Alt+u"
# Automatically enter password only
# KEY_FILL_PASS="Alt+p"
# Add password to clipboard
# KEY_CLIP_PASS="Ctrl+Alt+p"
# For the individual gopass entry:
# Automatically fill selected field
# KEY_ENTRYMENU_FILL="Return"
# Add field to clipboard
# KEY_ENTRYMENU_CLIP="Alt+Return"
# The field name containing your gopass username # The field name containing your gopass username
# can take multiple names, separated by space # can take multiple names, separated by space
@ -37,7 +50,7 @@
_rofi() { _rofi() {
# TODO add check for dmenu # TODO add check for dmenu
exist rofi critical "rofi-pass" || exit 0 exist rofi critical "rofi-pass" || exit 0
rofi -dmenu -no-auto-select -i "$@" -theme /themes/dmenu rofi -dmenu -no-auto-select -i "$@"
} }
# exit on escape pressed # exit on escape pressed
@ -49,17 +62,17 @@ exit_check() {
# simply return a list of all passwords in gopass store # simply return a list of all passwords in gopass store
# TODO choose password store # TODO choose password store
# TODO only show website names (+ folder names), and account names for multiple accounts on one site # TODO only show website names (+ folder names), and account names for multiple accounts on one site
_gp_list_passwords() { list_passwords() {
gopass list --flat gopass list --flat
} }
# return password for argument passed # return password for argument passed
_gp_show_password() { show_password() {
gopass show -f --password "$1" gopass show -f --password "$1"
} }
# send password to clipboard # send password to clipboard
_gp_clip_password() { clip_password() {
gopass show -c "$1" gopass show -c "$1"
} }
@ -69,12 +82,12 @@ _gp_clip_password() {
_gp_get_field() { _gp_get_field() {
local gp_entry="$1" local gp_entry="$1"
local gp_field="$2" local gp_field="$2"
local gp_opt="$3" local clip="$3"
for key in $gp_field; do for key in $gp_field; do
# return on first successfully returned key # return on first successfully returned key
if [ -n "$gp_opt" ]; then if [ -n "$clip" ]; then
gopass show "$gp_opt" -f "$gp_entry" "$key" && break gopass show -c "$gp_entry" "$key" && break
else else
gopass show -f "$gp_entry" "$key" && break gopass show -f "$gp_entry" "$key" && break
fi fi
@ -82,69 +95,145 @@ _gp_get_field() {
} }
# return username for argument passed # return username for argument passed
_gp_show_username() { show_username() {
_gp_get_field "$1" "${GOPASS_USERNAME_FIELD:-"username user login"}" _gp_get_field "$1" "${GOPASS_USERNAME_FIELD:-"username user login"}"
} }
_gp_clip_username() { clip_username() {
_gp_get_field "$1" "${GOPASS_USERNAME_FIELD:-"username user login"}" "-c" _gp_get_field "$1" "${GOPASS_USERNAME_FIELD:-"username user login"}" "-c"
} }
show_field() {
_gp_get_field "$1" "$2"
}
clip_field() {
_gp_get_field "$1" "$2" "-c"
}
list_fields() {
gopass show -f "$1" | tail -n+2
}
# invoke the dotool to type inputs # invoke the dotool to type inputs
_type() { _type() {
local tool local tool="${BACKEND:-xdotool}"
local toolmode local toolmode="$1"
local key local key="$2"
tool="${BACKEND:-xdotool}"
toolmode="$1"
key="$2"
"$tool" "$toolmode" --delay "${AUTOENTRY_DELAY:-20}" "$key" "$tool" "$toolmode" --delay "${AUTOENTRY_DELAY:-30}" "$key"
} }
# automatically enter entry chain, set via AUTOENTRY_CHAIN # automatically enter entry chain, set via AUTOENTRY_CHAIN
# transform special chain entries into valid dotool commands # transform special chain entries into valid dotool commands
autoentry() { autofill() {
local selected local selected="${1}"
local autoentry_chain local autoentry_chain="${2}"
selected="${1}"
autoentry_chain="${AUTOENTRY_CHAIN:-username :tab password}"
for part in $autoentry_chain; do for part in $autoentry_chain; do
case "$part" in case "$part" in
":tab") _type key Tab ;; ":tab") _type key Tab ;;
":return") _type key Return ;; ":return") _type key Return ;;
":space") _type key space ;; ":space") _type key space ;;
"username") _type type "$(_gp_show_username "$selected")" ;; "username") _type type "$(show_username "$selected")" ;;
"password") _type type "$(_gp_show_password "$selected")" ;; "password") _type type "$(show_password "$selected")" ;;
*) printf '%s' "$part" ;; ":direct") _type type "$selected" ;;
*) printf '%s' "$selected" ;;
esac esac
done done
} }
main() { # opens a menu for the specified gopass entry, containing its individual fields
# entry="$(list_passwords | _rofi -kb-accept-entry "" -kb-custom-1 "${key_autotype}" -kb-custom-2 "${key_usertype}" -kb-custom-3 "${key_passtype}" -kb-custom-4 "${key_actions}" -mesg "${key_autotype}: Autotype | ${key_usertype}: Type User | ${key_passtype}: Type Pass | ${key_actions}: More Actions")" entrymenu() {
local entry="$1"
local k_entrymenu_fill="${KEY_ENTRYMENU_FILL:-Return}"
local k_entrymenu_clip="${KEY_ENTRYMENU_CLIP:-Alt+Return}"
entry="$(_gp_list_passwords | _rofi -kb-accept-entry "" -kb-custom-1 "${KEY_AUTOENTRY:-Return}")" local pass_obfuscation="(hidden)"
local field
field=$(
printf "password: %s\n%s" "$pass_obfuscation" "$(list_fields "$entry")" |
_rofi \
-kb-accept-entry "" \
-kb-custom-1 "$k_entrymenu_fill" \
-kb-custom-2 "$k_entrymenu_clip" \
-mesg "| $k_entrymenu_fill: fill selection | $k_entrymenu_clip: clip selection |"
)
exit_value=$? exit_value=$?
exit_check "$exit_value"
exit_check "${exit_value}" # get field name
case "${exit_value}" in field=${field%%:*}
# autoentry selected case "$exit_value" in
"10") "10")
autoentry "${entry}" if [ "$field" = "password" ]; then
exit autofill "$entry" "password"
else
autofill "$(show_field "$entry" "$field")" ":direct"
fi
exit 0
;; ;;
"11") "11")
printf '%s' "$(gopass show "${entry}" username)" | _dotool type if [ "$field" = "password" ]; then
exit clip_password "$entry"
else
clip_field "$entry" "$field"
fi
exit 0
;;
esac
}
main() {
local autoentry_chain="${AUTOENTRY_CHAIN:-username :tab password}"
local k_autofill="${KEY_AUTOFILL:-Return}"
local k_fill_user="${KEY_FILL_USER:-Alt+u}"
local k_clip_user="${KEY_CLIP_USER:-Ctrl+Alt+u}"
local k_fill_pass="${KEY_FILL_PASS:-Alt+p}"
local k_clip_pass="${KEY_CLIP_PASS:-Ctrl+Alt+p}"
local k_submenu="${KEY_CLIP_PASS:-Alt+Return}"
entry="$(
list_passwords |
_rofi -kb-accept-entry "" \
-kb-custom-1 "$k_autofill" \
-kb-custom-2 "$k_clip_user" \
-kb-custom-3 "$k_clip_pass" \
-kb-custom-4 "$k_fill_user" \
-kb-custom-5 "$k_fill_pass" \
-kb-custom-6 "$k_submenu" \
-mesg "| $k_autofill: fill credentials | $k_submenu: open entry | $k_fill_user: fill username | $k_fill_pass: fill password | $k_clip_user: clip username | $k_clip_pass: clip password |"
)"
exit_value=$?
exit_check "$exit_value"
case "$exit_value" in
"10")
autofill "$entry" "$autoentry_chain"
exit 0
;;
"11")
clip_username "$entry"
exit 0
;; ;;
"12") "12")
printf '%s' "$(gopass show --password "${entry}")" | _dotool type clip_password "$entry"
exit
;;
"13")
autofill "$entry" "username"
exit
;;
"14")
autofill "$entry" "password"
exit
;;
"15")
entrymenu "$entry"
exit exit
;; ;;
esac esac
do_menu "${entry}"
} }
main main