#!/usr/bin/env bash

single=0 # merge the certs into a single cert
force=0 # if to skip similariaty checks or not
quiet=0 # should i shut up?!?!? :<
cert='cert.pem' # where the public cert should go
key='cert.key' # where the private cert should go
domain='localhost' # the domain to copy certs from

email="freya@freyacat.org"

status=0

usage() {
	printf "usage: recert [-hsfq] [-d DOMAIN] [-c CERT] [-k KEY]\n\n"
	printf "\t-h\t\tshow the help message\n"
	printf "\t-s\t\tcombine the certs into a single cert\n"
	printf "\t-f\t\tskip cert equal checks (force)\n"
	printf "\t-q\t\tquiet output\n"
	printf "\t-d DOMAIN\tthe domain name to recert\n"
	printf "\t-c CERT\t\tthe destination path for the cert\n"
	printf "\t-k KEY\t\tthe destination path for the key (no -s)\n"
}

hash() {
	if [ -f "$1" ]; then
		sha3sum "$1" | awk '{ print $1 }';
	fi
}

letscert() {
	args=(--non-interactive --agree-tos --no-eff-email --email "$email")
	certbot delete \
		$args \
		--cert-name "$domain"
	certbot certonly \
		$args \
		--preferred-chain "ISRG Root X1" \
		--key-type rsa \
		--webroot \
		--webroot-path "/var/www/html" \
		--domains "$1"
	status=1
}

recert_log() {
	if [ $quiet = 0 ]; then
		printf "$*" 1>&2
	fi
}

chk_command() {
	if ! command -v "$1" > /dev/null; then
		>&2 echo "error: command '$1' could not be found"
		exit 1
	fi
}

while getopts ":hsfqd:c:k:" arg > /dev/null; do
	case $arg in
		h)
			usage
			exit 0
			;;
		s)
			single=1
			;;
		f)
			force=1
			;;
		q)
			quiet=1
			;;
		d)
			domain=${OPTARG}
			;;
		c)
			cert=${OPTARG}
			;;
		k)
			key=${OPTARG}
			;;
		?)
			echo "unknown option"
			exit 1
			;;
	esac
done

chk_command "getopts"
chk_command "certbot"
chk_command "openssl"

if [ ! "$cert" = "cert.pem" ] && [ "$key" = "cert.key" ]; then
	name=${cert%.*}
	key="$name.key"
fi

# Step 1: make sure letsencrypt certs exist (create if not)
lets_root="/etc/letsencrypt/live"
lets_cert="$lets_root/$domain/fullchain.pem"
lets_key="$lets_root/$domain/privkey.pem"
if [ ! -f "$lets_cert" ] && [ ! -f "$lets_key" ]; then
	letscert "$domain"
fi

# Step 2: make sure certs wont expire soon (create if will)
if openssl x509 -checkend 604800 -noout -in "$lets_cert" > /dev/null; then
	# certificate is good, only update if forced
	if [ $force = 1 ]; then
		rm "$lets_root"/*
		rmdir "$lets_root"
		recert_log "renewing... "
		letscert "$domain"
	fi
else
	recert_log "renewing... "
	letscert "$domain"
fi

# Step 3: store lets encrypt cert into tmp file
tmp=$(mktemp)
if [ $single = 1 ]; then
	{
		cat "$lets_cert";
		echo;
		cat "$lets_key";
	} >> "$tmp"
fi

# Setup 4: get hashes
current_hash=""
if [ -f "$cert" ]; then
	current_hash=$(md5sum "$lets_cert" | cut -f 1 -d " ")
else
	current_hash="FORCE"
fi

new_hash=""
if [ $single = 1 ]; then
	new_hash=$(md5sum "$tmp" | cut -f 1 -d " ")
else
	new_hash=$(md5sum "$lets_cert" | cut -f 1 -d " ")
fi

# Step 5: copy if hases out of date
if [ "$current_hash" != "$new_hash" ]; then
	recert_log "copied certs\n"
	if [ $single = 1 ]; then
		cp "$tmp" "$cert"
	else
		cp "$lets_cert" "$cert"
		cp "$lets_key" "$key"
	fi
	status=1
else
	recert_log "up to date\n"
fi

# Cleanup
rm "$tmp"

exit "$status"