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.

178 lines
5.9 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. #!/usr/bin/env sh
  2. ########################################################################
  3. # Hurricane Electric hook script for acme.sh
  4. #
  5. # Environment variables:
  6. #
  7. # - $HE_Username (your dns.he.net username)
  8. # - $HE_Password (your dns.he.net password)
  9. #
  10. # Author: Ondrej Simek <me@ondrejsimek.com>
  11. # Git repo: https://github.com/angel333/acme.sh
  12. #-- dns_he_add() - Add TXT record --------------------------------------
  13. # Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..."
  14. dns_he_add() {
  15. _full_domain=$1
  16. _txt_value=$2
  17. _info "Using DNS-01 Hurricane Electric hook"
  18. HE_Username="${HE_Username:-$(_readaccountconf_mutable HE_Username)}"
  19. HE_Password="${HE_Password:-$(_readaccountconf_mutable HE_Password)}"
  20. if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then
  21. HE_Username=
  22. HE_Password=
  23. _err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables."
  24. return 1
  25. fi
  26. _saveaccountconf_mutable HE_Username "$HE_Username"
  27. _saveaccountconf_mutable HE_Password "$HE_Password"
  28. # Fills in the $_zone_id
  29. _find_zone "$_full_domain" || return 1
  30. _debug "Zone id \"$_zone_id\" will be used."
  31. body="email=${HE_Username}&pass=${HE_Password}"
  32. body="$body&account="
  33. body="$body&menu=edit_zone"
  34. body="$body&Type=TXT"
  35. body="$body&hosted_dns_zoneid=$_zone_id"
  36. body="$body&hosted_dns_recordid="
  37. body="$body&hosted_dns_editzone=1"
  38. body="$body&Priority="
  39. body="$body&Name=$_full_domain"
  40. body="$body&Content=$_txt_value"
  41. body="$body&TTL=300"
  42. body="$body&hosted_dns_editrecord=Submit"
  43. response="$(_post "$body" "https://dns.he.net/")"
  44. exit_code="$?"
  45. if [ "$exit_code" -eq 0 ]; then
  46. _info "TXT record added successfully."
  47. else
  48. _err "Couldn't add the TXT record."
  49. fi
  50. _debug2 response "$response"
  51. return "$exit_code"
  52. }
  53. #-- dns_he_rm() - Remove TXT record ------------------------------------
  54. # Usage: dns_he_rm _acme-challenge.subdomain.domain.com "XyZ123..."
  55. dns_he_rm() {
  56. _full_domain=$1
  57. _txt_value=$2
  58. _info "Cleaning up after DNS-01 Hurricane Electric hook"
  59. HE_Username="${HE_Username:-$(_readaccountconf_mutable HE_Username)}"
  60. HE_Password="${HE_Password:-$(_readaccountconf_mutable HE_Password)}"
  61. # fills in the $_zone_id
  62. _find_zone "$_full_domain" || return 1
  63. _debug "Zone id \"$_zone_id\" will be used."
  64. # Find the record id to clean
  65. body="email=${HE_Username}&pass=${HE_Password}"
  66. body="$body&hosted_dns_zoneid=$_zone_id"
  67. body="$body&menu=edit_zone"
  68. body="$body&hosted_dns_editzone="
  69. domain_regex="$(echo "$_full_domain" | sed 's/\./\\./g')" # escape dots
  70. _record_id=$(_post "$body" "https://dns.he.net/" \
  71. | tr -d '\n' \
  72. | _egrep_o "data=\"&quot;${_txt_value}&quot;([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${domain_regex}','TXT'\)" \
  73. | _egrep_o "[0-9]+','${domain_regex}','TXT'\)$" \
  74. | _egrep_o "^[0-9]+"
  75. )
  76. # The series of egreps above could have been done a bit shorter but
  77. # I wanted to double-check whether it's the correct record (in case
  78. # HE changes their website somehow).
  79. # Remove the record
  80. body="email=${HE_Username}&pass=${HE_Password}"
  81. body="$body&menu=edit_zone"
  82. body="$body&hosted_dns_zoneid=$_zone_id"
  83. body="$body&hosted_dns_recordid=$_record_id"
  84. body="$body&hosted_dns_editzone=1"
  85. body="$body&hosted_dns_delrecord=1"
  86. body="$body&hosted_dns_delconfirm=delete"
  87. _post "$body" "https://dns.he.net/" \
  88. | grep '<div id="dns_status" onClick="hideThis(this);">Successfully removed record.</div>' \
  89. >/dev/null
  90. exit_code="$?"
  91. if [ "$exit_code" -eq 0 ]; then
  92. _info "Record removed successfully."
  93. else
  94. _err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand."
  95. return "$exit_code"
  96. fi
  97. }
  98. ########################## PRIVATE FUNCTIONS ###########################
  99. #-- _find_zone() -------------------------------------------------------
  100. # Returns the most specific zone found in administration interface.
  101. #
  102. # Example:
  103. #
  104. # _find_zone first.second.third.co.uk
  105. #
  106. # ... will return the first zone that exists in admin out of these:
  107. # - "first.second.third.co.uk"
  108. # - "second.third.co.uk"
  109. # - "third.co.uk"
  110. # - "co.uk" <-- unlikely
  111. # - "uk" <-'
  112. #
  113. # (another approach would be something like this:
  114. # https://github.com/hlandau/acme/blob/master/_doc/dns.hook
  115. # - that's better if there are multiple pages. It's so much simpler.
  116. # )
  117. _find_zone() {
  118. _domain="$1"
  119. body="email=${HE_Username}&pass=${HE_Password}"
  120. _matches=$(_post "$body" "https://dns.he.net/" \
  121. | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+"
  122. )
  123. # Zone names and zone IDs are in same order
  124. _zone_ids=$(echo "$_matches" | cut -d '"' -f 5)
  125. _zone_names=$(echo "$_matches" | cut -d '"' -f 3)
  126. _debug2 "These are the zones on this HE account:"
  127. _debug2 "$_zone_names"
  128. _debug2 "And these are their respective IDs:"
  129. _debug2 "$_zone_ids"
  130. # Walk through all possible zone names
  131. _strip_counter=1
  132. while true; do
  133. _attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-)
  134. # All possible zone names have been tried
  135. if [ -z "$_attempted_zone" ]; then
  136. _err "No zone for domain \"$_domain\" found."
  137. return 1
  138. fi
  139. _debug "Looking for zone \"${_attempted_zone}\""
  140. # Take care of "." and only match whole lines. Note that grep -F
  141. # cannot be used because there's no way to make it match whole
  142. # lines.
  143. regex="^$(echo "$_attempted_zone" | sed 's/\./\\./g')$"
  144. line_num=$(echo "$_zone_names" \
  145. | grep -n "$regex" \
  146. | cut -d : -f 1
  147. )
  148. if [ -n "$line_num" ]; then
  149. _zone_id=$(echo "$_zone_ids" | sed "${line_num}q;d")
  150. _debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"."
  151. return 0
  152. fi
  153. _debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less specific zone."
  154. _strip_counter=$(_math "$_strip_counter" + 1)
  155. done
  156. }
  157. # vim: et:ts=2:sw=2: