#!/bin/bash

set -e

PRODUCT="docspace"
DIR="/usr/bin"
LETSENCRYPT="/etc/letsencrypt/live"
OPENRESTY="/etc/openresty/conf.d"
WEBROOT_PATH="/var/www/${PRODUCT}"
CONFIG_DIR="/etc/onlyoffice/${PRODUCT}"
DHPARAM_PATH=${DHPARAM_PATH:-"/etc/ssl/certs/dhparam.pem"}
SYSTEMD_DIR=$(dirname $($(command -v dpkg-query &> /dev/null && echo "dpkg-query -L" || echo "rpm -ql") ${PRODUCT}-api | grep systemd/system/))
ENVIRONMENT=$(grep -oP 'ENVIRONMENT=\K.*' "${CONFIG_DIR}/systemd.env")
USER_CONF="${CONFIG_DIR}/appsettings.${ENVIRONMENT}.json"

# Check if configuration files are present
if [ ! -f "${OPENRESTY}/onlyoffice-proxy-ssl.conf.template" -a ! -f "${OPENRESTY}/onlyoffice-proxy.conf.template" ]; then
 echo "Error: proxy configuration file not found." && exit 1
fi

help(){
  echo 
  echo "This script provided to automatically setup SSL Certificates for DocSpace"
  echo "Automatically get Let's Encrypt SSL Certificates:"
  echo "  docspace-ssl-setup EMAIL DOMAIN"
  echo "    EMAIL         Email used for registration and recovery contact."
  echo "                  Use commas to specify multiple emails."
  echo "    DOMAIN        Domain name(s) to apply the certificate to."
  echo "                  Multiple domains: use commas to specify several domains."
  echo "                  Wildcard domains (no auto-renew): require DNS-01 challenge and ability to create DNS TXT records."
  echo 
  echo "    Example:"
  echo "      docspace-ssl-setup u1@example.com,u2@example.com example.com,s1.example.com,s2.example.com"
  echo "      docspace-ssl-setup support@example.com example.com,*.example.com"
  echo 
  echo "Using your own certificates via the -f or --file parameter:"
  echo "  docspace-ssl-setup --file DOMAIN CERTIFICATE [PRIVATEKEY]"
  echo "    DOMAIN        Main domain name to apply."
  echo "    CERTIFICATE   Path to the certificate file for the domain (PEM, PFX, DER, CER, PKCS#7)."
  echo "    PRIVATEKEY    (Optional) Path to private key (required unless PFX)."
  echo "                  Required for PEM, DER, and CER formats."
  echo "    Example:"
  echo "      docspace-ssl-setup --file example.com /etc/ssl/example.crt /etc/ssl/example.key"
  echo "      docspace-ssl-setup --file example.com /etc/ssl/example.pfx"
  echo 
  echo "Return to the default proxy configuration using the -d or --default parameter:"
  echo "  docspace-ssl-setup --default"
  echo ""
  exit 0
}

check_file_format() {
  FILE=$1

  if openssl pkcs12 -in "$FILE" -info -noout --passin pass:"$PFX_PASSWORD" > /dev/null 2>&1; then
    CERTIFICATE_FILE="${FILE%.pfx}.pem"
    PRIVATEKEY_FILE="${FILE%.pfx}-private.pem"
    echo "$FILE is a valid PFX certificate. Converting to PEM..."
    openssl pkcs12 -in "$FILE" -out "$CERTIFICATE_FILE" -nokeys --passin pass:"$PFX_PASSWORD"
    openssl pkcs12 -in "$FILE" -out "$PRIVATEKEY_FILE" -nocerts -nodes --passin pass:"$PFX_PASSWORD"

  elif openssl x509 -in "$FILE" -inform DER -text -noout > /dev/null 2>&1; then
    echo "$FILE is a valid DER/CER certificate. Converting to PEM..."
    CERTIFICATE_FILE="${FILE%.*}.pem"
    openssl x509 -in "$FILE" -inform DER -out "$CERTIFICATE_FILE"

  elif openssl x509 -in "$FILE" -inform PEM -text -noout > /dev/null 2>&1; then
    echo "$FILE is a valid PEM certificate."
    CERTIFICATE_FILE="$FILE"

  elif openssl pkey -in "$FILE" -check > /dev/null 2>&1; then
    echo "$FILE is a valid private key."
    PRIVATEKEY_FILE="$FILE"

  elif openssl pkcs7 -in "$FILE" -print_certs -noout > /dev/null 2>&1; then
    echo "$FILE is a valid PKCS#7 certificate. Converting to PEM..."
    CERTIFICATE_FILE="${FILE%.p7b}.pem"
    openssl pkcs7 -in "$FILE" -print_certs -out "$CERTIFICATE_FILE"
  else
    echo "Unsupported or invalid file format: $FILE" && exit 1
  fi
}

