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.

197 lines
4.9 KiB

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