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)"
23 _info
"Using digitalocean dns validation - add record"
24 _debug fulldomain
"$fulldomain"
25 _debug txtvalue
"$txtvalue"
27 ## save the env vars (key and domain split location) for later automated use
28 _saveaccountconf DO_API_KEY
"$DO_API_KEY"
30 ## split the domain for DO API
31 if ! _get_base_domain
"$fulldomain"; then
32 _err
"domain not found in your account for addition"
35 _debug _sub_domain
"$_sub_domain"
36 _debug _domain
"$_domain"
38 ## Set the header with our post type and key auth key
39 export _H1
="Content-Type: application/json"
40 export _H2
="Authorization: Bearer $DO_API_KEY"
41 PURL
='https://api.digitalocean.com/v2/domains/'$_domain'/records'
42 PBODY
='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'"}'
47 ## the create request - post
48 ## args: BODY, URL, [need64, httpmethod]
49 response
="$(_post "$PBODY" "$PURL")"
52 if [ "$?" != "0" ]; then
53 _err
"error in response: $response"
56 _debug2 response
"$response"
62 ## Remove the txt record after validation.
63 ## Usage: fulldomain txtvalue
64 ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
66 fulldomain
="$(echo "$1" | _lower_case)"
68 _info
"Using digitalocean dns validation - remove record"
69 _debug fulldomain
"$fulldomain"
70 _debug txtvalue
"$txtvalue"
72 ## split the domain for DO API
73 if ! _get_base_domain
"$fulldomain"; then
74 _err
"domain not found in your account for removal"
77 _debug _sub_domain
"$_sub_domain"
78 _debug _domain
"$_domain"
80 ## Set the header with our post type and key auth key
81 export _H1
="Content-Type: application/json"
82 export _H2
="Authorization: Bearer $DO_API_KEY"
83 ## get URL for the list of domains
84 ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
85 GURL
="https://api.digitalocean.com/v2/domains/$_domain/records"
87 ## while we dont have a record ID we keep going
88 while [ -z "$record" ]; do
90 ## the create request - get
91 ## args: URL, [onlyheader, timeout]
92 domain_list
="$(_get "$GURL")"
94 ## check for what we are looing for: "type":"A","name":"$_sub_domain"
95 record
="$(echo "$domain_list" | _egrep_o "\"id
\"\s
*\
:\s
*\"*\d
+\"*[^
}]*\"name
\"\s
*\
:\s
*\"$_sub_domain\"[^
}]*\"data
\"\s
*\
:\s
*\"$txtvalue\"")"
96 ## 3) check record and get next page
97 if [ -z "$record" ]; then
98 ## find the next page if we dont have a match
99 nextpage
="$(echo "$domain_list" | _egrep_o "\"links
\".
*" | _egrep_o "\"next
\".
*" | _egrep_o "http.
*page\
=\d
+")"
100 if [ -z "$nextpage" ]; then
101 _err
"no record and no nextpage in digital ocean DNS removal"
104 _debug2 nextpage
"$nextpage"
107 ## we break out of the loop when we have a record
110 ## we found the record
111 rec_id
="$(echo "$record" | _egrep_o "id
\"\s
*\
:\s
*\"*\d
+" | _egrep_o "\d
+")"
112 _debug rec_id
"$rec_id"
115 ## delete URL for removing the one we dont want
116 DURL
="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id"
118 ## the create request - delete
119 ## args: BODY, URL, [need64, httpmethod]
120 response
="$(_post "" "$DURL" "" "DELETE
")"
122 ## check response (sort of)
123 if [ "$?" != "0" ]; then
124 _err
"error in remove response: $response"
127 _debug2 response
"$response"
129 ## finished correctly
133 ##################### Private functions below #####################
135 ## Split the domain provided into the "bade domain" and the "start prefix".
136 ## This function searches for the longest subdomain in your account
137 ## for the full domain given and splits it into the base domain (zone)
138 ## and the prefix/record to be added/removed
140 ## EG: "_acme-challenge.two.three.four.domain.com"
142 ## _sub_domain="_acme-challenge.two"
143 ## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists
144 ## if only "domain.com" exists it will return
145 ## _sub_domain="_acme-challenge.two.three.four"
146 ## _domain="domain.com"
149 fulldomain
="$(echo "$1" | tr '[:upper:]' '[:lower:]')"
150 _debug fulldomain
"$fulldomain"
152 # domain max legal length = 253
155 ## get a list of domains for the account to check thru
157 export _H1
="Content-Type: application/json"
158 export _H2
="Authorization: Bearer $DO_API_KEY"
159 _debug DO_API_KEY
"$DO_API_KEY"
160 ## get URL for the list of domains
161 ## havent seen this request paginated, tested with 18 domains (more requires manual requests with DO)
162 DOMURL
="https://api.digitalocean.com/v2/domains"
164 ## get the domain list (DO gives basically a full XFER!)
165 domain_list
="$(_get "$DOMURL")"
168 if [ "$?" != "0" ]; then
169 _err
"error in domain_list response: $domain_list"
172 _debug2 domain_list
"$domain_list"
174 ## for each shortening of our $fulldomain, check if it exists in the $domain_list
175 ## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge"
177 while [ $i -gt 0 ]; do
178 ## get next longest domain
179 _domain
=$
(printf "%s" "$fulldomain" | cut
-d .
-f "$i"-"$MAX_DOM")
180 ## check we got something back from our cut (or are we at the end)
181 if [ -z "$_domain" ]; then
182 ## we got to the end of the domain - invalid domain
183 _err
"domain not found in DigitalOcean account"
186 ## we got part of a domain back - grep it out
187 found
="$(echo "$domain_list" | _egrep_o "\"name
\"\s
*\
:\s
*\"$_domain\"")"
188 ## check if it exists
189 if [ ! -z "$found" ]; then
190 ## exists - exit loop returning the parts
191 sub_point
=$
(_math
$i - 1)
192 _sub_domain
=$
(printf "%s" "$fulldomain" | cut
-d .
-f 1-"$sub_point")
193 _debug _domain
"$_domain"
194 _debug _sub_domain
"$_sub_domain"
197 ## increment cut point $i
201 ## we went through the entire domain zone list and dint find one that matched
202 ## doesnt look like we can add in the record
203 _err
"domain not found in DigitalOcean account, but we should never get here"