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.

281 lines
7.4 KiB

  1. #!/usr/bin/env sh
  2. # shellcheck disable=SC2034
  3. dns_beget_info='Beget.com
  4. Site: Beget.com
  5. Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_beget
  6. Options:
  7. BEGET_User API user
  8. BEGET_Password API password
  9. Issues: github.com/acmesh-official/acme.sh/issues/6200
  10. Author: ARNik arnik@arnik.ru
  11. '
  12. Beget_Api="https://api.beget.com/api"
  13. #################### Public functions ####################
  14. # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
  15. # Used to add txt record
  16. dns_beget_add() {
  17. fulldomain=$1
  18. txtvalue=$2
  19. _debug "dns_beget_add() $fulldomain $txtvalue"
  20. fulldomain=$(echo "$fulldomain" | _lower_case)
  21. Beget_Username="${Beget_Username:-$(_readaccountconf_mutable Beget_Username)}"
  22. Beget_Password="${Beget_Password:-$(_readaccountconf_mutable Beget_Password)}"
  23. if [ -z "$Beget_Username" ] || [ -z "$Beget_Password" ]; then
  24. Beget_Username=""
  25. Beget_Password=""
  26. _err "You must export variables: Beget_Username, and Beget_Password"
  27. return 1
  28. fi
  29. #save the credentials to the account conf file.
  30. _saveaccountconf_mutable Beget_Username "$Beget_Username"
  31. _saveaccountconf_mutable Beget_Password "$Beget_Password"
  32. _info "Prepare subdomain."
  33. if ! _prepare_subdomain "$fulldomain"; then
  34. _err "Can't prepare subdomain."
  35. return 1
  36. fi
  37. _info "Get domain records"
  38. data="{\"fqdn\":\"$fulldomain\"}"
  39. res=$(_api_call "$Beget_Api/dns/getData" "$data")
  40. if ! _is_api_reply_ok "$res"; then
  41. _err "Can't get domain records."
  42. return 1
  43. fi
  44. _info "Add new TXT record"
  45. data="{\"fqdn\":\"$fulldomain\",\"records\":{"
  46. data=${data}$(_parce_records "$res" "A")
  47. data=${data}$(_parce_records "$res" "AAAA")
  48. data=${data}$(_parce_records "$res" "CAA")
  49. data=${data}$(_parce_records "$res" "MX")
  50. data=${data}$(_parce_records "$res" "SRV")
  51. data=${data}$(_parce_records "$res" "TXT")
  52. data=$(echo "$data" | sed 's/,$//')
  53. data=${data}'}}'
  54. str=$(_txt_to_dns_json "$txtvalue")
  55. data=$(_add_record "$data" "TXT" "$str")
  56. res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
  57. if ! _is_api_reply_ok "$res"; then
  58. _err "Can't change domain records."
  59. return 1
  60. fi
  61. return 0
  62. }
  63. # Usage: fulldomain txtvalue
  64. # Used to remove the txt record after validation
  65. dns_beget_rm() {
  66. fulldomain=$1
  67. txtvalue=$2
  68. _debug "dns_beget_rm() $fulldomain $txtvalue"
  69. fulldomain=$(echo "$fulldomain" | _lower_case)
  70. Beget_Username="${Beget_Username:-$(_readaccountconf_mutable Beget_Username)}"
  71. Beget_Password="${Beget_Password:-$(_readaccountconf_mutable Beget_Password)}"
  72. _info "Get current domain records"
  73. data="{\"fqdn\":\"$fulldomain\"}"
  74. res=$(_api_call "$Beget_Api/dns/getData" "$data")
  75. if ! _is_api_reply_ok "$res"; then
  76. _err "Can't get domain records."
  77. return 1
  78. fi
  79. _info "Remove TXT record"
  80. data="{\"fqdn\":\"$fulldomain\",\"records\":{"
  81. data=${data}$(_parce_records "$res" "A")
  82. data=${data}$(_parce_records "$res" "AAAA")
  83. data=${data}$(_parce_records "$res" "CAA")
  84. data=${data}$(_parce_records "$res" "MX")
  85. data=${data}$(_parce_records "$res" "SRV")
  86. data=${data}$(_parce_records "$res" "TXT")
  87. data=$(echo "$data" | sed 's/,$//')
  88. data=${data}'}}'
  89. str=$(_txt_to_dns_json "$txtvalue")
  90. data=$(_rm_record "$data" "$str")
  91. res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
  92. if ! _is_api_reply_ok "$res"; then
  93. _err "Can't change domain records."
  94. return 1
  95. fi
  96. return 0
  97. }
  98. #################### Private functions below ####################
  99. # Create subdomain if needed
  100. # Usage: _prepare_subdomain [fulldomain]
  101. _prepare_subdomain() {
  102. fulldomain=$1
  103. _info "Detect the root zone"
  104. if ! _get_root "$fulldomain"; then
  105. _err "invalid domain"
  106. return 1
  107. fi
  108. _debug _domain_id "$_domain_id"
  109. _debug _sub_domain "$_sub_domain"
  110. _debug _domain "$_domain"
  111. if [ -z "$_sub_domain" ]; then
  112. _debug "$fulldomain is a root domain."
  113. return 0
  114. fi
  115. _info "Get subdomain list"
  116. res=$(_api_call "$Beget_Api/domain/getSubdomainList")
  117. if ! _is_api_reply_ok "$res"; then
  118. _err "Can't get subdomain list."
  119. return 1
  120. fi
  121. if _contains "$res" "\"fqdn\":\"$fulldomain\""; then
  122. _debug "Subdomain $fulldomain already exist."
  123. return 0
  124. fi
  125. _info "Subdomain $fulldomain does not exist. Let's create one."
  126. data="{\"subdomain\":\"$_sub_domain\",\"domain_id\":$_domain_id}"
  127. res=$(_api_call "$Beget_Api/domain/addSubdomainVirtual" "$data")
  128. if ! _is_api_reply_ok "$res"; then
  129. _err "Can't create subdomain."
  130. return 1
  131. fi
  132. _debug "Cleanup subdomen records"
  133. data="{\"fqdn\":\"$fulldomain\",\"records\":{}}"
  134. res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
  135. if ! _is_api_reply_ok "$res"; then
  136. _debug "Can't cleanup $fulldomain records."
  137. fi
  138. data="{\"fqdn\":\"www.$fulldomain\",\"records\":{}}"
  139. res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
  140. if ! _is_api_reply_ok "$res"; then
  141. _debug "Can't cleanup www.$fulldomain records."
  142. fi
  143. return 0
  144. }
  145. # Usage: _get_root _acme-challenge.www.domain.com
  146. #returns
  147. # _sub_domain=_acme-challenge.www
  148. # _domain=domain.com
  149. # _domain_id=32436365
  150. _get_root() {
  151. fulldomain=$1
  152. i=1
  153. p=1
  154. _debug "Get domain list"
  155. res=$(_api_call "$Beget_Api/domain/getList")
  156. if ! _is_api_reply_ok "$res"; then
  157. _err "Can't get domain list."
  158. return 1
  159. fi
  160. while true; do
  161. h=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-100)
  162. _debug h "$h"
  163. if [ -z "$h" ]; then
  164. return 1
  165. fi
  166. if _contains "$res" "$h"; then
  167. _domain_id=$(echo "$res" | _egrep_o "\"id\":[0-9]*,\"fqdn\":\"$h\"" | cut -d , -f1 | cut -d : -f2)
  168. if [ "$_domain_id" ]; then
  169. if [ "$h" != "$fulldomain" ]; then
  170. _sub_domain=$(echo "$fulldomain" | cut -d . -f 1-"$p")
  171. else
  172. _sub_domain=""
  173. fi
  174. _domain=$h
  175. return 0
  176. fi
  177. return 1
  178. fi
  179. p="$i"
  180. i=$(_math "$i" + 1)
  181. done
  182. return 1
  183. }
  184. # Parce DNS records from json string
  185. # Usage: _parce_records [j_str] [record_name]
  186. _parce_records() {
  187. j_str=$1
  188. record_name=$2
  189. res="\"$record_name\":["
  190. res=${res}$(echo "$j_str" | _egrep_o "\"$record_name\":\[.*" | cut -d '[' -f2 | cut -d ']' -f1)
  191. res=${res}"],"
  192. echo "$res"
  193. }
  194. # Usage: _add_record [data] [record_name] [record_data]
  195. _add_record() {
  196. data=$1
  197. record_name=$2
  198. record_data=$3
  199. echo "$data" | sed "s/\"$record_name\":\[/\"$record_name\":\[$record_data,/" | sed "s/,\]/\]/"
  200. }
  201. # Usage: _rm_record [data] [record_data]
  202. _rm_record() {
  203. data=$1
  204. record_data=$2
  205. echo "$data" | sed "s/$record_data//g" | sed "s/,\+/,/g" |
  206. sed "s/{,/{/g" | sed "s/,}/}/g" |
  207. sed "s/\[,/\[/g" | sed "s/,\]/\]/g"
  208. }
  209. _txt_to_dns_json() {
  210. echo "{\"ttl\":600,\"txtdata\":\"$1\"}"
  211. }
  212. # Usage: _api_call [api_url] [input_data]
  213. _api_call() {
  214. api_url="$1"
  215. input_data="$2"
  216. _debug "_api_call $api_url"
  217. _debug "Request: $input_data"
  218. # res=$(curl -s -L -D ./http.header \
  219. # "$api_url" \
  220. # --data-urlencode login=$Beget_Username \
  221. # --data-urlencode passwd=$Beget_Password \
  222. # --data-urlencode input_format=json \
  223. # --data-urlencode output_format=json \
  224. # --data-urlencode "input_data=$input_data")
  225. url="$api_url?login=$Beget_Username&passwd=$Beget_Password&input_format=json&output_format=json"
  226. if [ -n "$input_data" ]; then
  227. url=${url}"&input_data="
  228. url=${url}$(echo "$input_data" | _url_encode)
  229. fi
  230. res=$(_get "$url")
  231. _debug "Reply: $res"
  232. echo "$res"
  233. }
  234. # Usage: _is_api_reply_ok [api_reply]
  235. _is_api_reply_ok() {
  236. _contains "$1" '^{"status":"success","answer":{"status":"success","result":.*}}$'
  237. }