From 2d365efe564362b1d29964a4acb0a7a89e846e27 Mon Sep 17 00:00:00 2001 From: rka Date: Fri, 18 Apr 2025 02:48:48 +0300 Subject: [PATCH] Add Edgecenter DNS API --- dnsapi/dns_edgecenter.sh | 163 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 dnsapi/dns_edgecenter.sh diff --git a/dnsapi/dns_edgecenter.sh b/dnsapi/dns_edgecenter.sh new file mode 100644 index 00000000..cdd150df --- /dev/null +++ b/dnsapi/dns_edgecenter.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 + +# EdgeCenter DNS API integration for acme.sh +# Author: Konstantin Ruchev +dns_edgecenter_info='edgecenter DNS API +Site: https://edgecenter.ru +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_edgecenter +Options: + EDGECENTER_API_KEY auth APIKey' + +EDGECENTER_API="https://api.edgecenter.ru" +DOMAIN_TYPE= +DOMAIN_MASTER= + +######## Public functions ##################### + +#Usage: dns_edgecenter_add _acme-challenge.www.domain.com "TXT_RECORD_VALUE" +dns_edgecenter_add() { + fulldomain="$1" + txtvalue="$2" + + _info "Using EdgeCenter DNS API" + + if ! _dns_edgecenter_init_check; then + return 1 + fi + + _debug "Detecting root zone for $fulldomain" + if ! _get_root "$fulldomain"; then + return 1 + fi + + subdomain="${fulldomain%."$_zone"}" + subdomain=${subdomain%.} + + _debug "Zone: $_zone" + _debug "Subdomain: $subdomain" + _debug "TXT value: $txtvalue" + + payload='{"resource_records": [ { "content": ["'"$txtvalue"'"] } ], "ttl": 60 }' + _dns_edgecenter_http_api_call "post" "dns/v2/zones/$_zone/$subdomain.$_zone/txt" "$payload" + + if _contains "$response" '"error":"rrset is already exists"'; then + _debug "RRSet exists, merging values" + _dns_edgecenter_http_api_call "get" "dns/v2/zones/$_zone/$subdomain.$_zone/txt" + current="$response" + newlist="" + for v in $(echo "$current" | sed -n 's/.*"content":\["\([^"]*\)"\].*/\1/p'); do + newlist="$newlist {\"content\":[\"$v\"]}," + done + newlist="$newlist{\"content\":[\"$txtvalue\"]}" + putdata="{\"resource_records\":[${newlist}]} +" + _dns_edgecenter_http_api_call "put" "dns/v2/zones/$_zone/$subdomain.$_zone/txt" "$putdata" + _info "Updated existing RRSet with new TXT value." + return 0 + fi + + if _contains "$response" '"exception":'; then + _err "Record cannot be added." + return 1 + fi + + _info "TXT record added successfully." + return 0 +} + +#Usage: dns_edgecenter_rm _acme-challenge.www.domain.com "TXT_RECORD_VALUE" +dns_edgecenter_rm() { + fulldomain="$1" + txtvalue="$2" + + _info "Removing TXT record for $fulldomain" + + if ! _dns_edgecenter_init_check; then + return 1 + fi + + if ! _get_root "$fulldomain"; then + return 1 + fi + + subdomain="${fulldomain%."$_zone"}" + subdomain=${subdomain%.} + + _dns_edgecenter_http_api_call "delete" "dns/v2/zones/$_zone/$subdomain.$_zone/txt" + + if [ -z "$response" ]; then + _info "TXT record deleted successfully." + else + _info "TXT record may not have been deleted: $response" + fi + return 0 +} + +#################### Private functions below ################################## + +_dns_edgecenter_init_check() { + EDGECENTER_API_KEY="${EDGECENTER_API_KEY:-$(_readaccountconf_mutable EDGECENTER_API_KEY)}" + if [ -z "$EDGECENTER_API_KEY" ]; then + _err "EDGECENTER_API_KEY was not exported." + return 1 + fi + + _saveaccountconf_mutable EDGECENTER_API_KEY "$EDGECENTER_API_KEY" + export _H1="Authorization: APIKey $EDGECENTER_API_KEY" + + _dns_edgecenter_http_api_call "get" "dns/v2/clients/me/features" + if ! _contains "$response" '"id":'; then + _err "Invalid API key." + return 1 + fi + return 0 +} + +_get_root() { + domain="$1" + i=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f "$i"-) + if [ -z "$h" ]; then + return 1 + fi + _dns_edgecenter_http_api_call "get" "dns/v2/zones/$h" + if ! _contains "$response" 'zone is not found'; then + _zone="$h" + return 0 + fi + i=$((i + 1)) + done + return 1 +} + +_dns_edgecenter_http_api_call() { + mtd="$1" + endpoint="$2" + data="$3" + + export _H1="Authorization: APIKey $EDGECENTER_API_KEY" + + case "$mtd" in + get) + response="$(_get "$EDGECENTER_API/$endpoint")" + ;; + post) + response="$(_post "$data" "$EDGECENTER_API/$endpoint")" + ;; + delete) + response="$(_post "" "$EDGECENTER_API/$endpoint" "" "DELETE")" + ;; + put) + response="$(_post "$data" "$EDGECENTER_API/$endpoint" "" "PUT")" + ;; + *) + _err "Unknown HTTP method $mtd" + return 1 + ;; + esac + + _debug "HTTP $mtd response: $response" + return 0 +}