You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
5.2 KiB

  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. ## DO_DOMAIN_START="3"
  12. ## start of the digital ocean dns base domain from the LEFT
  13. ## (EG: one.two.three.four.five.com -> one.two & three.four.five.com)
  14. ##
  15. ##################### Public functions #####################
  16. ## Create the text record for validation.
  17. ## Usage: fulldomain txtvalue
  18. ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
  19. dns_digitalocean_add() {
  20. fulldomain=$1
  21. txtvalue=$2
  22. _info "Using digitalocean dns validation - add record"
  23. _debug fulldomain "$fulldomain"
  24. _debug txtvalue "$txtvalue"
  25. _debug DO_DOMAIN_START "$DO_DOMAIN_START"
  26. ## split the domain for DO API
  27. if ! _get_base_domain "$fulldomain" "$DO_DOMAIN_START"; then
  28. _err "invalid domain or split"
  29. return 1
  30. fi
  31. _debug _sub_domain "$_sub_domain"
  32. _debug _domain "$_domain"
  33. ## Set the header with our post type and key auth key
  34. export _H1="Content-Type: application/json"
  35. export _H2="Authorization: Bearer $DO_API_KEY"
  36. PURL='https://api.digitalocean.com/v2/domains/'$_domain'/records'
  37. PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'"}'
  38. _debug PURL "$PURL"
  39. _debug PBODY "$PBODY"
  40. ## the create request - post
  41. ## args: BODY, URL, [need64, httpmethod]
  42. response="$(_post "$PBODY" "$PURL")"
  43. ## check response (sort of)
  44. if [ "$?" != "0" ]; then
  45. _err "error in response: $response"
  46. return 1
  47. fi
  48. _debug response "$response"
  49. ## finished correctly
  50. return 0
  51. }
  52. ## Remove the txt record after validation.
  53. ## Usage: fulldomain txtvalue
  54. ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
  55. dns_digitalocean_rm() {
  56. fulldomain=$1
  57. txtvalue=$2
  58. _info "Using digitalocean dns validation - remove record"
  59. _debug fulldomain "$fulldomain"
  60. _debug txtvalue "$txtvalue"
  61. _debug DO_DOMAIN_START "$DO_DOMAIN_START"
  62. ## split the domain for DO API
  63. if ! _get_base_domain "$fulldomain" "$DO_DOMAIN_START"; then
  64. _err "invalid domain or split in remove"
  65. return 1
  66. fi
  67. _debug _sub_domain "$_sub_domain"
  68. _debug _domain "$_domain"
  69. ## Set the header with our post type and key auth key
  70. export _H1="Content-Type: application/json"
  71. export _H2="Authorization: Bearer $DO_API_KEY"
  72. ## get URL for the list of domains
  73. ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
  74. GURL="https://api.digitalocean.com/v2/domains/$_domain/records"
  75. ## while we dont have a record ID we keep going
  76. while [ -z "$record" ]; do
  77. ## 1) get the URL
  78. ## the create request - get
  79. ## args: URL, [onlyheader, timeout]
  80. domain_list="$(_get "$GURL")"
  81. ## 2) find record
  82. ## check for what we are looing for: "type":"A","name":"$_sub_domain"
  83. record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*\d+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")"
  84. ## 3) check record and get next page
  85. if [ -z "$record" ]; then
  86. ## find the next page if we dont have a match
  87. nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=\d+")"
  88. if [ -z "$nextpage" ]; then
  89. _err "no record and no nextpage in digital ocean DNS removal"
  90. return 1
  91. fi
  92. _debug nextpage "$nextpage"
  93. GURL="$nextpage"
  94. fi
  95. ## we break out of the loop when we have a record
  96. done
  97. ## we found the record
  98. rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*\d+" | _egrep_o "\d+")"
  99. _debug rec_id "$rec_id"
  100. ## delete the record
  101. ## delete URL for removing the one we dont want
  102. DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id"
  103. ## the create request - delete
  104. ## args: BODY, URL, [need64, httpmethod]
  105. response="$(_post "" "$DURL" "" "DELETE")"
  106. ## check response (sort of)
  107. if [ "$?" != "0" ]; then
  108. _err "error in remove response: $response"
  109. return 1
  110. fi
  111. _debug response "$response"
  112. ## finished correctly
  113. return 0
  114. }
  115. ##################### Private functions below #####################
  116. ## Split the domain provided at "base_domain_start_position" from the FRONT
  117. ## USAGE: fulldomain base_domain_start_position
  118. ## EG: "_acme-challenge.two.three.four.domain.com" "3"
  119. ## returns
  120. ## _sub_domain="_acme-challenge.two"
  121. ## _domain="three.four.domain.com"
  122. _get_base_domain() {
  123. # args
  124. domain=$1
  125. dom_point=$2
  126. sub_point=$(_math "$dom_point" - 1)
  127. _debug "split domain" "$domain"
  128. _debug "split dom_point" "$dom_point"
  129. _debug "split sub_point" "$sub_point"
  130. # domain max length - 253
  131. MAX_DOM=255
  132. ## cut in half and check
  133. _domain=$(printf "%s" "$domain" | cut -d . -f "$dom_point"-"$MAX_DOM")
  134. _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$sub_point")
  135. if [ -z "$_domain" ]; then
  136. ## not valid
  137. _err "invalid split location"
  138. return 1
  139. fi
  140. if [ -z "$_sub_domain" ]; then
  141. ## not valid
  142. _err "invalid split location"
  143. return 1
  144. fi
  145. _debug "split _domain" "$_domain"
  146. _debug "split _sub_domain" "$_sub_domain"
  147. ## all ok
  148. return 0
  149. }