I am working on a series of patches and would like to discuss the usefulness (and possibly the implementation) with you. (And maybe I can get a comment from Jason if this has any chance of getting merged.)
The problem
===========
Sometimes you want to use pass in your shell scripts. Or you want to
interface pass with other shell tools via pipelines. The contents of
the password files are easily pipeable (just
`pass show something | script.sh`).
But the "metadata" ($PREFIX, directory and file names) is not easily
accessible. If you want to do something with these you have to
understand the internals of pass and reimplement part of the logic that
is already implemented in pass. Some completion functions do this for
example.
The idea
========
I do not want to change the output of existing commands for this so I
propose a new sub command: "script-interface". It will have further sub
commands. These will print some data in a format that is easily usable
by scripts (for example a list of all password files in a find-like
format in contrast to the tree printed by `pass show`).
Implementation
==============
A series of patches that I would like to discuss is attached. Until now
I implemented these script interface sub commands (docs still missing):
pass script-interface prefix -- prints the location of the password
store, so users do not have to
understand the (admittedly simple)
logic with $PASSWORD_STORE_DIR
pass script-interface entries -- print password entries (gpg files
with extension removed) in a
find-like format
pass script-interface dirs -- print directories that contain
entries in an find like format
pass script-interface dirs2 -- (faster implementation of dirs)
pass script-interface keys -- list all usable gpg keys
Reason / motivation
===================
- I think pass can/should hide its internal logic from the user
- I think pass should make data and information accessible for scripting
(I proposed a patch for pass grep for the same reason)
- I think that by doing this we can implement small "features" outside
of pass more easily. (For example there was a patch for a --firstline
option to pass show on this list recently. That can simply be
implemented by pipeing to `head -n 1`. And the qr-code patch can also
be replaced by a simple pipe.)
- I like code reuse so I had a look at the completion functions for
possible duplicates
Specific to my work flow: I have pass specific scripts in
$PASSWORD_STORE_DIR/bin which I would like to hide from password
listings. Therefore I would support a strict categorisation for
"password files" (files that match *.gpg), "relevant directories"
(directories that contain password files, anywhere below them) and
"others" (.gpg-id, .gitattributes, bin/script.sh, ...). This idea was
used to some extend in the attached patches.
Discussion
==========
Do you know more use cases for this? Or more sub commands? Or do you
have any critics? Or, or, or ...
Thank you
Lucas
From c48ff10a23e7343c58f71d7cfd7dd888801020fe Mon Sep 17 00:00:00 2001 Message-Id: <c48ff10a23e7343c58f71d7cfd7dd888801020fe.1454635746.git.l-...@web.de> From: Lucas Hoffmann <[email protected]> Date: Wed, 26 Aug 2015 11:10:53 +0200 Subject: [PATCH 1/6] Add script-interface subcommand. MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.7.0" This is a multi-part message in MIME format. --------------2.7.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- src/password-store.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) --------------2.7.0 Content-Type: text/x-patch; name="0001-Add-script-interface-subcommand.patch" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="0001-Add-script-interface-subcommand.patch" diff --git a/src/password-store.sh b/src/password-store.sh index 6f85d3b..198da35 100755 --- a/src/password-store.sh +++ b/src/password-store.sh @@ -118,6 +118,9 @@ check_sneaky_paths() { [[ $path =~ /\.\.$ || $path =~ ^\.\./ || $path =~ /\.\./ || $path =~ ^\.\.$ ]] && die "Error: You've attempted to pass a sneaky path to pass. Go home." done } +list_all_gpg_files() { + find -L "$PREFIX" -name .git -prune -o \( -type f -name '*.gpg' -print \) +} # # END helper functions @@ -569,6 +572,16 @@ cmd_git() { fi } +cmd_script_interface() { + case "$1" in + prefix) echo "$PREFIX";; + entries) list_all_gpg_files | sed -e "s#^${PREFIX//#/\\#}/\{0,1\}##" -e 's/\.gpg$//';; + dirs) list_all_gpg_files | sed -e "s#^${PREFIX//#/\\#}/\{0,1\}##" | while read line; do [[ -d "$PREFIX/${line%/*}" ]] && echo "${line%/*}"; done | sort -u;; + keys) $GPG $PASSWORD_STORE_GPG_OPTS --list-secret-keys --with-colons | cut -d : -f 10 | sort -u | sed '/^$/d';; + *) die "Error: Wrong argument for script-interface.";; + esac +} + # # END subcommand functions # @@ -590,6 +603,7 @@ case "$1" in rename|mv) shift; cmd_copy_move "move" "$@" ;; copy|cp) shift; cmd_copy_move "copy" "$@" ;; git) shift; cmd_git "$@" ;; + script-interface) shift; cmd_script_interface "$@";; *) COMMAND="show"; cmd_show "$@" ;; esac exit 0 --------------2.7.0--
From a223d3012fda4dee788b7d288886107d3a0c14e8 Mon Sep 17 00:00:00 2001 Message-Id: <a223d3012fda4dee788b7d288886107d3a0c14e8.1454635746.git.l-...@web.de> In-Reply-To: <c48ff10a23e7343c58f71d7cfd7dd888801020fe.1454635746.git.l-...@web.de> References: <c48ff10a23e7343c58f71d7cfd7dd888801020fe.1454635746.git.l-...@web.de> From: Lucas Hoffmann <[email protected]> Date: Thu, 27 Aug 2015 08:37:03 +0200 Subject: [PATCH 2/6] change function MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.7.0" This is a multi-part message in MIME format. --------------2.7.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- src/password-store.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) --------------2.7.0 Content-Type: text/x-patch; name="0002-change-function.patch" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="0002-change-function.patch" diff --git a/src/password-store.sh b/src/password-store.sh index 198da35..9506d81 100755 --- a/src/password-store.sh +++ b/src/password-store.sh @@ -118,8 +118,10 @@ check_sneaky_paths() { [[ $path =~ /\.\.$ || $path =~ ^\.\./ || $path =~ /\.\./ || $path =~ ^\.\.$ ]] && die "Error: You've attempted to pass a sneaky path to pass. Go home." done } -list_all_gpg_files() { - find -L "$PREFIX" -name .git -prune -o \( -type f -name '*.gpg' -print \) +find_files () { + local prefix="${1:-$PREFIX}" + shift + find -L "$prefix" -name .git -prune -o \( -type f -name '*.gpg' "${@:--print}" \) } # @@ -575,8 +577,8 @@ cmd_git() { cmd_script_interface() { case "$1" in prefix) echo "$PREFIX";; - entries) list_all_gpg_files | sed -e "s#^${PREFIX//#/\\#}/\{0,1\}##" -e 's/\.gpg$//';; - dirs) list_all_gpg_files | sed -e "s#^${PREFIX//#/\\#}/\{0,1\}##" | while read line; do [[ -d "$PREFIX/${line%/*}" ]] && echo "${line%/*}"; done | sort -u;; + entries) find_files | sed -e "s#^${PREFIX//#/\\#}/\{0,1\}##" -e 's/\.gpg$//';; + dirs) find_files | sed -e "s#^${PREFIX//#/\\#}/\{0,1\}##" | while read line; do [[ -d "$PREFIX/${line%/*}" ]] && echo "${line%/*}"; done | sort -u;; keys) $GPG $PASSWORD_STORE_GPG_OPTS --list-secret-keys --with-colons | cut -d : -f 10 | sort -u | sed '/^$/d';; *) die "Error: Wrong argument for script-interface.";; esac --------------2.7.0--
From 31d79e2bd5b58dd44d1dac8d7b032beff0f13602 Mon Sep 17 00:00:00 2001 Message-Id: <31d79e2bd5b58dd44d1dac8d7b032beff0f13602.1454635746.git.l-...@web.de> In-Reply-To: <c48ff10a23e7343c58f71d7cfd7dd888801020fe.1454635746.git.l-...@web.de> References: <c48ff10a23e7343c58f71d7cfd7dd888801020fe.1454635746.git.l-...@web.de> From: Lucas Hoffmann <[email protected]> Date: Thu, 27 Aug 2015 08:39:24 +0200 Subject: [PATCH 3/6] Use function in pass. MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.7.0" This is a multi-part message in MIME format. --------------2.7.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- src/password-store.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) --------------2.7.0 Content-Type: text/x-patch; name="0003-Use-function-in-pass.patch" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="0003-Use-function-in-pass.patch" diff --git a/src/password-store.sh b/src/password-store.sh index 9506d81..6c72f8c 100755 --- a/src/password-store.sh +++ b/src/password-store.sh @@ -110,7 +110,7 @@ reencrypt_path() { mv "$passfile_temp" "$passfile" || rm -f "$passfile_temp" fi prev_gpg_recipients="${GPG_RECIPIENTS[*]}" - done < <(find "$1" -iname '*.gpg' -print0) + done < <(find_files "$1" -print0) } check_sneaky_paths() { local path @@ -121,7 +121,7 @@ check_sneaky_paths() { find_files () { local prefix="${1:-$PREFIX}" shift - find -L "$prefix" -name .git -prune -o \( -type f -name '*.gpg' "${@:--print}" \) + find -L "$prefix" -name .git -prune -o \( -type f -iname '*.gpg' "${@:--print}" \) } # @@ -355,7 +355,7 @@ cmd_grep() { passfile="${passfile##*/}" printf "\e[94m%s\e[1m%s\e[0m:\n" "$passfile_dir" "$passfile" echo "$grepresults" - done < <(find -L "$PREFIX" -iname '*.gpg' -print0) + done < <(find_files "$PREFIX" -print0) } cmd_insert() { --------------2.7.0--
From b6c0e437572f6a0fca94aa9d469c42e6de9e18d6 Mon Sep 17 00:00:00 2001 Message-Id: <b6c0e437572f6a0fca94aa9d469c42e6de9e18d6.1454635746.git.l-...@web.de> In-Reply-To: <c48ff10a23e7343c58f71d7cfd7dd888801020fe.1454635746.git.l-...@web.de> References: <c48ff10a23e7343c58f71d7cfd7dd888801020fe.1454635746.git.l-...@web.de> From: Lucas Hoffmann <[email protected]> Date: Thu, 27 Aug 2015 08:50:26 +0200 Subject: [PATCH 4/6] use in completion MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.7.0" This is a multi-part message in MIME format. --------------2.7.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- src/completion/pass.bash-completion | 2 +- src/completion/pass.fish-completion | 24 ++++-------------------- src/completion/pass.zsh-completion | 11 +++-------- 3 files changed, 8 insertions(+), 29 deletions(-) --------------2.7.0 Content-Type: text/x-patch; name="0004-use-in-completion.patch" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="0004-use-in-completion.patch" diff --git a/src/completion/pass.bash-completion b/src/completion/pass.bash-completion index efd4b70..7b2f3bc 100644 --- a/src/completion/pass.bash-completion +++ b/src/completion/pass.bash-completion @@ -56,7 +56,7 @@ _pass_complete_folders () { _pass_complete_keys () { local IFS=$'\n' # Extract names and email addresses from gpg --list-keys - local keys="$(gpg2 --list-secret-keys --with-colons | cut -d : -f 10 | sort -u | sed '/^$/d')" + local keys="$(pass script-interface keys)" COMPREPLY+=($(compgen -W "${keys}" -- ${cur})) } diff --git a/src/completion/pass.fish-completion b/src/completion/pass.fish-completion index c32a42c..ecf1d6f 100644 --- a/src/completion/pass.fish-completion +++ b/src/completion/pass.fish-completion @@ -6,11 +6,7 @@ set PROG 'pass' function __fish_pass_get_prefix - set -l prefix "$PASSWORD_STORE_DIR" - if [ -z "$prefix" ] - set prefix "$HOME/.password-store" - end - echo "$prefix" + pass script-interface prefix end function __fish_pass_needs_command @@ -31,25 +27,13 @@ function __fish_pass_uses_command end function __fish_pass_print_gpg_keys - gpg2 --list-keys | grep uid | sed 's/.*<\(.*\)>/\1/' + pass script-interface keys end function __fish_pass_print_entry_dirs - set -l prefix (__fish_pass_get_prefix) - set -l dirs - eval "set dirs "$prefix"/**/" - for dir in $dirs - set entry (echo "$dir" | sed "s#$prefix/\(.*\)#\1#") - echo "$entry" - end + pass script-interface dirs end function __fish_pass_print_entries - set -l prefix (__fish_pass_get_prefix) - set -l files - eval "set files "$prefix"/**.gpg" - for file in $files - set file (echo "$file" | sed "s#$prefix/\(.*\)\.gpg#\1#") - echo "$file" - end + pass script-interface entries end function __fish_pass_print_entries_and_dirs __fish_pass_print_entry_dirs diff --git a/src/completion/pass.zsh-completion b/src/completion/pass.zsh-completion index 9bb3f97..bbc3b94 100644 --- a/src/completion/pass.zsh-completion +++ b/src/completion/pass.zsh-completion @@ -111,24 +111,19 @@ _pass_cmd_show () { "--clip[put it on the clipboard]" _pass_complete_entries } -_pass_complete_entries_helper () { - local IFS=$'\n' - local prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store}" - _values -C 'passwords' ${$(find -L "$prefix" \( -name .git -o -name .gpg-id \) -prune -o $@ -print 2>/dev/null | sed -e "s#${prefix}/\{0,1\}##" -e 's#\.gpg##' | sort):-""} -} _pass_complete_entries_with_subdirs () { - _pass_complete_entries_helper + { pass script-interface entries; pass script-interface dirs } | sort } _pass_complete_entries () { - _pass_complete_entries_helper -type f + pass script-interface entries } _pass_complete_keys () { local IFS=$'\n' # Extract names and email addresses from gpg --list-keys - _values 'gpg keys' $(gpg2 --list-secret-keys --with-colons | cut -d : -f 10 | sort -u | sed '/^$/d') + _values 'gpg keys' $(pass script-interface keys) } _pass --------------2.7.0--
From 1d44797be7fac54fe8f3d8cdac290d44659fd508 Mon Sep 17 00:00:00 2001 Message-Id: <1d44797be7fac54fe8f3d8cdac290d44659fd508.1454635746.git.l-...@web.de> In-Reply-To: <c48ff10a23e7343c58f71d7cfd7dd888801020fe.1454635746.git.l-...@web.de> References: <c48ff10a23e7343c58f71d7cfd7dd888801020fe.1454635746.git.l-...@web.de> From: Lucas Hoffmann <[email protected]> Date: Sat, 9 Jan 2016 10:38:24 +0100 Subject: [PATCH 5/6] Use the script interface in contrib and completion. MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.7.0" This is a multi-part message in MIME format. --------------2.7.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- contrib/dmenu/passmenu | 9 +-------- src/completion/pass.bash-completion | 4 ++-- 2 files changed, 3 insertions(+), 10 deletions(-) --------------2.7.0 Content-Type: text/x-patch; name="0005-Use-the-script-interface-in-contrib-and-completion.patch" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="0005-Use-the-script-interface-in-contrib-and-completion.patch" diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu index 9b5239d..08e400e 100755 --- a/contrib/dmenu/passmenu +++ b/contrib/dmenu/passmenu @@ -1,19 +1,12 @@ #!/usr/bin/env bash -shopt -s nullglob globstar - typeit=0 if [[ $1 == "--type" ]]; then typeit=1 shift fi -prefix=${PASSWORD_STORE_DIR-~/.password-store} -password_files=( "$prefix"/**/*.gpg ) -password_files=( "${password_files[@]#"$prefix"/}" ) -password_files=( "${password_files[@]%.gpg}" ) - -password=$(printf '%s\n' "${password_files[@]}" | dmenu "$@") +password=$(pass script-interface entries | dmenu "$@") [[ -n $password ]] || exit diff --git a/src/completion/pass.bash-completion b/src/completion/pass.bash-completion index 7b2f3bc..a6bb6de 100644 --- a/src/completion/pass.bash-completion +++ b/src/completion/pass.bash-completion @@ -5,7 +5,7 @@ # This file is licensed under the GPLv2+. Please see COPYING for more information. _pass_complete_entries () { - prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store/}" + prefix="$(pass script-interface prefix)" prefix="${prefix%/}/" suffix=".gpg" autoexpand=${1:-0} @@ -42,7 +42,7 @@ _pass_complete_entries () { } _pass_complete_folders () { - prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store/}" + prefix="$(pass script-interface prefix)" prefix="${prefix%/}/" local IFS=$'\n' --------------2.7.0--
From b89d1bb6b57d9afb944a7cb779f96b2e1f6fd67c Mon Sep 17 00:00:00 2001 Message-Id: <b89d1bb6b57d9afb944a7cb779f96b2e1f6fd67c.1454635746.git.l-...@web.de> In-Reply-To: <c48ff10a23e7343c58f71d7cfd7dd888801020fe.1454635746.git.l-...@web.de> References: <c48ff10a23e7343c58f71d7cfd7dd888801020fe.1454635746.git.l-...@web.de> From: Lucas Hoffmann <[email protected]> Date: Sat, 9 Jan 2016 11:00:21 +0100 Subject: [PATCH 6/6] dirs2 script interface sub command. MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.7.0" This is a multi-part message in MIME format. --------------2.7.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- src/password-store.sh | 1 + 1 file changed, 1 insertion(+) --------------2.7.0 Content-Type: text/x-patch; name="0006-dirs2-script-interface-sub-command.patch" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="0006-dirs2-script-interface-sub-command.patch" diff --git a/src/password-store.sh b/src/password-store.sh index 6c72f8c..3274222 100755 --- a/src/password-store.sh +++ b/src/password-store.sh @@ -579,6 +579,7 @@ cmd_script_interface() { prefix) echo "$PREFIX";; entries) find_files | sed -e "s#^${PREFIX//#/\\#}/\{0,1\}##" -e 's/\.gpg$//';; dirs) find_files | sed -e "s#^${PREFIX//#/\\#}/\{0,1\}##" | while read line; do [[ -d "$PREFIX/${line%/*}" ]] && echo "${line%/*}"; done | sort -u;; + dirs2) cd "$PREFIX" && find . -type d \( -name .git -prune -o -print \) | while read line; do [[ "$line" != . ]] && [[ -n "$line/"*.gpg ]] && echo "${line#./}"; done | sort -u;; keys) $GPG $PASSWORD_STORE_GPG_OPTS --list-secret-keys --with-colons | cut -d : -f 10 | sort -u | sed '/^$/d';; *) die "Error: Wrong argument for script-interface.";; esac --------------2.7.0--
signature.asc
Description: signature
_______________________________________________ Password-Store mailing list [email protected] http://lists.zx2c4.com/mailman/listinfo/password-store
