From 2236d7fec8131404b47ac74c172719c8fbd8dadf Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Tue, 11 Jan 2022 17:47:30 +0100 Subject: [PATCH 1/2] Reformat file --- pass-pick | 476 +++++++++++++++++++++++++++--------------------------- 1 file changed, 238 insertions(+), 238 deletions(-) diff --git a/pass-pick b/pass-pick index 5c76db1..48ddeec 100755 --- a/pass-pick +++ b/pass-pick @@ -57,137 +57,137 @@ # Passes along any options given to main script. rofi_opts=("$@") _picker() { - if [ -n "$PICKER_BACKEND" ]; then - "${PICKER_BACKEND[@]}" - elif command -v rofi 1>/dev/null 2>/dev/null; then - rofi -dmenu -no-auto-select -i "${rofi_opts[@]}" "$@" -p "entry" - elif command -v bemenu 1>/dev/null 2>/dev/null; then - bemenu -l 20 -i -p "entry >" - elif command -v dmenu 1>/dev/null 2>/dev/null; then - dmenu -i -p "entry >" - else - printf "%s: 📦 %s must be installed for %s function.\n" "critical" "rofi/bemenu/dmenu" "this" >&2 - notify-send "📦 rofi/bemenu/dmenu" --urgency="critical" "must be installed for this function." - exit 1 - fi + if [ -n "$PICKER_BACKEND" ]; then + "${PICKER_BACKEND[@]}" + elif command -v rofi 1>/dev/null 2>/dev/null; then + rofi -dmenu -no-auto-select -i "${rofi_opts[@]}" "$@" -p "entry" + elif command -v bemenu 1>/dev/null 2>/dev/null; then + bemenu -l 20 -i -p "entry >" + elif command -v dmenu 1>/dev/null 2>/dev/null; then + dmenu -i -p "entry >" + else + printf "%s: 📦 %s must be installed for %s function.\n" "critical" "rofi/bemenu/dmenu" "this" >&2 + notify-send "📦 rofi/bemenu/dmenu" --urgency="critical" "must be installed for this function." + exit 1 + fi } # copies to clipboard, removes any trailing newlines, # and only keeps it in for 1 paste (1 loop to read in script, 1 to output) _clipper() { - if command -v wl-copy 1>/dev/null 2>/dev/null; then - wl-copy -o -n - elif command -v xclip 1>/dev/null 2>/dev/null; then - xclip -i -selection 'clipboard' -loops 2 -rmlastnl - elif command -v xsel 1>/dev/null 2>/dev/null; then - xsel -b - else - notify-send "No clipboard utility" "Install wl-copy, xclip or xsel." - fi + if command -v wl-copy 1>/dev/null 2>/dev/null; then + wl-copy -o -n + elif command -v xclip 1>/dev/null 2>/dev/null; then + xclip -i -selection 'clipboard' -loops 2 -rmlastnl + elif command -v xsel 1>/dev/null 2>/dev/null; then + xsel -b + else + notify-send "No clipboard utility" "Install wl-copy, xclip or xsel." + fi } # parse, see https://unix.stackexchange.com/a/331965/8541 _parse_config() { - (grep -e "^$2=" -m 1 "$1" 2>/dev/null || printf "var=__UNDEFINED__\n") | head -n1 | cut -d '=' -f 2- + (grep -e "^$2=" -m 1 "$1" 2>/dev/null || printf "var=__UNDEFINED__\n") | head -n1 | cut -d '=' -f 2- } # read config file get_config() { - local locations=( - "$PP_CONFIGURATION_FILE" - "${xdg_config_home:-$HOME/.config}/pass-picker/pass-picker.conf" - "$HOME/.pass-picker.conf" - "/etc/pass-picker.conf" - ) + local locations=( + "$PP_CONFIGURATION_FILE" + "${xdg_config_home:-$HOME/.config}/pass-picker/pass-picker.conf" + "$HOME/.pass-picker.conf" + "/etc/pass-picker.conf" + ) - # return the first config file with a valid path - for config in "${locations[@]}"; do - if [[ -n "$config" && -f "$config" ]]; then - # see if the config has been given a value - local val - val="$(_parse_config "$config" "$1")" - break - fi - done + # return the first config file with a valid path + for config in "${locations[@]}"; do + if [[ -n $config && -f $config ]]; then + # see if the config has been given a value + local val + val="$(_parse_config "$config" "$1")" + break + fi + done - # if there was a config file but no value - # or there was no config file at all - if [ "$val" = "__UNDEFINED__" ] || [ -z "$val" ]; then - val="$2" - fi - printf -- "%s" "$val" + # if there was a config file but no value + # or there was no config file at all + if [ "$val" = "__UNDEFINED__" ] || [ -z "$val" ]; then + val="$2" + fi + printf -- "%s" "$val" } set_defaults() { - # The location of the pass-picker config file - # PP_CONFIGURATION_FILE="~/.config/pass-picker/pass-picker.conf" - # set options, leaving already set environment variables intact - # try to read any settings from config files - PICKER_BACKEND="${PP_PICKER_BACKEND:-$(get_config PICKER_BACKEND)}" + # The location of the pass-picker config file + # PP_CONFIGURATION_FILE="~/.config/pass-picker/pass-picker.conf" + # set options, leaving already set environment variables intact + # try to read any settings from config files + PICKER_BACKEND="${PP_PICKER_BACKEND:-$(get_config PICKER_BACKEND)}" - KEY_AUTOFILL="${PP_KEY_AUTOFILL:-$(get_config KEY_AUTOFILL Return)}" - KEY_ENTRY_OPEN="${PP_KEY_ENTRY_OPEN:-$(get_config KEY_ENTRY_OPEN Alt+Return)}" - KEY_FILL_USER="${PP_KEY_FILL_USER:-$(get_config KEY_FILL_USER Alt+u)}" - KEY_CLIP_USER="${PP_KEY_CLIP_USER:-$(get_config KEY_CLIP_USER Ctrl+Alt+u)}" - KEY_FILL_PASS="${PP_KEY_FILL_PASS:-$(get_config KEY_FILL_PASS Alt+p)}" - KEY_CLIP_PASS="${PP_KEY_CLIP_PASS:-$(get_config KEY_CLIP_PASS Ctrl+Alt+p)}" - KEY_ENTRYMENU_FILL="${PP_KEY_ENTRYMENU_FILL:-$(get_config KEY_ENTRYMENU_FILL Return)}" - KEY_ENTRYMENU_CLIP="${PP_KEY_ENTRYMENU_CLIP:-$(get_config KEY_ENTRYMENU_CLIP Alt+Return)}" - KEY_ENTRYMENU_SHOWFIELD="${KEY_ENTRYMENU_SHOWFIELD:-$(get_config KEY_ENTRYMENU_SHOWFIELD Alt+s)}" - KEY_ENTRYMENU_QUIT="${PP_KEY_ENTRYMENU_QUIT:-$(get_config KEY_ENTRYMENU_QUIT Alt+BackSpace)}" + KEY_AUTOFILL="${PP_KEY_AUTOFILL:-$(get_config KEY_AUTOFILL Return)}" + KEY_ENTRY_OPEN="${PP_KEY_ENTRY_OPEN:-$(get_config KEY_ENTRY_OPEN Alt+Return)}" + KEY_FILL_USER="${PP_KEY_FILL_USER:-$(get_config KEY_FILL_USER Alt+u)}" + KEY_CLIP_USER="${PP_KEY_CLIP_USER:-$(get_config KEY_CLIP_USER Ctrl+Alt+u)}" + KEY_FILL_PASS="${PP_KEY_FILL_PASS:-$(get_config KEY_FILL_PASS Alt+p)}" + KEY_CLIP_PASS="${PP_KEY_CLIP_PASS:-$(get_config KEY_CLIP_PASS Ctrl+Alt+p)}" + KEY_ENTRYMENU_FILL="${PP_KEY_ENTRYMENU_FILL:-$(get_config KEY_ENTRYMENU_FILL Return)}" + KEY_ENTRYMENU_CLIP="${PP_KEY_ENTRYMENU_CLIP:-$(get_config KEY_ENTRYMENU_CLIP Alt+Return)}" + KEY_ENTRYMENU_SHOWFIELD="${KEY_ENTRYMENU_SHOWFIELD:-$(get_config KEY_ENTRYMENU_SHOWFIELD Alt+s)}" + KEY_ENTRYMENU_QUIT="${PP_KEY_ENTRYMENU_QUIT:-$(get_config KEY_ENTRYMENU_QUIT Alt+BackSpace)}" - AUTOFILL_BACKEND="${PP_AUTOFILL_BACKEND:-$(get_config AUTOFILL_BACKEND wtype)}" - AUTOFILL_CHAIN="${PP_AUTOENTRY_CHAIN:-$(get_config AUTOFILL_CHAIN 'username :tab password')}" - AUTOFILL_DELAY="${PP_AUTOENTRY_DELAY:-$(get_config AUTOFILL_DELAY 30)}" + AUTOFILL_BACKEND="${PP_AUTOFILL_BACKEND:-$(get_config AUTOFILL_BACKEND wtype)}" + AUTOFILL_CHAIN="${PP_AUTOENTRY_CHAIN:-$(get_config AUTOFILL_CHAIN 'username :tab password')}" + AUTOFILL_DELAY="${PP_AUTOENTRY_DELAY:-$(get_config AUTOFILL_DELAY 30)}" - PASS_USERNAME_FIELD="${PP_PASS_USERNAME_FIELD:-$(get_config PASS_USERNAME_FIELD 'username user login')}" - PASS_COFFIN_OPEN_TIME="${PP_PASS_COFFIN_OPEN_TIME:-$(get_config PASS_COFFIN_OPEN_TIME 0)}" - PASS_COFFIN_LOCATION="${PP_PASS_COFFIN_LOCATION:-$(get_config PASS_COFFIN_LOCATION)}" + PASS_USERNAME_FIELD="${PP_PASS_USERNAME_FIELD:-$(get_config PASS_USERNAME_FIELD 'username user login')}" + PASS_COFFIN_OPEN_TIME="${PP_PASS_COFFIN_OPEN_TIME:-$(get_config PASS_COFFIN_OPEN_TIME 0)}" + PASS_COFFIN_LOCATION="${PP_PASS_COFFIN_LOCATION:-$(get_config PASS_COFFIN_LOCATION)}" } # exit on escape pressed exit_check() { - [ "$1" -eq 1 ] && exit + [ "$1" -eq 1 ] && exit } # simply return a list of all passwords in pass store # TODO only show website names (+ folder names), and account names for multiple accounts on one site list_passwords() { - shopt -s nullglob globstar - prefix=${PASSWORD_STORE_DIR:-~/.password-store} - password_files=("$prefix"/**/*.gpg) - password_files=("${password_files[@]#"$prefix"/}") - password_files=("${password_files[@]%.gpg}") + shopt -s nullglob globstar + prefix=${PASSWORD_STORE_DIR:-~/.password-store} + password_files=("$prefix"/**/*.gpg) + password_files=("${password_files[@]#"$prefix"/}") + password_files=("${password_files[@]%.gpg}") - printf '%s\n' "${password_files[@]}" + printf '%s\n' "${password_files[@]}" } # return password for argument passed show_password() { - pass show "$1" | head -n1 + pass show "$1" | head -n1 } # send password to clipboard clip_password() { - pass show -c "$1" + pass show -c "$1" } # attempt to return the field specified # attempts all (space separated) fields until the # first one successfully returned _p_get_field() { - local gp_entry="$1" - local gp_field="$2" + local gp_entry="$1" + local gp_field="$2" - # return on first successfully returned key - for key in $gp_field; do - local value - value=$(_p_get_key_value "$gp_entry" "$key") + # return on first successfully returned key + for key in $gp_field; do + local value + value=$(_p_get_key_value "$gp_entry" "$key") - # found entry - if [ -n "$value" ]; then - echo "$value" && break - fi - done + # found entry + if [ -n "$value" ]; then + echo "$value" && break + fi + done } # returns the corresponding value for the key passed in @@ -195,210 +195,210 @@ _p_get_field() { # $1: pass (file) entry to search through # $2: string name of the containting key _p_get_key_value() { - local value - value=$(list_fields "$1" | grep "$2") + local value + value=$(list_fields "$1" | grep "$2") - # get everything after first colon, remove whitespace - echo "$value" | cut -d':' -f2- | tr -d '[:blank:]' + # get everything after first colon, remove whitespace + echo "$value" | cut -d':' -f2- | tr -d '[:blank:]' } # return username for argument passed # Prefers in-metadata username, falls back to filename show_username() { - result=$(_p_get_field "$1" "${PASS_USERNAME_FIELD}") - if [ -z "$result" ]; then - echo "${1##*/}" - fi + result=$(_p_get_field "$1" "${PASS_USERNAME_FIELD}") + if [ -z "$result" ]; then + echo "${1##*/}" + fi } clip_username() { - show_username "$1" "${PASS_USERNAME_FIELD}" | _clipper + show_username "$1" "${PASS_USERNAME_FIELD}" | _clipper } show_field() { - _p_get_field "$1" "$2" + _p_get_field "$1" "$2" } clip_field() { - show_field "$1" "$2" | _clipper + show_field "$1" "$2" | _clipper } list_fields() { - pass show "$1" | tail -n+2 + pass show "$1" | tail -n+2 } # invoke the dotool to type inputs _type() { - local tool="${AUTOFILL_BACKEND}" - local toolmode="$1" - local key="$2" + local tool="${AUTOFILL_BACKEND}" + local toolmode="$1" + local key="$2" - if [ "$tool" = "wtype" ]; then - if [ "$toolmode" = "type" ]; then - "$tool" -s "${AUTOFILL_DELAY}" -- "$key" - elif [ "$toolmode" = "key" ]; then - "$tool" -s "${AUTOFILL_DELAY}" -k "$key" - fi - elif [ "$tool" = "xdotool" ]; then - "$tool" "$toolmode" --delay "${AUTOFILL_DELAY}" "$key" - elif [ "$tool" = "ydotool" ]; then - "$tool" "$toolmode" --key-delay "${AUTOFILL_DELAY}" "$key" - else - "$tool" "$toolmode" "$key" - fi + if [ "$tool" = "wtype" ]; then + if [ "$toolmode" = "type" ]; then + "$tool" -s "${AUTOFILL_DELAY}" -- "$key" + elif [ "$toolmode" = "key" ]; then + "$tool" -s "${AUTOFILL_DELAY}" -k "$key" + fi + elif [ "$tool" = "xdotool" ]; then + "$tool" "$toolmode" --delay "${AUTOFILL_DELAY}" "$key" + elif [ "$tool" = "ydotool" ]; then + "$tool" "$toolmode" --key-delay "${AUTOFILL_DELAY}" "$key" + else + "$tool" "$toolmode" "$key" + fi } # automatically fill out fields # transform special chain entries into valid dotool commands autofill() { - local selected="${1}" - local autoentry_chain="${2}" + 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 "$(show_username "$selected")" ;; - "password") _type type "$(show_password "$selected")" ;; - ":direct") _type type "$selected" ;; - *) printf '%s' "$selected" ;; - esac - done + for part in $autoentry_chain; do + case "$part" in + ":tab") _type key Tab ;; + ":return") _type key Return ;; + ":space") _type key space ;; + "username") _type type "$(show_username "$selected")" ;; + "password") _type type "$(show_password "$selected")" ;; + ":direct") _type type "$selected" ;; + *) printf '%s' "$selected" ;; + esac + done } # opens a menu for the specified pass entry, containing its individual fields entrymenu() { - local entry="$1" - local deobfuscate="$2" - local k_entrymenu_fill="${KEY_ENTRYMENU_FILL}" - local k_entrymenu_clip="${KEY_ENTRYMENU_CLIP}" - local k_entrymenu_showfield="${KEY_ENTRYMENU_SHOWFIELD}" - local k_entrymenu_quit="${KEY_ENTRYMENU_QUIT}" + local entry="$1" + local deobfuscate="$2" + local k_entrymenu_fill="${KEY_ENTRYMENU_FILL}" + local k_entrymenu_clip="${KEY_ENTRYMENU_CLIP}" + local k_entrymenu_showfield="${KEY_ENTRYMENU_SHOWFIELD}" + local k_entrymenu_quit="${KEY_ENTRYMENU_QUIT}" - local pass - if [ "$deobfuscate" = "true" ]; then - pass="$(show_password "$entry")" - else - pass="(hidden)" - fi + local pass + if [ "$deobfuscate" = "true" ]; then + pass="$(show_password "$entry")" + else + pass="(hidden)" + fi - local field - field=$( - printf "password: %s\n%s" "$pass" "$(list_fields "$entry")" | - _picker \ - -kb-accept-entry "" \ - -kb-custom-1 "$k_entrymenu_fill" \ - -kb-custom-2 "$k_entrymenu_clip" \ - -kb-custom-3 "$k_entrymenu_quit" \ - -kb-custom-4 "$k_entrymenu_showfield" \ - -mesg " ᐊ $k_entrymenu_quit ᐊ | $k_entrymenu_fill: fill selection | $k_entrymenu_clip: clip selection | $k_entrymenu_showfield: reveal password" - ) - exit_value=$? - exit_check "$exit_value" + local field + field=$( + printf "password: %s\n%s" "$pass" "$(list_fields "$entry")" \ + | _picker \ + -kb-accept-entry "" \ + -kb-custom-1 "$k_entrymenu_fill" \ + -kb-custom-2 "$k_entrymenu_clip" \ + -kb-custom-3 "$k_entrymenu_quit" \ + -kb-custom-4 "$k_entrymenu_showfield" \ + -mesg " ᐊ $k_entrymenu_quit ᐊ | $k_entrymenu_fill: fill selection | $k_entrymenu_clip: clip selection | $k_entrymenu_showfield: reveal password" + ) + exit_value=$? + exit_check "$exit_value" - # get field name - field=${field%%:*} - case "$exit_value" in - "0" | "10") - if [ "$field" = "password" ]; then - autofill "$entry" "password" - else - autofill "$(show_field "$entry" "$field")" ":direct" - fi - exit 0 - ;; - "11") - if [ "$field" = "password" ]; then - clip_password "$entry" - else - clip_field "$entry" "$field" - fi - exit 0 - ;; - "12") - main - ;; - "13") - local toggle - if [ "$deobfuscate" = "true" ]; then - toggle=false - else - toggle=true - fi - entrymenu "$entry" "$toggle" - ;; - esac + # get field name + field=${field%%:*} + case "$exit_value" in + "0" | "10") + if [ "$field" = "password" ]; then + autofill "$entry" "password" + else + autofill "$(show_field "$entry" "$field")" ":direct" + fi + exit 0 + ;; + "11") + if [ "$field" = "password" ]; then + clip_password "$entry" + else + clip_field "$entry" "$field" + fi + exit 0 + ;; + "12") + main + ;; + "13") + local toggle + if [ "$deobfuscate" = "true" ]; then + toggle=false + else + toggle=true + fi + entrymenu "$entry" "$toggle" + ;; + esac } open_coffin() { - ## there's a closed coffin in our directory - if [ -f "${PASS_COFFIN_LOCATION:-${PASSWORD_STORE_DIR:-~/.password-store}/.coffin/coffin.tar.gpg}" ]; then - if [ "$PASS_COFFIN_OPEN_TIME" -eq 0 ]; then - coffin_should_close_instantly=true - pass open -t 1h # we still set a maximum time limit just to hedge against failures - else - pass open -t "${PASS_COFFIN_OPEN_TIME:-3h}" - fi - fi + ## there's a closed coffin in our directory + if [ -f "${PASS_COFFIN_LOCATION:-${PASSWORD_STORE_DIR:-~/.password-store}/.coffin/coffin.tar.gpg}" ]; then + if [ "$PASS_COFFIN_OPEN_TIME" -eq 0 ]; then + coffin_should_close_instantly=true + pass open -t 1h # we still set a maximum time limit just to hedge against failures + else + pass open -t "${PASS_COFFIN_OPEN_TIME:-3h}" + fi + fi } # make sure we remember to close the coffin if the program terminates close_coffin() { - if [ "$coffin_should_close_instantly" = true ]; then - pass close - fi + if [ "$coffin_should_close_instantly" = true ]; then + pass close + fi } trap close_coffin SIGINT SIGTERM ERR EXIT main() { - local autoentry_chain="${AUTOFILL_CHAIN}" - local k_autofill="${KEY_AUTOFILL}" - local k_fill_user="${KEY_FILL_USER}" - local k_clip_user="${KEY_CLIP_USER}" - local k_fill_pass="${KEY_FILL_PASS}" - local k_clip_pass="${KEY_CLIP_PASS}" - local k_submenu="${KEY_ENTRY_OPEN}" + local autoentry_chain="${AUTOFILL_CHAIN}" + local k_autofill="${KEY_AUTOFILL}" + local k_fill_user="${KEY_FILL_USER}" + local k_clip_user="${KEY_CLIP_USER}" + local k_fill_pass="${KEY_FILL_PASS}" + local k_clip_pass="${KEY_CLIP_PASS}" + local k_submenu="${KEY_ENTRY_OPEN}" - open_coffin + open_coffin - entry="$( - list_passwords | - _picker -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=$? + entry="$( + list_passwords \ + | _picker -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=$? - echo "$entry" - exit_check "$exit_value" - case "$exit_value" in - "0" | "10") - autofill "$entry" "$autoentry_chain" - ;; - "11") - clip_username "$entry" - ;; - "12") - clip_password "$entry" - ;; - "13") - autofill "$entry" "username" - ;; - "14") - autofill "$entry" "password" - ;; - "15") - entrymenu "$entry" - ;; - esac + echo "$entry" + exit_check "$exit_value" + case "$exit_value" in + "0" | "10") + autofill "$entry" "$autoentry_chain" + ;; + "11") + clip_username "$entry" + ;; + "12") + clip_password "$entry" + ;; + "13") + autofill "$entry" "username" + ;; + "14") + autofill "$entry" "password" + ;; + "15") + entrymenu "$entry" + ;; + esac - exit 0 + exit 0 } set_defaults From 6dc0cd6d16f9c6723b3ee02562dec9f2b6595e67 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Tue, 11 Jan 2022 17:50:24 +0100 Subject: [PATCH 2/2] Fix regression for username fallback While usernames were now picked up correctly as a fallback from the filename if none were present in the fields themselves, if there were any in the fields the program would return an empty string. This fixes it for both cases, the username existing in the entry fields or only in the filename. Entry fields will still take precedence. --- pass-pick | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pass-pick b/pass-pick index 48ddeec..79a07a7 100755 --- a/pass-pick +++ b/pass-pick @@ -208,6 +208,8 @@ show_username() { result=$(_p_get_field "$1" "${PASS_USERNAME_FIELD}") if [ -z "$result" ]; then echo "${1##*/}" + else + echo "$result" fi }