#!/bin/sh # Ref: http://info2html.sourceforge.net/cgi-bin/info2html-demo/info2html?%28pinentry%29Protocol set -e VERSION="0.1"; if [ -z "$DISPLAY" ]; then DISPLAY=":1"; export DISPLAY; fi prompt_string_default="PIN: " title=""; prompt_string="$prompt_string_default"; description=""; keyinfo=""; repeat=""; error__password_mismatch="Passwords don't match"; AP_YES="Yes"; AP_NO="No"; prompt_action='/home/tavo/.config/scripts/menu/menu "$AP_PROMPT" pass'; confirm_action='echo -e "$AP_YES\n$AP_NO" | /home/tavo/.config/scripts/menu/menu "$AP_PROMPT"'; display_error_action='notify-send -a "Pinentry" "$AP_ERROR"'; # :: Prompt string (default if empty) ask_password() { export AP_PROMPT="${1:-"$prompt_string"}"; printf '' | sh -c "$prompt_action" 2> /dev/null; } # :: Prompt string (default if empty) confirm() { export AP_PROMPT="${1:-"$prompt_string"}"; export AP_YES; export AP_NO; printf '' | sh -c "$confirm_action" 2> /dev/null; } # :: Error text show_error() { export AP_ERROR="$1"; sh -c "$display_error_action" 2> /dev/null; } cancelled_error() { echo "ERR 83886179 Operation cancelled <Pinentry>"; } com_error() { echo "ERR 83886360 IP parameter error <Pinentry>>"; } not_implemented_error() { echo "ERR 536870981 Not implemented <User defined source 1>"; } unknown_error() { echo "ERR 536871187 Unknown IPC command <User defined source 1>"; } reset() { description= prompt_string="$prompt_string_default" keyinfo= repeat= error__password_mismatch= setok= setnotok= setcancel= title= } save_option() { echo "OK"; } get_info() { arg=$(echo "$1" | tr a-z A-Z) case "$arg" in VERSION) echo "D $VERSION" && echo "OK" ;; PID) echo "D $$" && echo "OK" ;; *) com_error ;; esac; } # :: Repeat string -> Password -> OK | ERR password_prompt() { pass=""; if pass=$(ask_password "$([ -z "$1" ] && echo "$repeat")"); then if [ -n "$1" ]; then password_prompt "" "$pass"; else # If password repeat attempt failed, try again, # Else continue if [ -n "$2" ] && [ "$pass" != "$2" ]; then show_error "$error__password_mismatch"; password_prompt "$repeat"; else if [ ! -z "$pass" ]; then echo "D $pass" | sed 's/%/%25/; s/\r/%0D/' | # % = 25 and CR = %0D awk 'BEGIN {ORS="%0A"} /^..*$/ {print}' | # LF = %0A sed 's/%0A$//' # Strip trailing %0A echo fi echo "OK"; fi; fi; else cancelled_error; fi; repeat= } # :: OK | ERR confirm_prompt() { if [ "$(confirm)" = "$AP_YES" ]; then echo "OK" else cancelled_error; fi } pinentry_help() { cat <<END # NOP # CANCEL # OPTION # BYE # AUTH # RESET # END # HELP # SETDESC # SETPROMPT # SETKEYINFO # SETREPEAT # SETREPEATERROR # SETERROR # SETOK # SETNOTOK # SETCANCEL # GETPIN # CONFIRM # MESSAGE # SETQUALITYBAR # SETQUALITYBAR_TT # SETGENPIN # SETGENPIN_TT # GETINFO # SETTITLE # SETTIMEOUT # CLEARPASSPHRASE END } interpret_command() { # Refuse lines of more than 1000 bytes + newline if [ $(echo "$1" | wc -c) -gt 1001 ]; then echo "ERR too long" return fi cmd="$(echo "$1" | cut -d' ' -f1 | tr a-z A-Z)"; data="$(echo "$1" | cut -d' ' -f2-)"; case "${cmd}" in NOP) ;; CANCEL) not_implemented_error ;; OPTION) save_option "$data" ;; BYE) exit 0 ;; AUTH) not_implemented_error ;; RESET) reset ;; END) not_implemented_error ;; HELP) pinentry_help ;; SETDESC) description="$data"; echo "OK" ;; SETPROMPT) prompt_string="$data"; echo "OK" ;; SETKEYINFO) keyinfo="$data"; echo "OK" ;; SETREPEAT) repeat="${data:-"repeat"}"; echo "OK" ;; SETREPEATERROR) error__password_mismatch="$data"; echo "OK" ;; SETERROR) not_implemented_error ;; SETOK) setok="$data" ;; SETNOTOK) setnotok="$data" ;; SETCANCEL) setcancel="$data" ;; GETPIN) password_prompt "$repeat" "" ;; CONFIRM) confirm_prompt ;; MESSAGE) not_implemented_error ;; SETQUALITYBAR) not_implemented_error ;; SETQUALITYBAR_TT) not_implemented_error ;; SETGENPIN) not_implemented_error ;; SETGENPIN_TT) not_implemented_error ;; GETINFO) get_info "$data" ;; SETTITLE) title="$data"; echo "OK" ;; SETTIMEOUT) not_implemented_error ;; CLEARPASSPHRASE) not_implemented_error ;; '' | \#*) ;; *) unknown_error ;; esac; } help() { echo "Usage: $0 [-D DISPLAY] [--prompt script] [--confirm script] [-hv]"; cat <<END $0 (pinentry) $VERSION Copyright (C) 2020 Akshay Nair This software is released under the MIT License <https://www.mit-license.org/> END printf "Usage: %s [options] (-h for help)\n" "$0" >&2 cat <<END Ask securely for a secret and print it to stdout. Options: --prompt CMD How to ask for the secret --confirm CMD How to confirm the secret --error-command CMD What to do if secret is not confirmed CMD will be executed by sh(1). The defaults are: prompt ='dmenu -P -p "$prompt_string"'; confirm ='echo -e "$AP_YES\n$AP_NO" | dmenu -p "$prompt_string"'; error-command ='notify-send -a "Pinentry" "$error__password_mismatch"'; Standard pinentry options -d, --debug Turn on debugging output -D, --display DISPLAY Set the X display -T, --ttyname FILE Set the tty terminal node name -N, --ttytype NAME Set the tty terminal type -C, --lc-ctype STRING Set the tty LC_CTYPE value -M, --lc-messages STRING Set the tty LC_MESSAGES value -o, --timeout SECS Timeout waiting for input after this many seconds -g, --no-global-grab Grab keyboard only while window is focused -W, --parent-wid Parent window ID (for positioning) -c, --colors STRING Set custom colors for ncurses -a, --ttyalert STRING Set the alert mode (none, beep or flash) Please report bugs to <https://github.com/phenax/any-pinentry/issues>. END } parse_cliargs() { getopt -T || exit_status=$? if [ $exit_status -ne 4 ]; then printf "Your version of getopt(1) is out of date\n" >&2 exit 1 fi TEMP=$(getopt -n "$0" -o dD:T:N:C:M:o:gWc:a:h \ --long debug,display:,ttyname:,ttytype:,lc-ctype:,lc-messages:,timeout:,no-global-grab,parent-wid,colors:,ttyalert:,prompt:,confirm:,error:,help,version \ -- "$@") if [ $? -ne 0 ]; then help exit 1 fi eval set -- "$TEMP" unset TEMP while true; do case "$1" in -d | --debug) shift ;; -D | --display) shift 2 ;; -T | --ttyname) shift 2 ;; -N | --ttytype) shift 2 ;; -C | --lc-ctype) shift 2 ;; -M | --lc-messages) shift 2 ;; -o | --timeout) shift 2 ;; -g | --no-global-grab) shift ;; -W | --parent-wid) shift ;; -c | --colors) echo "colors=$2"; shift 2 ;; -a | --ttyalert) shift 2 ;; --error-command) display_error_action="$2"; shift 2 ;; --prompt) prompt_action="$2"; shift 2 ;; --confirm) confirm_action="$2"; shift 2 ;; -h | --help) help && exit 0 ;; --version) echo "anypinentry-$VERSION" && exit 0 ;; --) shift; break ;; *) ;; esac done } # Main parse_cliargs "$@"; # Initialize protocol echo "OK Pleased to meet you" while read -r line; do interpret_command "$line"; done; # "SETERROR" # "SETOK" # "SETNOTOK" # "SETCANCEL" # "MESSAGE" # "SETQUALITYBAR" # "SETQUALITYBAR_TT" # "SETTIMEOUT" # "CLEARPASSPHRASE"