m-chrzan.xyz
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2017-02-25 16:56:58 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2017-02-25 16:56:58 +0100
commitb24a90c8dde57e019b7c88039821c4a39361f1b3 (patch)
tree6ca95e2e054d97d424a4b5d092b6b76f3287661d
parentb08781e2a6e183986eb1c24f51cdeff879b7a6af (diff)
git: use inner-most directory
-rw-r--r--man/pass.111
-rwxr-xr-xsrc/password-store.sh64
2 files changed, 48 insertions, 27 deletions
diff --git a/man/pass.1 b/man/pass.1
index ffbc405..e842178 100644
--- a/man/pass.1
+++ b/man/pass.1
@@ -41,8 +41,10 @@ Otherwise COMMAND must be one of the valid commands listed below.
Several of the commands below rely on or provide additional functionality if
the password store directory is also a git repository. If the password store
directory is a git repository, all password store modification commands will
-cause a corresponding git commit. See the \fIEXTENDED GIT EXAMPLE\fP section
-for a detailed description using \fBinit\fP and
+cause a corresponding git commit. Sub-directories may be separate nested git
+repositories, and pass will use the inner-most directory relative to the
+current password. See the \fIEXTENDED GIT EXAMPLE\fP section for a detailed
+description using \fBinit\fP and
.BR git (1).
The \fBinit\fP command must be run before other commands in order to initialize
@@ -410,11 +412,6 @@ Overrides the default gpg key identification set by \fBinit\fP. Keys must not
contain spaces and thus use of the hexadecimal key signature is recommended.
Multiple keys may be specified separated by spaces.
.TP
-.I PASSWORD_STORE_GIT
-Overrides the default root of the git repository, which is helpful if
-\fIPASSWORD_STORE_DIR\fP is temporarily set to a sub-directory of the default
-password store.
-.TP
.I PASSWORD_STORE_GPG_OPTS
Additional options to be passed to all invocations of GPG.
.TP
diff --git a/src/password-store.sh b/src/password-store.sh
index 17142f0..eced113 100755
--- a/src/password-store.sh
+++ b/src/password-store.sh
@@ -20,24 +20,30 @@ GENERATED_LENGTH="${PASSWORD_STORE_GENERATED_LENGTH:-25}"
CHARACTER_SET="${PASSWORD_STORE_CHARACTER_SET:-[:graph:]}"
CHARACTER_SET_NO_SYMBOLS="${PASSWORD_STORE_CHARACTER_SET_NO_SYMBOLS:-[:alnum:]}"
-export GIT_DIR="${PASSWORD_STORE_GIT:-$PREFIX}/.git"
-export GIT_WORK_TREE="${PASSWORD_STORE_GIT:-$PREFIX}"
+export GIT_CEILING_DIRECTORIES="$PREFIX/.."
#
# BEGIN helper functions
#
+set_git() {
+ INNER_GIT_DIR="${1%/*}"
+ while [[ ! -d $INNER_GIT_DIR && ${INNER_GIT_DIR%/*}/ == "${PREFIX%/}/"* ]]; do
+ INNER_GIT_DIR="${INNER_GIT_DIR%/*}"
+ done
+ [[ $(git -C "$INNER_GIT_DIR" rev-parse --is-inside-work-tree 2>/dev/null) == true ]] || INNER_GIT_DIR=""
+}
git_add_file() {
- [[ -e $GIT_DIR ]] || return
- git add "$1" || return
- [[ -n $(git status --porcelain "$1") ]] || return
+ [[ -n $INNER_GIT_DIR ]] || return
+ git -C "$INNER_GIT_DIR" add "$1" || return
+ [[ -n $(git -C "$INNER_GIT_DIR" status --porcelain "$1") ]] || return
git_commit "$2"
}
git_commit() {
local sign=""
- [[ -e $GIT_DIR ]] || return
- [[ $(git config --bool --get pass.signcommits) == "true" ]] && sign="-S"
- git commit $sign -m "$1"
+ [[ -n $INNER_GIT_DIR ]] || return
+ [[ $(git -C "$INNER_GIT_DIR" config --bool --get pass.signcommits) == "true" ]] && sign="-S"
+ git -C "$INNER_GIT_DIR" commit $sign -m "$1"
}
yesno() {
[[ -t 0 ]] || return 0
@@ -306,12 +312,13 @@ cmd_init() {
[[ -n $id_path && ! -d $PREFIX/$id_path && -e $PREFIX/$id_path ]] && die "Error: $PREFIX/$id_path exists but is not a directory."
local gpg_id="$PREFIX/$id_path/.gpg-id"
+ set_git "$gpg_id"
if [[ $# -eq 1 && -z $1 ]]; then
[[ ! -f "$gpg_id" ]] && die "Error: $gpg_id does not exist and so cannot be removed."
rm -v -f "$gpg_id" || exit 1
- if [[ -e $GIT_DIR ]]; then
- git rm -qr "$gpg_id"
+ if [[ -n $INNER_GIT_DIR ]]; then
+ git -C "$INNER_GIT_DIR" rm -qr "$gpg_id"
git_commit "Deinitialize ${gpg_id}${id_path:+ ($id_path)}."
fi
rmdir -p "${gpg_id%/*}" 2>/dev/null
@@ -419,6 +426,7 @@ cmd_insert() {
local path="${1%/}"
local passfile="$PREFIX/$path.gpg"
check_sneaky_paths "$path"
+ set_git "$passfile"
[[ $force -eq 0 && -e $passfile ]] && yesno "An entry already exists for $path. Overwrite it?"
@@ -459,6 +467,7 @@ cmd_edit() {
mkdir -p -v "$PREFIX/$(dirname "$path")"
set_gpg_recipients "$(dirname "$path")"
local passfile="$PREFIX/$path.gpg"
+ set_git "$passfile"
tmpdir #Defines $SECURE_TMPDIR
local tmp_file="$(mktemp -u "$SECURE_TMPDIR/XXXXXX")-${path//\//-}.txt"
@@ -500,6 +509,7 @@ cmd_generate() {
mkdir -p -v "$PREFIX/$(dirname "$path")"
set_gpg_recipients "$(dirname "$path")"
local passfile="$PREFIX/$path.gpg"
+ set_git "$passfile"
[[ $inplace -eq 0 && $force -eq 0 && -e $passfile ]] && yesno "An entry already exists for $path. Overwrite it?"
@@ -545,14 +555,17 @@ cmd_delete() {
local passdir="$PREFIX/${path%/}"
local passfile="$PREFIX/$path.gpg"
- [[ -f $passfile && -d $passdir && $path == */ || ! -f $passfile ]] && passfile="$passdir"
+ [[ -f $passfile && -d $passdir && $path == */ || ! -f $passfile ]] && passfile="${passdir%/}/"
[[ -e $passfile ]] || die "Error: $path is not in the password store."
+ set_git "$passfile"
[[ $force -eq 1 ]] || yesno "Are you sure you would like to delete $path?"
rm $recursive -f -v "$passfile"
- if [[ -e $GIT_DIR && ! -e $passfile ]]; then
- git rm -qr "$passfile"
+ set_git "$passfile"
+ if [[ -n $INNER_GIT_DIR && ! -e $passfile ]]; then
+ git -C "$INNER_GIT_DIR" rm -qr "$passfile"
+ set_git "$passfile"
git_commit "Remove $path from store."
fi
rmdir -p "${passfile%/*}" 2>/dev/null
@@ -588,14 +601,23 @@ cmd_copy_move() {
local interactive="-i"
[[ ! -t 0 || $force -eq 1 ]] && interactive="-f"
+ set_git "$new_path"
if [[ $move -eq 1 ]]; then
mv $interactive -v "$old_path" "$new_path" || exit 1
[[ -e "$new_path" ]] && reencrypt_path "$new_path"
- if [[ -e $GIT_DIR && ! -e $old_path ]]; then
- git rm -qr "$old_path"
+ set_git "$new_path"
+ if [[ -n $INNER_GIT_DIR && ! -e $old_path ]]; then
+ git -C "$INNER_GIT_DIR" rm -qr "$old_path" 2>/dev/null
+ set_git "$new_path"
git_add_file "$new_path" "Rename ${1} to ${2}."
fi
+ set_git "$old_path"
+ if [[ -n $INNER_GIT_DIR && ! -e $old_path ]]; then
+ git -C "$INNER_GIT_DIR" rm -qr "$old_path" 2>/dev/null
+ set_git "$old_path"
+ [[ -n $(git -C "$INNER_GIT_DIR" status --porcelain "$old_path") ]] && git_commit "Remove ${1}."
+ fi
rmdir -p "$old_dir" 2>/dev/null
else
cp $interactive -r -v "$old_path" "$new_path" || exit 1
@@ -605,18 +627,20 @@ cmd_copy_move() {
}
cmd_git() {
+ set_git "$PREFIX/"
if [[ $1 == "init" ]]; then
- git "$@" || exit 1
+ INNER_GIT_DIR="$PREFIX"
+ git -C "$INNER_GIT_DIR" "$@" || exit 1
git_add_file "$PREFIX" "Add current contents of password store."
echo '*.gpg diff=gpg' > "$PREFIX/.gitattributes"
git_add_file .gitattributes "Configure git repository for gpg file diff."
- git config --local diff.gpg.binary true
- git config --local diff.gpg.textconv "$GPG -d ${GPG_OPTS[*]}"
- elif [[ -e $GIT_DIR ]]; then
+ git -C "$INNER_GIT_DIR" config --local diff.gpg.binary true
+ git -C "$INNER_GIT_DIR" config --local diff.gpg.textconv "$GPG -d ${GPG_OPTS[*]}"
+ elif [[ -n $INNER_GIT_DIR ]]; then
tmpdir nowarn #Defines $SECURE_TMPDIR. We don't warn, because at most, this only copies encrypted files.
export TMPDIR="$SECURE_TMPDIR"
- git "$@"
+ git -C "$INNER_GIT_DIR" "$@"
else
die "Error: the password store is not a git repository. Try \"$PROGRAM git init\"."
fi