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

Reply via email to