]>
Commit | Line | Data |
---|---|---|
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 | ||
13 | IONOS_API="https://api.hosting.ionos.com/dns" | |
14 | IONOS_ROUTE_ZONES="/v1/zones" | |
15 | ||
22f7ac22 | 16 | IONOS_TXT_TTL=60 # minimum accepted by API |
a00046f9 LB |
17 | IONOS_TXT_PRIO=10 |
18 | ||
19 | dns_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 | ||
48 | dns_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 | } |