]> git.proxmox.com Git - mirror_acme.sh.git/blame - dnsapi/dns_ionos.sh
dnsapi/ionos: Fixes for Solaris
[mirror_acme.sh.git] / dnsapi / dns_ionos.sh
CommitLineData
a00046f9
LB
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
13IONOS_API="https://api.hosting.ionos.com/dns"
14IONOS_ROUTE_ZONES="/v1/zones"
15
22f7ac22 16IONOS_TXT_TTL=60 # minimum accepted by API
a00046f9
LB
17IONOS_TXT_PRIO=10
18
19dns_ionos_add() {
20 fulldomain=$1
21 txtvalue=$2
22
d21e6235
LB
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"
a00046f9 33
d21e6235
LB
34 if [ "$_existing_records" ]; then
35 _body="[$_new_record,$_existing_records]"
36 else
37 _body="[$_new_record]"
38 fi
a00046f9
LB
39
40 if _ionos_rest PATCH "$IONOS_ROUTE_ZONES/$_zone_id" "$_body" && [ -z "$response" ]; then
22f7ac22 41 _info "TXT record has been created successfully."
a00046f9
LB
42 return 0
43 fi
44
45 return 1
46}
47
48dns_ionos_rm() {
49 fulldomain=$1
50 txtvalue=$2
51
d21e6235
LB
52 if ! _ionos_init; then
53 return 1
54 fi
a00046f9 55
d21e6235 56 if ! _ionos_get_record "$fulldomain" "$_zone_id" "$txtvalue"; then
a00046f9
LB
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
22f7ac22 62 _info "TXT record has been deleted successfully."
a00046f9
LB
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)}"
22f7ac22 72
a00046f9
LB
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=2
96 p=1
97
98 if _ionos_rest GET "$IONOS_ROUTE_ZONES"; then
d21e6235 99 response="$(echo "$response" | tr -d "\n")"
a00046f9
LB
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
a9d88301 107 _zone="$(echo "$response" | _egrep_o "\"name\":\"$h\".*\}")"
a00046f9 108 if [ "$_zone" ]; then
a9d88301 109 _zone_id=$(printf "%s\n" "$_zone" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
a00046f9
LB
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
d21e6235
LB
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
a9d88301 135 _existing_records="$(printf "%s\n" "$response" | _egrep_o "\"records\":\[.*\]" | _head_n 1 | cut -d '[' -f 2 | sed 's/]//')"
d21e6235
LB
136 fi
137}
138
a00046f9
LB
139_ionos_get_record() {
140 fulldomain=$1
141 zone_id=$2
d21e6235 142 txtrecord=$3
a00046f9
LB
143
144 if _ionos_rest GET "$IONOS_ROUTE_ZONES/$zone_id?recordName=$fulldomain&recordType=TXT"; then
22f7ac22 145 response="$(echo "$response" | tr -d "\n")"
a00046f9 146
a9d88301 147 _record="$(echo "$response" | _egrep_o "\"name\":\"$fulldomain\"[^\}]*\"type\":\"TXT\"[^\}]*\"content\":\"\\\\\"$txtrecord\\\\\"\".*\}")"
a00046f9 148 if [ "$_record" ]; then
a9d88301 149 _record_id=$(printf "%s\n" "$_record" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
22f7ac22
LB
150
151 return 0
a00046f9
LB
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}