#!/usr/bin/env bash

site=hanzalova
tls_tld=internal

app_name=swym
app_env=dev

nginx_host=${site}.${tls_tld}
nginx_user=nginx
app_fqdn=${app_env}.${app_name}.${nginx_host}
dev_fqdn=$(hostnamectl hostname)
dev_ip=$(ip -4 addr show scope global | awk '/inet /{print $2}' | cut -d/ -f1 | head -1)

tls_work_dir=${HOME}/.config/tls/${tls_tld}
tls_algorithm=rsa
tls_key_options=rsa_keygen_bits:4096
tls_cert_basic_constraints=basicConstraints=critical,CA:FALSE
tls_cert_extended_key_usage=extendedKeyUsage=serverAuth,clientAuth
tls_cert_validity_in_days=1095

tls_key_bitmask=0640
tls_cert_bitmask=0644
tls_ca_pem_filename=ca.${tls_tld}-${tls_algorithm}.pem
tls_ca_key_path=${tls_work_dir}/key/${tls_ca_pem_filename}
tls_ca_cert_path=${tls_work_dir}/cert/${tls_ca_pem_filename}

tls_system_ca_cert_dir=/etc/pki/ca-trust/source/anchors
tls_system_cert_dir=/etc/pki/tls/misc
tls_system_key_dir=/etc/pki/tls/private

tls_dev_pem_filename=${dev_fqdn}-${tls_algorithm}.pem
tls_dev_key_path=${tls_work_dir}/key/${tls_dev_pem_filename}
tls_dev_csr_path=${tls_work_dir}/csr/${tls_dev_pem_filename}
tls_dev_ext_path=${tls_work_dir}/csr/${dev_fqdn}-${tls_algorithm}.conf
tls_dev_cert_path=${tls_work_dir}/cert/${tls_dev_pem_filename}
tls_dev_cert_chain_path=${tls_work_dir}/cert/${dev_fqdn}-${tls_algorithm}-chain.pem

tls_app_pem_filename=${app_fqdn}-${tls_algorithm}.pem
tls_app_key_path=${tls_work_dir}/key/${tls_app_pem_filename}
tls_app_csr_path=${tls_work_dir}/csr/${tls_app_pem_filename}
tls_app_ext_path=${tls_work_dir}/csr/${app_fqdn}-${tls_algorithm}.conf
tls_app_cert_path=${tls_work_dir}/cert/${tls_app_pem_filename}
tls_app_cert_chain_path=${tls_work_dir}/cert/${app_fqdn}-${tls_algorithm}-chain.pem

mkdir -p ${tls_work_dir}/{key,csr,cert}

# sync local ca cert
echo "${dev_fqdn}:"
echo "  ca:"
if [ -s ${tls_system_ca_cert_dir}/${tls_ca_pem_filename} ]; then
    echo "    local: observed ${tls_system_ca_cert_dir}/${tls_ca_pem_filename}"
elif sudo install \
    --owner root \
    --group root \
    --mode ${tls_cert_bitmask} \
    ${tls_ca_cert_path} \
    ${tls_system_ca_cert_dir}/${tls_ca_pem_filename} \
    && sudo update-ca-trust; then
    echo "    local: created ${tls_system_ca_cert_dir}/${tls_ca_pem_filename} (${tls_cert_bitmask})"
else
    echo "    local: create failed ${tls_system_ca_cert_dir}/${tls_ca_pem_filename}"
    exit 1
fi

# observe or create dev key
echo "  key:"
if [ -f ${tls_dev_key_path} ]; then
    echo "    local: observed ${tls_dev_key_path}"
elif openssl genpkey \
        -algorithm ${tls_algorithm} \
        -pkeyopt ${tls_key_options} \
        -out ${tls_dev_key_path} \
        2> ${tls_dev_key_path}.log \
    && chmod ${tls_key_bitmask} ${tls_dev_key_path}; then
    echo "    local: created ${tls_dev_key_path}"
else
    echo "    local: create failed ${tls_dev_key_path}"
    exit 1
fi
# sync dev key to filesystem
if sudo install \
    --owner root \
    --group root \
    --mode ${tls_key_bitmask} \
    ${tls_dev_key_path} \
    ${tls_system_key_dir}/${tls_dev_pem_filename} \
    && sudo setfacl \
        --modify u:${USER}:r \
        ${tls_system_key_dir}/${tls_dev_pem_filename}; then
    echo "    local: synced ${tls_dev_key_path} to ${tls_system_key_dir}/${tls_dev_pem_filename} (${tls_key_bitmask})"
