2018-09-02 15:25:44 +02:00
#!/usr/bin/env sh
2023-11-18 17:57:12 +01:00
# shellcheck disable=SC2034
dns_namecheap_info = ' NameCheap.com
Site: NameCheap.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_namecheap
Options:
NAMECHEAP_API_KEY API Key
NAMECHEAP_USERNAME Username
NAMECHEAP_SOURCEIP Source IP
Issues: github.com/acmesh-official/acme.sh/issues/2107
'
2018-09-02 15:25:44 +02:00
# Namecheap API
# https://www.namecheap.com/support/api/intro.aspx
2018-09-08 01:06:35 +02:00
# 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.
2018-09-02 15:25:44 +02:00
######## Public functions #####################
2019-01-26 12:15:13 +01:00
NAMECHEAP_API = "https://api.namecheap.com/xml.response"
2018-09-02 15:25:44 +02:00
#Usage: dns_namecheap_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_namecheap_add( ) {
fulldomain = $1
txtvalue = $2
if ! _namecheap_check_config; then
2018-09-08 01:28:56 +02:00
_err " $error "
return 1
2018-09-02 15:25:44 +02:00
fi
2018-09-05 15:29:42 +02:00
if ! _namecheap_set_publicip; then
2018-09-08 01:28:56 +02:00
return 1
2018-09-05 15:29:42 +02:00
fi
2018-09-02 15:25:44 +02:00
_debug "First detect the root zone"
if ! _get_root " $fulldomain " ; then
_err "invalid domain"
return 1
fi
_debug fulldomain " $fulldomain "
_debug txtvalue " $txtvalue "
_debug domain " $_domain "
_debug sub_domain " $_sub_domain "
_set_namecheap_TXT " $_domain " " $_sub_domain " " $txtvalue "
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_namecheap_rm( ) {
fulldomain = $1
txtvalue = $2
2018-09-08 02:06:35 +02:00
2018-09-05 15:29:42 +02:00
if ! _namecheap_set_publicip; then
2018-09-08 01:28:56 +02:00
return 1
2018-09-05 15:29:42 +02:00
fi
2018-09-02 15:25:44 +02:00
if ! _namecheap_check_config; then
2018-09-08 01:28:56 +02:00
_err " $error "
return 1
2018-09-02 15:25:44 +02:00
fi
_debug "First detect the root zone"
if ! _get_root " $fulldomain " ; then
_err "invalid domain"
return 1
fi
_debug fulldomain " $fulldomain "
_debug txtvalue " $txtvalue "
_debug domain " $_domain "
_debug sub_domain " $_sub_domain "
_del_namecheap_TXT " $_domain " " $_sub_domain " " $txtvalue "
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
_get_root( ) {
2019-02-25 12:19:36 +01:00
fulldomain = $1
if ! _get_root_by_getList " $fulldomain " ; then
_debug "Failed domain lookup via domains.getList api call. Trying domain lookup via domains.dns.getHosts api."
# The above "getList" api will only return hosts *owned* by the calling user. However, if the calling
# user is not the owner, but still has administrative rights, we must query the getHosts api directly.
2022-10-17 10:45:48 +02:00
# See this comment and the official namecheap response: https://disq.us/p/1q6v9x9
2019-02-25 12:19:36 +01:00
if ! _get_root_by_getHosts " $fulldomain " ; then
return 1
fi
fi
return 0
}
_get_root_by_getList( ) {
2018-09-02 15:25:44 +02:00
domain = $1
if ! _namecheap_post "namecheap.domains.getList" ; then
2018-09-08 01:28:56 +02:00
_err " $error "
return 1
2018-09-02 15:25:44 +02:00
fi
i = 2
p = 1
while true; do
2018-09-08 02:06:35 +02:00
2024-10-13 17:41:22 +02:00
h = $( printf "%s" " $domain " | cut -d . -f " $i " -100)
2018-09-02 15:25:44 +02:00
_debug h " $h "
if [ -z " $h " ] ; then
#not valid
return 1
fi
2019-02-25 12:19:36 +01:00
if ! _contains " $h " "\\." ; then
#not valid
return 1
fi
2018-09-02 15:25:44 +02:00
if ! _contains " $response " " $h " ; then
_debug " $h not found "
else
2024-10-13 17:41:22 +02:00
_sub_domain = $( printf "%s" " $domain " | cut -d . -f 1-" $p " )
2018-09-02 15:25:44 +02:00
_domain = " $h "
return 0
fi
p = " $i "
i = $( _math " $i " + 1)
done
return 1
}
2019-02-25 12:19:36 +01:00
_get_root_by_getHosts( ) {
i = 100
p = 99
2024-10-13 17:55:22 +02:00
while [ " $p " -ne 0 ] ; do
2019-02-25 12:19:36 +01:00
2024-10-13 17:41:22 +02:00
h = $( printf "%s" " $1 " | cut -d . -f " $i " -100)
2019-02-25 12:19:36 +01:00
if [ -n " $h " ] ; then
if _contains " $h " "\\." ; then
_debug h " $h "
if _namecheap_set_tld_sld " $h " ; then
2024-10-13 17:41:22 +02:00
_sub_domain = $( printf "%s" " $1 " | cut -d . -f 1-" $p " )
2019-02-25 12:19:36 +01:00
_domain = " $h "
return 0
else
_debug " $h not found "
fi
fi
fi
i = " $p "
p = $( _math " $p " - 1)
done
return 1
}
2018-09-02 15:25:44 +02:00
_namecheap_set_publicip( ) {
2018-09-08 02:06:35 +02:00
2018-09-05 15:29:42 +02:00
if [ -z " $NAMECHEAP_SOURCEIP " ] ; then
_err "No Source IP specified for Namecheap API."
2021-01-25 20:46:52 +01:00
_err "Use your public ip address or an url to retrieve it (e.g. https://ifconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
2018-09-05 15:29:42 +02:00
return 1
else
2018-09-08 01:28:56 +02:00
_saveaccountconf NAMECHEAP_SOURCEIP " $NAMECHEAP_SOURCEIP "
2018-09-05 15:29:42 +02:00
_debug sourceip " $NAMECHEAP_SOURCEIP "
2018-09-08 02:06:35 +02:00
2018-09-05 15:29:42 +02:00
ip = $( echo " $NAMECHEAP_SOURCEIP " | _egrep_o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' )
2019-07-13 14:35:09 +02:00
addr = $( echo " $NAMECHEAP_SOURCEIP " | _egrep_o '(http|https):\/\/.*' )
2018-09-08 02:06:35 +02:00
2018-09-05 15:29:42 +02:00
_debug2 ip " $ip "
_debug2 addr " $addr "
2018-09-08 02:06:35 +02:00
2018-09-05 15:29:42 +02:00
if [ -n " $ip " ] ; then
_publicip = " $ip "
elif [ -n " $addr " ] ; then
_publicip = $( _get " $addr " )
2018-09-07 14:53:21 +02:00
else
2018-09-05 15:29:42 +02:00
_err "No Source IP specified for Namecheap API."
2021-01-25 20:46:52 +01:00
_err "Use your public ip address or an url to retrieve it (e.g. https://ifconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
2018-09-05 15:29:42 +02:00
return 1
fi
fi
2018-09-08 02:06:35 +02:00
2018-09-05 15:29:42 +02:00
_debug publicip " $_publicip "
2018-09-08 02:06:35 +02:00
2018-09-05 15:29:42 +02:00
return 0
2018-09-02 15:25:44 +02:00
}
_namecheap_post( ) {
command = $1
data = " ApiUser= ${ NAMECHEAP_USERNAME } &ApiKey= ${ NAMECHEAP_API_KEY } &ClientIp= ${ _publicip } &UserName= ${ NAMECHEAP_USERNAME } &Command= ${ command } "
2019-01-26 12:15:13 +01:00
_debug2 "_namecheap_post data" " $data "
2018-09-02 15:25:44 +02:00
response = " $( _post " $data " " $NAMECHEAP_API " "" "POST" ) "
_debug2 response " $response "
if _contains " $response " "Status=\"ERROR\"" >/dev/null; then
error = $( echo " $response " | _egrep_o ">.*<\\/Error>" | cut -d '<' -f 1 | tr -d '>' )
_err " error $error "
return 1
fi
return 0
}
_namecheap_parse_host( ) {
_host = $1
_debug _host " $_host "
2019-01-10 22:06:46 +01:00
_hostid = $( echo " $_host " | _egrep_o ' HostId="[^"]*' | cut -d '"' -f 2)
_hostname = $( echo " $_host " | _egrep_o ' Name="[^"]*' | cut -d '"' -f 2)
_hosttype = $( echo " $_host " | _egrep_o ' Type="[^"]*' | cut -d '"' -f 2)
2021-03-04 14:38:51 +01:00
_hostaddress = $( echo " $_host " | _egrep_o ' Address="[^"]*' | cut -d '"' -f 2 | _xml_decode)
2019-01-10 22:06:46 +01:00
_hostmxpref = $( echo " $_host " | _egrep_o ' MXPref="[^"]*' | cut -d '"' -f 2)
_hostttl = $( echo " $_host " | _egrep_o ' TTL="[^"]*' | cut -d '"' -f 2)
2018-09-02 15:25:44 +02:00
_debug hostid " $_hostid "
_debug hostname " $_hostname "
_debug hosttype " $_hosttype "
_debug hostaddress " $_hostaddress "
_debug hostmxpref " $_hostmxpref "
_debug hostttl " $_hostttl "
}
_namecheap_check_config( ) {
if [ -z " $NAMECHEAP_API_KEY " ] ; then
_err "No API key specified for Namecheap API."
_err "Create your key and export it as NAMECHEAP_API_KEY"
return 1
fi
if [ -z " $NAMECHEAP_USERNAME " ] ; then
_err "No username key specified for Namecheap API."
_err "Create your key and export it as NAMECHEAP_USERNAME"
return 1
fi
_saveaccountconf NAMECHEAP_API_KEY " $NAMECHEAP_API_KEY "
_saveaccountconf NAMECHEAP_USERNAME " $NAMECHEAP_USERNAME "
return 0
}
_set_namecheap_TXT( ) {
subdomain = $2
txt = $3
2018-10-21 12:17:23 +02:00
if ! _namecheap_set_tld_sld " $1 " ; then
return 1
fi
request = " namecheap.domains.dns.getHosts&SLD= ${ _sld } &TLD= ${ _tld } "
2018-09-02 15:25:44 +02:00
if ! _namecheap_post " $request " ; then
2018-09-08 01:28:56 +02:00
_err " $error "
return 1
2018-09-02 15:25:44 +02:00
fi
2018-09-07 14:53:21 +02:00
hosts = $( echo " $response " | _egrep_o '<host[^>]*' )
2018-09-02 15:25:44 +02:00
_debug hosts " $hosts "
if [ -z " $hosts " ] ; then
2022-05-31 17:41:22 +02:00
_err "Hosts not found"
2018-09-08 01:28:56 +02:00
return 1
2018-09-02 15:25:44 +02:00
fi
2018-09-05 15:29:42 +02:00
_namecheap_reset_hostList
2018-09-02 15:25:44 +02:00
2018-09-05 15:29:42 +02:00
while read -r host; do
2018-09-02 15:25:44 +02:00
if _contains " $host " "<host" ; then
_namecheap_parse_host " $host "
2019-01-26 12:15:13 +01:00
_debug2 _hostname "_hostname"
_debug2 _hosttype "_hosttype"
_debug2 _hostaddress "_hostaddress"
_debug2 _hostmxpref "_hostmxpref"
_hostaddress = " $( printf "%s" " $_hostaddress " | _url_encode) "
_debug2 "encoded _hostaddress" "_hostaddress"
2018-09-07 14:53:21 +02:00
_namecheap_add_host " $_hostname " " $_hosttype " " $_hostaddress " " $_hostmxpref " " $_hostttl "
fi
done <<EOT
echo " $hosts "
EOT
_namecheap_add_host " $subdomain " "TXT" " $txt " 10 120
_debug hostrequestfinal " $_hostrequest "
2018-10-21 12:17:23 +02:00
request = " namecheap.domains.dns.setHosts&SLD= ${ _sld } &TLD= ${ _tld } ${ _hostrequest } "
2018-09-07 14:53:21 +02:00
if ! _namecheap_post " $request " ; then
2018-09-08 01:28:56 +02:00
_err " $error "
return 1
2018-09-07 14:53:21 +02:00
fi
return 0
}
_del_namecheap_TXT( ) {
subdomain = $2
txt = $3
2018-10-21 12:17:23 +02:00
if ! _namecheap_set_tld_sld " $1 " ; then
return 1
fi
request = " namecheap.domains.dns.getHosts&SLD= ${ _sld } &TLD= ${ _tld } "
2018-09-07 14:53:21 +02:00
if ! _namecheap_post " $request " ; then
2018-09-08 01:28:56 +02:00
_err " $error "
return 1
2018-09-07 14:53:21 +02:00
fi
hosts = $( echo " $response " | _egrep_o '<host[^>]*' )
_debug hosts " $hosts "
if [ -z " $hosts " ] ; then
2022-05-31 17:41:22 +02:00
_err "Hosts not found"
2018-09-08 01:28:56 +02:00
return 1
2018-09-07 14:53:21 +02:00
fi
_namecheap_reset_hostList
found = 0
2018-09-02 15:25:44 +02:00
2018-09-07 14:53:21 +02:00
while read -r host; do
if _contains " $host " "<host" ; then
_namecheap_parse_host " $host "
2018-09-08 01:28:56 +02:00
if [ " $_hosttype " = "TXT" ] && [ " $_hostname " = " $subdomain " ] && [ " $_hostaddress " = " $txt " ] ; then
_debug "TXT entry found"
2018-09-08 02:06:35 +02:00
found = 1
2018-09-02 15:25:44 +02:00
else
2019-01-26 13:27:53 +01:00
_hostaddress = " $( printf "%s" " $_hostaddress " | _url_encode) "
2018-09-05 15:29:42 +02:00
_namecheap_add_host " $_hostname " " $_hosttype " " $_hostaddress " " $_hostmxpref " " $_hostttl "
2018-09-07 14:53:21 +02:00
fi
2018-09-02 15:25:44 +02:00
fi
done <<EOT
2018-09-05 15:29:42 +02:00
echo " $hosts "
2018-09-02 15:25:44 +02:00
EOT
if [ $found -eq 0 ] ; then
2018-09-07 14:53:21 +02:00
_debug "TXT entry not found"
return 0
2018-09-02 15:25:44 +02:00
fi
2018-09-05 15:29:42 +02:00
_debug hostrequestfinal " $_hostrequest "
2018-09-02 15:25:44 +02:00
2018-10-21 12:17:23 +02:00
request = " namecheap.domains.dns.setHosts&SLD= ${ _sld } &TLD= ${ _tld } ${ _hostrequest } "
2018-09-02 15:25:44 +02:00
if ! _namecheap_post " $request " ; then
2018-09-08 01:28:56 +02:00
_err " $error "
return 1
2018-09-02 15:25:44 +02:00
fi
return 0
}
2018-09-05 15:29:42 +02:00
_namecheap_reset_hostList( ) {
_hostindex = 0
_hostrequest = ""
}
#Usage: _namecheap_add_host HostName RecordType Address MxPref TTL
_namecheap_add_host( ) {
_hostindex = $( _math " $_hostindex " + 1)
_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 " )
}
2018-10-21 12:17:23 +02:00
_namecheap_set_tld_sld( ) {
domain = $1
_tld = ""
_sld = ""
i = 2
while true; do
2024-10-13 17:41:22 +02:00
_tld = $( printf "%s" " $domain " | cut -d . -f " $i " -100)
2018-10-21 12:17:23 +02:00
_debug tld " $_tld "
if [ -z " $_tld " ] ; then
_debug "invalid tld"
return 1
fi
j = $( _math " $i " - 1)
_sld = $( printf "%s" " $domain " | cut -d . -f 1-" $j " )
_debug sld " $_sld "
if [ -z " $_sld " ] ; then
_debug "invalid sld"
return 1
fi
request = " namecheap.domains.dns.getHosts&SLD= $_sld &TLD= $_tld "
if ! _namecheap_post " $request " ; then
_debug " sld( $_sld )/tld( $_tld ) not found "
else
_debug " sld( $_sld )/tld( $_tld ) found "
return 0
fi
i = $( _math " $i " + 1)
done
}
2021-03-04 14:38:51 +01:00
_xml_decode( ) {
sed 's/"/"/g'
}