#!/usr/bin/env sh # shellcheck disable=SC2034 dns_servercow_info='ServerCow.de Site: ServerCow.de Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_servercow Options: SERVERCOW_API_Username Username SERVERCOW_API_Password Password Issues: github.com/jhartlep/servercow-dns-api/issues Author: Jens Hartlep ' SERVERCOW_API="https://api.servercow.de/dns/v1/domains" ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_servercow_add() { fulldomain=$1 txtvalue=$2 SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then SERVERCOW_API_Username="" SERVERCOW_API_Password="" _err "You didn't specify a ServerCow api username and password yet." _err "Please create your username and password and try again." return 1 fi #save the api username and password to the account conf file. _saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username" _saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_Password" _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 txt records" # check whether a txt record already exists for the subdomain if printf -- "%s" "$response" | grep "{\"name\":\"$_sub_domain\",\"ttl\":20,\"type\":\"TXT\"" >/dev/null; then _info "A txt record with the same name already exists." # Extract the content field content_field=${response#*{\"name\":\""$_sub_domain"\",\"ttl\":20,\"type\":\"TXT\",\"content\":} # Check if content is already an array (starts with [) if printf -- "%s" "$content_field" | grep '^\[' >/dev/null; then # Content is an array - extract all values _debug "Content is already an array" # Extract everything between [ and ] content_array=${content_field#\[} content_array=${content_array%%\]*} # Build new array with new value prepended _info "Add the new txtvalue to the existing txt record array." if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":[\"$txtvalue\",$content_array],\"ttl\":20}"; then if printf -- "%s" "$response" | grep "ok" >/dev/null; then _info "Added additional txtvalue, OK" return 0 else _err "Add txt record error." return 1 fi fi _err "Add txt record error." return 1 else # Content is a single value - extract it _debug "Content is a single value" txtvalue_old=${content_field%%\"*} txtvalue_old=${txtvalue_old#\"} _debug txtvalue_old "$txtvalue_old" _info "Add the new txtvalue to the existing txt record." if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":[\"$txtvalue\",\"$txtvalue_old\"],\"ttl\":20}"; then if printf -- "%s" "$response" | grep "ok" >/dev/null; then _info "Added additional txtvalue, OK" return 0 else _err "Add txt record error." return 1 fi fi _err "Add txt record error." return 1 fi else _info "There is no txt record with the name yet." _info "Adding record" if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then if printf -- "%s" "$response" | grep "ok" >/dev/null; then _info "Added, OK" return 0 else _err "Add txt record error." return 1 fi fi _err "Add txt record error." return 1 fi } #fulldomain txtvalue dns_servercow_rm() { fulldomain=$1 txtvalue=$2 SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then SERVERCOW_API_Username="" SERVERCOW_API_Password="" _err "You didn't specify a ServerCow api username and password yet." _err "Please create your username and password and try again." 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" _debug "Deleting txt record" if ! _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then _err "Delete record error." return 1 fi if printf -- "%s" "$response" | grep "ok" >/dev/null; then _info "Deleted, OK" return 0 else _err "Delete txt record error." return 1 fi } #################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www # _domain=domain.com _get_root() { fulldomain=$1 i=2 p=1 while true; do _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-100) _debug _domain "$_domain" if [ -z "$_domain" ]; then #not valid return 1 fi if ! _servercow_api GET "$_domain"; then return 1 fi if ! _contains "$response" '"error":"no such domain in user context"' >/dev/null; then _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$p") if [ -z "$_sub_domain" ]; then #not valid return 1 fi return 0 fi p=$i i=$(_math "$i" + 1) done return 1 } _servercow_api() { method=$1 domain=$2 data="$3" export _H1="Content-Type: application/json" export _H2="X-Auth-Username: $SERVERCOW_API_Username" export _H3="X-Auth-Password: $SERVERCOW_API_Password" if [ "$method" != "GET" ]; then _debug data "$data" response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")" else response="$(_get "$SERVERCOW_API/$domain")" fi if [ "$?" != "0" ]; then _err "error $domain" return 1 fi _debug2 response "$response" return 0 }