[PATCH] show and edit: Option to show/edit everything except first line

Pelle Nilsson pellenilsson at fastmail.fm
Sat Feb 18 23:11:00 CET 2017


Makes it possible to view or edit the less sensitive data (like URL and
username) without exposing the password to bystanders.
---
 man/pass.1                          |  7 +++++--
 src/completion/pass.bash-completion |  3 ++-
 src/completion/pass.fish-completion |  2 ++
 src/completion/pass.zsh-completion  | 12 +++++++++--
 src/password-store.sh               | 40 ++++++++++++++++++++++++++++---------
 5 files changed, 50 insertions(+), 14 deletions(-)

diff --git a/man/pass.1 b/man/pass.1
index 71bfc7e..db9d4f4 100644
--- a/man/pass.1
+++ b/man/pass.1
@@ -90,7 +90,7 @@ 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] ] [ \fI--qrcode\fP[=\fIline-number\fP], \fI-q\fP[\fIline-number\fP] ] \fIpass-name\fP
+\fBshow\fP [ \fI--clip\fP[=\fIline-number\fP], \fI-c\fP[\fIline-number\fP] ] [ \fI--qrcode\fP[=\fIline-number\fP], \fI-q\fP[\fIline-number\fP] ] [ \fI--without-password\fP, \fI-w\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
@@ -99,6 +99,7 @@ and then restore the clipboard after 45 (or \fIPASSWORD_STORE_CLIP_TIME\fP) seco
 or \fI-q\fP is specified, do not print the password but instead display a QR code using
 .BR qrencode (1)
 either to the terminal or graphically if supported.
+If \fI--without-password\fP or \fI-w\fP is specified, print everything except for the first line.
 .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
@@ -109,7 +110,7 @@ EOF or Ctrl+D is reached. Otherwise, only a single line from standard in is read
 before overwriting an existing password, unless \fI--force\fP or \fI-f\fP is specified. This
 command is alternatively named \fBadd\fP.
 .TP
-\fBedit\fP \fIpass-name\fP
+\fBedit\fP [ \fI--without-password\fP, \fI-w\fP] \fIpass-name\fP
 Insert a new password or edit an existing password using the default text editor specified
 by the environment variable \fIEDITOR\fP or using
 .BR vi (1)
@@ -117,6 +118,8 @@ as a fallback. This mode makes use of temporary files for editing, but care is t
 ensure that temporary files are created in \fI/dev/shm\fP in order to avoid writing to
 difficult-to-erase disk sectors. If \fI/dev/shm\fP is not accessible, fallback to
 the ordinary \fITMPDIR\fP location, and print a warning.
+If \fI--without-password\fP or \fI-w\fP is specified, edit everything except for the first line,
+and leave first line untouched.
 .TP
 \fBgenerate\fP [ \fI--no-symbols\fP, \fI-n\fP ] [ \fI--clip\fP, \fI-c\fP ] [ \fI--in-place\fP, \fI-i\fP | \fI--force\fP, \fI-f\fP ] \fIpass-name [pass-length]\fP
 Generate a new password using \fB/dev/urandom\fP of length \fIpass-length\fP
diff --git a/src/completion/pass.bash-completion b/src/completion/pass.bash-completion
index 456485b..37f9558 100644
--- a/src/completion/pass.bash-completion
+++ b/src/completion/pass.bash-completion
@@ -95,10 +95,11 @@ _pass()
 				fi
 				;;
 			ls|list|edit)
+				COMPREPLY+=($(compgen -W "-w --without-password" -- ${cur}))
 				_pass_complete_entries
 				;;
 			show|-*)
-				COMPREPLY+=($(compgen -W "-c --clip" -- ${cur}))
+				COMPREPLY+=($(compgen -W "-c --clip -w --without-password" -- ${cur}))
 				_pass_complete_entries 1
 				;;
 			insert)
