[pass] [PASS][PATCH] new feature passmenu multi-clip

mitfree lists at ampling.com
Sun May 8 16:59:34 CEST 2016


Hello. After two years of using pass and following the mailing list
I've finally found a way to add multi-clip. This is a feature
heavily inspired by Nicolas S. Dade's pwsafe. It started as an idea for
a feature request, then it was a proof of concept, and now, after a few
weeks of poking and prodding, I'm happy to share a full working alt
version of passmenu. I use it every day and I hope you will too.

Thank you milki and Jason and others for your past correspondence helping
to steer me in this direction. [rolling][loops]

First:
If you like the way passmenu currently behaves, then you wont notice
much of a change. In this version, I've preserved all single clip
behavior. 

This patch:
If you add my patch, you will gain the ability to select multiple
passwords and paste them in series. Meaning, after the first paste,
passmenu continues and lines up another. This is useful for pasting
logins and passwords. To do this, in dmenu press Ctrl-Enter instead of
Enter to continue selecting entries. Hit Enter on the last entry. Now
you can paste each entry once.

The magic line:  ## line #73
<code>xclip -l 1 -quiet -sel "$X_SELECTION" </code>
Here xclip waits for one X selection request and prints.
https://github.com/ampling/pass/blob/passmenu_multi-clip/contrib/dmenu/passmenu#L73

Multi-line vs Fist-line storage. 
Yes. I'm aware of both methods of storage. I had both in mind when
writing this. I found it easier to address first-line storage in
this patch, but I have an idea of how to add multi-line clips later.

Pro-tip  ## passmenu --type
I'm really liking xdotool. Try setting a keyboard shortcut for passmenu
--type, then select url, login and pass. Then, paste, paste, paste, enter.
Xdotool gets arround places which mess with the clipboard. I'm looking
at you firefox omnibar. Try it. It's simply the most constantly low
hassle authentication process I've yet tried.

What I've learned:
It's a bad idea for a pass or passmenu process to overlap with another
process of pass or passmenu. I needed a file lock for the clipboard. I
like flock as a file lock, but it wasn't default on all platforms. With
portability in mind, I went with mktemp -d.

I've done my best to go with sane defaults here. If you feel there's a
better way, please let me know.

In addition my the diff bellow, you can find my patch with full history
attached and on github.
https://github.com/ampling/pass/blob/passmenu_multi-clip/contrib/dmenu/passmenu


diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index 7a9c517..68b4150 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -1,25 +1,98 @@
 #!/usr/bin/env bash
 
-shopt -s nullglob globstar
+shopt -s nullglob globstar failglob
+set -euo pipefail
 
+tool=${1:-} 
 typeit=0
-if [[ $1 == "--type" ]]; then
-	typeit=1
-	shift
+if [[ $tool == "--type" ]]; then
+  typeit=1
+  shift
 fi
 
-prefix=${PASSWORD_STORE_DIR-~/.password-store}
+X_SELECTION="${PASSWORD_STORE_X_SELECTION:-clipboard}"
+CLIP_TIME="${PASSWORD_STORE_CLIP_TIME:-45}"
+prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store}"
+
 password_files=( "$prefix"/**/*.gpg )
 password_files=( "${password_files[@]#"$prefix"/}" )
 password_files=( "${password_files[@]%.gpg}" )
+password=( ${password:-""} )
+before=( "${before:-}" )
+userID="$(id -u $(whoami))"
+stalelock=( "${stalelock:-""}" )
+stalelock=( "$(find '/tmp' -maxdepth 1 -name "passmenulock."$userID".*" -user $(whoami) -print0  -quit)" ) &&
+cleanup=True || { true; cleanup=False; }
+
+_finish () {
+  [[ -n $before ]] &&
+  printf "$before" | base64 -d | xclip -sel "$X_SELECTION" -i
+  [[ True = "$cleanup" ]] &&
+  if compgen -G "/tmp/passmenulock.1000*" >/dev/null 2>&1 ;then
+    rmdir /tmp/passmenulock."$userID".* >/dev/null 2>&1
+  fi
+  exit
+}
+trap _finish EXIT
 
