3 ########################################################################
4 # Hurricane Electric hook script for acme.sh
6 # Environment variables:
8 # - $HE_Username (your dns.he.net username)
9 # - $HE_Password (your dns.he.net password)
11 # Author: Ondrej Simek <me@ondrejsimek.com>
12 # Git repo: https://github.com/angel333/acme.sh
14 #-- dns_he_add() - Add TXT record --------------------------------------
15 # Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..."
20 _info
"Using DNS-01 Hurricane Electric hook"
22 HE_Username
="${HE_Username:-$(_readaccountconf_mutable HE_Username)}"
23 HE_Password
="${HE_Password:-$(_readaccountconf_mutable HE_Password)}"
24 if [ -z "$HE_Username" ] ||
[ -z "$HE_Password" ]; then
27 _err
"No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables."
30 _saveaccountconf_mutable HE_Username
"$HE_Username"
31 _saveaccountconf_mutable HE_Password
"$HE_Password"
33 # Fills in the $_zone_id
34 _find_zone
"$_full_domain" ||
return 1
35 _debug
"Zone id \"$_zone_id\" will be used."
36 username_encoded
="$(printf "%s
" "${HE_Username}" | _url_encode)"
37 password_encoded
="$(printf "%s
" "${HE_Password}" | _url_encode)"
38 body
="email=${username_encoded}&pass=${password_encoded}"
40 body
="$body&menu=edit_zone"
42 body
="$body&hosted_dns_zoneid=$_zone_id"
43 body
="$body&hosted_dns_recordid="
44 body
="$body&hosted_dns_editzone=1"
45 body
="$body&Priority="
46 body
="$body&Name=$_full_domain"
47 body
="$body&Content=$_txt_value"
49 body
="$body&hosted_dns_editrecord=Submit"
50 response
="$(_post "$body" "https
://dns.he.net
/")"
52 if [ "$exit_code" -eq 0 ]; then
53 _info
"TXT record added successfully."
55 _err
"Couldn't add the TXT record."
57 _debug2 response
"$response"
61 #-- dns_he_rm() - Remove TXT record ------------------------------------
62 # Usage: dns_he_rm _acme-challenge.subdomain.domain.com "XyZ123..."
67 _info
"Cleaning up after DNS-01 Hurricane Electric hook"
68 HE_Username
="${HE_Username:-$(_readaccountconf_mutable HE_Username)}"
69 HE_Password
="${HE_Password:-$(_readaccountconf_mutable HE_Password)}"
70 # fills in the $_zone_id
71 _find_zone
"$_full_domain" ||
return 1
72 _debug
"Zone id \"$_zone_id\" will be used."
74 # Find the record id to clean
75 username_encoded
="$(printf "%s
" "${HE_Username}" | _url_encode)"
76 password_encoded
="$(printf "%s
" "${HE_Password}" | _url_encode)"
77 body
="email=${username_encoded}&pass=${password_encoded}"
78 body
="$body&hosted_dns_zoneid=$_zone_id"
79 body
="$body&menu=edit_zone"
80 body
="$body&hosted_dns_editzone="
82 response
="$(_post "$body" "https
://dns.he.net
/")"
83 _debug2
"response" "$response"
84 if ! _contains
"$response" "$_txt_value"; then
85 _debug
"The txt record is not found, just skip"
88 _record_id
="$(echo "$response" | tr -d "#" | sed "s/<tr/#<tr/g" | tr -d "\n" | tr "#" "\n" | grep "$_full_domain" | grep '"dns_tr"' | grep "$_txt_value" | cut -d '"' -f 4)"
89 _debug2 _record_id
"$_record_id"
90 if [ -z "$_record_id" ]; then
91 _err
"Can not find record id"
95 username_encoded
="$(printf "%s
" "${HE_Username}" | _url_encode)"
96 password_encoded
="$(printf "%s
" "${HE_Password}" | _url_encode)"
97 body
="email=${username_encoded}&pass=${password_encoded}"
98 body
="$body&menu=edit_zone"
99 body
="$body&hosted_dns_zoneid=$_zone_id"
100 body
="$body&hosted_dns_recordid=$_record_id"
101 body
="$body&hosted_dns_editzone=1"
102 body
="$body&hosted_dns_delrecord=1"
103 body
="$body&hosted_dns_delconfirm=delete"
104 _post
"$body" "https://dns.he.net/" \
105 |
grep '<div id="dns_status" onClick="hideThis(this);">Successfully removed record.</div>' \
108 if [ "$exit_code" -eq 0 ]; then
109 _info
"Record removed successfully."
111 _err
"Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand."
116 ########################## PRIVATE FUNCTIONS ###########################
120 username_encoded
="$(printf "%s
" "${HE_Username}" | _url_encode)"
121 password_encoded
="$(printf "%s
" "${HE_Password}" | _url_encode)"
122 body
="email=${username_encoded}&pass=${password_encoded}"
123 response
="$(_post "$body" "https
://dns.he.net
/")"
124 _debug2 response
"$response"
125 if _contains
"$response" '>Incorrect<'; then
126 _err
"Unable to login to dns.he.net please check username and password"
129 _table
="$(echo "$response" | tr -d "#" | sed "s/<table/#<table/g" | tr -d "\n" | tr "#" "\n" | grep 'id="domains_table"')"
130 _debug2 _table
"$_table"
131 _matches
="$(echo "$_table" | sed "s
/<tr
/#<tr/g" | tr "#" "\n" | grep 'alt="edit"' | tr -d " " | sed "s/<td/#<td/g" | tr "#" "\n" | grep 'hosted_dns_zoneid')"
132 _debug2 _matches
"$_matches"
133 # Zone names and zone IDs are in same order
134 _zone_ids
=$
(echo "$_matches" | _egrep_o
"hosted_dns_zoneid=[0-9]*&" | cut
-d = -f 2 |
tr -d '&')
135 _zone_names
=$
(echo "$_matches" | _egrep_o
"name=.*onclick" | cut
-d '"' -f 2)
136 _debug2
"These are the zones on this HE account:"
137 _debug2
"$_zone_names"
138 _debug2
"And these are their respective IDs:"
140 if [ -z "$_zone_names" ] ||
[ -z "$_zone_ids" ]; then
141 _err
"Can not get zone names."
144 # Walk through all possible zone names
147 _attempted_zone
=$
(echo "$_domain" | cut
-d .
-f ${_strip_counter}-)
149 # All possible zone names have been tried
150 if [ -z "$_attempted_zone" ]; then
151 _err
"No zone for domain \"$_domain\" found."
155 _debug
"Looking for zone \"${_attempted_zone}\""
157 line_num
="$(echo "$_zone_names" | grep -n "^
$_attempted_zone" | cut -d : -f 1)"
159 if [ "$line_num" ]; then
160 _zone_id
=$
(echo "$_zone_ids" |
sed -n "${line_num}p")
161 _debug
"Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"."
165 _debug
"Zone \"$_attempted_zone\" doesn't exist, let's try a less specific zone."
166 _strip_counter
=$
(_math
"$_strip_counter" + 1)