-
-
Save scr34m/c7af866d9c3e0c4bc5850d651c59b770 to your computer and use it in GitHub Desktop.
#!/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 | |
} |
Igen az RM nem lett itt implementálva és elírás amit fent írsz.
Nem elírás, amikor lekéred a $record -ot, az a grep séma nem veszi bele a JSON element lezáró } -ját. Amikor a sed ben a $record}
áll akkor az így jelenik meg:
"9999999":{"name":"_acme-challenge.DOMAIN.","type":"TXT","ttl":"3600","txtdata":"DNS-TOKEN"}
Ha kihagyom a } -ot,akkor ez lesz:
"9999999":{"name":"_acme-challenge.DOMAIN.","type":"TXT","ttl":"3600","txtdata":"DNS-TOKEN"
És a JSON szerkezethibás lesz.
Egyenlőre még API lekérdezés és a műveletek eredményének stringként kiírás szintjén prototípus van meg, de bizakodó vagyok. ;)
@scr34m az alábbi változásokra vetnél egy pillantást?
--- dns_dotroll.sh 2021-07-03 05:24:46.432577041 +0200
+++ dns_dotroll.sh 2021-09-16 06:26:47.853243691 +0200
@@ -8,6 +8,10 @@
fulldomain=$1
txtvalue=$2
+ _info "Adding TXT record using dotroll API"
+ _debug fulldomain "$fulldomain"
+ _debug txtvalue "$txtvalue"
+
Dotroll_User="${Dotroll_User:-$(_readaccountconf_mutable Dotroll_User)}"
Dotroll_Password="${Dotroll_Password:-$(_readaccountconf_mutable Dotroll_Password)}"
if [ -z "$Dotroll_User" ] || [ -z "$Dotroll_Password" ]; then
@@ -43,15 +47,11 @@
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")
- record=$(echo $records_list | _egrep_o ",\"[0-9]+\"\:{*\"name\":\"$fulldomain\.\"[^}]*")
- _debug record $record
- if [ ! -z "$record" ]; then
- records_list=$(echo "$records_list" | sed "s/$record}//")
- fi
-
+ # unchanged records_list
modify=$(echo "$records_list" | _url_encode)
new=$(echo '[{"name": "'${fulldomain}'.", "type": "TXT", "ttl": 3600, "txtdata": "'${txtvalue}'"}]' | _url_encode)
@@ -67,11 +67,84 @@
return 0
}
+
+# Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_dotroll_rm() {
fulldomain=$1
txtvalue=$2
- #todo
+ _info "Removing TXT record using dotroll API"
+ _debug fulldomain "$fulldomain"
+ _debug txtvalue "$txtvalue"
+
+ Dotroll_User="${Dotroll_User:-$(_readaccountconf_mutable Dotroll_User)}"
+ Dotroll_Password="${Dotroll_Password:-$(_readaccountconf_mutable Dotroll_Password)}"
+ if [ -z "$Dotroll_User" ] || [ -z "$Dotroll_Password" ]; then
+ Dotroll_User=""
+ Dotroll_Password=""
+ _err "You don't specify dotroll user accounts."
+ _err "Please create you key and try again."
+ return 1
+ fi
+
+ #save the user and password to the account conf file.
+ _saveaccountconf_mutable Dotroll_User "$Dotroll_User"
+ _saveaccountconf_mutable 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 "$_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
+
+ # modified records_list
+ modify=$(echo "$records_list" | _url_encode)
+
+ # URL-param 'modify' only!
+ _dotroll_rest "$_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
Úgy gondolom ezekkel a módosításokkal működni fog.
Ránézésre parádés 🎺
Pár nap múlva kiderül, hogy sikerült-e a módositás, aztán küldöm egyben a módosított scriptet
Tegnap reggel egy wildcard megújitás cronból sikerrel lefutott, tehát a módosítások működtek. @scr34m emailben mehet a script ?
Jöhet igen, köszi!
@koceka kiegészítése
@scr34m a wildcard megújítás aztán megint nemjött ösze, plusz van hogy ugyanazon telepítésben több különböző dotroll fiókban vannak domainek, és a wildcard igénylésnél horror méretű zónába kell hozzááadni majd letörölni a TXT rekordot. néhány hete ezért átnéztem a scriptet, az eredmény egy POST képes, a dotroll adatokat a domain konfigjába mentő változat lett.
forkolom, aztán lesz egy diff a mostani állapothoz, remélem könnyen mergelhető lesz
@scr34m hát igen ezt picit nagyobb változás lett:
https://gist.github.com/gnanet/0f78f81afbed91b6235b8a7c4eed1681/revisions#diff-5ebc9433f9e54ab61c2019176a868fbc5146de6dfaeea3732df6e3ec69096c5f
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.
@gnanet mergelve, köszi
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"
Ezt ugye benne hagytad?
@koceka kiegészítése
Nem mert azt a commitod kiszedte de most berakom újra :)
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.
Azt amit én hasznalok es nemreg mergelte @scr34m azt par honapja már folyamatos wildcard sslekhez hasznalom es nem lattam hogy gondja kett volna
@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
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.
Hát szerintem ha most ezt tudod tesztelni a _normalizeJson-val kellene menni mivel azért alakították ki, hogy ilyen eseteket kezeljenek.
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
Igen az RM nem lett itt implementálva és elírás amit fent írsz.