1
0
mirror of https://github.com/octoleo/Purse.git synced 2024-12-29 12:32:39 +00:00
Purse/pwd.sh

215 lines
4.0 KiB
Bash
Raw Normal View History

2015-07-03 18:59:27 +00:00
#!/usr/bin/env bash
2015-07-02 02:03:55 +00:00
#
2015-10-31 04:08:51 +00:00
# Script for managing passwords in a GunPG symmetrically encrypted file.
2015-07-02 02:03:55 +00:00
set -o errtrace
2015-07-02 02:03:55 +00:00
set -o nounset
set -o pipefail
2015-07-02 02:03:55 +00:00
2015-10-31 04:08:51 +00:00
filter="$(command -v grep) --invert-match --regexp"
gpg="$(command -v gpg || command -v gpg2)"
safe="${PWDSH_SAFE:=pwd.sh.safe}"
2015-07-02 02:03:55 +00:00
fail () {
# Print an error message and exit.
2015-07-02 02:03:55 +00:00
tput setaf 1 ; echo "Error: ${1}" ; tput sgr0
exit 1
}
2015-07-02 02:03:55 +00:00
get_pass () {
# Prompt for a password.
2015-07-02 02:03:55 +00:00
2015-07-03 13:07:54 +00:00
password=''
prompt="${1}"
while IFS= read -p "${prompt}" -r -s -n 1 char ; do
2015-07-03 13:07:54 +00:00
if [[ ${char} == $'\0' ]] ; then
break
2015-07-03 17:05:06 +00:00
elif [[ ${char} == $'\177' ]] ; then
if [[ -z "${password}" ]] ; then
prompt=""
2015-07-03 13:07:54 +00:00
else
prompt=$'\b \b'
password="${password%?}"
2015-07-02 02:03:55 +00:00
fi
2015-07-03 13:07:54 +00:00
else
2015-07-03 17:05:06 +00:00
prompt="*"
password+="${char}"
2015-07-03 13:07:54 +00:00
fi
2015-07-02 02:03:55 +00:00
done
2015-10-31 04:08:51 +00:00
if [[ -z "${password}" ]] ; then
fail "No password provided"
fi
2015-07-02 02:03:55 +00:00
}
decrypt () {
# Decrypt with a password.
2015-07-02 02:03:55 +00:00
echo "${1}" | ${gpg} \
2015-07-02 02:03:55 +00:00
--decrypt --armor --batch \
--passphrase-fd 0 "${2}" 2>/dev/null
2015-07-02 02:03:55 +00:00
}
encrypt () {
# Encrypt with a password.
2015-07-02 02:03:55 +00:00
${gpg} \
--symmetric --armor --batch --yes \
--passphrase-fd 3 \
--output "${2}" "${3}" 3< <(echo "${1}")
2015-07-02 02:03:55 +00:00
}
read_pass () {
# Read a password from safe.
2015-07-02 02:03:55 +00:00
2015-08-07 18:11:11 +00:00
if [[ ! -s ${safe} ]] ; then
fail "No passwords found"
fi
if [[ -z "${2+x}" ]] ; then
read -p "
Username to read? (default: all) " username
else
2015-08-07 18:11:11 +00:00
username="${2}"
fi
2015-10-31 04:08:51 +00:00
if [[ -z "${username}" || "${username}" == "all" ]] ; then
2015-07-03 04:16:37 +00:00
username=""
fi
2015-08-07 18:11:11 +00:00
get_pass "
2015-07-03 21:03:26 +00:00
Enter password to unlock ${safe}: "
2015-08-07 18:11:11 +00:00
printf "\n\n"
decrypt ${password} ${safe} | grep " ${username}" || fail "Decryption failed"
2015-07-02 02:03:55 +00:00
}
gen_pass () {
# Generate a password.
2015-07-02 02:03:55 +00:00
2015-07-03 21:03:26 +00:00
len=50
2015-07-03 15:49:38 +00:00
max=100
if [[ -z "${3+x}" ]] ; then
read -p "
2015-07-03 21:03:26 +00:00
Password length? (default: ${len}, max: ${max}) " length
else
length="${3}"
fi
2015-07-02 02:31:38 +00:00
if [[ ${length} =~ ^[0-9]+$ ]] ; then
len=${length}
2015-07-02 02:03:55 +00:00
fi
2015-07-03 04:29:12 +00:00
# base64: 4 characters for every 3 bytes
2015-10-31 04:08:51 +00:00
${gpg} --gen-random --armor 0 "$((${max} * 3/4))" | cut -c -${len}
2015-08-07 18:24:08 +00:00
}
2015-07-02 02:31:38 +00:00
write_pass () {
# Write a password in safe.
2015-07-02 02:03:55 +00:00
# If no password provided, clear the entry by writing an empty line.
2015-10-31 04:08:51 +00:00
if [[ -z "${userpass+x}" ]] ; then
entry=" "
else
2015-10-31 04:08:51 +00:00
entry="${userpass} ${username}"
2015-07-02 02:31:38 +00:00
fi
2015-07-03 21:03:26 +00:00
get_pass "
Enter password to unlock ${safe}: " ; echo
# If safe exists, decrypt it and filter out username, or bail on error.
2015-10-31 04:08:51 +00:00
# If successful, append entry, or blank line.
# Filter out any blank lines.
# Finally, encrypt it all to a new safe file, or fail.
# If successful, update to new safe file.
2015-10-31 04:08:51 +00:00
( if [[ -f "${safe}" ]] ; then
decrypt ${password} ${safe} | \
2015-10-31 04:08:51 +00:00
${filter} " ${username}$" || return
fi ; \
2015-10-31 04:08:51 +00:00
echo "${entry}") | \
${filter} "^[[:space:]]*$" | \
encrypt ${password} ${safe}.new - || fail "Write to safe failed"
mv ${safe}.new ${safe}
2015-07-02 02:03:55 +00:00
}
create_username () {
2015-10-31 04:08:51 +00:00
# Create username with password.
2015-07-02 02:03:55 +00:00
if [[ -z "${2+x}" ]] ; then
read -p "
2015-07-03 21:03:26 +00:00
Username: " username
else
username="${2}"
fi
if [[ -z "${3+x}" ]] ; then
read -p "
2015-07-03 21:03:26 +00:00
Generate password? (y/n, default: y) " rand_pass
else
rand_pass=""
fi
2015-07-03 21:03:26 +00:00
if [[ "${rand_pass}" =~ ^([nN][oO]|[nN])$ ]]; then
2015-07-03 21:03:26 +00:00
get_pass "
Enter password for \"${username}\": " ; echo
2015-08-07 18:24:08 +00:00
userpass=${password}
2015-07-02 02:03:55 +00:00
else
userpass=$(gen_pass "$@")
if [[ -z "${4+x}" || ! "${4}" =~ ^([qQ])$ ]] ; then
echo "
2015-07-03 21:03:26 +00:00
Password: ${userpass}"
fi
2015-07-02 02:03:55 +00:00
fi
}
sanity_check () {
2015-10-31 04:08:51 +00:00
# Make sure required programs are installed and are executable.
2015-07-02 02:03:55 +00:00
if [[ -z ${gpg} && ! -x ${gpg} ]] ; then
fail "GnuPG is not available"
2015-07-02 02:03:55 +00:00
fi
}
sanity_check
2015-07-02 02:03:55 +00:00
if [[ -z "${1+x}" ]] ; then
read -n 1 -p "
Read, write, or delete password? (r/w/d, default: r) " action
printf "\n"
2015-07-27 11:58:43 +00:00
else
action="${1}"
2015-07-27 11:58:43 +00:00
fi
if [[ "${action}" =~ ^([wW])$ ]] ; then
create_username "$@"
write_pass
elif [[ "${action}" =~ ^([dD])$ ]] ; then
if [[ -z "${2+x}" ]] ; then
read -p "
Username to delete? " username
else
username="${2}"
fi
write_pass
else
read_pass "$@"
fi
2015-07-02 02:03:55 +00:00
2015-07-03 21:03:26 +00:00
tput setaf 2 ; echo "
Done" ; tput sgr0