[gopass] Fix simple autoentry of user credentials

Simplify gopass autoentry script heavily. Will pick up user credentials
from gopass store and enter them in whatever way the user wishes.

Fix key entry for changes in gopass 1.9.* password display options.

Several default variables can be customized, see the top of the
rofi-gopass file.
This commit is contained in:
Marty Oehme 2020-05-14 12:47:01 +02:00
parent 3796fa8ce5
commit 6fe0b66bd1
No known key found for this signature in database
GPG key ID: 0CCB0526EFB9611A

View file

@ -1,228 +1,116 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Code originally inspired by https://github.com/carnager/rofi-pass/
# Code belongs to https://github.com/carnager/rofi-pass/
# Copyright (C) 2019 carnager
# DEFAULT OPTIONS
# typing tool used, choice of:
# xdotool |
BACKEND=xdotool
# the complete typing chain autoentry uses
# possible fields:
# :tab | :space | :enter | username | password
#
# Note that spaces have to be passed explicitly with :space,
# putting a literal ' ' in the chain will not work
#
# By default it enters the username, tabs down, and enters the password
# It does not press return at the end for safety, though you can add
# :return to make it do so.
AUTOENTRY_CHAIN="username :tab password"
# wait time before entering each input
# in milliseconds
AUTOENTRY_DELAY=20
# default key bindings
# Automatically enter username and password
KEY_AUTOENTRY="Return"
# rofi wrapper. Add custom settings here.
_rofi() {
# TODO add check for dmenu
exist rofi critical "rofi-pass" || exit 0
rofi -dmenu -no-auto-select -i "$@" -theme /themes/dmenu
}
# default settings
backend=xdotool
dotool_delay=20
daemon_wait=2
autotype_delay=2
key_autotype="Return"
key_usertype="Alt+2"
key_passtype="Alt+3"
key_actions="Alt+a"
key_clipboard="Alt+1"
key_fieldtype="Return"
# read config file
get_config_file() {
configs=("$ROFI_PASS_CONFIG"
"$HOME/.config/rofi-pass/rofi-gopass.conf"
"/etc/rofi-gopass.conf")
# return the first config file with a valid path
for config in "${configs[@]}"; do
# '! -z' is needed in case ROFI_PASS_CONFIG is not set
if [[ ! -z "${config}" && -f "${config}" ]]; then
printf "%s" "$config"
return
fi
done
}
# Make sure ESC will always end the programm.
# Call this function with "exit_check $?" after each rofi call.
# exit on escape pressed
# rofi returns exit code 1 on esc
exit_check() {
exit_value=$1
if [[ "${exit_value}" == "1" ]]; then
exit
fi
[ "$1" -eq 1 ] && exit
}
clipboard() {
local entry
local key
local value
entry="${1}"
key="${2}"
value="$(gopass show "${entry}" "${key}")"
printf '%s' "${value}" | xclip -sel clip
notify-send "rofi-gopass" "Copied ${key} to clipboard\nClearing in 45 seconds."
(
sleep 45
printf '%s' "" | xclip
printf '%s' "" | xclip -selection clipboard | notify-send "rofi-gopass" "Clipboard cleared"
) &
exit
}
_ydotoold() {
if ! pgrep -x "ydotoold" >/dev/null; then
# ydotoold blocks the terminal, so we need to background it.
# Sadly this way we never know when the process finished starting up.
# Until ydotoold receives proper daemonizing we add a sleep value here.
ydotoold &
sleep "${daemon_wait}"
fi
}
_dotool() {
local mode
local key
mode="${1}"
key="${2:-null}"
case "${mode}" in
"type")
case "${backend}" in
"xdotool") xdotool type --delay "${dotool_delay}" --file - ;;
"ydotool")
_ydotoold
ydotool type --delay "${dotool_delay}" --file -
;;
esac
;;
"key")
case "${backend}" in
"xdotool") xdotool key "${key}" ;;
"ydotool")
_ydotoold
ydotool key "${key}"
;;
esac
;;
esac
}
list_passwords() {
# 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() {
gopass list --flat
}
autopass() {
local entry
local autotype
entry="${1}"
autotype="$(gopass show "${entry}" autotype)"
autotype="${autotype:-username :tab pass}"
# return password for argument passed
_gp_show_password() {
gopass show -f --password "$1"
}
for word in ${autotype}; do
case "$word" in
":tab") _dotool key Tab ;;
":space") _dotool key " " ;;
":delay") sleep "${autotype_delay}" ;;
":enter") _dotool key enter ;;
"pass") printf '%s' "$(gopass show --password "${entry}")" | _dotool type ;;
*) printf '%s' "$(gopass show "${entry}" "${word}")" | _dotool type ;;
GOPASS_USERNAME_ATTEMPTS="username user login"
# return username for argument passed
_gp_show_username() {
for key in $GOPASS_USERNAME_ATTEMPTS; do
done
gopass show -f "$1" username || gopass -f show "$1" user || gopass -f show "$1" login
}
# send password to clipboard
_gp_clip_password() {
gopass show -c "$1"
}
# invoke the dotool to type inputs
_type() {
local tool
local toolmode
local key
tool="${BACKEND}"
toolmode="$1"
key="$2"
"$tool" "$toolmode" --delay "$AUTOENTRY_DELAY" "$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}"
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" ;;
esac
done
}
list_keys() {
# gopass has no option to only list keys, so we need to build the list ourselves.
local entry
local keys
entry="${1}"
keys="$(gopass show "${entry}")"
printf '%s\n' "${keys}" | while read -r line; do
if [[ "${line}" == *": "* ]]; then
printf '%s\n' "${line%: *}"
fi
done
}
edit_key() {
local entry
local keys
entry="${1}"
keys="$(list_keys "${entry}")"
key_name=$(printf '%s\n' "${keys}" | _rofi -mesg "Enter new key or chose existing one")
exit_check $?
value_name=$(printf '%s' "" | _rofi -mesg "Enter Value for key \"${key_name}\"")
exit_check $?
if [[ -z "${key_name}" ]]; then
printf '%s' "${value_name}" | gopass insert -a "${entry}" "${key_name}"
else
printf '%s' "${value_name}" | gopass insert "${entry}" "${key_name}"
fi
}
# For dangerous operations call this function first. You can provide a message as argument.
# Example: confirm "Are you sure you want to delete entry?"
confirm() {
local message
message="${1}"
confirm_content=(
"Yes"
"No")
confirm_menu=$(printf '%s\n' "${confirm_content[@]}" | _rofi -mesg "${message}")
exit_check $?
case "${confirm_menu}" in
"Yes") : ;;
"No") exit ;;
esac
}
custom_type() {
local entry
local keys
entry="${1}"
keys="$(list_keys "${entry}")"
key_name=$(printf '%s\n' "${keys}" | _rofi -kb-accept-entry "" -no-custom -kb-custom-1 "${key_clipboard}" -kb-custom-2 "${key_fieldtype}" -mesg "${key_clipboard}: Copy to Clipboard | ${key_fieldtype}: Type Field")
local exit_value=$?
exit_check "${exit_value}"
case "${exit_value}" in
"10") clipboard "${entry}" "${key_name}" ;;
"11")
printf '%s' "$(gopass show "${entry}" "${key_name}")" | _dotool type
exit
;;
esac
}
do_menu() {
local entry
entry="${1}"
action_menu_content=(
"< Go Back"
"---"
"Show Fields"
"Add/Edit Keys"
"Generate New Password"
"Delete Entry"
)
action_menu="$(printf '%s\n' "${action_menu_content[@]}" | _rofi -no-custom -mesg "Selected Entry: ${entry}" -p '> ')"
exit_value=$?
exit_check "${exit_value}"
case "${action_menu}" in
"< Go Back") main ;;
"Show Fields") custom_type "${entry}" ;;
"Add/Edit Keys") edit_key "${entry}" ;;
"Delete Entry")
confirm "Delete ${entry}?"
gopass rm -f "${entry}"
;;
"Generate New Password")
confirm "Generate a new password for ${entry}?"
gopass generate -f "${entry}"
;;
esac
}
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")"
# 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")"
entry="$(_gp_list_passwords | _rofi -kb-accept-entry "" -kb-custom-1 "${KEY_AUTOENTRY}")"
exit_value=$?
exit_check "${exit_value}"
case "${exit_value}" in
# autoentry selected
"10")
autopass "${entry}"
autoentry "${entry}"
exit
;;
"11")