enforce absolute $PA_DIR + update dir handling (#51) * enforce absolute $PA_DIR + update dir handling * test: use absolute dir (/tmp/pa-test) * globby Co-authored-by: arĉi <arcxi@dismail.de> * data directory * unbreak xdg basedir spec Co-authored-by: arĉi <arcxi@dismail.de> * simplify mkdir -p Co-authored-by: arĉi <arcxi@dismail.de> * s/basedir/PA_DIR/g * small readme fixes * adjust contribs --------- Co-authored-by: arĉi <arcxi@dismail.de>
j3s j3s@c3f.net
Tue, 11 Feb 2025 21:36:53 -0600
6 files changed,
36 insertions(+),
43 deletions(-)
M
README
→
README
@@ -32,7 +32,7 @@ [l]ist - List all entries.
[s]how [name] - Show password for an entry. env vars: - password dir: export PA_DIR=~/.local/share/pa/passwords + data directory: export PA_DIR=~/.local/share/pa/passwords password length: export PA_LENGTH=50 password pattern: export PA_PATTERN=A-Za-z0-9-_ disable tracking: export PA_NOGIT=@@ -40,8 +40,8 @@
command examples $ pa add test - Generate a password? [y/N]: y - Saved 'test' to the store. + generate a password? [y/N]: y + saved 'test' to the store. $ pa list test@@ -53,7 +53,7 @@ $ pa edit test
<opens $EDITOR or vi> $ pa del test - Delete password 'test'? [y/N]: y + delete password 'test'? [y/N]: y $ pa git log --oneline bbe85dc (HEAD -> main) delete 'test'
M
contrib/pa-pass
→
contrib/pa-pass
@@ -6,8 +6,7 @@ # password dir of pass: export PASSWORD_STORE_DIR=~/.password-store
# password dir of pa: export PA_DIR=~/.local/share/pa/passwords : "${PASSWORD_STORE_DIR:=$HOME/.password-store}" -basedir=${XDG_DATA_HOME:=$HOME/.local/share}/pa -: "${PA_DIR:=$basedir/passwords}" +: "${PA_DIR:=${XDG_DATA_HOME:-$HOME/.local/share}/pa}" # Create pa store if it doesn't exist. pa l >/dev/null || exit@@ -16,12 +15,13 @@ age=$(command -v age || command -v rage)
find "$PASSWORD_STORE_DIR" -name '*.gpg' | while read -r passfile; do name=$(printf %s "${passfile#"$PASSWORD_STORE_DIR/"}" | sed 's/\.gpg$//') - mkdir -p "$PA_DIR/$(dirname "./$name")" + mkdir -p "$PA_DIR/passwords/$(dirname "./$name")" gpg2 -d "$passfile" | - $age -R "$basedir/recipients" -o "$PA_DIR/$name.age" && + $age -R "$PA_DIR/recipients" -o "$PA_DIR/passwords/$name.age" && printf '%s\n' "saved '$name' to the store." done if [ -z "${PA_NOGIT+x}" ] && command -v git >/dev/null 2>&1; then - git -C "$PA_DIR" add . && git -C "$PA_DIR" commit -m "migrate from pass" + git -C "$PA_DIR/passwords" add . + git -C "$PA_DIR/passwords" commit -m "migrate from pass" fi
M
contrib/pa-rekey
→
contrib/pa-rekey
@@ -19,13 +19,12 @@
# Restrict permissions of any new files to only the current user. umask 077 -basedir=${XDG_DATA_HOME:=$HOME/.local/share}/pa -: "${PA_DIR:=$basedir/passwords}" +: "${PA_DIR:=${XDG_DATA_HOME:-$HOME/.local/share}/pa}" -realstore=$(realpath "$PA_DIR") || +realstore=$(realpath "$PA_DIR/passwords") || die "couldn't get path to password directory" -tmpdir=$basedir/tmp +tmpdir=$PA_DIR/tmp mkdir "$tmpdir" || die "couldn't create temporary directory"@@ -57,8 +56,8 @@ rm -rf "$realstore" ||
die "couldn't remove password directory" mv "$tmpdir/passwords" "$realstore" -mv "$tmpdir/identities" "$(realpath "$basedir/identities")" -mv "$tmpdir/recipients" "$(realpath "$basedir/recipients")" +mv "$tmpdir/identities" "$(realpath "$PA_DIR/identities")" +mv "$tmpdir/recipients" "$(realpath "$PA_DIR/recipients")" rmdir "$tmpdir" # Recreate git repository if needed.
M
contrib/pa-urn
→
contrib/pa-urn
@@ -36,10 +36,9 @@
age=$(command -v age || command -v rage) || die "age not found, install per https://age-encryption.org" -basedir=${XDG_DATA_HOME:=$HOME/.local/share}/pa -: "${PA_DIR:=$basedir/passwords}" +: "${PA_DIR:=${XDG_DATA_HOME:-$HOME/.local/share}/pa}" -dir=$(realpath "$PA_DIR") || +dir=$(realpath "$PA_DIR/passwords") || die "couldn't get path to password directory" name=$(basename "$dir")@@ -56,15 +55,15 @@ die "couldn't change to parent of password directory"
case $1 in c*) - { create_tar "$name" | $age -R "$basedir/recipients" -o "$urn"; } && + { create_tar "$name" | $age -R "$PA_DIR/recipients" -o "$urn"; } && printf '%s\n' "store has been archived into $urn" ;; o*) [ -f "$urn" ] || die "file '$urn' doesn't exist" - { $age --decrypt -i "$basedir/identities" "$urn" | extract_tar; } && - printf '%s\n' "file has been extracted into $PA_DIR" + { $age --decrypt -i "$PA_DIR/identities" "$urn" | extract_tar; } && + printf '%s\n' "file has been extracted into $PA_DIR/passwords" ;; *) usage ;; esac
M
pa
→
pa
@@ -188,7 +188,7 @@ [l]ist - List all entries.
[s]how [name] - Show password for an entry. env vars: - password dir: export PA_DIR=~/.local/share/pa/passwords + data directory: export PA_DIR=~/.local/share/pa password length: export PA_LENGTH=50 password pattern: export PA_PATTERN=A-Za-z0-9-_ disable tracking: export PA_NOGIT=@@ -203,20 +203,19 @@
age_keygen=$(command -v age-keygen || command -v rage-keygen) || die "age-keygen not found, install per https://age-encryption.org" - basedir=${XDG_DATA_HOME:=$HOME/.local/share}/pa - : "${PA_DIR:=$basedir/passwords}" - identities_file=$basedir/identities - recipients_file=$basedir/recipients + : "${PA_DIR:=${XDG_DATA_HOME:-$HOME/.local/share}/pa}" + + glob "$PA_DIR" '/*' || + die "PA_DIR must be an absolute path (got '$PA_DIR')" + + identities_file=$PA_DIR/identities + recipients_file=$PA_DIR/recipients - mkdir -p "$basedir" "$PA_DIR" || + mkdir -p "$PA_DIR/passwords" || die "couldn't create pa directories" - cd "$PA_DIR" || + cd "$PA_DIR/passwords" || die "couldn't change to password directory" - - # Move any passwords hanging out in the old dir - # for backwards-compat reasons - mv "$basedir"/*.age "$PA_DIR" 2>/dev/null # Ensure that globbing is disabled # to avoid insecurities with word-splitting.@@ -272,11 +271,7 @@
glob "$command" '[ds]*' && [ ! -f "$name.age" ] && die "password '$name' doesn't exist" - # First, copy any existing identities files from the old - # storage location to the new one for backwards compat. - # Then, attempt key generation. [ -f "$identities_file" ] || - cp ~/.age/key.txt "$identities_file" 2>/dev/null || $age_keygen -o "$identities_file" 2>/dev/null [ -f "$recipients_file" ] ||
M
test
→
test
@@ -8,14 +8,14 @@ printf "%s\n" "$*"
failures=$((failures + 1)) } -export PA_DIR=test-stuff/passwords +export PA_DIR=/tmp/pa-test # clean up previous run # (the previous state is left around # intentionally, in case the dev # wants to poke around) # that's why we don't clean up on exit -rm -rf test-stuff +rm -rf /tmp/pa-test # pa welcomes you ./pa | grep -q "a simple password manager" ||@@ -25,13 +25,13 @@ # generate pa dirs/identityfile/recipientfile
./pa list # pa auto-generated files are correct -test -s test-stuff/identities || +test -s "$PA_DIR/identities" || fail "an identities file should exist" -test -s test-stuff/recipients || +test -s "$PA_DIR/recipients" || fail "a recipients file should exist" -test -d "$PA_DIR/.git" || +test -d "$PA_DIR/passwords/.git" || fail "git dir should exist" # TODO: ensure git author/email are set correctly, etc@@ -44,7 +44,7 @@ generate a password? [y/N]: y
saved 'nested/password' to the store." || fail "pa add should say it stored nested/password" -test -s test-stuff/passwords/nested/password.age || +test -s "$PA_DIR/passwords/nested/password.age" || fail "pa add should create an encrypted password file" # pa list@@ -56,7 +56,7 @@ test" ||
fail "pa list output should match example" # ensure git commits are working -git -C test-stuff/passwords log | grep -q "add 'nested/password'" || +git -C "$PA_DIR/passwords" log | grep -q "add 'nested/password'" || fail "git log should have line: add 'nested/password'" # print info & exit w/ correct status