#!/bin/sh
#
# Copyright (c) 2017 by Stefan Esser <se@freebsd.org>
# All rights reserved.
#
# Distributed under the BSD 2-clause Simplified License.
#

CFGFILE="/usr/local/etc/pwned-check.conf"

[ -r "$CFGFILE" ] && . $CFGFILE
: ${DBDIR:=/var/db/pwned-check}
: ${URLBASE:=https://downloads.pwnedpasswords.com/passwords}

# Helper functions
progname ()
{
    basename "$0"
}

errexit ()
{
    echo $(progname)": $@"
    exit 1
}

usage ()
{
    echo "usage: "$(progname)" [-u]"
    exit 2
}

# Fetch files with pwned password hashes
fetchpwfiles ()
{
	umask 022
	mkdir -p $DBDIR || errexit "No write permission on data directory."
	local f s_txt s_txt_7z hash
	while read f s_txt s_txt_7z hash
	do
		local f7z="$f.7z"
		echo "Checking '$DBDIR/$f' ..."
		local s_txt_is=$(stat -f %z $f 2>/dev/null)
		if [ "$s_txt_is" != "$s_txt" ]; then
			local s_txt_7z_is=$(stat -f %z $f7z 2>/dev/null)
			if [ "$s_txt_7z_is" != "$s_txt_7z" ]; then
				echo "Fetching '$DBDIR/$f7z' ..."
				fetch -S $s_txt_7z "$URLBASE/$f7z" || errexit "Could not fetch '$URLBASE/$f7z'."
			fi
			echo "Checking '$DBDIR/$f7z' ..."
			local hash_is=$(sha1 -q "$f7z")
			if [ "$hash_is" != "$hash" ]; then
				rm -f "$f7z"
				errexit "File '$f7z' fails SHA1 check: '$hash_is' should be '$hash'."
			fi
			echo "Extracting '$DBDIR/$f' ..."
			tar xOf "$f7z" | cut -d ":" -f 1 > "$f" || errexit "Decompression of file '$f7z' failed."
			local s_txt_is=$(stat -f %z "$f")
			if [ "$s_txt_is" != "$s_txt" ]; then
				rm -f "$f"
				errexit "File '$f' has size $s_txt_is after decompression, should be $s_txt."
			fi
		fi
		rm -f "$f7z"
	done <<EOF
pwned-passwords-ordered-2.0.txt 20567110522 9647404191 87437926c6293d034a259a2b86a2d077e7fd5a63
EOF
	echo "All data files have been successfully downloaded and extracted."
	# delete old data files (their content is included in the new datafiles)
	while read f
	do
	      rm -f $f $f.7z
	done <<EOF
pwned-passwords-1.0.txt
pwned-passwords-update-1.txt
pwned-passwords-update-2.txt
EOF
}

# Password lookup
exitcode=0

lookup ()
{
    local hash=$(echo "$1" | tr 'a-z' 'A-Z')
    if [ "$USEFILES" = yes ]; then
	look "$hash" pwned-passwords*.txt > /dev/null
    else
	expected=${hash#?????}
	prefix=${hash%$expected}
	fetch -q -o - https://api.pwnedpasswords.com/range/$prefix 2>/dev/null | grep -i "^$expected:" >/dev/null
    fi
}

checkpw ()
{
    local pwd="$1"
    local hash=$(echo -n "$pwd" | sha1)
    if lookup "$hash"; then
	echo "$pwd"
	exitcode=1
    elif expr "$pwd" : '[A-Fa-f0-9]\{40\}$' > /dev/null; then
	if lookup "$pwd"; then
	    echo "$pwd"
	    exitcode=1
	fi
    fi
}

# Main program
export LC_COLLATE=C
if cd "$DBDIR" && ls pwned-passwords*.txt; then
	USEFILES=yes
fi >/dev/null 2>&1

if [ "$#" -gt 0 ]; then
    if [ "$1" = "-u" ]; then
	fetchpwfiles
	exit 0
    else	
	echo "usage: "$(progname)" [-u]"
	exit 2
    fi
fi

while read pwd
do
    checkpw "$pwd"
done

exit $exitcode
