aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--man/pass.110
-rw-r--r--src/completion/pass.bash-completion4
-rw-r--r--src/completion/pass.fish-completion4
-rw-r--r--src/completion/pass.zsh-completion3
-rwxr-xr-xsrc/password-store.sh60
5 files changed, 56 insertions, 25 deletions
diff --git a/man/pass.1 b/man/pass.1
index 3039143..561fd86 100644
--- a/man/pass.1
+++ b/man/pass.1
@@ -130,7 +130,15 @@ or \fI-f\fP is specified, do not interactively prompt before removal.
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.
+trailing \fI/\fP, it is always treated as a directory. Passwords will be reencrypted
+to the corresponding keys of their new destination.
+.TP
+\fBcp\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.
.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/completion/pass.bash-completion b/src/completion/pass.bash-completion
index 08378f7..69a044d 100644
--- a/src/completion/pass.bash-completion
+++ b/src/completion/pass.bash-completion
@@ -57,7 +57,7 @@ _pass()
{
COMPREPLY=()
local cur="${COMP_WORDS[COMP_CWORD]}"
- local commands="init ls find grep show insert generate edit rm git help version"
+ local commands="init ls find grep show insert generate edit rm mv cp git help version"
if [[ $COMP_CWORD -gt 1 ]]; then
local lastarg="${COMP_WORDS[$COMP_CWORD-1]}"
case "${COMP_WORDS[1]}" in
@@ -84,7 +84,7 @@ _pass()
COMPREPLY+=($(compgen -W "-n --no-symbols -c --clip -f --force" -- ${cur}))
_pass_complete_entries
;;
- mv|rename)
+ cp|copy|mv|rename)
COMPREPLY+=($(compgen -W "-f --force" -- ${cur}))
_pass_complete_entries
;;
diff --git a/src/completion/pass.fish-completion b/src/completion/pass.fish-completion
index 2498be4..b0c44ef 100644
--- a/src/completion/pass.fish-completion
+++ b/src/completion/pass.fish-completion
@@ -85,6 +85,10 @@ complete -c $PROG -f -A -n '__fish_pass_needs_command' -a mv -d 'Command: rename
complete -c $PROG -f -A -n '__fish_pass_uses_command mv' -s f -l force -d 'Force rename'
complete -c $PROG -f -A -n '__fish_pass_uses_command mv' -a "(__fish_pass_print_entries_and_dirs)"
+complete -c $PROG -f -A -n '__fish_pass_needs_command' -a cp -d 'Command: copy existing password'
+complete -c $PROG -f -A -n '__fish_pass_uses_command cp' -s f -l force -d 'Force copy'
+complete -c $PROG -f -A -n '__fish_pass_uses_command cp' -a "(__fish_pass_print_entries_and_dirs)"
+
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a rm -d 'Command: remove existing password'
complete -c $PROG -f -A -n '__fish_pass_uses_command rm' -s r -l recursive -d 'Remove password groups recursively'
complete -c $PROG -f -A -n '__fish_pass_uses_command rm' -s f -l force -d 'Force removal'
diff --git a/src/completion/pass.zsh-completion b/src/completion/pass.zsh-completion
index b451fbf..55d9bb5 100644
--- a/src/completion/pass.zsh-completion
+++ b/src/completion/pass.zsh-completion
@@ -48,7 +48,7 @@ _pass () {
"--clip[copy password to the clipboard]"
_pass_complete_entries_with_subdirs
;;
- mv|rename)
+ cp|copy|mv|rename)
_arguments : \
"-f[force rename]" \
"--force[force rename]" \
@@ -90,6 +90,7 @@ _pass () {
"generate:Generate a new password using pwgen"
"edit:Edit a password with \$EDITOR"
"mv:Rename the password"
+ "cp:Copy the password"
"rm:Remove the password"
"git:Call git on the password store"
"version:Output version information"
diff --git a/src/password-store.sh b/src/password-store.sh
index 5b2293a..9f280cf 100755
--- a/src/password-store.sh
+++ b/src/password-store.sh
@@ -80,6 +80,20 @@ agent_check() {
_EOF
)"
}
+reencrypt_path() {
+ local passfile
+ local passfile_dir
+ local fake_uniqueness_safety
+ 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#/}"
+ 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"
+ done
+}
#
# END helper functions
@@ -192,6 +206,8 @@ cmd_usage() {
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 cv [--force,-f] old-path new-path
+ Copies old-path to new-path, optionally forcefully.
$PROGRAM git git-command-args...
If the password store is a git repository, execute a git command
specified by git-command-args.
@@ -238,16 +254,7 @@ cmd_init() {
if [[ $reencrypt -eq 1 ]]; then
agent_check
- local passfile
- find "$PREFIX/$id_path" -iname '*.gpg' | while read -r passfile; do
- fake_uniqueness_safety="$RANDOM"
- passfile_dir="${passfile%/*}"
- passfile_dir="${passfile_dir#$PREFIX}"
- passfile_dir="${passfile_dir#/}"
- 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"
- done
+ reencrypt_path "$PREFIX/$id_path"
git_add_file "$PREFIX/$id_path" "Reencrypted password store using new GPG id ${id_print}."
fi
}
@@ -503,9 +510,12 @@ cmd_delete() {
fi
}
-cmd_rename() {
- local force=0
+cmd_copy_move() {
+ local move=1
+ [[ $1 == "copy" ]] && move=0
+ shift
+ local force=0
local opts
opts="$($GETOPT -o f -l force -n "$PROGRAM" -- "$@")"
local err=$?
@@ -537,16 +547,23 @@ cmd_rename() {
local interactive="-i"
[[ $force -eq 1 ]] && interactive="-f"
- mv $interactive -v "$old_path" "$new_path" || exit 1
+ if [[ $move -eq 1 ]]; then
+ mv $interactive -v "$old_path" "$new_path" || exit 1
+ [[ -e "$new_path" ]] && reencrypt_path "$new_path"
- if [[ -d $GIT_DIR && ! -e $old_path ]]; then
- git rm -qr "$old_path"
- git_add_file "$new_path" "Renamed ${1} to ${2}."
- fi
+ if [[ -d $GIT_DIR && ! -e $old_path ]]; then
+ git rm -qr "$old_path"
+ git_add_file "$new_path" "Renamed ${1} to ${2}."
+ fi
- while rmdir "$old_dir" &>/dev/null; do
- old_dir="${old_dir%/*}"
- done
+ while rmdir "$old_dir" &>/dev/null; do
+ old_dir="${old_dir%/*}"
+ done
+ else
+ cp $interactive -r -v "$old_path" "$new_path" || exit 1
+ [[ -e "$new_path" ]] && reencrypt_path "$new_path"
+ git_add_file "$new_path" "Copied ${1} to ${2}."
+ fi
}
cmd_git() {
@@ -579,7 +596,8 @@ case "$1" in
edit) shift; cmd_edit "$@"; ;;
generate) shift; cmd_generate "$@"; ;;
delete|rm|remove) shift; cmd_delete "$@"; ;;
- rename|mv) shift; cmd_rename "$@"; ;;
+ rename|mv) shift; cmd_copy_move "move" "$@"; ;;
+ copy|cp) shift; cmd_copy_move "copy" "$@"; ;;
git) shift; cmd_git "$@"; ;;
*) COMMAND="show"; cmd_show "$@"; ;;
esac