#!/usr/bin/env sh # This script has been created at June 2020, based on knowledge base of wedos.com provider. # It is intended to allow DNS-01 challenges for acme.sh using wedos's WAPI using XML. # Author Michal Tuma # For issues send me an email WEDOS_WAPI_ENDPOINT="https://api.wedos.com/wapi/xml" TESTING_STAGE= ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_wedos_add() { fulldomain=$1 txtvalue=$2 WEDOS_Username="${WEDOS_Username:-$(_readaccountconf_mutable WEDOS_Username)}" WEDOS_Wapipass="${WEDOS_Wapipass:-$(_readaccountconf_mutable WEDOS_Wapipass)}" WEDOS_Authtoken="${WEDOS_Authtoken:-$(_readaccountconf_mutable WEDOS_Authtoken)}" if [ "$WEDOS_Authtoken" ]; then _debug "WEDOS Authtoken was already saved, using saved one" _saveaccountconf_mutable WEDOS_Authtoken "$WEDOS_Authtoken" else if [ -z "$WEDOS_Username" ] || [ -z "$WEDOS_Wapipass" ]; then WEDOS_Username="" WEDOS_Wapipass="" _err "You didn't specify a WEDOS's username and wapi key yet." _err "Please type: export WEDOS_Username=" _err "And: export WEDOS_Wapipass=" _err "After you export those variables, run the script again, the values will be saved for future" return 1 fi #build WEDOS_Authtoken _debug "WEDOS Authtoken were not saved yet, building" WEDOS_Authtoken=`echo -n "$WEDOS_Wapipass" | sha1sum | head -c 40` _debug "WEDOS_Authtoken step 1, WAPI PASS sha1 sum: '$WEDOS_Authtoken'" WEDOS_Authtoken=`echo $WEDOS_Username$WEDOS_Authtoken` _debug "WEDOS_Authtoken step 2, username concat with token without hours: `$WEDOS_Authtoken`" #save details _saveaccountconf_mutable WEDOS_Username "$WEDOS_Username" _saveaccountconf_mutable WEDOS_Wapipass "$WEDOS_Wapipass" _saveaccountconf_mutable WEDOS_Authtoken "$WEDOS_Authtoken" fi if ! _get_root "$fulldomain"; then _err "WEDOS Account do not contain primary domain to fullfill add of $fulldomain!" return 1 fi _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" if _wapi_row_add "$_domain" "$_sub_domain" "$txtvalue" "300"; then _info "WEDOS WAPI: dns record added and dns changes were commited" return 0 else _err "FAILED TO ADD DNS RECORD OR COMMIT DNS CHANGES" return 1 fi } #fulldomain txtvalue dns_wedos_rm() { fulldomain=$1 txtvalue=$2 WEDOS_Username="${WEDOS_Username:-$(_readaccountconf_mutable WEDOS_Username)}" WEDOS_Wapipass="${WEDOS_Wapipass:-$(_readaccountconf_mutable WEDOS_Wapipass)}" WEDOS_Authtoken="${WEDOS_Authtoken:-$(_readaccountconf_mutable WEDOS_Authtoken)}" if [ "$WEDOS_Authtoken" ]; then _debug "WEDOS Authtoken was already saved, using saved one" _saveaccountconf_mutable WEDOS_Authtoken "$WEDOS_Authtoken" else if [ -z "$WEDOS_Username" ] || [ -z "$WEDOS_Wapipass" ]; then WEDOS_Username="" WEDOS_Wapipass="" _err "You didn't specify a WEDOS's username and wapi key yet." _err "Please type: export WEDOS_Username=" _err "And: export WEDOS_Wapipass=" _err "After you export those variables, run the script again, the values will be saved for future" return 1 fi #build WEDOS_Authtoken _debug "WEDOS Authtoken were not saved yet, building" WEDOS_Authtoken=`echo -n "$WEDOS_Wapipass" | sha1sum | head -c 40` _debug "WEDOS_Authtoken step 1, WAPI PASS sha1 sum: '$WEDOS_Authtoken'" WEDOS_Authtoken=`echo $WEDOS_Username$WEDOS_Authtoken` _debug "WEDOS_Authtoken step 2, username concat with token without hours: `$WEDOS_Authtoken`" #save details _saveaccountconf_mutable WEDOS_Username "$WEDOS_Username" _saveaccountconf_mutable WEDOS_Wapipass "$WEDOS_Wapipass" _saveaccountconf_mutable WEDOS_Authtoken "$WEDOS_Authtoken" fi if ! _get_root "$fulldomain"; then _err "WEDOS Account do not contain primary domain to fullfill add of $fulldomain!" return 1 fi _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" if _wapi_find_row "$_domain" "$_sub_domain" "$txtvalue"; then _info "WEDOS WAPI: dns record found with id '$_row_id'" if _wapi_delete_row "$_domain" "$_row_id"; then _info "WEDOS WAPI: dns row were deleted and changes commited!" return 0 fi fi _err "Requested dns row were not found or was imposible to delete it, do it manually" _err "Delete: $fulldomain" _err "Value: $txtvalue" return 1 } #################### Private functions below ################################## # Function _wapi_post(), only takes data, prepares auth token and provide result # $1 - WAPI command string, like 'dns-domains-list' # $2 - WAPI data for given command, is not required # returns WAPI response if request were successfully delivered to WAPI endpoint _wapi_post() { command=$1 data=$2 _debug "Command : $command" _debug "Data : $data" if [ -z "$command" ]; then _err "No command were provided, implamantation error!" return 1 fi # Prepare authentification token hour=`date +%H` token=`echo -n "$WEDOS_Authtoken$hour" | sha1sum | head -c 40` _debug "Authentification token is '$token'" # Build xml request request=`echo "request=\ \ $WEDOS_Username\ $token\ $command"` if [ -z "$data" ]; then echo "" 1>/dev/null else request=`echo "$request$data"` fi if [ -z "$TESTING_STAGE" ]; then echo "" 1>/dev/null else request=`echo "$request\ 1"` fi request=`echo "$request\ "` _debug "Request to WAPI is: $request" response="$(_post "$request" "$WEDOS_WAPI_ENDPOINT")" if [ "$?" != "0" ]; then _err "Error contacting WEDOS WAPI with command $command" return 1 fi _debug "Response : $response" echo $response | grep "1000" 1>/dev/null 2>/dev/null return "$?" } # _get_root() function, for provided full domain, like _acme_challenge.www.example.com verify if WEDOS contains a primary active domain and found what is subdomain # $1 - full domain to verify, ie _acme_challenge.www.example.com # build $_domain found at WEDOS, like example.com and $_sub_domain from provided full domain, like _acme_challenge.www _get_root() { domain=$1 if [ -z "$domain" ]; then _err "Function _get_root was called without argument, implementation error!" return 1; fi _debug "Get root for domain: $domain" _debug "Getting list of domains using WAPI ..." _wapi_post "dns-domains-list" if [ "$?" != "0" ]; then _err "Error on WAPI request for list of domains, response : $response" return 1 else _debug "DNS list were successfully retrieved, response : $response" fi for xml_domain in `echo $response | tr -d '\012\015' | egrep -o -e "( )*.*( )*primary( )*active" | grep -o -e ".*"` do _debug "Active and primary XML DOMAIN found: $xml_domain" end_of_name=`expr ${#xml_domain} - 7` xml_domain_name=`echo $xml_domain | cut -c 7-$end_of_name` _debug "Found primary active domain: $xml_domain_name" regex=".*\\."`echo $xml_domain_name | sed 's/\./\\\\./g'` _debug "Regex for matching domain: '$regex'" echo "$domain" | egrep -e "$regex" 1>/dev/null 2>/dev/null if [ "$?" != "0" ]; then _debug "found domain do not match required" else end_of_name=`expr ${#domain} - ${#xml_domain_name} - 1` _domain=$xml_domain_name _sub_domain=`echo $domain | cut -c -$end_of_name` _info "Domain '$_domain' was found at WEDOS account as primary, and subdomain is '$_sub_domain'!" return 0 fi done return 1 } # for provided domain, it commites all performed changes _wapi_dns_commit() { domain=$1 if [ -z "$domain" ]; then _err "Invalid request to commit dns changes, domain is empty, implementation error!" return 1; fi data=`echo " \ $domain\ "` _wapi_post "dns-domain-commit" "$data" if [ "$?" != "0" ]; then _err "Error on WAPI request to commit DNS changes, response : $response" _err "PLEASE USE WEB ACCESS TO CHECK IF CHANGES ARE REQUIRED TO COMMIT OR ROLLBACKED IMMEDIATELLY!" return 1 else _debug "DNS CHANGES COMMITED, response : $response" _info "WEDOS DNS WAPI: Changes were commited to domain '$domain'" fi return 0 } # add one TXT dns row to a specified fomain _wapi_row_add() { domain=$1 sub_domain=$2 value=$3 ttl=$4 if [ -z "$domain" ] || [ -z "$sub_domain" ] || [ -z "$value" ] || [ -z "$ttl" ]; then _err "Invalid request to add record, domain: '$domain', sub_domain: '$sub_domain', value: '$value' and ttl: '$ttl', on of required input were not provided, implementation error!" return 1; fi # Prepare data for request to WAPI data=`echo " \ $domain\ $sub_domain\ $ttl\ TXT\ $value\ Created using WAPI from acme.sh\ "` _debug "Adding row using WAPI ..." _wapi_post "dns-row-add" "$data" if [ "$?" != "0" ]; then _err "Error on WAPI request to add new TXT row, response : $response" return 1 else _debug "ROW ADDED, response : $response" _info "WEDOS DNS WAPI: Row to domain '$domain' with name '$sub_domain' were successfully added with value '$value' and ttl set to $ttl" fi # Now we have to commit _wapi_dns_commit "$domain" return "$?" } _wapi_find_row() { domain=$1 sub_domain=$2 value=$3 if [ -z "$domain" ] || [ -z "$sub_domain" ] || [ -z "$value" ]; then _err "Invalud request to finad a row, domain: '$domain', sub_domain: '$sub_domain' and value: '$value', one of required input were not provided, implementation error!" return 1 fi data=`echo " \ $domain\ "` _debug "Searching rows using WAPI ..." _wapi_post "dns-rows-list" "$data" if [ "$?" != "0" ]; then _err "Error on WAPI request to list domain rows, response : $response" return 1 fi _debug "Domain rows found, response : $response" sub_domain_regex=`echo $sub_domain | sed "s/\./\\\\./g"` _debug "Subdomain regex '$sub_domain_regex'" for xml_row in `echo $response | tr -d '\012\015' | egrep -o -e "( )*[0-9]*( )*$sub_domain_regex( )*[0-9]*( )*TXT( )*$value" | grep -o -e "[0-9]*"` do _debug "Found row in DNS with ID : $xml_row" _row_id=`echo $xml_row | egrep -o -e "[0-9]*"` _info "WEDOS API: Found DNS row id $_row_id for domain $domain" return 0 done _info "WEDOS API: No TXT row found for domain '$domain' with name '$sub_domain' and value '$value'" return 1 } _wapi_delete_row() { domain=$1 row_id=$2 if [ -z $domain ] || [ -z $row_id ]; then _err "Invalid request to delete domain dns row, domain: '$domain' and row_id: '$row_id', one of required input were not provided, implementation error!" return 1 fi data=`echo " \ $domain $row_id "` _debug "Deleting dns row using WAPI ..." _wapi_post "dns-row-delete" "$data" if [ "$?" != 0 ]; then _err "Error on WAPI request to delete dns row, response: $response" return 1 fi _debug "DNS row were deleted, response: $response" _info "WEDOS API: Required dns domain row with row_id '$row_id' were correctly deleted at domain '$domain'" # Now we have to commit changes _wapi_dns_commit "$domain" return "$?" }