diff --git a/dnsapi/dns_clouddns.sh b/dnsapi/dns_clouddns.sh new file mode 100755 index 00000000..31ae4ee9 --- /dev/null +++ b/dnsapi/dns_clouddns.sh @@ -0,0 +1,197 @@ +#!/usr/bin/env sh + +# Author: Radek Sprta + +#CLOUDDNS_EMAIL=XXXXX +#CLOUDDNS_PASSWORD="YYYYYYYYY" +#CLOUDDNS_CLIENT_ID=XXXXX + +CLOUDDNS_API='https://admin.vshosting.cloud/clouddns' +CLOUDDNS_LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login' + +######## Public functions ##################### + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_clouddns_add() { + fulldomain=$1 + txtvalue=$2 + _debug "fulldomain" "$fulldomain" + + CLOUDDNS_CLIENT_ID="${CLOUDDNS_CLIENT_ID:-$(_readaccountconf_mutable CLOUDDNS_CLIENT_ID)}" + CLOUDDNS_EMAIL="${CLOUDDNS_EMAIL:-$(_readaccountconf_mutable CLOUDDNS_EMAIL)}" + CLOUDDNS_PASSWORD="${CLOUDDNS_PASSWORD:-$(_readaccountconf_mutable CLOUDDNS_PASSWORD)}" + + if [ -z "$CLOUDDNS_PASSWORD" ] || [ -z "$CLOUDDNS_EMAIL" ] || [ -z "$CLOUDDNS_CLIENT_ID" ]; then + CLOUDDNS_CLIENT_ID="" + CLOUDDNS_EMAIL="" + CLOUDDNS_PASSWORD="" + _err "You didn't specify a CloudDNS password, email and client ID yet." + return 1 + fi + if ! _contains "$CLOUDDNS_EMAIL" "@"; then + _err "It seems that the CLOUDDNS_EMAIL=$CLOUDDNS_EMAIL is not a valid email address." + _err "Please check and retry." + return 1 + fi + # Save CloudDNS client id, email and password to config file + _saveaccountconf_mutable CLOUDDNS_CLIENT_ID "$CLOUDDNS_CLIENT_ID" + _saveaccountconf_mutable CLOUDDNS_EMAIL "$CLOUDDNS_EMAIL" + _saveaccountconf_mutable CLOUDDNS_PASSWORD "$CLOUDDNS_PASSWORD" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + # Add TXT record + data="{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"value\":\"$txtvalue\",\"domainId\":\"$_domain_id\"}" + if _clouddns_api POST "record-txt" "$data"; then + if _contains "$response" "$txtvalue"; then + _info "Added, OK" + elif _contains "$response" '"code":4136'; then + _info "Already exists, OK" + else + _err "Add TXT record error." + return 1 + fi + fi + + _debug "Publishing record changes" + _clouddns_api PUT "domain/$_domain_id/publish" "{\"soaTtl\":300}" +} + +# Usage: rm _acme-challenge.www.domain.com +dns_clouddns_rm() { + fulldomain=$1 + _debug "fulldomain" "$fulldomain" + + CLOUDDNS_CLIENT_ID="${CLOUDDNS_CLIENT_ID:-$(_readaccountconf_mutable CLOUDDNS_CLIENT_ID)}" + CLOUDDNS_EMAIL="${CLOUDDNS_EMAIL:-$(_readaccountconf_mutable CLOUDDNS_EMAIL)}" + CLOUDDNS_PASSWORD="${CLOUDDNS_PASSWORD:-$(_readaccountconf_mutable CLOUDDNS_PASSWORD)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + # Get record ID + _clouddns_api GET "domain/$_domain_id" + if _contains "$response" "lastDomainRecordList"; then + re="\"lastDomainRecordList\".*\"id\":\"([^\"}]*)\"[^}]*\"name\":\"$fulldomain.\"," + _last_domains=$(echo "$response" | _egrep_o "$re") + re2="\"id\":\"([^\"}]*)\"[^}]*\"name\":\"$fulldomain.\"," + _record_id=$(echo "$_last_domains" | _egrep_o "$re2" | _head_n 1 | cut -d : -f 2 | cut -d , -f 1 | tr -d "\"") + _debug _record_id "$_record_id" + else + _err "Could not retrieve record ID" + return 1 + fi + + _info "Removing record" + if _clouddns_api DELETE "record/$_record_id"; then + if _contains "$response" "\"error\":"; then + _err "Could not remove record" + return 1 + fi + fi + + _debug "Publishing record changes" + _clouddns_api PUT "domain/$_domain_id/publish" "{\"soaTtl\":300}" +} + +#################### Private functions below ################################## + +# Usage: _get_root _acme-challenge.www.domain.com +# Returns: +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + + # Get domain root + data="{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$CLOUDDNS_CLIENT_ID\"}]}" + _clouddns_api "POST" "domain/search" "$data" + domain_slice="$domain" + while [ -z "$domain_root" ]; do + if _contains "$response" "\"domainName\":\"$domain_slice\.\""; then + domain_root="$domain_slice" + _debug domain_root "$domain_root" + fi + domain_slice="$(echo "$domain_slice" | cut -d . -f 2-)" + done + + # Get domain id + data="{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$CLOUDDNS_CLIENT_ID\"}, \ + {\"name\": \"domainName\", \"operator\": \"eq\", \"value\": \"$domain_root.\"}]}" + _clouddns_api "POST" "domain/search" "$data" + if _contains "$response" "\"id\":\""; then + re='domainType\":\"[^\"]*\",\"id\":\"([^\"]*)\",' # Match domain id + _domain_id=$(echo "$response" | _egrep_o "$re" | _head_n 1 | cut -d : -f 3 | tr -d "\",") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | sed "s/.$domain_root//") + _domain="$domain_root" + return 0 + fi + _err 'Domain name not found on your CloudDNS account' + return 1 + fi + return 1 +} + +# Usage: _clouddns_api GET domain/search '{"data": "value"}' +# Returns: +# response='{"message": "api response"}' +_clouddns_api() { + method=$1 + endpoint="$2" + data="$3" + _debug endpoint "$endpoint" + + if [ -z "$CLOUDDNS_TOKEN" ]; then + _clouddns_login + fi + _debug CLOUDDNS_TOKEN "$CLOUDDNS_TOKEN" + + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $CLOUDDNS_TOKEN" + + if [ "$method" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$CLOUDDNS_API/$endpoint" "" "$method" | tr -d '\t\r\n ')" + else + response="$(_get "$CLOUDDNS_API/$endpoint" | tr -d '\t\r\n ')" + fi + + # shellcheck disable=SC2181 + if [ "$?" != "0" ]; then + _err "Error $endpoint" + return 1 + fi + _debug2 response "$response" + return 0 +} + +# Returns: +# CLOUDDNS_TOKEN=dslfje2rj23l +_clouddns_login() { + login_data="{\"email\": \"$CLOUDDNS_EMAIL\", \"password\": \"$CLOUDDNS_PASSWORD\"}" + response="$(_post "$login_data" "$CLOUDDNS_LOGIN_API" "" "POST" "Content-Type: application/json")" + + if _contains "$response" "\"accessToken\":\""; then + CLOUDDNS_TOKEN=$(echo "$response" | _egrep_o "\"accessToken\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") + export CLOUDDNS_TOKEN + else + echo 'Could not get CloudDNS access token; check your credentials' + return 1 + fi + return 0 +}