Skip to content

Instantly share code, notes, and snippets.

@scr34m
Last active June 9, 2023 07:29
Show Gist options
  • Save scr34m/c7af866d9c3e0c4bc5850d651c59b770 to your computer and use it in GitHub Desktop.
Save scr34m/c7af866d9c3e0c4bc5850d651c59b770 to your computer and use it in GitHub Desktop.
Acme.sh DNS API interface for Dotroll
#!/usr/bin/bash
# Dotroll domain api
# - api access values stored per domain, including migration from account stored values
# - zone data is POST-ed to avoid "414 Request-URI Too Large" errors
#
# Initially export values Dotroll_User and Dotroll_Password
# export Dotroll_User='<your.dotroll@user>'; export Dotroll_Password='<dotroll_api_password>'; acme.sh --issue --dns dns_dotroll -d <domain.tld> -d '*.<domain.tld>'
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_dotroll_add() {
fulldomain=$1
txtvalue=$2
_info "Adding TXT record using dotroll API"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
Dotroll_User="${Dotroll_User:-$(_readdomainconf Dotroll_User)}"
Dotroll_Password="${Dotroll_Password:-$(_readdomainconf Dotroll_Password)}"
if [ -z "$Dotroll_User" ] || [ -z "$Dotroll_Password" ]; then
_debug "Try to migrate from account conf"
Acc_Dotroll_User="$(_readaccountconf_mutable Dotroll_User)"
Acc_Dotroll_Password="$(_readaccountconf_mutable Dotroll_Password)"
if [ -n "$Acc_Dotroll_User" ] && [ -n "$Acc_Dotroll_Password" ]; then
Dotroll_User="$Acc_Dotroll_User"
Dotroll_Password="$Acc_Dotroll_Password"
_savedomainconf Dotroll_User "$Acc_Dotroll_User"
_savedomainconf Dotroll_Password "$Acc_Dotroll_Password"
else
Dotroll_User=""
Dotroll_Password=""
_err "You don't specify dotroll user accounts."
_err "Please create you key and try again."
return 1
fi
fi
#save the user and password to the domain conf file.
_savedomainconf Dotroll_User "$Dotroll_User"
_savedomainconf Dotroll_Password "$Dotroll_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 existing records"
_dotroll_rest GET "$_domain/get"
if ! _contains "$response" 'message":"OK"'; then
return 1
fi
if _contains "$response" "$txtvalue"; then
_info "The record is existing, skip"
return 0
fi
# IMPORTANT this does only add new records, the original records are not altered, but are required by the API
records=$(echo "$response" | cut -c 12- | rev | cut -c 40- | rev)
records_list=$(printf "{%s}" "$records")
# unchanged records_list
modify=$(echo "$records_list" | _url_encode)
new=$(echo '[{"name": "'${fulldomain}'.", "type": "TXT", "ttl": 3600, "txtdata": "'${txtvalue}'"}]' | _url_encode)
_dotroll_rest POST "$_domain/modify" "modify=${modify}&new=${new}"
if ! _contains "$response" 'message":"OK"'; then
_err "Add txt record error."
return 1
fi
_info "Added, sleeping 10 seconds"
_sleep 10
#todo: check if the record takes effect
return 0
}
# Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_dotroll_rm() {
fulldomain=$1
txtvalue=$2
_info "Removing TXT record using dotroll API"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
Dotroll_User="${Dotroll_User:-$(_readdomainconf Dotroll_User)}"
Dotroll_Password="${Dotroll_Password:-$(_readdomainconf Dotroll_Password)}"
if [ -z "$Dotroll_User" ] || [ -z "$Dotroll_Password" ]; then
_debug "Try to migrate from account conf"
Acc_Dotroll_User="$(_readaccountconf_mutable Dotroll_User)"
Acc_Dotroll_Password="$(_readaccountconf_mutable Dotroll_Password)"
if [ -n "$Acc_Dotroll_User" ] && [ -n "$Acc_Dotroll_Password" ]; then
Dotroll_User="$Acc_Dotroll_User"
Dotroll_Password="$Acc_Dotroll_Password"
_savedomainconf Dotroll_User "$Acc_Dotroll_User"
_savedomainconf Dotroll_Password "$Acc_Dotroll_Password"
else
Dotroll_User=""
Dotroll_Password=""
_err "You don't specify dotroll user accounts."
_err "Please create you key and try again."
return 1
fi
fi
#save the user and password to the domain conf file.
_savedomainconf Dotroll_User "$Dotroll_User"
_savedomainconf Dotroll_Password "$Dotroll_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 existing records"
_dotroll_rest GET "$_domain/get"
if ! _contains "$response" 'message":"OK"'; then
return 1
fi
if ! _contains "$response" "$txtvalue"; then
_info "The TXT record is missing, skip"
return 0
fi
# IMPORTANT this does only remove a single record by pairs of fulldomain + txtvalue
records=$(echo "$response" | cut -c 12- | rev | cut -c 40- | rev)
records_list=$(printf "{%s}" "$records")
record=$(echo $records_list | _egrep_o ",\"[0-9]+\"\:{*\"name\":\"$fulldomain\.\"[^}]*\"${txtvalue}\"}")
record_cnt=$(echo $records_list | _egrep_o ",\"[0-9]+\"\:{*\"name\":\"$fulldomain\.\"[^}]*\"${txtvalue}\"}" | wc -l)
if [ ! -z "${record}" ]; then
if [ $record_cnt -gt 1 ]; then
while read recordline
do
records_list=$(echo "${records_list}" | sed -e "s|${recordline}||")
_debug _records_list "${records_list}"
done < <(echo "${record}")
else
records_list=$(echo "${records_list}" | sed -e "s|${record}||")
_debug _records_list "${records_list}"
fi
fi
# remove whitespaces
records_list=$(echo "$records_list" | xargs)
# modified records_list
modify=$(echo "$records_list" | _url_encode)
# URL-param 'modify' only!
_dotroll_rest POST "$_domain/modify" "modify=${modify}"
if ! _contains "$response" 'message":"OK"'; then
_err "Remove txt record error."
return 1
fi
_info "Removed, sleeping 10 seconds"
_sleep 10
#todo: check if the record takes effect
return 0
}
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
_get_root() {
domain=$1
i=2
p=1
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
if [ -z "$h" ]; then
#not valid
return 1
fi
_dotroll_rest GET "$h/get"
if ! _contains "$response" 'message":"OK"'; then
_debug "$h not found or error"
else
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain="$h"
return 0
fi
p="$i"
i=$(_math "$i" + 1)
done
return 1
}
_dotroll_rest() {
m="$1"
ep="$2"
data="$3"
_debug m $m
_debug ep $ep
_dotroll_auth=$(printf "%s:%s" "$Dotroll_User" "$Dotroll_Password" | _base64)
export _H1="Authorization: Basic $_dotroll_auth"
#response=$(_get "https://api.dotroll.com/domains/zone/$ep")
if [ "$m" != "GET" ]; then
_debug data "$data"
response="$(_post "$data" "https://api.dotroll.com/domains/zone/$ep" "" "$m")"
else
response=$(_get "https://api.dotroll.com/domains/zone/$ep")
fi
if [ "$?" != "0" ]; then
_err "error $ep"
return 1
fi
_debug response "$response"
return 0
}
@scr34m
Copy link
Author

