From c241352a7b87ffce8e03d8054821581e5b9bce66 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 14 May 2020 17:43:10 +0200 Subject: [PATCH] [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. --- gopass/.local/bin/rofi-gopass | 165 ++++++++++++++++++++++++++-------- 1 file changed, 127 insertions(+), 38 deletions(-) diff --git a/gopass/.local/bin/rofi-gopass b/gopass/.local/bin/rofi-gopass index bc5865f..8e86ba8 100755 --- a/gopass/.local/bin/rofi-gopass +++ b/gopass/.local/bin/rofi-gopass @@ -1,6 +1,6 @@ #!/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 @@ -26,7 +26,20 @@ # default key bindings # 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 # can take multiple names, separated by space @@ -37,7 +50,7 @@ _rofi() { # TODO add check for dmenu 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 @@ -49,17 +62,17 @@ exit_check() { # simply return a list of all passwords in gopass store # TODO choose password store # TODO only show website names (+ folder names), and account names for multiple accounts on one site -_gp_list_passwords() { +list_passwords() { gopass list --flat } # return password for argument passed -_gp_show_password() { +show_password() { gopass show -f --password "$1" } # send password to clipboard -_gp_clip_password() { +clip_password() { gopass show -c "$1" } @@ -69,12 +82,12 @@ _gp_clip_password() { _gp_get_field() { local gp_entry="$1" local gp_field="$2" - local gp_opt="$3" + local clip="$3" for key in $gp_field; do # return on first successfully returned key - if [ -n "$gp_opt" ]; then - gopass show "$gp_opt" -f "$gp_entry" "$key" && break + if [ -n "$clip" ]; then + gopass show -c "$gp_entry" "$key" && break else gopass show -f "$gp_entry" "$key" && break fi @@ -82,69 +95,145 @@ _gp_get_field() { } # return username for argument passed -_gp_show_username() { +show_username() { _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" } +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 _type() { - local tool - local toolmode - local key - tool="${BACKEND:-xdotool}" - toolmode="$1" - key="$2" + local tool="${BACKEND:-xdotool}" + local toolmode="$1" + local key="$2" - "$tool" "$toolmode" --delay "${AUTOENTRY_DELAY:-20}" "$key" + "$tool" "$toolmode" --delay "${AUTOENTRY_DELAY:-30}" "$key" } # automatically enter entry chain, set via AUTOENTRY_CHAIN # transform special chain entries into valid dotool commands -autoentry() { - local selected - local autoentry_chain - selected="${1}" - autoentry_chain="${AUTOENTRY_CHAIN:-username :tab password}" +autofill() { + local selected="${1}" + local autoentry_chain="${2}" for part in $autoentry_chain; do case "$part" in ":tab") _type key Tab ;; ":return") _type key Return ;; ":space") _type key space ;; - "username") _type type "$(_gp_show_username "$selected")" ;; - "password") _type type "$(_gp_show_password "$selected")" ;; - *) printf '%s' "$part" ;; + "username") _type type "$(show_username "$selected")" ;; + "password") _type type "$(show_password "$selected")" ;; + ":direct") _type type "$selected" ;; + *) printf '%s' "$selected" ;; esac done } -main() { - # 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")" +# opens a menu for the specified gopass entry, containing its individual fields +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_check "$exit_value" - exit_check "${exit_value}" - case "${exit_value}" in - # autoentry selected + # get field name + field=${field%%:*} + case "$exit_value" in "10") - autoentry "${entry}" - exit + if [ "$field" = "password" ]; then + autofill "$entry" "password" + else + autofill "$(show_field "$entry" "$field")" ":direct" + fi + exit 0 ;; "11") - printf '%s' "$(gopass show "${entry}" username)" | _dotool type - exit + if [ "$field" = "password" ]; then + 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") - 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 ;; esac - do_menu "${entry}" } main