Skip to content

Commit d0d3dc8

Browse files
nsantorelliNicolas Santorelli
andauthored
Add EuroDNS DNS API plugin (dns_eurodns) (#6903)
Co-authored-by: Nicolas Santorelli <nsantorelli@eurodns.com>
1 parent 923b7c2 commit d0d3dc8

1 file changed

Lines changed: 267 additions & 0 deletions

File tree

dnsapi/dns_eurodns.sh

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
#!/usr/bin/env sh
2+
# shellcheck disable=SC2034
3+
dns_eurodns_info='EuroDNS
4+
Site: eurodns.com
5+
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_eurodns
6+
Options:
7+
EURODNS_APP_ID Application ID
8+
EURODNS_API_KEY API Key
9+
EURODNS_TTL TTL. Default: "600".
10+
Issues: github.com/acmesh-official/acme.sh/issues
11+
Author: Nicolas Santorelli
12+
'
13+
14+
#
15+
# EuroDNS DNS API
16+
#
17+
# EuroDNS API documentation:
18+
# https://docapi.eurodns.com
19+
#
20+
# Usage:
21+
# export EURODNS_APP_ID="your-app-id"
22+
# export EURODNS_API_KEY="your-api-key"
23+
# acme.sh --issue --dns dns_eurodns -d example.com -d *.example.com
24+
#
25+
# The credentials will be saved in ~/.acme.sh/account.conf
26+
#
27+
# Optional:
28+
# export EURODNS_API_URL="https://rest-api.eurodns.com" # Default API URL
29+
# export EURODNS_TTL=600 # Default TTL (minimum 600 for EuroDNS)
30+
#
31+
32+
EURODNS_API_DEFAULT="https://rest-api.eurodns.com"
33+
EURODNS_TTL_DEFAULT=600
34+
35+
######## Public functions #####################
36+
37+
#Usage: dns_eurodns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
38+
dns_eurodns_add() {
39+
fulldomain="$(echo "$1" | _lower_case)"
40+
txtvalue=$2
41+
42+
_info "Using EuroDNS DNS API"
43+
_debug fulldomain "$fulldomain"
44+
_debug txtvalue "$txtvalue"
45+
46+
EURODNS_APP_ID="${EURODNS_APP_ID:-$(_readaccountconf_mutable EURODNS_APP_ID)}"
47+
EURODNS_API_KEY="${EURODNS_API_KEY:-$(_readaccountconf_mutable EURODNS_API_KEY)}"
48+
EURODNS_API_URL="${EURODNS_API_URL:-$(_readaccountconf_mutable EURODNS_API_URL)}"
49+
EURODNS_API_URL="${EURODNS_API_URL:-$EURODNS_API_DEFAULT}"
50+
EURODNS_TTL="${EURODNS_TTL:-$(_readaccountconf_mutable EURODNS_TTL)}"
51+
EURODNS_TTL="${EURODNS_TTL:-$EURODNS_TTL_DEFAULT}"
52+
53+
if [ -z "$EURODNS_APP_ID" ] || [ -z "$EURODNS_API_KEY" ]; then
54+
EURODNS_APP_ID=""
55+
EURODNS_API_KEY=""
56+
_err "You didn't specify EuroDNS App ID and API Key."
57+
_err "Please export EURODNS_APP_ID and EURODNS_API_KEY and try again."
58+
return 1
59+
fi
60+
61+
_saveaccountconf_mutable EURODNS_APP_ID "$EURODNS_APP_ID"
62+
_saveaccountconf_mutable EURODNS_API_KEY "$EURODNS_API_KEY"
63+
if [ "$EURODNS_API_URL" != "$EURODNS_API_DEFAULT" ]; then
64+
_saveaccountconf_mutable EURODNS_API_URL "$EURODNS_API_URL"
65+
fi
66+
if [ "$EURODNS_TTL" != "$EURODNS_TTL_DEFAULT" ]; then
67+
_saveaccountconf_mutable EURODNS_TTL "$EURODNS_TTL"
68+
fi
69+
70+
_debug "First detect the root zone"
71+
if ! _get_root "$fulldomain"; then
72+
_err "Invalid domain"
73+
return 1
74+
fi
75+
_debug _domain "$_domain"
76+
_debug _sub_domain "$_sub_domain"
77+
78+
_info "Adding TXT record"
79+
if _eurodns_add_txt_record "$_domain" "$_sub_domain" "$txtvalue"; then
80+
_info "Added TXT record successfully."
81+
return 0
82+
else
83+
_err "Failed to add TXT record."
84+
return 1
85+
fi
86+
}
87+
88+
#Usage: fulldomain txtvalue
89+
dns_eurodns_rm() {
90+
fulldomain="$(echo "$1" | _lower_case)"
91+
txtvalue=$2
92+
93+
_info "Using EuroDNS DNS API"
94+
_debug fulldomain "$fulldomain"
95+
_debug txtvalue "$txtvalue"
96+
97+
EURODNS_APP_ID="${EURODNS_APP_ID:-$(_readaccountconf_mutable EURODNS_APP_ID)}"
98+
EURODNS_API_KEY="${EURODNS_API_KEY:-$(_readaccountconf_mutable EURODNS_API_KEY)}"
99+
EURODNS_API_URL="${EURODNS_API_URL:-$(_readaccountconf_mutable EURODNS_API_URL)}"
100+
EURODNS_API_URL="${EURODNS_API_URL:-$EURODNS_API_DEFAULT}"
101+
102+
if [ -z "$EURODNS_APP_ID" ] || [ -z "$EURODNS_API_KEY" ]; then
103+
EURODNS_APP_ID=""
104+
EURODNS_API_KEY=""
105+
_err "You didn't specify EuroDNS App ID and API Key."
106+
return 1
107+
fi
108+
109+
_debug "First detect the root zone"
110+
if ! _get_root "$fulldomain"; then
111+
_err "Invalid domain"
112+
return 1
113+
fi
114+
_debug _domain "$_domain"
115+
_debug _sub_domain "$_sub_domain"
116+
117+
_info "Removing TXT record"
118+
if _eurodns_rm_txt_record "$_domain" "$_sub_domain" "$txtvalue"; then
119+
_info "Removed TXT record successfully."
120+
return 0
121+
else
122+
_err "Failed to remove TXT record."
123+
return 1
124+
fi
125+
}
126+
127+
#################### Private functions below ##################################
128+
129+
# _sub_domain=_acme-challenge.www
130+
# _domain=domain.com
131+
_get_root() {
132+
domain=$1
133+
i=1
134+
p=1
135+
136+
while true; do
137+
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
138+
_debug h "$h"
139+
if [ -z "$h" ]; then
140+
return 1
141+
fi
142+
143+
_eurodns_rest GET "dns-zones/$h"
144+
if [ "$?" != "0" ]; then
145+
if [ "$_code" = "404" ]; then
146+
_debug "Zone $h not found, continuing..."
147+
else
148+
_err "API error looking up zone $h"
149+
return 1
150+
fi
151+
p=$i
152+
i=$(_math "$i" + 1)
153+
continue
154+
fi
155+
156+
if _contains "$response" '"name"'; then
157+
if [ "$i" = "1" ]; then
158+
_sub_domain="@"
159+
else
160+
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
161+
fi
162+
_domain=$h
163+
return 0
164+
fi
165+
166+
p=$i
167+
i=$(_math "$i" + 1)
168+
done
169+
170+
return 1
171+
}
172+
173+
_eurodns_add_txt_record() {
174+
domain=$1
175+
subdomain=$2
176+
txtvalue=$3
177+
178+
data='[{"type":"TXT","host":"'"$subdomain"'","rdata":"'"$txtvalue"'","ttl":'"$EURODNS_TTL"'}]'
179+
180+
_debug "Adding TXT record via API"
181+
if _eurodns_rest POST "dns-zones/$domain/dns-records" "$data"; then
182+
if _contains "$response" "$txtvalue"; then
183+
return 0
184+
fi
185+
fi
186+
_err "Failed to add TXT record"
187+
return 1
188+
}
189+
190+
_eurodns_rm_txt_record() {
191+
domain=$1
192+
subdomain=$2
193+
txtvalue=$3
194+
195+
_debug "Getting current zone data for $domain"
196+
197+
if ! _eurodns_rest GET "dns-zones/$domain"; then
198+
_err "Failed to get zone data"
199+
return 1
200+
fi
201+
202+
zone_data=$(echo "$response" | _normalizeJson)
203+
_debug2 zone_data "$zone_data"
204+
205+
# Find the record ID matching our TXT record
206+
record_id=$(echo "$zone_data" | tr '{' '\n' | grep -F '"TXT"' | grep -F "\"$subdomain\"" | grep -F "\"$txtvalue\"" | _egrep_o '"id" *: *[0-9]+' | cut -d : -f 2 | _head_n 1)
207+
_debug record_id "$record_id"
208+
209+
if [ -z "$record_id" ]; then
210+
_info "TXT record not found or already removed"
211+
return 0
212+
fi
213+
214+
_debug "Deleting TXT record $record_id"
215+
if ! _eurodns_rest DELETE "dns-zones/$domain/dns-records/$record_id"; then
216+
_err "Failed to delete TXT record"
217+
return 1
218+
fi
219+
220+
return 0
221+
}
222+
223+
# Usage: _eurodns_rest METHOD ENDPOINT [DATA]
224+
_eurodns_rest() {
225+
method=$1
226+
endpoint=$2
227+
data="$3"
228+
229+
export _H1="X-APP-ID: $EURODNS_APP_ID"
230+
export _H2="X-API-KEY: $EURODNS_API_KEY"
231+
export _H3="Content-Type: application/json"
232+
233+
url="$EURODNS_API_URL/$endpoint"
234+
235+
_debug2 url "$url"
236+
_debug2 method "$method"
237+
_debug2 data "$data"
238+
239+
: >"$HTTP_HEADER"
240+
241+
if [ "$method" = "GET" ]; then
242+
response="$(_get "$url")"
243+
else
244+
response="$(_post "$data" "$url" "" "$method")"
245+
fi
246+
247+
_ret="$?"
248+
unset _H1 _H2 _H3
249+
_debug2 response "$response"
250+
251+
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
252+
_debug2 _code "$_code"
253+
254+
if [ "$_ret" != "0" ]; then
255+
_err "Error calling API: $endpoint"
256+
return 1
257+
fi
258+
259+
if [ "$_code" != "200" ] && [ "$_code" != "201" ] && [ "$_code" != "204" ]; then
260+
if [ "$_code" != "404" ]; then
261+
_err "API error (HTTP $_code): $response"
262+
fi
263+
return 1
264+
fi
265+
266+
return 0
267+
}

0 commit comments

Comments
 (0)