dns_dgon.sh 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #!/usr/bin/env sh
  2. ## Will be called by acme.sh to add the txt record to your api system.
  3. ## returns 0 means success, otherwise error.
  4. ## Author: thewer <github at thewer.com>
  5. ## GitHub: https://github.com/gitwer/acme.sh
  6. ##
  7. ## Environment Variables Required:
  8. ##
  9. ## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc"
  10. ##
  11. ##################### Public functions #####################
  12. ## Create the text record for validation.
  13. ## Usage: fulldomain txtvalue
  14. ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
  15. dns_dgon_add() {
  16. fulldomain="$(echo "$1" | _lower_case)"
  17. txtvalue=$2
  18. DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}"
  19. # Check if API Key Exist
  20. if [ -z "$DO_API_KEY" ]; then
  21. DO_API_KEY=""
  22. _err "You did not specify DigitalOcean API key."
  23. _err "Please export DO_API_KEY and try again."
  24. return 1
  25. fi
  26. _info "Using digitalocean dns validation - add record"
  27. _debug fulldomain "$fulldomain"
  28. _debug txtvalue "$txtvalue"
  29. ## save the env vars (key and domain split location) for later automated use
  30. _saveaccountconf_mutable DO_API_KEY "$DO_API_KEY"
  31. ## split the domain for DO API
  32. if ! _get_base_domain "$fulldomain"; then
  33. _err "domain not found in your account for addition"
  34. return 1
  35. fi
  36. _debug _sub_domain "$_sub_domain"
  37. _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'","ttl":120}'
  43. _debug PURL "$PURL"
  44. _debug PBODY "$PBODY"
  45. ## the create request - post
  46. ## args: BODY, URL, [need64, httpmethod]
  47. response="$(_post "$PBODY" "$PURL")"
  48. ## check response
  49. if [ "$?" != "0" ]; then
  50. _err "error in response: $response"
  51. return 1
  52. fi
  53. _debug2 response "$response"
  54. ## finished correctly
  55. return 0
  56. }
  57. ## Remove the txt record after validation.
  58. ## Usage: fulldomain txtvalue
  59. ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
  60. dns_dgon_rm() {
  61. fulldomain="$(echo "$1" | _lower_case)"
  62. txtvalue=$2
  63. DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}"
  64. # Check if API Key Exist
  65. if [ -z "$DO_API_KEY" ]; then
  66. DO_API_KEY=""
  67. _err "You did not specify DigitalOcean API key."
  68. _err "Please export DO_API_KEY and try again."
  69. return 1
  70. fi
  71. _info "Using digitalocean dns validation - remove record"
  72. _debug fulldomain "$fulldomain"
  73. _debug txtvalue "$txtvalue"
  74. ## split the domain for DO API
  75. if ! _get_base_domain "$fulldomain"; then
  76. _err "domain not found in your account for removal"
  77. return 1
  78. fi
  79. _debug _sub_domain "$_sub_domain"
  80. _debug _domain "$_domain"
  81. ## Set the header with our post type and key auth key
  82. export _H1="Content-Type: application/json"
  83. export _H2="Authorization: Bearer $DO_API_KEY"
  84. ## get URL for the list of domains
  85. ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
  86. GURL="https://api.digitalocean.com/v2/domains/$_domain/records"
  87. ## Get all the matching records
  88. while true; do
  89. ## 1) get the URL
  90. ## the create request - get
  91. ## args: URL, [onlyheader, timeout]
  92. domain_list="$(_get "$GURL")"
  93. ## check response
  94. if [ "$?" != "0" ]; then
  95. _err "error in domain_list response: $domain_list"
  96. return 1
  97. fi
  98. _debug2 domain_list "$domain_list"
  99. ## 2) find records
  100. ## check for what we are looking for: "type":"A","name":"$_sub_domain"
  101. record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[0-9]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")"
  102. if [ ! -z "$record" ]; then
  103. ## we found records
  104. rec_ids="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
  105. _debug rec_ids "$rec_ids"
  106. if [ ! -z "$rec_ids" ]; then
  107. echo "$rec_ids" | while IFS= read -r rec_id; do
  108. ## delete the record
  109. ## delete URL for removing the one we dont want
  110. DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id"
  111. ## the create request - delete
  112. ## args: BODY, URL, [need64, httpmethod]
  113. response="$(_post "" "$DURL" "" "DELETE")"
  114. ## check response (sort of)
  115. if [ "$?" != "0" ]; then
  116. _err "error in remove response: $response"
  117. return 1
  118. fi
  119. _debug2 response "$response"
  120. done
  121. fi
  122. fi
  123. ## 3) find the next page
  124. nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")"
  125. if [ -z "$nextpage" ]; then
  126. break
  127. fi
  128. _debug2 nextpage "$nextpage"
  129. GURL="$nextpage"
  130. done
  131. ## finished correctly
  132. return 0
  133. }
  134. ##################### 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
  139. ## USAGE: fulldomain
  140. ## EG: "_acme-challenge.two.three.four.domain.com"
  141. ## returns
  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"
  147. _get_base_domain() {
  148. # args
  149. fulldomain="$(echo "$1" | _lower_case)"
  150. _debug fulldomain "$fulldomain"
  151. # domain max legal length = 253
  152. MAX_DOM=255
  153. ## get a list of domains for the account to check thru
  154. ## Set the headers
  155. export _H1="Content-Type: application/json"
  156. export _H2="Authorization: Bearer $DO_API_KEY"
  157. _debug DO_API_KEY "$DO_API_KEY"
  158. ## get URL for the list of domains
  159. ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
  160. DOMURL="https://api.digitalocean.com/v2/domains"
  161. ## while we dont have a matching domain we keep going
  162. while [ -z "$found" ]; do
  163. ## get the domain list (current page)
  164. domain_list="$(_get "$DOMURL")"
  165. ## check response
  166. if [ "$?" != "0" ]; then
  167. _err "error in domain_list response: $domain_list"
  168. return 1
  169. fi
  170. _debug2 domain_list "$domain_list"
  171. ## for each shortening of our $fulldomain, check if it exists in the $domain_list
  172. ## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge"
  173. i=2
  174. while [ $i -gt 0 ]; do
  175. ## get next longest domain
  176. _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
  177. ## check we got something back from our cut (or are we at the end)
  178. if [ -z "$_domain" ]; then
  179. break
  180. fi
  181. ## we got part of a domain back - grep it out
  182. found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")"
  183. ## check if it exists
  184. if [ ! -z "$found" ]; then
  185. ## exists - exit loop returning the parts
  186. sub_point=$(_math $i - 1)
  187. _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
  188. _debug _domain "$_domain"
  189. _debug _sub_domain "$_sub_domain"
  190. return 0
  191. fi
  192. ## increment cut point $i
  193. i=$(_math $i + 1)
  194. done
  195. if [ -z "$found" ]; then
  196. ## find the next page if we dont have a match
  197. nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")"
  198. if [ -z "$nextpage" ]; then
  199. _err "no record and no nextpage in digital ocean DNS removal"
  200. return 1
  201. fi
  202. _debug2 nextpage "$nextpage"
  203. DOMURL="$nextpage"
  204. fi
  205. done
  206. ## we went through the entire domain zone list and dint find one that matched
  207. ## doesnt look like we can add in the record
  208. _err "domain not found in DigitalOcean account, but we should never get here"
  209. return 1
  210. }