[Pull request] Shortcut feature

Ondrej Vaško ondrej.vaskoo at gmail.com
Mon Mar 27 00:51:22 CEST 2017


Dear password store users,

First of all thank you for developing such a great command line utility as
*pass* is. I am fresh IT university graduate and a while ago I started
using *pass* in a smaller company I work in, but let's go for my pull
request.

*TLDR*

Implementation of shortcuts which are written left of the password
files in *pass
ls/find/search *output and can be used with *pass show -s<number>* to
retrieve passwords not by full path, but by usually short number.

*Short description*

This commit introduces shortcut argument *-s* or *--shortcut* to *pass show
*command with which you can reference password not by full path, but by
number, which reference the specific gpg file in your password storage
directory.

*Motivation*

Long paths to keys where you have multiple options in autocomplete are
harder to write, so I was thinking about easier way to input path to
password I want to look for. I was thinking about something like short hash
for the files, or unique ID, but when I pulled actual code for pass I found
that the code is made very simple (which is great) but also harder to
extend (for example because of relying on the output of *tree* command).

After few days of thinking about an easy solution I decided to use an
*inode* as a reference shortcut for paths and implemented new argument to *pass
show* command. Inodes are easy to get (tree --inodes) and easy to find
(with *find* -inum).

*Usage*

The best use case I found is when you use *pass find/search* or *pass ls
<dir> along* with *pass show -s<shortcut>*.

Example:

*$ pass find db*   #This is usual output

passwords
    └── customers
            ├── customer1
            │        ├── db01.example.com
            │        │         ├──  root
            │        │         └──  customer1
            │        └── db02.example.com
            │                   └──  root
            └── customer2
                      └── db.customer2.com
                                 └──  root

*$ pass find db   *# Output after implementing new shortcut feature

passwords
    └── customers
            ├── customer1
            │        ├── db01.example.com
            │        │         ├──  [123456]  root
            │        │         └──  [123457]  customer1
            │        └── db02.example.com
            │                   └──  [135412]  root
            └── customer2
                      └── db.customer2.com
                                 └──  [<NUMBER>]  root

*$ pass **show -**s123456*
*> customer1rootpassword*

*Benefits*

   - Inodes are usually not very long, therefore you can write pass show
   -s<N> easily on keyboard, or copy shortcut with mouse (but I don't want to
   encourage people to use mouse) or keyboard.

*Downsides*

   - I needed to add shortcut ID to the output of tree command, so the
   output is now different. I sedded out inodes for directories so the printed
   tree is prettier.
   - Files which have string [<number>] in name can cause troubles
   (filtering of regex '\[[0-9]+\]\ \ ')
   - There must not be a space after argument -s. Relevant usage is '*pass
   show -s<number>'. *I reused code from other functions, so maybe other
   functions behave the same.

*Git diff*

All tests passed OK with exception of *t0500-find.sh* where the changed
output was issue, so I updated regex to strip inode number ([NUMBER]) in
this test. Git diff is located in attachment.

Thank you for reading :-).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.zx2c4.com/pipermail/password-store/attachments/20170327/f55328c1/attachment.html>
-------------- next part --------------
diff --git a/src/password-store.sh b/src/password-store.sh
index bad8d4f..d38a47a 100755
--- a/src/password-store.sh
+++ b/src/password-store.sh
@@ -222,6 +222,7 @@ tmpdir() {
 	fi
 
 }
+
 GETOPT="getopt"
 SHRED="shred -f -z"
 
@@ -263,9 +264,10 @@ 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]] {pass-name|[-s[shortcut-id],--shortcut[=shortcut-id]]}
 	        Show existing password and optionally put it on the clipboard.
 	        If put on the clipboard, it will be cleared in $CLIP_TIME seconds.
+	        Password can also be referenced by number (shortcut) shown in brackets left to the gpg file.
 	    $PROGRAM grep search-string
 	        Search for password files containing search-string when decrypted.
 	    $PROGRAM insert [--echo,-e | --multiline,-m] [--force,-f] pass-name
@@ -345,21 +347,31 @@ 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 shortcut=0
+	opts="$($GETOPT -o q::c::s:: -l qrcode::,clip::,shortcut:: -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 ;;
+		-s|--shortcut) shortcut=1; shortcut_id="${2}"; shift 2 ;;
 		--) 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 ) || ( -n $1 && $shortcut -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--clip[=line-number],-c[line-number]] [--qrcode[=line-number],-q[line-number]] {pass-name|[-s[shortcut-name],--shortcut[=shortcut-number]]}"
 
