dns_bh.sh 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #!/usr/bin/env sh
  2. # shellcheck disable=SC2034
  3. dns_bh_info='Best-Hosting.cz
  4. Site: best-hosting.cz
  5. Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_bh
  6. Options:
  7. BH_API_USER API User identifier.
  8. BH_API_KEY API Secret key.
  9. Issues: github.com/acmesh-official/acme.sh/issues/6854
  10. Author: @heximcz
  11. '
  12. BH_Api="https://best-hosting.cz/api/v1"
  13. ######## Public functions #####################
  14. # Usage: dns_bh_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
  15. dns_bh_add() {
  16. fulldomain=$1
  17. txtvalue=$2
  18. # --- 1. Credentials ---
  19. BH_API_USER="${BH_API_USER:-$(_readaccountconf_mutable BH_API_USER)}"
  20. BH_API_KEY="${BH_API_KEY:-$(_readaccountconf_mutable BH_API_KEY)}"
  21. if [ -z "$BH_API_USER" ] || [ -z "$BH_API_KEY" ]; then
  22. BH_API_USER=""
  23. BH_API_KEY=""
  24. _err "You must specify BH_API_USER and BH_API_KEY."
  25. return 1
  26. fi
  27. _saveaccountconf_mutable BH_API_USER "$BH_API_USER"
  28. _saveaccountconf_mutable BH_API_KEY "$BH_API_KEY"
  29. # --- 2. Add TXT record ---
  30. _info "Adding TXT record for $fulldomain"
  31. json_payload="{\"fulldomain\":\"$fulldomain\",\"txtvalue\":\"$txtvalue\"}"
  32. if ! _bh_rest POST "dns" "$json_payload"; then
  33. _err "Failed to add DNS record."
  34. return 1
  35. fi
  36. _norm_add=$(printf "%s" "$response" | tr -d '[:space:]')
  37. if ! _contains "$_norm_add" '"status":"success"'; then
  38. _err "API error: $response"
  39. return 1
  40. fi
  41. record_id=$(printf "%s" "$_norm_add" | _egrep_o '"id":[0-9]+' | cut -d':' -f2)
  42. _debug record_id "$record_id"
  43. if [ -z "$record_id" ]; then
  44. _err "Could not parse record ID from response."
  45. return 1
  46. fi
  47. # Sanitize key — replace dots and hyphens with underscores
  48. _conf_key=$(printf "%s" "BH_record_ids_${fulldomain}" | tr '.-' '_')
  49. # Wildcard support: store space-separated list of IDs
  50. # First call stores "111", second call stores "111 222"
  51. _existing_ids=$(_readdomainconf "$_conf_key")
  52. if [ -z "$_existing_ids" ]; then
  53. _savedomainconf "$_conf_key" "$record_id"
  54. else
  55. _savedomainconf "$_conf_key" "$_existing_ids $record_id"
  56. fi
  57. _info "DNS TXT record added successfully."
  58. return 0
  59. }
  60. # Usage: dns_bh_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
  61. dns_bh_rm() {
  62. fulldomain=$1
  63. txtvalue=$2
  64. # --- 1. Credentials ---
  65. BH_API_USER="${BH_API_USER:-$(_readaccountconf_mutable BH_API_USER)}"
  66. BH_API_KEY="${BH_API_KEY:-$(_readaccountconf_mutable BH_API_KEY)}"
  67. if [ -z "$BH_API_USER" ] || [ -z "$BH_API_KEY" ]; then
  68. BH_API_USER=""
  69. BH_API_KEY=""
  70. _err "You must specify BH_API_USER and BH_API_KEY."
  71. return 1
  72. fi
  73. # Sanitize key — same as in add
  74. _conf_key=$(printf "%s" "BH_record_ids_${fulldomain}" | tr '.-' '_')
  75. # --- 2. Load stored record ID(s) ---
  76. _existing_ids=$(_readdomainconf "$_conf_key")
  77. _debug _existing_ids "$_existing_ids"
  78. if [ -z "$_existing_ids" ]; then
  79. _err "Could not find record ID for $fulldomain."
  80. return 1
  81. fi
  82. record_id=""
  83. _remaining_ids=""
  84. # Find the record ID that matches both the name and txtvalue
  85. for _id in $_existing_ids; do
  86. if ! _bh_rest GET "dns/$_id"; then
  87. _debug "Failed to query record id $_id, skipping."
  88. # Keep it in the list so a later run can try again
  89. if [ -z "$_remaining_ids" ]; then
  90. _remaining_ids="$_id"
  91. else
  92. _remaining_ids="$_remaining_ids $_id"
  93. fi
  94. continue
  95. fi
  96. _match_name=0
  97. _match_content=0
  98. _norm_response=$(printf "%s" "$response" | tr -d '[:space:]')
  99. case "$_norm_response" in
  100. *"\"name\":\"$fulldomain\""*)
  101. _match_name=1
  102. ;;
  103. esac
  104. case "$_norm_response" in
  105. *"\"content\":\"$txtvalue\""*)
  106. _match_content=1
  107. ;;
  108. esac
  109. if [ "$_match_name" -eq 1 ] && [ "$_match_content" -eq 1 ]; then
  110. record_id="$_id"
  111. _debug "Matched record id" "$record_id"
  112. # Do not add this ID to _remaining_ids; it will be deleted
  113. continue
  114. fi
  115. # Not a match — keep ID for potential future cleanups
  116. if [ -z "$_remaining_ids" ]; then
  117. _remaining_ids="$_id"
  118. else
  119. _remaining_ids="$_remaining_ids $_id"
  120. fi
  121. done
  122. if [ -z "$record_id" ]; then
  123. _err "Could not find matching TXT record for $fulldomain with the given value."
  124. return 1
  125. fi
  126. # --- 3. Delete record ---
  127. _info "Removing TXT record for $fulldomain"
  128. if ! _bh_rest DELETE "dns/$record_id"; then
  129. _err "Failed to remove DNS record."
  130. return 1
  131. fi
  132. # Update stored list — remove used ID
  133. if [ -z "$_remaining_ids" ]; then
  134. _cleardomainconf "$_conf_key"
  135. else
  136. _savedomainconf "$_conf_key" "$_remaining_ids"
  137. fi
  138. _info "DNS TXT record removed successfully."
  139. return 0
  140. }
  141. #################### Private functions #####################
  142. _bh_rest() {
  143. m="$1"
  144. ep="$2"
  145. data="$3"
  146. _debug "$ep"
  147. _credentials="$(printf "%s:%s" "$BH_API_USER" "$BH_API_KEY" | _base64)"
  148. export _H1="Authorization: Basic $_credentials"
  149. export _H2="Content-Type: application/json"
  150. export _H3="Accept: application/json"
  151. if [ "$m" = "GET" ]; then
  152. response="$(_get "$BH_Api/$ep")"
  153. else
  154. _debug data "$data"
  155. response="$(_post "$data" "$BH_Api/$ep" "" "$m")"
  156. fi
  157. if [ "$?" != "0" ]; then
  158. _err "Error calling $m $BH_Api/$ep"
  159. return 1
  160. fi
  161. _debug2 response "$response"
  162. return 0
  163. }