#!/bin/bash # Code belongs to https://github.com/carnager/rofi-pass/ # Copyright (C) 2019 carnager # rofi wrapper. Add custom settings here. _rofi() { 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_check() { exit_value=$1 if [[ "${exit_value}" == "1" ]]; then exit fi } 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() { gopass list --flat } autopass() { local entry local autotype entry="${1}" autotype="$(gopass show "${entry}" autotype)" autotype="${autotype:-username :tab pass}" 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 ;; 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")" exit_value=$? exit_check "${exit_value}" case "${exit_value}" in "10") autopass "${entry}" exit ;; "11") printf '%s' "$(gopass show "${entry}" username)" | _dotool type exit ;; "12") printf '%s' "$(gopass show --password "${entry}")" | _dotool type exit ;; esac do_menu "${entry}" } main