#!/bin/bash
# certbot wrapper for revoking certs

SPATH="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")"    # dir of the script
SNAME="$(basename ${BASH_SOURCE[0]})"                    # name of the script

ASCEDSCONF='local site certbot'
ASCEDSLIBS='utils'

if [ ! -r "${SPATH}/asceds-certbot-head" ] ; then
   echo "No header ${SPATH}/asceds-certbot-head. Exiting"
   exit 9
fi

. ${SPATH}/asceds-certbot-head

asceds-certbot-revoke-usage()
{
  cat << ENDUSAGE

Usage: asceds-certbot-revoke [-h] [-e] [-q] -c <client_name>
-h --> display usage and exit
-q --> no question asked; sends output to the logs in ${ASCEDSLOGDIR}/
-c <client_name> --> cert for <client_name> will be revoked (one per use)
-e --> execute certbot revoke (just echo the command by default)

Checks if certbot is installed and certificate files exist.
Displays status of the client and of the certificate files.
Checks if cert manager is authorized to revoke requested certificate.
Displays (by default) or executes (if -e or if CERTBOTEXEC is not empty)
the certbot command to revoke the certificate.
If -e or -d or CERTBOTEXEC is not empty:
   Removes any certificate files from ~asceds/<client_name>/
      and /etc/letsencrypt/*/client_name>/*
   If client is unmanaged, removes the cert files from the web dir.
Removes all the files related to the certificate -> asceds-client-remove

ENDUSAGE
exit 0
}

# example of command:
# certbot revoke --non-interactive --delete-after-revoke --agree-tos \
#       --register-unsafely-without-email \
#       --server https://acme.sectigo.com/v2/InCommonRSAOV \
#       --eab-kid ... \
#       --eab-hmac-key ... \
#       --cert-path /etc/letsencrypt/archive/${DOMAIN_NAME}/cert1.pem


# run as root only
asceds-run-asroot

# echo by default if CERTBOTEXEC is not predefined
if [ -n "${CERTBOTEXEC}" ] ; then
   # this states the obvious, just here for the show
   CERTBOTEXEC=''
fi

# output to terminal by default
QUIETRUN=""

# initialize REVOKE_DOMAIN_NAME
REVOKE_DOMAIN_NAME=''

# remove client from asceds and certbot
REMOVE_CLIENT=''

# general validation and parse of the command line
if  [ -z "${ARGS}" ] ; then
   asceds-certbot-revoke-usage
else
   for ARG in ${ARGS} ; do
      #echo "ARG=${ARG}"
      if [ "${ARG}" != "${ARG//[^-_a-zA-Z0-9.]/}" ] ; then
         asceds-error "Malformed argument ${ARG}"
      elif [ "${ARG}" == "-h" ] ; then
         asceds-certbot-revoke-usage
      elif [ "${ARG}" == "-q" ] ; then
         shift
         asceds-exec-noninteractive "$*"
         # bring other scripts in non-interactive mode
         QUIETRUN="y"
      elif [ "${ARG}" == "-e" ] ; then
         shift
         CERTBOTEXEC="eval"
      elif [ "${ARG}" == "-d" ] ; then
         shift
         REMOVE_CLIENT='yes'
      elif [ "${ARG}" == "-c" ] ; then
         shift
         if [[ "$1" != -* ]] && [ -n "$1" ] ; then
            REVOKE_DOMAIN_NAME=$( cat <<< $1 | tr '[:upper:]' '[:lower:]' )
            asceds-expand-hostname "${REVOKE_DOMAIN_NAME}" && \
               REVOKE_DOMAIN_NAME="${ASCEDS_FQDN}"
            asceds-validate-fqdn "${REVOKE_DOMAIN_NAME}" || \
               asceds-error "Invalid client FQDN ${REVOKE_DOMAIN_NAME}"
         fi
      else
         shift
      fi
   done
fi
if [ -z "${REVOKE_DOMAIN_NAME}" ] ; then
   asceds-certbot-revoke-usage
fi

# checks on client name
if [ -z "${REVOKE_DOMAIN_NAME}" ] ; then
   asceds-error "No cert to revoke was passwed as argument"
elif [ ! -d "/etc/letsencrypt/live/${REVOKE_DOMAIN_NAME}" ] ; then
   asceds-error "Domain name ${REVOKE_DOMAIN_NAME} is unknown to letsencrypt"
elif [ ! -e "/etc/letsencrypt/live/${REVOKE_DOMAIN_NAME}/cert.pem" ] ; then
   asceds-error "No letsencrypt certificates exist for ${REVOKE_DOMAIN_NAME}"
else
   asceds-echo "Revoking certificate for ${REVOKE_DOMAIN_NAME}"
fi

# current cert
if [ -r "/etc/letsencrypt/live/${REVOKE_DOMAIN_NAME}/cert.pem" ] ; then
   REVOKE_CERT=$( readlink -f /etc/letsencrypt/live/${REVOKE_DOMAIN_NAME}/cert.pem )
else
   asceds-error "The certificate file for ${REVOKE_DOMAIN_NAME} could not be found."
fi 

# status of the cert
if [ -n "${OPENSSLEXT}" ] ; then
   eval ${OPENSSLEXT} < ${REVOKE_CERT} 
fi
echo "Cert Validity:" 
openssl x509 -dates -noout < ${REVOKE_CERT} | sed -e "s/^/   /"

# client config file checks and info
if [ -f "${ASCEDSHOMEDIR}/${REVOKE_DOMAIN_NAME}_cert.conf" ] ; then
   NO_RETURN=''
   NO_ASCEDS=''
   ASCEDS_CERT_ID=''
   CLIENT_ENC=''
   asceds-parse-certconf "${ASCEDSHOMEDIR}/${REVOKE_DOMAIN_NAME}_cert.conf"
   if [ -n "${NO_ASCEDS}" ] ; then
      echo "Client ${REVOKE_DOMAIN_NAME} is unmanaged, configured by ${NO_ASCEDS}"
      if [ -z "${ASCEDS_CERT_ID}" ] ; then
         asceds-warning "Client ${REVOKE_DOMAIN_NAME} is unmanaged but ASCEDS_CERT_ID is not defined"
      fi
   elif [ -n "${NO_RETURN}" ] ; then
      echo "Client ${REVOKE_DOMAIN_NAME} is managed but marked read-only"
   fi
   if [ "${REVOKE_DOMAIN_NAME}" != "${CLIENT_DOMAIN_NAME}" ] ; then
      asceds-error "Bad CLIENT_DOMAIN_NAME in ${ASCEDSHOMEDIR}/${REVOKE_DOMAIN_NAME}_cert.conf"
   fi
else
   asceds-error "No config file for client ${REVOKE_DOMAIN_NAME}."
fi

# check if certbot was configured and is executable
if [ -z "${CERTBOTBIN}" ] ; then
   asceds-error "No value was configured for certbot"
fi
if [ ! -x "$( readlink -f ${CERTBOTBIN} )" ] ; then
   asceds-error "No executable was found for certbot"
fi

# Checks if cert manager is authorized to revoke requested certificate
asceds-check-domains "${REVOKE_DOMAIN_NAME}" "${CLIENT_SANS_LIST}"

# initial certbot option list
CERTBOTOPTS="revoke ${CERTBOTOPTS}"
if [ -n "${ACMESERVER}" ] ; then
   CERTBOTOPTS="${CERTBOTOPTS} --server ${ACMESERVER}" 
fi
if [ -n "${EABKID}" ] ; then
   CERTBOTOPTS="${CERTBOTOPTS} --eab-kid ${EABKID}"
fi
if [ -n "${EABHMACKEY}" ] ; then
   CERTBOTOPTS="${CERTBOTOPTS} --eab-hmac-key ${EABHMACKEY} "
fi
CERTBOTOPTS="${CERTBOTOPTS} --cert-path ${REVOKE_CERT} "

# set the key type
asceds-set-certbot-key 

echo

if [ -z "${CERTBOTEXEC}" ] ; then
   echo
   echo "Certbot command to run to revoke this certificate:"
   echo "${CERTBOTBIN} ${CERTBOTOPTS}"
   echo
else
   asceds-echo "Revoking certificate ..."
   eval ${CERTBOTBIN} ${CERTBOTOPTS}
   # test if successfully revoked
   if [ -d "/etc/letsencrypt/live/${REVOKE_DOMAIN_NAME}" ] ; then
      asceds-error "Certificate dir /etc/letsencrypt/live/${REVOKE_DOMAIN_NAME} still exists"
   fi
fi

if [ -n "${CERTBOTEXEC}" ] || [ -n "${REMOVE_CLIENT}" ] ; then
   asceds-disable-host "${REVOKE_DOMAIN_NAME}"
   asceds-client-remove -q -c "${REVOKE_DOMAIN_NAME}"
fi

