#!/bin/bash
set -eu
### --help Info: настройка конфигов nginx
### --help Usage:
### --help Example:
. /opt/fox_utils/crab_sys.sh
declare ARG_CERTBOT_RENEW
sys::arg_parse "$@"

declare DOMAIN=
declare ORG_DOMAIN=
declare ACCOUNT_FQDN=
declare NGINX_SCHEME=
declare NGINX_USE_CERTBOT=
declare ADMIN_EMAIL=
declare EVA_PY_VERSION
declare CA_BUNDLE
declare ID_LIKE
declare PY_PACKAGES

declare NGINX_ENABLED EXTERNAL_PORT_HTTPS DISABLE_HTTPS_REDIRECT EVA_DEPLOY_TYPE
declare EVA_HTTP_PORT EVA_HTTPS_PORT BASE_HREF
source /opt/CONFIG

# NGINX_ACCOUNT_SCHEME='port'
if [[ ! ${EVA_PY_VERSION:-} ]]; then
	EVA_PY_VERSION="$(\
		python3 -c \
		'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')"
fi

. /etc/os-release
# 1)
# ID_LIKE=debian # Ubuntu, Astra
# ID_LIKE="rhel centos fedora" # RedOS
# 2)
# https://go.dev/src/crypto/x509/root_linux.go
# 	"/etc/ssl/certs/ca-certificates.crt",                // Debian/Ubuntu/Gentoo etc.
# 	"/etc/pki/tls/certs/ca-bundle.crt",                  // Fedora/RHEL 6
# 	"/etc/ssl/ca-bundle.pem",                            // OpenSUSE
# 	"/etc/pki/tls/cacert.pem",                           // OpenELEC
# 	"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
# 	"/etc/ssl/cert.pem",                                 // Alpine Linux
if [[ ${ID_LIKE:-debian} =~ debian ]]; then
	CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt"
	PY_PACKAGES="dist-packages"
elif [[ ${ID_LIKE:-debian} =~ rhel ]]; then
	CA_BUNDLE="/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem"
	PY_PACKAGES="site-packages"
fi

prepare(){
	# rm -f /etc/nginx/sites-enabled/default
	if [ ! -f /mnt/tmp/etc/nginx/dh4096.pem ]; then
		mkdir -p /mnt/tmp/etc/nginx/
		openssl dhparam -dsaparam -out /mnt/tmp/etc/nginx/dh4096.pem 4096
	fi
	return 0
}


build_selfsigned_if_not_exists(){
	if [ -f "/etc/nginx/ssl/${DOMAIN}.crt" ]; then
		# Это может быть клиентский сертификат, не имеем права его трогать
		return 0
	fi

	(
		cd /etc/nginx/ssl/
		echo "Не найден сертификат для домена ${DOMAIN}. Генерируем самоподписной"
		/opt/bin/self-signed-cert-ctl "$DOMAIN"
	)

	rm -f /etc/nginx/conf.d/${DOMAIN}.conf
	return 0
}

check_selfsigned_rootcert(){
	local ln_ca ln_pem
	if [ ! -f "/etc/nginx/ssl/rootCA.pem" ]; then
		echo "Самоподписной сертификат не использовался"
		return 0
	fi
	# Проверяем, что root сертификат прописан в файлы
	grep -F -x -f \
		"/etc/nginx/ssl/rootCA.pem" \
		"$CA_BUNDLE" >/tmp/_nginx_configure.crt.$$
	ln_ca="$(cat /tmp/_nginx_configure.crt.$$ | grep -v '^---' | sort | uniq | wc -l || true )"
	rm -f "/tmp/_nginx_configure.crt.$$"
	ln_pem="$(cat /etc/nginx/ssl/rootCA.pem | grep -v '^---' | sort | uniq | wc -l )"
	if [ "$ln_ca" != "$ln_pem" ]; then
		echo "Прописываем самоподписной сертификат"
		cat "/etc/nginx/ssl/rootCA.pem" \
			>> "$CA_BUNDLE"
		cat "/etc/nginx/ssl/rootCA.pem" \
			>> "/usr/local/lib/python$EVA_PY_VERSION/$PY_PACKAGES/certifi/cacert.pem"
	fi
	return 0
}