-password=$(printf '%s\n' "${password_files[@]}" | dmenu "$@")
+## Clearing stale Xclip loops avoids a posible race condition.
+if test -n "$stalelock" ;then
+  report=( "$(ps -u $(id -u $(whoami)) aux | grep "bash" | 
+  grep "passmenu" | grep -v "$$")" )
+  stalePID=( "$(printf $stalelock | 
+  sed -e "s/\/tmp\/passmenulock\.[0-9]\{1,6\}\?\..*\.//g")" )
+  if [[ "$report" == *"$stalePID"* ]] ;then
+    kill "$stalePID" || exit 1
+  else
+    rmdir /tmp/passmenulock.$userID.* >/dev/null 2>&1 || exit 1
+  fi
+fi
+
+## dmenu exits on KeyPress not KeyRelease.
+# It would be nice to send KeyRelease event to some dummy window.
+# psydocode: xdotool getwindowfocus; create dummy window;
+# exec dmenu; close dummy window; restore focus.
+for password in $(printf '%s\n' "${password_files[@]}" | dmenu -f "$@"); do
+  passel+=("$password")
+done
 
 [[ -n $password ]] || exit
+# It would be nice to first somehow test if string exists.
+before="$(xclip -sel "$X_SELECTION" -o 2>/dev/null | base64)" || true
+
+umask 077
+( mktemp -d "/tmp/passmenulock."$userID".XXXXXXXXXX"."$$" >/dev/null 2>&1 && cleanup=True ||
+  { echo >&2 ":: Unable to make a filelock."; exit 1; } )
 
 if [[ $typeit -eq 0 ]]; then
-	pass show -c "$password" 2>/dev/null
+  if [ ${#passel[@]} -gt "1" ]; then
+    round=0
+    for entry in "${passel[@]}"; do
+      printf '%s\n' "Sending "${passel[$round]}" via "$X_SELECTION""
+      pass show "$entry" | sed '1!d' | tr -d '\n' |
+      xclip -l 1 -quiet -sel "$X_SELECTION" >/dev/null 2>&1
+      round=`expr $round + 1`
+    done
+  else
+    printf '%s\n' "Sending "$password" via "$X_SELECTION""
+    pass show "$password" | sed '1!d' | tr -d '\n' |
+    xclip -sel "$X_SELECTION" -i && sleep "$CLIP_TIME" 
+  fi
 else
-	pass show "$password" | { read -r pass; printf %s "$pass"; } |
-		xdotool type --clearmodifiers --file -
+  command -v xdotool >/dev/null 2>&1 || 
+  { echo >&2 "e: cannot find xdotool."; exit 1; }
+  if [ ${#passel[@]} -gt "1" ]; then
+    round=0
+    for entry in "${passel[@]}"; do
+      printf '%s\n' "Sending "${passel[$round]}" via "$X_SELECTION""
+      printf '' | xclip -l 1 -quiet -sel "$X_SELECTION" >/dev/null 2>&1
+      pass show "$entry" | sed '1!d' | tr -d '\n' | 
+      xdotool type --clearmodifiers --file -
+      round=`expr $round + 1`
+    done
+  else
+    pass show "$password" | sed '1!d' | tr -d '\n' |
+    xdotool type --clearmodifiers --file -
+  fi
 fi
+exit



-- 
At your service,
mitfree
http://ampling.com

-------------- next part --------------
A non-text attachment was scrubbed...
Name: passmenu_multi-clip.patch
Type: text/x-diff
Size: 26266 bytes
Desc: not available
URL: <http://lists.zx2c4.com/pipermail/password-store/attachments/20160508/6a47d8fc/attachment-0001.patch>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 949 bytes
Desc: signature
URL: <http://lists.zx2c4.com/pipermail/password-store/attachments/20160508/6a47d8fc/attachment-0001.asc>


More information about the Password-Store mailing list