#!/usr/bin/with-contenv bash

# Display variables for troubleshooting
echo -e "Variables set:\\n\
PUID=${PUID}\\n\
PGID=${PGID}\\n\
TZ=${TZ}\\n\
URL=${URL}\\n\
SUBDOMAINS=${SUBDOMAINS}\\n\
EXTRA_DOMAINS=${EXTRA_DOMAINS}\\n\
ONLY_SUBDOMAINS=${ONLY_SUBDOMAINS}\\n\
VALIDATION=${VALIDATION}\\n\
DNSPLUGIN=${DNSPLUGIN}\\n\
EMAIL=${EMAIL}\\n\
STAGING=${STAGING}\\n"

# Echo init finish for test runs
if [ -n "${TEST_RUN}" ]; then
	echo '[services.d] done.'
fi

# Sanitize variables
SANED_VARS=( DNSPLUGIN EMAIL EXTRA_DOMAINS ONLY_SUBDOMAINS STAGING SUBDOMAINS URL VALIDATION )
for i in "${SANED_VARS[@]}"
do
  export echo "$i"="${!i//\"/}"
  export echo "$i"="$(echo "${!i}" | tr '[:upper:]' '[:lower:]')"
done

# check to make sure that the required variables are set
[[ -z "$URL" ]] && \
  echo "Please pass your URL as an environment variable in your docker run command. See docker info for more details." && \
  sleep infinity

# make our folders and links
mkdir -p \
	/config/{log/letsencrypt,log/fail2ban,etc/letsencrypt,fail2ban,crontabs,dns-conf,geoip2db} \
	/var/run/fail2ban
rm -rf /etc/letsencrypt
ln -s /config/etc/letsencrypt /etc/letsencrypt

