From d263f38c91cacc2503f4854e1939f3313c3a8496 Mon Sep 17 00:00:00 2001 From: upstream Date: Fri, 2 Oct 2026 16:57:43 +0200 Subject: [PATCH] Upstream proxmox-git/proxmox-acme state of the touched files before 363c8a5b3d --- src/proxmox-acme | 999 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 999 insertions(+) create mode 100644 src/proxmox-acme diff --git a/src/proxmox-acme b/src/proxmox-acme new file mode 100644 index 0000000..705f7df --- /dev/null +++ b/src/proxmox-acme @@ -0,0 +1,999 @@ +#!/bin/bash + +VER=1.0 + +PROJECT_NAME="ProxmoxACME" + +USER_AGENT="$PROJECT_NAME/$VER" + +DNS_PLUGIN_PATH="/usr/share/proxmox-acme/dnsapi" +HTTP_HEADER="$(mktemp)" + +DEBUG="0" + +_base64() { + openssl base64 -e | tr -d '\r\n' +} + +_dbase64() { + openssl base64 -d +} + +# Usage: hashalg [outputhex] +# Output Base64-encoded digest +_digest() { + alg="$1" + + if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then + if [ "$2" ]; then + openssl dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' + else + openssl dgst -"$alg" -binary | _base64 + fi + fi +} + +_usage() { + __red "$@" >&2 + printf "\n" >&2 +} + +_upper_case() { + # shellcheck disable=SC2018,SC2019 + tr 'a-z' 'A-Z' +} + +_lower_case() { + # shellcheck disable=SC2018,SC2019 + tr 'A-Z' 'a-z' +} + +_startswith() { + _str="$1" + _sub="$2" + echo "$_str" | grep "^$_sub" >/dev/null 2>&1 +} + +_endswith() { + _str="$1" + _sub="$2" + echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1 +} + +_contains() { + _str="$1" + _sub="$2" + echo "$_str" | grep -- "$_sub" >/dev/null 2>&1 +} + +# str index [sep] +_getfield() { + _str="$1" + _findex="$2" + _sep="$3" + + if [ -z "$_sep" ]; then + _sep="," + fi + + _ffi="$_findex" + while [ "$_ffi" -gt "0" ]; do + _fv="$(echo "$_str" | cut -d "$_sep" -f "$_ffi")" + if [ "$_fv" ]; then + printf -- "%s" "$_fv" + return 0 + fi + _ffi="$(_math "$_ffi" - 1)" + done + + printf -- "%s" "$_str" + +} + +_exists() { + cmd="$1" + if eval type type >/dev/null 2>&1; then + type "$cmd" >/dev/null 2>&1 + else command + command -v "$cmd" >/dev/null 2>&1 + fi + ret="$?" + return $ret +} + +# a + b +_math() { + _m_opts="$@" + printf "%s" "$(($_m_opts))" +} + +_egrep_o() { + if ! egrep -o "$1" 2>/dev/null; then + sed -n 's/.*\('"$1"'\).*/\1/p' + fi +} + +_h2b() { + if _exists xxd; then + if _contains "$(xxd --help 2>&1)" "assumes -c30"; then + if xxd -r -p -c 9999 2>/dev/null; then + return + fi + else + if xxd -r -p 2>/dev/null; then + return + fi + fi + fi + + hex=$(cat) + ic="" + jc="" + _debug2 _URGLY_PRINTF "$_URGLY_PRINTF" + if [ -z "$_URGLY_PRINTF" ]; then + if [ "$_ESCAPE_XARGS" ] && _exists xargs; then + _debug2 "xargs" + echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf + else + for h in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/ \1/g'); do + if [ -z "$h" ]; then + break + fi + printf "\x$h%s" + done + fi + else + for c in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\)/ \1/g'); do + if [ -z "$ic" ]; then + ic=$c + continue + fi + jc=$c + ic="$(_h_char_2_dec "$ic")" + jc="$(_h_char_2_dec "$jc")" + printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s" + ic="" + jc="" + done + fi + +} + +#Usage: keyfile hashalg +#Output: Base64-encoded signature value +_sign() { + keyfile="$1" + alg="$2" + if [ -z "$alg" ]; then + _usage "Usage: _sign keyfile hashalg" + return 1 + fi + + _sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile " + + if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || grep "BEGIN PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then + $_sign_openssl -$alg | _base64 + elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then + if ! _signedECText="$($_sign_openssl -sha$__ECC_KEY_LEN | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then + _err "Sign failed: $_sign_openssl" + _err "Key file: $keyfile" + _err "Key content:$(wc -l <"$keyfile") lines" + return 1 + fi + _debug3 "_signedECText" "$_signedECText" + _ec_r="$(echo "$_signedECText" | _head_n 2 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")" + _ec_s="$(echo "$_signedECText" | _head_n 3 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")" + if [ "$__ECC_KEY_LEN" -eq "256" ]; then + while [ "${#_ec_r}" -lt "64" ]; do + _ec_r="0${_ec_r}" + done + while [ "${#_ec_s}" -lt "64" ]; do + _ec_s="0${_ec_s}" + done + fi + if [ "$__ECC_KEY_LEN" -eq "384" ]; then + while [ "${#_ec_r}" -lt "96" ]; do + _ec_r="0${_ec_r}" + done + while [ "${#_ec_s}" -lt "96" ]; do + _ec_s="0${_ec_s}" + done + fi + if [ "$__ECC_KEY_LEN" -eq "512" ]; then + while [ "${#_ec_r}" -lt "132" ]; do + _ec_r="0${_ec_r}" + done + while [ "${#_ec_s}" -lt "132" ]; do + _ec_s="0${_ec_s}" + done + fi + _debug3 "_ec_r" "$_ec_r" + _debug3 "_ec_s" "$_ec_s" + printf "%s" "$_ec_r$_ec_s" | _h2b | _base64 + else + _err "Unknown key file format." + return 1 + fi + +} + +#dummy function because proxmox-acme does not call inithttp +_resethttp() { + : +} + +_HTTP_MAX_RETRY=8 + +# body url [needbase64] [POST|PUT|DELETE] [ContentType] +_post() { + body="$1" + _post_url="$2" + needbase64="$3" + httpmethod="$4" + _postContentType="$5" + _sleep_retry_sec=1 + _http_retry_times=0 + _hcode=0 + while [ "${_http_retry_times}" -le "$_HTTP_MAX_RETRY" ]; do + [ "$_http_retry_times" = "$_HTTP_MAX_RETRY" ] + _lastHCode="$?" + _debug "Retrying post" + _post_impl "$body" "$_post_url" "$needbase64" "$httpmethod" "$_postContentType" "$_lastHCode" + _hcode="$?" + _debug _hcode "$_hcode" + if [ "$_hcode" = "0" ]; then + break + fi + _http_retry_times=$(_math $_http_retry_times + 1) + _sleep $_sleep_retry_sec + done + return $_hcode +} + +# body url [needbase64] [POST|PUT|DELETE] [ContentType] [displayError] +_post_impl() { + body="$1" + _post_url="$2" + needbase64="$3" + httpmethod="$4" + _postContentType="$5" + displayError="$6" + + if [ -z "$httpmethod" ]; then + httpmethod="POST" + fi + + _CURL="curl -L --silent --dump-header $HTTP_HEADER -g " + if [ "$HTTPS_INSECURE" ]; then + _CURL="$_CURL --insecure " + fi + if [ "$httpmethod" = "HEAD" ]; then + _CURL="$_CURL -I " + fi + if [ "$needbase64" ]; then + if [ "$body" ]; then + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" + fi + else + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)" + fi + fi + else + if [ "$body" ]; then + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" + fi + else + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")" + fi + fi + fi + _ret="$?" + if [ "$_ret" != "0" ]; then + if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then + _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" + fi + fi + printf "%s" "$response" + return $_ret +} + +# url getheader timeout +_get() { + url="$1" + onlyheader="$2" + t="$3" + _sleep_retry_sec=1 + _http_retry_times=0 + _hcode=0 + while [ "${_http_retry_times}" -le "$_HTTP_MAX_RETRY" ]; do + [ "$_http_retry_times" = "$_HTTP_MAX_RETRY" ] + _lastHCode="$?" + _debug "Retrying GET" + _get_impl "$url" "$onlyheader" "$t" "$_lastHCode" + _hcode="$?" + _debug _hcode "$_hcode" + if [ "$_hcode" = "0" ]; then + break + fi + _http_retry_times=$(_math $_http_retry_times + 1) + _sleep $_sleep_retry_sec + done + return $_hcode +} + +# url getheader timeout displayError +_get_impl() { + url="$1" + onlyheader="$2" + t="$3" + displayError="$4" + + _CURL="curl -L --silent --dump-header $HTTP_HEADER -g " + if [ "$HTTPS_INSECURE" ]; then + _CURL="$_CURL --insecure " + fi + if [ "$t" ]; then + _CURL="$_CURL --connect-timeout $t" + fi + if [ "$onlyheader" ]; then + $_CURL -I --user-agent "USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" + else + $_CURL --user-agent "USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" + fi + ret=$? + if [ "$ret" != "0" ]; then + if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then + _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret" + fi + fi + return $ret +} + +#endpoint domain type +_ns_lookup_impl() { + _ns_ep="$1" + _ns_domain="$2" + _ns_type="$3" + _debug2 "_ns_ep" "$_ns_ep" + _debug2 "_ns_domain" "$_ns_domain" + _debug2 "_ns_type" "$_ns_type" + + response="$(_H1="accept: application/dns-json" _get "$_ns_ep?name=$_ns_domain&type=$_ns_type")" + _ret=$? + _debug2 "response" "$response" + if [ "$_ret" != "0" ]; then + return $_ret + fi + _answers="$(echo "$response" | tr '{}' '<>' | _egrep_o '"Answer":\[[^]]*]' | tr '<>' '\n\n')" + _debug2 "_answers" "$_answers" + echo "$_answers" +} + +#domain, type +_ns_lookup_cf() { + _cf_ld="$1" + _cf_ld_type="$2" + _cf_ep="https://cloudflare-dns.com/dns-query" + _ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type" +} + +#domain, type +_ns_purge_cf() { + _cf_d="$1" + _cf_d_type="$2" + _debug "Purging Cloudflare $_cf_d_type record for domain $_cf_d" + _cf_purl="https://cloudflare-dns.com/api/v1/purge?domain=$_cf_d&type=$_cf_d_type" + response="$(_post "" "$_cf_purl")" + _debug2 response "$response" +} + +#checks if cf server is available +_ns_is_available_cf() { + if _get "https://cloudflare-dns.com" "" 10 >/dev/null; then + return 0 + else + return 1 + fi +} + +_ns_is_available_google() { + if _get "https://dns.google" "" 10 >/dev/null; then + return 0 + else + return 1 + fi +} + +#domain, type +_ns_lookup_google() { + _cf_ld="$1" + _cf_ld_type="$2" + _cf_ep="https://dns.google/resolve" + _ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type" +} + +_ns_is_available_ali() { + if _get "https://dns.alidns.com" "" 10 >/dev/null; then + return 0 + else + return 1 + fi +} + +#domain, type +_ns_lookup_ali() { + _cf_ld="$1" + _cf_ld_type="$2" + _cf_ep="https://dns.alidns.com/resolve" + _ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type" +} + +_ns_is_available_dp() { + if _get "https://doh.pub" "" 10 >/dev/null; then + return 0 + else + return 1 + fi +} + +#dnspod +_ns_lookup_dp() { + _cf_ld="$1" + _cf_ld_type="$2" + _cf_ep="https://doh.pub/dns-query" + _ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type" +} + +_ns_select_doh() { + if [ -z "$DOH_USE" ]; then + _debug "Detecting DNS server first." + if _ns_is_available_cf; then + _debug "Using Cloudflare doh server" + export DOH_USE=$DOH_CLOUDFLARE + elif _ns_is_available_google; then + _debug "Using Google DOH server" + export DOH_USE=$DOH_GOOGLE + elif _ns_is_available_ali; then + _debug "Using Aliyun DOH server" + export DOH_USE=$DOH_ALI + elif _ns_is_available_dp; then + _debug "Using DNS POD DOH server" + export DOH_USE=$DOH_DP + else + _err "No DOH" + fi + fi +} + +#domain, type +_ns_lookup() { + _ns_select_doh + if [ "$DOH_USE" = "$DOH_CLOUDFLARE" ] || [ -z "$DOH_USE" ]; then + _ns_lookup_cf "$@" + elif [ "$DOH_USE" = "$DOH_GOOGLE" ]; then + _ns_lookup_google "$@" + elif [ "$DOH_USE" = "$DOH_ALI" ]; then + _ns_lookup_ali "$@" + elif [ "$DOH_USE" = "$DOH_DP" ]; then + _ns_lookup_dp "$@" + else + _err "Unknown DOH provider: DOH_USE=$DOH_USE" + fi + +} + +_head_n() { + head -n "$1" +} + +_tail_n() { + tail -n "$1" +} + +# stdin output hexstr splited by one space +# input:"abc" +# output: " 61 62 63" +_hex_dump() { + od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n" +} + +# stdin stdout +_url_encode() { + _hex_str=$(_hex_dump) + for _hex_code in $_hex_str; do + #upper case + case "${_hex_code}" in + "41") + printf "%s" "A" + ;; + "42") + printf "%s" "B" + ;; + "43") + printf "%s" "C" + ;; + "44") + printf "%s" "D" + ;; + "45") + printf "%s" "E" + ;; + "46") + printf "%s" "F" + ;; + "47") + printf "%s" "G" + ;; + "48") + printf "%s" "H" + ;; + "49") + printf "%s" "I" + ;; + "4a") + printf "%s" "J" + ;; + "4b") + printf "%s" "K" + ;; + "4c") + printf "%s" "L" + ;; + "4d") + printf "%s" "M" + ;; + "4e") + printf "%s" "N" + ;; + "4f") + printf "%s" "O" + ;; + "50") + printf "%s" "P" + ;; + "51") + printf "%s" "Q" + ;; + "52") + printf "%s" "R" + ;; + "53") + printf "%s" "S" + ;; + "54") + printf "%s" "T" + ;; + "55") + printf "%s" "U" + ;; + "56") + printf "%s" "V" + ;; + "57") + printf "%s" "W" + ;; + "58") + printf "%s" "X" + ;; + "59") + printf "%s" "Y" + ;; + "5a") + printf "%s" "Z" + ;; + + #lower case + "61") + printf "%s" "a" + ;; + "62") + printf "%s" "b" + ;; + "63") + printf "%s" "c" + ;; + "64") + printf "%s" "d" + ;; + "65") + printf "%s" "e" + ;; + "66") + printf "%s" "f" + ;; + "67") + printf "%s" "g" + ;; + "68") + printf "%s" "h" + ;; + "69") + printf "%s" "i" + ;; + "6a") + printf "%s" "j" + ;; + "6b") + printf "%s" "k" + ;; + "6c") + printf "%s" "l" + ;; + "6d") + printf "%s" "m" + ;; + "6e") + printf "%s" "n" + ;; + "6f") + printf "%s" "o" + ;; + "70") + printf "%s" "p" + ;; + "71") + printf "%s" "q" + ;; + "72") + printf "%s" "r" + ;; + "73") + printf "%s" "s" + ;; + "74") + printf "%s" "t" + ;; + "75") + printf "%s" "u" + ;; + "76") + printf "%s" "v" + ;; + "77") + printf "%s" "w" + ;; + "78") + printf "%s" "x" + ;; + "79") + printf "%s" "y" + ;; + "7a") + printf "%s" "z" + ;; + + #numbers + "30") + printf "%s" "0" + ;; + "31") + printf "%s" "1" + ;; + "32") + printf "%s" "2" + ;; + "33") + printf "%s" "3" + ;; + "34") + printf "%s" "4" + ;; + "35") + printf "%s" "5" + ;; + "36") + printf "%s" "6" + ;; + "37") + printf "%s" "7" + ;; + "38") + printf "%s" "8" + ;; + "39") + printf "%s" "9" + ;; + "2d") + printf "%s" "-" + ;; + "5f") + printf "%s" "_" + ;; + "2e") + printf "%s" "." + ;; + "7e") + printf "%s" "~" + ;; + + #other hex + *) + printf '%%%s' "$_hex_code" + ;; + esac + done +} + +# Usage: hashalg secret_hex [outputhex] +# Output binary hmac +_hmac() { + alg="$1" + secret_hex="$2" + outputhex="$3" + + if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then + if [ "$outputhex" ]; then + (openssl dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || openssl dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' + else + openssl dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || openssl dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary + fi + fi +} + +# domain +_is_idn() { + _is_idn_d="$1" + _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '*.,-_') + [ "$_idn_temp" ] +} + +# aa.com +_idn() { + __idn_d="$1" + if ! _is_idn "$__idn_d"; then + printf "%s" "$__idn_d" + return 0 + fi + + if _exists idn; then + idn "$__idn_d" | tr -d "\r\n" + else + _err "Please install idn to process IDN names." + fi +} + +_normalizeJson() { + sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n" +} + +# options file +_sed_i() { + sed -i "$1" "$2" +} + +# sleep sec +_sleep() { + sleep "$1" +} + +_stat() { + stat -c '%U:%G' "$1" 2>/dev/null +} + +#keyfile +_isRSA() { + keyfile=$1 + if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || ${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -noout -text | grep "^publicExponent:" >/dev/null 2>&1; then + return 0 + fi + return 1 +} + +#keyfile +_isEcc() { + keyfile=$1 + if grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || ${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" >/dev/null 2>&1; then + return 0 + fi + return 1 +} + +_time() { + date -u "+%s" +} + +_utc_date() { + date -u "+%Y-%m-%d %H:%M:%S" +} + +# stubbed/aliased: +__green() { + printf -- "%b" "$1" +} + +__red() { + printf -- "%b" "$1" +} + +_log() { + return 0 +} + +_info() { + printf -- "%s" "[$(date)] " >&1 + echo "$1" +} + +_err() { + printf -- "%s" "[$(date)] " >&2 + if [ -z "$2" ]; then + __red "$1" >&2 + else + __red "$1='$2'" >&2 + fi + printf "\n" >&2 + return 1 +} + +# key +_readaccountconf() { + echo "${!1}" +} + +# key +_readaccountconf_mutable() { + _readaccountconf "$1" +} + +# key +_readdomainconf() { + echo "${!1}" +} + +# no-ops: +_clearaccountconf() { + return 0 +} + +_clearaccountconf_mutable() { + return 0 +} + +_cleardomainconf() { + return 0 +} + +_debug() { + if [[ $DEBUG -eq 0 ]]; then + return + fi + printf -- "%s" "[$(date)] " >&1 + echo "$1 $2" +} + +_debug2() { + _debug $1 $2 +} + +_debug3() { + _debug $1 $2 +} + +_secure_debug() { + _debug $1 $2 +} + +_secure_debug2() { + _debug $1 $2 +} + +_secure_debug3() { + _debug $1 $2 +} + +_saveaccountconf() { + return 0 +} + +_saveaccountconf_mutable() { + return 0 +} + +_save_conf() { + return 0 +} + +_savedomainconf() { + return 0 +} + +_source_plugin_config() { + return 0 +} + +# this is for de-escaping a JSON-encoded *string*, e.g. from: http:\/\/ to http:// +_json_decode() { + _j_str="$(sed 's#\\/#/#g')" + _debug3 "_json_decode" + _debug3 "_j_str" "$_j_str" + echo "$_j_str" +} + +# Proxmox implementation to inject the DNSAPI variables +_load_plugin_config() { + while IFS= read -r line; do + ADDR=(${line/=/ }) + key="${ADDR[0]}" + value="${ADDR[1]}" + + # acme.sh uses eval insted of export + if [ -n "$key" ]; then + export "$key"="$value" + fi + done +} + +# call setup and teardown direct +# the parameter must be set in the correct order +# $1 DNS Plugin name +# $2 Fully Qualified Domain Name +# $3 value for TXT record +# $4 DNS plugin auth and config parameter separated by "," +# $5 0 is off, and the default all others are on. + +setup() { + dns_plugin="dns_$1" + dns_plugin_path="${DNS_PLUGIN_PATH}/${dns_plugin}.sh" + fqdn="_acme-challenge.$2" + DEBUG=$3 + IFS= read -r txtvalue + plugin_conf_string=$4 + + _load_plugin_config + + if ! . "$dns_plugin_path"; then + _err "Load file $dns_plugin error." + return 1 + fi + + addcommand="${dns_plugin}_add" + if ! _exists "$addcommand"; then + _err "It seems that your api file is not correct, it must have a function named: $addcommand" + return 1 + fi + + if ! $addcommand "$fqdn" "$txtvalue"; then + _err "Error add txt for domain:$fulldomain" + return 1 + fi +} + +teardown() { + dns_plugin="dns_$1" + dns_plugin_path="${DNS_PLUGIN_PATH}/${dns_plugin}.sh" + fqdn="_acme-challenge.$2" + DEBUG=$3 + IFS= read -r txtvalue + + _load_plugin_config + + if ! . "$dns_plugin_path"; then + _err "Load file $dns_plugin error." + return 1 + fi + + rmcommand="${dns_plugin}_rm" + if ! _exists "$rmcommand"; then + _err "It seems that your api file is not correct, it must have a function named: $rmcommand" + return 1 + fi + + if ! $rmcommand "$fqdn" "$txtvalue"; then + _err "Error add txt for domain:$fulldomain" + return 1 + fi +} + +"$@"