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.

202 lines
6.5 KiB

5 years ago
  1. #!/usr/bin/env sh
  2. # shellcheck disable=SC2034
  3. dns_clouddns_info='vshosting.cz CloudDNS
  4. Site: github.com/vshosting/clouddns
  5. Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_clouddns
  6. Options:
  7. CLOUDDNS_EMAIL Email
  8. CLOUDDNS_PASSWORD Password
  9. CLOUDDNS_CLIENT_ID Client ID
  10. Issues: github.com/acmesh-official/acme.sh/issues/2699
  11. Author: Radek Sprta <sprta@vshosting.cz>
  12. '
  13. CLOUDDNS_API='https://admin.vshosting.cloud/clouddns'
  14. CLOUDDNS_LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login'
  15. ######## Public functions #####################
  16. # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
  17. dns_clouddns_add() {
  18. fulldomain=$1
  19. txtvalue=$2
  20. _debug "fulldomain" "$fulldomain"
  21. CLOUDDNS_CLIENT_ID="${CLOUDDNS_CLIENT_ID:-$(_readaccountconf_mutable CLOUDDNS_CLIENT_ID)}"
  22. CLOUDDNS_EMAIL="${CLOUDDNS_EMAIL:-$(_readaccountconf_mutable CLOUDDNS_EMAIL)}"
  23. CLOUDDNS_PASSWORD="${CLOUDDNS_PASSWORD:-$(_readaccountconf_mutable CLOUDDNS_PASSWORD)}"
  24. if [ -z "$CLOUDDNS_PASSWORD" ] || [ -z "$CLOUDDNS_EMAIL" ] || [ -z "$CLOUDDNS_CLIENT_ID" ]; then
  25. CLOUDDNS_CLIENT_ID=""
  26. CLOUDDNS_EMAIL=""
  27. CLOUDDNS_PASSWORD=""
  28. _err "You didn't specify a CloudDNS password, email and client ID yet."
  29. return 1
  30. fi
  31. if ! _contains "$CLOUDDNS_EMAIL" "@"; then
  32. _err "It seems that the CLOUDDNS_EMAIL=$CLOUDDNS_EMAIL is not a valid email address."
  33. _err "Please check and retry."
  34. return 1
  35. fi
  36. # Save CloudDNS client id, email and password to config file
  37. _saveaccountconf_mutable CLOUDDNS_CLIENT_ID "$CLOUDDNS_CLIENT_ID"
  38. _saveaccountconf_mutable CLOUDDNS_EMAIL "$CLOUDDNS_EMAIL"
  39. _saveaccountconf_mutable CLOUDDNS_PASSWORD "$CLOUDDNS_PASSWORD"
  40. _debug "First detect the root zone"
  41. if ! _get_root "$fulldomain"; then
  42. _err "Invalid domain"
  43. return 1
  44. fi
  45. _debug _domain_id "$_domain_id"
  46. _debug _sub_domain "$_sub_domain"
  47. _debug _domain "$_domain"
  48. # Add TXT record
  49. data="{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"value\":\"$txtvalue\",\"domainId\":\"$_domain_id\"}"
  50. if _clouddns_api POST "record-txt" "$data"; then
  51. if _contains "$response" "$txtvalue"; then
  52. _info "Added, OK"
  53. elif _contains "$response" '"code":4136'; then
  54. _info "Already exists, OK"
  55. else
  56. _err "Add TXT record error."
  57. return 1
  58. fi
  59. fi
  60. _debug "Publishing record changes"
  61. _clouddns_api PUT "domain/$_domain_id/publish" "{\"soaTtl\":300}"
  62. }
  63. # Usage: rm _acme-challenge.www.domain.com
  64. dns_clouddns_rm() {
  65. fulldomain=$1
  66. _debug "fulldomain" "$fulldomain"
  67. CLOUDDNS_CLIENT_ID="${CLOUDDNS_CLIENT_ID:-$(_readaccountconf_mutable CLOUDDNS_CLIENT_ID)}"
  68. CLOUDDNS_EMAIL="${CLOUDDNS_EMAIL:-$(_readaccountconf_mutable CLOUDDNS_EMAIL)}"
  69. CLOUDDNS_PASSWORD="${CLOUDDNS_PASSWORD:-$(_readaccountconf_mutable CLOUDDNS_PASSWORD)}"
  70. _debug "First detect the root zone"
  71. if ! _get_root "$fulldomain"; then
  72. _err "Invalid domain"
  73. return 1
  74. fi
  75. _debug _domain_id "$_domain_id"
  76. _debug _sub_domain "$_sub_domain"
  77. _debug _domain "$_domain"
  78. # Get record ID
  79. _clouddns_api GET "domain/$_domain_id"
  80. if _contains "$response" "lastDomainRecordList"; then
  81. re="\"lastDomainRecordList\".*\"id\":\"([^\"}]*)\"[^}]*\"name\":\"$fulldomain.\","
  82. _last_domains=$(echo "$response" | _egrep_o "$re")
  83. re2="\"id\":\"([^\"}]*)\"[^}]*\"name\":\"$fulldomain.\","
  84. _record_id=$(echo "$_last_domains" | _egrep_o "$re2" | _head_n 1 | cut -d : -f 2 | cut -d , -f 1 | tr -d "\"")
  85. _debug _record_id "$_record_id"
  86. else
  87. _err "Could not retrieve record ID"
  88. return 1
  89. fi
  90. _info "Removing record"
  91. if _clouddns_api DELETE "record/$_record_id"; then
  92. if _contains "$response" "\"error\":"; then
  93. _err "Could not remove record"
  94. return 1
  95. fi
  96. fi
  97. _debug "Publishing record changes"
  98. _clouddns_api PUT "domain/$_domain_id/publish" "{\"soaTtl\":300}"
  99. }
  100. #################### Private functions below ##################################
  101. # Usage: _get_root _acme-challenge.www.domain.com
  102. # Returns:
  103. # _sub_domain=_acme-challenge.www
  104. # _domain=domain.com
  105. # _domain_id=sdjkglgdfewsdfg
  106. _get_root() {
  107. domain=$1
  108. # Get domain root
  109. data="{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$CLOUDDNS_CLIENT_ID\"}]}"
  110. _clouddns_api "POST" "domain/search" "$data"
  111. domain_slice="$domain"
  112. while [ -z "$domain_root" ]; do
  113. if _contains "$response" "\"domainName\":\"$domain_slice\.\""; then
  114. domain_root="$domain_slice"
  115. _debug domain_root "$domain_root"
  116. fi
  117. domain_slice="$(echo "$domain_slice" | cut -d . -f 2-)"
  118. done
  119. # Get domain id
  120. data="{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$CLOUDDNS_CLIENT_ID\"}, \
  121. {\"name\": \"domainName\", \"operator\": \"eq\", \"value\": \"$domain_root.\"}]}"
  122. _clouddns_api "POST" "domain/search" "$data"
  123. if _contains "$response" "\"id\":\""; then
  124. re='domainType\":\"[^\"]*\",\"id\":\"([^\"]*)\",' # Match domain id
  125. _domain_id=$(echo "$response" | _egrep_o "$re" | _head_n 1 | cut -d : -f 3 | tr -d "\",")
  126. if [ "$_domain_id" ]; then
  127. _sub_domain=$(printf "%s" "$domain" | sed "s/.$domain_root//")
  128. _domain="$domain_root"
  129. return 0
  130. fi
  131. _err 'Domain name not found on your CloudDNS account'
  132. return 1
  133. fi
  134. return 1
  135. }
  136. # Usage: _clouddns_api GET domain/search '{"data": "value"}'
  137. # Returns:
  138. # response='{"message": "api response"}'
  139. _clouddns_api() {
  140. method=$1
  141. endpoint="$2"
  142. data="$3"
  143. _debug endpoint "$endpoint"
  144. if [ -z "$CLOUDDNS_TOKEN" ]; then
  145. _clouddns_login
  146. fi
  147. _debug CLOUDDNS_TOKEN "$CLOUDDNS_TOKEN"
  148. export _H1="Content-Type: application/json"
  149. export _H2="Authorization: Bearer $CLOUDDNS_TOKEN"
  150. if [ "$method" != "GET" ]; then
  151. _debug data "$data"
  152. response="$(_post "$data" "$CLOUDDNS_API/$endpoint" "" "$method" | tr -d '\t\r\n ')"
  153. else
  154. response="$(_get "$CLOUDDNS_API/$endpoint" | tr -d '\t\r\n ')"
  155. fi
  156. # shellcheck disable=SC2181
  157. if [ "$?" != "0" ]; then
  158. _err "Error $endpoint"
  159. return 1
  160. fi
  161. _debug2 response "$response"
  162. return 0
  163. }
  164. # Returns:
  165. # CLOUDDNS_TOKEN=dslfje2rj23l
  166. _clouddns_login() {
  167. login_data="{\"email\": \"$CLOUDDNS_EMAIL\", \"password\": \"$CLOUDDNS_PASSWORD\"}"
  168. response="$(_post "$login_data" "$CLOUDDNS_LOGIN_API" "" "POST" "Content-Type: application/json")"
  169. if _contains "$response" "\"accessToken\":\""; then
  170. CLOUDDNS_TOKEN=$(echo "$response" | _egrep_o "\"accessToken\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
  171. export CLOUDDNS_TOKEN
  172. else
  173. echo 'Could not get CloudDNS access token; check your credentials'
  174. return 1
  175. fi
  176. return 0
  177. }