check_corp_rootcert(){
	local ln_ca ln_pem
	if [ ! -f "/etc/nginx/ssl/corp_rootCA.pem" ]; then
		echo "Корпоративный корневой сертификат не указан."
		echo "Если он необходим, сохраните его в /etc/nginx/ssl/corp_rootCA.pem"
		return 0
	fi
	sed -i 's/\r$//' /etc/nginx/ssl/corp_rootCA.pem
	# Simple Validate
	grep -Fxqe '-----BEGIN CERTIFICATE-----' /etc/nginx/ssl/corp_rootCA.pem
	grep -F -x -f \
		"/etc/nginx/ssl/corp_rootCA.pem" \
		"$CA_BUNDLE" >/tmp/_nginx_configure.crt.$$
	ln_ca="$(cat /tmp/_nginx_configure.crt.$$ | grep -v '^---' | sort | uniq | wc -l || true )"
	rm -f "/tmp/_nginx_configure.crt.$$"
	ln_pem="$(cat /etc/nginx/ssl/corp_rootCA.pem | grep -v '^---' | sort | uniq | wc -l )"
	if [ "$ln_ca" != "$ln_pem" ]; then
		echo "Прописываем корпоративный корневой сертификат в систему"
		cat "/etc/nginx/ssl/corp_rootCA.pem" \
			>> "$CA_BUNDLE"
		cat "/etc/nginx/ssl/corp_rootCA.pem" \
			>> "/usr/local/lib/python$EVA_PY_VERSION/$PY_PACKAGES/certifi/cacert.pem"
	fi
	return 0
}

localhost_domain(){
	if [[ ${EVA_DEPLOY_TYPE:-} = k8s || $(id -u) != 0 ]]; then
		echo "Skip patch /etc/hosts EVA_DEPLOY_TYPE=${EVA_DEPLOY_TYPE:-}, uid=$(id -u)"
		return 0
	fi

	echo "Прописываем 127.0.0.1 $DOMAIN в /etc/hosts"
	if ! grep -q "127.0.0.1 $DOMAIN" /etc/hosts; then
		echo "127.0.0.1 $DOMAIN" >> /etc/hosts || true
		# Для read-only docker-контейнеров должен использоваться параметр -h
	fi
	return 0
}


configure_base_href() {
	# Возможность работы под префиксом.
	local base_href='' base_href_redirect=''
	if [[ ${BASE_HREF:-} ]]; then
		base_href="$BASE_HREF"
		# Приведём к виду /prefix
		base_href="${base_href%/}"
		base_href="${base_href#/}"
		base_href="/$base_href"
		base_href_redirect="location / { rewrite ^ https://\$host"
		base_href_redirect+="${EXTERNAL_PORT_HTTPS:+:$EXTERNAL_PORT_HTTPS}"
		base_href_redirect+="$base_href\$request_uri redirect; }"
	fi
	sed -i "s~@@@base_href%%%~$base_href~g" \
		/mnt/tmp/etc/nginx/conf.d/eva-app.conf
	sed -i -Ee "s~@@@base_href_redirect%%%~$base_href_redirect~" \
		/mnt/tmp/etc/nginx/conf.d/eva-app.conf
	# !!! do not touch read-only files, patch by backend endpoint on-fly
	# sed -i -Ee "/<base href=/ s~href=\"[^\"]*\"~href=\"${base_href}/\"~" \
	# 	/opt/eva-app/dist/cmf-angular/index.html || true
	/opt/fox_utils/crab_conf set BASE_HREF "$base_href" /opt/eva-app/custom/config.py
	return 0
}


configure_listen_ports() {
	# Возможность переопределить порты
	sed -i "s/@@@eva_http_port%%%/${EVA_HTTP_PORT:-1080}/g" /mnt/tmp/etc/nginx/conf.d/eva-app.conf
	sed -i "s/@@@eva_https_port%%%/${EVA_HTTPS_PORT:-1443}/g" /mnt/tmp/etc/nginx/conf.d/eva-app.conf
	# Dont listen private port in non-root mode
	if [[ $(id -u) = 0 ]]; then
		sed -i "s/@@@listen_http_private%%%/listen 80;/g" /mnt/tmp/etc/nginx/conf.d/eva-app.conf
		sed -i "s/@@@listen_https_private%%%/listen 443 ssl;/g" /mnt/tmp/etc/nginx/conf.d/eva-app.conf
	else
		sed -i "s/@@@listen_http_private%%%//g" /mnt/tmp/etc/nginx/conf.d/eva-app.conf
		sed -i "s/@@@listen_https_private%%%//g" /mnt/tmp/etc/nginx/conf.d/eva-app.conf
	fi
	return 0
}


configure_https_redirect() {
	if [[ ${DISABLE_HTTPS_REDIRECT:-} ]]; then
		sed -i 's/@@@https_redirect_schema%%%/redirect_disabled/g' \
			/mnt/tmp/etc/nginx/conf.d/eva-app.conf
	else
		sed -i 's/@@@https_redirect_schema%%%/http/g' \
			/mnt/tmp/etc/nginx/conf.d/eva-app.conf
	fi
	return 0
}


