]>
Commit | Line | Data |
---|---|---|
ac690fce | 1 | #!/usr/bin/env sh |
2 | ||
3 | ## Will be called by acme.sh to add the txt record to your api system. | |
4 | ## returns 0 means success, otherwise error. | |
5 | ||
6 | ## Author: thewer <github at thewer.com> | |
7 | ## GitHub: https://github.com/gitwer/acme.sh | |
8 | ||
9 | ## | |
10 | ## Environment Variables Required: | |
11 | ## | |
12 | ## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc" | |
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_dgon_add() { | |
21 | fulldomain="$(echo "$1" | _lower_case)" | |
22 | txtvalue=$2 | |
9c4f7aa6 M |
23 | |
24 | DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}" | |
eca57bee | 25 | # Check if API Key Exists |
9c4f7aa6 M |
26 | if [ -z "$DO_API_KEY" ]; then |
27 | DO_API_KEY="" | |
28 | _err "You did not specify DigitalOcean API key." | |
29 | _err "Please export DO_API_KEY and try again." | |
30 | return 1 | |
31 | fi | |
32 | ||
ac690fce | 33 | _info "Using digitalocean 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 | |
9c4f7aa6 | 38 | _saveaccountconf_mutable DO_API_KEY "$DO_API_KEY" |
ac690fce | 39 | |
40 | ## split the domain for DO 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 | ||
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' | |
9c4f7aa6 | 52 | PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'","ttl":120}' |
ac690fce | 53 | |
54 | _debug PURL "$PURL" | |
55 | _debug PBODY "$PBODY" | |
56 | ||
57 | ## the create request - post | |
58 | ## args: BODY, URL, [need64, httpmethod] | |
59 | response="$(_post "$PBODY" "$PURL")" | |
60 | ||
61 | ## check response | |
62 | if [ "$?" != "0" ]; then | |
63 | _err "error in response: $response" | |
64 | return 1 | |
65 | fi | |
66 | _debug2 response "$response" | |
67 | ||
68 | ## finished correctly | |
69 | return 0 | |
70 | } | |
71 | ||
72 | ## Remove the txt record after validation. | |
73 | ## Usage: fulldomain txtvalue | |
74 | ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs" | |
75 | dns_dgon_rm() { | |
76 | fulldomain="$(echo "$1" | _lower_case)" | |
77 | txtvalue=$2 | |
9c4f7aa6 M |
78 | |
79 | DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}" | |
eca57bee | 80 | # Check if API Key Exists |
9c4f7aa6 M |
81 | if [ -z "$DO_API_KEY" ]; then |
82 | DO_API_KEY="" | |
83 | _err "You did not specify DigitalOcean API key." | |
84 | _err "Please export DO_API_KEY and try again." | |
85 | return 1 | |
86 | fi | |
87 | ||
ac690fce | 88 | _info "Using digitalocean dns validation - remove record" |
89 | _debug fulldomain "$fulldomain" | |
90 | _debug txtvalue "$txtvalue" | |
91 | ||
92 | ## split the domain for DO API | |
93 | if ! _get_base_domain "$fulldomain"; then | |
94 | _err "domain not found in your account for removal" | |
95 | return 1 | |
96 | fi | |
97 | _debug _sub_domain "$_sub_domain" | |
98 | _debug _domain "$_domain" | |
99 | ||
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" | |
106 | ||
5b7cac10 | 107 | ## Get all the matching records |
4a18c45e | 108 | while true; do |
ac690fce | 109 | ## 1) get the URL |
110 | ## the create request - get | |
111 | ## args: URL, [onlyheader, timeout] | |
112 | domain_list="$(_get "$GURL")" | |
5b7cac10 TB |
113 | |
114 | ## check response | |
115 | if [ "$?" != "0" ]; then | |
116 | _err "error in domain_list response: $domain_list" | |
117 | return 1 | |
ac690fce | 118 | fi |
5b7cac10 | 119 | _debug2 domain_list "$domain_list" |
ac690fce | 120 | |
5b7cac10 TB |
121 | ## 2) find records |
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\"")" | |
ac690fce | 124 | |
14089f8c | 125 | if [ -n "$record" ]; then |
5b7cac10 TB |
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" | |
14089f8c | 130 | if [ -n "$rec_ids" ]; then |
4a18c45e | 131 | echo "$rec_ids" | while IFS= read -r rec_id; do |
5b7cac10 TB |
132 | ## delete the record |
133 | ## delete URL for removing the one we dont want | |
134 | DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id" | |
135 | ||
136 | ## the create 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 | |
ac690fce | 150 | |
5b7cac10 TB |
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 | |
154 | break | |
155 | fi | |
156 | _debug2 nextpage "$nextpage" | |
157 | GURL="$nextpage" | |
ac690fce | 158 | |
5b7cac10 | 159 | done |
ac690fce | 160 | |
161 | ## finished correctly | |
162 | return 0 | |
163 | } | |
164 | ||
165 | ##################### Private functions below ##################### | |
166 | ||
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 | |
171 | ## USAGE: fulldomain | |
172 | ## EG: "_acme-challenge.two.three.four.domain.com" | |
173 | ## returns | |
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" | |
179 | _get_base_domain() { | |
180 | # args | |
189a7766 | 181 | fulldomain="$(echo "$1" | _lower_case)" |
ac690fce | 182 | _debug fulldomain "$fulldomain" |
183 | ||
184 | # domain max legal length = 253 | |
185 | MAX_DOM=255 | |
186 | ||
187 | ## get a list of domains for the account to check thru | |
188 | ## Set the headers | |
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 | |
5b7cac10 | 193 | ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}} |
ac690fce | 194 | DOMURL="https://api.digitalocean.com/v2/domains" |
dcc9624c | 195 | found="" |
ac690fce | 196 | |
5b7cac10 TB |
197 | ## while we dont have a matching domain we keep going |
198 | while [ -z "$found" ]; do | |
199 | ## get the domain list (current page) | |
200 | domain_list="$(_get "$DOMURL")" | |
ac690fce | 201 | |
5b7cac10 TB |
202 | ## check response |
203 | if [ "$?" != "0" ]; then | |
204 | _err "error in domain_list response: $domain_list" | |
ac690fce | 205 | return 1 |
206 | fi | |
5b7cac10 TB |
207 | _debug2 domain_list "$domain_list" |
208 | ||
b3df1a2b | 209 | i=1 |
5b7cac10 TB |
210 | while [ $i -gt 0 ]; do |
211 | ## get next longest domain | |
212 | _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM") | |
213 | ## check we got something back from our cut (or are we at the end) | |
214 | if [ -z "$_domain" ]; then | |
215 | break | |
216 | fi | |
217 | ## we got part of a domain back - grep it out | |
218 | found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")" | |
219 | ## check if it exists | |
14089f8c | 220 | if [ -n "$found" ]; then |
5b7cac10 TB |
221 | ## exists - exit loop returning the parts |
222 | sub_point=$(_math $i - 1) | |
223 | _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point") | |
224 | _debug _domain "$_domain" | |
225 | _debug _sub_domain "$_sub_domain" | |
226 | return 0 | |
227 | fi | |
228 | ## increment cut point $i | |
229 | i=$(_math $i + 1) | |
230 | done | |
231 | ||
232 | if [ -z "$found" ]; then | |
233 | ## find the next page if we dont have a match | |
234 | nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")" | |
235 | if [ -z "$nextpage" ]; then | |
236 | _err "no record and no nextpage in digital ocean DNS removal" | |
237 | return 1 | |
238 | fi | |
239 | _debug2 nextpage "$nextpage" | |
240 | DOMURL="$nextpage" | |
ac690fce | 241 | fi |
5b7cac10 | 242 | |
ac690fce | 243 | done |
244 | ||
245 | ## we went through the entire domain zone list and dint find one that matched | |
246 | ## doesnt look like we can add in the record | |
247 | _err "domain not found in DigitalOcean account, but we should never get here" | |
248 | return 1 | |
249 | } |