else
    echo "    local: sync failed ${tls_dev_key_path} to ${tls_system_key_dir}/${tls_dev_pem_filename}"
    exit 1
fi

# observe or create dev csr
echo "  csr:"
if [ "${tls_overwrite_dev_certs}" != "true" ] && [ -f ${tls_dev_csr_path} ]; then
    echo "    local: observed ${tls_dev_csr_path}"
elif openssl req -new \
        -key ${tls_dev_key_path} \
        -subj "/CN=${dev_fqdn}" \
        -addext ${tls_cert_basic_constraints} \
        -addext ${tls_cert_extended_key_usage} \
        -addext "subjectAltName=DNS:${dev_fqdn},IP:${dev_ip}" \
        -out ${tls_dev_csr_path}; then
    if [ "${tls_overwrite_dev_certs}" = "true" ]; then
        echo "    local: recreated ${tls_dev_csr_path}"
    else
        echo "    local: created ${tls_dev_csr_path}"
    fi
else
    echo "    local: create failed ${tls_dev_csr_path}"
    exit 1
fi
if [ "${tls_overwrite_dev_certs}" = "true" ] || [ ! -f ${tls_dev_ext_path} ]; then
    echo ${tls_cert_basic_constraints} > ${tls_dev_ext_path}
    echo ${tls_cert_extended_key_usage} >> ${tls_dev_ext_path}
    echo subjectAltName=DNS:${dev_fqdn},IP:${dev_ip} >> ${tls_dev_ext_path}
fi

# observe or create dev cert, signed by ca
echo "  cert:"
if [ "${tls_overwrite_dev_certs}" != "true" ] && [ -f ${tls_dev_cert_path} ]; then
    echo "    local: observed ${tls_dev_cert_path}"
elif openssl x509 \
        -req \
        -in ${tls_dev_csr_path} \
        -CA ${tls_ca_cert_path} \
        -CAkey ${tls_ca_key_path} \
        -CAcreateserial \
        -out ${tls_dev_cert_path} \
        -extfile ${tls_dev_ext_path} \
        -days ${tls_cert_validity_in_days} \
        -sha256 \
    2> ${tls_dev_cert_path}.log; then
    if [ "${tls_overwrite_dev_certs}" = "true" ]; then
        echo "    local: recreated ${tls_dev_cert_path}"
    else
        echo "    local: created ${tls_dev_cert_path}"
    fi
else
    echo "    local: create failed ${tls_dev_cert_path}"
    exit 1
fi

# sync dev cert to filesystem
if sudo install \
    --owner root \
    --group root \
    --mode ${tls_cert_bitmask} \
    ${tls_dev_cert_path} \
    ${tls_system_cert_dir}/${tls_dev_pem_filename}; then
    echo "    local: synced ${tls_dev_cert_path} to ${tls_system_cert_dir}/${tls_dev_pem_filename} (${tls_cert_bitmask})"
else
    echo "    local: sync failed ${tls_dev_cert_path} to ${tls_system_cert_dir}/${tls_dev_pem_filename}"
    exit 1
fi

# sync ca cert to nginx host
echo "${nginx_host}:"
echo "  ca:"
if rsync \
    --archive \
    --compress \
    --rsync-path 'sudo rsync' \
    --chown root:root \
    --chmod ${tls_cert_bitmask} \
    ${tls_ca_cert_path} \
    ${nginx_host}:${tls_system_ca_cert_dir}/${tls_ca_pem_filename} \
    && ssh ${nginx_host} sudo update-ca-trust; then
    echo "    sync succeeded: ${tls_ca_cert_path} to ${nginx_host}:${tls_system_ca_cert_dir}/${tls_ca_pem_filename}"
else
    echo "    sync failed: ${tls_ca_cert_path} to ${nginx_host}:${tls_system_ca_cert_dir}/${tls_ca_pem_filename}"
    exit 1
fi

# observe or create app key
echo "  key:"
if [ -f ${tls_app_key_path} ]; then
    echo "    local: observed ${tls_app_key_path}"
