Small refactor, add help doc, simplify prompts

This commit is contained in:
drduh 2017-03-31 13:35:15 -07:00 committed by GitHub
parent d14f551e87
commit 274954953c
1 changed files with 91 additions and 71 deletions

162
pwd.sh
View File

@ -1,6 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#
# Script for managing passwords in a GnuPG symmetrically encrypted file.
set -o errtrace set -o errtrace
set -o nounset set -o nounset
@ -14,6 +12,7 @@ safe="${PWDSH_SAFE:=pwd.sh.safe}"
fail () { fail () {
# Print an error message and exit. # Print an error message and exit.
printf "\n\n"
tput setaf 1 1 1 ; echo "Error: ${1}" ; tput sgr0 tput setaf 1 1 1 ; echo "Error: ${1}" ; tput sgr0
exit 1 exit 1
} }
@ -22,7 +21,7 @@ fail () {
get_pass () { get_pass () {
# Prompt for a password. # Prompt for a password.
password='' password=""
prompt="${1}" prompt="${1}"
while IFS= read -p "${prompt}" -r -s -n 1 char ; do while IFS= read -p "${prompt}" -r -s -n 1 char ; do
@ -40,28 +39,22 @@ get_pass () {
password+="${char}" password+="${char}"
fi fi
done done
if [[ -z "${password}" ]] ; then
fail "No password provided"
fi
} }
decrypt () { decrypt () {
# Decrypt with a password. # Decrypt with a password.
echo "${1}" | ${gpg} \ echo "${1}" | ${gpg} --armor --batch \
--decrypt --armor --batch \ --decrypt --passphrase-fd 0 "${2}" 2>/dev/null
--passphrase-fd 0 "${2}" 2>/dev/null
} }
encrypt () { encrypt () {
# Encrypt with a password. # Encrypt with a password.
${gpg} \ ${gpg} --armor --batch \
--symmetric --armor --batch --yes \ --symmetric --yes --passphrase-fd 3 \
--passphrase-fd 3 \
--output "${2}" "${3}" 3< <(echo "${1}") --output "${2}" "${3}" 3< <(echo "${1}")
} }
@ -69,25 +62,22 @@ encrypt () {
read_pass () { read_pass () {
# Read a password from safe. # Read a password from safe.
if [[ ! -s ${safe} ]] ; then if [[ ! -s ${safe} ]] ; then fail "No password safe found" ; fi
fail "No passwords found"
fi
if [[ -z "${2+x}" ]] ; then if [[ -z "${2+x}" ]] ; then read -r -p "
read -r -p " Username (Enter for all): " username
Username to read? (default: all) " username
else else
username="${2}" username="${2}"
fi fi
if [[ -z "${username}" || "${username}" == "all" ]] ; then if [[ -z "${username}" || "${username}" == "all" ]] ; then username="" ; fi
username=""
fi
get_pass " while [[ -z "${password}" ]] ; do get_pass "
Enter password to unlock ${safe}: " Password to unlock ${safe}: " ; done
printf "\n\n" 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 len=50
max=100 max=100
if [[ -z "${3+x}" ]] ; then if [[ -z "${3+x}" ]] ; then read -p "
read -p "
Password length? (default: ${len}, max: ${max}) " length Password length (default: ${len}, max: ${max}): " length
else else
length="${3}" length="${3}"
fi fi
if [[ ${length} =~ ^[0-9]+$ ]] ; then if [[ ${length} =~ ^[0-9]+$ ]] ; then len=${length} ; fi
len=${length}
fi
# base64: 4 characters for every 3 bytes # 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_pass () {
# Write a password in safe. # 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 if [[ -z "${userpass+x}" ]] ; then
entry=" " entry=" "
else else
@ -124,7 +112,7 @@ write_pass () {
fi fi
get_pass " 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 safe exists, decrypt it and filter out username, or bail on error.
# If successful, append entry, or blank line. # If successful, append entry, or blank line.
@ -138,33 +126,25 @@ write_pass () {
echo "${entry}") | \ echo "${entry}") | \
(${filter} "^[[:space:]]*$|^mtime:[[:digit:]]+$";echo mtime:$(date +%s)) | \ (${filter} "^[[:space:]]*$|^mtime:[[:digit:]]+$";echo mtime:$(date +%s)) | \
encrypt ${password} ${safe}.new - || fail "Write to safe failed" encrypt ${password} ${safe}.new - || fail "Write to safe failed"
mv ${safe}.new ${safe} mv ${safe}{.new,}
} }
create_username () { new_entry () {
# Create username with password. # Prompt for new username and/or password.
if [[ -z "${2+x}" ]] ; then if [[ -z "${2+x}" ]] ; then read -r -p "
read -r -p "
Username: " username Username: " username
else else
username="${2}" username="${2}"
fi fi
if [[ -z "${3+x}" ]] ; then if [[ -z "${3+x}" ]] ; then get_pass "
read -p " Password for \"${username}\" (Enter to generate): "
Generate password? (y/n, default: y) " rand_pass userpass="${password}"
else
rand_pass=""
fi fi
if [[ "${rand_pass}" =~ ^([nN][oO]|[nN])$ ]]; then if [[ -z "${password}" ]] ; then userpass=$(gen_pass "$@")
get_pass "
Enter password for \"${username}\": " ; echo
userpass=${password}
else
userpass=$(gen_pass "$@")
if [[ -z "${4+x}" || ! "${4}" =~ ^([qQ])$ ]] ; then if [[ -z "${4+x}" || ! "${4}" =~ ^([qQ])$ ]] ; then
echo " echo "
Password: ${userpass}" Password: ${userpass}"
@ -172,42 +152,82 @@ create_username () {
fi fi
} }
print_help () {
# Print help text.
sanity_check () { echo "
# Make sure required programs are installed and are executable. pwd.sh is a shell script to manage passwords with GnuPG symmetric encryption.
if [[ -z ${gpg} && ! -x ${gpg} ]] ; then The script can be run interactively as './pwd.sh' or with the following args:
fail "GnuPG is not available"
fi * '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 password=""
read -n 1 -p "
Read, write, or delete password? (r/w/d, default: r) " action action=""
printf "\n" if [[ -n "${1+x}" ]] ; then
else
action="${1}" action="${1}"
fi fi
if [[ "${action}" =~ ^([wW])$ ]] ; then while [[ -z "${action}" ]] ;
create_username "$@" 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 write_pass
elif [[ "${action}" =~ ^([dD])$ ]] ; then elif [[ "${action}" =~ ^([dD])$ ]] ; then
if [[ -z "${2+x}" ]] ; then if [[ -z "${2+x}" ]] ; then read -p "
read -p " Username: " username
Username to delete? " username
else else
username="${2}" username="${2}"
fi fi
write_pass write_pass
else else
read_pass "$@" read_pass "$@"
fi fi
tput setaf 2 2 2 ; echo " printf "\n" ; tput setaf 2 2 2 ; echo "Done" ; tput sgr0
Done" ; tput sgr0