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