# copy dns default configs
cp -n /defaults/dns-conf/* /config/dns-conf/
chown -R abc:abc /config/dns-conf

# copy reverse proxy configs
cp -R /defaults/proxy-confs /config/nginx/
# remove outdated files (remove this action after 2020/10/17)
rm -f /config/nginx/proxy-confs/seafile.subdomain.config.sample /config/nginx/proxy-confs/librespeed.subdomain.com.sample

# copy/update the fail2ban config defaults to/in /config
cp -R /defaults/fail2ban/filter.d /config/fail2ban/
cp -R /defaults/fail2ban/action.d /config/fail2ban/
# if jail.local is missing in /config, copy default
[[ ! -f /config/fail2ban/jail.local ]] && \
	cp /defaults/jail.local /config/fail2ban/jail.local
# Replace fail2ban config with user config
[[ -d /etc/fail2ban/filter.d ]] && \
	rm -rf /etc/fail2ban/filter.d
[[ -d /etc/fail2ban/action.d ]] && \
	rm -rf /etc/fail2ban/action.d
cp -R /config/fail2ban/filter.d /etc/fail2ban/
cp -R /config/fail2ban/action.d /etc/fail2ban/
cp /defaults/fail2ban/fail2ban.local /etc/fail2ban/
cp /config/fail2ban/jail.local /etc/fail2ban/jail.local

# copy crontab and proxy defaults if needed
[[ ! -f /config/crontabs/root ]] && \
	cp /etc/crontabs/root /config/crontabs/
[[ ! -f /config/nginx/proxy.conf ]] && \
	cp /defaults/proxy.conf /config/nginx/proxy.conf
[[ ! -f /config/nginx/ssl.conf ]] && \
	cp /defaults/ssl.conf /config/nginx/ssl.conf
[[ ! -f /config/nginx/ldap.conf ]] && \
	cp /defaults/ldap.conf /config/nginx/ldap.conf
[[ ! -f /config/nginx/authelia-server.conf ]] && \
	cp /defaults/authelia-server.conf /config/nginx/authelia-server.conf
[[ ! -f /config/nginx/authelia-location.conf ]] && \
	cp /defaults/authelia-location.conf /config/nginx/authelia-location.conf
[[ ! -f /config/nginx/geoip2.conf ]] && \
	cp /defaults/geoip2.conf /config/nginx/geoip2.conf

# copy pre-generated dhparams or generate if needed
[[ ! -f /config/nginx/dhparams.pem ]] && \
  cp /defaults/dhparams.pem /config/nginx/dhparams.pem
if ! grep -q 'PARAMETERS' "/config/nginx/dhparams.pem"; then
  curl -o /config/nginx/dhparams.pem -L "https://lsio.ams3.digitaloceanspaces.com/dhparams.pem"
fi
if ! grep -q 'PARAMETERS' "/config/nginx/dhparams.pem"; then
  echo "Generating dhparams.pem. This will take a long time. Do not stop the container until this process is completed."
  openssl dhparam -out /config/nginx/dhparams.pem 4096
fi

# check to make sure DNSPLUGIN is selected if dns validation is used
[[ "$VALIDATION" = "dns" ]] && [[ ! "$DNSPLUGIN" =~ ^(aliyun|cloudflare|cloudxns|cpanel|digitalocean|dnsimple|dnsmadeeasy|domeneshop|gandi|google|inwx|linode|luadns|netcup|nsone|ovh|rfc2136|route53|transip)$ ]] && \
  echo "Please set the DNSPLUGIN variable to a valid plugin name. See docker info for more details." && \
  sleep infinity

# import user crontabs
rm /etc/crontabs/*
cp /config/crontabs/* /etc/crontabs/

# create original config file if it doesn't exist
if [ ! -f "/config/donoteditthisfile.conf" ]; then
  echo -e "ORIGURL=\"$URL\" ORIGSUBDOMAINS=\"$SUBDOMAINS\" ORIGONLY_SUBDOMAINS=\"$ONLY_SUBDOMAINS\" ORIGEXTRA_DOMAINS=\"$EXTRA_DOMAINS\" ORIGVALIDATION=\"$VALIDATION\" ORIGDNSPLUGIN=\"$DNSPLUGIN\" ORIGPROPAGATION=\"$PROPAGATION\" ORIGSTAGING=\"$STAGING\" ORIGDUCKDNSTOKEN=\"$DUCKDNSTOKEN\"" > /config/donoteditthisfile.conf
  echo "Created donoteditthisfile.conf"
fi

# load original config settings
# shellcheck disable=SC1091
. /config/donoteditthisfile.conf

# set default validation to http
if [ -z "$VALIDATION" ]; then
  VALIDATION="http"
  echo "VALIDATION parameter not set; setting it to http"
fi

# if staging is set to true, use the staging server
if [ "$STAGING" = "true" ]; then
  echo "NOTICE: Staging is active"
  ACMESERVER="https://acme-staging-v02.api.letsencrypt.org/directory"
else
  ACMESERVER="https://acme-v02.api.letsencrypt.org/directory"
fi

# figuring out url only vs url & subdomains vs subdomains only
if [ -n "$SUBDOMAINS" ]; then
  echo "SUBDOMAINS entered, processing"
  if [ "$SUBDOMAINS" = "wildcard" ]; then
    if [ "$ONLY_SUBDOMAINS" = true ]; then
      export URL_REAL="-d *.${URL}"
      echo "Wildcard cert for only the subdomains of $URL will be requested"
    else
      export URL_REAL="-d *.${URL} -d ${URL}"
      echo "Wildcard cert for $URL will be requested"
    fi
  else
    echo "SUBDOMAINS entered, processing"
    for job in $(echo "$SUBDOMAINS" | tr "," " "); do
      export SUBDOMAINS_REAL="$SUBDOMAINS_REAL -d ${job}.${URL}"
    done
    if [ "$ONLY_SUBDOMAINS" = true ]; then
      URL_REAL="$SUBDOMAINS_REAL"
      echo "Only subdomains, no URL in cert"
    else
      URL_REAL="-d ${URL}${SUBDOMAINS_REAL}"
    fi
    echo "Sub-domains processed are: $SUBDOMAINS_REAL"
  fi
else
  echo "No subdomains defined"
  URL_REAL="-d $URL"
fi

# add extra domains
if [ -n "$EXTRA_DOMAINS" ]; then
  echo "EXTRA_DOMAINS entered, processing"
  for job in $(echo "$EXTRA_DOMAINS" | tr "," " "); do
    export EXTRA_DOMAINS_REAL="$EXTRA_DOMAINS_REAL -d ${job}"
  done
  echo "Extra domains processed are: $EXTRA_DOMAINS_REAL"
  URL_REAL="$URL_REAL $EXTRA_DOMAINS_REAL"
fi

# figuring out whether to use e-mail and which
if [[ $EMAIL == *@* ]]; then
  echo "E-mail address entered: ${EMAIL}"
  EMAILPARAM="-m ${EMAIL} --no-eff-email"
else
  echo "No e-mail address entered or address invalid"
  EMAILPARAM="--register-unsafely-without-email"
fi

# setting the validation method to use
if [ "$VALIDATION" = "dns" ]; then
  if [ "$DNSPLUGIN" = "route53" ]; then
    if [ -n "$PROPAGATION" ];then PROPAGATIONPARAM="--dns-${DNSPLUGIN}-propagation-seconds ${PROPAGATION}"; fi
    PREFCHAL="--dns-${DNSPLUGIN} ${PROPAGATIONPARAM} --manual-public-ip-logging-ok"
  elif [[ "$DNSPLUGIN" =~ ^(cpanel)$ ]]; then
    if [ -n "$PROPAGATION" ];then PROPAGATIONPARAM="--certbot-dns-${DNSPLUGIN}:${DNSPLUGIN}-propagation-seconds ${PROPAGATION}"; fi
    PREFCHAL="-a certbot-dns-${DNSPLUGIN}:${DNSPLUGIN} --certbot-dns-${DNSPLUGIN}:${DNSPLUGIN}-credentials /config/dns-conf/${DNSPLUGIN}.ini ${PROPAGATIONPARAM} --manual-public-ip-logging-ok"
  elif [[ "$DNSPLUGIN" =~ ^(gandi)$ ]]; then
    if [ -n "$PROPAGATION" ];then echo "Gandi dns plugin does not support setting propagation time"; fi
    PREFCHAL="-a certbot-plugin-${DNSPLUGIN}:dns --certbot-plugin-${DNSPLUGIN}:dns-credentials /config/dns-conf/${DNSPLUGIN}.ini --manual-public-ip-logging-ok"
  elif [[ "$DNSPLUGIN" =~ ^(google)$ ]]; then
    if [ -n "$PROPAGATION" ];then PROPAGATIONPARAM="--dns-${DNSPLUGIN}-propagation-seconds ${PROPAGATION}"; fi
    PREFCHAL="--dns-${DNSPLUGIN} --dns-${DNSPLUGIN}-credentials /config/dns-conf/${DNSPLUGIN}.json ${PROPAGATIONPARAM} --manual-public-ip-logging-ok"
  elif [[ "$DNSPLUGIN" =~ ^(aliyun|domeneshop|inwx|transip)$ ]]; then
    if [ -n "$PROPAGATION" ];then PROPAGATIONPARAM="--certbot-dns-${DNSPLUGIN}:dns-${DNSPLUGIN}-propagation-seconds ${PROPAGATION}"; fi
    PREFCHAL="-a certbot-dns-${DNSPLUGIN}:dns-${DNSPLUGIN} --certbot-dns-${DNSPLUGIN}:dns-${DNSPLUGIN}-credentials /config/dns-conf/${DNSPLUGIN}.ini ${PROPAGATIONPARAM} --manual-public-ip-logging-ok"
  elif [[ "$DNSPLUGIN" =~ ^(netcup)$ ]]; then
    if [ -n "$PROPAGATION" ];then PROPAGATIONPARAM="--dns-${DNSPLUGIN}-propagation-seconds ${PROPAGATION}"; fi
    PREFCHAL="-a dns-${DNSPLUGIN} --dns-${DNSPLUGIN}-credentials /config/dns-conf/${DNSPLUGIN}.ini ${PROPAGATIONPARAM} --manual-public-ip-logging-ok"
  else
    if [ -n "$PROPAGATION" ];then PROPAGATIONPARAM="--dns-${DNSPLUGIN}-propagation-seconds ${PROPAGATION}"; fi
    PREFCHAL="--dns-${DNSPLUGIN} --dns-${DNSPLUGIN}-credentials /config/dns-conf/${DNSPLUGIN}.ini ${PROPAGATIONPARAM} --manual-public-ip-logging-ok"
  fi
  echo "${VALIDATION} validation via ${DNSPLUGIN} plugin is selected"
elif [ "$VALIDATION" = "tls-sni" ]; then
  PREFCHAL="--non-interactive --standalone --preferred-challenges http"
  echo "*****tls-sni validation has been deprecated, attempting http validation instead"
elif [ "$VALIDATION" = "duckdns" ]; then
  PREFCHAL="--non-interactive --manual --preferred-challenges dns --manual-public-ip-logging-ok --manual-auth-hook /app/duckdns-txt"
  chmod +x /app/duckdns-txt
  echo "duckdns validation is selected"
  if [ "$SUBDOMAINS" = "wildcard" ]; then
    echo "the resulting certificate will only cover the subdomains due to a limitation of duckdns, so it is advised to set the root location to use www.subdomain.duckdns.org"
    export URL_REAL="-d *.${URL}"
  else
    echo "the resulting certificate will only cover the main domain due to a limitation of duckdns, ie. subdomain.duckdns.org"
    export URL_REAL="-d ${URL}"
  fi
else
  PREFCHAL="--non-interactive --standalone --preferred-challenges http"
  echo "http validation is selected"
fi

# setting the symlink for key location
rm -rf /config/keys/letsencrypt
if [ "$ONLY_SUBDOMAINS" = "true" ] && [ ! "$SUBDOMAINS" = "wildcard" ] ; then
  DOMAIN="$(echo "$SUBDOMAINS" | tr ',' ' ' | awk '{print $1}').${URL}"
  ln -s ../etc/letsencrypt/live/"$DOMAIN" /config/keys/letsencrypt
else
  ln -s ../etc/letsencrypt/live/"$URL" /config/keys/letsencrypt
fi

# checking for changes in cert variables, revoking certs if necessary
if [ ! "$URL" = "$ORIGURL" ] || [ ! "$SUBDOMAINS" = "$ORIGSUBDOMAINS" ] || [ ! "$ONLY_SUBDOMAINS" = "$ORIGONLY_SUBDOMAINS" ] || [ ! "$EXTRA_DOMAINS" = "$ORIGEXTRA_DOMAINS" ] || [ ! "$VALIDATION" = "$ORIGVALIDATION" ] || [ ! "$DNSPLUGIN" = "$ORIGDNSPLUGIN" ] || [ ! "$PROPAGATION" = "$ORIGPROPAGATION" ] || [ ! "$STAGING" = "$ORIGSTAGING" ] || [ ! "$DUCKDNSTOKEN" = "$ORIGDUCKDNSTOKEN" ]; then
  echo "Different validation parameters entered than what was used before. Revoking and deleting existing certificate, and an updated one will be created"
  if [ "$ORIGONLY_SUBDOMAINS" = "true" ] && [ ! "$ORIGSUBDOMAINS" = "wildcard" ]; then
    ORIGDOMAIN="$(echo "$ORIGSUBDOMAINS" | tr ',' ' ' | awk '{print $1}').${ORIGURL}"
    [[ -f /config/etc/letsencrypt/live/"$ORIGDOMAIN"/fullchain.pem ]] && certbot revoke --non-interactive --cert-path /config/etc/letsencrypt/live/"$ORIGDOMAIN"/fullchain.pem
  else
    [[ -f /config/etc/letsencrypt/live/"$ORIGURL"/fullchain.pem ]] && certbot revoke --non-interactive --cert-path /config/etc/letsencrypt/live/"$ORIGURL"/fullchain.pem
  fi
  rm -rf /config/etc/letsencrypt
  mkdir -p /config/etc/letsencrypt
fi

# saving new variables
echo -e "ORIGURL=\"$URL\" ORIGSUBDOMAINS=\"$SUBDOMAINS\" ORIGONLY_SUBDOMAINS=\"$ONLY_SUBDOMAINS\" ORIGEXTRA_DOMAINS=\"$EXTRA_DOMAINS\" ORIGVALIDATION=\"$VALIDATION\" ORIGDNSPLUGIN=\"$DNSPLUGIN\" ORIGPROPAGATION=\"$PROPAGATION\" ORIGSTAGING=\"$STAGING\" ORIGDUCKDNSTOKEN=\"$DUCKDNSTOKEN\"" > /config/donoteditthisfile.conf

# alter extension for error message
if [ "$DNSPLUGIN" = "google" ]; then
  FILENAME="$DNSPLUGIN.json"
else
  FILENAME="$DNSPLUGIN.ini"
fi

# generating certs if necessary
if [ ! -f "/config/keys/letsencrypt/fullchain.pem" ]; then
  echo "Generating new certificate"
 # shellcheck disable=SC2086
 certbot certonly --renew-by-default --server $ACMESERVER $PREFCHAL --rsa-key-size 4096 $EMAILPARAM --agree-tos $URL_REAL
  if [ -d /config/keys/letsencrypt ]; then
    cd /config/keys/letsencrypt || exit
  else
    if [ "$VALIDATION" = "dns" ]; then
      echo "ERROR: Cert does not exist! Please see the validation error above. Make sure you entered correct credentials into the /config/dns-conf/${FILENAME} file."
    elif [ "$VALIDATION" = "duckdns" ]; then
      echo "ERROR: Cert does not exist! Please see the validation error above. Make sure your DUCKDNSTOKEN is correct."
    else
      echo "ERROR: Cert does not exist! Please see the validation error above. The issue may be due to incorrect dns or port forwarding settings. Please fix your settings and recreate the container"
    fi
    sleep infinity
  fi
  openssl pkcs12 -export -out privkey.pfx -inkey privkey.pem -in cert.pem -certfile chain.pem -passout pass:
  sleep 1
  cat {privkey,fullchain}.pem > priv-fullchain-bundle.pem
  echo "New certificate generated; starting nginx"
else
  echo "Certificate exists; parameters unchanged; starting nginx"
fi

# create GeoIP2 folder symlink
[[ -d /var/lib/libmaxminddb ]] && [[ ! -L /var/lib/libmaxminddb ]] && \
  rm -rf /var/lib/libmaxminddb
[[ ! -d /var/lib/libmaxminddb ]] && \
  ln -s /config/geoip2db /var/lib/libmaxminddb
# check GeoIP2 database
if [ -n "$MAXMINDDB_LICENSE_KEY" ]; then
  sed -i "s|.*MAXMINDDB_LICENSE_KEY.*|MAXMINDDB_LICENSE_KEY=\"${MAXMINDDB_LICENSE_KEY}\"|g" /etc/conf.d/libmaxminddb
  if [ ! -f /var/lib/libmaxminddb/GeoLite2-City.mmdb ]; then
    echo "Downloading GeoIP2 City database."
    /etc/periodic/weekly/libmaxminddb
  fi
elif [ -f /var/lib/libmaxminddb/GeoLite2-City.mmdb ]; then
  echo -e "Currently using the user provided GeoLite2-City.mmdb.\nIf you want to enable weekly auto-updates of the database, retrieve a free license key from MaxMind,\nand add a new env variable \"MAXMINDDB_LICENSE_KEY\", set to your license key."
else
  echo -e "Starting 2019/12/30, GeoIP2 databases require personal license key to download. Please retrieve a free license key from MaxMind,\nand add a new env variable \"MAXMINDDB_LICENSE_KEY\", set to your license key."
fi

# logfiles needed by fail2ban
[[ ! -f /config/log/nginx/error.log ]] && \
	touch /config/log/nginx/error.log
[[ ! -f /config/log/nginx/access.log ]] && \
	touch /config/log/nginx/access.log

# permissions
chown -R abc:abc \
	/config
chmod -R 0644 /etc/logrotate.d
chmod -R +r /config/log
chmod +x /app/le-renew.sh
chmod 700 /defaults/dns-conf
chmod 600 /defaults/dns-conf/*
