Subversion Repositories ALCASAR

Rev

Rev 3163 | Rev 3169 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log

#!/bin/bash
#
# $Id: alcasar-letsencrypt.sh 3168 2024-01-17 15:28:46Z rexy $
#
# alcasar-letsencrypt.sh
# by Tom HOUDAYER
#
# This script is distributed under the Gnu General Public License (GPL)
#
# Manage Let's Encrypt for ALCASAR integration

CONF_FILE="/usr/local/etc/alcasar-letsencrypt"

ACCOUNT_EMAIL=""
DOMAIN=""
DNS_API=""

DEBUG=false
STAGING_SERVER=""
FORCE=""
OPT_PARAMS=""

ACMESH_HOME="/usr/local/etc/letsencrypt"
ACMESH_BIN="/opt/acme.sh/acme.sh"

usage="Usage: alcasar-letsencrypt.sh
       --issue -d alcasar.domain.tld --email alcasar@domain.tld [--dns-api dns_registrar] [--force] [--staging]
       --renew [-d alcasar.domain.tld] [--force] [--staging]"


################################################################################
#                                    ISSUE                                     #
################################################################################
issue() {
        if [ ! -f $ACMESH_BIN ]; then
                echo "The client does not seem to be installed."
                return 1
        fi

        TMP_OUTPUT=$(mktemp --suffix=_ALCASAR-LE)

        if [ ! -z $ACCOUNT_EMAIL ]; then
                emailField=" --accountemail $ACCOUNT_EMAIL"
                sed -i "s/^email=.*/email=$ACCOUNT_EMAIL/" $CONF_FILE
        else
                emailField=""
        fi
        rm -rf $ACMESH_HOME/certs/*
        $DEBUG && debugOpt=" --debug" || debugOpt=""
        [ ! -z "$DNS_API" ] && dnsApiOpt="$DNS_API" || dnsApiOpt="--yes-I-know-dns-manual-mode-enough-go-ahead-please"
        $ACMESH_BIN --config-home $ACMESH_HOME/data \
                $STAGING_SERVER $FORCE $debugOpt \
                $emailField \
                --issue --dns $dnsApiOpt -d $DOMAIN \
                $OPT_PARAMS \
                > $TMP_OUTPUT 2>&1
        exitCode=$?

        $DEBUG && cat $TMP_OUTPUT && echo -e "\n\n"

        sed -i "s/^domainRequest=.*/domainRequest=$DOMAIN/" $CONF_FILE
        sed -i "s/^dateIssueRequest=.*/dateIssueRequest=$(date +%s)/" $CONF_FILE
        sed -i "s/^dnsapi=.*/dnsapi=${DNS_API:="dns"}/" $CONF_FILE

        if ! _handle_client_response $TMP_OUTPUT; then
                if [ $exitCode -ne 0 ]; then
                        echo -e "Error!\n"
                        cat $TMP_OUTPUT
                        rm -f $TMP_OUTPUT
                        return 1
                else
                        echo -e "Unknown state\n"
                        cat $TMP_OUTPUT
                fi
        fi

        rm -f $TMP_OUTPUT
}


################################################################################
#                                    RENEW                                     #
################################################################################
renew() {
        if [ ! -f $ACMESH_BIN ]; then
                echo "The client does not seem to be installed."
                return 1
        fi

        TMP_OUTPUT=$(mktemp --suffix=_ALCASAR-LE)

        $DEBUG && debugOpt=" --debug" || debugOpt=""
        [ ! -z "$DNS_API" ] && dnsApiOpt="" || dnsApiOpt="--yes-I-know-dns-manual-mode-enough-go-ahead-please"
        $ACMESH_BIN --config-home $ACMESH_HOME/data \
                $STAGING_SERVER $FORCE $debugOpt \
                --renew -d $DOMAIN $dnsApiOpt \
                $OPT_PARAMS \
                > $TMP_OUTPUT 2>&1
        exitCode=$?

        $DEBUG && cat $TMP_OUTPUT && echo -e "\n\n"

        if ! _handle_client_response $TMP_OUTPUT; then
                if [ $exitCode -ne 0 ]; then
                        echo -e "Error!\n"
                        cat $TMP_OUTPUT
                        rm -f $TMP_OUTPUT
                        return 1
                else
                        echo -e "Unknown state\n"
                        cat $TMP_OUTPUT
                fi
        fi

        rm -f $TMP_OUTPUT
}


################################################################################
#                                  CRON TASK                                   #
################################################################################
cron_task() {
        if [ $(grep '^dateNextRenewal=' $CONF_FILE | cut -d'=' -f2) -le $(date +%s) ]; then
                logger -t alcasar-letsencrypt "Launch CRON task."
                renew
        fi
}