-	local path="$1"
-	local passfile="$PREFIX/$path.gpg"
+	local path=""
+
+	if [[ $shortcut -eq 1 ]]; then
+		[[ $shortcut_id =~ ^[0-9]+$ ]] || die "Shortcut ID '$shortcut_id' is not a number."
+		path=$(find $PREFIX -type f -inum $shortcut_id -printf "%P\n" | head -n1)
+	else
+		path="$1"
+	fi
+
+	local passfile="$PREFIX/${path%.gpg}.gpg"
 	check_sneaky_paths "$path"
+
 	if [[ -f $passfile ]]; then
 		if [[ $clip -eq 0 && $qrcode -eq 0 ]]; then
 			$GPG -d "${GPG_OPTS[@]}" "$passfile" || exit $?
@@ -373,13 +385,15 @@ cmd_show() {
 				qrcode "$pass" "$path"
 			fi
 		fi
+	elif [[ $shortcut -eq 1 && -z $path ]]; then
+		die "Error: password file with shortcut ID '$shortcut_id' does not exists in password store directory."
 	elif [[ -d $PREFIX/$path ]]; then
 		if [[ -z $path ]]; then
 			echo "Password Store"
 		else
 			echo "${path%\/}"
 		fi
-		tree -C -l --noreport "$PREFIX/$path" | tail -n +2 | sed -E 's/\.gpg(\x1B\[[0-9]+m)?( ->|$)/\1\2/g' # remove .gpg at end of line, but keep colors
+		tree -C -l --noreport --inodes "$PREFIX/$path" | tail -n +2 | sed -E '/\.gpg(\x1B\[[0-9]+m)?( ->|$)/!s/\[[0-9]+\]\ \ //g' | sed -E 's/\.gpg(\x1B\[[0-9]+m)?( ->|$)/\1\2/g' # remove .gpg at end of line, but keep colors
 	elif [[ -z $path ]]; then
 		die "Error: password store is empty. Try \"pass init\"."
 	else
@@ -391,7 +405,7 @@ cmd_find() {
 	[[ $# -eq 0 ]] && die "Usage: $PROGRAM $COMMAND pass-names..."
 	IFS="," eval 'echo "Search Terms: $*"'
 	local terms="*$(printf '%s*|*' "$@")"
-	tree -C -l --noreport -P "${terms%|*}" --prune --matchdirs --ignore-case "$PREFIX" | tail -n +2 | sed -E 's/\.gpg(\x1B\[[0-9]+m)?( ->|$)/\1\2/g'
+	tree -C -l --noreport --inodes -P "${terms%|*}" --prune --matchdirs --ignore-case "$PREFIX" | tail -n +2 | sed -E '/\.gpg$/!s/\[[0-9]+\]\ \ //g' | sed -E 's/\.gpg(\x1B\[[0-9]+m)?( ->|$)/\1\2/g'
 }
 
 cmd_grep() {
diff --git a/tests/t0500-find.sh b/tests/t0500-find.sh
index 3cf6815..28e8254 100755
--- a/tests/t0500-find.sh
+++ b/tests/t0500-find.sh
@@ -12,7 +12,7 @@ test_expect_success 'Make sure find resolves correct files' '
 	"$PASS" generate Fishthings 122 &&
 	"$PASS" generate Fishies/stuff 21 &&
 	"$PASS" generate Fishies/otherstuff 1234 &&
-	[[ $("$PASS" find fish | sed "s/^[ \`|-]*//g;s/$(printf \\x1b)\\[[0-9;]*[a-zA-Z]//g" | tr "\\n" -) == "Search Terms: fish-Fish-Fishies-otherstuff-stuff-Fishthings-" ]]
+	[[ $("$PASS" find fish | sed -E "s/\[[0-9]+\]\ \ //g" | sed "s/^[ \`|-]*//g;s/$(printf \\x1b)\\[[0-9;]*[a-zA-Z]//g" | tr "\\n" -) == "Search Terms: fish-Fish-Fishies-otherstuff-stuff-Fishthings-" ]]
 '
 
 test_done


More information about the Password-Store mailing list