build_scheme_domain() {
	local conf org_domain cookie_domain app_name account_url='' app_fqdn
	# DOMAIN == APP_FQDN
	# ORG_DOMAIN == AUTH_SESSION_COOKIE_DOMAIN or APP_FQDN
	# ACCOUNT_FQDN
	app_fqdn="$DOMAIN"
	app_name="${DOMAIN%%.*}"
	if [[ ${ORG_DOMAIN:-} ]]; then
		cookie_domain=".$ORG_DOMAIN"
	else
		ORG_DOMAIN="$DOMAIN"
		cookie_domain="$DOMAIN${EXTERNAL_PORT_HTTPS:+:$EXTERNAL_PORT_HTTPS}"
	fi
	org_domain="$ORG_DOMAIN"
	if [[ ${ACCOUNT_FQDN:-} ]]; then
		account_url="https://$ACCOUNT_FQDN"
	fi

	echo "Настраиваем работу на домене ${DOMAIN} ..."
	# configure
	cp -a /opt/bin/templates/eva-app.conf /mnt/tmp/etc/nginx/conf.d/eva-app.conf
	sed -i "s/@@@eva_domain%%%/${DOMAIN}/g" /mnt/tmp/etc/nginx/conf.d/eva-app.conf
	sed -i "s/@@@external_https_port%%%/${EXTERNAL_PORT_HTTPS:+:$EXTERNAL_PORT_HTTPS}/g" \
		/mnt/tmp/etc/nginx/conf.d/eva-app.conf
	configure_https_redirect
	configure_base_href
	configure_listen_ports

	# Описание полей https://bcrm.carbonsoft.ru/project/Document/DOC-004285
	# Версия без SSO
	for conf in /opt/eva-app/custom/config.py; do
		/opt/fox_utils/crab_conf set ORG_DOMAIN "$org_domain" "$conf"
		/opt/fox_utils/crab_conf set APP_NAME "$app_name" "$conf"
		/opt/fox_utils/crab_conf set APP_FQDN "$app_fqdn" "$conf"
		/opt/fox_utils/crab_conf set AUTH_SERVER_URL "$account_url" "$conf"
		/opt/fox_utils/crab_conf set AUTH_SESSION_COOKIE_DOMAIN \
			"$cookie_domain" "$conf"
		/opt/fox_utils/crab_conf set HOSTNAME_FQDN "$app_fqdn" "$conf"
		/opt/fox_utils/crab_conf set ORG_NAME "$app_name" "$conf"
		/opt/fox_utils/crab_conf set EXTERNAL_PORT_HTTPS \
			"${EXTERNAL_PORT_HTTPS:-}"  "$conf"
	done

	/opt/fox_utils/crab_conf set APP_FQDN "$app_fqdn" "/opt/eva_git/custom/config.py"

	echo "$app_name" > /opt/eva-app/custom/org_name
	return 0
}

check_certbot(){
	local nginx_conf
	echo "Проверяем сертификат LetsEncrypt"
	# certbot портит конфиг, сохраним и восстановим его
	nginx_conf="$(</mnt/tmp/etc/nginx/conf.d/eva-app.conf)"
	if ! certbot --nginx -d "$DOMAIN" -m "$ADMIN_EMAIL" -n --agree-tos; then
		echo "Ошибка получения сертификата Lets Encrypt!"
		echo "Возможно, домен $DOMAIN недоступен из сети интернет или указан неверно."
		echo "Если домен недоступен из интернета (например, доступен только в интранете)"
		echo "то нужно отключить опцию NGINX_USE_CERTBOT и добавить сертификат вручную"
		echo "$nginx_conf" >/mnt/tmp/etc/nginx/conf.d/eva-app.conf
		return 0
	fi
	echo "$nginx_conf" >/mnt/tmp/etc/nginx/conf.d/eva-app.conf
	ln -sf /etc/letsencrypt/live/${DOMAIN}/fullchain.pem \
		/etc/nginx/ssl/${DOMAIN}.crt
	ln -sf /etc/letsencrypt/live/${DOMAIN}/privkey.pem \
		/etc/nginx/ssl/${DOMAIN}.key
	return 0
}

main(){
	if [ "${NGINX_ENABLED:-TRUE}" != 'TRUE' ]; then
		echo "Сервис nginx отключен, пропускаем процедуру его конфигурации"
		exit 0
	fi
	if [ "${ARG_CERTBOT_RENEW:-}" = "TRUE" ] && [ "${NGINX_USE_CERTBOT:-}" = "1" ]; then
		check_certbot
		return 0
	fi
	prepare
	build_selfsigned_if_not_exists
	check_selfsigned_rootcert
	check_corp_rootcert
	localhost_domain
	build_scheme_domain
	if [ "${NGINX_USE_CERTBOT:-}" = "1" ]; then
		check_certbot
	fi
	return 0
}

main
exit 0
