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.

199 lines
5.1 KiB

  1. #!/usr/bin/env sh
  2. # shellcheck disable=SC2034
  3. dns_desec_info='deSEC.io
  4. Site: desec.readthedocs.io/en/latest/
  5. Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_desec
  6. Options:
  7. DDNSS_Token API Token
  8. Issues: github.com/acmesh-official/acme.sh/issues/2180
  9. Author: Zheng Qian
  10. '
  11. REST_API="https://desec.io/api/v1/domains"
  12. ######## Public functions #####################
  13. #Usage: dns_desec_add _acme-challenge.foobar.dedyn.io "d41d8cd98f00b204e9800998ecf8427e"
  14. dns_desec_add() {
  15. fulldomain=$1
  16. txtvalue=$2
  17. _info "Using desec.io api"
  18. _debug fulldomain "$fulldomain"
  19. _debug txtvalue "$txtvalue"
  20. DEDYN_TOKEN="${DEDYN_TOKEN:-$(_readaccountconf_mutable DEDYN_TOKEN)}"
  21. if [ -z "$DEDYN_TOKEN" ]; then
  22. DEDYN_TOKEN=""
  23. _err "You did not specify DEDYN_TOKEN yet."
  24. _err "Please create your key and try again."
  25. _err "e.g."
  26. _err "export DEDYN_TOKEN=d41d8cd98f00b204e9800998ecf8427e"
  27. return 1
  28. fi
  29. #save the api token to the account conf file.
  30. _saveaccountconf_mutable DEDYN_TOKEN "$DEDYN_TOKEN"
  31. _debug "First detect the root zone"
  32. if ! _get_root "$fulldomain" "$REST_API/"; then
  33. _err "invalid domain"
  34. return 1
  35. fi
  36. _debug _sub_domain "$_sub_domain"
  37. _debug _domain "$_domain"
  38. # Get existing TXT record
  39. _debug "Getting txt records"
  40. txtvalues="\"\\\"$txtvalue\\\"\""
  41. _desec_rest GET "$REST_API/$_domain/rrsets/$_sub_domain/TXT/"
  42. if [ "$_code" = "200" ]; then
  43. oldtxtvalues="$(echo "$response" | _egrep_o "\"records\":\\[\"\\S*\"\\]" | cut -d : -f 2 | tr -d "[]\\\\\"" | sed "s/,/ /g")"
  44. _debug "existing TXT found"
  45. _debug oldtxtvalues "$oldtxtvalues"
  46. if [ -n "$oldtxtvalues" ]; then
  47. for oldtxtvalue in $oldtxtvalues; do
  48. txtvalues="$txtvalues, \"\\\"$oldtxtvalue\\\"\""
  49. done
  50. fi
  51. fi
  52. _debug txtvalues "$txtvalues"
  53. _info "Adding record"
  54. body="[{\"subname\":\"$_sub_domain\", \"type\":\"TXT\", \"records\":[$txtvalues], \"ttl\":3600}]"
  55. if _desec_rest PUT "$REST_API/$_domain/rrsets/" "$body"; then
  56. if _contains "$response" "$txtvalue"; then
  57. _info "Added, OK"
  58. return 0
  59. else
  60. _err "Add txt record error."
  61. return 1
  62. fi
  63. fi
  64. _err "Add txt record error."
  65. return 1
  66. }
  67. #Usage: fulldomain txtvalue
  68. #Remove the txt record after validation.
  69. dns_desec_rm() {
  70. fulldomain=$1
  71. txtvalue=$2
  72. _info "Using desec.io api"
  73. _debug fulldomain "$fulldomain"
  74. _debug txtvalue "$txtvalue"
  75. DEDYN_TOKEN="${DEDYN_TOKEN:-$(_readaccountconf_mutable DEDYN_TOKEN)}"
  76. if [ -z "$DEDYN_TOKEN" ]; then
  77. DEDYN_TOKEN=""
  78. _err "You did not specify DEDYN_TOKEN yet."
  79. _err "Please create your key and try again."
  80. _err "e.g."
  81. _err "export DEDYN_TOKEN=d41d8cd98f00b204e9800998ecf8427e"
  82. return 1
  83. fi
  84. _debug "First detect the root zone"
  85. if ! _get_root "$fulldomain" "$REST_API/"; then
  86. _err "invalid domain"
  87. return 1
  88. fi
  89. _debug _sub_domain "$_sub_domain"
  90. _debug _domain "$_domain"
  91. # Get existing TXT record
  92. _debug "Getting txt records"
  93. txtvalues=""
  94. _desec_rest GET "$REST_API/$_domain/rrsets/$_sub_domain/TXT/"
  95. if [ "$_code" = "200" ]; then
  96. oldtxtvalues="$(echo "$response" | _egrep_o "\"records\":\\[\"\\S*\"\\]" | cut -d : -f 2 | tr -d "[]\\\\\"" | sed "s/,/ /g")"
  97. _debug "existing TXT found"
  98. _debug oldtxtvalues "$oldtxtvalues"
  99. if [ -n "$oldtxtvalues" ]; then
  100. for oldtxtvalue in $oldtxtvalues; do
  101. if [ "$txtvalue" != "$oldtxtvalue" ]; then
  102. txtvalues="$txtvalues, \"\\\"$oldtxtvalue\\\"\""
  103. fi
  104. done
  105. fi
  106. fi
  107. txtvalues="$(echo "$txtvalues" | cut -c3-)"
  108. _debug txtvalues "$txtvalues"
  109. _info "Deleting record"
  110. body="[{\"subname\":\"$_sub_domain\", \"type\":\"TXT\", \"records\":[$txtvalues], \"ttl\":3600}]"
  111. _desec_rest PUT "$REST_API/$_domain/rrsets/" "$body"
  112. if [ "$_code" = "200" ]; then
  113. _info "Deleted, OK"
  114. return 0
  115. fi
  116. _err "Delete txt record error."
  117. return 1
  118. }
  119. #################### Private functions below ##################################
  120. _desec_rest() {
  121. m="$1"
  122. ep="$2"
  123. data="$3"
  124. export _H1="Authorization: Token $DEDYN_TOKEN"
  125. export _H2="Accept: application/json"
  126. export _H3="Content-Type: application/json"
  127. if [ "$m" != "GET" ]; then
  128. _secure_debug2 data "$data"
  129. response="$(_post "$data" "$ep" "" "$m")"
  130. else
  131. response="$(_get "$ep")"
  132. fi
  133. _ret="$?"
  134. _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
  135. _debug "http response code $_code"
  136. _secure_debug2 response "$response"
  137. if [ "$_ret" != "0" ]; then
  138. _err "error $ep"
  139. return 1
  140. fi
  141. response="$(printf "%s" "$response" | _normalizeJson)"
  142. return 0
  143. }
  144. #_acme-challenge.www.domain.com
  145. #returns
  146. # _sub_domain=_acme-challenge.www
  147. # _domain=domain.com
  148. _get_root() {
  149. domain="$1"
  150. ep="$2"
  151. i=2
  152. p=1
  153. while true; do
  154. h=$(printf "%s" "$domain" | cut -d . -f $i-100)
  155. _debug h "$h"
  156. if [ -z "$h" ]; then
  157. #not valid
  158. return 1
  159. fi
  160. if ! _desec_rest GET "$ep"; then
  161. return 1
  162. fi
  163. if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
  164. _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
  165. _domain=$h
  166. return 0
  167. fi
  168. p=$i
  169. i=$(_math "$i" + 1)
  170. done
  171. return 1
  172. }