elif openssl genpkey \
        -algorithm ${tls_algorithm} \
        -pkeyopt ${tls_key_options} \
        -out ${tls_app_key_path} \
        2> ${tls_app_key_path}.log \
    && chmod ${tls_key_bitmask} ${tls_app_key_path}; then
    echo "    local: created ${tls_app_key_path}"
else
    echo "    local: create failed ${tls_app_key_path}"
    exit 1
fi
# sync app key to nginx host
if rsync \
    --archive \
    --compress \
    --rsync-path 'sudo rsync' \
    --chown root:root \
    --chmod ${tls_key_bitmask} \
    ${tls_app_key_path} \
    ${nginx_host}:${tls_system_key_dir}/${tls_app_pem_filename} \
    && ssh ${nginx_host} sudo setfacl \
        --modify u:${nginx_user}:r \
        ${tls_system_key_dir}/${tls_app_pem_filename}; then
    echo "    proxy: synced ${tls_app_key_path} to ${nginx_host}:${tls_system_key_dir}/${tls_app_pem_filename}"
else
    echo "    proxy: sync failed ${tls_app_key_path} to ${nginx_host}:${tls_system_key_dir}/${tls_app_pem_filename}"
    exit 1
fi

# observe or create app csr
echo "  csr:"
if [ "${tls_overwrite_app_certs}" != "true" ] && [ -f ${tls_app_csr_path} ]; then
    echo "    local: observed ${tls_app_csr_path}"
elif openssl req -new \
        -key ${tls_app_key_path} \
        -subj "/CN=${app_fqdn}" \
        -addext ${tls_cert_basic_constraints} \
        -addext ${tls_cert_extended_key_usage} \
        -addext "subjectAltName=DNS:${app_fqdn}" \
        -out ${tls_app_csr_path}; then
    if [ "${tls_overwrite_app_certs}" = "true" ]; then
        echo "    local: recreated ${tls_app_csr_path}"
    else
        echo "    local: created ${tls_app_csr_path}"
    fi
else
    echo "    local: create failed ${tls_app_csr_path}"
    exit 1
fi
if [ "${tls_overwrite_app_certs}" = "true" ] || [ ! -f ${tls_app_ext_path} ]; then
    echo ${tls_cert_basic_constraints} > ${tls_app_ext_path}
    echo ${tls_cert_extended_key_usage} >> ${tls_app_ext_path}
    echo subjectAltName=DNS:${app_fqdn} >> ${tls_app_ext_path}
fi

# observe or create app cert, signed by ca
echo "  cert:"
if [ "${tls_overwrite_app_certs}" != "true" ] && [ -f ${tls_app_cert_path} ]; then
    echo "    local: observed ${tls_app_cert_path}"
elif openssl x509 \
        -req \
        -in ${tls_app_csr_path} \
        -CA ${tls_ca_cert_path} \
        -CAkey ${tls_ca_key_path} \
        -CAcreateserial \
        -out ${tls_app_cert_path} \
        -extfile ${tls_app_ext_path} \
        -days ${tls_cert_validity_in_days} \
        -sha256 \
    2> ${tls_app_cert_path}.log; then
    if [ "${tls_overwrite_app_certs}" = "true" ]; then
        echo "    local: recreated ${tls_app_cert_path}"
    else
        echo "    local: created ${tls_app_cert_path}"
    fi
else
    echo "    local: create failed ${tls_app_cert_path}"
    exit 1
fi

# create app chain cert (app + ca). note that order is significant. app first, for integrations that read first cert only.
cat \
    ${tls_app_cert_path} \
    ${tls_ca_cert_path} \
    > ${tls_app_cert_chain_path}
# sync app chain cert to nginx host
if rsync \
    --archive \
    --compress \
    --rsync-path 'sudo rsync' \
    --chown root:root \
    --chmod ${tls_cert_bitmask} \
    ${tls_app_cert_chain_path} \
    ${nginx_host}:${tls_system_cert_dir}/${tls_app_pem_filename}; then
    echo "    proxy: synced ${tls_app_cert_path} to ${nginx_host}:${tls_system_cert_dir}/${tls_app_pem_filename}"
else
    echo "    proxy: sync failed ${tls_app_cert_path} to ${nginx_host}:${tls_system_cert_dir}/${tls_app_pem_filename}"
    exit 1
fi
