Hi all, I've added a command line flag to "pass show" so that a password may be automatically typed out using xdotool after a specified delay. The motivation for this is that the clipboard can be easily accessed, even without any administrator privileges, and typing out a password by hand is tedious. Client side web applications may also view clipboard contents, whereas a keylogger requires elevated privileges and is more difficult for an attacker to install on a your machine.
I've also ensured that the password doesn't appear in the output of a well timed "ps". This adds the optional dependency of "xdotool", should one want to use this feature. The flag may be used like so: "pass show --type=5 email/gmail" or "pass show -t5 email/gmail". If no argument is specified, the default delay of 3 seconds is used. The default may be changed using the PASSWORD_STORE_TYPE_DELAY environment variable. The delay may be anything "sleep" understands. If there are any bugs or issues with this patch, please let me know. Anas
From 0edba990503a8ab91df3bb9461cb63a92d432d53 Mon Sep 17 00:00:00 2001 From: Anas Syed <[email protected]> Date: Mon, 8 Feb 2016 12:53:10 +0000 Subject: [PATCH] Added feature to automatically type out the password after a delay This avoids the potential security issue of another program copying the clipboard contents, and also ensures that the password does not show up in a well timed `ps aux` and its variants --- README | 2 ++ man/pass.1 | 17 +++++++++++++++-- src/completion/pass.bash-completion | 2 +- src/completion/pass.fish-completion | 4 ++++ src/completion/pass.zsh-completion | 4 +++- src/password-store.sh | 22 ++++++++++++++++++---- 6 files changed, 43 insertions(+), 8 deletions(-) diff --git a/README b/README index 1cc01b9..541831b 100644 --- a/README +++ b/README @@ -28,3 +28,5 @@ Depends on: - GNU getopt http://www.kernel.org/pub/linux/utils/util-linux/ http://software.frodo.looijaard.name/getopt/ +- xdotool + http://www.semicomplete.com/projects/xdotool/ diff --git a/man/pass.1 b/man/pass.1 index 33b6036..11048ec 100644 --- a/man/pass.1 +++ b/man/pass.1 @@ -86,12 +86,19 @@ List names of passwords inside the tree that match \fIpass-names\fP by using the .BR tree (1) program. This command is alternatively named \fBsearch\fP. .TP -\fBshow\fP [ \fI--clip\fP[=\fIline-number\fP], \fI-c\fP[\fIline-number\fP] ] \fIpass-name\fP +\fBshow\fP [ \fI--clip\fP[=\fIline-number\fP], \fI-c\fP[\fIline-number\fP] ] \ +[ \fI--type\fP[=\fIdelay\fP], \fI-t\fP[\fIdelay\fP] ] \fIpass-name\fP Decrypt and print a password named \fIpass-name\fP. If \fI--clip\fP or \fI-c\fP is specified, do not print the password but instead copy the first (or otherwise specified) line to the clipboard using .BR xclip (1) -and then restore the clipboard after 45 (or \fIPASSWORD_STORE_CLIP_TIME\fP) seconds. +and then restore the clipboard after 45 (or \fIPASSWORD_STORE_CLIP_TIME\fP) +seconds. If \fI--type\fP or \fI-t\fP is specified, type out the password using +.BR xdotool (1) +after the specified delay. The default delay is 3 seconds, but may be set using +\fIPASSWORD_STORE_TYPE_DELAY\fP. The delay argument may be anything +.BR sleep (1) +understands. .TP \fBinsert\fP [ \fI--echo\fP, \fI-e\fP | \fI--multiline\fP, \fI-m\fP ] [ \fI--force\fP, \fI-f\fP ] \fIpass-name\fP Insert a new password into the password store called \fIpass-name\fP. This will @@ -413,6 +420,12 @@ for more info. Specifies the number of seconds to wait before restoring the clipboard, by default \fI45\fP seconds. .TP +.I PASSWORD_STORE_TYPE_DELAY +Specifies the time to wait before typing out the password, by default \fI3\fP +seconds. This can be anything +.BR sleep (1) +understands. +.TP .I PASSWORD_STORE_UMASK Sets the umask of all files modified by pass, by default \fI077\fP. .TP diff --git a/src/completion/pass.bash-completion b/src/completion/pass.bash-completion index 456485b..df64d34 100644 --- a/src/completion/pass.bash-completion +++ b/src/completion/pass.bash-completion @@ -98,7 +98,7 @@ _pass() _pass_complete_entries ;; show|-*) - COMPREPLY+=($(compgen -W "-c --clip" -- ${cur})) + COMPREPLY+=($(compgen -W "-c --clip -t --type" -- ${cur})) _pass_complete_entries 1 ;; insert) diff --git a/src/completion/pass.fish-completion b/src/completion/pass.fish-completion index c32a42c..ca4bc46 100644 --- a/src/completion/pass.fish-completion +++ b/src/completion/pass.fish-completion @@ -98,12 +98,16 @@ complete -c $PROG -f -A -n '__fish_pass_uses_command edit' -a "(__fish_pass_prin complete -c $PROG -f -A -n '__fish_pass_needs_command' -a show -d 'Command: show existing password' complete -c $PROG -f -A -n '__fish_pass_uses_command show' -s c -l clip -d 'Put password in clipboard' +complete -c $PROG -f -A -n '__fish_pass_uses_command show' -s t -l type -d 'Automatically type out the password after a delay' complete -c $PROG -f -A -n '__fish_pass_uses_command show' -a "(__fish_pass_print_entries)" # When no command is given, `show` is defaulted. complete -c $PROG -f -A -n '__fish_pass_needs_command' -s c -l clip -d 'Put password in clipboard' +complete -c $PROG -f -A -n '__fish_pass_needs_command' -s t -l type -d 'Automatically type out the password after a delay' complete -c $PROG -f -A -n '__fish_pass_needs_command' -a "(__fish_pass_print_entries)" complete -c $PROG -f -A -n '__fish_pass_uses_command -c' -a "(__fish_pass_print_entries)" complete -c $PROG -f -A -n '__fish_pass_uses_command --clip' -a "(__fish_pass_print_entries)" +complete -c $PROG -f -A -n '__fish_pass_uses_command -t' -a "(__fish_pass_print_entries)" +complete -c $PROG -f -A -n '__fish_pass_uses_command --type' -a "(__fish_pass_print_entries)" complete -c $PROG -f -A -n '__fish_pass_needs_command' -a git -d 'Command: execute a git command' complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'init' -d 'Initialize git repository' diff --git a/src/completion/pass.zsh-completion b/src/completion/pass.zsh-completion index 27ce15a..efd2c86 100644 --- a/src/completion/pass.zsh-completion +++ b/src/completion/pass.zsh-completion @@ -117,7 +117,9 @@ _pass () { _pass_cmd_show () { _arguments : \ "-c[put it on the clipboard]" \ - "--clip[put it on the clipboard]" + "--clip[put it on the clipboard]" \ + "-t[automatically type out the password after a delay]" \ + "--type[automatically type out the password after a delay]" _pass_complete_entries } _pass_complete_entries_helper () { diff --git a/src/password-store.sh b/src/password-store.sh index 63be840..02e6562 100755 --- a/src/password-store.sh +++ b/src/password-store.sh @@ -15,6 +15,7 @@ which gpg2 &>/dev/null && GPG="gpg2" PREFIX="${PASSWORD_STORE_DIR:-$HOME/.password-store}" X_SELECTION="${PASSWORD_STORE_X_SELECTION:-clipboard}" CLIP_TIME="${PASSWORD_STORE_CLIP_TIME:-45}" +TYPE_DELAY="${PASSWORD_STORE_TYPE_DELAY:-3}" GENERATED_LENGTH="${PASSWORD_STORE_GENERATED_LENGTH:-25}" export GIT_DIR="${PASSWORD_STORE_GIT:-$PREFIX}/.git" @@ -295,23 +296,36 @@ cmd_init() { } cmd_show() { - local opts clip_location clip=0 - opts="$($GETOPT -o c:: -l clip:: -n "$PROGRAM" -- "$@")" + local opts clip_location clip=0 auto_type=0 delay + opts="$($GETOPT -o c::,t:: -l clip::,type:: -n "$PROGRAM" -- "$@")" local err=$? eval set -- "$opts" while true; do case $1 in -c|--clip) clip=1; clip_location="${2:-1}"; shift 2 ;; + -t|--type) auto_type=1; delay="${2:-$TYPE_DELAY}"; shift 2 ;; --) shift; break ;; esac done - [[ $err -ne 0 ]] && die "Usage: $PROGRAM $COMMAND [--clip[=line-number],-c[line-number]] [pass-name]" + [[ $err -ne 0 ]] && die "Usage: $PROGRAM $COMMAND [--clip[=line-number],-c[line-number]] [--type[=delay],-t[delay]] [pass-name]" + + # Could add the ability to use both if needed + [[ $auto_type -eq 1 && $clip -eq 1 ]] && + die "Can't use --clip and --type together" local path="$1" local passfile="$PREFIX/$path.gpg" check_sneaky_paths "$path" if [[ -f $passfile ]]; then if [[ $clip -eq 0 ]]; then - $GPG -d "${GPG_OPTS[@]}" "$passfile" || exit $? + if [[ $auto_type -eq 1 ]]; then + local pass="$($GPG -d "${GPG_OPTS[@]}" "$passfile" | head -n1)" + [[ -n $pass ]] || die "Failed to obtain password" + sleep $delay || exit $? + builtin echo -n "$pass" | + xdotool type --clearmodifiers --file - + else + $GPG -d "${GPG_OPTS[@]}" "$passfile" || exit $? + fi else [[ $clip_location =~ ^[0-9]+$ ]] || die "Clip location '$clip_location' is not a number." local pass="$($GPG -d "${GPG_OPTS[@]}" "$passfile" | tail -n +${clip_location} | head -n 1)" -- 2.5.4
_______________________________________________ Password-Store mailing list [email protected] http://lists.zx2c4.com/mailman/listinfo/password-store
