]> git.proxmox.com Git - mirror_acme.sh.git/blob - dnsapi/dns_namecheap.sh
Merge pull request #2063 from Neilpang/dev
[mirror_acme.sh.git] / dnsapi / dns_namecheap.sh
1 #!/usr/bin/env sh
2
3 # Namecheap API
4 # https://www.namecheap.com/support/api/intro.aspx
5 #
6 # Requires Namecheap API key set in
7 #NAMECHEAP_API_KEY,
8 #NAMECHEAP_USERNAME,
9 #NAMECHEAP_SOURCEIP
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
12 ######## Public functions #####################
13
14 NAMECHEAP_API="https://api.namecheap.com/xml.response"
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
22 _err "$error"
23 return 1
24 fi
25
26 if ! _namecheap_set_publicip; then
27 return 1
28 fi
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
49
50 if ! _namecheap_set_publicip; then
51 return 1
52 fi
53
54 if ! _namecheap_check_config; then
55 _err "$error"
56 return 1
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"
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() {
79 domain=$1
80
81 if ! _namecheap_post "namecheap.domains.getList"; then
82 _err "$error"
83 return 1
84 fi
85
86 i=2
87 p=1
88
89 while true; do
90
91 h=$(printf "%s" "$domain" | cut -d . -f $i-100)
92 _debug h "$h"
93 if [ -z "$h" ]; then
94 #not valid
95 return 1
96 fi
97
98 if ! _contains "$response" "$h"; then
99 _debug "$h not found"
100 else
101 _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
102 _domain="$h"
103 return 0
104 fi
105 p="$i"
106 i=$(_math "$i" + 1)
107 done
108 return 1
109 }
110
111 _namecheap_set_publicip() {
112
113 if [ -z "$NAMECHEAP_SOURCEIP" ]; then
114 _err "No Source IP specified for Namecheap API."
115 _err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
116 return 1
117 else
118 _saveaccountconf NAMECHEAP_SOURCEIP "$NAMECHEAP_SOURCEIP"
119 _debug sourceip "$NAMECHEAP_SOURCEIP"
120
121 ip=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
122 addr=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '(http|https)://.*')
123
124 _debug2 ip "$ip"
125 _debug2 addr "$addr"
126
127 if [ -n "$ip" ]; then
128 _publicip="$ip"
129 elif [ -n "$addr" ]; then
130 _publicip=$(_get "$addr")
131 else
132 _err "No Source IP specified for Namecheap API."
133 _err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
134 return 1
135 fi
136 fi
137
138 _debug publicip "$_publicip"
139
140 return 0
141 }
142
143 _namecheap_post() {
144 command=$1
145 data="ApiUser=${NAMECHEAP_USERNAME}&ApiKey=${NAMECHEAP_API_KEY}&ClientIp=${_publicip}&UserName=${NAMECHEAP_USERNAME}&Command=${command}"
146 _debug2 "_namecheap_post data" "$data"
147 response="$(_post "$data" "$NAMECHEAP_API" "" "POST")"
148 _debug2 response "$response"
149
150 if _contains "$response" "Status=\"ERROR\"" >/dev/null; then
151 error=$(echo "$response" | _egrep_o ">.*<\\/Error>" | cut -d '<' -f 1 | tr -d '>')
152 _err "error $error"
153 return 1
154 fi
155
156 return 0
157 }
158
159 _namecheap_parse_host() {
160 _host=$1
161 _debug _host "$_host"
162
163 _hostid=$(echo "$_host" | _egrep_o ' HostId="[^"]*' | cut -d '"' -f 2)
164 _hostname=$(echo "$_host" | _egrep_o ' Name="[^"]*' | cut -d '"' -f 2)
165 _hosttype=$(echo "$_host" | _egrep_o ' Type="[^"]*' | cut -d '"' -f 2)
166 _hostaddress=$(echo "$_host" | _egrep_o ' Address="[^"]*' | cut -d '"' -f 2)
167 _hostmxpref=$(echo "$_host" | _egrep_o ' MXPref="[^"]*' | cut -d '"' -f 2)
168 _hostttl=$(echo "$_host" | _egrep_o ' TTL="[^"]*' | cut -d '"' -f 2)
169
170 _debug hostid "$_hostid"
171 _debug hostname "$_hostname"
172 _debug hosttype "$_hosttype"
173 _debug hostaddress "$_hostaddress"
174 _debug hostmxpref "$_hostmxpref"
175 _debug hostttl "$_hostttl"
176 }
177
178 _namecheap_check_config() {
179
180 if [ -z "$NAMECHEAP_API_KEY" ]; then
181 _err "No API key specified for Namecheap API."
182 _err "Create your key and export it as NAMECHEAP_API_KEY"
183 return 1
184 fi
185
186 if [ -z "$NAMECHEAP_USERNAME" ]; then
187 _err "No username key specified for Namecheap API."
188 _err "Create your key and export it as NAMECHEAP_USERNAME"
189 return 1
190 fi
191
192 _saveaccountconf NAMECHEAP_API_KEY "$NAMECHEAP_API_KEY"
193 _saveaccountconf NAMECHEAP_USERNAME "$NAMECHEAP_USERNAME"
194
195 return 0
196 }
197
198 _set_namecheap_TXT() {
199 subdomain=$2
200 txt=$3
201
202 if ! _namecheap_set_tld_sld "$1"; then
203 return 1
204 fi
205
206 request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}"
207
208 if ! _namecheap_post "$request"; then
209 _err "$error"
210 return 1
211 fi
212
213 hosts=$(echo "$response" | _egrep_o '<host[^>]*')
214 _debug hosts "$hosts"
215
216 if [ -z "$hosts" ]; then
217 _error "Hosts not found"
218 return 1
219 fi
220
221 _namecheap_reset_hostList
222
223 while read -r host; do
224 if _contains "$host" "<host"; then
225 _namecheap_parse_host "$host"
226 _debug2 _hostname "_hostname"
227 _debug2 _hosttype "_hosttype"
228 _debug2 _hostaddress "_hostaddress"
229 _debug2 _hostmxpref "_hostmxpref"
230 _hostaddress="$(printf "%s" "$_hostaddress" | _url_encode)"
231 _debug2 "encoded _hostaddress" "_hostaddress"
232 _namecheap_add_host "$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl"
233 fi
234 done <<EOT
235 echo "$hosts"
236 EOT
237
238 _namecheap_add_host "$subdomain" "TXT" "$txt" 10 120
239
240 _debug hostrequestfinal "$_hostrequest"
241
242 request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}"
243
244 if ! _namecheap_post "$request"; then
245 _err "$error"
246 return 1
247 fi
248
249 return 0
250 }
251
252 _del_namecheap_TXT() {
253 subdomain=$2
254 txt=$3
255
256 if ! _namecheap_set_tld_sld "$1"; then
257 return 1
258 fi
259
260 request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}"
261
262 if ! _namecheap_post "$request"; then
263 _err "$error"
264 return 1
265 fi
266
267 hosts=$(echo "$response" | _egrep_o '<host[^>]*')
268 _debug hosts "$hosts"
269
270 if [ -z "$hosts" ]; then
271 _error "Hosts not found"
272 return 1
273 fi
274
275 _namecheap_reset_hostList
276
277 found=0
278
279 while read -r host; do
280 if _contains "$host" "<host"; then
281 _namecheap_parse_host "$host"
282 if [ "$_hosttype" = "TXT" ] && [ "$_hostname" = "$subdomain" ] && [ "$_hostaddress" = "$txt" ]; then
283 _debug "TXT entry found"
284 found=1
285 else
286 _hostaddress="$(printf "%s" "$_hostaddress" | _url_encode)"
287 _namecheap_add_host "$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl"
288 fi
289 fi
290 done <<EOT
291 echo "$hosts"
292 EOT
293
294 if [ $found -eq 0 ]; then
295 _debug "TXT entry not found"
296 return 0
297 fi
298
299 _debug hostrequestfinal "$_hostrequest"
300
301 request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}"
302
303 if ! _namecheap_post "$request"; then
304 _err "$error"
305 return 1
306 fi
307
308 return 0
309 }
310
311 _namecheap_reset_hostList() {
312 _hostindex=0
313 _hostrequest=""
314 }
315
316 #Usage: _namecheap_add_host HostName RecordType Address MxPref TTL
317 _namecheap_add_host() {
318 _hostindex=$(_math "$_hostindex" + 1)
319 _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")
320 }
321
322 _namecheap_set_tld_sld() {
323 domain=$1
324 _tld=""
325 _sld=""
326
327 i=2
328
329 while true; do
330
331 _tld=$(printf "%s" "$domain" | cut -d . -f $i-100)
332 _debug tld "$_tld"
333
334 if [ -z "$_tld" ]; then
335 _debug "invalid tld"
336 return 1
337 fi
338
339 j=$(_math "$i" - 1)
340
341 _sld=$(printf "%s" "$domain" | cut -d . -f 1-"$j")
342 _debug sld "$_sld"
343
344 if [ -z "$_sld" ]; then
345 _debug "invalid sld"
346 return 1
347 fi
348
349 request="namecheap.domains.dns.getHosts&SLD=$_sld&TLD=$_tld"
350
351 if ! _namecheap_post "$request"; then
352 _debug "sld($_sld)/tld($_tld) not found"
353 else
354 _debug "sld($_sld)/tld($_tld) found"
355 return 0
356 fi
357
358 i=$(_math "$i" + 1)
359
360 done
361
362 }