diff --git a/dnsapi/dns_openprovider.sh b/dnsapi/dns_openprovider.sh index b584fad2b6..24c9021e81 100755 --- a/dnsapi/dns_openprovider.sh +++ b/dnsapi/dns_openprovider.sh @@ -1,246 +1,198 @@ #!/usr/bin/env sh # shellcheck disable=SC2034 -dns_openprovider_info='OpenProvider.eu -Site: OpenProvider.eu -Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_openprovider +dns_openprovider_info='OpenProvider +Site: + OpenProvider.eu + OpenProvider.com +Docs: + github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_openprovider Options: - OPENPROVIDER_USER Username - OPENPROVIDER_PASSWORDHASH Password hash -Issues: github.com/acmesh-official/acme.sh/issues/2104 -Author: Sylvia van Os + OPENPROVIDER_USERNAME Openprovider Account Username + OPENPROVIDER_PASSWORD Openprovider Account Password +Issues: + github.com/acmesh-official/acme.sh/issues/2104 +Author: + Sylvia van Os (original SOAP/XML API) + Lambiek12 (converted to REST API) ' -OPENPROVIDER_API="https://api.openprovider.eu/" -#OPENPROVIDER_API="https://api.cte.openprovider.eu/" # Test API +OPENPROVIDER_API_URL="https://api.openprovider.eu/v1beta" ######## Public functions ##################### -#Usage: dns_openprovider_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record dns_openprovider_add() { - fulldomain="$1" - txtvalue="$2" + fulldomain=$1 + txtvalue=$2 - OPENPROVIDER_USER="${OPENPROVIDER_USER:-$(_readaccountconf_mutable OPENPROVIDER_USER)}" - OPENPROVIDER_PASSWORDHASH="${OPENPROVIDER_PASSWORDHASH:-$(_readaccountconf_mutable OPENPROVIDER_PASSWORDHASH)}" + _openprovider_prepare_credentials || return 1 - if [ -z "$OPENPROVIDER_USER" ] || [ -z "$OPENPROVIDER_PASSWORDHASH" ]; then - _err "You didn't specify the openprovider user and/or password hash." + _debug "Try fetch OpenProvider DNS zone details" + if ! _get_dns_zone "$fulldomain"; then + _err "DNS zone not found within configured OpenProvider account." return 1 fi - # save the username and password to the account conf file. - _saveaccountconf_mutable OPENPROVIDER_USER "$OPENPROVIDER_USER" - _saveaccountconf_mutable OPENPROVIDER_PASSWORDHASH "$OPENPROVIDER_PASSWORDHASH" + if [ -n "$_domain_id" ]; then + addzonerecordrequestparameters="dns/zones/$_domain_name" + addzonerecordrequestbody="{\"id\":$_domain_id,\"name\":\"$_domain_name\",\"records\":{\"add\":[{\"name\":\"$_sub_domain\",\"ttl\":900,\"type\":\"TXT\",\"value\":\"$txtvalue\"}]}}" - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" - return 1 + if _openprovider_rest PUT "$addzonerecordrequestparameters" "$addzonerecordrequestbody"; then + if _contains "$response" "\"success\":true"; then + return 0 + elif _contains "$response" "\"Duplicate record\""; then + _debug "Record already existed" + return 0 + else + _err "Adding TXT record failed due to errors." + return 1 + fi + fi fi - _debug _domain_name "$_domain_name" - _debug _domain_extension "$_domain_extension" - - _debug "Getting current records" - existing_items="" - results_retrieved=0 - while true; do - _openprovider_request "$(printf '%s.%s%s' "$_domain_name" "$_domain_extension" "$results_retrieved")" + _err "Adding TXT record failed due to errors." + return 1 +} - items="$response" - while true; do - item="$(echo "$items" | _egrep_o '.*<\/openXML>' | sed -n 's/.*\(.*<\/item>\).*/\1/p')" - _debug existing_items "$existing_items" - _debug results_retrieved "$results_retrieved" - _debug item "$item" +# Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to remove the txt record after validation +dns_openprovider_rm() { + fulldomain=$1 + txtvalue=$2 - if [ -z "$item" ]; then - break - fi + _openprovider_prepare_credentials || return 1 - tmpitem="$(echo "$item" | sed 's/\*/\\*/g')" - items="$(echo "$items" | sed "s|${tmpitem}||")" + _debug "Try fetch OpenProvider DNS zone details" + if ! _get_dns_zone "$fulldomain"; then + _err "DNS zone not found within configured OpenProvider account." + return 1 + fi - results_retrieved="$(_math "$results_retrieved" + 1)" - new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)\.'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" - if [ -z "$new_item" ]; then - # Domain apex - new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" - fi + if [ -n "$_domain_id" ]; then + removezonerecordrequestparameters="dns/zones/$_domain_name" + removezonerecordrequestbody="{\"id\":$_domain_id,\"name\":\"$_domain_name\",\"records\":{\"remove\":[{\"name\":\"$_sub_domain\",\"ttl\":900,\"type\":\"TXT\",\"value\":\"\\\"$txtvalue\\\"\"}]}}" - if [ -z "$(echo "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA)<\/type>.*")" ]; then - _debug "not an allowed record type, skipping" "$new_item" - continue + if _openprovider_rest PUT "$removezonerecordrequestparameters" "$removezonerecordrequestbody"; then + if _contains "$response" "\"success\":true"; then + return 0 + else + _err "Removing TXT record failed due to errors." + return 1 fi - - existing_items="$existing_items$new_item" - done - - total="$(echo "$response" | _egrep_o '.*?<\/total>' | sed -n 's/.*\(.*\)<\/total>.*/\1/p')" - - _debug total "$total" - if [ "$results_retrieved" -eq "$total" ]; then - break fi - done - - _debug "Creating acme record" - acme_record="$(echo "$fulldomain" | sed -e "s/.$_domain_name.$_domain_extension$//")" - _openprovider_request "$(printf '%s%smaster%s%sTXT%s600' "$_domain_name" "$_domain_extension" "$existing_items" "$acme_record" "$txtvalue")" + fi - return 0 + _err "Removing TXT record failed due to errors." + return 1 } -#Usage: fulldomain txtvalue -#Remove the txt record after validation. -dns_openprovider_rm() { - fulldomain="$1" - txtvalue="$2" - - OPENPROVIDER_USER="${OPENPROVIDER_USER:-$(_readaccountconf_mutable OPENPROVIDER_USER)}" - OPENPROVIDER_PASSWORDHASH="${OPENPROVIDER_PASSWORDHASH:-$(_readaccountconf_mutable OPENPROVIDER_PASSWORDHASH)}" +#################### OpenProvider API common functions #################### +_openprovider_prepare_credentials() { + OPENPROVIDER_USERNAME="${OPENPROVIDER_USERNAME:-$(_readaccountconf_mutable OPENPROVIDER_USERNAME)}" + OPENPROVIDER_PASSWORD="${OPENPROVIDER_PASSWORD:-$(_readaccountconf_mutable OPENPROVIDER_PASSWORD)}" - if [ -z "$OPENPROVIDER_USER" ] || [ -z "$OPENPROVIDER_PASSWORDHASH" ]; then - _err "You didn't specify the openprovider user and/or password hash." + if [ -z "$OPENPROVIDER_USERNAME" ] || [ -z "$OPENPROVIDER_PASSWORD" ]; then + OPENPROVIDER_USERNAME="" + OPENPROVIDER_PASSWORD="" + _err "You didn't specify the Openprovider username or password yet." return 1 fi - # save the username and password to the account conf file. - _saveaccountconf_mutable OPENPROVIDER_USER "$OPENPROVIDER_USER" - _saveaccountconf_mutable OPENPROVIDER_PASSWORDHASH "$OPENPROVIDER_PASSWORDHASH" + #save the credentials to the account conf file. + _saveaccountconf_mutable OPENPROVIDER_USERNAME "$OPENPROVIDER_USERNAME" + _saveaccountconf_mutable OPENPROVIDER_PASSWORD "$OPENPROVIDER_PASSWORD" +} + +_openprovider_rest() { + httpmethod=$1 + queryparameters=$2 + requestbody=$3 - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" + _openprovider_rest_login + if [ -z "$openproviderauthtoken" ]; then + _err "Unable to fetch authentication token from Openprovider API." return 1 fi - _debug _domain_name "$_domain_name" - _debug _domain_extension "$_domain_extension" - - _debug "Getting current records" - existing_items="" - results_retrieved=0 - while true; do - _openprovider_request "$(printf '%s.%s%s' "$_domain_name" "$_domain_extension" "$results_retrieved")" - - # Remove acme records from items - items="$response" - while true; do - item="$(echo "$items" | _egrep_o '.*<\/openXML>' | sed -n 's/.*\(.*<\/item>\).*/\1/p')" - _debug existing_items "$existing_items" - _debug results_retrieved "$results_retrieved" - _debug item "$item" - - if [ -z "$item" ]; then - break - fi - - tmpitem="$(echo "$item" | sed 's/\*/\\*/g')" - items="$(echo "$items" | sed "s|${tmpitem}||")" + export _H1="Content-Type: application/json" + export _H2="Accept: application/json" + export _H3="Authorization: Bearer $openproviderauthtoken" - results_retrieved="$(_math "$results_retrieved" + 1)" - if ! echo "$item" | grep -v "$fulldomain"; then - _debug "acme record, skipping" "$item" - continue - fi + _debug httpmethod "$httpmethod" + _debug requestfullurl "$OPENPROVIDER_API_URL/$queryparameters" + _debug queryparameters "$queryparameters" - new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)\.'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" + if [ "$httpmethod" != "GET" ]; then + _debug requestbody "$requestbody" - if [ -z "$new_item" ]; then - # domain apex - new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" - fi + response="$(_post "$requestbody" "$OPENPROVIDER_API_URL/$queryparameters" "" "$httpmethod")" + else + response="$(_get "$OPENPROVIDER_API_URL/$queryparameters")" + fi - if [ -z "$(echo "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA)<\/type>.*")" ]; then - _debug "not an allowed record type, skipping" "$new_item" - continue - fi + if [ "$?" != "0" ]; then + _err "No valid parameters supplied for Openprovider API: Error $queryparameters" + return 1 + fi - existing_items="$existing_items$new_item" - done + _debug2 response "$response" - total="$(echo "$response" | _egrep_o '.*?<\/total>' | sed -n 's/.*\(.*\)<\/total>.*/\1/p')" + return 0 +} - _debug total "$total" +_openprovider_rest_login() { + export _H1="Content-Type: application/json" + export _H2="Accept: application/json" - if [ "$results_retrieved" -eq "$total" ]; then - break - fi - done + loginrequesturl="$OPENPROVIDER_API_URL/auth/login" + loginrequestbody="{\"ip\":\"0.0.0.0\",\"password\":\"$OPENPROVIDER_PASSWORD\",\"username\":\"$OPENPROVIDER_USERNAME\"}" + loginresponse="$(_post "$loginrequestbody" "$loginrequesturl" "" "POST")" - _debug "Removing acme record" - _openprovider_request "$(printf '%s%smaster%s' "$_domain_name" "$_domain_extension" "$existing_items")" + openproviderauthtoken="$(printf "%s\n" "$loginresponse" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')" + _debug openproviderauthtoken "$openproviderauthtoken" - return 0 + export openproviderauthtoken } -#################### Private functions below ################################## -#_acme-challenge.www.domain.com -#returns -# _domain_name=domain -# _domain_extension=com -_get_root() { +#################### Private functions ################################## + +# Usage: _get_dns_zone _acme-challenge.www.domain.com +# Returns: +# _domain_id=123456789 +# _domain_name=domain.com +# _sub_domain=_acme-challenge.www +_get_dns_zone() { domain=$1 - i=2 + i=1 + p=1 - results_retrieved=0 while true; do - h=$(echo "$domain" | cut -d . -f "$i"-100) - _debug h "$h" + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then - #not valid + # Empty value not allowed return 1 fi - _openprovider_request "$(printf '%s%s' "$(echo "$h" | cut -d . -f 1)" "$results_retrieved")" - - items="$response" - while true; do - item="$(echo "$items" | _egrep_o '.*<\/openXML>' | sed -n 's/.*\(.*<\/domain>\).*/\1/p')" - _debug existing_items "$existing_items" - _debug results_retrieved "$results_retrieved" - _debug item "$item" - - if [ -z "$item" ]; then - break - fi - - tmpitem="$(echo "$item" | sed 's/\*/\\*/g')" - items="$(echo "$items" | sed "s|${tmpitem}||")" + if ! _openprovider_rest GET "dns/zones/$h" ""; then + return 1 + fi - results_retrieved="$(_math "$results_retrieved" + 1)" + if _contains "$response" "\"name\":\"$h\""; then + _domain_id="$(printf "%s\n" "$response" | _egrep_o '"id" *: *[^,]*' | _head_n 1 | sed 's#^"id" *: *##')" + _debug _domain_id "$_domain_id" - _domain_name="$(echo "$item" | sed -n 's/.*.*\(.*\)<\/name>.*<\/domain>.*/\1/p')" - _domain_extension="$(echo "$item" | sed -n 's/.*.*\(.*\)<\/extension>.*<\/domain>.*/\1/p')" + _domain_name="$h" _debug _domain_name "$_domain_name" - _debug _domain_extension "$_domain_extension" - if [ "$_domain_name.$_domain_extension" = "$h" ]; then - return 0 - fi - done - - total="$(echo "$response" | _egrep_o '.*?<\/total>' | sed -n 's/.*\(.*\)<\/total>.*/\1/p')" - - _debug total "$total" - if [ "$results_retrieved" -eq "$total" ]; then - results_retrieved=0 - i="$(_math "$i" + 1)" + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") + _debug _sub_domain "$_sub_domain" + return 0 fi - done - return 1 -} -_openprovider_request() { - request_xml=$1 + p=$i + i=$(_math "$i" + 1) + done - xml_prefix='' - xml_content=$(printf '%s%s%s' "$OPENPROVIDER_USER" "$OPENPROVIDER_PASSWORDHASH" "$request_xml") - response="$(_post "$(echo "$xml_prefix$xml_content" | tr -d '\n')" "$OPENPROVIDER_API" "" "POST" "application/xml")" - _debug response "$response" - if ! _contains "$response" "0.*"; then - _err "API request failed." - return 1 - fi + return 1 }