#!/bin/sh /etc/rc.common

USE_PROCD=1
run_dir=/var/run/acme
export CHALLENGE_DIR=$run_dir/challenge
export CERT_DIR=/etc/ssl/acme
NFT_HANDLE=
HOOK=/usr/lib/acme/hook
LOG_TAG=acme

# shellcheck source=net/acme/files/functions.sh
. "$IPKG_INSTROOT/usr/lib/acme/functions.sh"

cleanup() {
	log debug "cleaning up"
	if [ -e $run_dir/lock ]; then
		rm $run_dir/lock
	fi
	if [ "$NFT_HANDLE" ]; then
		# $NFT_HANDLE contains the string 'handle XX' so pass it unquoted to nft
		nft delete rule inet fw4 input $NFT_HANDLE
	fi
}

load_options() {
	section=$1

	# compatibility for old option name
	config_get_bool staging "$section" use_staging
	if [ -z "$staging" ]; then
		config_get_bool staging "$section" staging 0
	fi
	export staging
	config_get calias "$section" calias
	export calias
	config_get dalias "$section" dalias
	export dalias
	config_get domains "$section" domains
	export domains
	export main_domain
	main_domain="$(first_arg $domains)"
	config_get keylength "$section" keylength
	if [ "$keylength" ]; then
		log warn "Option \"keylength\" is deprecated, please use key_type (e.g., ec256, rsa2048) instead."
		case $keylength in
		ec-*) key_type=${keylength/-/} ;;
		*) key_type=rsa$keylength ;;
		esac
	else
		config_get key_type "$section" key_type ec256
	fi
	export key_type
	config_get dns "$section" dns
	export dns
	config_get acme_server "$section" acme_server
	export acme_server
	config_get days "$section" days
	export days
	config_get standalone "$section" standalone
	[ -n "$standalone" ] && log warn "Option \"standalone\" is deprecated."
	config_get dns_wait "$section" dns_wait
	export dns_wait
	config_get webroot "$section" webroot
	if [ "$webroot" ]; then
		log warn "Option \"webroot\" is deprecated, please remove it and change your web server's config so it serves ACME challenge requests from $CHALLENGE_DIR."
		CHALLENGE_DIR=$webroot
	fi

	config_get validation_method "$section" validation_method
	# if validation_method isn't set then guess it
	if [ -z "$validation_method" ]; then
		if [ -n "$dns" ]; then
			validation_method="dns"
		elif [ "$standalone" = 1 ]; then
			validation_method="standalone"
		else
			validation_method="webroot"
		fi
		log warn "Please set \"option validation_method $validation_method\"."
	fi
	export validation_method
}

first_arg() {
	echo "$1"
}

get_cert() {
	section=$1

	config_get_bool enabled "$section" enabled 1
	[ "$enabled" = 1 ] || return

	load_options "$section"
	if [ "$validation_method" = "webroot" ]; then
		mkdir -p "$CHALLENGE_DIR"
	fi

	if [ "$validation_method" = "standalone" ] && [ -z "$NFT_HANDLE" ]; then
		if ! NFT_HANDLE=$(nft -a -e insert rule inet fw4 input tcp dport 80 counter accept comment ACME | grep -o 'handle [0-9]\+'); then
			return 1
		fi
		log debug "added nft rule: $NFT_HANDLE"
	fi

	load_credentials() {
		eval export "$1"
	}
	config_list_foreach "$section" credentials load_credentials

	"$HOOK" get
}

load_globals() {
	section=$1

	config_get account_email "$section" account_email
	if [ -z "$account_email" ]; then
		log err "account_email option is required"
		exit 1
	fi
	export account_email

	config_get state_dir "$section" state_dir
	if [ "$state_dir" ]; then
		log warn "Option \"state_dir\" is deprecated, please remove it. Certificates now exist in $CERT_DIR."
		mkdir -p "$state_dir"
	else
		state_dir=/etc/acme
	fi
	export state_dir

	config_get debug "$section" debug 0
	export debug

	# only look for the first acme section
	return 1
}

start_service() {
	mkdir -p $run_dir
	exec 200>$run_dir/lock
	if ! flock -n 200; then
		log err "Another ACME instance is already running."
		exit 1
	fi

	trap cleanup EXIT

	config_load acme
	config_foreach load_globals acme

	config_foreach get_cert cert
}

service_triggers() {
	procd_add_config_trigger config.change acme \
		/etc/init.d/acme start
}
