#!/usr/bin/env bash
# gencommit -- Wikipedia style committed identity generator
#   (see http://en.wikipedia.org/wiki/Wikipedia:CID for explanation)
#
# - The hash function is SHA-1 (hashfunc="sha1").
#
# - The date format is "%Y-%m-%d".
#
# - The commitment secret is generated by hashing:
#
#     secret = hashfunc ( domain + " " + date + " " + passphrase )
#
# - The commitment itself is generated by hashing the secret, once.
#
#     public = hashfunc ( secret )
#
#     commitment = public + " " + domain + " " + date + " " + hashfunc

. lib.bash || exit

fmtseed() { printf '%s %s %s' "$@"; }
unfmtdate() { date -d "$1" +'%s'; }
fmtdate() { date -d "$1" +'%Y-%m-%d'; }
fmthashfunc() { printf '%s' "$1" | tr 'A-Z' 'a-z' | tr -d -c 'a-z0-9'; }

colwidth=11

readc() { read -p "$(printf '%*s ' $colwidth "$1")" -r "${@:2}"; }
echoc() { printf "%*s %s\n" $colwidth "$1" "${*:2}"; }

reads() { readc "$1" -e -i "${!2}" "$2"; }
readp() {
	if [[ "$DISPLAY" ]]; then
		printf '%*s (starting pinentry)' $colwidth "$1"
		local r=$(askpin \
				-p "$1" -t "${0##*/}" -W "$WINDOWID" \
				-d "Generating a commitment for '$domain' at $date.")
		declare -g "$2=$r"
		printf '\n'
	else
		readc "$1" -s "$2"
		printf '...\n'
	fi
}

fhash_openssl() { openssl "$1" -r | awk '{print $1}'; }
fhmac_openssl() { openssl "$1" -r -hmac "$2" | awk '{print $1}'; }

fhash=([sha1]=fhash_openssl [sha256]=fhash_openssl)
fhmac=([sha1]=fhmac_openssl [sha256]=fhmac_openssl)

hash() { "${fhash[hash]}" "$hash" "$@"; }
hmac() { "${fhmac[hmac]}" "$hmac" "$@"; }

domain=$1
date=$2
hash=$3
hash=$(fmthashfunc "${hash:-sha1}")

if [[ ! "${fhash[hash]}" ]]; then
	die "unsupported hash '$hash'"
fi

if [[ "$domain" ]]; then
	echoc "domain:" "$domain"
else
	reads "domain?" domain
fi

if ! [[ "$domain" ]]; then
	die "domain is empty"
fi

if [[ "$date" ]]; then
	date=$(fmtdate "$date")
	echoc "date:" "$date"
else
	reads "date?" date
	date=$(fmtdate "${date:-today}")
fi

if ! [[ "$date" ]]; then
	die "invalid date '$date'"
fi

if (( $(unfmtdate "$date") < $(unfmtdate "2013-11-15") )); then
	unset hmac
else
	hmac=sha1
fi

readp "passphrase?" passphrase

if ! [[ "$passphrase" ]]; then
	die "passphrase is empty"
fi

# generate the site secret that might be revealed to admins

if [[ "$hmac" ]]; then
	secret=$(fmtseed "$domain" "$date" | hmac "$passphrase")
else
	secret=$(fmtseed "$domain" "$date" "$passphrase" | hash)
fi

# hash the secret to generate the public value

public=$(printf '%s' "$secret" | hash)

# print out

echoc "hash input:" "$(fmtseed "$domain" "$date" "...")"

echoc "hash algo:" "$hash, ${hmac:-none}"

echoc "secret:" "$(printf '\e[31m%s\e[m' "$secret")"

echoc "commitment:" "$(printf '\e[32m%s\e[m' "$public") $domain $date $hash"
