Skip to content

Instantly share code, notes, and snippets.

@tomcz
Last active January 5, 2025 00:46
Command line random password generator
#!/usr/bin/env bash
set -eo pipefail
# Ref: https://theworld.com/~reinhold/diceware.html
# Ref: https://www.eff.org/deeplinks/2016/07/new-wordlists-random-passphrases
if [[ ! -x "$(command -v curl)" ]]; then
echo "Please install curl"
exit 1
fi
if [[ ! -x "$(command -v shuf)" ]]; then
echo "Please install coreutils"
exit 1
fi
if [[ ! -x "$(command -v gum)" ]]; then
echo "Please install https://github.com/charmbracelet/gum"
exit 1
fi
opt_five='five dice, long wordlist'
url_five='https://www.eff.org/files/2016/07/18/eff_large_wordlist.txt'
dst_five='eff_large_wordlist.txt'
opt_four_short='four dice, short wordlist'
url_four_short='https://www.eff.org/files/2016/09/08/eff_short_wordlist_1.txt'
dst_four_short='eff_short_wordlist_1.txt'
opt_four_long='four dice, long wordlist'
url_four_long='https://www.eff.org/files/2016/09/08/eff_short_wordlist_2_0.txt'
dst_four_long='eff_short_wordlist_2_0.txt'
echo 'Which wordlist to use?'
WORDLIST=$(gum choose "$opt_five" "$opt_four_short" "$opt_four_long")
echo ">> $WORDLIST"
echo 'How many words to pick?'
COUNT=$(gum input --value='4')
echo ">> $COUNT"
echo 'Which word separator to use?'
SEPARATOR=$(gum choose 'dash' 'space' 'underscore')
echo ">> $SEPARATOR"
CACHE_DIR="${HOME}/.diceware"
if [[ ! -d "$CACHE_DIR" ]]; then
mkdir "$CACHE_DIR"
fi
word_src="$url_five"
word_file="${dst_five}"
if [[ "$WORDLIST" == "$opt_four_short" ]]; then
word_src="$url_four_short"
word_file="$dst_four_short"
fi
if [[ "$WORDLIST" == "$opt_four_long" ]]; then
word_src="$url_four_long"
word_file="$dst_four_long"
fi
word_file="${CACHE_DIR}/${word_file}"
if [[ ! -f "$word_file" ]]; then
curl -sSf "$word_src" -o "$word_file"
fi
dice='4'
if [[ "$WORDLIST" == "$opt_five" ]]; then
dice='5'
fi
separator=' '
if [[ "$SEPARATOR" == "dash" ]]; then
separator='-'
elif [[ "$SEPARATOR" == "underscore" ]]; then
separator='_'
fi
phrase=''
for i in $(seq "$COUNT"); do
group=''
for j in $(seq "$dice"); do
roll=$(shuf -i 1-6 -n 1 --random-source=/dev/random)
if [[ -z "$group" ]]; then
group="$roll"
else
group="${group}${roll}"
fi
done
word=$(grep "$group" "$word_file" | awk '{print $2}')
if [[ -z "$phrase" ]]; then
phrase="$word"
else
phrase="${phrase}${separator}${word}"
fi
done
gum style \
--border double --align center \
--margin '1 2' --padding '2 4' \
"$phrase"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment