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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.