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.

358 lines
9.3 KiB

  1. #!/usr/bin/env sh
  2. #This is the euserv.eu api wrapper for acme.sh
  3. #
  4. #Author: Michael Brueckner
  5. #Report Bugs: https://www.github.com/initit/acme.sh or mbr@initit.de
  6. #
  7. #EUSERV_Username="username"
  8. #
  9. #EUSERV_Password="password"
  10. #
  11. # Dependencies:
  12. # -------------
  13. # - none -
  14. EUSERV_Api="https://api.euserv.net"
  15. ######## Public functions #####################
  16. #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
  17. dns_euserv_add() {
  18. fulldomain="$(echo "$1" | _lower_case)"
  19. txtvalue=$2
  20. EUSERV_Username="${EUSERV_Username:-$(_readaccountconf_mutable EUSERV_Username)}"
  21. EUSERV_Password="${EUSERV_Password:-$(_readaccountconf_mutable EUSERV_Password)}"
  22. if [ -z "$EUSERV_Username" ] || [ -z "$EUSERV_Password" ]; then
  23. EUSERV_Username=""
  24. EUSERV_Password=""
  25. _err "You don't specify euserv user and password yet."
  26. _err "Please create your key and try again."
  27. return 1
  28. fi
  29. #save the user and email to the account conf file.
  30. _saveaccountconf_mutable EUSERV_Username "$EUSERV_Username"
  31. _saveaccountconf_mutable EUSERV_Password "$EUSERV_Password"
  32. _debug "First detect the root zone"
  33. if ! _get_root "$fulldomain"; then
  34. _err "invalid domain"
  35. return 1
  36. fi
  37. _debug "_sub_domain" "$_sub_domain"
  38. _debug "_domain" "$_domain"
  39. _info "Adding record"
  40. if ! _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue"; then
  41. return 1
  42. fi
  43. }
  44. #fulldomain txtvalue
  45. dns_euserv_rm() {
  46. fulldomain="$(echo "$1" | _lower_case)"
  47. txtvalue=$2
  48. EUSERV_Username="${EUSERV_Username:-$(_readaccountconf_mutable EUSERV_Username)}"
  49. EUSERV_Password="${EUSERV_Password:-$(_readaccountconf_mutable EUSERV_Password)}"
  50. if [ -z "$EUSERV_Username" ] || [ -z "$EUSERV_Password" ]; then
  51. EUSERV_Username=""
  52. EUSERV_Password=""
  53. _err "You don't specify euserv user and password yet."
  54. _err "Please create your key and try again."
  55. return 1
  56. fi
  57. #save the user and email to the account conf file.
  58. _saveaccountconf_mutable EUSERV_Username "$EUSERV_Username"
  59. _saveaccountconf_mutable EUSERV_Password "$EUSERV_Password"
  60. _debug "First detect the root zone"
  61. if ! _get_root "$fulldomain"; then
  62. _err "invalid domain"
  63. return 1
  64. fi
  65. _debug "_sub_domain" "$_sub_domain"
  66. _debug "_domain" "$_domain"
  67. _debug "Getting txt records"
  68. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  69. <methodCall>
  70. <methodName>domain.dns_get_active_records</methodName>
  71. <params>
  72. <param>
  73. <value>
  74. <struct>
  75. <member>
  76. <name>login</name>
  77. <value>
  78. <string>%s</string>
  79. </value>
  80. </member>
  81. <member>
  82. <name>password</name>
  83. <value>
  84. <string>%s</string>
  85. </value>
  86. </member>
  87. <member>
  88. <name>domain_id</name>
  89. <value>
  90. <int>%s</int>
  91. </value>
  92. </member>
  93. </struct>
  94. </value>
  95. </param>
  96. </params>
  97. </methodCall>' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id")
  98. export _H1="Content-Type: text/xml"
  99. response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")"
  100. if ! _contains "$response" "<member><name>status</name><value><i4>100</i4></value></member>"; then
  101. _err "Error could not get txt records"
  102. _debug "xml_content" "$xml_content"
  103. _debug "response" "$response"
  104. return 1
  105. fi
  106. if ! printf "%s" "$response" | grep '>dns_record_content<.*>'"$txtvalue"'<' >/dev/null; then
  107. _info "Do not need to delete record"
  108. else
  109. # find XML block where txtvalue is in. The record_id is allways prior this line!
  110. _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1 )
  111. # record_id is the last <name> Tag with a number before the row _endLine, identified by </name><value><struct>
  112. _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '</name><value><struct>' | tail -n 1 | sed 's/.*<name>\([0-9]*\)<\/name>.*/\1/' )
  113. _info "Deleting record"
  114. _euserv_delete_record "$_record_id"
  115. fi
  116. }
  117. #################### Private functions below ##################################
  118. _get_root() {
  119. domain=$1
  120. _debug "get root"
  121. # Just to read the domain_orders once
  122. domain=$1
  123. i=2
  124. p=1
  125. if ! _euserv_get_domain_orders; then
  126. return 1
  127. fi
  128. # Get saved response with domain_orders
  129. response="$_euserv_domain_orders"
  130. while true; do
  131. h=$(printf "%s" "$domain" | cut -d . -f $i-100)
  132. _debug h "$h"
  133. if [ -z "$h" ]; then
  134. #not valid
  135. return 1
  136. fi
  137. if _contains "$response" "$h"; then
  138. _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
  139. _domain="$h"
  140. if ! _euserv_get_domain_id "$_domain"; then
  141. _err "invalid domain"
  142. return 1
  143. fi
  144. return 0
  145. fi
  146. p=$i
  147. i=$(_math "$i" + 1)
  148. done
  149. return 1
  150. }
  151. _euserv_get_domain_orders() {
  152. # returns: _euserv_domain_orders
  153. _debug "get domain_orders"
  154. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  155. <methodCall>
  156. <methodName>domain.get_domain_orders</methodName>
  157. <params>
  158. <param>
  159. <value>
  160. <struct>
  161. <member>
  162. <name>login</name>
  163. <value><string>%s</string></value>
  164. </member>
  165. <member>
  166. <name>password</name>
  167. <value><string>%s</string></value>
  168. </member>
  169. </struct>
  170. </value>
  171. </param>
  172. </params>
  173. </methodCall>' "$EUSERV_Username" "$EUSERV_Password")
  174. export _H1="Content-Type: text/xml"
  175. response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")"
  176. if ! _contains "$response" "<member><name>status</name><value><i4>100</i4></value></member>"; then
  177. _err "Error could not get domain orders"
  178. _debug "xml_content" "$xml_content"
  179. _debug "response" "$response"
  180. return 1
  181. fi
  182. # save response to reduce API calls
  183. _euserv_domain_orders="$response"
  184. return 0
  185. }
  186. _euserv_get_domain_id() {
  187. # returns: _euserv_domain_id
  188. domain=$1
  189. _debug "get domain_id"
  190. # find line where the domain name is within the $response
  191. _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1)
  192. # next occurency of domain_id after the domain_name is the correct one
  193. _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*<i4>\([0-9]*\)<\/i4>.*/\1/')
  194. if [ -z "$_euserv_domain_id" ]; then
  195. _err "Could not find domain_id for domain $domain"
  196. _debug "_euserv_domain_orders" "$_euserv_domain_orders"
  197. return 1
  198. fi
  199. return 0
  200. }
  201. _euserv_delete_record() {
  202. record_id=$1
  203. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  204. <methodCall>
  205. <methodName>domain.dns_delete_record</methodName>
  206. <params>
  207. <param>
  208. <value>
  209. <struct>
  210. <member>
  211. <name>login</name>
  212. <value>
  213. <string>%s</string>
  214. </value>
  215. </member>
  216. <member>
  217. <name>password</name>
  218. <value>
  219. <string>%s</string>
  220. </value>
  221. </member>
  222. <member>
  223. <name>dns_record_id</name>
  224. <value>
  225. <int>%s</int>
  226. </value>
  227. </member>
  228. </struct>
  229. </value>
  230. </param>
  231. </params>
  232. </methodCall>' "$EUSERV_Username" "$EUSERV_Password" "$record_id")
  233. export _H1="Content-Type: text/xml"
  234. response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")"
  235. if ! _contains "$response" "<member><name>status</name><value><i4>100</i4></value></member>"; then
  236. _err "Error deleting record"
  237. _debug "xml_content" "$xml_content"
  238. _debug "response" "$response"
  239. return 1
  240. fi
  241. return 0
  242. }
  243. _euserv_add_record() {
  244. domain=$1
  245. sub_domain=$2
  246. txtval=$3
  247. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  248. <methodCall>
  249. <methodName>domain.dns_create_record</methodName>
  250. <params>
  251. <param>
  252. <value>
  253. <struct>
  254. <member>
  255. <name>login</name>
  256. <value>
  257. <string>%s</string>
  258. </value>
  259. </member>
  260. <member>
  261. <name>password</name>
  262. <value>
  263. <string>%s</string></value>
  264. </member>
  265. <member>
  266. <name>domain_id</name>
  267. <value>
  268. <int>%s</int>
  269. </value>
  270. </member>
  271. <member>
  272. <name>dns_record_subdomain</name>
  273. <value>
  274. <string>%s</string>
  275. </value>
  276. </member>
  277. <member>
  278. <name>dns_record_type</name>
  279. <value>
  280. <string>TXT</string>
  281. </value>
  282. </member>
  283. <member>
  284. <name>dns_record_value</name>
  285. <value>
  286. <string>%s</string>
  287. </value>
  288. </member>
  289. <member>
  290. <name>dns_record_ttl</name>
  291. <value>
  292. <int>300</int>
  293. </value>
  294. </member>
  295. </struct>
  296. </value>
  297. </param>
  298. </params>
  299. </methodCall>' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id" "$sub_domain" "$txtval")
  300. export _H1="Content-Type: text/xml"
  301. response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")"
  302. if ! _contains "$response" "<member><name>status</name><value><i4>100</i4></value></member>"; then
  303. _err "Error could not create record"
  304. _debug "xml_content" "$xml_content"
  305. _debug "response" "$response"
  306. return 1
  307. fi
  308. return 0
  309. }