diff --git a/src/completion/pass.fish-completion b/src/completion/pass.fish-completion
index c32a42c..42aa113 100644
--- a/src/completion/pass.fish-completion
+++ b/src/completion/pass.fish-completion
@@ -94,10 +94,12 @@ complete -c $PROG -f -A -n '__fish_pass_uses_command rm' -s f -l force -d 'Force
 complete -c $PROG -f -A -n '__fish_pass_uses_command rm' -a "(__fish_pass_print_entries_and_dirs)"
 
 complete -c $PROG -f -A -n '__fish_pass_needs_command' -a edit -d 'Command: edit password using text editor'
+complete -c $PROG -f -A -n '__fish_pass_uses_command edit' -s w -l without-password -d 'Don't display password itself'
 complete -c $PROG -f -A -n '__fish_pass_uses_command edit' -a "(__fish_pass_print_entries)"
 
 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 w -l without-password -d 'Don't display password itself'
 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'
diff --git a/src/completion/pass.zsh-completion b/src/completion/pass.zsh-completion
index 27ce15a..fc5eae5 100644
--- a/src/completion/pass.zsh-completion
+++ b/src/completion/pass.zsh-completion
@@ -35,7 +35,13 @@ _pass () {
 					"--path[gpg-id will only be applied to this subfolder]"
 				_pass_complete_keys
 				;;
-			ls|list|edit)
+			ls|list)
+				_pass_complete_entries_with_subdirs
+				;;
+			edit)
+				_arguments : \
+					"-w[don't display password itself]" \
+					"--without-password[don't display password itself]"
 				_pass_complete_entries_with_subdirs
 				;;
 			insert)
