diff --git a/dnsapi/dns_abion.sh b/dnsapi/dns_abion.sh new file mode 100644 index 00000000..acd12229 --- /dev/null +++ b/dnsapi/dns_abion.sh @@ -0,0 +1,198 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_abion_info='Abion.com +Site: abion.com +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_abion +Options: + ABION_API_KEY API Key. Created in the Abion Core web interface. +Issues: github.com/acmesh-official/acme.sh/issues/7325 +' + +ABION_Api_Endpoint="https://api.abion.com/v1" + +##################### Public functions ##################### + +# Usage: dns_abion_add +# Example: dns_abion_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_abion_add() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + ABION_API_KEY="${ABION_API_KEY:-$(_readaccountconf_mutable ABION_API_KEY)}" + + if [ -z "$ABION_API_KEY" ]; then + ABION_API_KEY="" + _err "You need to specify ABION_API_KEY." + return 1 + fi + + _saveaccountconf_mutable ABION_API_KEY "$ABION_API_KEY" + + _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 ! _abion_get_txt_records; then + return 1 + fi + + if _contains "$_txt_records" "\"rdata\":\"$txtvalue\""; then + _info "TXT record already exists" + return 0 + fi + + _records=$(echo "$_txt_records" | tr '\n' ',' | sed 's/,*$//') + if [ -n "$_records" ]; then + _records="$_records," + fi + + _info "Adding record" + if ! _abion_patch_txt "[$_records{\"rdata\":\"$txtvalue\",\"ttl\":60}]"; then + return 1 + fi + + _info "Added, OK" + return 0 +} + +# Usage: dns_abion_rm +dns_abion_rm() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + ABION_API_KEY="${ABION_API_KEY:-$(_readaccountconf_mutable ABION_API_KEY)}" + + if [ -z "$ABION_API_KEY" ]; then + ABION_API_KEY="" + _err "You need to specify ABION_API_KEY." + return 1 + fi + + _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 ! _abion_get_txt_records; then + return 1 + fi + + if ! _contains "$_txt_records" "\"rdata\":\"$txtvalue\""; then + _info "TXT record not found, nothing to remove" + return 0 + fi + + _records=$(echo "$_txt_records" | grep -v "\"rdata\":\"$txtvalue\"" | tr '\n' ',' | sed 's/,*$//') + + if [ -n "$_records" ]; then + _records="[$_records]" + else + _records="null" + fi + + _info "Deleting record" + if ! _abion_patch_txt "$_records"; then + return 1 + fi + + _info "Deleted, OK" + return 0 +} + +##################### Private functions ##################### + +_get_root() { + domain=$1 + i=1 + p=0 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) + _debug h "$h" + if [ -z "$h" ]; then + return 1 + fi + + if ! _abion_rest GET "zones/$h"; then + return 1 + fi + + if _contains "$response" '"type" *: *"zone"'; then + if [ "$p" = "0" ]; then + _sub_domain="@" + else + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") + fi + _domain="$h" + return 0 + fi + + if ! _contains "$response" "Zone not found"; then + _err "$response" + return 1 + fi + + p="$i" + i=$(_math "$i" + 1) + done +} + +_abion_get_txt_records() { + if ! _abion_rest GET "zones/$_domain"; then + return 1 + fi + + _sub_re=$(printf "%s" "$_sub_domain" | sed 's/[.]/\\./g') + _txt_records=$(echo "$response" | _normalizeJson | + sed -n "s/.*\"$_sub_re\":{//p" | + sed 's/\] *}.*/]/' | + _egrep_o '"TXT":\[[^]]*\]' | + sed 's/^"TXT":\[ *//;s/ *\]$//;s/} *, *{/}\ +{/g') + _debug2 _txt_records "$_txt_records" + return 0 +} + +_abion_patch_txt() { + if ! _abion_rest PATCH "zones/$_domain" "{\"data\":{\"type\":\"zone\",\"id\":\"$_domain\",\"attributes\":{\"records\":{\"$_sub_domain\":{\"TXT\":$1}}}}}"; then + return 1 + fi + + if ! _contains "$response" '"type" *: *"zone"'; then + _err "Unexpected API response: $response" + return 1 + fi + + return 0 +} + +_abion_rest() { + method=$1 + endpoint=$2 + data=$3 + + export _H1="X-API-KEY: $ABION_API_KEY" + export _H2="Content-Type: application/json" + + if [ "$method" = "GET" ]; then + response="$(_get "$ABION_Api_Endpoint/$endpoint")" + else + response="$(_post "$data" "$ABION_Api_Endpoint/$endpoint" "" "$method")" + fi + + if [ "$?" != "0" ]; then + _err "error $endpoint" + return 1 + fi + + _debug2 response "$response" + return 0 +}