From af759f2330d5abe369871780eaf95972912c5351 Mon Sep 17 00:00:00 2001 From: gmanic <30374118+gmanic@users.noreply.github.com> Date: Sun, 14 May 2023 20:02:43 +0000 Subject: [PATCH 01/53] Enable additional command line parameters for nsupdate For being able to use e.g. "-v" to use TCP communication with the NSUPDATE_SERVER -> NSUPDATE_OPT has been added. NSUPDATE_OPT will be plainly added to the command line of nsupdate. NSUPDATE_OPT will also be saved to conf respectively read from conf --- dnsapi/dns_nsupdate.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index cd4b7140..569fc6a5 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -10,6 +10,7 @@ dns_nsupdate_add() { NSUPDATE_SERVER_PORT="${NSUPDATE_SERVER_PORT:-$(_readaccountconf_mutable NSUPDATE_SERVER_PORT)}" NSUPDATE_KEY="${NSUPDATE_KEY:-$(_readaccountconf_mutable NSUPDATE_KEY)}" NSUPDATE_ZONE="${NSUPDATE_ZONE:-$(_readaccountconf_mutable NSUPDATE_ZONE)}" + NSUPDATE_OPT="${NSUPDATE_ZONE:-$(_readaccountconf_mutable NSUPDATE_OPT)}" _checkKeyFile || return 1 @@ -18,6 +19,7 @@ dns_nsupdate_add() { _saveaccountconf_mutable NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}" _saveaccountconf_mutable NSUPDATE_KEY "${NSUPDATE_KEY}" _saveaccountconf_mutable NSUPDATE_ZONE "${NSUPDATE_ZONE}" + _saveaccountconf_mutable NSUPDATE_OPT "${NSUPDATE_OPT}" [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 @@ -26,13 +28,13 @@ dns_nsupdate_add() { [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d" [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D" if [ -z "${NSUPDATE_ZONE}" ]; then - nsupdate -k "${NSUPDATE_KEY}" $nsdebug < Date: Sun, 14 May 2023 20:20:22 +0000 Subject: [PATCH 02/53] Correct Typo, add -n test Added a test for non-zero-string, corrected type ZONE instead of OPT --- dnsapi/dns_nsupdate.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 569fc6a5..4161ad5b 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -10,7 +10,7 @@ dns_nsupdate_add() { NSUPDATE_SERVER_PORT="${NSUPDATE_SERVER_PORT:-$(_readaccountconf_mutable NSUPDATE_SERVER_PORT)}" NSUPDATE_KEY="${NSUPDATE_KEY:-$(_readaccountconf_mutable NSUPDATE_KEY)}" NSUPDATE_ZONE="${NSUPDATE_ZONE:-$(_readaccountconf_mutable NSUPDATE_ZONE)}" - NSUPDATE_OPT="${NSUPDATE_ZONE:-$(_readaccountconf_mutable NSUPDATE_OPT)}" + NSUPDATE_OPT="${NSUPDATE_OPT:-$(_readaccountconf_mutable NSUPDATE_OPT)}" _checkKeyFile || return 1 @@ -23,6 +23,7 @@ dns_nsupdate_add() { [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 + [ -n "${NSUPDATE_OPT}" ] || NSUPDATE_OPT="" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d" From f99d6dac084ad43cf559061f1cdf4ff0e0fc4885 Mon Sep 17 00:00:00 2001 From: gmanic <30374118+gmanic@users.noreply.github.com> Date: Sun, 14 May 2023 20:58:48 +0000 Subject: [PATCH 03/53] Push for actions --- dnsapi/dns_nsupdate.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 4161ad5b..77786a8c 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -3,6 +3,7 @@ ######## Public functions ##################### #Usage: dns_nsupdate_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# actions push dns_nsupdate_add() { fulldomain=$1 txtvalue=$2 From 0b0476e196ac38daeaba4a178617221f2d048fe7 Mon Sep 17 00:00:00 2001 From: gmanic <30374118+gmanic@users.noreply.github.com> Date: Sun, 14 May 2023 21:01:51 +0000 Subject: [PATCH 04/53] Update dns_nsupdate.sh --- dnsapi/dns_nsupdate.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 77786a8c..4161ad5b 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -3,7 +3,6 @@ ######## Public functions ##################### #Usage: dns_nsupdate_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -# actions push dns_nsupdate_add() { fulldomain=$1 txtvalue=$2 From f44dec2c8df66323733baad579970190fc7a25fa Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Thu, 25 Apr 2024 18:43:35 +0300 Subject: [PATCH 05/53] add new provider - Alviy.com --- dnsapi/dns_alviy.sh | 182 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 dnsapi/dns_alviy.sh diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh new file mode 100644 index 00000000..4f736a94 --- /dev/null +++ b/dnsapi/dns_alviy.sh @@ -0,0 +1,182 @@ +#!/usr/bin/env sh + +# Alviy domain api +# Get API key and secret from https://cloud.alviy.com/token +# +# Alviy_token="some-secret-key" +# +# Ex.: acme.sh --issue --staging --dns dns_alviy -d "*.s.example.com" -d "s.example.com" + +Alviy_Api="https://cloud.alviy.com/api/v1" + +######## Public functions ##################### + +#Usage: dns_alviy_add _acme-challenge.www.domain.com "content" +dns_alviy_add() { + fulldomain=$1 + txtvalue=$2 + + Alviy_token="${Alviy_token:-$(_readaccountconf_mutable Alviy_token)}" + if [ -z "$Alviy_token" ]; then + Alviy_token="" + _err "Please specify Alviy token." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable Alviy_token "$Alviy_token" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting existing records" + if _alviy_txt_exists $_domain $fulldomain $txtvalue; then + _info "This record already exists, skipping" + return 0 + fi + + _add_data="{\"content\":\"$txtvalue\",\"type\":\"TXT\"}" + _debug2 _add_data "$_add_data" + _info "Adding record" + if _alviy_rest POST "zone/$_domain/domain/$fulldomain/" "$_add_data"; then + _debug "Checking updated records of '${fulldomain}'" + + if ! _alviy_txt_exists $_domain $fulldomain $txtvalue; then + _err "TXT record '${txtvalue}' for '${fulldomain}', value wasn't set!" + return 1 + fi + + else + _err "Add txt record error, value '${txtvalue}' for '${fulldomain}' was not set." + return 1 + fi + + _sleep 10 + _info "Added TXT record '${txtvalue}' for '${fulldomain}'." + return 0 +} + +#fulldomain +dns_alviy_rm() { + fulldomain=$1 + txtvalue=$2 + + Alviy_token="${Alviy_token:-$(_readaccountconf_mutable Alviy_token)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if ! _alviy_txt_exists $_domain $fulldomain $txtvalue; then + _info "The record does not exist, skip" + return 0 + fi + + _add_data="" + uuid=$(echo $response |tr "{" "\n"|grep $txtvalue|tr "," "\n"|grep uuid|cut -d \" -f4) + # delete record + _debug "Delete TXT record for '${fulldomain}'" + if ! _alviy_rest DELETE "zone/$_domain/record/$uuid" "{\"confirm\":1}"; then + _err "Cannot delete empty TXT record for '$fulldomain'" + return 1 + fi + _info "The record '$fulldomain'='$txtvalue' deleted" +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _alviy_rest GET "zone/$h"; then + return 1 + fi + + if _contains "$response" '"code":"NOT_FOUND"'; then + _debug "$h not found" + else + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +_alviy_txt_exists() { + zone=$1 + domain=$2 + content_data=$3 + _debug "Getting existing records" + + if ! _alviy_rest GET "zone/$zone/domain/$domain/TXT/"; then + _info "The record does not exist" + return 1 + fi + + if ! _contains "$response" "$3"; then + _info "The record has other value" + return 1 + fi + # GOOD code return - TRUE function + return 0 +} + +_alviy_rest() { + method=$1 + path="$2" + content_data="$3" + _debug "$path" + + export _H1="Authorization: Bearer $Alviy_token" + export _H2="Content-Type: application/json" + + if [ "$content_data" ] || [ "$method" = "DELETE" ]; then + _debug "data ($method): " "$content_data" + response="$(_post "$content_data" "$Alviy_Api/$path" "" "$method")" + else + response="$(_get "$Alviy_Api/$path")" + fi + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + if [ "$_code" == "401" ]; then + _err "It seems that your api key or secret is not correct." + return 1 + fi + + + if [ "$_code" != "200" ]; then + _err "API call error ($method): $path Response code $_code" + fi + if [ "$?" != "0" ]; then + _err "error on rest call ($method): $path. Response:" + _err "$response" + return 1 + fi + _debug2 response "$response" + return 0 +} + From 78ba205f4d1da2ccda76482c4fb615333e7a91dd Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Thu, 25 Apr 2024 19:37:49 +0300 Subject: [PATCH 06/53] DNS test init --- dnsapi/dns_alviy.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 4f736a94..31d6a9c9 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -1,6 +1,7 @@ #!/usr/bin/env sh # Alviy domain api +# # Get API key and secret from https://cloud.alviy.com/token # # Alviy_token="some-secret-key" From 2fcda9a73ae2f4a6d8dc30e12c61d14cfc8bc7ee Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Thu, 25 Apr 2024 22:07:29 +0300 Subject: [PATCH 07/53] Quotes recomendations --- dnsapi/dns_alviy.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 31d6a9c9..1077ec06 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -37,7 +37,7 @@ dns_alviy_add() { _debug _domain "$_domain" _debug "Getting existing records" - if _alviy_txt_exists $_domain $fulldomain $txtvalue; then + if _alviy_txt_exists "$_domain" "$fulldomain" "$txtvalue"; then _info "This record already exists, skipping" return 0 fi @@ -48,7 +48,7 @@ dns_alviy_add() { if _alviy_rest POST "zone/$_domain/domain/$fulldomain/" "$_add_data"; then _debug "Checking updated records of '${fulldomain}'" - if ! _alviy_txt_exists $_domain $fulldomain $txtvalue; then + if ! _alviy_txt_exists "$_domain" "$fulldomain" "$txtvalue"; then _err "TXT record '${txtvalue}' for '${fulldomain}', value wasn't set!" return 1 fi @@ -79,13 +79,13 @@ dns_alviy_rm() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - if ! _alviy_txt_exists $_domain $fulldomain $txtvalue; then + if ! _alviy_txt_exists "$_domain" "$fulldomain" "$txtvalue"; then _info "The record does not exist, skip" return 0 fi _add_data="" - uuid=$(echo $response |tr "{" "\n"|grep $txtvalue|tr "," "\n"|grep uuid|cut -d \" -f4) + uuid=$(echo "$response" |tr "{" "\n"|grep "$txtvalue"|tr "," "\n"|grep uuid|cut -d \" -f4) # delete record _debug "Delete TXT record for '${fulldomain}'" if ! _alviy_rest DELETE "zone/$_domain/record/$uuid" "{\"confirm\":1}"; then @@ -163,7 +163,7 @@ _alviy_rest() { response="$(_get "$Alviy_Api/$path")" fi _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" - if [ "$_code" == "401" ]; then + if [ "$_code" = "401" ]; then _err "It seems that your api key or secret is not correct." return 1 fi From 2e9f1592252d7d7866de846449b89e1e1ed6da79 Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Thu, 25 Apr 2024 22:15:16 +0300 Subject: [PATCH 08/53] shfmt --- dnsapi/dns_alviy.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 1077ec06..975f20d4 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -85,7 +85,7 @@ dns_alviy_rm() { fi _add_data="" - uuid=$(echo "$response" |tr "{" "\n"|grep "$txtvalue"|tr "," "\n"|grep uuid|cut -d \" -f4) + uuid=$(echo "$response" | tr "{" "\n" | grep "$txtvalue" | tr "," "\n" | grep uuid | cut -d \" -f4) # delete record _debug "Delete TXT record for '${fulldomain}'" if ! _alviy_rest DELETE "zone/$_domain/record/$uuid" "{\"confirm\":1}"; then @@ -168,7 +168,6 @@ _alviy_rest() { return 1 fi - if [ "$_code" != "200" ]; then _err "API call error ($method): $path Response code $_code" fi @@ -180,4 +179,3 @@ _alviy_rest() { _debug2 response "$response" return 0 } - From e1acea52f8de193e68d0b377c8b87cc8ddc03932 Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Thu, 25 Apr 2024 22:27:04 +0300 Subject: [PATCH 09/53] run DNS test --- dnsapi/dns_alviy.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 975f20d4..eab133cb 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -1,7 +1,6 @@ #!/usr/bin/env sh # Alviy domain api -# # Get API key and secret from https://cloud.alviy.com/token # # Alviy_token="some-secret-key" From d1df5f3021d00418c2884895f5697b181b3d82cb Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Thu, 25 Apr 2024 22:36:11 +0300 Subject: [PATCH 10/53] test DNS --- dnsapi/dns_alviy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index eab133cb..3ea9ebd3 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -1,5 +1,5 @@ #!/usr/bin/env sh - +# # Alviy domain api # Get API key and secret from https://cloud.alviy.com/token # From 4a8c2251e0ba445a4cb68858132eece7d801ee54 Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Thu, 25 Apr 2024 22:47:53 +0300 Subject: [PATCH 11/53] 4th+ level domain --- dnsapi/dns_alviy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 3ea9ebd3..fe1048fe 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -104,7 +104,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | rev | cut -d . -f 1-2 | rev ) if [ -z "$h" ]; then #not valid return 1 From c0b87adee55076b4ef23b496e4ee9cc50c40b7ec Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Thu, 25 Apr 2024 22:51:32 +0300 Subject: [PATCH 12/53] shfmt --- dnsapi/dns_alviy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index fe1048fe..8ff2684e 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -104,7 +104,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | rev | cut -d . -f 1-2 | rev ) + h=$(printf "%s" "$domain" | rev | cut -d . -f 1-2 | rev) if [ -z "$h" ]; then #not valid return 1 From 7ef1340e2add05a48189312f1a7f507224087fc7 Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Thu, 25 Apr 2024 23:16:11 +0300 Subject: [PATCH 13/53] Update dns_alviy.sh --- dnsapi/dns_alviy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 8ff2684e..d90513e8 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -110,7 +110,7 @@ _get_root() { return 1 fi - if ! _alviy_rest GET "zone/$h"; then + if ! _alviy_rest GET "zone/$h/"; then return 1 fi From 03b53cbb60c9131d872637016f759b7bb57cfbe2 Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Fri, 26 Apr 2024 20:38:01 +0300 Subject: [PATCH 14/53] run DNS test --- dnsapi/dns_alviy.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index d90513e8..6e75c9ab 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -1,6 +1,7 @@ #!/usr/bin/env sh # # Alviy domain api +# # Get API key and secret from https://cloud.alviy.com/token # # Alviy_token="some-secret-key" From 4bf4259dda037e6c2c117e8e7e7d9618cd36dfb3 Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Fri, 26 Apr 2024 23:05:42 +0300 Subject: [PATCH 15/53] Update _get_root logic --- dnsapi/dns_alviy.sh | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 6e75c9ab..6a99c6da 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -103,28 +103,24 @@ dns_alviy_rm() { _get_root() { domain=$1 i=2 - p=1 - while true; do - h=$(printf "%s" "$domain" | rev | cut -d . -f 1-2 | rev) - if [ -z "$h" ]; then - #not valid - return 1 - fi + h=$(printf "%s" "$domain" | rev | cut -d . -f 1-2 | rev) + if [ -z "$h" ]; then + #not valid + _debug "can't get host from $domain" + return 1 + fi - if ! _alviy_rest GET "zone/$h/"; then - return 1 - fi + if ! _alviy_rest GET "zone/$h/"; then + return 1 + fi - if _contains "$response" '"code":"NOT_FOUND"'; then - _debug "$h not found" - else - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _domain="$h" - return 0 - fi - p="$i" - i=$(_math "$i" + 1) - done + if _contains "$response" '"code":"NOT_FOUND"'; then + _debug "$h not found" + else + _sub_domain=$(printf "%s" "$domain" | rev | cut -d . -f 3- | rev) + _domain="$h" + return 0 + fi return 1 } From 1078fdc157072d88d7658ef92f4ed4b359f904e3 Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Fri, 26 Apr 2024 23:25:38 +0300 Subject: [PATCH 16/53] fix Shellcheck --- dnsapi/dns_alviy.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 6a99c6da..2f8b7994 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -102,16 +102,16 @@ dns_alviy_rm() { # _domain=domain.com _get_root() { domain=$1 - i=2 h=$(printf "%s" "$domain" | rev | cut -d . -f 1-2 | rev) if [ -z "$h" ]; then #not valid - _debug "can't get host from $domain" + hd=$(printf "%s" "$domain" | rev) + _debug "can't get host from $domain $hd" return 1 fi if ! _alviy_rest GET "zone/$h/"; then - return 1 + return 1 fi if _contains "$response" '"code":"NOT_FOUND"'; then From e814cccc4490d1b8c2552258e260e8537e57cbec Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Sat, 27 Apr 2024 00:06:22 +0300 Subject: [PATCH 17/53] Update dns_alviy.sh --- dnsapi/dns_alviy.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 2f8b7994..93b5750f 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -105,8 +105,8 @@ _get_root() { h=$(printf "%s" "$domain" | rev | cut -d . -f 1-2 | rev) if [ -z "$h" ]; then #not valid - hd=$(printf "%s" "$domain" | rev) - _debug "can't get host from $domain $hd" + _alviy_rest GET "zone/$domain/" + _debug "can't get host from $domain" return 1 fi From dbe7cb8dbb5650169f8d21f2efce6a06bd9175c6 Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Sat, 27 Apr 2024 09:55:38 +0300 Subject: [PATCH 18/53] remove rev command --- dnsapi/dns_alviy.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 93b5750f..9501bff1 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -102,7 +102,15 @@ dns_alviy_rm() { # _domain=domain.com _get_root() { domain=$1 - h=$(printf "%s" "$domain" | rev | cut -d . -f 1-2 | rev) + i=3 + a="init" + while [ ! -z $a ] + do + a=$(printf "%s" "$domain" | cut -d . -f $i-) + i=`expr $i + 1` + done + num=`expr $i - 3` + h=$(printf "%s" "$domain" | cut -d . -f $num-) if [ -z "$h" ]; then #not valid _alviy_rest GET "zone/$domain/" @@ -117,7 +125,8 @@ _get_root() { if _contains "$response" '"code":"NOT_FOUND"'; then _debug "$h not found" else - _sub_domain=$(printf "%s" "$domain" | rev | cut -d . -f 3- | rev) + s_n=`expr $num - 1` + _sub_domain=$(printf "%s" "$domain" | cut -d . -f -$s_n) _domain="$h" return 0 fi From dab244ad2536f43727065700de807d65d4ebaeef Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Sat, 27 Apr 2024 11:29:30 +0300 Subject: [PATCH 19/53] shfmt --- dnsapi/dns_alviy.sh | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 9501bff1..d87d1c6e 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -104,13 +104,12 @@ _get_root() { domain=$1 i=3 a="init" - while [ ! -z $a ] - do + while [ ! -z $a ]; do a=$(printf "%s" "$domain" | cut -d . -f $i-) - i=`expr $i + 1` + i=$(($i + 1)) done - num=`expr $i - 3` - h=$(printf "%s" "$domain" | cut -d . -f $num-) + n=$(($i - 3)) + h=$(printf "%s" "$domain" | cut -d . -f $n-) if [ -z "$h" ]; then #not valid _alviy_rest GET "zone/$domain/" @@ -125,8 +124,8 @@ _get_root() { if _contains "$response" '"code":"NOT_FOUND"'; then _debug "$h not found" else - s_n=`expr $num - 1` - _sub_domain=$(printf "%s" "$domain" | cut -d . -f -$s_n) + s=$(($n - 1)) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f -$s) _domain="$h" return 0 fi From 54eec82311c90cca2ce99ff97e5c8132679e1e50 Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Sat, 27 Apr 2024 11:45:14 +0300 Subject: [PATCH 20/53] spellcheck --- dnsapi/dns_alviy.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index d87d1c6e..77c16405 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -104,11 +104,11 @@ _get_root() { domain=$1 i=3 a="init" - while [ ! -z $a ]; do + while [ -n $a ]; do a=$(printf "%s" "$domain" | cut -d . -f $i-) - i=$(($i + 1)) + i=$((i + 1)) done - n=$(($i - 3)) + n=$((i - 3)) h=$(printf "%s" "$domain" | cut -d . -f $n-) if [ -z "$h" ]; then #not valid @@ -124,7 +124,7 @@ _get_root() { if _contains "$response" '"code":"NOT_FOUND"'; then _debug "$h not found" else - s=$(($n - 1)) + s=$((n - 1)) _sub_domain=$(printf "%s" "$domain" | cut -d . -f -$s) _domain="$h" return 0 From d73953af3d5442179874d03f67c460e9cf043280 Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Sat, 27 Apr 2024 12:28:06 +0300 Subject: [PATCH 21/53] spellcheck --- dnsapi/dns_alviy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 77c16405..94832e16 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -104,7 +104,7 @@ _get_root() { domain=$1 i=3 a="init" - while [ -n $a ]; do + while [ -n "$a" ]; do a=$(printf "%s" "$domain" | cut -d . -f $i-) i=$((i + 1)) done From aa41df4e7db492f1243e4828203ceaed67d7da96 Mon Sep 17 00:00:00 2001 From: alviy <96288197+alviy@users.noreply.github.com> Date: Sat, 27 Apr 2024 13:49:37 +0300 Subject: [PATCH 22/53] run test --- dnsapi/dns_alviy.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_alviy.sh b/dnsapi/dns_alviy.sh index 94832e16..2217b0df 100644 --- a/dnsapi/dns_alviy.sh +++ b/dnsapi/dns_alviy.sh @@ -1,5 +1,4 @@ #!/usr/bin/env sh -# # Alviy domain api # # Get API key and secret from https://cloud.alviy.com/token From 89586530a5211a3c8f804c94d45ffefcd0a458b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Weselowski?= Date: Wed, 26 Jun 2024 14:09:44 +0200 Subject: [PATCH 23/53] improve performance and memory usage for dns_anx when fetching all zones the memory usage can exceede limits and also cause timeouts. with this change the zone will be searched via the longest to shortest match using the get endpoint. --- dnsapi/dns_anx.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dnsapi/dns_anx.sh b/dnsapi/dns_anx.sh index c1a1130a..05ac1874 100644 --- a/dnsapi/dns_anx.sh +++ b/dnsapi/dns_anx.sh @@ -127,8 +127,6 @@ _get_root() { i=1 p=1 - _anx_rest GET "zone.json" - while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" @@ -137,6 +135,7 @@ _get_root() { return 1 fi + _anx_rest GET "zone.json/${h}" if _contains "$response" "\"name\":\"$h\""; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain=$h From 3c35eadbc40618278166efaae62a9d6527d14f3b Mon Sep 17 00:00:00 2001 From: PMExtra Date: Thu, 11 Jul 2024 18:29:20 +0800 Subject: [PATCH 24/53] feat(deploy_ali_cdn): support Alibaba Cloud CDN deployment --- deploy/ali_cdn.sh | 157 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 deploy/ali_cdn.sh diff --git a/deploy/ali_cdn.sh b/deploy/ali_cdn.sh new file mode 100644 index 00000000..0f33ab46 --- /dev/null +++ b/deploy/ali_cdn.sh @@ -0,0 +1,157 @@ +#!/usr/bin/env sh + +# Script to create certificate to Alibaba Cloud CDN +# +# This deployment required following variables +# export Ali_Key="ALIACCESSKEY" +# export Ali_Secret="ALISECRETKEY" +# export DEPLOY_ALI_CDN_DOMAIN="cdn.example.com" +# If you have more than one domain, just +# export DEPLOY_ALI_CDN_DOMAIN="cdn1.example.com cdn2.example.com" +# +# The credentials are shared with all domains, also shared with dns_ali api + +Ali_API="https://cdn.aliyuncs.com/" + +ali_cdn_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}" + Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}" + if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then + Ali_Key="" + Ali_Secret="" + _err "You don't specify aliyun api key and secret yet." + return 1 + fi + + #save the api key and secret to the account conf file. + _saveaccountconf_mutable Ali_Key "$Ali_Key" + _saveaccountconf_mutable Ali_Secret "$Ali_Secret" + + _getdeployconf DEPLOY_ALI_CDN_DOMAIN + if [ "$DEPLOY_ALI_CDN_DOMAIN" ]; then + _savedeployconf DEPLOY_ALI_CDN_DOMAIN "$DEPLOY_ALI_CDN_DOMAIN" + else + DEPLOY_ALI_CDN_DOMAIN="$_cdomain" + fi + + # read cert and key files and urlencode both + _cert=$(_url_encode_upper <"$_cfullchain") + _key=$(_url_encode_upper <"$_ckey") + + _debug2 _cert "$_cert" + _debug2 _key "$_key" + + ## update domain ssl config + for domain in $DEPLOY_ALI_CDN_DOMAIN; do + _set_cdn_domain_ssl_certificate_query "$domain" "$_cert" "$_key" + if _ali_rest "Set CDN domain SSL certificate for $domain" "" POST; then + _info "Domain $domain certificate has been deployed successfully" + fi + done + + return 0 +} + +#################### Private functions below ################################## + +# act ign mtd +_ali_rest() { + act="$1" + ign="$2" + mtd="$3" + + signature=$(printf "%s" "$mtd&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64) + signature=$(_ali_urlencode "$signature") + url="$Ali_API?$query&Signature=$signature" + + if [ "$mtd" = "GET" ]; then + response="$(_get "$url")" + else + # post payload is not supported yet because of signature + response="$(_post "" "$url")" + fi + + _ret="$?" + _debug2 response "$response" + if [ "$_ret" != "0" ]; then + _err "Error <$act>" + return 1 + fi + + if [ -z "$ign" ]; then + message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" + if [ "$message" ]; then + _err "$message" + return 1 + fi + fi +} + +_ali_urlencode() { + _str="$1" + _str_len=${#_str} + _u_i=1 + while [ "$_u_i" -le "$_str_len" ]; do + _str_c="$(printf "%s" "$_str" | cut -c "$_u_i")" + case $_str_c in [a-zA-Z0-9.~_-]) + printf "%s" "$_str_c" + ;; + *) + printf "%%%02X" "'$_str_c" + ;; + esac + _u_i="$(_math "$_u_i" + 1)" + done +} + +_ali_nonce() { + #_head_n 1 Date: Thu, 11 Jul 2024 18:41:39 +0800 Subject: [PATCH 25/53] feat(deploy_ali_cdn): improve upper-case --- deploy/ali_cdn.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/ali_cdn.sh b/deploy/ali_cdn.sh index 0f33ab46..6bbb3b43 100644 --- a/deploy/ali_cdn.sh +++ b/deploy/ali_cdn.sh @@ -131,7 +131,7 @@ _url_encode_upper() { encoded=$(_url_encode) for match in $(echo "$encoded" | _egrep_o '%..' | sort -u); do - upper=$(echo "$match" | tr '[:lower:]' '[:upper:]') + upper=$(echo "$match" | _upper_case) encoded=$(echo "$encoded" | sed "s/$match/$upper/g") done From 37f9fd3498ca9d2138502acf51f6d6787c83398b Mon Sep 17 00:00:00 2001 From: WhiteAls Date: Sat, 20 Jul 2024 05:38:51 +0300 Subject: [PATCH 26/53] The old Yandex DNS API was discontinued #4555 --- dnsapi/dns_yandex.sh | 121 ------------------------------------------- 1 file changed, 121 deletions(-) delete mode 100755 dnsapi/dns_yandex.sh diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh deleted file mode 100755 index d780459f..00000000 --- a/dnsapi/dns_yandex.sh +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env sh -# shellcheck disable=SC2034 -dns_yandex_info='Yandex Domains -Site: tech.Yandex.com/domain/ -Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_yandex -Options: - PDD_Token API Token -Issues: github.com/non7top/acme.sh/issues -Author: -' - -######## Public functions ##################### - -#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_yandex_add() { - fulldomain="${1}" - txtvalue="${2}" - _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" - - _PDD_credentials || return 1 - - _PDD_get_domain || return 1 - _debug "Found suitable domain: $domain" - - _PDD_get_record_ids || return 1 - _debug "Record_ids: $record_ids" - - if [ -n "$record_ids" ]; then - _info "All existing $subdomain records from $domain will be removed at the very end." - fi - - data="domain=${domain}&type=TXT&subdomain=${subdomain}&ttl=300&content=${txtvalue}" - uri="https://pddimp.yandex.ru/api2/admin/dns/add" - result="$(_post "${data}" "${uri}" | _normalizeJson)" - _debug "Result: $result" - - if ! _contains "$result" '"success":"ok"'; then - if _contains "$result" '"success":"error"' && _contains "$result" '"error":"record_exists"'; then - _info "Record already exists." - else - _err "Can't add $subdomain to $domain." - return 1 - fi - fi -} - -#Usage: dns_myapi_rm _acme-challenge.www.domain.com -dns_yandex_rm() { - fulldomain="${1}" - _debug "Calling: dns_yandex_rm() '${fulldomain}'" - - _PDD_credentials || return 1 - - _PDD_get_domain "$fulldomain" || return 1 - _debug "Found suitable domain: $domain" - - _PDD_get_record_ids "${domain}" "${subdomain}" || return 1 - _debug "Record_ids: $record_ids" - - for record_id in $record_ids; do - data="domain=${domain}&record_id=${record_id}" - uri="https://pddimp.yandex.ru/api2/admin/dns/del" - result="$(_post "${data}" "${uri}" | _normalizeJson)" - _debug "Result: $result" - - if ! _contains "$result" '"success":"ok"'; then - _info "Can't remove $subdomain from $domain." - fi - done -} - -#################### Private functions below ################################## - -_PDD_get_domain() { - subdomain_start=1 - while true; do - domain_start=$(_math $subdomain_start + 1) - domain=$(echo "$fulldomain" | cut -d . -f "$domain_start"-) - subdomain=$(echo "$fulldomain" | cut -d . -f -"$subdomain_start") - - _debug "Checking domain $domain" - if [ -z "$domain" ]; then - return 1 - fi - - uri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=$domain" - result="$(_get "${uri}" | _normalizeJson)" - _debug "Result: $result" - - if _contains "$result" '"success":"ok"'; then - return 0 - fi - subdomain_start=$(_math $subdomain_start + 1) - done -} - -_PDD_credentials() { - if [ -z "${PDD_Token}" ]; then - PDD_Token="" - _err "You need to export PDD_Token=xxxxxxxxxxxxxxxxx." - _err "You can get it at https://pddimp.yandex.ru/api2/admin/get_token." - return 1 - else - _saveaccountconf PDD_Token "${PDD_Token}" - fi - export _H1="PddToken: $PDD_Token" -} - -_PDD_get_record_ids() { - _debug "Check existing records for $subdomain" - - uri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${domain}" - result="$(_get "${uri}" | _normalizeJson)" - _debug "Result: $result" - - if ! _contains "$result" '"success":"ok"'; then - return 1 - fi - - record_ids=$(echo "$result" | _egrep_o "{[^{]*\"subdomain\":\"${subdomain}\"[^}]*}" | sed -n -e 's#.*"record_id": \([0-9]*\).*#\1#p') -} From f84577bcda887f87c2db944fb54e544a9f0edbda Mon Sep 17 00:00:00 2001 From: WhiteAls Date: Sat, 20 Jul 2024 05:41:54 +0300 Subject: [PATCH 27/53] Support for the Yandex 360 for Business DNS API --- dnsapi/dns_yandex360.sh | 334 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 dnsapi/dns_yandex360.sh diff --git a/dnsapi/dns_yandex360.sh b/dnsapi/dns_yandex360.sh new file mode 100644 index 00000000..3e879c52 --- /dev/null +++ b/dnsapi/dns_yandex360.sh @@ -0,0 +1,334 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_yandex360_info='Yandex 360 for Business DNS API. +Yandex 360 for Business is a digital environment for effective collaboration. +Site: https://360.yandex.com/ +Docs: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_yandex360 +Options: + YANDEX360_CLIENT_ID OAuth 2.0 ClientID + YANDEX360_CLIENT_SECRET OAuth 2.0 Client secret + YANDEX360_ORG_ID Organization ID +OptionsAlt: + YANDEX360_ACCESS_TOKEN OAuth 2.0 Access token. Optional. +Issues: https://github.com/acmesh-official/acme.sh/issues/5213 +Author: +' + +YANDEX360_API_BASE='https://api360.yandex.net/directory/v1/org' +YANDEX360_OAUTH_BASE='https://oauth.yandex.ru' + +######## Public functions ##################### + +dns_yandex360_add() { + fulldomain=$1 + txtvalue=$2 + _info 'Using Yandex 360 DNS API' + + if ! _check_yandex360_variables; then + return 1 + fi + + if ! _get_root "$fulldomain"; then + return 1 + fi + + sub_domain=$(echo "$fulldomain" | sed "s/\.$root_domain$//") + + _debug 'Adding Yandex 360 DNS record for subdomain' "$sub_domain" + dns_api_url="${YANDEX360_API_BASE}/${YANDEX360_ORG_ID}/domains/${root_domain}/dns" + data='{"name":"'"$sub_domain"'","type":"TXT","ttl":60,"text":"'"$txtvalue"'"}' + + response="$(_post "$data" "$dns_api_url" '' 'POST' 'application/json')" + response="$(echo "$response" | _normalizeJson)" + _debug 'Response' "$response" + + if _contains "$response" 'recordId'; then + return 0 + else + return 1 + fi +} + +dns_yandex360_rm() { + fulldomain=$1 + txtvalue=$2 + _info 'Using Yandex 360 DNS API' + + if ! _check_yandex360_variables; then + return 1 + fi + + if ! _get_root "$fulldomain"; then + return 1 + fi + + _debug 'Retrieving 100 records from Yandex 360 DNS' + dns_api_url="${YANDEX360_API_BASE}/${YANDEX360_ORG_ID}/domains/${root_domain}/dns?perPage=100" + response="$(_get "$dns_api_url" '' '')" + response="$(echo "$response" | _normalizeJson)" + _debug 'Response' "$response" + + if ! _contains "$response" "$txtvalue"; then + _info 'DNS record not found. Nothing to remove.' + return 1 + fi + + record_id=$( + echo "$response" | + sed -En 's/.*"recordId":([0-9]+).*"text":"'"${txtvalue}"'".*$/\1/p' + ) + + if [ -z "$record_id" ]; then + _err 'Unable to get record ID to remove' + return 1 + fi + + _debug 'Removing DNS record' "$record_id" + delete_url="${YANDEX360_API_BASE}/${YANDEX360_ORG_ID}/domains/${root_domain}/dns/${record_id}" + + response="$(_post '' "$delete_url" '' 'DELETE')" + response="$(echo "$response" | _normalizeJson)" + _debug 'Response' "$response" + + if _contains "$response" '{}'; then + return 0 + else + return 1 + fi +} + +#################### Private functions below ################################## + +_check_yandex360_variables() { + YANDEX360_CLIENT_ID="${YANDEX360_CLIENT_ID:-$(_readaccountconf_mutable YANDEX360_CLIENT_ID)}" + YANDEX360_CLIENT_SECRET="${YANDEX360_CLIENT_SECRET:-$(_readaccountconf_mutable YANDEX360_CLIENT_SECRET)}" + YANDEX360_ORG_ID="${YANDEX360_ORG_ID:-$(_readaccountconf_mutable YANDEX360_ORG_ID)}" + YANDEX360_ACCESS_TOKEN="${YANDEX360_ACCESS_TOKEN:-$(_readaccountconf_mutable YANDEX360_ACCESS_TOKEN)}" + YANDEX360_REFRESH_TOKEN="${YANDEX360_REFRESH_TOKEN:-$(_readaccountconf_mutable YANDEX360_REFRESH_TOKEN)}" + + if [ -z "$YANDEX360_ORG_ID" ]; then + _err '=========================================' + _err ' ERROR' + _err '=========================================' + _err "A required environment variable YANDEX360_ORG_ID is not set" + _err 'For more details, please visit: https://wiki.acme.sh/dnsapi#30-use-pddyandexru-api' + _err '=========================================' + return 1 + fi + + _saveaccountconf_mutable YANDEX360_ORG_ID "$YANDEX360_ORG_ID" + + if [ -n "$YANDEX360_ACCESS_TOKEN" ]; then + _info '=========================================' + _info ' ATTENTION' + _info '=========================================' + _info 'A manually provided Yandex 360 access token has been detected, which is not recommended.' + _info 'Please note that this token is valid for a limited time after issuance.' + _info 'It is recommended to obtain the token interactively using acme.sh for one-time setup.' + _info 'Subsequent token renewals will be handled automatically.' + _info 'For more details, please visit: https://wiki.acme.sh/dnsapi#30-use-pddyandexru-api' + _info '=========================================' + + _saveaccountconf_mutable YANDEX360_ACCESS_TOKEN "$YANDEX360_ACCESS_TOKEN" + export _H1="Authorization: OAuth $YANDEX360_ACCESS_TOKEN" + return 0 + fi + + if [ -z "$YANDEX360_CLIENT_ID" ] || [ -z "$YANDEX360_CLIENT_SECRET" ]; then + _err '=========================================' + _err ' ERROR' + _err '=========================================' + _err 'The preferred environment variables YANDEX360_CLIENT_ID, YANDEX360_CLIENT_SECRET, and YANDEX360_ORG_ID, or alternatively YANDEX360_ACCESS_TOKEN, is not set.' + _err 'It is recommended to export the first three variables over the latter before running acme.sh.' + _err 'For more details, please visit: https://wiki.acme.sh/dnsapi#30-use-pddyandexru-api' + _err '=========================================' + return 1 + fi + + _saveaccountconf_mutable YANDEX360_CLIENT_ID "$YANDEX360_CLIENT_ID" + _saveaccountconf_mutable YANDEX360_CLIENT_SECRET "$YANDEX360_CLIENT_SECRET" + + if [ -n "$YANDEX360_REFRESH_TOKEN" ]; then + _debug 'Refresh token found. Attempting to refresh access token.' + if _refresh_token; then + return 0 + fi + fi + + if ! _get_token; then + return 1 + fi + + return 0 +} + +_get_token() { + _info "$(_red '=========================================')" + _info "$(_red ' NOTICE')" + _info "$(_red '=========================================')" + _info "$(_red 'Before using the Yandex 360 API, you need to complete an authorization procedure.')" + _info "$(_red 'The initial access token is obtained interactively and is a one-time operation.')" + _info "$(_red 'Subsequent API requests will be handled automatically.')" + _info "$(_red '=========================================')" + + _info 'Initiating device authorization flow' + device_code_url="${YANDEX360_OAUTH_BASE}/device/code" + + hostname=$(uname -n) + data="client_id=$YANDEX360_CLIENT_ID&device_id=acme.sh ${hostname}&device_name=acme.sh ${hostname}" + + response="$(_post "$data" "$device_code_url" '' 'POST')" + response="$(echo "$response" | _normalizeJson)" + _debug 'Response' "$response" + + if ! _contains "$response" 'device_code'; then + _err 'Failed to get device code' + return 1 + fi + + device_code=$( + echo "$response" | + _egrep_o '"device_code":"[^"]*"' | + cut -d: -f2 | + tr -d '"' + ) + _debug 'Device code' "$device_code" + + user_code=$( + echo "$response" | + _egrep_o '"user_code":"[^"]*"' | + cut -d: -f2 | + tr -d '"' + ) + _debug 'User code' "$user_code" + + verification_url=$( + echo "$response" | + _egrep_o '"verification_url":"[^"]*"' | + cut -d: -f2- | + tr -d '"' + ) + _debug 'Verification URL' "$verification_url" + + interval=$( + echo "$response" | + _egrep_o '"interval":[[:space:]]*[0-9]+' | + cut -d: -f2 + ) + _debug 'Polling interval' "$interval" + + _info "$(__red 'Please visit '"$verification_url"' and log in as an organization administrator')" + _info "$(__red 'Once logged in, enter the code: '"$user_code"' on the page from the previous step')" + _info "$(__red 'Waiting for authorization...')" + + _debug 'Polling for token' + token_url="${YANDEX360_OAUTH_BASE}/token" + + while true; do + data="grant_type=device_code&code=$device_code&client_id=$YANDEX360_CLIENT_ID&client_secret=$YANDEX360_CLIENT_SECRET" + + response="$(_post "$data" "$token_url" '' 'POST')" + response="$(echo "$response" | _normalizeJson)" + + if _contains "$response" 'access_token'; then + YANDEX360_ACCESS_TOKEN=$( + echo "$response" | + _egrep_o '"access_token":"[^"]*"' | + cut -d: -f2- | + tr -d '"' + ) + YANDEX360_REFRESH_TOKEN=$( + echo "$response" | + _egrep_o '"refresh_token":"[^"]*"' | + cut -d: -f2- | + tr -d '"' + ) + + _secure_debug 'Response' "$response" + _secure_debug 'Received access token' "$YANDEX360_ACCESS_TOKEN" + _secure_debug 'Received refresh token' "$YANDEX360_REFRESH_TOKEN" + + _saveaccountconf_mutable YANDEX360_REFRESH_TOKEN "$YANDEX360_REFRESH_TOKEN" + + export _H1="Authorization: OAuth $YANDEX360_ACCESS_TOKEN" + + _info 'Access token obtained successfully' + return 0 + elif _contains "$response" 'authorization_pending'; then + _debug 'Response' "$response" + _debug "Authorization pending. Waiting $interval seconds before next attempt." + _sleep "$interval" + else + _debug 'Response' "$response" + _err 'Failed to get access token' + return 1 + fi + done +} + +_refresh_token() { + token_url="${YANDEX360_OAUTH_BASE}/token" + + data="grant_type=refresh_token&refresh_token=$YANDEX360_REFRESH_TOKEN&client_id=$YANDEX360_CLIENT_ID&client_secret=$YANDEX360_CLIENT_SECRET" + + response="$(_post "$data" "$token_url" '' 'POST')" + response="$(echo "$response" | _normalizeJson)" + + if _contains "$response" 'access_token'; then + YANDEX360_ACCESS_TOKEN=$( + echo "$response" | + _egrep_o '"access_token":"[^"]*"' | + cut -d: -f2 | + tr -d '"' + ) + YANDEX360_REFRESH_TOKEN=$( + echo "$response" | + _egrep_o '"refresh_token":"[^"]*"' | + cut -d: -f2- | + tr -d '"' + ) + + _secure_debug 'Response' "$response" + _secure_debug 'Received access token' "$YANDEX360_ACCESS_TOKEN" + _secure_debug 'Received refresh token' "$YANDEX360_REFRESH_TOKEN" + + _saveaccountconf_mutable YANDEX360_REFRESH_TOKEN "$YANDEX360_REFRESH_TOKEN" + + export _H1="Authorization: OAuth $YANDEX360_ACCESS_TOKEN" + + _info 'Access token refreshed successfully' + return 0 + else + _debug 'Response' "$response" + _info 'Failed to refresh token. Will attempt to obtain a new one.' + return 1 + fi +} + +_get_root() { + domain="$1" + i=1 + while true; do + h=$(echo "$domain" | cut -d . -f "$i"-) + _debug "Checking domain: $h" + + if [ -z "$h" ]; then + _err "Could not determine root domain" + return 1 + fi + + dns_api_url="${YANDEX360_API_BASE}/${YANDEX360_ORG_ID}/domains/${h}/dns" + + response="$(_get "$dns_api_url" '' '')" + response="$(echo "$response" | _normalizeJson)" + _debug 'Response' "$response" + + if _contains "$response" '"total":'; then + root_domain="$h" + _debug 'Root domain found' "$root_domain" + return 0 + fi + + i=$(_math "$i" + 1) + done +} From 7ca861805dc78a1167b520cb8562d3d76b7e7c3b Mon Sep 17 00:00:00 2001 From: WhiteAls Date: Sat, 20 Jul 2024 19:03:38 +0300 Subject: [PATCH 28/53] Fixed incorrect links in informational messages --- dnsapi/dns_yandex360.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_yandex360.sh b/dnsapi/dns_yandex360.sh index 3e879c52..91eff6d2 100644 --- a/dnsapi/dns_yandex360.sh +++ b/dnsapi/dns_yandex360.sh @@ -111,7 +111,7 @@ _check_yandex360_variables() { _err ' ERROR' _err '=========================================' _err "A required environment variable YANDEX360_ORG_ID is not set" - _err 'For more details, please visit: https://wiki.acme.sh/dnsapi#30-use-pddyandexru-api' + _err 'For more details, please visit: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_yandex360' _err '=========================================' return 1 fi @@ -126,7 +126,7 @@ _check_yandex360_variables() { _info 'Please note that this token is valid for a limited time after issuance.' _info 'It is recommended to obtain the token interactively using acme.sh for one-time setup.' _info 'Subsequent token renewals will be handled automatically.' - _info 'For more details, please visit: https://wiki.acme.sh/dnsapi#30-use-pddyandexru-api' + _info 'For more details, please visit: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_yandex360' _info '=========================================' _saveaccountconf_mutable YANDEX360_ACCESS_TOKEN "$YANDEX360_ACCESS_TOKEN" @@ -140,7 +140,7 @@ _check_yandex360_variables() { _err '=========================================' _err 'The preferred environment variables YANDEX360_CLIENT_ID, YANDEX360_CLIENT_SECRET, and YANDEX360_ORG_ID, or alternatively YANDEX360_ACCESS_TOKEN, is not set.' _err 'It is recommended to export the first three variables over the latter before running acme.sh.' - _err 'For more details, please visit: https://wiki.acme.sh/dnsapi#30-use-pddyandexru-api' + _err 'For more details, please visit: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_yandex360' _err '=========================================' return 1 fi From 7aaa9583fa4a2055702edfe2bc61d0689e139cdc Mon Sep 17 00:00:00 2001 From: Joris van den Dries Date: Wed, 24 Jul 2024 12:05:57 +0200 Subject: [PATCH 29/53] Update teams notify script to support new notification setup using workflows instead of connectors being fased out. Color support has been dropped since this has no support inside adaptive-card --- notify/teams.sh | 69 +++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 37 deletions(-) mode change 100644 => 100755 notify/teams.sh diff --git a/notify/teams.sh b/notify/teams.sh old mode 100644 new mode 100755 index 1bc5ed08..aa4d2a4e --- a/notify/teams.sh +++ b/notify/teams.sh @@ -3,10 +3,6 @@ #Support Microsoft Teams webhooks #TEAMS_WEBHOOK_URL="" -#TEAMS_THEME_COLOR="" -#TEAMS_SUCCESS_COLOR="" -#TEAMS_ERROR_COLOR="" -#TEAMS_SKIP_COLOR="" teams_send() { _subject="$1" @@ -14,9 +10,9 @@ teams_send() { _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped _debug "_statusCode" "$_statusCode" - _color_success="2cbe4e" # green - _color_danger="cb2431" # red - _color_muted="586069" # gray + _color_success="Good" # green + _color_danger="Attention" # red + _color_muted="Accent" # gray TEAMS_WEBHOOK_URL="${TEAMS_WEBHOOK_URL:-$(_readaccountconf_mutable TEAMS_WEBHOOK_URL)}" if [ -z "$TEAMS_WEBHOOK_URL" ]; then @@ -26,26 +22,6 @@ teams_send() { fi _saveaccountconf_mutable TEAMS_WEBHOOK_URL "$TEAMS_WEBHOOK_URL" - TEAMS_THEME_COLOR="${TEAMS_THEME_COLOR:-$(_readaccountconf_mutable TEAMS_THEME_COLOR)}" - if [ -n "$TEAMS_THEME_COLOR" ]; then - _saveaccountconf_mutable TEAMS_THEME_COLOR "$TEAMS_THEME_COLOR" - fi - - TEAMS_SUCCESS_COLOR="${TEAMS_SUCCESS_COLOR:-$(_readaccountconf_mutable TEAMS_SUCCESS_COLOR)}" - if [ -n "$TEAMS_SUCCESS_COLOR" ]; then - _saveaccountconf_mutable TEAMS_SUCCESS_COLOR "$TEAMS_SUCCESS_COLOR" - fi - - TEAMS_ERROR_COLOR="${TEAMS_ERROR_COLOR:-$(_readaccountconf_mutable TEAMS_ERROR_COLOR)}" - if [ -n "$TEAMS_ERROR_COLOR" ]; then - _saveaccountconf_mutable TEAMS_ERROR_COLOR "$TEAMS_ERROR_COLOR" - fi - - TEAMS_SKIP_COLOR="${TEAMS_SKIP_COLOR:-$(_readaccountconf_mutable TEAMS_SKIP_COLOR)}" - if [ -n "$TEAMS_SKIP_COLOR" ]; then - _saveaccountconf_mutable TEAMS_SKIP_COLOR "$TEAMS_SKIP_COLOR" - fi - export _H1="Content-Type: application/json" _subject=$(echo "$_subject" | _json_encode) @@ -63,16 +39,35 @@ teams_send() { ;; esac - _color=$(echo "$_color" | tr -cd 'a-fA-F0-9') - if [ -z "$_color" ]; then - _color=$(echo "${TEAMS_THEME_COLOR:-$_color_muted}" | tr -cd 'a-fA-F0-9') - fi - - _data="{\"title\": \"$_subject\"," - if [ -n "$_color" ]; then - _data="$_data\"themeColor\": \"$_color\", " - fi - _data="$_data\"text\": \"$_content\"}" + _data="{ + \"type\": \"message\", + \"attachments\": [ + { + \"contentType\": \"application/vnd.microsoft.card.adaptive\", + \"contentUrl\": null, + \"content\": { + \"$schema\": \"http://adaptivecards.io/schemas/adaptive-card.json\", + \"type\": \"AdaptiveCard\", + \"version\": \"1.2\", + \"body\": [ + { + \"type\": \"TextBlock\", + \"size\": \"large\", + \"weight\": \"bolder\", + \"wrap\": true, + \"color\": \"$_color\", + \"text\": \"$_subject\" + }, + { + \"type\": \"TextBlock\", + \"text\": \"$_content\", + \"wrap\": true + } + ] + } + } + ] +}" if response=$(_post "$_data" "$TEAMS_WEBHOOK_URL"); then if ! _contains "$response" error; then From 4cd187181673b1e9a94fe30f0eecabd239d03c55 Mon Sep 17 00:00:00 2001 From: Joris van den Dries Date: Wed, 24 Jul 2024 12:23:17 +0200 Subject: [PATCH 30/53] Removed obsolete documentation --- notify/teams.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/notify/teams.sh b/notify/teams.sh index aa4d2a4e..f1b11d5b 100755 --- a/notify/teams.sh +++ b/notify/teams.sh @@ -10,9 +10,9 @@ teams_send() { _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped _debug "_statusCode" "$_statusCode" - _color_success="Good" # green - _color_danger="Attention" # red - _color_muted="Accent" # gray + _color_success="Good" + _color_danger="Attention" + _color_muted="Accent" TEAMS_WEBHOOK_URL="${TEAMS_WEBHOOK_URL:-$(_readaccountconf_mutable TEAMS_WEBHOOK_URL)}" if [ -z "$TEAMS_WEBHOOK_URL" ]; then From 3cefcd8204167910ad05db860e428de4e5e34120 Mon Sep 17 00:00:00 2001 From: Joris van den Dries Date: Wed, 24 Jul 2024 15:02:48 +0200 Subject: [PATCH 31/53] change reference to static value --- notify/teams.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notify/teams.sh b/notify/teams.sh index f1b11d5b..5e8fe6c0 100755 --- a/notify/teams.sh +++ b/notify/teams.sh @@ -46,7 +46,7 @@ teams_send() { \"contentType\": \"application/vnd.microsoft.card.adaptive\", \"contentUrl\": null, \"content\": { - \"$schema\": \"http://adaptivecards.io/schemas/adaptive-card.json\", + \"schema\": \"http://adaptivecards.io/schemas/adaptive-card.json\", \"type\": \"AdaptiveCard\", \"version\": \"1.2\", \"body\": [ From bcb7e5f2c88e18eb4d7b7373fd05286e86994a76 Mon Sep 17 00:00:00 2001 From: gmanic <30374118+gmanic@users.noreply.github.com> Date: Wed, 24 Jul 2024 20:28:39 +0000 Subject: [PATCH 32/53] Update dns_nsupdate.sh Corrected required variable double quote --- dnsapi/dns_nsupdate.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 4161ad5b..7c68f343 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -29,13 +29,13 @@ dns_nsupdate_add() { [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d" [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D" if [ -z "${NSUPDATE_ZONE}" ]; then - nsupdate -k "${NSUPDATE_KEY}" $nsdebug ${NSUPDATE_OPT} < Date: Thu, 1 Aug 2024 02:18:48 +0000 Subject: [PATCH 33/53] Optimizing debug output --- dnsapi/dns_yandex360.sh | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_yandex360.sh b/dnsapi/dns_yandex360.sh index 91eff6d2..e5f48bff 100644 --- a/dnsapi/dns_yandex360.sh +++ b/dnsapi/dns_yandex360.sh @@ -40,11 +40,11 @@ dns_yandex360_add() { response="$(_post "$data" "$dns_api_url" '' 'POST' 'application/json')" response="$(echo "$response" | _normalizeJson)" - _debug 'Response' "$response" if _contains "$response" 'recordId'; then return 0 else + _debug 'Response' "$response" return 1 fi } @@ -66,10 +66,10 @@ dns_yandex360_rm() { dns_api_url="${YANDEX360_API_BASE}/${YANDEX360_ORG_ID}/domains/${root_domain}/dns?perPage=100" response="$(_get "$dns_api_url" '' '')" response="$(echo "$response" | _normalizeJson)" - _debug 'Response' "$response" if ! _contains "$response" "$txtvalue"; then _info 'DNS record not found. Nothing to remove.' + _debug 'Response' "$response" return 1 fi @@ -88,11 +88,11 @@ dns_yandex360_rm() { response="$(_post '' "$delete_url" '' 'DELETE')" response="$(echo "$response" | _normalizeJson)" - _debug 'Response' "$response" if _contains "$response" '{}'; then return 0 else + _debug 'Response' "$response" return 1 fi } @@ -179,10 +179,10 @@ _get_token() { response="$(_post "$data" "$device_code_url" '' 'POST')" response="$(echo "$response" | _normalizeJson)" - _debug 'Response' "$response" if ! _contains "$response" 'device_code'; then _err 'Failed to get device code' + _debug 'Response' "$response" return 1 fi @@ -244,9 +244,8 @@ _get_token() { tr -d '"' ) - _secure_debug 'Response' "$response" - _secure_debug 'Received access token' "$YANDEX360_ACCESS_TOKEN" - _secure_debug 'Received refresh token' "$YANDEX360_REFRESH_TOKEN" + _secure_debug 'Obtained access token' "$YANDEX360_ACCESS_TOKEN" + _secure_debug 'Obtained refresh token' "$YANDEX360_REFRESH_TOKEN" _saveaccountconf_mutable YANDEX360_REFRESH_TOKEN "$YANDEX360_REFRESH_TOKEN" @@ -288,7 +287,6 @@ _refresh_token() { tr -d '"' ) - _secure_debug 'Response' "$response" _secure_debug 'Received access token' "$YANDEX360_ACCESS_TOKEN" _secure_debug 'Received refresh token' "$YANDEX360_REFRESH_TOKEN" @@ -299,8 +297,8 @@ _refresh_token() { _info 'Access token refreshed successfully' return 0 else - _debug 'Response' "$response" _info 'Failed to refresh token. Will attempt to obtain a new one.' + _debug 'Response' "$response" return 1 fi } From 2f1ca949f0d4225c80198bf474c624c252330f04 Mon Sep 17 00:00:00 2001 From: WhiteAls Date: Thu, 1 Aug 2024 02:33:09 +0000 Subject: [PATCH 34/53] Fix: Make record_id extraction independent of JSON key order --- dnsapi/dns_yandex360.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_yandex360.sh b/dnsapi/dns_yandex360.sh index e5f48bff..c4b5dbf4 100644 --- a/dnsapi/dns_yandex360.sh +++ b/dnsapi/dns_yandex360.sh @@ -75,7 +75,9 @@ dns_yandex360_rm() { record_id=$( echo "$response" | - sed -En 's/.*"recordId":([0-9]+).*"text":"'"${txtvalue}"'".*$/\1/p' + _egrep_o '\{[^}]*'"${txtvalue}"'[^}]*\}' | + _egrep_o '"recordId":[0-9]*' | + cut -d':' -f2 ) if [ -z "$record_id" ]; then From c7d78f45942d25b405f724c4543fbc45730df64b Mon Sep 17 00:00:00 2001 From: WhiteAls Date: Thu, 1 Aug 2024 02:44:22 +0000 Subject: [PATCH 35/53] Fix: Corrected the entry point for Yandex 360 API --- dnsapi/dns_yandex360.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_yandex360.sh b/dnsapi/dns_yandex360.sh index c4b5dbf4..815f2bce 100644 --- a/dnsapi/dns_yandex360.sh +++ b/dnsapi/dns_yandex360.sh @@ -14,7 +14,7 @@ Issues: https://github.com/acmesh-official/acme.sh/issues/5213 Author: ' -YANDEX360_API_BASE='https://api360.yandex.net/directory/v1/org' +YANDEX360_API_BASE='https://api360.yandex.net/directory/v1' YANDEX360_OAUTH_BASE='https://oauth.yandex.ru' ######## Public functions ##################### @@ -35,7 +35,7 @@ dns_yandex360_add() { sub_domain=$(echo "$fulldomain" | sed "s/\.$root_domain$//") _debug 'Adding Yandex 360 DNS record for subdomain' "$sub_domain" - dns_api_url="${YANDEX360_API_BASE}/${YANDEX360_ORG_ID}/domains/${root_domain}/dns" + dns_api_url="${YANDEX360_API_BASE}/org/${YANDEX360_ORG_ID}/domains/${root_domain}/dns" data='{"name":"'"$sub_domain"'","type":"TXT","ttl":60,"text":"'"$txtvalue"'"}' response="$(_post "$data" "$dns_api_url" '' 'POST' 'application/json')" @@ -63,7 +63,7 @@ dns_yandex360_rm() { fi _debug 'Retrieving 100 records from Yandex 360 DNS' - dns_api_url="${YANDEX360_API_BASE}/${YANDEX360_ORG_ID}/domains/${root_domain}/dns?perPage=100" + dns_api_url="${YANDEX360_API_BASE}/org/${YANDEX360_ORG_ID}/domains/${root_domain}/dns?perPage=100" response="$(_get "$dns_api_url" '' '')" response="$(echo "$response" | _normalizeJson)" @@ -86,7 +86,7 @@ dns_yandex360_rm() { fi _debug 'Removing DNS record' "$record_id" - delete_url="${YANDEX360_API_BASE}/${YANDEX360_ORG_ID}/domains/${root_domain}/dns/${record_id}" + delete_url="${YANDEX360_API_BASE}/org/${YANDEX360_ORG_ID}/domains/${root_domain}/dns/${record_id}" response="$(_post '' "$delete_url" '' 'DELETE')" response="$(echo "$response" | _normalizeJson)" @@ -317,7 +317,7 @@ _get_root() { return 1 fi - dns_api_url="${YANDEX360_API_BASE}/${YANDEX360_ORG_ID}/domains/${h}/dns" + dns_api_url="${YANDEX360_API_BASE}/org/${YANDEX360_ORG_ID}/domains/${h}/dns" response="$(_get "$dns_api_url" '' '')" response="$(echo "$response" | _normalizeJson)" From 13c68cd7994a13d5ab7b0242ad2c9607234ed185 Mon Sep 17 00:00:00 2001 From: WhiteAls Date: Thu, 1 Aug 2024 03:04:23 +0000 Subject: [PATCH 36/53] Refactor: Rename _check_yandex360_variables to _check_variables and improve error handling --- dnsapi/dns_yandex360.sh | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/dnsapi/dns_yandex360.sh b/dnsapi/dns_yandex360.sh index 815f2bce..2abeede1 100644 --- a/dnsapi/dns_yandex360.sh +++ b/dnsapi/dns_yandex360.sh @@ -24,7 +24,7 @@ dns_yandex360_add() { txtvalue=$2 _info 'Using Yandex 360 DNS API' - if ! _check_yandex360_variables; then + if ! _check_variables; then return 1 fi @@ -54,7 +54,7 @@ dns_yandex360_rm() { txtvalue=$2 _info 'Using Yandex 360 DNS API' - if ! _check_yandex360_variables; then + if ! _check_variables; then return 1 fi @@ -101,7 +101,7 @@ dns_yandex360_rm() { #################### Private functions below ################################## -_check_yandex360_variables() { +_check_variables() { YANDEX360_CLIENT_ID="${YANDEX360_CLIENT_ID:-$(_readaccountconf_mutable YANDEX360_CLIENT_ID)}" YANDEX360_CLIENT_SECRET="${YANDEX360_CLIENT_SECRET:-$(_readaccountconf_mutable YANDEX360_CLIENT_SECRET)}" YANDEX360_ORG_ID="${YANDEX360_ORG_ID:-$(_readaccountconf_mutable YANDEX360_ORG_ID)}" @@ -133,32 +133,33 @@ _check_yandex360_variables() { _saveaccountconf_mutable YANDEX360_ACCESS_TOKEN "$YANDEX360_ACCESS_TOKEN" export _H1="Authorization: OAuth $YANDEX360_ACCESS_TOKEN" - return 0 - fi - if [ -z "$YANDEX360_CLIENT_ID" ] || [ -z "$YANDEX360_CLIENT_SECRET" ]; then + elif [ -z "$YANDEX360_CLIENT_ID" ] || [ -z "$YANDEX360_CLIENT_SECRET" ]; then _err '=========================================' _err ' ERROR' _err '=========================================' - _err 'The preferred environment variables YANDEX360_CLIENT_ID, YANDEX360_CLIENT_SECRET, and YANDEX360_ORG_ID, or alternatively YANDEX360_ACCESS_TOKEN, is not set.' - _err 'It is recommended to export the first three variables over the latter before running acme.sh.' + _err 'The required environment variables YANDEX360_CLIENT_ID and YANDEX360_CLIENT_SECRET are not set.' + _err 'Alternatively, you can set YANDEX360_ACCESS_TOKEN environment variable.' _err 'For more details, please visit: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_yandex360' _err '=========================================' return 1 - fi + else _saveaccountconf_mutable YANDEX360_CLIENT_ID "$YANDEX360_CLIENT_ID" _saveaccountconf_mutable YANDEX360_CLIENT_SECRET "$YANDEX360_CLIENT_SECRET" if [ -n "$YANDEX360_REFRESH_TOKEN" ]; then _debug 'Refresh token found. Attempting to refresh access token.' - if _refresh_token; then - return 0 + if ! _refresh_token; then + if ! _get_token; then + return 1 fi fi - + else if ! _get_token; then return 1 + fi + fi fi return 0 From 2f08bd1965eebd1abf28ac88f97c85020ff8d176 Mon Sep 17 00:00:00 2001 From: WhiteAls Date: Thu, 1 Aug 2024 03:28:32 +0000 Subject: [PATCH 37/53] Refactor: Improve Yandex360 DNS API integration: - Make YANDEX360_ORG_ID optional and auto-retrieve if not provided. - Refactor _get_root function to search across multiple organizations. --- dnsapi/dns_yandex360.sh | 103 ++++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 36 deletions(-) diff --git a/dnsapi/dns_yandex360.sh b/dnsapi/dns_yandex360.sh index 2abeede1..2c8fc89f 100644 --- a/dnsapi/dns_yandex360.sh +++ b/dnsapi/dns_yandex360.sh @@ -7,8 +7,8 @@ Docs: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_yandex360 Options: YANDEX360_CLIENT_ID OAuth 2.0 ClientID YANDEX360_CLIENT_SECRET OAuth 2.0 Client secret - YANDEX360_ORG_ID Organization ID OptionsAlt: + YANDEX360_ORG_ID Organization ID. Optional. YANDEX360_ACCESS_TOKEN OAuth 2.0 Access token. Optional. Issues: https://github.com/acmesh-official/acme.sh/issues/5213 Author: @@ -108,18 +108,6 @@ _check_variables() { YANDEX360_ACCESS_TOKEN="${YANDEX360_ACCESS_TOKEN:-$(_readaccountconf_mutable YANDEX360_ACCESS_TOKEN)}" YANDEX360_REFRESH_TOKEN="${YANDEX360_REFRESH_TOKEN:-$(_readaccountconf_mutable YANDEX360_REFRESH_TOKEN)}" - if [ -z "$YANDEX360_ORG_ID" ]; then - _err '=========================================' - _err ' ERROR' - _err '=========================================' - _err "A required environment variable YANDEX360_ORG_ID is not set" - _err 'For more details, please visit: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_yandex360' - _err '=========================================' - return 1 - fi - - _saveaccountconf_mutable YANDEX360_ORG_ID "$YANDEX360_ORG_ID" - if [ -n "$YANDEX360_ACCESS_TOKEN" ]; then _info '=========================================' _info ' ATTENTION' @@ -145,20 +133,43 @@ _check_variables() { return 1 else - _saveaccountconf_mutable YANDEX360_CLIENT_ID "$YANDEX360_CLIENT_ID" - _saveaccountconf_mutable YANDEX360_CLIENT_SECRET "$YANDEX360_CLIENT_SECRET" + _saveaccountconf_mutable YANDEX360_CLIENT_ID "$YANDEX360_CLIENT_ID" + _saveaccountconf_mutable YANDEX360_CLIENT_SECRET "$YANDEX360_CLIENT_SECRET" - if [ -n "$YANDEX360_REFRESH_TOKEN" ]; then - _debug 'Refresh token found. Attempting to refresh access token.' + if [ -n "$YANDEX360_REFRESH_TOKEN" ]; then + _debug 'Refresh token found. Attempting to refresh access token.' if ! _refresh_token; then if ! _get_token; then return 1 + fi + fi + else + if ! _get_token; then + return 1 + fi fi fi + + if [ -z "$YANDEX360_ORG_ID" ]; then + org_response="$(_get "${YANDEX360_API_BASE}/org" '' '')" + org_response="$(echo "$org_response" | _normalizeJson)" + + if _contains "$org_response" '"organizations":'; then + YANDEX360_ORG_ID=$( + echo "$org_response" | + _egrep_o '"id":[[:space:]]*[0-9]+' | + cut -d: -f2 + ) + _debug 'Automatically retrieved YANDEX360_ORG_ID' "$YANDEX360_ORG_ID" else - if ! _get_token; then - return 1 - fi + _err '=========================================' + _err ' ERROR' + _err '=========================================' + _err "Failed to retrieve YANDEX360_ORG_ID automatically." + _err 'For more details, please visit: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_yandex360' + _err '=========================================' + _debug 'Response' "$org_response" + return 1 fi fi @@ -308,28 +319,48 @@ _refresh_token() { _get_root() { domain="$1" - i=1 - while true; do - h=$(echo "$domain" | cut -d . -f "$i"-) - _debug "Checking domain: $h" - if [ -z "$h" ]; then - _err "Could not determine root domain" - return 1 + for org_id in $YANDEX360_ORG_ID; do + _debug 'Checking organization ID' "$org_id" + domains_api_url="${YANDEX360_API_BASE}/org/${org_id}/domains" + + domains_response="$(_get "$domains_api_url" '' '')" + domains_response="$(echo "$domains_response" | _normalizeJson)" + + if ! _contains "$domains_response" '"domains":'; then + _debug 'No domains found for organization' "$org_id" + _debug 'Response' "$domains_response" + continue fi - dns_api_url="${YANDEX360_API_BASE}/org/${YANDEX360_ORG_ID}/domains/${h}/dns" + domain_names=$( + echo "$domains_response" | + _egrep_o '"name":"[^"]*"' | + cut -d'"' -f4 + ) - response="$(_get "$dns_api_url" '' '')" - response="$(echo "$response" | _normalizeJson)" - _debug 'Response' "$response" + for d in $domain_names; do + d="$(_idn "$d")" + _debug 'Checking domain' "$d" + + if _endswith "$domain" "$d"; then + root_domain="$d" + break + fi + done + + if [ -n "$root_domain" ]; then + _debug "Root domain found: $root_domain in organization $org_id" + + YANDEX360_ORG_ID="$org_id" + _saveaccountconf_mutable YANDEX360_ORG_ID "$YANDEX360_ORG_ID" - if _contains "$response" '"total":'; then - root_domain="$h" - _debug 'Root domain found' "$root_domain" return 0 fi - - i=$(_math "$i" + 1) done + + if [ -z "$root_domain" ]; then + _err "Could not find a matching root domain for $domain in any organization" + return 1 + fi } From 1700f064b3dc208071d85d123d6e5b3be9d93616 Mon Sep 17 00:00:00 2001 From: WhiteAls Date: Sat, 3 Aug 2024 18:59:29 +0000 Subject: [PATCH 38/53] Fix: Support for IDN --- dnsapi/dns_yandex360.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_yandex360.sh b/dnsapi/dns_yandex360.sh index 2c8fc89f..05563f90 100644 --- a/dnsapi/dns_yandex360.sh +++ b/dnsapi/dns_yandex360.sh @@ -20,7 +20,7 @@ YANDEX360_OAUTH_BASE='https://oauth.yandex.ru' ######## Public functions ##################### dns_yandex360_add() { - fulldomain=$1 + fulldomain="$(_idn "$1")" txtvalue=$2 _info 'Using Yandex 360 DNS API' @@ -50,7 +50,7 @@ dns_yandex360_add() { } dns_yandex360_rm() { - fulldomain=$1 + fulldomain="$(_idn "$1")" txtvalue=$2 _info 'Using Yandex 360 DNS API' From 435bb3f1d30408ec8838d0ee0661e22b2984a4b6 Mon Sep 17 00:00:00 2001 From: Roland Giesler Date: Wed, 21 Aug 2024 12:13:04 +0200 Subject: [PATCH 39/53] Update dns_miab.sh The MIAB API requires that the txtvlaue to a TXT record includes the "value=" and "ttl=" components as part of the TXT record when adding a new record. --- dnsapi/dns_miab.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index ec9867db..79e751bf 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -19,7 +19,8 @@ dns_miab_add() { txtvalue=$2 _info "Using miab challange add" _debug fulldomain "$fulldomain" - _debug txtvalue "$txtvalue" + # Added to accomodate the new TXT record format used by the API + _debug txtvalue "value="+="$txtvalue"+"&ttl=300" #retrieve MIAB environemt vars if ! _retrieve_miab_env; then From 0122eabd44a8d82b033a51292457161e18381aee Mon Sep 17 00:00:00 2001 From: Roland Giesler Date: Wed, 21 Aug 2024 15:10:37 +0200 Subject: [PATCH 40/53] Update dns_miab.sh Corrected typo --- dnsapi/dns_miab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index 79e751bf..837234c4 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -20,7 +20,7 @@ dns_miab_add() { _info "Using miab challange add" _debug fulldomain "$fulldomain" # Added to accomodate the new TXT record format used by the API - _debug txtvalue "value="+="$txtvalue"+"&ttl=300" + _debug txtvalue "value="+="$txtvalue"+="&ttl=300" #retrieve MIAB environemt vars if ! _retrieve_miab_env; then From 42e78f9a3ee031a0332b6a5241800aa8fee2ee94 Mon Sep 17 00:00:00 2001 From: Lifeboy Date: Wed, 21 Aug 2024 15:42:49 +0200 Subject: [PATCH 41/53] changes not yet tested --- dnsapi/dns_miab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index 837234c4..6b1555d0 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -19,7 +19,7 @@ dns_miab_add() { txtvalue=$2 _info "Using miab challange add" _debug fulldomain "$fulldomain" - # Added to accomodate the new TXT record format used by the API + # Added to accomodate the new TXT record format used by the API to include value= and ttl= _debug txtvalue "value="+="$txtvalue"+="&ttl=300" #retrieve MIAB environemt vars From 10cfc6838dacc56f2415ce179816549fb9d2b31e Mon Sep 17 00:00:00 2001 From: Nikolay Pronchev Date: Thu, 22 Aug 2024 09:12:21 +0300 Subject: [PATCH 42/53] add Timeweb Cloud DNS API --- dnsapi/dns_timeweb.sh | 405 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 dnsapi/dns_timeweb.sh diff --git a/dnsapi/dns_timeweb.sh b/dnsapi/dns_timeweb.sh new file mode 100644 index 00000000..2edca180 --- /dev/null +++ b/dnsapi/dns_timeweb.sh @@ -0,0 +1,405 @@ +#!/usr/bin/env sh + +# acme.sh DNS API for Timeweb Cloud provider (https://timeweb.cloud). +# +# Author: https://github.com/nikolaypronchev. +# +# Prerequisites: +# Timeweb Cloud API JWT token. Obtain one from the Timeweb Cloud control panel +# ("API and Terraform" section: https://timeweb.cloud/my/api-keys). The JWT token +# must be provided to this script in one of two ways: +# 1. As the "TW_Token" variable, for example: "export TW_Token=eyJhbG...zUxMiIs"; +# 2. As a "TW_Token" config entry in acme.sh account config file +# (usually located at ~/.acme.sh/account.conf by default). + +TW_Api="https://api.timeweb.cloud/api/v1" + +################ Public functions ################ + +# Adds an ACME DNS-01 challenge DNS TXT record via the Timeweb Cloud API. +# +# Param1: The ACME DNS-01 challenge FQDN. +# Param2: The value of the ACME DNS-01 challenge TXT record. +# +# Example: dns_timeweb_add "_acme-challenge.sub.domain.com" "D-52Wm...4uYM" +dns_timeweb_add() { + _debug "$(__green "Timeweb DNS API"): \"dns_timeweb_add\" started." + + _timeweb_set_acme_fqdn "$1" || return 1 + _timeweb_set_acme_txt "$2" || return 1 + _timeweb_check_token || return 1 + _timeweb_split_acme_fqdn || return 1 + _timeweb_dns_txt_add || return 1 + + _debug "$(__green "Timeweb DNS API"): \"dns_timeweb_add\" finished." +} + +# Removes a DNS TXT record via the Timeweb Cloud API. +# +# Param1: The ACME DNS-01 challenge FQDN. +# Param2: The value of the ACME DNS-01 challenge TXT record. +# +# Example: dns_timeweb_rm "_acme-challenge.sub.domain.com" "D-52Wm...4uYM" +dns_timeweb_rm() { + _debug "$(__green "Timeweb DNS API"): \"dns_timeweb_rm\" started." + + _timeweb_set_acme_fqdn "$1" || return 1 + _timeweb_set_acme_txt "$2" || return 1 + _timeweb_check_token || return 1 + _timeweb_split_acme_fqdn || return 1 + _timeweb_get_dns_txt || return 1 + _timeweb_dns_txt_remove || return 1 + + _debug "$(__green "Timeweb DNS API"): \"dns_timeweb_rm\" finished." +} + +################ Private functions ################ + +# Checks and sets the ACME DNS-01 challenge FQDN. +# +# Param1: The ACME DNS-01 challenge FQDN. +# +# Example: _timeweb_set_acme_fqdn "_acme-challenge.sub.domain.com" +# +# Sets the "Acme_Fqdn" variable (_acme-challenge.sub.domain.com) +_timeweb_set_acme_fqdn() { + Acme_Fqdn=$1 + _debug "Setting ACME DNS-01 challenge FQDN \"$Acme_Fqdn\"." + [ -z "$Acme_Fqdn" ] && { + _err "ACME DNS-01 challenge FQDN is empty." + return 1 + } + return 0 +} + +# Checks and sets the value of the ACME DNS-01 challenge TXT record. +# +# Param1: Value of the ACME DNS-01 challenge TXT record. +# +# Example: _timeweb_set_acme_txt "D-52Wm...4uYM" +# +# Sets the "Acme_Txt" variable to the provided value (D-52Wm...4uYM) +_timeweb_set_acme_txt() { + Acme_Txt=$1 + _debug "Setting the value of the ACME DNS-01 challenge TXT record to \"$Acme_Txt\"." + [ -z "$Acme_Txt" ] && { + _err "ACME DNS-01 challenge TXT record value is empty." + return 1 + } + return 0 +} + +# Checks if the Timeweb Cloud API JWT token is present (refer to the script description). +# Adds or updates the token in the acme.sh account configuration. +_timeweb_check_token() { + _debug "Checking for the presence of the Timeweb Cloud API JWT token." + + TW_Token="${TW_Token:-$(_readaccountconf_mutable TW_Token)}" + + [ -z "$TW_Token" ] && { + _err "Timeweb Cloud API JWT token was not found." + return 1 + } + + _saveaccountconf_mutable TW_Token "$TW_Token" +} + +# Divides the ACME DNS-01 challenge FQDN into its main domain and subdomain components. +_timeweb_split_acme_fqdn() { + _debug "Trying to divide \"$Acme_Fqdn\" into its main domain and subdomain components." + + TW_Page_Limit=100 + TW_Page_Offset=0 + + while [ -z "$TW_Domains_Total" ] || + [ "$((TW_Domains_Total + TW_Page_Limit))" -gt "$((TW_Page_Offset + TW_Page_Limit))" ]; do + + _timeweb_list_domains "$TW_Page_Limit" "$TW_Page_Offset" || return 1 + + # Remove the 'subdomains' subarray to prevent confusion with FQDNs. + + TW_Domains=$( + echo "$TW_Domains" | + sed 's/"subdomains":\[[^]]*]//g' + ) + + [ -z "$TW_Domains" ] && { + _err "Failed to parse the list of domains." + return 1 + } + + while + TW_Domain=$( + echo "$TW_Domains" | + sed -n 's/.*{[^{]*"fqdn":"\([^"]*\)"[^}]*}.*/\1/p' + ) + + [ -n "$TW_Domain" ] && { + _timeweb_is_main_domain "$TW_Domain" && return 0 + + TW_Domains=$( + echo "$TW_Domains" | + sed 's/{\([^{]*"fqdn":"'"$TW_Domain"'"[^}]*\)}//' + ) + continue + } + do :; done + + TW_Page_Offset=$(_math "$TW_Page_Offset" + "$TW_Page_Limit") + done + + _err "Failed to divide \"$Acme_Fqdn\" into its main domain and subdomain components." + return 1 +} + +# Searches for a previously added DNS TXT record. +# +# Sets the "TW_Dns_Txt_Id" variable. +_timeweb_get_dns_txt() { + _debug "Trying to locate a DNS TXT record with the value \"$Acme_Txt\"." + + TW_Page_Limit=100 + TW_Page_Offset=0 + + while [ -z "$TW_Dns_Records_Total" ] || + [ "$((TW_Dns_Records_Total + TW_Page_Limit))" -gt "$((TW_Page_Offset + TW_Page_Limit))" ]; do + _timeweb_list_dns_records "$TW_Page_Limit" "$TW_Page_Offset" || return 1 + + while + Dns_Record=$( + echo "$TW_Dns_Records" | + sed -n 's/.*{\([^{]*{[^{]*'"$Acme_Txt"'[^}]*}[^}]*\)}.*/\1/p' + ) + + [ -n "$Dns_Record" ] && { + _timeweb_is_added_txt "$Dns_Record" && return 0 + + TW_Dns_Records=$( + echo "$TW_Dns_Records" | + sed 's/{\([^{]*{[^{]*'"$Acme_Txt"'[^}]*}[^}]*\)}//' + ) + continue + } + do :; done + + TW_Page_Offset=$(_math "$TW_Page_Offset" + "$TW_Page_Limit") + done + + _err "DNS TXT record was not found." + return 1 +} + +# Lists domains via the Timeweb Cloud API. +# +# Param 1: Limit for listed domains. +# Param 2: Offset for domains list. +# +# Sets the "TW_Domains" variable. +# Sets the "TW_Domains_Total" variable. +_timeweb_list_domains() { + _debug "Listing domains via Timeweb Cloud API. Limit: $1, offset: $2." + + export _H1="Authorization: Bearer $TW_Token" + + if ! TW_Domains=$(_get "$TW_Api/domains?limit=$1&offset=$2"); then + _err "The request to the Timeweb Cloud API failed." + return 1 + fi + + [ -z "$TW_Domains" ] && { + _err "Empty response from the Timeweb Cloud API." + return 1 + } + + TW_Domains_Total=$( + echo "$TW_Domains" | + sed 's/.*"meta":{"total":\([0-9]*\)[^0-9].*/\1/' + ) + + [ -z "$TW_Domains_Total" ] && { + _err "Failed to extract the total count of domains." + return 1 + } + + [ "$TW_Domains_Total" -eq "0" ] && { + _err "Domains are missing." + return 1 + } + + _debug "Total count of domains in the Timeweb Cloud account: $TW_Domains_Total." +} + +# Lists domain DNS records via the Timeweb Cloud API. +# +# Param 1: Limit for listed DNS records. +# Param 2: Offset for DNS records list. +# +# Sets the "TW_Dns_Records" variable. +# Sets the "TW_Dns_Records_Total" variable. +_timeweb_list_dns_records() { + _debug "Listing domain DNS records via the Timeweb Cloud API. Limit: $1, offset: $2." + + export _H1="Authorization: Bearer $TW_Token" + + if ! TW_Dns_Records=$(_get "$TW_Api/domains/$TW_Main_Domain/dns-records?limit=$1&offset=$2"); then + _err "The request to the Timeweb Cloud API failed." + return 1 + fi + + [ -z "$TW_Dns_Records" ] && { + _err "Empty response from the Timeweb Cloud API." + return 1 + } + + TW_Dns_Records_Total=$( + echo "$TW_Dns_Records" | + sed 's/.*"meta":{"total":\([0-9]*\)[^0-9].*/\1/' + ) + + [ -z "$TW_Dns_Records_Total" ] && { + _err "Failed to extract the total count of DNS records." + return 1 + } + + [ "$TW_Dns_Records_Total" -eq "0" ] && { + _err "DNS records are missing." + return 1 + } + + _debug "Total count of DNS records: $TW_Dns_Records_Total." +} + +# Verifies whether the domain is the primary domain for the ACME DNS-01 challenge FQDN. +# The requirement is that the provided domain is the top-level domain +# for the ACME DNS-01 challenge FQDN. +# +# Param 1: Domain object returned by Timeweb Cloud API. +# +# Sets the "TW_Main_Domain" variable (e.g. "_acme-challenge.s1.domain.co.uk" → "domain.co.uk"). +# Sets the "TW_Subdomains" variable (e.g. "_acme-challenge.s1.domain.co.uk" → "_acme-challenge.s1"). +_timeweb_is_main_domain() { + _debug "Checking if \"$1\" is the main domain of the ACME DNS-01 challenge FQDN." + + [ -z "$1" ] && { + _debug "Failed to extract FQDN. Skipping domain." + return 1 + } + + ! echo ".$Acme_Fqdn" | grep -qi "\.$1$" && { + _debug "Domain does not match the ACME DNS-01 challenge FQDN. Skipping domain." + return 1 + } + + TW_Main_Domain=$1 + TW_Subdomains=$( + echo "$Acme_Fqdn" | + sed "s/\.*.\{${#1}\}$//" + ) + + _debug "Matched domain. ACME DNS-01 challenge FQDN split as [$TW_Subdomains].[$TW_Main_Domain]." + return 0 +} + +# Verifies whether a DNS record was previously added based on the following criteria: +# - The value matches the ACME DNS-01 challenge TXT record value; +# - The record type is TXT; +# - The subdomain matches the ACME DNS-01 challenge FQDN. +# +# Param 1: DNS record object returned by Timeweb Cloud API. +# +# Sets the "TW_Dns_Txt_Id" variable. +_timeweb_is_added_txt() { + _debug "Checking if \"$1\" is a previously added DNS TXT record." + + echo "$1" | grep -qv '"type":"TXT"' && { + _debug "Not a TXT record. Skipping the record." + return 1 + } + + if [ -n "$TW_Subdomains" ]; then + echo "$1" | grep -qvi "\"subdomain\":\"$TW_Subdomains\"" && { + _debug "Subdomains do not match. Skipping the record." + return 1 + } + else + echo "$1" | grep -q '"subdomain\":"..*"' && { + _debug "Subdomains do not match. Skipping the record." + return 1 + } + fi + + TW_Dns_Txt_Id=$( + echo "$1" | + sed 's/.*"id":\([0-9]*\)[^0-9].*/\1/' + ) + + [ -z "$TW_Dns_Txt_Id" ] && { + _debug "Failed to extract the DNS record ID. Skipping the record." + return 1 + } + + _debug "Matching DNS TXT record ID is \"$TW_Dns_Txt_Id\"." + return 0 +} + +# Adds a DNS TXT record via the Timeweb Cloud API. +_timeweb_dns_txt_add() { + _debug "Adding a new DNS TXT record via the Timeweb Cloud API." + + export _H1="Authorization: Bearer $TW_Token" + export _H2="Content-Type: application/json" + + if ! TW_Response=$( + _post "{ + \"subdomain\":\"$TW_Subdomains\", + \"type\":\"TXT\", + \"value\":\"$Acme_Txt\" + }" \ + "$TW_Api/domains/$TW_Main_Domain/dns-records" + ); then + _err "The request to the Timeweb Cloud API failed." + return 1 + fi + + [ -z "$TW_Response" ] && { + _err "An unexpected empty response was received from the Timeweb Cloud API." + return 1 + } + + TW_Dns_Txt_Id=$( + echo "$TW_Response" | + sed 's/.*"id":\([0-9]*\)[^0-9].*/\1/' + ) + + [ -z "$TW_Dns_Txt_Id" ] && { + _err "Failed to extract the DNS TXT Record ID." + return 1 + } + + _debug "DNS TXT record has been added. ID: \"$TW_Dns_Txt_Id\"." +} + +# Removes a DNS record via the Timeweb Cloud API. +_timeweb_dns_txt_remove() { + _debug "Removing DNS record via the Timeweb Cloud API." + + export _H1="Authorization: Bearer $TW_Token" + + if ! TW_Response=$( + _post \ + "" \ + "$TW_Api/domains/$TW_Main_Domain/dns-records/$TW_Dns_Txt_Id" \ + "" \ + "DELETE" + ); then + _err "The request to the Timeweb Cloud API failed." + return 1 + fi + + [ -n "$TW_Response" ] && { + _err "Received an unexpected response body from the Timeweb Cloud API." + return 1 + } + + _debug "DNS TXT record with ID \"$TW_Dns_Txt_Id\" has been removed." +} From fa3591f4f2393640bad4e153c0e91e5964d8498c Mon Sep 17 00:00:00 2001 From: Lifeboy Date: Thu, 22 Aug 2024 14:39:09 +0200 Subject: [PATCH 43/53] TXT record ADD test successfully --- dnsapi/dns_miab.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index 6b1555d0..6177903e 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -16,11 +16,11 @@ Author: Darven Dissek, William Gertz #Usage: dns_miab_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_miab_add() { fulldomain=$1 - txtvalue=$2 - _info "Using miab challange add" - _debug fulldomain "$fulldomain" + txtvalue="value="$2"&ttl=300" # Added to accomodate the new TXT record format used by the API to include value= and ttl= - _debug txtvalue "value="+="$txtvalue"+="&ttl=300" + _info "Using miab challenge add" + _debug fulldomain "$fulldomain" + _debug txtvalue $txtvalue #retrieve MIAB environemt vars if ! _retrieve_miab_env; then @@ -56,7 +56,7 @@ dns_miab_rm() { fulldomain=$1 txtvalue=$2 - _info "Using miab challage delete" + _info "Using miab challenge delete" _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" From 00bbe68f78e72661d1df71b64cda8764fcc97abc Mon Sep 17 00:00:00 2001 From: "i18n.site" Date: Fri, 23 Aug 2024 16:00:08 +0800 Subject: [PATCH 44/53] Update dns_huaweicloud.sh fix https://github.com/acmesh-official/acme.sh/issues/5261 --- dnsapi/dns_huaweicloud.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_huaweicloud.sh b/dnsapi/dns_huaweicloud.sh index f3df41f4..ee2d2b8e 100644 --- a/dnsapi/dns_huaweicloud.sh +++ b/dnsapi/dns_huaweicloud.sh @@ -210,7 +210,7 @@ _get_recordset_id() { _zoneid=$3 export _H1="X-Auth-Token: ${_token}" - response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}") + response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}&status=ACTIVE") if _contains "${response}" '"id"'; then _id="$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")" printf "%s" "${_id}" @@ -227,7 +227,7 @@ _add_record() { # Get Existing Records export _H1="X-Auth-Token: ${_token}" - response=$(_get "${dns_api}/v2/zones/${zoneid}/recordsets?name=${_domain}") + response=$(_get "${dns_api}/v2/zones/${zoneid}/recordsets?name=${_domain}&status=ACTIVE") _debug2 "${response}" _exist_record=$(echo "${response}" | _egrep_o '"records":[^]]*' | sed 's/\"records\"\:\[//g') From fab292d2dea84d41e3237324978e395f630753ce Mon Sep 17 00:00:00 2001 From: Lifeboy Date: Tue, 27 Aug 2024 17:06:36 +0200 Subject: [PATCH 45/53] correct a typo --- dnsapi/dns_miab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index 6177903e..c126b666 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -27,7 +27,7 @@ dns_miab_add() { return 1 fi - #check domain and seperate into doamin and host + #check domain and seperate into domain and host if ! _get_root "$fulldomain"; then _err "Cannot find any part of ${fulldomain} is hosted on ${MIAB_Server}" return 1 From cefa7d940a310af21dedcad1d03676fbe6c7064c Mon Sep 17 00:00:00 2001 From: "i18n.site" Date: Wed, 28 Aug 2024 11:31:29 +0800 Subject: [PATCH 46/53] Update DNS.yml DNS.yml can be triggered manually --- .github/workflows/DNS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/DNS.yml b/.github/workflows/DNS.yml index 727ba315..c1406d91 100644 --- a/.github/workflows/DNS.yml +++ b/.github/workflows/DNS.yml @@ -1,5 +1,6 @@ name: DNS on: + workflow_dispatch: push: paths: - 'dnsapi/*.sh' From 65c3dc21f42484173fa4a94c7905df7dd531b0ab Mon Sep 17 00:00:00 2001 From: Lifeboy Date: Mon, 2 Sep 2024 11:50:33 +0200 Subject: [PATCH 47/53] Added comments --- dnsapi/dns_miab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index c126b666..aeeab03c 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -16,8 +16,8 @@ Author: Darven Dissek, William Gertz #Usage: dns_miab_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_miab_add() { fulldomain=$1 + # Added "value=" and "&ttl=300" to accomodate the new TXT record format used by the MIAB API txtvalue="value="$2"&ttl=300" - # Added to accomodate the new TXT record format used by the API to include value= and ttl= _info "Using miab challenge add" _debug fulldomain "$fulldomain" _debug txtvalue $txtvalue From 9cec2688edc0978d2a138ffe38e19e2392342854 Mon Sep 17 00:00:00 2001 From: Lifeboy Date: Mon, 2 Sep 2024 11:58:27 +0200 Subject: [PATCH 48/53] Syntax corrections suggested by testing script --- dnsapi/dns_miab.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index aeeab03c..5e7b3c3a 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -17,10 +17,10 @@ Author: Darven Dissek, William Gertz dns_miab_add() { fulldomain=$1 # Added "value=" and "&ttl=300" to accomodate the new TXT record format used by the MIAB API - txtvalue="value="$2"&ttl=300" + txtvalue="value=" "$2" "&ttl=300" _info "Using miab challenge add" _debug fulldomain "$fulldomain" - _debug txtvalue $txtvalue + _debug txtvalue "$txtvalue" #retrieve MIAB environemt vars if ! _retrieve_miab_env; then From 3006c90fb84aed0d8372ac87fe942ea28aed95a7 Mon Sep 17 00:00:00 2001 From: Lifeboy Date: Mon, 2 Sep 2024 12:04:56 +0200 Subject: [PATCH 49/53] Syntax corrections suggested by testing script --- dnsapi/dns_miab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index 5e7b3c3a..c42b25e8 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -16,7 +16,7 @@ Author: Darven Dissek, William Gertz #Usage: dns_miab_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_miab_add() { fulldomain=$1 - # Added "value=" and "&ttl=300" to accomodate the new TXT record format used by the MIAB API + # Added "value=" and "&ttl=300" to accomodate the new TXT record format used by the MIAB / PMIAB API txtvalue="value=" "$2" "&ttl=300" _info "Using miab challenge add" _debug fulldomain "$fulldomain" From 031d53b04f27e5cf7e74ad66b989b8e042e443c5 Mon Sep 17 00:00:00 2001 From: Lifeboy Date: Mon, 2 Sep 2024 12:14:22 +0200 Subject: [PATCH 50/53] Syntax corrections suggested by testing script --- dnsapi/dns_miab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index c42b25e8..a24ed9a6 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -16,7 +16,7 @@ Author: Darven Dissek, William Gertz #Usage: dns_miab_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_miab_add() { fulldomain=$1 - # Added "value=" and "&ttl=300" to accomodate the new TXT record format used by the MIAB / PMIAB API + # Added "value=" and "&ttl=300" to accomodate the new TXT record format used by the MIAB/PMIAB API txtvalue="value=" "$2" "&ttl=300" _info "Using miab challenge add" _debug fulldomain "$fulldomain" From dc6ea97877764c51c836ed87cdaaebd48fbf3130 Mon Sep 17 00:00:00 2001 From: Lifeboy Date: Mon, 2 Sep 2024 14:54:22 +0200 Subject: [PATCH 51/53] Syntax corrections, previous change broke script --- dnsapi/dns_miab.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index a24ed9a6..c16c856b 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -17,10 +17,10 @@ Author: Darven Dissek, William Gertz dns_miab_add() { fulldomain=$1 # Added "value=" and "&ttl=300" to accomodate the new TXT record format used by the MIAB/PMIAB API - txtvalue="value=" "$2" "&ttl=300" + txtvalue="value=$2&ttl=300" _info "Using miab challenge add" _debug fulldomain "$fulldomain" - _debug txtvalue "$txtvalue" + _debug txtvalue $txtvalue #retrieve MIAB environemt vars if ! _retrieve_miab_env; then From 02fb40c5074cd0b069e0be408b6c740491858552 Mon Sep 17 00:00:00 2001 From: Lifeboy Date: Mon, 2 Sep 2024 14:56:00 +0200 Subject: [PATCH 52/53] Syntax corrections, previous change broke script --- dnsapi/dns_miab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index c16c856b..9416c8ce 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -20,7 +20,7 @@ dns_miab_add() { txtvalue="value=$2&ttl=300" _info "Using miab challenge add" _debug fulldomain "$fulldomain" - _debug txtvalue $txtvalue + _debug txtvalue "$txtvalue" #retrieve MIAB environemt vars if ! _retrieve_miab_env; then From 0fa20da990243d619e87f623601e5fdf60b1010c Mon Sep 17 00:00:00 2001 From: WhiteAls Date: Tue, 3 Sep 2024 17:11:43 +0000 Subject: [PATCH 53/53] Little optimisations and fixes. - Removed or moved `_normalizeJson` processing to occur only when needed. - Corrected usage of `_red` to `__red`. - Simplified JSON parsing by using more concise `cut` commands. - Simplify token refresh logic. --- dnsapi/dns_yandex360.sh | 70 +++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/dnsapi/dns_yandex360.sh b/dnsapi/dns_yandex360.sh index 05563f90..c6b6053d 100644 --- a/dnsapi/dns_yandex360.sh +++ b/dnsapi/dns_yandex360.sh @@ -39,7 +39,6 @@ dns_yandex360_add() { data='{"name":"'"$sub_domain"'","type":"TXT","ttl":60,"text":"'"$txtvalue"'"}' response="$(_post "$data" "$dns_api_url" '' 'POST' 'application/json')" - response="$(echo "$response" | _normalizeJson)" if _contains "$response" 'recordId'; then return 0 @@ -65,7 +64,6 @@ dns_yandex360_rm() { _debug 'Retrieving 100 records from Yandex 360 DNS' dns_api_url="${YANDEX360_API_BASE}/org/${YANDEX360_ORG_ID}/domains/${root_domain}/dns?perPage=100" response="$(_get "$dns_api_url" '' '')" - response="$(echo "$response" | _normalizeJson)" if ! _contains "$response" "$txtvalue"; then _info 'DNS record not found. Nothing to remove.' @@ -73,6 +71,8 @@ dns_yandex360_rm() { return 1 fi + response="$(echo "$response" | _normalizeJson)" + record_id=$( echo "$response" | _egrep_o '\{[^}]*'"${txtvalue}"'[^}]*\}' | @@ -89,7 +89,6 @@ dns_yandex360_rm() { delete_url="${YANDEX360_API_BASE}/org/${YANDEX360_ORG_ID}/domains/${root_domain}/dns/${record_id}" response="$(_post '' "$delete_url" '' 'DELETE')" - response="$(echo "$response" | _normalizeJson)" if _contains "$response" '{}'; then return 0 @@ -138,27 +137,20 @@ _check_variables() { if [ -n "$YANDEX360_REFRESH_TOKEN" ]; then _debug 'Refresh token found. Attempting to refresh access token.' - if ! _refresh_token; then - if ! _get_token; then - return 1 - fi - fi - else - if ! _get_token; then - return 1 - fi fi + + _refresh_token || _get_token || return 1 fi if [ -z "$YANDEX360_ORG_ID" ]; then org_response="$(_get "${YANDEX360_API_BASE}/org" '' '')" - org_response="$(echo "$org_response" | _normalizeJson)" - if _contains "$org_response" '"organizations":'; then + if _contains "$org_response" '"organizations"'; then + org_response="$(echo "$org_response" | _normalizeJson)" YANDEX360_ORG_ID=$( echo "$org_response" | _egrep_o '"id":[[:space:]]*[0-9]+' | - cut -d: -f2 + cut -d':' -f2 ) _debug 'Automatically retrieved YANDEX360_ORG_ID' "$YANDEX360_ORG_ID" else @@ -177,13 +169,13 @@ _check_variables() { } _get_token() { - _info "$(_red '=========================================')" - _info "$(_red ' NOTICE')" - _info "$(_red '=========================================')" - _info "$(_red 'Before using the Yandex 360 API, you need to complete an authorization procedure.')" - _info "$(_red 'The initial access token is obtained interactively and is a one-time operation.')" - _info "$(_red 'Subsequent API requests will be handled automatically.')" - _info "$(_red '=========================================')" + _info "$(__red '=========================================')" + _info "$(__red ' NOTICE')" + _info "$(__red '=========================================')" + _info "$(__red 'Before using the Yandex 360 API, you need to complete an authorization procedure.')" + _info "$(__red 'The initial access token is obtained interactively and is a one-time operation.')" + _info "$(__red 'Subsequent API requests will be handled automatically.')" + _info "$(__red '=========================================')" _info 'Initiating device authorization flow' device_code_url="${YANDEX360_OAUTH_BASE}/device/code" @@ -192,7 +184,6 @@ _get_token() { data="client_id=$YANDEX360_CLIENT_ID&device_id=acme.sh ${hostname}&device_name=acme.sh ${hostname}" response="$(_post "$data" "$device_code_url" '' 'POST')" - response="$(echo "$response" | _normalizeJson)" if ! _contains "$response" 'device_code'; then _err 'Failed to get device code' @@ -200,34 +191,33 @@ _get_token() { return 1 fi + response="$(echo "$response" | _normalizeJson)" + device_code=$( echo "$response" | _egrep_o '"device_code":"[^"]*"' | - cut -d: -f2 | - tr -d '"' + cut -d'"' -f4 ) _debug 'Device code' "$device_code" user_code=$( echo "$response" | _egrep_o '"user_code":"[^"]*"' | - cut -d: -f2 | - tr -d '"' + cut -d'"' -f4 ) _debug 'User code' "$user_code" verification_url=$( echo "$response" | _egrep_o '"verification_url":"[^"]*"' | - cut -d: -f2- | - tr -d '"' + cut -d'"' -f4 ) _debug 'Verification URL' "$verification_url" interval=$( echo "$response" | _egrep_o '"interval":[[:space:]]*[0-9]+' | - cut -d: -f2 + cut -d':' -f2 ) _debug 'Polling interval' "$interval" @@ -242,20 +232,18 @@ _get_token() { data="grant_type=device_code&code=$device_code&client_id=$YANDEX360_CLIENT_ID&client_secret=$YANDEX360_CLIENT_SECRET" response="$(_post "$data" "$token_url" '' 'POST')" - response="$(echo "$response" | _normalizeJson)" if _contains "$response" 'access_token'; then + response="$(echo "$response" | _normalizeJson)" YANDEX360_ACCESS_TOKEN=$( echo "$response" | _egrep_o '"access_token":"[^"]*"' | - cut -d: -f2- | - tr -d '"' + cut -d'"' -f4 ) YANDEX360_REFRESH_TOKEN=$( echo "$response" | _egrep_o '"refresh_token":"[^"]*"' | - cut -d: -f2- | - tr -d '"' + cut -d'"' -f4 ) _secure_debug 'Obtained access token' "$YANDEX360_ACCESS_TOKEN" @@ -285,20 +273,18 @@ _refresh_token() { data="grant_type=refresh_token&refresh_token=$YANDEX360_REFRESH_TOKEN&client_id=$YANDEX360_CLIENT_ID&client_secret=$YANDEX360_CLIENT_SECRET" response="$(_post "$data" "$token_url" '' 'POST')" - response="$(echo "$response" | _normalizeJson)" if _contains "$response" 'access_token'; then + response="$(echo "$response" | _normalizeJson)" YANDEX360_ACCESS_TOKEN=$( echo "$response" | _egrep_o '"access_token":"[^"]*"' | - cut -d: -f2 | - tr -d '"' + cut -d'"' -f4 ) YANDEX360_REFRESH_TOKEN=$( echo "$response" | _egrep_o '"refresh_token":"[^"]*"' | - cut -d: -f2- | - tr -d '"' + cut -d'"' -f4 ) _secure_debug 'Received access token' "$YANDEX360_ACCESS_TOKEN" @@ -325,14 +311,14 @@ _get_root() { domains_api_url="${YANDEX360_API_BASE}/org/${org_id}/domains" domains_response="$(_get "$domains_api_url" '' '')" - domains_response="$(echo "$domains_response" | _normalizeJson)" - if ! _contains "$domains_response" '"domains":'; then + if ! _contains "$domains_response" '"domains"'; then _debug 'No domains found for organization' "$org_id" _debug 'Response' "$domains_response" continue fi + domains_response="$(echo "$domains_response" | _normalizeJson)" domain_names=$( echo "$domains_response" | _egrep_o '"name":"[^"]*"' |