################################################################################
#                            HANDLE CLIENT RESPONSE                            #
################################################################################
_handle_client_response() {
        [ $# -lt 1 ] && return 1
        responseFile=$1

        # issue / renew
        if [ $(cat $responseFile | grep "Add the following TXT record:" -c) -ne 0 ]; then
                challenge=$(cat $responseFile | grep -E "TXT value: '[0-9a-zA-Z_-]+'" -o | cut -d"'" -f2)
                sed -i "s/^challenge=.*/challenge=$challenge/" $CONF_FILE

                echo "Add the following TXT record:"
                echo "Domain:    '_acme-challenge.$DOMAIN'"
                echo "TXT value: '$challenge'"
        elif [ $(cat $responseFile | grep "Cert success." -c) -ne 0 ]; then
                sed -i "s/^challenge=.*/challenge=/" $CONF_FILE
                sed -i "s/^dateIssued=.*/dateIssued=$(date +%s)/" $CONF_FILE
                sed -i "s/^dateNextRenewal=.*/dateNextRenewal=$(date +%s -d '2 months - 3 days')/" $CONF_FILE

                install_cert
                logger -t alcasar-letsencrypt "Certificate \"$DOMAIN\" imported."
                echo "Certificate imported."
                [ -z $DNS_API ] && echo "Note: you can delete the TXT record."
        elif [ $(cat $responseFile | grep "Domains not changed." -c) -ne 0 ]; then
                echo "Domain not changed"
        elif [ $(cat $responseFile | grep "$DOMAIN is already verified, skip dns-01." -c) -ne 0 ]; then
                echo "Domain already verified"
        elif [ $(cat $responseFile | grep "Error add txt for domain:_acme-challenge.$DOMAIN" -c) -ne 0 ]; then
                echo "Error add txt for domain:_acme-challenge.$DOMAIN"
        elif [ $(cat $responseFile | grep "Please add the TXT records to the domains, and retry again." -c) -ne 0 ]; then
                echo "Dns record not added yet, you need to add it manually and retry again."
        elif [ $(cat $responseFile | grep 'new-authz error: {"type":"urn:acme:error:malformed","detail":"Error creating new authz :: \(.*\)","status": 400}' -c) -ne 0 ]; then
                errorMsg=$(cat $responseFile | grep 'new-authz error: {"type":"urn:acme:error:malformed","detail":"Error creating new authz :: \(.*\)","status": 400}' | sed 's/.*new-authz error: {"type":"urn:acme:error:malformed","detail":"Error creating new authz :: \(.*\)","status": 400}.*/\1/')
                echo "Incorrect domain name"
                echo "$errorMsg"
        elif [ $(cat $responseFile | grep "'$DOMAIN' is not a issued domain, skip." -c) -ne 0 ]; then
                echo "'$DOMAIN' is not a issued domain"

        # renew
        elif [ $(cat $responseFile | grep "Skip, Next renewal time is: " -c) -ne 0 ]; then
                nextRenewal=$(cat $responseFile | grep 'Skip, Next renewal time is: ' | sed 's/.*Skip, Next renewal time is: \(.*\)/\1/')
                echo "Skip, Next renewal time is: $nextRenewal"
                echo "Add '--force' to force to renew."
        elif [ $(cat $responseFile | grep "$DOMAIN:Verify error:Correct value not found for DNS challenge" -c) -ne 0 ]; then
                echo "Correct value not found for DNS challenge"
        elif [ $(cat $responseFile | grep "Unable to update challenge :: The challenge is not pending." -c) -ne 0 ]; then
                echo "The challenge is not pending. You need to issue."
        else
                return 2
        fi

        return 0
}


################################################################################
#                             INSTALL CERTIFICATE                              #
################################################################################
install_cert() {
        echo "Importing certificate to ALCASAR..."
        LE_cert_folder="$( echo "$ACMESH_HOME/certs/$DOMAIN"*"")"
        if [ ! -f $LE_cert_folder"/"$DOMAIN.cer ]; then
                echo "Certificate not found."
                return 1
        fi

        /usr/local/bin/alcasar-importcert.sh \
                -i $LE_cert_folder"/"$DOMAIN.cer \
                -k $LE_cert_folder"/"$DOMAIN.key \
                -c $LE_cert_folder/fullchain.cer \
                > /dev/null 2>&1

        if [ $? -ne 0 ]; then
                echo "Error."
                return 1
        fi
}


################################################################################
#                                     MAIN                                     #
################################################################################

if [ $# -eq 0 ]; then
        echo "$usage"
        exit 1
fi

cmd=""

while [ $# -gt 0 ]; do
        case $1 in
                -\? | -h | --help)
                        echo "$usage"
                        exit 0
                        ;;

                --issue)
                        cmd="issue"
                        shift 1
                        ;;
                --renew)
                        cmd="renew"
                        shift 1
                        ;;
                --cron)
                        cmd="cron"
                        shift 1
                        ;;
                --install-cert)
                        cmd="install-cert"
                        shift 1
                        ;;

                --email)
                        ACCOUNT_EMAIL="$2"
                        shift 2
                        ;;
                --domain | -d)
                        DOMAIN="$2"
                        shift 2
                        ;;
                --dns-api)
                        DNS_API="$2"
                        shift 2
                        ;;
                --force)
                        FORCE="--force"
                        shift 1
                        ;;
                --staging)
                        STAGING_SERVER="--staging"
                        shift 1
                        ;;
                --debug)
                        DEBUG=true
                        shift 1
                        ;;

                *)
                        found=false
                        for param in "--dnssleep"; do
                                if [ $1 == $param ]; then
                                        OPT_PARAMS="$OPT_PARAMS $1 $2"
                                        shift 2
                                        found=true
                                        break
                                fi
                        done

                        if ! $found; then
                                echo "Unknown argument: $1"
                                echo "$usage"
                                exit 1
                        fi
                        ;;
        esac
done

if [ -z $DOMAIN ]; then
        if [ $(grep '^domainRequest=' $CONF_FILE | cut -d'=' -f2 | wc --chars) -gt 1 ]; then
                DOMAIN="$(grep '^domainRequest=' $CONF_FILE | cut -d'=' -f2)"
        else
                DOMAIN="$(grep '^HOSTNAME=' /usr/local/etc/alcasar.conf | cut -d'=' -f2).$(grep '^DOMAIN=' /usr/local/etc/alcasar.conf | cut -d'=' -f2)"
        fi
fi

case $cmd in
        issue)
                issue
                ;;
        renew)
                renew
                ;;
        cron)
                cron_task
                ;;
        install-cert)
                install_cert
                ;;

        *) exit 1 ;;
esac