CAPTAIN'S PHLOG: 2020.01.10
GOPHER://TILDECOW.COM
_________________________________________________________________
# Commenting your code for fun & profit...
[UPDATE 1/14/20] THIS is quite good:
gopher://josuah.net/0/ascii/obfuscation.txt
Looking back over half a century of personal experience, I feel
it's probably time to utter these words: KIDS THESE DAYS (don't
properly comment their code). Really it has nothing to do with
kids or the present day. I can still remember Mr. Jennings in
my 11th grade BASIC programming class harping on the importance
of comments until my ears bled. I didn't do it then. I didn't
do it for most of my life. I've just started doing it this year.
Following these pearls of wisdom is a random bash script I
coppied from GitHub and REMOVED FROM ITS CONTEXT. Don't read
it. For anyone but the more advanced shell scriptor, figuring
out what is does line-by-line is a real investment in time! The
script isn't important (sorry "drduh"). The illustration is.
"But Tim", I hear you wondering, "exactly why DID you mend
your ways?".
When I was young, my code was disposable. Even the pieces I
wrote as part of my short lived 'day job' as a programmer were
written, deployed, and promptly abandoed if they worked more than
half the time. (Granted this was BASIC on an AM Jacquard J-100
mini-computer and stored on a 20Mb Pertec that took two adults
to lift safely, so no big loss there) This neatly expanded on my
habbits from Mr. Jennings class. The assignment was handed in,
no need to care anymore.
There are three reasons I've become a staunch advocate of inline
comments.
One: UNLIMITED ACCESS TO OTHERS' EXAMPLE CODE. Thanks to easy
access to gopher and the *cough* web, I can look at, build
upon (rip off), and test terrabytes of code that others have
developed. If I need an easily adaptable example, there it
is. But thanks to coders finding no time to add section by
section comments most of it is worthless to anyone not simply
copy/pasting a theoretically 'working' script.
Two: I'M CODING TO IMPROVE MY ART. I'm still an '80s programmer.
I code for fun. I would starve if I had to make money at this
shit. I really like it when I can pick up a piece of code, read
it, and GET it with one or perhaps two read-throughs. My code
is ART to me. Not High Art. It's not elegant or clever. It's
recreation. Programs lacking sufficient commenting deprive me
of simple pleasure. They're WORK.
Three: I'M GETTING OLDER (Or I'm just a fart in a whirlwind).
When I look back at my own uncodumented code - even a few months
after I write it - I am left scratching my head. Elaborating on a
script that I completely grokked less than a year ago becomes an
exercise in mystery. Commenting keeps my forgetfulness in check.
Even if I were a good writer and persuasive, I couldn't convince
you to start showering your code in concise comments. Hell,
you already know it's a good idea really. Some day, years from
now perhaps, you'll realize I was correct but by that point I'll
be the glimmer in your grandson's eye and definately NOT coming
back as a programmer. Peace.
# # THE EXAMPLE YOU NEEDN'T READ FOLLOWS... #
#!/usr/bin/env bash #
https://github.com/drduh/pwd.sh
set -o errtrace set -o nounset set -o pipefail
#set -x # uncomment to debug
umask 077
now=$(date +%s) copy="$(command -v xclip || command
-v pbcopy)" gpg="$(command -v gpg || command -v gpg2)"
backuptar="${PWDSH_BACKUP:=pwd.$(hostname).$(date +%F).tar}"
safeix="${PWDSH_INDEX:=pwd.index}" safedir="${PWDSH_SAFE:=safe}"
timeout=9
fail () {
# Print an error message and exit.
tput setaf 1 1 1 ; printf "\nError: ${1}\n" ; tput sgr0 exit 1
}
get_pass () {
# Prompt for a password.
password="" prompt="${1}"
while IFS= read -p "${prompt}" -r -s -n 1 char ; do
if [[ ${char} == $'\0' ]] ; then
break
elif [[ ${char} == $'\177' ]] ; then
if [[ -z "${password}" ]] ; then
prompt=""
else
prompt=$'\b \b' password="${password%?}"
fi
else
prompt="*" password+="${char}"
fi
done
}
decrypt () {
# Decrypt with GPG.
printf '%s\n' "${1}" | ${gpg} --armor --batch --no-symkey-cache
\
--decrypt --passphrase-fd 0 "${2}" 2>/dev/null
}
encrypt () {
# Encrypt with GPG.
${gpg} --armor --batch \
--symmetric --yes --passphrase-fd 3 --no-symkey-cache \
--output "${2}" "${3}" 3< <(printf '%s\n' "${1}") 2>/dev/null
}
read_pass () {
# Read a password from safe.
if [[ ! -s ${safeix} ]] ; then fail "${safeix} not found" ; fi
username="" while [[ -z "${username}" ]] ; do
if [[ -z "${2+x}" ]] ; then read -r -p "
Username: " username
else username="${2}" ; fi
done
while [[ -z "${password}" ]] ; do get_pass " Password to unlock
${safeix}: " ; done printf "\n"
spath=$(decrypt ${password} ${safeix} | \
grep -F "${username}" | tail -n1 | cut -d : -f2) || \
fail "Failed to decrypt ${safeix}"
clip <(decrypt ${password} ${spath}) || \
fail "Failed to decrypt ${spath}"
}
gen_pass () {
# Generate a password using GPG.
len=20 max=80
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
# base64: 4 characters for every 3 bytes ${gpg} --armor
--gen-random 0 "$((${max} * 3/4))" | cut -c -"${len}"
}
write_pass () {
# Write a password and update index file.
while [[ -z "${password}" ]] ; do get_pass " Password to unlock
${safeix}: " ; done printf "\n"
fpath=$(tr -dc "[:lower:]" < /dev/urandom | fold -w8 | head -n1)
spath=${safedir}/${fpath} printf '%s\n' "${userpass}" | \
encrypt "${password}" ${spath} - || \
fail "Failed to put ${spath}"
( if [[ -f "${safeix}" ]] ; then
decrypt "${password}" ${safeix} || return ; fi
printf "${username}@${now}:${spath}\n") | \ encrypt
"${password}" ${safeix}.${now} - || \
fail "Failed to put ${safeix}.${now}"
mv ${safeix}{.${now},}
}
list_entry () {
# Decrypt the index to list entries.
if [[ ! -s ${safeix} ]] ; then fail "${safeix} not found" ; fi
while [[ -z "${password}" ]] ; do get_pass " Password to unlock
${safeix}: " ; done printf "\n\n"
decrypt ${password} ${safeix} || fail "Decryption failed"
}
backup () {
# Archive encrypted index and safe directory.
if [[ -f ${safeix} && -d ${safedir} ]] ; then \
tar cfv ${backuptar} ${safeix} ${safedir}
else fail "Nothing to archive" ; fi printf "\nArchived
${backuptar}\n" ; \
}
clip () {
# Use clipboard and clear after timeout.
${copy} < ${1}
printf "\n" shift while [ $timeout -gt 0 ] ; do
printf "\r\033[KPassword on clipboard! Clearing in %.d"
$((timeout--)) sleep 1
done
printf "" | ${copy}
}
new_entry () {
# Prompt for new username and/or password.
username="" while [[ -z "${username}" ]] ; do
if [[ -z "${2+x}" ]] ; then read -r -p "
Username: " username
else username="${2}" ; fi
done
if [[ -z "${3+x}" ]] ; then get_pass " Password for
\"${username}\" (Enter to generate): "
userpass="${password}"
fi
printf "\n" if [[ -z "${password}" ]] ; then userpass=$(gen_pass
"$@") ; fi
}
print_help () {
# Print help text.
printf """ pwd.sh is a Bash shell script to manage passwords
with GnuPG symmetric encryption. pwd.sh can be used
interactively or by passing one of the following options:
* 'w' to write a password * 'r' to read a password * 'l'
to list passwords * 'b' to create an archive for backup
Example usage:
* Generate a 30 character password for 'userName':
./pwd.sh w userName 30
* Copy the password for 'userName' to clipboard:
./pwd.sh r userName
* List stored passwords and copy a previous version:
./pwd.sh l ./pwd.sh r userName@1574723625
* Create an archive for backup:
./pwd.sh b
* Restore an archive from backup:
tar xvf pwd*tar"""
}
if [[ -z ${gpg} && ! -x ${gpg} ]] ; then fail "GnuPG is not
available" ; fi
if [[ ! -d ${safedir} ]] ; then mkdir -p ${safedir} ; fi
chmod -R 0600 ${safeix} 2>/dev/null chmod -R 0700 ${safedir}
2>/dev/null
password="" action="" if [[ -n "${1+x}" ]] ; then action="${1}"
; fi
while [[ -z "${action}" ]] ; do
read -n 1 -p " Read or Write (or Help for more options):
" action printf "\n"
done
if [[ "${action}" =~ ^([hH])$ ]] ; then
print_help
elif [[ "${action}" =~ ^([bB])$ ]] ; then
backup
elif [[ "${action}" =~ ^([lL])$ ]] ; then
list_entry
elif [[ "${action}" =~ ^([wW])$ ]] ; then
new_entry "$@" write_pass
else read_pass "$@" ; fi
chmod -R 0400 ${safeix} ${safedir} 2>/dev/null
tput setaf 2 2 2 ; printf "\nDone\n" ; tput sgr0