From 37f9fd3498ca9d2138502acf51f6d6787c83398b Mon Sep 17 00:00:00 2001 From: WhiteAls Date: Sat, 20 Jul 2024 05:38:51 +0300 Subject: [PATCH 01/10] 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 02/10] 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 03/10] 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 a6488ff9accd5b72854a34e6b007e25730b8f359 Mon Sep 17 00:00:00 2001 From: WhiteAls Date: Thu, 1 Aug 2024 02:18:48 +0000 Subject: [PATCH 04/10] 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 05/10] 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 06/10] 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 07/10] 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 08/10] 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 09/10] 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 0fa20da990243d619e87f623601e5fdf60b1010c Mon Sep 17 00:00:00 2001 From: WhiteAls Date: Tue, 3 Sep 2024 17:11:43 +0000 Subject: [PATCH 10/10] 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":"[^"]*"' |