small pixel drawing of a pufferfish pa

Utilize age identity and recipient files

- simplify some code
- add a few ugly backwards-compat lifts
- Rename "key.txt" to "identities" and move its location to the pa store
  dir
- Move passwords into a dedicated "passwords" dir

Co-authored-by: Alan Morgan <alanxoc3@gmail.com>
Jes Olson j3s@c3f.net
Tue, 27 Dec 2022 23:10:57 -0800
commit

7b16e8e5378fb5a427915fc47ebfb1bdcdc8409f

parent

b32ce1a16187a101dc66e9fb8859c4626766aa1c

5 files changed, 53 insertions(+), 41 deletions(-)

jump to
M contrib/pa-bemenucontrib/pa-bemenu

@@ -8,8 +8,8 @@ # - wtype

# - bemenu # - pa -cd "${PA_DIR:-$HOME/.local/share/pa}" +cd "${PA_DIR:-$HOME/.local/share/pa/passwords}" password_files="$(find * -type f | grep -v '/.git')" -password=$(printf '%s\n' "$password_files" | sed 's/.age//' | bemenu -b "$@") +password=$(printf '%s\n' "$password_files" | sed 's/.age//' | bemenu -c -W 0.2 -l 20 "$@") pa show "$password" | head -n 1 | tr -d '\n' | wtype -
M contrib/pa-dmenucontrib/pa-dmenu

@@ -1,6 +1,6 @@

#!/bin/sh -cd "${PA_DIR:-$HOME/.local/share/pa}" +cd "${PA_DIR:-$HOME/.local/share/pa/passwords}" password_files="$(find * -type f | grep -v '/.git')" password=$(printf '%s\n' "$password_files" | sed 's/.age//' | dmenu "$@")
M contrib/pa-fuzzelcontrib/pa-fuzzel

@@ -2,7 +2,7 @@ #!/bin/sh

# # prompt for a password, then type the selected password -cd "${PA_DIR:-$HOME/.local/share/pa}" +cd "${PA_DIR:-$HOME/.local/share/pa/passwords}" password_files="$(find * -type f | grep -v '/.git')" password=$(printf '%s\n' "$password_files" | sed 's/.age//' | fuzzel -dmenu "$@")
M contrib/pa-roficontrib/pa-rofi

@@ -1,6 +1,6 @@

#!/bin/sh -cd "${PA_DIR:-$HOME/.local/share/pa}" +cd "${PA_DIR:-$HOME/.local/share/pa/passwords}" password_files="$(find * -type f | grep -v '/.git')" password=$(printf '%s\n' "$password_files" | sed 's/.age//' | rofi -dmenu -i "$@")
M papa

@@ -1,6 +1,6 @@

#!/bin/sh # -# pa - simple age-based password manager +# pa - a simple password manager based on age pw_add() { name=$1

@@ -43,7 +43,7 @@ #

# Heredocs are sometimes implemented via temporary files, # however this is typically done using 'mkstemp()' which # is more secure than a leak in '/proc'. - age -r "$pubkey" -o "$name.age" <<-EOF && + age -R "$recipients_file" -o "$name.age" <<-EOF && $pass EOF printf '%s\n' "Saved '$name' to the store."

@@ -67,7 +67,7 @@ tmpdir="$(dirname "$tmpfile")"

mkdir -p "$tmpdir" trap 'rm -rf /dev/shm/pa' EXIT - age -i ~/.age/key.txt --decrypt "$name.age" 2>/dev/null >"$tmpfile" || + age -i "$identities_file" --decrypt "$name.age" 2>/dev/null >"$tmpfile" || die "Could not decrypt $name.age" "${EDITOR:-vi}" "$tmpfile"

@@ -75,7 +75,7 @@

