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.

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