123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- #!/usr/bin/env sh
- # Namecheap API
- # https://www.namecheap.com/support/api/intro.aspx
- #
- # Requires Namecheap API key set in
- #NAMECHEAP_API_KEY,
- #NAMECHEAP_USERNAME,
- #NAMECHEAP_SOURCEIP
- # 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.
- ######## Public functions #####################
- NAMECHEAP_API="https://api.namecheap.com/xml.response"
- #Usage: dns_namecheap_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
- dns_namecheap_add() {
- fulldomain=$1
- txtvalue=$2
- if ! _namecheap_check_config; then
- _err "$error"
- return 1
- fi
- if ! _namecheap_set_publicip; then
- return 1
- 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"
- _set_namecheap_TXT "$_domain" "$_sub_domain" "$txtvalue"
- }
- #Usage: fulldomain txtvalue
- #Remove the txt record after validation.
- dns_namecheap_rm() {
- fulldomain=$1
- txtvalue=$2
- if ! _namecheap_set_publicip; then
- return 1
- fi
- if ! _namecheap_check_config; then
- _err "$error"
- return 1
- 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() {
- 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.
- # See this comment and the official namecheap response: http://disq.us/p/1q6v9x9
- if ! _get_root_by_getHosts "$fulldomain"; then
- return 1
- fi
- fi
- return 0
- }
- _get_root_by_getList() {
- domain=$1
- if ! _namecheap_post "namecheap.domains.getList"; then
- _err "$error"
- return 1
- fi
- i=2
- p=1
- while true; do
- h=$(printf "%s" "$domain" | cut -d . -f $i-100)
- _debug h "$h"
- if [ -z "$h" ]; then
- #not valid
- return 1
- fi
- if ! _contains "$h" "\\."; then
- #not valid
- return 1
- fi
- if ! _contains "$response" "$h"; then
- _debug "$h not found"
- else
- _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
- _domain="$h"
- return 0
- fi
- p="$i"
- i=$(_math "$i" + 1)
- done
- return 1
- }
- _get_root_by_getHosts() {
- i=100
- p=99
- while [ $p -ne 0 ]; do
- h=$(printf "%s" "$1" | cut -d . -f $i-100)
- if [ -n "$h" ]; then
- if _contains "$h" "\\."; then
- _debug h "$h"
- if _namecheap_set_tld_sld "$h"; then
- _sub_domain=$(printf "%s" "$1" | cut -d . -f 1-$p)
- _domain="$h"
- return 0
- else
- _debug "$h not found"
- fi
- fi
- fi
- i="$p"
- p=$(_math "$p" - 1)
- done
- return 1
- }
- _namecheap_set_publicip() {
- if [ -z "$NAMECHEAP_SOURCEIP" ]; then
- _err "No Source IP specified for Namecheap API."
- _err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
- return 1
- else
- _saveaccountconf NAMECHEAP_SOURCEIP "$NAMECHEAP_SOURCEIP"
- _debug sourceip "$NAMECHEAP_SOURCEIP"
- ip=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
- addr=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '(http|https):\/\/.*')
- _debug2 ip "$ip"
- _debug2 addr "$addr"
- if [ -n "$ip" ]; then
- _publicip="$ip"
- elif [ -n "$addr" ]; then
- _publicip=$(_get "$addr")
- else
- _err "No Source IP specified for Namecheap API."
- _err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
- return 1
- fi
- fi
- _debug publicip "$_publicip"
- return 0
- }
- _namecheap_post() {
- command=$1
- data="ApiUser=${NAMECHEAP_USERNAME}&ApiKey=${NAMECHEAP_API_KEY}&ClientIp=${_publicip}&UserName=${NAMECHEAP_USERNAME}&Command=${command}"
- _debug2 "_namecheap_post data" "$data"
- 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"
- _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)
- _hostaddress=$(echo "$_host" | _egrep_o ' Address="[^"]*' | cut -d '"' -f 2)
- _hostmxpref=$(echo "$_host" | _egrep_o ' MXPref="[^"]*' | cut -d '"' -f 2)
- _hostttl=$(echo "$_host" | _egrep_o ' TTL="[^"]*' | cut -d '"' -f 2)
- _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
- if ! _namecheap_set_tld_sld "$1"; then
- return 1
- fi
- request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}"
- if ! _namecheap_post "$request"; then
- _err "$error"
- return 1
- fi
- hosts=$(echo "$response" | _egrep_o '<host[^>]*')
- _debug hosts "$hosts"
- if [ -z "$hosts" ]; then
- _error "Hosts not found"
- return 1
- fi
- _namecheap_reset_hostList
- while read -r host; do
- if _contains "$host" "<host"; then
- _namecheap_parse_host "$host"
- _debug2 _hostname "_hostname"
- _debug2 _hosttype "_hosttype"
- _debug2 _hostaddress "_hostaddress"
- _debug2 _hostmxpref "_hostmxpref"
- _hostaddress="$(printf "%s" "$_hostaddress" | _url_encode)"
- _debug2 "encoded _hostaddress" "_hostaddress"
- _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"
- request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}"
- if ! _namecheap_post "$request"; then
- _err "$error"
- return 1
- fi
- return 0
- }
- _del_namecheap_TXT() {
- subdomain=$2
- txt=$3
- if ! _namecheap_set_tld_sld "$1"; then
- return 1
- fi
- request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}"
- if ! _namecheap_post "$request"; then
- _err "$error"
- return 1
- fi
- hosts=$(echo "$response" | _egrep_o '<host[^>]*')
- _debug hosts "$hosts"
- if [ -z "$hosts" ]; then
- _error "Hosts not found"
- return 1
- fi
- _namecheap_reset_hostList
- found=0
- while read -r host; do
- if _contains "$host" "<host"; then
- _namecheap_parse_host "$host"
- if [ "$_hosttype" = "TXT" ] && [ "$_hostname" = "$subdomain" ] && [ "$_hostaddress" = "$txt" ]; then
- _debug "TXT entry found"
- found=1
- else
- _hostaddress="$(printf "%s" "$_hostaddress" | _url_encode)"
- _namecheap_add_host "$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl"
- fi
- fi
- done <<EOT
- echo "$hosts"
- EOT
- if [ $found -eq 0 ]; then
- _debug "TXT entry not found"
- return 0
- fi
- _debug hostrequestfinal "$_hostrequest"
- request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}"
- if ! _namecheap_post "$request"; then
- _err "$error"
- return 1
- fi
- return 0
- }
- _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")
- }
- _namecheap_set_tld_sld() {
- domain=$1
- _tld=""
- _sld=""
- i=2
- while true; do
- _tld=$(printf "%s" "$domain" | cut -d . -f $i-100)
- _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
- }
|