[ -f "$tmpfile" ] || die "New password not saved" rm "$name.age" - age -r "$pubkey" -o "$name.age" "$tmpfile" + age -R "$recipients_file" -o "$name.age" "$tmpfile" } pw_del() {

@@ -90,7 +90,7 @@ }

} pw_show() { - age -i ~/.age/key.txt --decrypt "$1.age" 2>/dev/null || + age -i "$identities_file" --decrypt "$1.age" 2>/dev/null || die "Could not decrypt $1.age" }

@@ -98,18 +98,9 @@ pw_list() {

find . -type f -name \*.age | sed 's/..//;s/\.age$//' } -pw_gen() { - if yn "$HOME/.age/key.txt not detected, generate a new one?"; then - mkdir -p ~/.age - age-keygen -o ~/.age/key.txt - fi -} - -depends() { - for dep in $@; do - command -v "$dep" >/dev/null 2>&1 || - die "$dep not found, install per https://github.com/FiloSottile/age" - done +dep() { + command -v "$1" >/dev/null 2>&1 || + die "$1 not found, install per https://github.com/FiloSottile/age" } yn() {

@@ -167,15 +158,20 @@ }

usage() { printf %s "\ -pa 0.1.0 - age-based password manager -=> [a]dd [name] - Create a new password, randomly generated -=> [d]el [name] - Delete a password entry. -=> [e]dit [name] - Edit a password entry with $EDITOR. -=> [l]ist - List all entries. -=> [s]how [name] - Show password for an entry. -Password length: export PA_LENGTH=50 -Password pattern: export PA_PATTERN=_A-Z-a-z-0-9 -Store location: export PA_DIR=~/.local/share/pa + pa 0.1.1 + a simple password manager based on age + + commands: + [a]dd [name] - Create a new password, randomly generated + [d]el [name] - Delete a password entry. + [e]dit [name] - Edit a password entry with $EDITOR. + [l]ist - List all entries. + [s]how [name] - Show password for an entry. + + default env vars: + Password length: export PA_LENGTH=50 + Password pattern: export PA_PATTERN=_A-Z-a-z-0-9 + Password/key dir: export PA_DIR=~/.local/share/pa " exit 0 }

@@ -183,13 +179,22 @@

main() { : "${PA_DIR:=${XDG_DATA_HOME:=$HOME/.local/share}/pa}" - depends age age-keygen + password_dir="$PA_DIR/passwords" - mkdir -p "$PA_DIR" || - die "Couldn't create password directory" + mkdir -p "$password_dir" || + die "Couldn't create password store" - cd "$PA_DIR" || - die "Can't access password directory" + cd "$password_dir" || + die "Can't access the password store" + + # Move any passwords hanging out in the old dir + # for backwards-compat reasons + set +f + mv ~/.local/share/pa/*.age "$password_dir" 2>/dev/null + set -f + + glob "$1" '[aes]' && + depends age glob "$1" '[ades]*' && [ -z "$2" ] && die "Missing [name] argument"

@@ -213,8 +218,18 @@ # Restrict permissions of any new files to

# only the current user. umask 077 - [ -f ~/.age/key.txt ] || pw_gen - pubkey=$(sed -n 's/.*\(age\)/\1/p' ~/.age/key.txt) + identities_file="$PA_DIR/identities" + # Copy any existing identities files from the old + # storage location to the new one - backwards compat. + [ ! -f "$identities_file" ] && [ -f ~/.age/key.txt ] && + cp ~/.age/key.txt "$identities_file" + + [ ! -f "$identities_file" ] && dep age-keygen && + age-keygen -o "$identities_file" 2>/dev/null + + recipients_file="$PA_DIR/recipients" + [ ! -f "$recipients_file" ] && dep age-keygen && + age-keygen -y -o "$recipients_file" "$identities_file" 2>/dev/null # Ensure that we leave the terminal in a usable # state on exit or Ctrl+C.

@@ -233,9 +248,6 @@

# Ensure that debug mode is never enabled to # prevent the password from leaking. set +x - -# -set -e # Ensure that globbing is globally disabled # to avoid insecurities with word-splitting.