To get my feet wet with shell scripting I wrote this "minimal command line
password manager" (aka pwm
) taking inspiration from the well known pass
.
It uses gpg
and creates a keypair on the first start. It can perform four simple actions: list all entries stored, add, show the content of or remove an entry.
I'd like to get some feedback. I "spotted" two main issues and I also have two questions.
Issues:
read
command will trim starting and trailing spaces;[ -d $KEY_STORE_DIR ]
as check to decide if keys should be generated may be a bit "weak" if for example the previous generation failed: it will return "true" (since$KEY_STORE_DIR
will exists) and key generation command will never be called again causing troubles;
Questions:
- Am I "abusing"
gpg
? I mean, am I doing something "stupid" with it? I don't use it a lot, I'm not an "expert", what I need is just a way to encrypt and decrypt files using the same passphrase (secret key passphrase here), I hope I'm using it in a "legit and safe" way. - I "wrapped"
gpg
commands inside strings and then called them simply writing$VAR_NAME
. Is this somehow "bad practice" in shell scripting?
pwm
#!/bin/sh
# pwm: command line password manager.
# Encrypts passwords using gpg key created at the first start of the program.
# The private key passphrase acts as "master password" to show stored passwords,
# so choose it carefully.
# Passwords are stored inside $PWM_STORE_DIR while gpg home directory is
# $KEY_STORE_DIR.
#
# Usage:
# pwm # list all entries stored
# pwm entry # show content of entry
# pwm -a entry # add entry
# pwm -r entry # remove entry
PWM_STORE_DIR="$HOME/.pwm"
KEY_STORE_DIR="$PWM_STORE_DIR/.key"
GPG_BASE="gpg --quiet --homedir $KEY_STORE_DIR"
GPG_GEN_KEY="$GPG_BASE --full-generate-key"
GPG_ENCRYPT="$GPG_BASE --default-recipient-self --encrypt --output"
GPG_DECRYPT="$GPG_BASE --decrypt"
exit_with_error()
{
printf "Error: %s\n" "$1" >&2
exit 1
}
pwm_init()
{
type gpg > /dev/null 2>&1 || exit_with_error "gpg is required"
[ -d "$KEY_STORE_DIR" ] && return
mkdir -p "$KEY_STORE_DIR"
chmod -R 700 "$PWM_STORE_DIR"
$GPG_GEN_KEY
}
add_entry()
{
local entry="$1"
[ -f $entry ] && exit_with_error "$entry already exists"
if [ -t 0 ]; then
printf "%s" "Enter password to be stored: "
stty -echo
fi
read -r password
if [ -t 0 ]; then
stty echo
printf "%b" "\n"
fi
printf "%s" "$password" | $GPG_ENCRYPT "$entry"
chmod 600 "$entry"
}
show_entry()
{
local entry="$1"
[ -f $entry ] || exit_with_error "$entry doesn't exist"
$GPG_DECRYPT "$entry" && printf "%b" "\n"
}
remove_entry()
{
local entry="$1"
[ -f $entry ] || exit_with_error "$entry doesn't exist"
rm -i "$entry"
}
main()
{
pwm_init
case $# in
0)
ls -1 "$PWM_STORE_DIR"
;;
1)
show_entry "$PWM_STORE_DIR/$1"
;;
2)
case "$1" in
"-a")
add_entry "$PWM_STORE_DIR/$2"
;;
"-r")
remove_entry "$PWM_STORE_DIR/$2"
;;
*)
exit_with_error "unknown option $1"
;;
esac
;;
*)
exit_with_error "wrong number of arguments"
;;
esac
}
main "$@"