]> git.proxmox.com Git - mirror_acme.sh.git/blob - dnsapi/dns_ionos.sh
e6bd5000b2564dba519d9467a9f4c659388300a6
[mirror_acme.sh.git] / dnsapi / dns_ionos.sh
1 #!/usr/bin/env sh
2
3 # Supports IONOS DNS API Beta v1.0.0
4 #
5 # Usage:
6 # Export IONOS_PREFIX and IONOS_SECRET before calling acme.sh:
7 #
8 # $ export IONOS_PREFIX="..."
9 # $ export IONOS_SECRET="..."
10 #
11 # $ acme.sh --issue --dns dns_ionos ...
12
13 IONOS_API="https://api.hosting.ionos.com/dns"
14 IONOS_ROUTE_ZONES="/v1/zones"
15
16 IONOS_TXT_TTL=60 # minimum accepted by API
17 IONOS_TXT_PRIO=10
18
19 dns_ionos_add() {
20 fulldomain=$1
21 txtvalue=$2
22
23 if ! _ionos_init; then
24 return 1
25 fi
26
27 _new_record="{\"name\":\"$_sub_domain.$_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":$IONOS_TXT_TTL,\"prio\":$IONOS_TXT_PRIO,\"disabled\":false}"
28
29 # As no POST route is supported by the API, check for existing records and include them in the PATCH request in order not delete them.
30 # This is required to support ACME v2 wildcard certificate creation, where two TXT records for the same domain name are created.
31
32 _ionos_get_existing_records "$fulldomain" "$_zone_id"
33
34 if [ "$_existing_records" ]; then
35 _body="[$_new_record,$_existing_records]"
36 else
37 _body="[$_new_record]"
38 fi
39
40 if _ionos_rest PATCH "$IONOS_ROUTE_ZONES/$_zone_id" "$_body" && [ -z "$response" ]; then
41 _info "TXT record has been created successfully."
42 return 0
43 fi
44
45 return 1
46 }
47
48 dns_ionos_rm() {
49 fulldomain=$1
50 txtvalue=$2
51
52 if ! _ionos_init; then
53 return 1
54 fi
55
56 if ! _ionos_get_record "$fulldomain" "$_zone_id" "$txtvalue"; then
57 _err "Could not find _acme-challenge TXT record."
58 return 1
59 fi
60
61 if _ionos_rest DELETE "$IONOS_ROUTE_ZONES/$_zone_id/records/$_record_id" && [ -z "$response" ]; then
62 _info "TXT record has been deleted successfully."
63 return 0
64 fi
65
66 return 1
67 }
68
69 _ionos_init() {
70 IONOS_PREFIX="${IONOS_PREFIX:-$(_readaccountconf_mutable IONOS_PREFIX)}"
71 IONOS_SECRET="${IONOS_SECRET:-$(_readaccountconf_mutable IONOS_SECRET)}"
72
73 if [ -z "$IONOS_PREFIX" ] || [ -z "$IONOS_SECRET" ]; then
74 _err "You didn't specify an IONOS api prefix and secret yet."
75 _err "Read https://beta.developer.hosting.ionos.de/docs/getstarted to learn how to get a prefix and secret."
76 _err ""
77 _err "Then set them before calling acme.sh:"
78 _err "\$ export IONOS_PREFIX=\"...\""
79 _err "\$ export IONOS_SECRET=\"...\""
80 _err "\$ acme.sh --issue -d ... --dns dns_ionos"
81 return 1
82 fi
83
84 _saveaccountconf_mutable IONOS_PREFIX "$IONOS_PREFIX"
85 _saveaccountconf_mutable IONOS_SECRET "$IONOS_SECRET"
86
87 if ! _get_root "$fulldomain"; then
88 _err "Cannot find this domain in your IONOS account."
89 return 1
90 fi
91 }
92
93 _get_root() {
94 domain=$1
95 i=1
96 p=1
97
98 if _ionos_rest GET "$IONOS_ROUTE_ZONES"; then
99 response="$(echo "$response" | tr -d "\n")"
100
101 while true; do
102 h=$(printf "%s" "$domain" | cut -d . -f $i-100)
103 if [ -z "$h" ]; then
104 return 1
105 fi
106
107 _zone="$(echo "$response" | _egrep_o "\"name\":\"$h\".*\}")"
108 if [ "$_zone" ]; then
109 _zone_id=$(printf "%s\n" "$_zone" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
110 if [ "$_zone_id" ]; then
111 _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
112 _domain=$h
113
114 return 0
115 fi
116
117 return 1
118 fi
119
120 p=$i
121 i=$(_math "$i" + 1)
122 done
123 fi
124
125 return 1
126 }
127
128 _ionos_get_existing_records() {
129 fulldomain=$1
130 zone_id=$2
131
132 if _ionos_rest GET "$IONOS_ROUTE_ZONES/$zone_id?recordName=$fulldomain&recordType=TXT"; then
133 response="$(echo "$response" | tr -d "\n")"
134
135 _existing_records="$(printf "%s\n" "$response" | _egrep_o "\"records\":\[.*\]" | _head_n 1 | cut -d '[' -f 2 | sed 's/]//')"
136 fi
137 }
138
139 _ionos_get_record() {
140 fulldomain=$1
141 zone_id=$2
142 txtrecord=$3
143
144 if _ionos_rest GET "$IONOS_ROUTE_ZONES/$zone_id?recordName=$fulldomain&recordType=TXT"; then
145 response="$(echo "$response" | tr -d "\n")"
146
147 _record="$(echo "$response" | _egrep_o "\"name\":\"$fulldomain\"[^\}]*\"type\":\"TXT\"[^\}]*\"content\":\"\\\\\"$txtrecord\\\\\"\".*\}")"
148 if [ "$_record" ]; then
149 _record_id=$(printf "%s\n" "$_record" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
150
151 return 0
152 fi
153 fi
154
155 return 1
156 }
157
158 _ionos_rest() {
159 method="$1"
160 route="$2"
161 data="$3"
162
163 IONOS_API_KEY="$(printf "%s.%s" "$IONOS_PREFIX" "$IONOS_SECRET")"
164
165 export _H1="X-API-Key: $IONOS_API_KEY"
166
167 if [ "$method" != "GET" ]; then
168 export _H2="Accept: application/json"
169 export _H3="Content-Type: application/json"
170
171 response="$(_post "$data" "$IONOS_API$route" "" "$method")"
172 else
173 export _H2="Accept: */*"
174
175 response="$(_get "$IONOS_API$route")"
176 fi
177
178 if [ "$?" != "0" ]; then
179 _err "Error $route"
180 return 1
181 fi
182
183 return 0
184 }