dns_czechia.sh 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #!/usr/bin/env sh
  2. # dns_czechia.sh - CZECHIA.COM/ZONER DNS API for acme.sh (DNS-01)
  3. #
  4. # Documentation: https://api.czechia.com/swagger/index.html
  5. #shellcheck disable=SC2034
  6. dns_czechia_info='[
  7. {"name":"CZ_AuthorizationToken","usage":"Your API token from CZECHIA.COM/Zoner administration.","required":"1"},
  8. {"name":"CZ_Zones","usage":"Managed zones separated by comma or space (e.g. \"example.com\").","required":"1"},
  9. {"name":"CZ_API_BASE","usage":"Defaults to https://api.czechia.com","required":"0"}
  10. ]'
  11. dns_czechia_add() {
  12. fulldomain="$1"
  13. txtvalue="$2"
  14. _debug "dns_czechia_add fulldomain='$fulldomain'"
  15. if [ -z "$fulldomain" ] || [ -z "$txtvalue" ]; then
  16. _err "dns_czechia_add: missing fulldomain or txtvalue"
  17. return 1
  18. fi
  19. _czechia_load_conf || return 1
  20. _current_zone=$(_czechia_pick_zone "$fulldomain")
  21. if [ -z "$_current_zone" ]; then
  22. _err "No matching zone found for $fulldomain. Please check CZ_Zones."
  23. return 1
  24. fi
  25. _cz=$(printf "%s" "$_current_zone" | _lower_case | sed 's/[[:space:]]//g; s/\.$//')
  26. _tk=$(printf "%s" "$CZ_AuthorizationToken" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')
  27. if [ -z "$_cz" ] || [ -z "$_tk" ]; then
  28. _err "Missing zone or CZ_AuthorizationToken."
  29. return 1
  30. fi
  31. _url="$CZ_API_BASE/api/DNS/$_cz/TXT"
  32. _fd=$(printf "%s" "$fulldomain" | _lower_case | sed 's/\.$//')
  33. if [ "$_fd" = "$_cz" ]; then
  34. _h="@"
  35. else
  36. # Remove the literal ".<zone>" suffix from _fd, if present
  37. _h=${_fd%."$_cz"}
  38. [ "$_h" = "$_fd" ] && _h="@"
  39. fi
  40. [ -z "$_h" ] && _h="@"
  41. _info "Adding TXT record for $_h in zone $_cz"
  42. _h_esc=$(printf "%s" "$_h" | sed 's/\\/\\\\/g; s/"/\\"/g')
  43. _txt_esc=$(printf "%s" "$txtvalue" | sed 's/\\/\\\\/g; s/"/\\"/g')
  44. _body="{\"hostName\":\"$_h_esc\",\"text\":\"$_txt_esc\",\"ttl\":300,\"publishZone\":1}"
  45. _debug "URL: $_url"
  46. _debug "Body: $_body"
  47. export _H1="Content-Type: application/json"
  48. export _H2="AuthorizationToken: $_tk"
  49. _res="$(_post "$_body" "$_url" "" "POST")"
  50. _post_exit="$?"
  51. _debug2 "Response: $_res"
  52. if [ "$_post_exit" -ne 0 ]; then
  53. _err "API request failed. exit code $_post_exit"
  54. return 1
  55. fi
  56. if _contains "$_res" "already exists"; then
  57. _info "Record already exists, skipping."
  58. return 0
  59. fi
  60. _nres="$(_normalizeJson "$_res")"
  61. if [ "$?" -ne 0 ] || [ -z "$_nres" ]; then
  62. _nres="$_res"
  63. fi
  64. if _contains "$_nres" "\"status\":4" || _contains "$_nres" "\"status\":5" || _contains "$_nres" "\"errors\""; then
  65. _err "API error: $_res"
  66. return 1
  67. fi
  68. return 0
  69. }
  70. dns_czechia_rm() {
  71. fulldomain="$1"
  72. txtvalue="$2"
  73. _debug "dns_czechia_rm fulldomain='$fulldomain'"
  74. if [ -z "$fulldomain" ] || [ -z "$txtvalue" ]; then
  75. _err "dns_czechia_rm: missing fulldomain or txtvalue"
  76. return 1
  77. fi
  78. _czechia_load_conf || return 1
  79. _current_zone=$(_czechia_pick_zone "$fulldomain")
  80. if [ -z "$_current_zone" ]; then
  81. _err "No matching zone found for $fulldomain. Please check CZ_Zones configuration."
  82. return 1
  83. fi
  84. _cz=$(printf "%s" "$_current_zone" | _lower_case | sed 's/[[:space:]]//g; s/\.$//')
  85. _tk=$(printf "%s" "$CZ_AuthorizationToken" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')
  86. if [ -z "$_cz" ] || [ -z "$_tk" ]; then
  87. _err "Missing zone or CZ_AuthorizationToken."
  88. return 1
  89. fi
  90. _url="$CZ_API_BASE/api/DNS/$_cz/TXT"
  91. _fd=$(printf "%s" "$fulldomain" | _lower_case | sed 's/\.$//')
  92. if [ "$_fd" = "$_cz" ]; then
  93. _h="@"
  94. else
  95. _h=$(printf "%s" "$_fd" | sed "s/\.$_cz$//")
  96. [ "$_h" = "$_fd" ] && _h="@"
  97. fi
  98. [ -z "$_h" ] && _h="@"
  99. _h_esc=$(printf "%s" "$_h" | sed 's/\\/\\\\/g; s/"/\\"/g')
  100. _txt_esc=$(printf "%s" "$txtvalue" | sed 's/\\/\\\\/g; s/"/\\"/g')
  101. _body="{\"hostName\":\"$_h_esc\",\"text\":\"$_txt_esc\",\"ttl\":300,\"publishZone\":1}"
  102. _debug "URL: $_url"
  103. _debug "Body: $_body"
  104. export _H1="Content-Type: application/json"
  105. export _H2="AuthorizationToken: $_tk"
  106. _res="$(_post "$_body" "$_url" "" "DELETE")"
  107. _post_exit="$?"
  108. _debug2 "Response: $_res"
  109. if [ "$_post_exit" -ne 0 ]; then
  110. _err "CZECHIA DNS API DELETE request failed for $_fd: exit code $_post_exit, response: $_res"
  111. return 1
  112. fi
  113. _res_normalized=$(printf '%s' "$_res" | _normalizeJson)
  114. if _contains "$_res_normalized" '"isError":true'; then
  115. _err "CZECHIA DNS API reported an error while deleting TXT for $_fd: $_res"
  116. return 1
  117. fi
  118. return 0
  119. }
  120. _czechia_load_conf() {
  121. CZ_AuthorizationToken="${CZ_AuthorizationToken:-$(_readaccountconf_mutable CZ_AuthorizationToken)}"
  122. if [ -z "$CZ_AuthorizationToken" ]; then
  123. _err "Missing CZ_AuthorizationToken"
  124. return 1
  125. fi
  126. CZ_Zones="${CZ_Zones:-$(_readaccountconf_mutable CZ_Zones)}"
  127. if [ -z "$CZ_Zones" ]; then
  128. _err "Missing CZ_Zones"
  129. return 1
  130. fi
  131. CZ_API_BASE="${CZ_API_BASE:-$(_readaccountconf_mutable CZ_API_BASE)}"
  132. [ -z "$CZ_API_BASE" ] && CZ_API_BASE="https://api.czechia.com"
  133. _saveaccountconf_mutable CZ_AuthorizationToken "$CZ_AuthorizationToken"
  134. _saveaccountconf_mutable CZ_Zones "$CZ_Zones"
  135. _saveaccountconf_mutable CZ_API_BASE "$CZ_API_BASE"
  136. return 0
  137. }
  138. _czechia_pick_zone() {
  139. _fd=$(printf "%s" "$1" | _lower_case | sed 's/\.$//')
  140. _best_zone=""
  141. _zones_space=$(printf "%s" "$CZ_Zones" | sed 's/,/ /g')
  142. for _z in $_zones_space; do
  143. _clean_z=$(printf "%s" "$_z" | _lower_case | sed 's/[[:space:]]//g; s/\.$//')
  144. [ -z "$_clean_z" ] && continue
  145. case "$_fd" in
  146. "$_clean_z" | *."$_clean_z")
  147. if [ ${#_clean_z} -gt ${#_best_zone} ]; then
  148. _best_zone="$_clean_z"
  149. fi
  150. ;;
  151. esac
  152. done
  153. printf "%s" "$_best_zone"
  154. }