password-store

Simple password manager using gpg and ordinary unix directories
git clone https://git.zx2c4.com/password-store
Log | Files | Refs | README | LICENSE

commit 77f1384a6321eef06265ea5e5b11eabdc53ab720
parent bb717d68c5ba07516a6d0a156851792984367b53
Author: Jason A. Donenfeld <Jason@zx2c4.com>
Date:   Sun,  1 Jan 2017 21:03:38 +0100

show,generate: support qrcodes

Diffstat:
MREADME | 2++
Mman/pass.1 | 16+++++++++++-----
Msrc/password-store.sh | 55++++++++++++++++++++++++++++++++++++++++---------------
Msrc/platform/darwin.sh | 12++++++++++++
4 files changed, 65 insertions(+), 20 deletions(-)

diff --git a/README b/README @@ -26,3 +26,5 @@ Depends on: - GNU getopt http://www.kernel.org/pub/linux/utils/util-linux/ http://software.frodo.looijaard.name/getopt/ +- qrencode + https://fukuchi.org/works/qrencode/ diff --git a/man/pass.1 b/man/pass.1 @@ -90,12 +90,15 @@ 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--qrcode\fP[=\fIline-number\fP], \fI-q\fP[\fIline-number\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--qrcode\fP +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. .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 @@ -125,8 +128,10 @@ in generating passwords can be changed with the \fIPASSWORD_STORE_CHARACTER_SET\ If \fI--clip\fP or \fI-c\fP is specified, do not print the password but instead copy it to the clipboard using .BR xclip (1) -and then restore the clipboard after 45 (or \fIPASSWORD_STORE_CLIP_TIME\fP) seconds. -Prompt before overwriting an existing password, +and then restore the clipboard after 45 (or \fIPASSWORD_STORE_CLIP_TIME\fP) seconds. If \fI--qrcode\fP +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. Prompt before overwriting an existing password, unless \fI--force\fP or \fI-f\fP is specified. If \fI--in-place\fP or \fI-i\fP is specified, do not interactively prompt, and only replace the first line of the password file with the new generated password, keeping the remainder of the file intact. @@ -461,7 +466,8 @@ The location of the text editor used by \fBedit\fP. .BR gpg2 (1), .BR tr (1), .BR git (1), -.BR xclip (1). +.BR xclip (1), +.BR qrencode (1). .SH AUTHOR .B pass diff --git a/src/password-store.sh b/src/password-store.sh @@ -170,6 +170,23 @@ clip() { ) 2>/dev/null & disown echo "Copied $2 to clipboard. Will clear in $CLIP_TIME seconds." } + +qrcode() { + if [[ -n $DISPLAY || -n $WAYLAND_DISPLAY ]]; then + if type feh >/dev/null 2>&1; then + echo -n "$1" | qrencode --size 10 -o - | feh -x --title "pass: $2" -g +200+200 - + return + elif type gm >/dev/null 2>&1; then + echo -n "$1" | qrencode --size 10 -o - | gm display -title "pass: $2" -geometry +200+200 - + return + elif type display >/dev/null 2>&1; then + echo -n "$1" | qrencode --size 10 -o - | display -title "pass: $2" -geometry +200+200 - + return + fi + fi + echo -n "$1" | qrencode -t utf8 +} + tmpdir() { [[ -n $SECURE_TMPDIR ]] && return local warn=1 @@ -321,28 +338,33 @@ cmd_init() { } cmd_show() { - local opts clip_location clip=0 - opts="$($GETOPT -o c:: -l clip:: -n "$PROGRAM" -- "$@")" + local opts selected_line clip=0 qrcode=0 + opts="$($GETOPT -o q::c:: -l qrcode::,clip:: -n "$PROGRAM" -- "$@")" local err=$? eval set -- "$opts" while true; do case $1 in - -c|--clip) clip=1; clip_location="${2:-1}"; shift 2 ;; + -q|--qrcode) qrcode=1; selected_line="${2:-1}"; shift 2 ;; + -c|--clip) clip=1; selected_line="${2:-1}"; shift 2 ;; --) shift; break ;; esac done - [[ $err -ne 0 ]] && die "Usage: $PROGRAM $COMMAND [--clip[=line-number],-c[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]] [pass-name]" local path="$1" local passfile="$PREFIX/$path.gpg" check_sneaky_paths "$path" if [[ -f $passfile ]]; then - if [[ $clip -eq 0 ]]; then + if [[ $clip -eq 0 && $qrcode -eq 0 ]]; then $GPG -d "${GPG_OPTS[@]}" "$passfile" || exit $? 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)" - [[ -n $pass ]] || die "There is no password to put on the clipboard at line ${clip_location}." - clip "$pass" "$path" + [[ $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)" + [[ -n $pass ]] || die "There is no password to put on the clipboard at line ${selected_line}." + if [[ $clip -eq 1 ]]; then + clip "$pass" "$path" + elif [[ $qrcode -eq 1 ]]; then + qrcode "$pass" "$path" + fi fi elif [[ -d $PREFIX/$path ]]; then if [[ -z $path ]]; then @@ -457,19 +479,20 @@ cmd_edit() { } cmd_generate() { - local opts clip=0 force=0 characters="$CHARACTER_SET" inplace=0 pass - opts="$($GETOPT -o ncif -l no-symbols,clip,in-place,force -n "$PROGRAM" -- "$@")" + local opts qrcode=0 clip=0 force=0 characters="$CHARACTER_SET" inplace=0 pass + opts="$($GETOPT -o nqcif -l no-symbols,qrcode,clip,in-place,force -n "$PROGRAM" -- "$@")" local err=$? eval set -- "$opts" while true; do case $1 in -n|--no-symbols) characters="$CHARACTER_SET_NO_SYMBOLS"; shift ;; + -q|--qrcode) qrcode=1; shift ;; -c|--clip) clip=1; shift ;; -f|--force) force=1; shift ;; -i|--in-place) inplace=1; shift ;; --) shift; break ;; esac done - [[ $err -ne 0 || ( $# -ne 2 && $# -ne 1 ) || ( $force -eq 1 && $inplace -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--no-symbols,-n] [--clip,-c] [--in-place,-i | --force,-f] pass-name [pass-length]" + [[ $err -ne 0 || ( $# -ne 2 && $# -ne 1 ) || ( $force -eq 1 && $inplace -eq 1 ) || ( $qrcode -eq 1 && $clip -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--no-symbols,-n] [--clip,-c] [--qrcode,-q] [--in-place,-i | --force,-f] pass-name [pass-length]" local path="$1" local length="${2:-$GENERATED_LENGTH}" check_sneaky_paths "$path" @@ -497,10 +520,12 @@ cmd_generate() { [[ $inplace -eq 1 ]] && verb="Replace" git_add_file "$passfile" "$verb generated password for ${path}." - if [[ $clip -eq 0 ]]; then - printf "\e[1m\e[37mThe generated password for \e[4m%s\e[24m is:\e[0m\n\e[1m\e[93m%s\e[0m\n" "$path" "$pass" - else + if [[ $clip -eq 1 ]]; then clip "$pass" "$path" + elif [[ $qrcode -eq 1 ]]; then + qrcode "$pass" "$path" + else + printf "\e[1m\e[37mThe generated password for \e[4m%s\e[24m is:\e[0m\n\e[1m\e[93m%s\e[0m\n" "$path" "$pass" fi } diff --git a/src/platform/darwin.sh b/src/platform/darwin.sh @@ -31,5 +31,17 @@ tmpdir() { mount -t hfs -o noatime -o nobrowse "$DARWIN_RAMDISK_DEV" "$SECURE_TMPDIR" || die "Error: could not mount filesystem on ramdisk." } +qrcode() { + if type imgcat >/dev/null 2>&1; then + echo -n "$1" | qrencode --size 10 -o - | imgcat + elif type gm >/dev/null 2>&1; then + echo -n "$1" | qrencode --size 10 -o - | gm display -title "pass: $2" -geometry +200+200 - + elif type display >/dev/null 2>&1; then + echo -n "$1" | qrencode --size 10 -o - | display -title "pass: $2" -geometry +200+200 - + else + echo -n "$1" | qrencode -t utf8 + fi +} + GETOPT="$(brew --prefix gnu-getopt 2>/dev/null || { which port &>/dev/null && echo /opt/local; } || echo /usr/local)/bin/getopt" SHRED="srm -f -z"