3 ## Will be called by acme.sh to add the txt record to your api system.
4 ## returns 0 means success, otherwise error.
6 ## Author: thewer <github at thewer.com>
7 ## GitHub: https://github.com/gitwer/acme.sh
10 ## Environment Variables Required:
12 ## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc"
15 ##################### Public functions #####################
17 ## Create the text record for validation.
18 ## Usage: fulldomain txtvalue
19 ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
21 fulldomain
="$(echo "$1" | _lower_case)"
24 DO_API_KEY
="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}"
25 # Check if API Key Exists
26 if [ -z "$DO_API_KEY" ]; then
28 _err
"You did not specify DigitalOcean API key."
29 _err
"Please export DO_API_KEY and try again."
33 _info
"Using digitalocean dns validation - add record"
34 _debug fulldomain
"$fulldomain"
35 _debug txtvalue
"$txtvalue"
37 ## save the env vars (key and domain split location) for later automated use
38 _saveaccountconf_mutable DO_API_KEY
"$DO_API_KEY"
40 ## split the domain for DO API
41 if ! _get_base_domain
"$fulldomain"; then
42 _err
"domain not found in your account for addition"
45 _debug _sub_domain
"$_sub_domain"
46 _debug _domain
"$_domain"
48 ## Set the header with our post type and key auth key
49 export _H1
="Content-Type: application/json"
50 export _H2
="Authorization: Bearer $DO_API_KEY"
51 PURL
='https://api.digitalocean.com/v2/domains/'$_domain'/records'
52 PBODY
='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'","ttl":120}'
57 ## the create request - post
58 ## args: BODY, URL, [need64, httpmethod]
59 response
="$(_post "$PBODY" "$PURL")"
62 if [ "$?" != "0" ]; then
63 _err
"error in response: $response"
66 _debug2 response
"$response"
72 ## Remove the txt record after validation.
73 ## Usage: fulldomain txtvalue
74 ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
76 fulldomain
="$(echo "$1" | _lower_case)"
79 DO_API_KEY
="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}"
80 # Check if API Key Exists
81 if [ -z "$DO_API_KEY" ]; then
83 _err
"You did not specify DigitalOcean API key."
84 _err
"Please export DO_API_KEY and try again."
88 _info
"Using digitalocean dns validation - remove record"
89 _debug fulldomain
"$fulldomain"
90 _debug txtvalue
"$txtvalue"
92 ## split the domain for DO API
93 if ! _get_base_domain
"$fulldomain"; then
94 _err
"domain not found in your account for removal"
97 _debug _sub_domain
"$_sub_domain"
98 _debug _domain
"$_domain"
100 ## Set the header with our post type and key auth key
101 export _H1
="Content-Type: application/json"
102 export _H2
="Authorization: Bearer $DO_API_KEY"
103 ## get URL for the list of domains
104 ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
105 GURL
="https://api.digitalocean.com/v2/domains/$_domain/records"
107 ## Get all the matching records
110 ## the create request - get
111 ## args: URL, [onlyheader, timeout]
112 domain_list
="$(_get "$GURL")"
115 if [ "$?" != "0" ]; then
116 _err
"error in domain_list response: $domain_list"
119 _debug2 domain_list
"$domain_list"
122 ## check for what we are looking for: "type":"A","name":"$_sub_domain"
123 record
="$(echo "$domain_list" | _egrep_o "\"id
\"\s
*\
:\s
*\"*[0-9]+\"*[^
}]*\"name
\"\s
*\
:\s
*\"$_sub_domain\"[^
}]*\"data
\"\s
*\
:\s
*\"$txtvalue\"")"
125 if [ -n "$record" ]; then
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
133 ## delete URL for removing the one we dont want
134 DURL
="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id"
136 ## the create request - delete
137 ## args: BODY, URL, [need64, httpmethod]
138 response
="$(_post "" "$DURL" "" "DELETE
")"
140 ## check response (sort of)
141 if [ "$?" != "0" ]; then
142 _err
"error in remove response: $response"
145 _debug2 response
"$response"
151 ## 3) find the next page
152 nextpage
="$(echo "$domain_list" | _egrep_o "\"links
\".
*" | _egrep_o "\"next
\".
*" | _egrep_o "http.
*page\
=[0-9]+")"
153 if [ -z "$nextpage" ]; then
156 _debug2 nextpage
"$nextpage"
161 ## finished correctly
165 ##################### Private functions below #####################
167 ## Split the domain provided into the "bade domain" and the "start prefix".
168 ## This function searches for the longest subdomain in your account
169 ## for the full domain given and splits it into the base domain (zone)
170 ## and the prefix/record to be added/removed
172 ## EG: "_acme-challenge.two.three.four.domain.com"
174 ## _sub_domain="_acme-challenge.two"
175 ## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists
176 ## if only "domain.com" exists it will return
177 ## _sub_domain="_acme-challenge.two.three.four"
178 ## _domain="domain.com"
181 fulldomain
="$(echo "$1" | _lower_case)"
182 _debug fulldomain
"$fulldomain"
184 # domain max legal length = 253
187 ## get a list of domains for the account to check thru
189 export _H1
="Content-Type: application/json"
190 export _H2
="Authorization: Bearer $DO_API_KEY"
191 _debug DO_API_KEY
"$DO_API_KEY"
192 ## get URL for the list of domains
193 ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
194 DOMURL
="https://api.digitalocean.com/v2/domains"
196 ## while we dont have a matching domain we keep going
197 while [ -z "$found" ]; do
198 ## get the domain list (current page)
199 domain_list
="$(_get "$DOMURL")"
202 if [ "$?" != "0" ]; then
203 _err
"error in domain_list response: $domain_list"
206 _debug2 domain_list
"$domain_list"
208 ## for each shortening of our $fulldomain, check if it exists in the $domain_list
209 ## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge"
211 while [ $i -gt 0 ]; do
212 ## get next longest domain
213 _domain
=$
(printf "%s" "$fulldomain" | cut
-d .
-f "$i"-"$MAX_DOM")
214 ## check we got something back from our cut (or are we at the end)
215 if [ -z "$_domain" ]; then
218 ## we got part of a domain back - grep it out
219 found
="$(echo "$domain_list" | _egrep_o "\"name
\"\s
*\
:\s
*\"$_domain\"")"
220 ## check if it exists
221 if [ -n "$found" ]; then
222 ## exists - exit loop returning the parts
223 sub_point
=$
(_math
$i - 1)
224 _sub_domain
=$
(printf "%s" "$fulldomain" | cut
-d .
-f 1-"$sub_point")
225 _debug _domain
"$_domain"
226 _debug _sub_domain
"$_sub_domain"
229 ## increment cut point $i
233 if [ -z "$found" ]; then
234 ## find the next page if we dont have a match
235 nextpage
="$(echo "$domain_list" | _egrep_o "\"links
\".
*" | _egrep_o "\"next
\".
*" | _egrep_o "http.
*page\
=[0-9]+")"
236 if [ -z "$nextpage" ]; then
237 _err
"no record and no nextpage in digital ocean DNS removal"
240 _debug2 nextpage
"$nextpage"
246 ## we went through the entire domain zone list and dint find one that matched
247 ## doesnt look like we can add in the record
248 _err
"domain not found in DigitalOcean account, but we should never get here"