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.

196 lines
5.5 KiB

  1. #!/usr/bin/env sh
  2. ##########
  3. # Custom servercow.de DNS API v1 for use with [acme.sh](https://github.com/acmesh-official/acme.sh)
  4. #
  5. # Usage:
  6. # export SERVERCOW_API_Username=username
  7. # export SERVERCOW_API_Password=password
  8. # acme.sh --issue -d example.com --dns dns_servercow
  9. #
  10. # Issues:
  11. # Any issues / questions / suggestions can be posted here:
  12. # https://github.com/jhartlep/servercow-dns-api/issues
  13. #
  14. # Author: Jens Hartlep
  15. ##########
  16. SERVERCOW_API="https://api.servercow.de/dns/v1/domains"
  17. # Usage dns_servercow_add _acme-challenge.www.domain.com "abcdefghijklmnopqrstuvwxyz"
  18. dns_servercow_add() {
  19. fulldomain=$1
  20. txtvalue=$2
  21. _info "Using servercow"
  22. _debug fulldomain "$fulldomain"
  23. _debug txtvalue "$txtvalue"
  24. SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}"
  25. SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}"
  26. if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then
  27. SERVERCOW_API_Username=""
  28. SERVERCOW_API_Password=""
  29. _err "You don't specify servercow api username and password yet."
  30. _err "Please create your username and password and try again."
  31. return 1
  32. fi
  33. # save the credentials to the account conf file
  34. _saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username"
  35. _saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_Password"
  36. _debug "First detect the root zone"
  37. if ! _get_root "$fulldomain"; then
  38. _err "invalid domain"
  39. return 1
  40. fi
  41. _debug _sub_domain "$_sub_domain"
  42. _debug _domain "$_domain"
  43. # check whether a txt record already exists for the subdomain
  44. if printf -- "%s" "$response" | grep "{\"name\":\"$_sub_domain\",\"ttl\":20,\"type\":\"TXT\"" >/dev/null; then
  45. _info "A txt record with the same name already exists."
  46. # trim the string on the left
  47. txtvalue_old=${response#*{\"name\":\"$_sub_domain\",\"ttl\":20,\"type\":\"TXT\",\"content\":\"}
  48. # trim the string on the right
  49. txtvalue_old=${txtvalue_old%%\"*}
  50. _debug txtvalue_old "$txtvalue_old"
  51. _info "Add the new txtvalue to the existing txt record."
  52. if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":[\"$txtvalue\",\"$txtvalue_old\"],\"ttl\":20}"; then
  53. if printf -- "%s" "$response" | grep "ok" >/dev/null; then
  54. _info "Added additional txtvalue, OK"
  55. return 0
  56. else
  57. _err "add txt record error."
  58. return 1
  59. fi
  60. fi
  61. _err "add txt record error."
  62. return 1
  63. else
  64. _info "There is no txt record with the name yet."
  65. if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then
  66. if printf -- "%s" "$response" | grep "ok" >/dev/null; then
  67. _info "Added, OK"
  68. return 0
  69. else
  70. _err "add txt record error."
  71. return 1
  72. fi
  73. fi
  74. _err "add txt record error."
  75. return 1
  76. fi
  77. return 1
  78. }
  79. # Usage fulldomain txtvalue
  80. # Remove the txt record after validation
  81. dns_servercow_rm() {
  82. fulldomain=$1
  83. txtvalue=$2
  84. _info "Using servercow"
  85. _debug fulldomain "$fulldomain"
  86. _debug txtvalue "$fulldomain"
  87. SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}"
  88. SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}"
  89. if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then
  90. SERVERCOW_API_Username=""
  91. SERVERCOW_API_Password=""
  92. _err "You don't specify servercow api username and password yet."
  93. _err "Please create your username and password and try again."
  94. return 1
  95. fi
  96. _debug "First detect the root zone"
  97. if ! _get_root "$fulldomain"; then
  98. _err "invalid domain"
  99. return 1
  100. fi
  101. _debug _sub_domain "$_sub_domain"
  102. _debug _domain "$_domain"
  103. if _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then
  104. if printf -- "%s" "$response" | grep "ok" >/dev/null; then
  105. _info "Deleted, OK"
  106. _contains "$response" '"message":"ok"'
  107. else
  108. _err "delete txt record error."
  109. return 1
  110. fi
  111. fi
  112. }
  113. #################### Private functions below ##################################
  114. # _acme-challenge.www.domain.com
  115. # returns
  116. # _sub_domain=_acme-challenge.www
  117. # _domain=domain.com
  118. _get_root() {
  119. fulldomain=$1
  120. i=2
  121. p=1
  122. while true; do
  123. _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100)
  124. _debug _domain "$_domain"
  125. if [ -z "$_domain" ]; then
  126. # not valid
  127. return 1
  128. fi
  129. if ! _servercow_api GET "$_domain"; then
  130. return 1
  131. fi
  132. if ! _contains "$response" '"error":"no such domain in user context"' >/dev/null; then
  133. _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p)
  134. if [ -z "$_sub_domain" ]; then
  135. # not valid
  136. return 1
  137. fi
  138. return 0
  139. fi
  140. p=$i
  141. i=$(_math "$i" + 1)
  142. done
  143. return 1
  144. }
  145. _servercow_api() {
  146. method=$1
  147. domain=$2
  148. data="$3"
  149. export _H1="Content-Type: application/json"
  150. export _H2="X-Auth-Username: $SERVERCOW_API_Username"
  151. export _H3="X-Auth-Password: $SERVERCOW_API_Password"
  152. if [ "$method" != "GET" ]; then
  153. _debug data "$data"
  154. response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")"
  155. else
  156. response="$(_get "$SERVERCOW_API/$domain")"
  157. fi
  158. if [ "$?" != "0" ]; then
  159. _err "error $domain"
  160. return 1
  161. fi
  162. _debug2 response "$response"
  163. return 0
  164. }