4 # https://www.namecheap.com/support/api/intro.aspx
6 # Requires Namecheap API key set in
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.
12 ######## Public functions #####################
14 NAMECHEAP_API
="https://api.namecheap.com/xml.response"
16 #Usage: dns_namecheap_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
21 if ! _namecheap_check_config
; then
26 if ! _namecheap_set_publicip
; then
30 _debug
"First detect the root zone"
31 if ! _get_root
"$fulldomain"; then
36 _debug fulldomain
"$fulldomain"
37 _debug txtvalue
"$txtvalue"
38 _debug domain
"$_domain"
39 _debug sub_domain
"$_sub_domain"
41 _set_namecheap_TXT
"$_domain" "$_sub_domain" "$txtvalue"
44 #Usage: fulldomain txtvalue
45 #Remove the txt record after validation.
50 if ! _namecheap_set_publicip
; then
54 if ! _namecheap_check_config
; then
59 _debug
"First detect the root zone"
60 if ! _get_root
"$fulldomain"; then
65 _debug fulldomain
"$fulldomain"
66 _debug txtvalue
"$txtvalue"
67 _debug domain
"$_domain"
68 _debug sub_domain
"$_sub_domain"
70 _del_namecheap_TXT
"$_domain" "$_sub_domain" "$txtvalue"
73 #################### Private functions below ##################################
74 #_acme-challenge.www.domain.com
76 # _sub_domain=_acme-challenge.www
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: https://disq.us/p/1q6v9x9
86 if ! _get_root_by_getHosts
"$fulldomain"; then
94 _get_root_by_getList
() {
97 if ! _namecheap_post
"namecheap.domains.getList"; then
107 h
=$
(printf "%s" "$domain" | cut
-d .
-f $i-100)
113 if ! _contains
"$h" "\\."; then
118 if ! _contains
"$response" "$h"; then
119 _debug
"$h not found"
121 _sub_domain
=$
(printf "%s" "$domain" | cut
-d .
-f 1-$p)
131 _get_root_by_getHosts
() {
135 while [ $p -ne 0 ]; do
137 h
=$
(printf "%s" "$1" | cut
-d .
-f $i-100)
139 if _contains
"$h" "\\."; then
141 if _namecheap_set_tld_sld
"$h"; then
142 _sub_domain
=$
(printf "%s" "$1" | cut
-d .
-f 1-$p)
146 _debug
"$h not found"
156 _namecheap_set_publicip
() {
158 if [ -z "$NAMECHEAP_SOURCEIP" ]; then
159 _err
"No Source IP specified for Namecheap API."
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"
163 _saveaccountconf NAMECHEAP_SOURCEIP
"$NAMECHEAP_SOURCEIP"
164 _debug sourceip
"$NAMECHEAP_SOURCEIP"
166 ip
=$
(echo "$NAMECHEAP_SOURCEIP" | _egrep_o
'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
167 addr
=$
(echo "$NAMECHEAP_SOURCEIP" | _egrep_o
'(http|https):\/\/.*')
172 if [ -n "$ip" ]; then
174 elif [ -n "$addr" ]; then
175 _publicip
=$
(_get
"$addr")
177 _err
"No Source IP specified for Namecheap API."
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"
183 _debug publicip
"$_publicip"
190 data
="ApiUser=${NAMECHEAP_USERNAME}&ApiKey=${NAMECHEAP_API_KEY}&ClientIp=${_publicip}&UserName=${NAMECHEAP_USERNAME}&Command=${command}"
191 _debug2
"_namecheap_post data" "$data"
192 response
="$(_post "$data" "$NAMECHEAP_API" "" "POST
")"
193 _debug2 response
"$response"
195 if _contains
"$response" "Status=\"ERROR\"" >/dev
/null
; then
196 error
=$
(echo "$response" | _egrep_o
">.*<\\/Error>" | cut
-d '<' -f 1 |
tr -d '>')
204 _namecheap_parse_host
() {
206 _debug _host
"$_host"
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)
211 _hostaddress
=$
(echo "$_host" | _egrep_o
' Address="[^"]*' | cut
-d '"' -f 2 | _xml_decode
)
212 _hostmxpref
=$
(echo "$_host" | _egrep_o
' MXPref="[^"]*' | cut
-d '"' -f 2)
213 _hostttl
=$
(echo "$_host" | _egrep_o
' TTL="[^"]*' | cut
-d '"' -f 2)
215 _debug hostid
"$_hostid"
216 _debug hostname
"$_hostname"
217 _debug hosttype
"$_hosttype"
218 _debug hostaddress
"$_hostaddress"
219 _debug hostmxpref
"$_hostmxpref"
220 _debug hostttl
"$_hostttl"
223 _namecheap_check_config
() {
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"
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"
237 _saveaccountconf NAMECHEAP_API_KEY
"$NAMECHEAP_API_KEY"
238 _saveaccountconf NAMECHEAP_USERNAME
"$NAMECHEAP_USERNAME"
243 _set_namecheap_TXT
() {
247 if ! _namecheap_set_tld_sld
"$1"; then
251 request
="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}"
253 if ! _namecheap_post
"$request"; then
258 hosts
=$
(echo "$response" | _egrep_o
'<host[^>]*')
259 _debug hosts
"$hosts"
261 if [ -z "$hosts" ]; then
262 _err
"Hosts not found"
266 _namecheap_reset_hostList
268 while read -r host; do
269 if _contains
"$host" "<host"; then
270 _namecheap_parse_host
"$host"
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"
277 _namecheap_add_host
"$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl"
283 _namecheap_add_host
"$subdomain" "TXT" "$txt" 10 120
285 _debug hostrequestfinal
"$_hostrequest"
287 request
="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}"
289 if ! _namecheap_post
"$request"; then
297 _del_namecheap_TXT
() {
301 if ! _namecheap_set_tld_sld
"$1"; then
305 request
="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}"
307 if ! _namecheap_post
"$request"; then
312 hosts
=$
(echo "$response" | _egrep_o
'<host[^>]*')
313 _debug hosts
"$hosts"
315 if [ -z "$hosts" ]; then
316 _err
"Hosts not found"
320 _namecheap_reset_hostList
324 while read -r host; do
325 if _contains
"$host" "<host"; then
326 _namecheap_parse_host
"$host"
327 if [ "$_hosttype" = "TXT" ] && [ "$_hostname" = "$subdomain" ] && [ "$_hostaddress" = "$txt" ]; then
328 _debug
"TXT entry found"
331 _hostaddress
="$(printf "%s
" "$_hostaddress" | _url_encode)"
332 _namecheap_add_host
"$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl"
339 if [ $found -eq 0 ]; then
340 _debug
"TXT entry not found"
344 _debug hostrequestfinal
"$_hostrequest"
346 request
="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}"
348 if ! _namecheap_post
"$request"; then
356 _namecheap_reset_hostList
() {
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")
367 _namecheap_set_tld_sld
() {
376 _tld
=$
(printf "%s" "$domain" | cut
-d .
-f $i-100)
379 if [ -z "$_tld" ]; then
386 _sld
=$
(printf "%s" "$domain" | cut
-d .
-f 1-"$j")
389 if [ -z "$_sld" ]; then
394 request
="namecheap.domains.dns.getHosts&SLD=$_sld&TLD=$_tld"
396 if ! _namecheap_post
"$request"; then
397 _debug
"sld($_sld)/tld($_tld) not found"
399 _debug
"sld($_sld)/tld($_tld) found"