scr34m commented Jun 6, 2023

Ahh látom én hibásan account conf használtam a domain szintű beállítás helyett, szuper de ez annyira nem is nagy módosítás összeségében.

@scr34m
Copy link
Author

scr34m commented Jun 6, 2023

@gnanet mergelve, köszi

@gnanet
Copy link

gnanet commented Jun 6, 2023

Ahh látom én hibásan account conf használtam a domain szintű beállítás helyett, szuper de ez annyira nem is nagy módosítás összeségében.

nem hibáztál, a legtöbb dns plugin így működik, csak tudod: "olyan hiba/helyzet nem létezik amit a gina nem szopott be"

@gnanet
Copy link

gnanet commented Jun 6, 2023

Ezt ugye benne hagytad?

@koceka kiegészítése

@scr34m
Copy link
Author

scr34m commented Jun 6, 2023

Nem mert azt a commitod kiszedte de most berakom újra :)

@koceka
Copy link

koceka commented Jun 7, 2023

Gyorsan visszaszívtam, mert nem tuti. Ugyan a szkript látszólag megjavul tőle és nem dob hibát, de a rekord nem törlődik.
A scripttől függetlenül nálatok amúgy működik az API rendesen? Nem igazán tudok törölni, próbáltam manuál módszerekkel is (postman-nel) és habár rekordokat hozzáadni gond nélkül tudok vele, de törölni azzal sem.

@gnanet
Copy link

gnanet commented Jun 7, 2023

Azt amit én hasznalok es nemreg mergelte @scr34m azt par honapja már folyamatos wildcard sslekhez hasznalom es nem lattam hogy gondja kett volna

@gnanet
Copy link

gnanet commented Jun 9, 2023

@scr34m @koceka rájöttem miért nem jó nálam a törlés (mert nekem is 404 jön rá):
alaphiba, hogy ha már url-encode-ot használok, ugyanúgy mint a md5 és más hash-eknél is, az echo alapban rátesz egy sortörést, tehát az lesz a gond, hogy a modify data egy 0a ra végződik, amit echo -n -el kikapcsolhatunk:

  # modified records_list
  modify=$(echo -n "$records_list" | _url_encode)

És igazából csodálom, hogy az új hozzáadásánál nem pánikol rá erre a new-linera pedig az url-encode mindkét esetben a végére odatette a new-line-t

@gnanet
Copy link

gnanet commented Jun 9, 2023

Ezzel igazán az a bajom, hogy egy tr -d ' ' | tr -d "\n" egyértelműen a szóközöket és new-lineokat kitakarítja, mindegy mekkora stringről volt szó, az xargs alapműködésénél használt echo mint parancs bizonyos hosszúságig működik így alapértelmezésben.

# remove whitespaces
records_list=$(echo "$records_list" | xargs)

Másik megoldás, hogy a beépített funkciók közül több helyen használt normalizeJson-t lehetne bevetni:

_normalizeJson() {
  sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n"
}

Azután már ha json-t kell POST-olni, akkor egyben leszedte a szóközöket és sortörést, ezt url_encode-olni már gond nélkül lehetne.

@scr34m
Copy link
Author

scr34m commented Jun 9, 2023

Hát szerintem ha most ezt tudod tesztelni a _normalizeJson-val kellene menni mivel azért alakították ki, hogy ilyen eseteket kezeljenek.

@gnanet
Copy link

gnanet commented Jun 9, 2023

Hát szerintem ha most ezt tudod tesztelni a _normalizeJson-val kellene menni mivel azért alakították ki, hogy ilyen eseteket kezeljenek.
@scr34m
Épp május 31-én volt utoljára, de a fork-ban, és a használatban lévő szerveren átírtam _normalizeJson használatára

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment