From 274954953ce50ddecd4b2db5a603c51f9c4facae Mon Sep 17 00:00:00 2001 From: drduh Date: Fri, 31 Mar 2017 13:35:15 -0700 Subject: [PATCH] Small refactor, add help doc, simplify prompts --- pwd.sh | 162 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 91 insertions(+), 71 deletions(-) diff --git a/pwd.sh b/pwd.sh index 20588b5..9427697 100755 --- a/pwd.sh +++ b/pwd.sh @@ -1,6 +1,4 @@ #!/usr/bin/env bash -# -# Script for managing passwords in a GnuPG symmetrically encrypted file. set -o errtrace set -o nounset @@ -14,6 +12,7 @@ safe="${PWDSH_SAFE:=pwd.sh.safe}" fail () { # Print an error message and exit. + printf "\n\n" tput setaf 1 1 1 ; echo "Error: ${1}" ; tput sgr0 exit 1 } @@ -22,7 +21,7 @@ fail () { get_pass () { # Prompt for a password. - password='' + password="" prompt="${1}" while IFS= read -p "${prompt}" -r -s -n 1 char ; do @@ -40,28 +39,22 @@ get_pass () { password+="${char}" fi done - - if [[ -z "${password}" ]] ; then - fail "No password provided" - fi } decrypt () { # Decrypt with a password. - echo "${1}" | ${gpg} \ - --decrypt --armor --batch \ - --passphrase-fd 0 "${2}" 2>/dev/null + echo "${1}" | ${gpg} --armor --batch \ + --decrypt --passphrase-fd 0 "${2}" 2>/dev/null } encrypt () { # Encrypt with a password. - ${gpg} \ - --symmetric --armor --batch --yes \ - --passphrase-fd 3 \ + ${gpg} --armor --batch \ + --symmetric --yes --passphrase-fd 3 \ --output "${2}" "${3}" 3< <(echo "${1}") } @@ -69,25 +62,22 @@ encrypt () { read_pass () { # Read a password from safe. - if [[ ! -s ${safe} ]] ; then - fail "No passwords found" - fi + if [[ ! -s ${safe} ]] ; then fail "No password safe found" ; fi - if [[ -z "${2+x}" ]] ; then - read -r -p " - Username to read? (default: all) " username + if [[ -z "${2+x}" ]] ; then read -r -p " + Username (Enter for all): " username else username="${2}" fi - if [[ -z "${username}" || "${username}" == "all" ]] ; then - username="" - fi + if [[ -z "${username}" || "${username}" == "all" ]] ; then username="" ; fi - get_pass " - Enter password to unlock ${safe}: " + while [[ -z "${password}" ]] ; do get_pass " + Password to unlock ${safe}: " ; done printf "\n\n" - decrypt ${password} ${safe} | grep -F " ${username}" || fail "Decryption failed" + + decrypt ${password} ${safe} | grep -F " ${username}" \ + || fail "Decryption failed" } @@ -97,26 +87,24 @@ gen_pass () { len=50 max=100 - if [[ -z "${3+x}" ]] ; then - read -p " - Password length? (default: ${len}, max: ${max}) " length + if [[ -z "${3+x}" ]] ; then read -p " + + Password length (default: ${len}, max: ${max}): " length else length="${3}" fi - if [[ ${length} =~ ^[0-9]+$ ]] ; then - len=${length} - fi + if [[ ${length} =~ ^[0-9]+$ ]] ; then len=${length} ; fi # base64: 4 characters for every 3 bytes - ${gpg} --gen-random --armor 0 "$((${max} * 3/4))" | cut -c -${len} + ${gpg} --armor --gen-random 0 "$((${max} * 3/4))" | cut -c -"${len}" } write_pass () { # Write a password in safe. - # If no password provided, clear the entry by writing an empty line. + # If no password (delete action), clear the entry by writing an empty line. if [[ -z "${userpass+x}" ]] ; then entry=" " else @@ -124,7 +112,7 @@ write_pass () { fi get_pass " - Enter password to unlock ${safe}: " ; echo + Password to unlock ${safe}: " ; echo # If safe exists, decrypt it and filter out username, or bail on error. # If successful, append entry, or blank line. @@ -138,33 +126,25 @@ write_pass () { echo "${entry}") | \ (${filter} "^[[:space:]]*$|^mtime:[[:digit:]]+$";echo mtime:$(date +%s)) | \ encrypt ${password} ${safe}.new - || fail "Write to safe failed" - mv ${safe}.new ${safe} + mv ${safe}{.new,} } -create_username () { - # Create username with password. +new_entry () { + # Prompt for new username and/or password. - if [[ -z "${2+x}" ]] ; then - read -r -p " + if [[ -z "${2+x}" ]] ; then read -r -p " Username: " username else username="${2}" fi - if [[ -z "${3+x}" ]] ; then - read -p " - Generate password? (y/n, default: y) " rand_pass - else - rand_pass="" + if [[ -z "${3+x}" ]] ; then get_pass " + Password for \"${username}\" (Enter to generate): " + userpass="${password}" fi - if [[ "${rand_pass}" =~ ^([nN][oO]|[nN])$ ]]; then - get_pass " - Enter password for \"${username}\": " ; echo - userpass=${password} - else - userpass=$(gen_pass "$@") + if [[ -z "${password}" ]] ; then userpass=$(gen_pass "$@") if [[ -z "${4+x}" || ! "${4}" =~ ^([qQ])$ ]] ; then echo " Password: ${userpass}" @@ -172,42 +152,82 @@ create_username () { fi } +print_help () { + # Print help text. -sanity_check () { - # Make sure required programs are installed and are executable. + echo " + pwd.sh is a shell script to manage passwords with GnuPG symmetric encryption. - if [[ -z ${gpg} && ! -x ${gpg} ]] ; then - fail "GnuPG is not available" - fi + The script can be run interactively as './pwd.sh' or with the following args: + + * 'r' to read a password + * 'w' to write a password + * 'd' to delete a password + * 'h' to see this help text + + A username can be supplied as an additional argument or 'all' for all entries. + + For writing, a password length can be appended. Append 'q' to suppress output. + + Examples: + + * Read all passwords: + + ./pwd.sh r all + + * Write a password for 'github': + + ./pwd.sh w github + + * Generate a 50 character password for 'github' and write: + + ./pwd.sh w github 50 + + * To suppress the generated password: + + ./pwd.sh w github 50 q + + * Delete password for 'mail': + + ./pwd.sh d mail + + A password cannot be supplied as an argument, nor is used as one throughout + the script, to prevent it from appearing in process listing or logs. + + To report a bug, visit https://github.com/drduh/pwd.sh + " } -sanity_check +if [[ -z ${gpg} && ! -x ${gpg} ]] ; then fail "GnuPG is not available" ; fi -if [[ -z "${1+x}" ]] ; then - read -n 1 -p " - Read, write, or delete password? (r/w/d, default: r) " action - printf "\n" -else +password="" + +action="" +if [[ -n "${1+x}" ]] ; then action="${1}" -fi +fi -if [[ "${action}" =~ ^([wW])$ ]] ; then - create_username "$@" +while [[ -z "${action}" ]] ; + do read -n 1 -p " + Read, Write, or Delete password (or Help): " action + printf "\n" +done + +if [[ "${action}" =~ ^([hH])$ ]] ; then + print_help +elif [[ "${action}" =~ ^([wW])$ ]] ; then + new_entry "$@" write_pass - elif [[ "${action}" =~ ^([dD])$ ]] ; then - if [[ -z "${2+x}" ]] ; then - read -p " - Username to delete? " username + if [[ -z "${2+x}" ]] ; then read -p " + Username: " username else username="${2}" fi write_pass - else read_pass "$@" fi -tput setaf 2 2 2 ; echo " -Done" ; tput sgr0 +printf "\n" ; tput setaf 2 2 2 ; echo "Done" ; tput sgr0