]> git.proxmox.com Git - mirror_acme.sh.git/blob - dnsapi/dns_bunny.sh
Merge pull request #4531 from NCDGHA/bugfix/issue_4530_fix_http_status_503
[mirror_acme.sh.git] / dnsapi / dns_bunny.sh
1 #!/usr/bin/env sh
2
3 ## Will be called by acme.sh to add the TXT record via the Bunny DNS API.
4 ## returns 0 means success, otherwise error.
5
6 ## Author: nosilver4u <nosilver4u at ewww.io>
7 ## GitHub: https://github.com/nosilver4u/acme.sh
8
9 ##
10 ## Environment Variables Required:
11 ##
12 ## BUNNY_API_KEY="75310dc4-ca77-9ac3-9a19-f6355db573b49ce92ae1-2655-3ebd-61ac-3a3ae34834cc"
13 ##
14
15 ##################### Public functions #####################
16
17 ## Create the text record for validation.
18 ## Usage: fulldomain txtvalue
19 ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
20 dns_bunny_add() {
21 fulldomain="$(echo "$1" | _lower_case)"
22 txtvalue=$2
23
24 BUNNY_API_KEY="${BUNNY_API_KEY:-$(_readaccountconf_mutable BUNNY_API_KEY)}"
25 # Check if API Key is set
26 if [ -z "$BUNNY_API_KEY" ]; then
27 BUNNY_API_KEY=""
28 _err "You did not specify Bunny.net API key."
29 _err "Please export BUNNY_API_KEY and try again."
30 return 1
31 fi
32
33 _info "Using Bunny.net dns validation - add record"
34 _debug fulldomain "$fulldomain"
35 _debug txtvalue "$txtvalue"
36
37 ## save the env vars (key and domain split location) for later automated use
38 _saveaccountconf_mutable BUNNY_API_KEY "$BUNNY_API_KEY"
39
40 ## split the domain for Bunny API
41 if ! _get_base_domain "$fulldomain"; then
42 _err "domain not found in your account for addition"
43 return 1
44 fi
45 _debug _sub_domain "$_sub_domain"
46 _debug _domain "$_domain"
47 _debug _domain_id "$_domain_id"
48
49 ## Set the header with our post type and auth key
50 export _H1="Accept: application/json"
51 export _H2="AccessKey: $BUNNY_API_KEY"
52 export _H3="Content-Type: application/json"
53 PURL="https://api.bunny.net/dnszone/$_domain_id/records"
54 PBODY='{"Id":'$_domain_id',"Type":3,"Name":"'$_sub_domain'","Value":"'$txtvalue'","ttl":120}'
55
56 _debug PURL "$PURL"
57 _debug PBODY "$PBODY"
58
59 ## the create request - POST
60 ## args: BODY, URL, [need64, httpmethod]
61 response="$(_post "$PBODY" "$PURL" "" "PUT")"
62
63 ## check response
64 if [ "$?" != "0" ]; then
65 _err "error in response: $response"
66 return 1
67 fi
68 _debug2 response "$response"
69
70 ## finished correctly
71 return 0
72 }
73
74 ## Remove the txt record after validation.
75 ## Usage: fulldomain txtvalue
76 ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
77 dns_bunny_rm() {
78 fulldomain="$(echo "$1" | _lower_case)"
79 txtvalue=$2
80
81 BUNNY_API_KEY="${BUNNY_API_KEY:-$(_readaccountconf_mutable BUNNY_API_KEY)}"
82 # Check if API Key Exists
83 if [ -z "$BUNNY_API_KEY" ]; then
84 BUNNY_API_KEY=""
85 _err "You did not specify Bunny.net API key."
86 _err "Please export BUNNY_API_KEY and try again."
87 return 1
88 fi
89
90 _info "Using Bunny.net dns validation - remove record"
91 _debug fulldomain "$fulldomain"
92 _debug txtvalue "$txtvalue"
93
94 ## split the domain for Bunny API
95 if ! _get_base_domain "$fulldomain"; then
96 _err "Domain not found in your account for TXT record removal"
97 return 1
98 fi
99 _debug _sub_domain "$_sub_domain"
100 _debug _domain "$_domain"
101 _debug _domain_id "$_domain_id"
102
103 ## Set the header with our post type and key auth key
104 export _H1="Accept: application/json"
105 export _H2="AccessKey: $BUNNY_API_KEY"
106 ## get URL for the list of DNS records
107 GURL="https://api.bunny.net/dnszone/$_domain_id"
108
109 ## 1) Get the domain/zone records
110 ## the fetch request - GET
111 ## args: URL, [onlyheader, timeout]
112 domain_list="$(_get "$GURL")"
113
114 ## check response
115 if [ "$?" != "0" ]; then
116 _err "error in domain_list response: $domain_list"
117 return 1
118 fi
119 _debug2 domain_list "$domain_list"
120
121 ## 2) search through records
122 ## check for what we are looking for: "Type":3,"Value":"$txtvalue","Name":"$_sub_domain"
123 record="$(echo "$domain_list" | _egrep_o "\"Id\"\s*\:\s*\"*[0-9]+\"*,\s*\"Type\"[^}]*\"Value\"\s*\:\s*\"$txtvalue\"[^}]*\"Name\"\s*\:\s*\"$_sub_domain\"")"
124
125 if [ -n "$record" ]; then
126
127 ## We found records
128 rec_ids="$(echo "$record" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
129 _debug rec_ids "$rec_ids"
130 if [ -n "$rec_ids" ]; then
131 echo "$rec_ids" | while IFS= read -r rec_id; do
132 ## delete the record
133 ## delete URL for removing the one we dont want
134 DURL="https://api.bunny.net/dnszone/$_domain_id/records/$rec_id"
135
136 ## the removal request - DELETE
137 ## args: BODY, URL, [need64, httpmethod]
138 response="$(_post "" "$DURL" "" "DELETE")"
139
140 ## check response (sort of)
141 if [ "$?" != "0" ]; then
142 _err "error in remove response: $response"
143 return 1
144 fi
145 _debug2 response "$response"
146
147 done
148 fi
149 fi
150
151 ## finished correctly
152 return 0
153 }
154
155 ##################### Private functions below #####################
156
157 ## Split the domain provided into the "base domain" and the "start prefix".
158 ## This function searches for the longest subdomain in your account
159 ## for the full domain given and splits it into the base domain (zone)
160 ## and the prefix/record to be added/removed
161 ## USAGE: fulldomain
162 ## EG: "_acme-challenge.two.three.four.domain.com"
163 ## returns
164 ## _sub_domain="_acme-challenge.two"
165 ## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists
166 ## _domain_id=234
167 ## if only "domain.com" exists it will return
168 ## _sub_domain="_acme-challenge.two.three.four"
169 ## _domain="domain.com"
170 ## _domain_id=234
171 _get_base_domain() {
172 # args
173 fulldomain="$(echo "$1" | _lower_case)"
174 _debug fulldomain "$fulldomain"
175
176 # domain max legal length = 253
177 MAX_DOM=255
178 page=1
179
180 ## get a list of domains for the account to check thru
181 ## Set the headers
182 export _H1="Accept: application/json"
183 export _H2="AccessKey: $BUNNY_API_KEY"
184 _debug BUNNY_API_KEY "$BUNNY_API_KEY"
185 ## get URL for the list of domains
186 ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
187 DOMURL="https://api.bunny.net/dnszone"
188
189 ## while we dont have a matching domain we keep going
190 while [ -z "$found" ]; do
191 ## get the domain list (current page)
192 domain_list="$(_get "$DOMURL")"
193
194 ## check response
195 if [ "$?" != "0" ]; then
196 _err "error in domain_list response: $domain_list"
197 return 1
198 fi
199 _debug2 domain_list "$domain_list"
200
201 i=1
202 while [ $i -gt 0 ]; do
203 ## get next longest domain
204 _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
205 ## check we got something back from our cut (or are we at the end)
206 if [ -z "$_domain" ]; then
207 break
208 fi
209 ## we got part of a domain back - grep it out
210 found="$(echo "$domain_list" | _egrep_o "\"Id\"\s*:\s*\"*[0-9]+\"*,\s*\"Domain\"\s*\:\s*\"$_domain\"")"
211 ## check if it exists
212 if [ -n "$found" ]; then
213 ## exists - exit loop returning the parts
214 sub_point=$(_math $i - 1)
215 _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
216 _domain_id="$(echo "$found" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
217 _debug _domain_id "$_domain_id"
218 _debug _domain "$_domain"
219 _debug _sub_domain "$_sub_domain"
220 found=""
221 return 0
222 fi
223 ## increment cut point $i
224 i=$(_math $i + 1)
225 done
226
227 if [ -z "$found" ]; then
228 page=$(_math $page + 1)
229 nextpage="https://api.bunny.net/dnszone?page=$page"
230 ## Find the next page if we don't have a match.
231 hasnextpage="$(echo "$domain_list" | _egrep_o "\"HasMoreItems\"\s*:\s*true")"
232 if [ -z "$hasnextpage" ]; then
233 _err "No record and no nextpage in Bunny.net domain search."
234 found=""
235 return 1
236 fi
237 _debug2 nextpage "$nextpage"
238 DOMURL="$nextpage"
239 fi
240
241 done
242
243 ## We went through the entire domain zone list and didn't find one that matched.
244 ## If we ever get here, something is broken in the code...
245 _err "Domain not found in Bunny.net account, but we should never get here!"
246 found=""
247 return 1
248 }