Skip to content

Commit 46a8764

Browse files
authored
Merge pull request #3959 from Eagle3386/master
Add ArtFiles.de DNS API plugin
2 parents 9bb58e4 + 66a68ed commit 46a8764

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed

dnsapi/dns_artfiles.sh

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
#!/usr/bin/env sh
2+
3+
################################################################################
4+
# ACME.sh 3rd party DNS API plugin for ArtFiles.de
5+
################################################################################
6+
# Author: Martin Arndt, https://troublezone.net/
7+
# Released: 2022-02-27
8+
# Issues: https://github.com/acmesh-official/acme.sh/issues/4718
9+
################################################################################
10+
# Usage:
11+
# 1. export AF_API_USERNAME='api12345678'
12+
# 2. export AF_API_PASSWORD='apiPassword'
13+
# 3. acme.sh --issue -d example.com --dns dns_artfiles
14+
################################################################################
15+
16+
########## API configuration ###################################################
17+
18+
AF_API_SUCCESS='status":"OK'
19+
AF_URL_DCP='https://dcp.c.artfiles.de/api/'
20+
AF_URL_DNS=${AF_URL_DCP}'dns/{*}_dns.html?domain='
21+
AF_URL_DOMAINS=${AF_URL_DCP}'domain/get_domains.html'
22+
23+
########## Public functions ####################################################
24+
25+
# Adds a new TXT record for given ACME challenge value & domain.
26+
# Usage: dns_artfiles_add _acme-challenge.www.example.com "ACME challenge value"
27+
dns_artfiles_add() {
28+
domain="$1"
29+
txtValue="$2"
30+
_info 'Using ArtFiles.de DNS addition API…'
31+
_debug 'Domain' "$domain"
32+
_debug 'txtValue' "$txtValue"
33+
34+
_set_credentials
35+
_saveaccountconf_mutable 'AF_API_USERNAME' "$AF_API_USERNAME"
36+
_saveaccountconf_mutable 'AF_API_PASSWORD' "$AF_API_PASSWORD"
37+
38+
_set_headers
39+
_get_zone "$domain"
40+
_dns 'GET'
41+
if ! _contains "$response" 'TXT'; then
42+
_err 'Retrieving TXT records failed.'
43+
44+
return 1
45+
fi
46+
47+
_clean_records
48+
_dns 'SET' "$(printf -- '%s\n_acme-challenge "%s"' "$response" "$txtValue")"
49+
if ! _contains "$response" "$AF_API_SUCCESS"; then
50+
_err 'Adding ACME challenge value failed.'
51+
52+
return 1
53+
fi
54+
}
55+
56+
# Removes the existing TXT record for given ACME challenge value & domain.
57+
# Usage: dns_artfiles_rm _acme-challenge.www.example.com "ACME challenge value"
58+
dns_artfiles_rm() {
59+
domain="$1"
60+
txtValue="$2"
61+
_info 'Using ArtFiles.de DNS removal API…'
62+
_debug 'Domain' "$domain"
63+
_debug 'txtValue' "$txtValue"
64+
65+
_set_credentials
66+
_set_headers
67+
_get_zone "$domain"
68+
if ! _dns 'GET'; then
69+
return 1
70+
fi
71+
72+
if ! _contains "$response" "$txtValue"; then
73+
_err 'Retrieved TXT records are missing given ACME challenge value.'
74+
75+
return 1
76+
fi
77+
78+
_clean_records
79+
response="$(printf -- '%s' "$response" | sed '/_acme-challenge "'"$txtValue"'"/d')"
80+
_dns 'SET' "$response"
81+
if ! _contains "$response" "$AF_API_SUCCESS"; then
82+
_err 'Removing ACME challenge value failed.'
83+
84+
return 1
85+
fi
86+
}
87+
88+
########## Private functions ###################################################
89+
90+
# Cleans awful TXT records response of ArtFiles's API & pretty prints it.
91+
# Usage: _clean_records
92+
_clean_records() {
93+
_info 'Cleaning TXT records…'
94+
# Extract TXT part, strip trailing quote sign (ACME.sh API guidelines forbid
95+
# usage of SED's GNU extensions, hence couldn't omit it via regex), strip '\'
96+
# from '\"' & turn '\n' into real LF characters.
97+
# Yup, awful API to use - but that's all we got to get this working, so… ;)
98+
_debug2 'Raw ' "$response"
99+
response="$(printf -- '%s' "$response" | sed 's/^.*TXT":"\([^}]*\).*$/\1/;s/,".*$//;s/.$//;s/\\"/"/g;s/\\n/\n/g')"
100+
_debug2 'Clean' "$response"
101+
}
102+
103+
# Executes an HTTP GET or POST request for getting or setting DNS records,
104+
# containing given payload upon POST.
105+
# Usage: _dns [GET | SET] [payload]
106+
_dns() {
107+
_info 'Executing HTTP request…'
108+
action="$1"
109+
payload="$(printf -- '%s' "$2" | _url_encode)"
110+
url="$(printf -- '%s%s' "$AF_URL_DNS" "$domain" | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/')"
111+
112+
if [ "$action" = 'SET' ]; then
113+
_debug2 'Payload' "$payload"
114+
response="$(_post '' "$url&TXT=$payload" '' 'POST' 'application/x-www-form-urlencoded')"
115+
else
116+
response="$(_get "$url" '' 10)"
117+
fi
118+
119+
if ! _contains "$response" "$AF_API_SUCCESS"; then
120+
_err "DNS API error: $response"
121+
122+
return 1
123+
fi
124+
125+
_debug 'Response' "$response"
126+
127+
return 0
128+
}
129+
130+
# Gets the root domain zone for given domain.
131+
# Usage: _get_zone _acme-challenge.www.example.com
132+
_get_zone() {
133+
fqdn="$1"
134+
domains="$(_get "$AF_URL_DOMAINS" '' 10)"
135+
_info 'Getting domain zone…'
136+
_debug2 'FQDN' "$fqdn"
137+
_debug2 'Domains' "$domains"
138+
139+
while _contains "$fqdn" "."; do
140+
if _contains "$domains" "$fqdn"; then
141+
domain="$fqdn"
142+
_info "Found root domain zone: $domain"
143+
break
144+
else
145+
fqdn="${fqdn#*.}"
146+
_debug2 'FQDN' "$fqdn"
147+
fi
148+
done
149+
150+
if [ "$domain" = "$fqdn" ]; then
151+
return 0
152+
fi
153+
154+
_err 'Couldn'\''t find root domain zone.'
155+
156+
return 1
157+
}
158+
159+
# Sets the credentials for accessing ArtFiles's API
160+
# Usage: _set_credentials
161+
_set_credentials() {
162+
_info 'Setting credentials…'
163+
AF_API_USERNAME="${AF_API_USERNAME:-$(_readaccountconf_mutable AF_API_USERNAME)}"
164+
AF_API_PASSWORD="${AF_API_PASSWORD:-$(_readaccountconf_mutable AF_API_PASSWORD)}"
165+
if [ -z "$AF_API_USERNAME" ] || [ -z "$AF_API_PASSWORD" ]; then
166+
_err 'Missing ArtFiles.de username and/or password.'
167+
_err 'Please ensure both are set via export command & try again.'
168+
169+
return 1
170+
fi
171+
}
172+
173+
# Adds the HTTP Authorization & Content-Type headers to a follow-up request.
174+
# Usage: _set_headers
175+
_set_headers() {
176+
_info 'Setting headers…'
177+
encoded="$(printf -- '%s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)"
178+
export _H1="Authorization: Basic $encoded"
179+
export _H2='Content-Type: application/json'
180+
}

0 commit comments

Comments
 (0)