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