@@ -117,7 +123,9 @@ _pass () {
 _pass_cmd_show () {
 	_arguments : \
 		"-c[put it on the clipboard]" \
-		"--clip[put it on the clipboard]"
+		"--clip[put it on the clipboard]" \
+		"-w[don't display password itself]" \
+		"--without-password[don't display password itself]"
 	_pass_complete_entries
 }
 _pass_complete_entries_helper () {
diff --git a/src/password-store.sh b/src/password-store.sh
index 081057a..6a268e1 100755
--- a/src/password-store.sh
+++ b/src/password-store.sh
@@ -257,7 +257,7 @@ cmd_usage() {
 	        List passwords.
 	    $PROGRAM find pass-names...
 	    	List passwords that match pass-names.
-	    $PROGRAM [show] [--clip[=line-number],-c[line-number]] pass-name
+	    $PROGRAM [show] [--clip[=line-number],-c[line-number]] [--without-password,-w] pass-name
 	        Show existing password and optionally put it on the clipboard.
 	        If put on the clipboard, it will be cleared in $CLIP_TIME seconds.
 	    $PROGRAM grep search-string
@@ -266,7 +266,7 @@ cmd_usage() {
 	        Insert new password. Optionally, echo the password back to the console
 	        during entry. Or, optionally, the entry may be multiline. Prompt before
 	        overwriting existing password unless forced.
-	    $PROGRAM edit pass-name
+	    $PROGRAM edit [--without-password,-w] pass-name
 	        Insert a new password or edit an existing password using ${EDITOR:-vi}.
 	    $PROGRAM generate [--no-symbols,-n] [--clip,-c] [--in-place,-i | --force,-f] pass-name [pass-length]
 	        Generate a new password of pass-length (or $GENERATED_LENGTH if unspecified) with optionally no symbols.
@@ -338,24 +338,29 @@ cmd_init() {
 }
 
 cmd_show() {
-	local opts selected_line clip=0 qrcode=0
-	opts="$($GETOPT -o q::c:: -l qrcode::,clip:: -n "$PROGRAM" -- "$@")"
+	local opts selected_line clip=0 qrcode=0 without_password=0
+	opts="$($GETOPT -o q::c::,w -l qrcode::,clip::,without-password -n "$PROGRAM" -- "$@")"
 	local err=$?
 	eval set -- "$opts"
 	while true; do case $1 in
 		-q|--qrcode) qrcode=1; selected_line="${2:-1}"; shift 2 ;;
 		-c|--clip) clip=1; selected_line="${2:-1}"; shift 2 ;;
+		-w|--without-password) without_password=1; shift ;;
 		--) shift; break ;;
 	esac done
 
-	[[ $err -ne 0 || ( $qrcode -eq 1 && $clip -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--clip[=line-number],-c[line-number]] [--qrcode[=line-number],-q[line-number]] [pass-name]"
+	[[ $err -ne 0 || ( $qrcode -eq 1 && $clip -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--clip[=line-number],-c[line-number]] [--qrcode[=line-number],-q[line-number]] [--without-password,-w] [pass-name]"
 
 	local path="$1"
 	local passfile="$PREFIX/$path.gpg"
 	check_sneaky_paths "$path"
 	if [[ -f $passfile ]]; then
 		if [[ $clip -eq 0 && $qrcode -eq 0 ]]; then
-			$GPG -d "${GPG_OPTS[@]}" "$passfile" || exit $?
+			if [[ $without_password -eq 0 ]]; then
+				$GPG -d "${GPG_OPTS[@]}" "$passfile" || exit $?
+			else
+				$GPG -d "${GPG_OPTS[@]}" "$passfile" | tail -n +2 || exit $?
+			fi
 		else
 			[[ $selected_line =~ ^[0-9]+$ ]] || die "Clip location '$selected_line' is not a number."
 			local pass="$($GPG -d "${GPG_OPTS[@]}" "$passfile" | tail -n +${selected_line} | head -n 1)"
@@ -452,7 +457,16 @@ cmd_insert() {
 }
 
 cmd_edit() {
-	[[ $# -ne 1 ]] && die "Usage: $PROGRAM $COMMAND pass-name"
+	local opts without_password=0
+	opts="$($GETOPT -o w -l without-password -n "$PROGRAM" -- "$@")"
+	local err=$?
+	eval set -- "$opts"
+	while true; do case $1 in
+		-w|--without-password) without_password=1; shift ;;
+		--) shift; break ;;
+	esac done
+
+	[[ $err -ne 0 || ( $# -ne 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--without-password,-w] pass-name"
 
 	local path="${1%/}"
 	check_sneaky_paths "$path"
@@ -462,15 +476,23 @@ cmd_edit() {
 
 	tmpdir #Defines $SECURE_TMPDIR
 	local tmp_file="$(mktemp -u "$SECURE_TMPDIR/XXXXXX")-${path//\//-}.txt"
-
+	local tmp_file2="$(mktemp -u "$SECURE_TMPDIR/XXXXXX")-${path//\//-}.txt"
 
 	local action="Add"
 	if [[ -f $passfile ]]; then
-		$GPG -d -o "$tmp_file" "${GPG_OPTS[@]}" "$passfile" || exit 1
+		if [[ $without_password -eq 0 ]]; then
+			$GPG -d -o "$tmp_file" "${GPG_OPTS[@]}" "$passfile" || exit 1
+		else
+			$GPG -d -o - "${GPG_OPTS[@]}" "$passfile" | tail -n +2 > "$tmp_file" || exit 1
+		fi
 		action="Edit"
 	fi
 	${EDITOR:-vi} "$tmp_file"
 	[[ -f $tmp_file ]] || die "New password not saved."
+	if [[ $without_password -eq 1 ]]; then
+		$GPG -d -o - "${GPG_OPTS[@]}" "$passfile" 2>/dev/null | head -n 1 | cat - "$tmp_file" > "$tmp_file2"
+		mv -f "$tmp_file2" "$tmp_file"
+	fi
 	$GPG -d -o - "${GPG_OPTS[@]}" "$passfile" 2>/dev/null | diff - "$tmp_file" &>/dev/null && die "Password unchanged."
 	while ! $GPG -e "${GPG_RECIPIENT_ARGS[@]}" -o "$passfile" "${GPG_OPTS[@]}" "$tmp_file"; do
 		yesno "GPG encryption failed. Would you like to try again?"
-- 
2.11.0



More information about the Password-Store mailing list