case $1 in
  -f | --file )
    if [ -n "$2" ] && [ -n "$3" ]; then
    
      DOMAIN=$2
      CERTIFICATE_FILE=$3

      [[ $DOMAIN =~ ^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$ ]] || { echo "Error: domain name '$DOMAIN' is incorrect." >&2; exit 1; }
      if [[ "$CERTIFICATE_FILE" =~ \.(p12|pfx)$ ]]; then
        echo "Using PKCS#12 file for SSL configuration..."
        openssl pkcs12 -in "$CERTIFICATE_FILE" -info -noout -passin pass: >/dev/null 2>&1 || read -rsp "Enter password: " PFX_PASSWORD
        check_file_format "$CERTIFICATE_FILE"
      elif [ -n "$4" ]; then
        echo "Using specified certificate and private key for SSL configuration..."
        PRIVATEKEY_FILE=$4
        check_file_format "$CERTIFICATE_FILE" && check_file_format "$PRIVATEKEY_FILE"
      else
        echo "Error: PRIVATEKEY_FILE is required unless using a .p12/.pfx file." && exit 1
      fi
    else
      help
    fi
  ;;

  -d | --default )
    echo "Return to the default proxy configuration..."
    cp -f ${OPENRESTY}/onlyoffice-proxy.conf.template ${OPENRESTY}/onlyoffice-proxy.conf
    [[ -f "${DIR}/${PRODUCT}-renew-letsencrypt" ]] && rm -rf "${DIR}/${PRODUCT}-renew-letsencrypt"
    [[ -f "/etc/cron.weekly/${PRODUCT}-renew-letsencrypt" ]] && rm -rf "/etc/cron.weekly/${PRODUCT}-renew-letsencrypt"
    [ $(pgrep -x ""systemd"" | wc -l) -gt 0 ] && systemctl restart openresty || service openresty restart
    json -I -f ${USER_CONF} -e "this.files.docservice.url.portal = \"http://localhost:80\""
    json -I -f ${USER_CONF} -e "delete this.core['server-root']"
    chown onlyoffice:onlyoffice ${USER_CONF}
    
    IFS=';' read -ra CONN_ITEM <<< "$(json -f "$USER_CONF" ConnectionStrings.default.connectionString)"; 
    for ITEM in "${CONN_ITEM[@]}"; do KEY="${ITEM%%=*}"; VAL="${ITEM#*=}"; KEY="${KEY// /_}"; export "$KEY=$VAL"; done
    MYSQL=(mysql -h"$Server" -P"${Port:-3306}" -u"$User_ID" "-p$Password" "$Database")
    if [ -z "$(${MYSQL[@]} -N -s -e "SELECT 1 FROM core_settings WHERE tenant=-1 AND id='BaseDomain' LIMIT 1")" ]; then
      ${MYSQL[@]} -e "UPDATE tenants_tenants SET mappeddomain='NULL' WHERE alias='localhost';"
    fi
    
    NODE_EXTRA_CA_CERTS_FILES=$(grep -l "NODE_EXTRA_CA_CERTS" ${CONFIG_DIR}/systemd.env ${SYSTEMD_DIR}/ds-*.service || true)
    if [ -n "${NODE_EXTRA_CA_CERTS_FILES}" ]; then
      sed -i '/NODE_EXTRA_CA_CERTS/d' ${NODE_EXTRA_CA_CERTS_FILES}
      systemctl daemon-reload
      { grep -l "ExecStart=/usr/bin/node" ${SYSTEMD_DIR}/${PRODUCT}-*.service 2>/dev/null
        find ${SYSTEMD_DIR} -name "ds-*.service" ! -name "ds-example.service" 2>/dev/null
      } | xargs -I % basename % | xargs systemctl restart
    fi

    echo "OK"
    exit 0
  ;;

  * )
    if [ "$#" -ge "2" ]; then
      MAIL=$1
      DOMAINS=$2
      DOMAIN=${DOMAINS%%,*}; DOMAIN=${DOMAIN#\*\.}
      [[ ,$DOMAINS, == *,$DOMAIN,* ]] || DOMAINS+=",${DOMAIN}"
      LETSENCRYPT_ENABLE="true"

      # Install certbot if not already installed
      if ! type "certbot" &> /dev/null; then
        if type "apt-get" &> /dev/null; then
          apt-get -y update -qq
          apt-get -y -q install certbot
        elif type "yum" &> /dev/null; then
          yum -y install certbot
        fi
      fi

      echo "Generating Let's Encrypt SSL Certificates..."

      if [[ "${DOMAINS}" =~ \*\.[^,]* ]]; then
        CERTBOT_CMD=(certbot certonly --manual --preferred-challenges dns --key-type rsa --cert-name "${PRODUCT}" --agree-tos --email "${MAIL}" -d "${DOMAINS[@]}")
      else
        CERTBOT_CMD=(certbot certonly --expand --webroot -w "${WEBROOT_PATH}" --key-type rsa --cert-name "${PRODUCT}" --noninteractive --agree-tos --email "${MAIL}" -d "${DOMAINS[@]}")
      fi
      echo "${CERTBOT_CMD[@]}" > /var/log/le-start.log
      "${CERTBOT_CMD[@]}" | tee /var/log/le-new.log
    else
      help
    fi
  ;;
esac

[[ ! -f "${DHPARAM_PATH}" ]] && openssl dhparam -out ${DHPARAM_PATH} 2048
CERTIFICATE_FILE="${CERTIFICATE_FILE:-"${LETSENCRYPT}/${PRODUCT}/fullchain.pem"}"
PRIVATEKEY_FILE="${PRIVATEKEY_FILE:-"${LETSENCRYPT}/${PRODUCT}/privkey.pem"}"
[[ "$CERTIFICATE_FILE" != /* ]] && CERTIFICATE_FILE="$(cd "$(dirname "$CERTIFICATE_FILE")" && pwd)/$(basename "$CERTIFICATE_FILE")"
[[ "$PRIVATEKEY_FILE" != /* ]] && PRIVATEKEY_FILE="$(cd "$(dirname "$PRIVATEKEY_FILE")" && pwd)/$(basename "$PRIVATEKEY_FILE")"

if [ -f "${CERTIFICATE_FILE}" ]; then 
  if [ -f "${PRIVATEKEY_FILE}" ]; then
    cp -f ${OPENRESTY}/onlyoffice-proxy-ssl.conf.template ${OPENRESTY}/onlyoffice-proxy.conf
    json -I -f ${USER_CONF} -e "this.files.docservice.url.portal = \"https://${DOMAIN}\""
    json -I -f ${USER_CONF} -e "this.core['server-root'] = 'https://*/'"
    sed -i "s~\(ssl_certificate \).*;~\1${CERTIFICATE_FILE};~g" ${OPENRESTY}/onlyoffice-proxy.conf
    sed -i "s~\(ssl_certificate_key \).*;~\1${PRIVATEKEY_FILE};~g" ${OPENRESTY}/onlyoffice-proxy.conf
    sed -i "s~\(ssl_dhparam \).*;~\1${DHPARAM_PATH};~g" ${OPENRESTY}/onlyoffice-proxy.conf
    chown onlyoffice:onlyoffice ${USER_CONF}

    if [[ "${LETSENCRYPT_ENABLE}" = "true" ]]; then
      CRON_PATH=$(command -v crond || command -v cron) && CRON_SVC=${CRON_PATH##*/} || { echo "Error: neither crond nor cron is installed." >&2; }
      if [[ -n "${CRON_SVC}" ]]; then
        command -v systemctl &>/dev/null && systemctl enable --now "$CRON_SVC" || { command -v service &>/dev/null && service "${CRON_SVC%.service}" start; }
        if [ -d /etc/cron.weekly ]; then
            CRON_FILE="/etc/cron.weekly/${PRODUCT}-renew-letsencrypt"
            echo '#!/bin/bash' > ${CRON_FILE}
            echo '#' >> ${CRON_FILE}
            echo "# ${PRODUCT} Renew Let's Encrypt SSL Certificates" >> ${CRON_FILE}
            echo "" >> ${CRON_FILE}
            echo "echo \"[\$(date '+%F %T')] START /etc/cron.weekly/${PRODUCT}-renew-letsencrypt\" >> \"/var/log/${PRODUCT}-renew-letsencrypt.log\"" >> ${CRON_FILE}
            echo "certbot renew 2>&1 | tee -a /var/log/${PRODUCT}-renew-letsencrypt.log" >> ${CRON_FILE}
            if [ $(pgrep -x ""systemd"" | wc -l) -gt 0 ]; then
              echo 'systemctl restart openresty' >> "${CRON_FILE}"
            else 
              echo 'service openresty restart' >> "${CRON_FILE}"
            fi
            chmod a+x "${CRON_FILE}"
        else
          echo "Error: directory /etc/cron.weekly does not exist." >&2
        fi
      fi
    else
      CERTIFICATE_SUBJECT=$(openssl x509 -subject -noout -in "${CERTIFICATE_FILE}" | sed 's/subject=//')
      CERTIFICATE_ISSUER=$(openssl x509 -issuer -noout -in "${CERTIFICATE_FILE}" | sed 's/issuer=//')
      
      #Checking whether the certificate is self-signed
      if [[ -n "$CERTIFICATE_SUBJECT" && -n "$CERTIFICATE_ISSUER" && "$CERTIFICATE_SUBJECT" == "$CERTIFICATE_ISSUER" ]]; then
        chmod o+rx $(dirname "$CERTIFICATE_FILE")
        chmod 644 ${CERTIFICATE_FILE} ${PRIVATEKEY_FILE}
        grep -q "NODE_EXTRA_CA_CERTS" ${CONFIG_DIR}/systemd.env && \
          sed -i "s!\(NODE_EXTRA_CA_CERTS=\).*!\1${CERTIFICATE_FILE}!" ${CONFIG_DIR}/systemd.env || \
          echo "NODE_EXTRA_CA_CERTS=${CERTIFICATE_FILE}" >> ${CONFIG_DIR}/systemd.env
        for SYSTEMD_NODE_FILE in ${SYSTEMD_DIR}/ds-*.service; do
          [[ ${SYSTEMD_NODE_FILE} == *"ds-example"* || ! -f ${SYSTEMD_NODE_FILE} ]] && continue
          grep -q "NODE_EXTRA_CA_CERTS" ${SYSTEMD_NODE_FILE} && \
            sed -i "s!\(NODE_EXTRA_CA_CERTS=\).*!\1${CERTIFICATE_FILE}!" ${SYSTEMD_NODE_FILE} || \
            sed -i "/ExecStart=/i Environment=NODE_EXTRA_CA_CERTS=${CERTIFICATE_FILE}" ${SYSTEMD_NODE_FILE}
        done
        systemctl daemon-reload
        { grep -l "ExecStart=/usr/bin/node" ${SYSTEMD_DIR}/${PRODUCT}-*.service 2>/dev/null
          find ${SYSTEMD_DIR} -name "ds-*.service" ! -name "ds-example.service" 2>/dev/null
        } | xargs -I % basename % | xargs systemctl restart
      fi
    fi

    # fix Bug 75803 - In the "What's new..." email, the portal domain comes as localhost
    IFS=';' read -ra CONN_ITEM <<< "$(json -f "$USER_CONF" ConnectionStrings.default.connectionString)"; 
    for ITEM in "${CONN_ITEM[@]}"; do KEY="${ITEM%%=*}"; VAL="${ITEM#*=}"; KEY="${KEY// /_}"; export "$KEY=$VAL"; done
    MYSQL=(mysql -h"$Server" -P"${Port:-3306}" -u"$User_ID" "-p$Password" "$Database")
    if [ -z "$(${MYSQL[@]} -N -s -e "SELECT 1 FROM core_settings WHERE tenant=-1 AND id='BaseDomain' LIMIT 1")" ]; then
      ${MYSQL[@]} -e "UPDATE tenants_tenants SET mappeddomain='${DOMAIN}' WHERE alias='localhost';"
    fi

    [ $(pgrep -x ""systemd"" | wc -l) -gt 0 ] && systemctl restart openresty || service openresty restart

    echo "OK"
  else
    echo "Error: private key file at path ${PRIVATEKEY_FILE} not found." && exit 1
  fi
else
  echo "Error: certificate file at path ${CERTIFICATE_FILE} not found." && exit 1
fi
