]>
Commit | Line | Data |
---|---|---|
0d03309c L |
1 | #!/usr/bin/env sh |
2 | ||
3 | # Namecheap API | |
4 | # https://www.namecheap.com/support/api/intro.aspx | |
5 | # | |
ac9f6e3a PDH |
6 | # Requires Namecheap API key set in |
7 | #NAMECHEAP_API_KEY, | |
cc6159b3 | 8 | #NAMECHEAP_USERNAME, |
ac9f6e3a | 9 | #NAMECHEAP_SOURCEIP |
828d8eaa L |
10 | # Due to Namecheap's API limitation all the records of your domain will be read and re applied, make sure to have a backup of your records you could apply if any issue would arise. |
11 | ||
0d03309c L |
12 | ######## Public functions ##################### |
13 | ||
cc6159b3 | 14 | NAMECHEAP_API="https://api.namecheap.com/xml.response" |
0d03309c L |
15 | |
16 | #Usage: dns_namecheap_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | |
17 | dns_namecheap_add() { | |
18 | fulldomain=$1 | |
19 | txtvalue=$2 | |
20 | ||
21 | if ! _namecheap_check_config; then | |
697e694d L |
22 | _err "$error" |
23 | return 1 | |
0d03309c L |
24 | fi |
25 | ||
d813be1f | 26 | if ! _namecheap_set_publicip; then |
697e694d | 27 | return 1 |
d813be1f | 28 | fi |
0d03309c L |
29 | |
30 | _debug "First detect the root zone" | |
31 | if ! _get_root "$fulldomain"; then | |
32 | _err "invalid domain" | |
33 | return 1 | |
34 | fi | |
35 | ||
36 | _debug fulldomain "$fulldomain" | |
37 | _debug txtvalue "$txtvalue" | |
38 | _debug domain "$_domain" | |
39 | _debug sub_domain "$_sub_domain" | |
40 | ||
41 | _set_namecheap_TXT "$_domain" "$_sub_domain" "$txtvalue" | |
42 | } | |
43 | ||
44 | #Usage: fulldomain txtvalue | |
45 | #Remove the txt record after validation. | |
46 | dns_namecheap_rm() { | |
47 | fulldomain=$1 | |
48 | txtvalue=$2 | |
3975792b | 49 | |
d813be1f | 50 | if ! _namecheap_set_publicip; then |
697e694d | 51 | return 1 |
d813be1f | 52 | fi |
0d03309c L |
53 | |
54 | if ! _namecheap_check_config; then | |
697e694d L |
55 | _err "$error" |
56 | return 1 | |
0d03309c L |
57 | fi |
58 | ||
59 | _debug "First detect the root zone" | |
60 | if ! _get_root "$fulldomain"; then | |
61 | _err "invalid domain" | |
62 | return 1 | |
63 | fi | |
64 | ||
65 | _debug fulldomain "$fulldomain" | |
66 | _debug txtvalue "$txtvalue" | |
67 | _debug domain "$_domain" | |
68 | _debug sub_domain "$_sub_domain" | |
69 | ||
70 | _del_namecheap_TXT "$_domain" "$_sub_domain" "$txtvalue" | |
0d03309c L |
71 | } |
72 | ||
73 | #################### Private functions below ################################## | |
74 | #_acme-challenge.www.domain.com | |
75 | #returns | |
76 | # _sub_domain=_acme-challenge.www | |
77 | # _domain=domain.com | |
78 | _get_root() { | |
ec540743 TN |
79 | fulldomain=$1 |
80 | ||
81 | if ! _get_root_by_getList "$fulldomain"; then | |
82 | _debug "Failed domain lookup via domains.getList api call. Trying domain lookup via domains.dns.getHosts api." | |
83 | # The above "getList" api will only return hosts *owned* by the calling user. However, if the calling | |
84 | # user is not the owner, but still has administrative rights, we must query the getHosts api directly. | |
85 | # See this comment and the official namecheap response: http://disq.us/p/1q6v9x9 | |
86 | if ! _get_root_by_getHosts "$fulldomain"; then | |
87 | return 1 | |
88 | fi | |
89 | fi | |
90 | ||
91 | return 0 | |
92 | } | |
93 | ||
94 | _get_root_by_getList() { | |
0d03309c L |
95 | domain=$1 |
96 | ||
97 | if ! _namecheap_post "namecheap.domains.getList"; then | |
697e694d L |
98 | _err "$error" |
99 | return 1 | |
0d03309c L |
100 | fi |
101 | ||
102 | i=2 | |
103 | p=1 | |
104 | ||
105 | while true; do | |
3975792b | 106 | |
0d03309c L |
107 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) |
108 | _debug h "$h" | |
109 | if [ -z "$h" ]; then | |
110 | #not valid | |
111 | return 1 | |
112 | fi | |
ec540743 TN |
113 | if ! _contains "$h" "\\."; then |
114 | #not valid | |
115 | return 1 | |
116 | fi | |
0d03309c L |
117 | |
118 | if ! _contains "$response" "$h"; then | |
119 | _debug "$h not found" | |
120 | else | |
121 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) | |
122 | _domain="$h" | |
123 | return 0 | |
124 | fi | |
125 | p="$i" | |
126 | i=$(_math "$i" + 1) | |
127 | done | |
128 | return 1 | |
129 | } | |
130 | ||
ec540743 TN |
131 | _get_root_by_getHosts() { |
132 | i=100 | |
133 | p=99 | |
134 | ||
135 | while [ $p -ne 0 ]; do | |
136 | ||
137 | h=$(printf "%s" "$1" | cut -d . -f $i-100) | |
138 | if [ -n "$h" ]; then | |
139 | if _contains "$h" "\\."; then | |
140 | _debug h "$h" | |
141 | if _namecheap_set_tld_sld "$h"; then | |
142 | _sub_domain=$(printf "%s" "$1" | cut -d . -f 1-$p) | |
143 | _domain="$h" | |
144 | return 0 | |
145 | else | |
146 | _debug "$h not found" | |
147 | fi | |
148 | fi | |
149 | fi | |
150 | i="$p" | |
151 | p=$(_math "$p" - 1) | |
152 | done | |
153 | return 1 | |
154 | } | |
155 | ||
0d03309c | 156 | _namecheap_set_publicip() { |
3975792b | 157 | |
d813be1f L |
158 | if [ -z "$NAMECHEAP_SOURCEIP" ]; then |
159 | _err "No Source IP specified for Namecheap API." | |
f49e8ec5 | 160 | _err "Use your public ip address or an url to retrieve it (e.g. https://ifconfig.co/ip) and export it as NAMECHEAP_SOURCEIP" |
d813be1f L |
161 | return 1 |
162 | else | |
697e694d | 163 | _saveaccountconf NAMECHEAP_SOURCEIP "$NAMECHEAP_SOURCEIP" |
d813be1f | 164 | _debug sourceip "$NAMECHEAP_SOURCEIP" |
3975792b | 165 | |
d813be1f | 166 | ip=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}') |
28a9df66 | 167 | addr=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '(http|https):\/\/.*') |
3975792b | 168 | |
d813be1f L |
169 | _debug2 ip "$ip" |
170 | _debug2 addr "$addr" | |
3975792b | 171 | |
d813be1f L |
172 | if [ -n "$ip" ]; then |
173 | _publicip="$ip" | |
174 | elif [ -n "$addr" ]; then | |
175 | _publicip=$(_get "$addr") | |
b859dd66 | 176 | else |
d813be1f | 177 | _err "No Source IP specified for Namecheap API." |
f49e8ec5 | 178 | _err "Use your public ip address or an url to retrieve it (e.g. https://ifconfig.co/ip) and export it as NAMECHEAP_SOURCEIP" |
d813be1f L |
179 | return 1 |
180 | fi | |
181 | fi | |
3975792b | 182 | |
d813be1f | 183 | _debug publicip "$_publicip" |
3975792b | 184 | |
d813be1f | 185 | return 0 |
0d03309c L |
186 | } |
187 | ||
188 | _namecheap_post() { | |
189 | command=$1 | |
190 | data="ApiUser=${NAMECHEAP_USERNAME}&ApiKey=${NAMECHEAP_API_KEY}&ClientIp=${_publicip}&UserName=${NAMECHEAP_USERNAME}&Command=${command}" | |
cc6159b3 | 191 | _debug2 "_namecheap_post data" "$data" |
0d03309c L |
192 | response="$(_post "$data" "$NAMECHEAP_API" "" "POST")" |
193 | _debug2 response "$response" | |
194 | ||
195 | if _contains "$response" "Status=\"ERROR\"" >/dev/null; then | |
196 | error=$(echo "$response" | _egrep_o ">.*<\\/Error>" | cut -d '<' -f 1 | tr -d '>') | |
197 | _err "error $error" | |
198 | return 1 | |
199 | fi | |
200 | ||
201 | return 0 | |
202 | } | |
203 | ||
0d03309c L |
204 | _namecheap_parse_host() { |
205 | _host=$1 | |
0d03309c L |
206 | _debug _host "$_host" |
207 | ||
10ba2cd3 | 208 | _hostid=$(echo "$_host" | _egrep_o ' HostId="[^"]*' | cut -d '"' -f 2) |
209 | _hostname=$(echo "$_host" | _egrep_o ' Name="[^"]*' | cut -d '"' -f 2) | |
210 | _hosttype=$(echo "$_host" | _egrep_o ' Type="[^"]*' | cut -d '"' -f 2) | |
3817ddef | 211 | _hostaddress=$(echo "$_host" | _egrep_o ' Address="[^"]*' | cut -d '"' -f 2 | _xml_decode) |
10ba2cd3 | 212 | _hostmxpref=$(echo "$_host" | _egrep_o ' MXPref="[^"]*' | cut -d '"' -f 2) |
213 | _hostttl=$(echo "$_host" | _egrep_o ' TTL="[^"]*' | cut -d '"' -f 2) | |
0d03309c L |
214 | |
215 | _debug hostid "$_hostid" | |
216 | _debug hostname "$_hostname" | |
217 | _debug hosttype "$_hosttype" | |
218 | _debug hostaddress "$_hostaddress" | |
219 | _debug hostmxpref "$_hostmxpref" | |
220 | _debug hostttl "$_hostttl" | |
0d03309c L |
221 | } |
222 | ||
223 | _namecheap_check_config() { | |
224 | ||
225 | if [ -z "$NAMECHEAP_API_KEY" ]; then | |
226 | _err "No API key specified for Namecheap API." | |
227 | _err "Create your key and export it as NAMECHEAP_API_KEY" | |
228 | return 1 | |
229 | fi | |
230 | ||
231 | if [ -z "$NAMECHEAP_USERNAME" ]; then | |
232 | _err "No username key specified for Namecheap API." | |
233 | _err "Create your key and export it as NAMECHEAP_USERNAME" | |
234 | return 1 | |
235 | fi | |
236 | ||
237 | _saveaccountconf NAMECHEAP_API_KEY "$NAMECHEAP_API_KEY" | |
238 | _saveaccountconf NAMECHEAP_USERNAME "$NAMECHEAP_USERNAME" | |
239 | ||
240 | return 0 | |
241 | } | |
242 | ||
243 | _set_namecheap_TXT() { | |
244 | subdomain=$2 | |
245 | txt=$3 | |
46b3a915 L |
246 | |
247 | if ! _namecheap_set_tld_sld "$1"; then | |
248 | return 1 | |
249 | fi | |
250 | ||
251 | request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}" | |
0d03309c L |
252 | |
253 | if ! _namecheap_post "$request"; then | |
697e694d L |
254 | _err "$error" |
255 | return 1 | |
0d03309c L |
256 | fi |
257 | ||
b859dd66 | 258 | hosts=$(echo "$response" | _egrep_o '<host[^>]*') |
0d03309c L |
259 | _debug hosts "$hosts" |
260 | ||
261 | if [ -z "$hosts" ]; then | |
444a0282 | 262 | _err "Hosts not found" |
697e694d | 263 | return 1 |
0d03309c L |
264 | fi |
265 | ||
d813be1f | 266 | _namecheap_reset_hostList |
0d03309c | 267 | |
d813be1f | 268 | while read -r host; do |
0d03309c | 269 | if _contains "$host" "<host"; then |
0d03309c | 270 | _namecheap_parse_host "$host" |
cc6159b3 | 271 | _debug2 _hostname "_hostname" |
272 | _debug2 _hosttype "_hosttype" | |
273 | _debug2 _hostaddress "_hostaddress" | |
274 | _debug2 _hostmxpref "_hostmxpref" | |
275 | _hostaddress="$(printf "%s" "$_hostaddress" | _url_encode)" | |
276 | _debug2 "encoded _hostaddress" "_hostaddress" | |
b859dd66 L |
277 | _namecheap_add_host "$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl" |
278 | fi | |
279 | done <<EOT | |
280 | echo "$hosts" | |
281 | EOT | |
282 | ||
283 | _namecheap_add_host "$subdomain" "TXT" "$txt" 10 120 | |
284 | ||
285 | _debug hostrequestfinal "$_hostrequest" | |
286 | ||
46b3a915 | 287 | request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}" |
b859dd66 L |
288 | |
289 | if ! _namecheap_post "$request"; then | |
697e694d L |
290 | _err "$error" |
291 | return 1 | |
b859dd66 L |
292 | fi |
293 | ||
294 | return 0 | |
295 | } | |
296 | ||
297 | _del_namecheap_TXT() { | |
298 | subdomain=$2 | |
299 | txt=$3 | |
46b3a915 L |
300 | |
301 | if ! _namecheap_set_tld_sld "$1"; then | |
302 | return 1 | |
303 | fi | |
304 | ||
305 | request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}" | |
b859dd66 L |
306 | |
307 | if ! _namecheap_post "$request"; then | |
697e694d L |
308 | _err "$error" |
309 | return 1 | |
b859dd66 L |
310 | fi |
311 | ||
312 | hosts=$(echo "$response" | _egrep_o '<host[^>]*') | |
313 | _debug hosts "$hosts" | |
314 | ||
315 | if [ -z "$hosts" ]; then | |
444a0282 | 316 | _err "Hosts not found" |
697e694d | 317 | return 1 |
b859dd66 L |
318 | fi |
319 | ||
320 | _namecheap_reset_hostList | |
321 | ||
322 | found=0 | |
0d03309c | 323 | |
b859dd66 L |
324 | while read -r host; do |
325 | if _contains "$host" "<host"; then | |
326 | _namecheap_parse_host "$host" | |
697e694d L |
327 | if [ "$_hosttype" = "TXT" ] && [ "$_hostname" = "$subdomain" ] && [ "$_hostaddress" = "$txt" ]; then |
328 | _debug "TXT entry found" | |
3975792b | 329 | found=1 |
0d03309c | 330 | else |
43877d26 | 331 | _hostaddress="$(printf "%s" "$_hostaddress" | _url_encode)" |
d813be1f | 332 | _namecheap_add_host "$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl" |
b859dd66 | 333 | fi |
0d03309c | 334 | fi |
0d03309c | 335 | done <<EOT |
d813be1f | 336 | echo "$hosts" |
0d03309c L |
337 | EOT |
338 | ||
339 | if [ $found -eq 0 ]; then | |
b859dd66 L |
340 | _debug "TXT entry not found" |
341 | return 0 | |
0d03309c L |
342 | fi |
343 | ||
d813be1f | 344 | _debug hostrequestfinal "$_hostrequest" |
0d03309c | 345 | |
46b3a915 | 346 | request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}" |
0d03309c L |
347 | |
348 | if ! _namecheap_post "$request"; then | |
697e694d L |
349 | _err "$error" |
350 | return 1 | |
0d03309c L |
351 | fi |
352 | ||
353 | return 0 | |
354 | } | |
355 | ||
d813be1f L |
356 | _namecheap_reset_hostList() { |
357 | _hostindex=0 | |
358 | _hostrequest="" | |
359 | } | |
360 | ||
361 | #Usage: _namecheap_add_host HostName RecordType Address MxPref TTL | |
362 | _namecheap_add_host() { | |
363 | _hostindex=$(_math "$_hostindex" + 1) | |
364 | _hostrequest=$(printf '%s&HostName%d=%s&RecordType%d=%s&Address%d=%s&MXPref%d=%d&TTL%d=%d' "$_hostrequest" "$_hostindex" "$1" "$_hostindex" "$2" "$_hostindex" "$3" "$_hostindex" "$4" "$_hostindex" "$5") | |
365 | } | |
46b3a915 L |
366 | |
367 | _namecheap_set_tld_sld() { | |
368 | domain=$1 | |
369 | _tld="" | |
370 | _sld="" | |
371 | ||
372 | i=2 | |
373 | ||
374 | while true; do | |
375 | ||
376 | _tld=$(printf "%s" "$domain" | cut -d . -f $i-100) | |
377 | _debug tld "$_tld" | |
378 | ||
379 | if [ -z "$_tld" ]; then | |
380 | _debug "invalid tld" | |
381 | return 1 | |
382 | fi | |
383 | ||
384 | j=$(_math "$i" - 1) | |
385 | ||
386 | _sld=$(printf "%s" "$domain" | cut -d . -f 1-"$j") | |
387 | _debug sld "$_sld" | |
388 | ||
389 | if [ -z "$_sld" ]; then | |
390 | _debug "invalid sld" | |
391 | return 1 | |
392 | fi | |
393 | ||
394 | request="namecheap.domains.dns.getHosts&SLD=$_sld&TLD=$_tld" | |
395 | ||
396 | if ! _namecheap_post "$request"; then | |
397 | _debug "sld($_sld)/tld($_tld) not found" | |
398 | else | |
399 | _debug "sld($_sld)/tld($_tld) found" | |
400 | return 0 | |
401 | fi | |
402 | ||
403 | i=$(_math "$i" + 1) | |
404 | ||
405 | done | |
406 | ||
407 | } | |
3817ddef | 408 | |
409 | _xml_decode() { | |
410 | sed 's/"/"/g' | |
411 | } |