]> git.proxmox.com Git - mirror_acme.sh.git/blame - dnsapi/dns_namecheap.sh
Merge pull request #4658 from Justman10000/master
[mirror_acme.sh.git] / dnsapi / dns_namecheap.sh
CommitLineData
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 14NAMECHEAP_API="https://api.namecheap.com/xml.response"
0d03309c
L
15
16#Usage: dns_namecheap_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
17dns_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.
46dns_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.
3c933158 85 # See this comment and the official namecheap response: https://disq.us/p/1q6v9x9
ec540743
TN
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
280echo "$hosts"
281EOT
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 336echo "$hosts"
0d03309c
L
337EOT
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/&quot;/"/g'
411}