summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2014-04-18 01:23:11 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2014-04-18 01:23:11 +0200
commitebd57647fa54721ec64aba47c79819ad270b3a63 (patch)
tree17a313ca64db9cab77a0a01bd96d25d2e8d90455
parent73a39dafb0f2c0fde355bf62f3ac9e991c05dbb6 (diff)
downloadpass-ebd57647fa54721ec64aba47c79819ad270b3a63.tar.gz
pass-ebd57647fa54721ec64aba47c79819ad270b3a63.tar.bz2
pass-ebd57647fa54721ec64aba47c79819ad270b3a63.zip
reencryption: only reencrypt files when required
Diffstat (limited to '')
-rw-r--r--man/pass.112
-rwxr-xr-xsrc/password-store.sh41
2 files changed, 37 insertions, 16 deletions
diff --git a/man/pass.1 b/man/pass.1
index 561fd86..86946fb 100644
--- a/man/pass.1
+++ b/man/pass.1
@@ -126,19 +126,19 @@ alternatively named \fBremove\fP or \fBdelete\fP. If \fI--recursive\fP or \fI-r\
is specified, delete pass-name recursively if it is a directory. If \fI--force\fP
or \fI-f\fP is specified, do not interactively prompt before removal.
.TP
-\fBmv\fP [ \fI--force\fP, \fI-f\fP ] \fIold-path\fP \fInew-path\fP
+\fBmv\fP [ \fI--reencrypt\fP, \fI-e\fP ] [ \fI--force\fP, \fI-f\fP ] \fIold-path\fP \fInew-path\fP
Renames the password or directory named \fIold-path\fP to \fInew-path\fP. This
command is alternatively named \fBrename\fP. If \fI--force\fP is specified,
silently overwrite \fInew-path\fP if it exists. If \fInew-path\fP ends in a
-trailing \fI/\fP, it is always treated as a directory. Passwords will be reencrypted
-to the corresponding keys of their new destination.
+trailing \fI/\fP, it is always treated as a directory. Passwords may be optionally
+reencrypted to the corresponding keys of their new destination.
.TP
-\fBcp\fP [ \fI--force\fP, \fI-f\fP ] \fIold-path\fP \fInew-path\fP
+\fBcp\fP [ \fI--reencrypt\fP, \fI-e\fP ] [ \fI--force\fP, \fI-f\fP ] \fIold-path\fP \fInew-path\fP
Copies the password or directory named \fIold-path\fP to \fInew-path\fP. This
command is alternatively named \fBcopy\fP. If \fI--force\fP is specified,
silently overwrite \fInew-path\fP if it exists. If \fInew-path\fP ends in a
-trailing \fI/\fP, it is always treated as a directory. Passwords will be reencrypted
-to the corresponding keys of their new destination.
+trailing \fI/\fP, it is always treated as a directory. Passwords may be optionally
+reencrypted to the corresponding keys of their new destination.
.TP
\fBgit\fP \fIgit-command-args\fP...
If the password store is a git repository, pass \fIgit-command-args\fP as arguments to
diff --git a/src/password-store.sh b/src/password-store.sh
index e791ece..0828a32 100755
--- a/src/password-store.sh
+++ b/src/password-store.sh
@@ -41,11 +41,13 @@ yesno() {
}
set_gpg_recipients() {
GPG_RECIPIENT_ARGS=( )
+ GPG_RECIPIENTS=( )
local gpg_id
if [[ -n $PASSWORD_STORE_KEY ]]; then
for gpg_id in $PASSWORD_STORE_KEY; do
GPG_RECIPIENT_ARGS+=( "-r" "$gpg_id" )
+ GPG_RECIPIENTS+=( "$gpg_id" )
done
return
fi
@@ -69,6 +71,7 @@ set_gpg_recipients() {
while read -r gpg_id; do
GPG_RECIPIENT_ARGS+=( "-r" "$gpg_id" )
+ GPG_RECIPIENTS+=( "$gpg_id" )
done < "$current"
}
agent_check() {
@@ -84,15 +87,31 @@ agent_check() {
reencrypt_path() {
local passfile
local passfile_dir
+ local passfile_display
local fake_uniqueness_safety
+ local prev_gpg_recipients
+ local gpg_keys
+ local current_keys
find "$1" -iname '*.gpg' | while read -r passfile; do
fake_uniqueness_safety="$RANDOM"
passfile_dir="${passfile%/*}"
passfile_dir="${passfile_dir#$PREFIX}"
passfile_dir="${passfile_dir#/}"
+ passfile_display="${passfile#$PREFIX/}"
+ passfile_display="${passfile_display%.gpg}"
+
set_gpg_recipients "$passfile_dir"
- $GPG -d $GPG_OPTS "$passfile" | $GPG -e "${GPG_RECIPIENT_ARGS[@]}" -o "$passfile.new.$fake_uniqueness_safety" $GPG_OPTS &&
- mv -v "$passfile.new.$fake_uniqueness_safety" "$passfile"
+ [[ $prev_gpg_recipients != "${GPG_RECIPIENTS[@]}" ]] && \
+ gpg_keys="$(gpg --list-keys --keyid-format long "${GPG_RECIPIENTS[@]}" | sed -n 's/sub *.*\/\([A-F0-9]\{16\}\) .*/\1/p' | sort | uniq)"
+ current_keys="$($GPG -v --list-only --keyid-format long "$passfile" 2>&1 | cut -d ' ' -f 5 | sort | uniq)"
+
+ if [[ $gpg_keys != "$current_keys" ]]; then
+ echo "$passfile_display: reencrypting to ${gpg_keys//$'\n'/ }"
+ $GPG -d $GPG_OPTS "$passfile" | $GPG -e "${GPG_RECIPIENT_ARGS[@]}" -o "$passfile.new.$fake_uniqueness_safety" $GPG_OPTS &&
+ mv "$passfile.new.$fake_uniqueness_safety" "$passfile"
+ fi
+
+ prev_gpg_recipients="${GPG_RECIPIENTS[@]}"
done
}
@@ -205,10 +224,10 @@ cmd_usage() {
Prompt before overwriting existing password unless forced.
$PROGRAM rm [--recursive,-r] [--force,-f] pass-name
Remove existing password or directory, optionally forcefully.
- $PROGRAM mv [--force,-f] old-path new-path
- Renames or moves old-path to new-path, optionally forcefully.
- $PROGRAM cp [--force,-f] old-path new-path
- Copies old-path to new-path, optionally forcefully.
+ $PROGRAM mv [--reencrypt,-e] [--force,-f] old-path new-path
+ Renames or moves old-path to new-path, optionally forcefully, optionally reencrypting.
+ $PROGRAM cp [--reencrypt,-e] [--force,-f] old-path new-path
+ Copies old-path to new-path, optionally forcefully, optionally reencrypting.
$PROGRAM git git-command-args...
If the password store is a git repository, execute a git command
specified by git-command-args.
@@ -256,7 +275,7 @@ cmd_init() {
if [[ $reencrypt -eq 1 ]]; then
agent_check
reencrypt_path "$PREFIX/$id_path"
- git_add_file "$PREFIX/$id_path" "Reencrypted password store using new GPG id ${id_print}."
+ git_add_file "$PREFIX/$id_path" "Reencrypted password store using new GPG id ${id_print%, }."
fi
}
@@ -517,16 +536,18 @@ cmd_copy_move() {
shift
local force=0
+ local reencrypt=0
local opts
opts="$($GETOPT -o f -l force -n "$PROGRAM" -- "$@")"
local err=$?
eval set -- "$opts"
while true; do case $1 in
-f|--force) force=1; shift ;;
+ -e|--reencrypt) reencrypt=1; shift ;;
--) shift; break ;;
esac done
if [[ $# -ne 2 ]]; then
- echo "Usage: $PROGRAM $COMMAND [--force,-f] old-path new-path"
+ echo "Usage: $PROGRAM $COMMAND [--reencrypt,-e] [--force,-f] old-path new-path"
exit 1
fi
local old_path="$PREFIX/${1%/}"
@@ -550,7 +571,7 @@ cmd_copy_move() {
if [[ $move -eq 1 ]]; then
mv $interactive -v "$old_path" "$new_path" || exit 1
- [[ -e "$new_path" ]] && reencrypt_path "$new_path"
+ [[ $reencrypt -eq 1 && -e "$new_path" ]] && reencrypt_path "$new_path"
if [[ -d $GIT_DIR && ! -e $old_path ]]; then
git rm -qr "$old_path"
@@ -562,7 +583,7 @@ cmd_copy_move() {
done
else
cp $interactive -r -v "$old_path" "$new_path" || exit 1
- [[ -e "$new_path" ]] && reencrypt_path "$new_path"
+ [[ $reencrypt -eq 1 && -e "$new_path" ]] && reencrypt_path "$new_path"
git_add_file "$new_path" "Copied ${1} to ${2}."
fi
}