2
\$\begingroup\$

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 "$@"
\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.