#!/bin/sh
# Renew LetsEncrypt SSL certificate using certbot docker image.
#
# Important:
# * SSL_CERTIFICATE from env.local will be updated, backup that file first!
# * SUPPORT_EMAIL from env.local is used as renew email, make sure it's valid!
# * certbot requires your port 80 and 443 be accessible directly on the internet
#
# Useful extra options:
# * more --domain
# * --cert-name  # to avoid automatic /etc/letsencrypt/live/DOMAIN-0001 "safe" naming
# * --staging
# * --dry-run
#
# Port 80 and 443 must be free at the time of invoking this script
# (docker stop proxy)
#
# Renew mode assume initial request has also been performed using this same
# script.  To ensure working renewal, force again the initial request using
# this script.  Rename existing /etc/letsencrypt to something else is a simple
# way to "force requesting again".
#
# Setting environment variable FORCE_CERTBOT_E2E=1 when calling this script
# will perform all needed pre and post actions:
# * docker stop proxy
# * perform the certbot action
# * concat the fullchain.pem and privkey.pem to the proper location
# * docker start proxy
#
# Setting environment variable CERTBOT_RENEW=1 when calling this script
# will perform renew instead of requesting a new cert.  Renew mode will avoid
# hitting the LetsEncrypt server if cert is not within 1 month of expiry,
# avoiding unnecessary load on LetsEncrypt server (be a good netizen).
#
# Setting environment variable CERTBOTWRAPPER_LOGFILE='/path/to/logfile.log'
# will redirect all STDOUT and STDERR to that logfile so this script will be
# completely silent.

if [ ! -z "$CERTBOTWRAPPER_LOGFILE" ]; then
    exec >>$CERTBOTWRAPPER_LOGFILE 2>&1
fi

START_TIME="`date -Isecond`"
echo "==========
certbotwrapper START_TIME=$START_TIME"

set -x

THIS_FILE="`realpath "$0"`"
THIS_DIR="`dirname "$THIS_FILE"`"
SAVED_PWD="`pwd`"

. "$THIS_DIR/../read-configs.include.sh"

# Get PAVICS_FQDN_PUBLIC, PAVICS_FQDN, SUPPORT_EMAIL, SSL_CERTIFICATE.
read_configs

CERT_DOMAIN="$PAVICS_FQDN_PUBLIC"
if [ -z "$CERT_DOMAIN" ]; then
    CERT_DOMAIN="$PAVICS_FQDN"
fi

if [ ! -z "$FORCE_CERTBOT_E2E" ]; then
    cd $THIS_DIR/..
    docker stop proxy
    cd $SAVED_PWD
fi
CERTBOT_OPTS=""
if [ ! -z "$CERTBOT_RENEW" ]; then
    CERTBOT_OPTS="renew"
else
    CERTBOT_OPTS="certonly \
  --non-interactive \
  --agree-tos \
  --no-eff-email \
  --standalone \
  --email $SUPPORT_EMAIL \
  --domain $CERT_DOMAIN \
  --cert-name $CERT_DOMAIN"
fi

docker run --rm --name certbot \
  -v "/etc/letsencrypt:/etc/letsencrypt" \
  -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
  -v "/var/log/letsencrypt:/var/log/letsencrypt" \
  -p 443:443 -p 80:80 \
  certbot/certbot:v1.3.0 \
  $CERTBOT_OPTS \
  "$@"
RC=$?

if [ ! -z "$FORCE_CERTBOT_E2E" ]; then
    TMP_SSL_CERT="/tmp/tmp_certbotwrapper_ssl_cert.pem"
    CERTPATH="/etc/letsencrypt/live/$CERT_DOMAIN"
    cd $THIS_DIR/..
    docker run --rm --name copy_cert \
        -v "/etc/letsencrypt:/etc/letsencrypt" \
        $BASH_IMAGE \
        cat $CERTPATH/fullchain.pem $CERTPATH/privkey.pem > $TMP_SSL_CERT
    if [ -s "$TMP_SSL_CERT" ] && ! diff $SSL_CERTIFICATE $TMP_SSL_CERT && [ $RC -eq 0 ]; then
        # Only modify SSL_CERTIFICATE if there are real changes.
        cp -v $TMP_SSL_CERT $SSL_CERTIFICATE
    fi
    rm -v $TMP_SSL_CERT
    if [ -z "$FORCE_CERTBOT_E2E_NO_START_PROXY" ]; then
        docker start proxy
    fi
    cd $SAVED_PWD
else
    set +x
    echo "
What to do next:

CERTPATH=\"/etc/letsencrypt/live/$CERT_DOMAIN\"
cd $THIS_DIR/..
sudo cat \$CERTPATH/fullchain.pem \$CERTPATH/privkey.pem > $SSL_CERTIFICATE
openssl x509 -noout -text -in $SSL_CERTIFICATE
docker start proxy
"
fi

set +x
echo "
certbotwrapper finished START_TIME=$START_TIME
certbotwrapper finished   END_TIME=`date -Isecond`"

exit $RC
