pass-otp helper for StumpWM
DO NOT USE - this code is intended to be submitted to stumpwm-contrib repo at some point in time. Feel free to PR or educate me on lisp in the issues. Currently it works for me(tm)
.
Compatible with rofi-pass and stolen most of the readme from, thanks!
For some strange reason, rofi-pass didn’t work for my setup, the :otp
was never autotyped, instead of debugging, it was decided to have a StumpWM ‘native’ version built.
The xdotool type
command sends key-[Press|Release] events to the X server, it sends individual events, as can be seen here:
https://github.com/jordansissel/xdotool/blob/08c8e2d6cad60a69ce415499e34865157a1b66fd/xdo.c#L958
Recreating it with cl-xlib is pointless, at least for such a meager purpose of typing something into a window. A LISP implementation of xdotool is a whole other different project, which might someday be written by someone, maybe.
- keymaps
pass-otp-menu-map
key action RET inline view C-RET open url M-RET autotype M-n create new M-o display M-e edit M-q qr-code show/generate pass-otp-entry-menu-map
key action RET set-x-selection M-RET autotype - pinentry handler
stolen from stumpwm-contrib/util/pinentry (needed configurable port/host setts)
- open URL
if
url: (.*)
field is found, then it is used, otherwise the entry path is converted to url. Given an entry inhosting.com/someuser
like:somepassword --- url: https://panel.hosting.com/login
command
xdg-open https://panel.hosting.com/login
will run, ifurl:
wasn’t found thenhttps://hosting.com
will be used instead.
copy RET / type M-RET individual entries
Regex is ": (.*)"
Type any field from entry
of user and/or password fields.
foobarmysecurepassword
user: MyUser
url: http://my.url.foo
- Auto-typing of more than one field, using the
autotype
entry:foobarmysecurepassword --- user: MyUser SomeField: foobar AnotherField: barfoo url: http://my.url.foo autotype: SomeField :tab user any-string-at-all :tab AnotherField :tab pass
Use
:tab
,:enter
,:space
,:delay
,:otp
here to type Tab, Enter, Space, Delay or OTP (useful for toggling checkboxes) respectively.:delay
will trigger a delay (5 seconds by default).Anything else will be typed verbatim as-is, like the
any-string-at-all
string in the example above. - The field names for user, url and autotype are configurable
The format for OTPs should be pass-otp(1)
-compatible otpauth://[...]
- zbarimg
- nc from libressl (or probably any other implementation of netcat)
- xdotool
- xdg-open from xdg-utils
- pass
- pass-otp plugin
- firefox / chromium plugins to have url in title
- stumpwm-contrib/screenshot
cat /.gnupg/gpg-agent.conf
pinentry-program /full/path/to/pinentry-stumpwm
cat /full/path/to/pinentry-stumpwm
#!/path/to/your/bash
. $XDG_RUNTIME_DIR/pinentry-stumpwm.env
echo OK Your orders please
while IFS="\n" read -r command; do
if [ "$command" == "GETINFO flavor" ]; then
echo D stumpwm
elif [[ "$command" == SETDESC* ]]; then
description=${command:8}
elif [[ "$command" == SETPROMPT* ]]; then
prompt=${command:10}
elif [ "$command" == GETPIN ]; then
password=$(printf "%s\n%s\n" "$description" "$prompt" | nc $PINENTRY_HOST $PINENTRY_PORT)
echo D "$password"
elif [ "$command" == BYE ]; then
exit 0
fi
echo OK
done < /dev/stdin
Most of the settings have sane defaults, sufficient:
;; I find this useful in general
(setf *menu-maximum-height* 16)
(push "/some/path/stumpwm-pass-otp/" asdf:*central-registry*)
(ql:quickload :pass-otp)
(define-key *root-map* (kbd "s-p") "pass-otp")
(define-key *root-map* (kbd "C-s-p") "pass-otp-show-all")
Or tweak:
(setf pass-otp:*password-store-dir* (merge-pathnames #p".password-store/" (user-homedir-pathname))
pass-otp:*known-window-class-regex* "Firefox|Chromium"
pass-otp:*uri-regex* "(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$])"
pass-otp:*xdotool-delay* 3
pass-otp:*autotype-delay* 5
pass-otp:*autotype-default* "user :tab pass :enter"
pass-otp:*autotype-regex-username* "user"
pass-otp:*autotype-regex-password* "pass"
pass-otp:*field-regex-username* "username: (.*)"
pass-otp:*field-regex-autotype* "autotype: (.*)"
pass-otp:*pinentry-listen-address* "127.0.0.1"
pass-otp:*pinentry-listen-port* 65530
pass-otp:*field-regex-url* "url: (.*)"
pass-otp:*pass-otp-menu-map* (let ((m (make-sparse-keymap)))
(define-key m (kbd "M-RET") (pass-otp:entry-menu-action :entry-autotype))
(define-key m (kbd "M-o") (pass-otp:entry-menu-action :entry-display))
(define-key m (kbd "M-e") (pass-otp:entry-menu-action :entry-edit))
(define-key m (kbd "M-n") (pass-otp:entry-menu-action :entry-create))
(define-key m (kbd "C-RET") (pass-otp:entry-menu-action :entry-open-url))
(define-key m (kbd "M-q") (pass-otp:entry-menu-action :entry-qr-code))
(define-key m (kbd "RET") (pass-otp:entry-menu-action :entry-menu))
m))
- FIXME: gpg piv (ie. yubikey) will timeout on pin-entry
- Switch pinentry to use unix domain sockets instead of IP?
- Support for different password stores (roots), e.g. to separate passwords for work from private passwords