diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh
index cdda4775..87119521 100644
--- a/dnsapi/dns_gandi_livedns.sh
+++ b/dnsapi/dns_gandi_livedns.sh
@@ -69,9 +69,9 @@ dns_gandi_livedns_rm() {
_gandi_livedns_rest PUT \
"domains/$_domain/records/$_sub_domain/TXT" \
- "{\"rrset_ttl\": 300, \"rrset_values\": $_new_rrset_values}" \
- && _contains "$response" '{"message": "DNS Record Created"}' \
- && _info "Removing record $(__green "success")"
+ "{\"rrset_ttl\": 300, \"rrset_values\": $_new_rrset_values}" &&
+ _contains "$response" '{"message": "DNS Record Created"}' &&
+ _info "Removing record $(__green "success")"
}
#################### Private functions below ##################################
@@ -125,9 +125,9 @@ _dns_gandi_append_record() {
fi
_debug new_rrset_values "$_rrset_values"
_gandi_livedns_rest PUT "domains/$_domain/records/$sub_domain/TXT" \
- "{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" \
- && _contains "$response" '{"message": "DNS Record Created"}' \
- && _info "Adding record $(__green "success")"
+ "{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" &&
+ _contains "$response" '{"message": "DNS Record Created"}' &&
+ _info "Adding record $(__green "success")"
}
_dns_gandi_existing_rrset_values() {
@@ -145,8 +145,8 @@ _dns_gandi_existing_rrset_values() {
return 1
fi
_debug "Already has TXT record."
- _rrset_values=$(echo "$response" | _egrep_o 'rrset_values.*\[.*\]' \
- | _egrep_o '\[".*\"]')
+ _rrset_values=$(echo "$response" | _egrep_o 'rrset_values.*\[.*\]' |
+ _egrep_o '\[".*\"]')
return 0
}
diff --git a/dnsapi/dns_gcloud.sh b/dnsapi/dns_gcloud.sh
index 6365b338..03060a8c 100755
--- a/dnsapi/dns_gcloud.sh
+++ b/dnsapi/dns_gcloud.sh
@@ -78,8 +78,8 @@ _dns_gcloud_execute_tr() {
for i in $(seq 1 120); do
if gcloud dns record-sets changes list \
--zone="$managedZone" \
- --filter='status != done' \
- | grep -q '^.*'; then
+ --filter='status != done' |
+ grep -q '^.*'; then
_info "_dns_gcloud_execute_tr: waiting for transaction to be comitted ($i/120)..."
sleep 5
else
@@ -137,11 +137,11 @@ _dns_gcloud_find_zone() {
# List domains and find the zone with the deepest sub-domain (in case of some levels of delegation)
if ! match=$(gcloud dns managed-zones list \
--format="value(name, dnsName)" \
- --filter="$filter" \
- | while read -r dnsName name; do
+ --filter="$filter" |
+ while read -r dnsName name; do
printf "%s\t%s\t%s\n" "$(echo "$name" | awk -F"." '{print NF-1}')" "$dnsName" "$name"
- done \
- | sort -n -r | _head_n 1 | cut -f2,3 | grep '^.*'); then
+ done |
+ sort -n -r | _head_n 1 | cut -f2,3 | grep '^.*'); then
_err "_dns_gcloud_find_zone: Can't find a matching managed zone! Perhaps wrong project or gcloud credentials?"
return 1
fi
diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh
index 5829e00e..ef09fa0a 100755
--- a/dnsapi/dns_he.sh
+++ b/dnsapi/dns_he.sh
@@ -101,8 +101,8 @@ dns_he_rm() {
body="$body&hosted_dns_editzone=1"
body="$body&hosted_dns_delrecord=1"
body="$body&hosted_dns_delconfirm=delete"
- _post "$body" "https://dns.he.net/" \
- | grep 'Successfully removed record.
' \
+ _post "$body" "https://dns.he.net/" |
+ grep 'Successfully removed record.
' \
>/dev/null
exit_code="$?"
if [ "$exit_code" -eq 0 ]; then
diff --git a/dnsapi/dns_hetzner.sh b/dnsapi/dns_hetzner.sh
index 5db0418c..911d4a35 100644
--- a/dnsapi/dns_hetzner.sh
+++ b/dnsapi/dns_hetzner.sh
@@ -123,10 +123,10 @@ _find_record() {
return 1
else
_record_id=$(
- echo "$response" \
- | grep -o "{[^\{\}]*\"name\":\"$_record_name\"[^\}]*}" \
- | grep "\"value\":\"$_record_value\"" \
- | while read -r record; do
+ echo "$response" |
+ grep -o "{[^\{\}]*\"name\":\"$_record_name\"[^\}]*}" |
+ grep "\"value\":\"$_record_value\"" |
+ while read -r record; do
# test for type and
if [ -n "$(echo "$record" | _egrep_o '"type":"TXT"')" ]; then
echo "$record" | _egrep_o '"id":"[^"]*"' | cut -d : -f 2 | tr -d \"
diff --git a/dnsapi/dns_infomaniak.sh b/dnsapi/dns_infomaniak.sh
new file mode 100755
index 00000000..765cf39d
--- /dev/null
+++ b/dnsapi/dns_infomaniak.sh
@@ -0,0 +1,199 @@
+#!/usr/bin/env sh
+
+###############################################################################
+# Infomaniak API integration
+#
+# To use this API you need visit the API dashboard of your account
+# once logged into https://manager.infomaniak.com add /api/dashboard to the URL
+#
+# Please report bugs to
+# https://github.com/acmesh-official/acme.sh/issues/3188
+#
+# Note: the URL looks like this:
+# https://manager.infomaniak.com/v3//api/dashboard
+# Then generate a token with the scope Domain
+# this is given as an environment variable INFOMANIAK_API_TOKEN
+###############################################################################
+
+# base variables
+
+DEFAULT_INFOMANIAK_API_URL="https://api.infomaniak.com"
+DEFAULT_INFOMANIAK_TTL=300
+
+######## Public functions #####################
+
+#Usage: dns_infomaniak_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+dns_infomaniak_add() {
+
+ INFOMANIAK_API_TOKEN="${INFOMANIAK_API_TOKEN:-$(_readaccountconf_mutable INFOMANIAK_API_TOKEN)}"
+ INFOMANIAK_API_URL="${INFOMANIAK_API_URL:-$(_readaccountconf_mutable INFOMANIAK_API_URL)}"
+ INFOMANIAK_TTL="${INFOMANIAK_TTL:-$(_readaccountconf_mutable INFOMANIAK_TTL)}"
+
+ if [ -z "$INFOMANIAK_API_TOKEN" ]; then
+ INFOMANIAK_API_TOKEN=""
+ _err "Please provide a valid Infomaniak API token in variable INFOMANIAK_API_TOKEN"
+ return 1
+ fi
+
+ if [ -z "$INFOMANIAK_API_URL" ]; then
+ INFOMANIAK_API_URL="$DEFAULT_INFOMANIAK_API_URL"
+ fi
+
+ if [ -z "$INFOMANIAK_TTL" ]; then
+ INFOMANIAK_TTL="$DEFAULT_INFOMANIAK_TTL"
+ fi
+
+ #save the token to the account conf file.
+ _saveaccountconf_mutable INFOMANIAK_API_TOKEN "$INFOMANIAK_API_TOKEN"
+
+ if [ "$INFOMANIAK_API_URL" != "$DEFAULT_INFOMANIAK_API_URL" ]; then
+ _saveaccountconf_mutable INFOMANIAK_API_URL "$INFOMANIAK_API_URL"
+ fi
+
+ if [ "$INFOMANIAK_TTL" != "$DEFAULT_INFOMANIAK_TTL" ]; then
+ _saveaccountconf_mutable INFOMANIAK_TTL "$INFOMANIAK_TTL"
+ fi
+
+ export _H1="Authorization: Bearer $INFOMANIAK_API_TOKEN"
+ export _H2="Content-Type: application/json"
+
+ fulldomain="$1"
+ txtvalue="$2"
+
+ _info "Infomaniak DNS API"
+ _debug fulldomain "$fulldomain"
+ _debug txtvalue "$txtvalue"
+
+ fqdn=${fulldomain#_acme-challenge.}
+
+ # guess which base domain to add record to
+ zone_and_id=$(_find_zone "$fqdn")
+ if [ -z "$zone_and_id" ]; then
+ _err "cannot find zone to modify"
+ return 1
+ fi
+ zone=${zone_and_id% *}
+ domain_id=${zone_and_id#* }
+
+ # extract first part of domain
+ key=${fulldomain%.$zone}
+
+ _debug "zone:$zone id:$domain_id key:$key"
+
+ # payload
+ data="{\"type\": \"TXT\", \"source\": \"$key\", \"target\": \"$txtvalue\", \"ttl\": $INFOMANIAK_TTL}"
+
+ # API call
+ response=$(_post "$data" "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record")
+ if [ -n "$response" ] && echo "$response" | _contains '"result":"success"'; then
+ _info "Record added"
+ _debug "Response: $response"
+ return 0
+ fi
+ _err "could not create record"
+ _debug "Response: $response"
+ return 1
+}
+
+#Usage: fulldomain txtvalue
+#Remove the txt record after validation.
+dns_infomaniak_rm() {
+
+ INFOMANIAK_API_TOKEN="${INFOMANIAK_API_TOKEN:-$(_readaccountconf_mutable INFOMANIAK_API_TOKEN)}"
+ INFOMANIAK_API_URL="${INFOMANIAK_API_URL:-$(_readaccountconf_mutable INFOMANIAK_API_URL)}"
+ INFOMANIAK_TTL="${INFOMANIAK_TTL:-$(_readaccountconf_mutable INFOMANIAK_TTL)}"
+
+ if [ -z "$INFOMANIAK_API_TOKEN" ]; then
+ INFOMANIAK_API_TOKEN=""
+ _err "Please provide a valid Infomaniak API token in variable INFOMANIAK_API_TOKEN"
+ return 1
+ fi
+
+ if [ -z "$INFOMANIAK_API_URL" ]; then
+ INFOMANIAK_API_URL="$DEFAULT_INFOMANIAK_API_URL"
+ fi
+
+ if [ -z "$INFOMANIAK_TTL" ]; then
+ INFOMANIAK_TTL="$DEFAULT_INFOMANIAK_TTL"
+ fi
+
+ #save the token to the account conf file.
+ _saveaccountconf_mutable INFOMANIAK_API_TOKEN "$INFOMANIAK_API_TOKEN"
+
+ if [ "$INFOMANIAK_API_URL" != "$DEFAULT_INFOMANIAK_API_URL" ]; then
+ _saveaccountconf_mutable INFOMANIAK_API_URL "$INFOMANIAK_API_URL"
+ fi
+
+ if [ "$INFOMANIAK_TTL" != "$DEFAULT_INFOMANIAK_TTL" ]; then
+ _saveaccountconf_mutable INFOMANIAK_TTL "$INFOMANIAK_TTL"
+ fi
+
+ export _H1="Authorization: Bearer $INFOMANIAK_API_TOKEN"
+ export _H2="ContentType: application/json"
+
+ fulldomain=$1
+ txtvalue=$2
+ _info "Infomaniak DNS API"
+ _debug fulldomain "$fulldomain"
+ _debug txtvalue "$txtvalue"
+
+ fqdn=${fulldomain#_acme-challenge.}
+
+ # guess which base domain to add record to
+ zone_and_id=$(_find_zone "$fqdn")
+ if [ -z "$zone_and_id" ]; then
+ _err "cannot find zone to modify"
+ return 1
+ fi
+ zone=${zone_and_id% *}
+ domain_id=${zone_and_id#* }
+
+ # extract first part of domain
+ key=${fulldomain%.$zone}
+
+ _debug "zone:$zone id:$domain_id key:$key"
+
+ # find previous record
+ # shellcheck disable=SC1004
+ record_id=$(_get "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record" | sed 's/.*"data":\[\(.*\)\]}/\1/; s/},{/}\
+{/g' | sed -n 's/.*"id":"*\([0-9]*\)"*.*"source_idn":"'"$fulldomain"'".*"target_idn":"'"$txtvalue"'".*/\1/p')
+ if [ -z "$record_id" ]; then
+ _err "could not find record to delete"
+ return 1
+ fi
+ _debug "record_id: $record_id"
+
+ # API call
+ response=$(_post "" "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record/$record_id" "" DELETE)
+ if [ -n "$response" ] && echo "$response" | _contains '"result":"success"'; then
+ _info "Record deleted"
+ return 0
+ fi
+ _err "could not delete record"
+ return 1
+}
+
+#################### Private functions below ##################################
+
+_get_domain_id() {
+ domain="$1"
+
+ # shellcheck disable=SC1004
+ _get "${INFOMANIAK_API_URL}/1/product?service_name=domain&customer_name=$domain" | sed 's/.*"data":\[{\(.*\)}\]}/\1/; s/,/\
+/g' | sed -n 's/^"id":\(.*\)/\1/p'
+}
+
+_find_zone() {
+ zone="$1"
+
+ # find domain in list, removing . parts sequentialy
+ while _contains "$zone" '\.'; do
+ _debug "testing $zone"
+ id=$(_get_domain_id "$zone")
+ if [ -n "$id" ]; then
+ echo "$zone $id"
+ return
+ fi
+ zone=${zone#*.}
+ done
+}
diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh
index 2d8d6b0a..bd1e0391 100755
--- a/dnsapi/dns_ispconfig.sh
+++ b/dnsapi/dns_ispconfig.sh
@@ -95,29 +95,29 @@ _ISPC_getZoneInfo() {
server_id=$(echo "${curResult}" | _egrep_o "server_id.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
_debug "Server ID: '${server_id}'"
case "${server_id}" in
- '' | *[!0-9]*)
- _err "Server ID is not numeric."
- return 1
- ;;
- *) _info "Retrieved Server ID" ;;
+ '' | *[!0-9]*)
+ _err "Server ID is not numeric."
+ return 1
+ ;;
+ *) _info "Retrieved Server ID" ;;
esac
zone=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
_debug "Zone: '${zone}'"
case "${zone}" in
- '' | *[!0-9]*)
- _err "Zone ID is not numeric."
- return 1
- ;;
- *) _info "Retrieved Zone ID" ;;
+ '' | *[!0-9]*)
+ _err "Zone ID is not numeric."
+ return 1
+ ;;
+ *) _info "Retrieved Zone ID" ;;
esac
client_id=$(echo "${curResult}" | _egrep_o "sys_userid.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
_debug "Client ID: '${client_id}'"
case "${client_id}" in
- '' | *[!0-9]*)
- _err "Client ID is not numeric."
- return 1
- ;;
- *) _info "Retrieved Client ID." ;;
+ '' | *[!0-9]*)
+ _err "Client ID is not numeric."
+ return 1
+ ;;
+ *) _info "Retrieved Client ID." ;;
esac
zoneFound=""
zoneEnd=""
@@ -135,11 +135,11 @@ _ISPC_addTxt() {
record_id=$(echo "${curResult}" | _egrep_o "\"response.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
_debug "Record ID: '${record_id}'"
case "${record_id}" in
- '' | *[!0-9]*)
- _err "Couldn't add ACME Challenge TXT record to zone."
- return 1
- ;;
- *) _info "Added ACME Challenge TXT record to zone." ;;
+ '' | *[!0-9]*)
+ _err "Couldn't add ACME Challenge TXT record to zone."
+ return 1
+ ;;
+ *) _info "Added ACME Challenge TXT record to zone." ;;
esac
}
@@ -153,24 +153,24 @@ _ISPC_rmTxt() {
record_id=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
_debug "Record ID: '${record_id}'"
case "${record_id}" in
- '' | *[!0-9]*)
- _err "Record ID is not numeric."
+ '' | *[!0-9]*)
+ _err "Record ID is not numeric."
+ return 1
+ ;;
+ *)
+ unset IFS
+ _info "Retrieved Record ID."
+ curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\",\"update_serial\":true}"
+ curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")"
+ _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_delete'"
+ _debug "Result of _ISPC_rmTxt: '$curResult'"
+ if _contains "${curResult}" '"code":"ok"'; then
+ _info "Removed ACME Challenge TXT record from zone."
+ else
+ _err "Couldn't remove ACME Challenge TXT record from zone."
return 1
- ;;
- *)
- unset IFS
- _info "Retrieved Record ID."
- curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\",\"update_serial\":true}"
- curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")"
- _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_delete'"
- _debug "Result of _ISPC_rmTxt: '$curResult'"
- if _contains "${curResult}" '"code":"ok"'; then
- _info "Removed ACME Challenge TXT record from zone."
- else
- _err "Couldn't remove ACME Challenge TXT record from zone."
- return 1
- fi
- ;;
+ fi
+ ;;
esac
fi
}
diff --git a/dnsapi/dns_joker.sh b/dnsapi/dns_joker.sh
index 5d50953e..78399a1d 100644
--- a/dnsapi/dns_joker.sh
+++ b/dnsapi/dns_joker.sh
@@ -100,7 +100,7 @@ _get_root() {
fi
# Try to remove a test record. With correct root domain, username and password this will return "OK: ..." regardless
- # of record in question existing or not.
+ # of record in question existing or not.
if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$h&label=jokerTXTUpdateTest&type=TXT&value="; then
if _startswith "$response" "OK"; then
_sub_domain="$(echo "$fulldomain" | sed "s/\\.$h\$//")"
diff --git a/dnsapi/dns_kappernet.sh b/dnsapi/dns_kappernet.sh
new file mode 100644
index 00000000..83a7e5f8
--- /dev/null
+++ b/dnsapi/dns_kappernet.sh
@@ -0,0 +1,150 @@
+#!/usr/bin/env sh
+
+# kapper.net domain api
+# for further questions please contact: support@kapper.net
+# please report issues here: https://github.com/acmesh-official/acme.sh/issues/2977
+
+#KAPPERNETDNS_Key="yourKAPPERNETapikey"
+#KAPPERNETDNS_Secret="yourKAPPERNETapisecret"
+
+KAPPERNETDNS_Api="https://dnspanel.kapper.net/API/1.2?APIKey=$KAPPERNETDNS_Key&APISecret=$KAPPERNETDNS_Secret"
+
+###############################################################################
+# called with
+# fullhostname: something.example.com
+# txtvalue: someacmegenerated string
+dns_kappernet_add() {
+ fullhostname=$1
+ txtvalue=$2
+
+ KAPPERNETDNS_Key="${KAPPERNETDNS_Key:-$(_readaccountconf_mutable KAPPERNETDNS_Key)}"
+ KAPPERNETDNS_Secret="${KAPPERNETDNS_Secret:-$(_readaccountconf_mutable KAPPERNETDNS_Secret)}"
+
+ if [ -z "$KAPPERNETDNS_Key" ] || [ -z "$KAPPERNETDNS_Secret" ]; then
+ KAPPERNETDNS_Key=""
+ KAPPERNETDNS_Secret=""
+ _err "Please specify your kapper.net api key and secret."
+ _err "If you have not received yours - send your mail to"
+ _err "support@kapper.net to get your key and secret."
+ return 1
+ fi
+
+ #store the api key and email to the account conf file.
+ _saveaccountconf_mutable KAPPERNETDNS_Key "$KAPPERNETDNS_Key"
+ _saveaccountconf_mutable KAPPERNETDNS_Secret "$KAPPERNETDNS_Secret"
+ _debug "Checking Domain ..."
+ if ! _get_root "$fullhostname"; then
+ _err "invalid domain"
+ return 1
+ fi
+ _debug _sub_domain "SUBDOMAIN: $_sub_domain"
+ _debug _domain "DOMAIN: $_domain"
+
+ _info "Trying to add TXT DNS Record"
+ data="%7B%22name%22%3A%22$fullhostname%22%2C%22type%22%3A%22TXT%22%2C%22content%22%3A%22$txtvalue%22%2C%22ttl%22%3A%223600%22%2C%22prio%22%3A%22%22%7D"
+ if _kappernet_api GET "action=new&subject=$_domain&data=$data"; then
+
+ if _contains "$response" "{\"OK\":true"; then
+ _info "Waiting 120 seconds for DNS to spread the new record"
+ _sleep 120
+ return 0
+ else
+ _err "Error creating a TXT DNS Record: $fullhostname TXT $txtvalue"
+ _err "Error Message: $response"
+ return 1
+ fi
+ fi
+ _err "Failed creating TXT Record"
+}
+
+###############################################################################
+# called with
+# fullhostname: something.example.com
+dns_kappernet_rm() {
+ fullhostname=$1
+ txtvalue=$2
+
+ KAPPERNETDNS_Key="${KAPPERNETDNS_Key:-$(_readaccountconf_mutable KAPPERNETDNS_Key)}"
+ KAPPERNETDNS_Secret="${KAPPERNETDNS_Secret:-$(_readaccountconf_mutable KAPPERNETDNS_Secret)}"
+
+ if [ -z "$KAPPERNETDNS_Key" ] || [ -z "$KAPPERNETDNS_Secret" ]; then
+ KAPPERNETDNS_Key=""
+ KAPPERNETDNS_Secret=""
+ _err "Please specify your kapper.net api key and secret."
+ _err "If you have not received yours - send your mail to"
+ _err "support@kapper.net to get your key and secret."
+ return 1
+ fi
+
+ #store the api key and email to the account conf file.
+ _saveaccountconf_mutable KAPPERNETDNS_Key "$KAPPERNETDNS_Key"
+ _saveaccountconf_mutable KAPPERNETDNS_Secret "$KAPPERNETDNS_Secret"
+
+ _info "Trying to remove the TXT Record: $fullhostname containing $txtvalue"
+ data="%7B%22name%22%3A%22$fullhostname%22%2C%22type%22%3A%22TXT%22%2C%22content%22%3A%22$txtvalue%22%2C%22ttl%22%3A%223600%22%2C%22prio%22%3A%22%22%7D"
+ if _kappernet_api GET "action=del&subject=$fullhostname&data=$data"; then
+ if _contains "$response" "{\"OK\":true"; then
+ return 0
+ else
+ _err "Error deleting DNS Record: $fullhostname containing $txtvalue"
+ _err "Problem: $response"
+ return 1
+ fi
+ fi
+ _err "Problem deleting TXT DNS record"
+}
+
+#################### Private functions below ##################################
+# called with hostname
+# e.g._acme-challenge.www.domain.com returns
+# _sub_domain=_acme-challenge.www
+# _domain=domain.com
+_get_root() {
+ domain=$1
+ i=2
+ p=1
+ while true; do
+ h=$(printf "%s" "$domain" | cut -d . -f $i-100)
+ if [ -z "$h" ]; then
+ #not valid
+ return 1
+ fi
+ if ! _kappernet_api GET "action=list&subject=$h"; then
+ return 1
+ fi
+ if _contains "$response" '"OK":false'; 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
+}
+
+################################################################################
+# calls the kapper.net DNS Panel API
+# with
+# method
+# param
+_kappernet_api() {
+ method=$1
+ param="$2"
+
+ _debug param "PARAMETER=$param"
+ url="$KAPPERNETDNS_Api&$param"
+ _debug url "URL=$url"
+
+ if [ "$method" = "GET" ]; then
+ response="$(_get "$url")"
+ else
+ _err "Unsupported method"
+ return 1
+ fi
+
+ _debug2 response "$response"
+ return 0
+}
diff --git a/dnsapi/dns_misaka.sh b/dnsapi/dns_misaka.sh
index eed4170e..36ba5cfd 100755
--- a/dnsapi/dns_misaka.sh
+++ b/dnsapi/dns_misaka.sh
@@ -47,7 +47,7 @@ dns_misaka_add() {
if [ "$count" = "0" ]; then
_info "Adding record"
- if _misaka_rest PUT "zones/${_domain}/recordsets/${_sub_domain}/TXT" "{\"records\":[{\"value\":\"\\\"$txtvalue\\\"\"}],\"filters\":[],\"ttl\":1}"; then
+ if _misaka_rest POST "zones/${_domain}/recordsets/${_sub_domain}/TXT" "{\"records\":[{\"value\":\"\\\"$txtvalue\\\"\"}],\"filters\":[],\"ttl\":1}"; then
_debug response "$response"
if _contains "$response" "$_sub_domain"; then
_info "Added"
@@ -61,7 +61,7 @@ dns_misaka_add() {
else
_info "Updating record"
- _misaka_rest POST "zones/${_domain}/recordsets/${_sub_domain}/TXT?append=true" "{\"records\": [{\"value\": \"\\\"$txtvalue\\\"\"}],\"ttl\":1}"
+ _misaka_rest PUT "zones/${_domain}/recordsets/${_sub_domain}/TXT?append=true" "{\"records\": [{\"value\": \"\\\"$txtvalue\\\"\"}],\"ttl\":1}"
if [ "$?" = "0" ] && _contains "$response" "$_sub_domain"; then
_info "Updated!"
#todo: check if the record takes effect
diff --git a/dnsapi/dns_netlify.sh b/dnsapi/dns_netlify.sh
new file mode 100644
index 00000000..2ce13e2b
--- /dev/null
+++ b/dnsapi/dns_netlify.sh
@@ -0,0 +1,162 @@
+#!/usr/bin/env sh
+
+#NETLIFY_ACCESS_TOKEN="xxxx"
+
+NETLIFY_HOST="api.netlify.com/api/v1/"
+NETLIFY_URL="https://$NETLIFY_HOST"
+
+######## Public functions #####################
+
+#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+dns_netlify_add() {
+ fulldomain=$1
+ txtvalue=$2
+
+ NETLIFY_ACCESS_TOKEN="${NETLIFY_ACCESS_TOKEN:-$(_readaccountconf_mutable NETLIFY_ACCESS_TOKEN)}"
+
+ if [ -z "$NETLIFY_ACCESS_TOKEN" ]; then
+ NETLIFY_ACCESS_TOKEN=""
+ _err "Please specify your Netlify Access Token and try again."
+ return 1
+ fi
+
+ _info "Using Netlify"
+ _debug fulldomain "$fulldomain"
+ _debug txtvalue "$txtvalue"
+
+ _saveaccountconf_mutable NETLIFY_ACCESS_TOKEN "$NETLIFY_ACCESS_TOKEN"
+
+ if ! _get_root "$fulldomain" "$accesstoken"; then
+ _err "invalid domain"
+ return 1
+ fi
+
+ _debug _domain_id "$_domain_id"
+ _debug _sub_domain "$_sub_domain"
+ _debug _domain "$_domain"
+
+ dnsRecordURI="dns_zones/$_domain_id/dns_records"
+
+ body="{\"type\":\"TXT\", \"hostname\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"ttl\":\"10\"}"
+
+ _netlify_rest POST "$dnsRecordURI" "$body" "$NETLIFY_ACCESS_TOKEN"
+ _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
+ if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then
+ _info "validation value added"
+ return 0
+ else
+ _err "error adding validation value ($_code)"
+ return 1
+ fi
+
+ _err "Not fully implemented!"
+ return 1
+}
+
+#Usage: dns_myapi_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+#Remove the txt record after validation.
+dns_netlify_rm() {
+ _info "Using Netlify"
+ txtdomain="$1"
+ txt="$2"
+ _debug txtdomain "$txtdomain"
+ _debug txt "$txt"
+
+ _saveaccountconf_mutable NETLIFY_ACCESS_TOKEN "$NETLIFY_ACCESS_TOKEN"
+
+ if ! _get_root "$txtdomain" "$accesstoken"; then
+ _err "invalid domain"
+ return 1
+ fi
+
+ _debug _domain_id "$_domain_id"
+ _debug _sub_domain "$_sub_domain"
+ _debug _domain "$_domain"
+
+ dnsRecordURI="dns_zones/$_domain_id/dns_records"
+
+ _netlify_rest GET "$dnsRecordURI" "" "$NETLIFY_ACCESS_TOKEN"
+
+ _record_id=$(echo "$response" | _egrep_o "\"type\":\"TXT\",[^\}]*\"value\":\"$txt\"" | head -n 1 | _egrep_o "\"id\":\"[^\"\}]*\"" | cut -d : -f 2 | tr -d \")
+ _debug _record_id "$_record_id"
+ if [ "$_record_id" ]; then
+ _netlify_rest DELETE "$dnsRecordURI/$_record_id" "" "$NETLIFY_ACCESS_TOKEN"
+ _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
+ if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then
+ _info "validation value removed"
+ return 0
+ else
+ _err "error removing validation value ($_code)"
+ return 1
+ fi
+ return 0
+ fi
+ return 1
+}
+
+#################### Private functions below ##################################
+
+_get_root() {
+ domain=$1
+ accesstoken=$2
+ i=1
+ p=1
+
+ _netlify_rest GET "dns_zones" "" "$accesstoken"
+
+ while true; do
+ h=$(printf "%s" "$domain" | cut -d . -f $i-100)
+ _debug2 "Checking domain: $h"
+ if [ -z "$h" ]; then
+ #not valid
+ _err "Invalid domain"
+ return 1
+ fi
+
+ if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
+ _domain_id=$(echo "$response" | _egrep_o "\"[^\"]*\",\"name\":\"$h" | cut -d , -f 1 | tr -d \")
+ if [ "$_domain_id" ]; then
+ if [ "$i" = 1 ]; then
+ #create the record at the domain apex (@) if only the domain name was provided as --domain-alias
+ _sub_domain="@"
+ else
+ _sub_domain=$(echo "$domain" | cut -d . -f 1-$p)
+ fi
+ _domain=$h
+ return 0
+ fi
+ return 1
+ fi
+ p=$i
+ i=$(_math "$i" + 1)
+ done
+ return 1
+}
+
+_netlify_rest() {
+ m=$1
+ ep="$2"
+ data="$3"
+ _debug "$ep"
+
+ token_trimmed=$(echo "$NETLIFY_ACCESS_TOKEN" | tr -d '"')
+
+ export _H1="Content-Type: application/json"
+ export _H2="Authorization: Bearer $token_trimmed"
+
+ : >"$HTTP_HEADER"
+
+ if [ "$m" != "GET" ]; then
+ _debug data "$data"
+ response="$(_post "$data" "$NETLIFY_URL$ep" "" "$m")"
+ else
+ response="$(_get "$NETLIFY_URL$ep")"
+ fi
+
+ if [ "$?" != "0" ]; then
+ _err "error $ep"
+ return 1
+ fi
+ _debug2 response "$response"
+ return 0
+}
diff --git a/dnsapi/dns_nic.sh b/dnsapi/dns_nic.sh
index 5052ee10..56170f87 100644
--- a/dnsapi/dns_nic.sh
+++ b/dnsapi/dns_nic.sh
@@ -166,7 +166,7 @@ _get_root() {
if _contains "$_all_domains" "^$h$"; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain=$h
- _service=$(printf "%s" "$response" | grep "idn-name=\"$_domain\"" | sed -r "s/.*service=\"(.*)\".*$/\1/")
+ _service=$(printf "%s" "$response" | grep -m 1 "idn-name=\"$_domain\"" | sed -r "s/.*service=\"(.*)\".*$/\1/")
return 0
fi
p="$i"
diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh
index 96ef5969..890cc804 100644
--- a/dnsapi/dns_one.sh
+++ b/dnsapi/dns_one.sh
@@ -6,10 +6,10 @@
# Created: 2019-02-17
# Fixed by: @der-berni
# Modified: 2020-04-07
-#
+#
# Use ONECOM_KeepCnameProxy to keep the CNAME DNS record
# export ONECOM_KeepCnameProxy="1"
-#
+#
# export ONECOM_User="username"
# export ONECOM_Password="password"
#
diff --git a/dnsapi/dns_openstack.sh b/dnsapi/dns_openstack.sh
new file mode 100755
index 00000000..38619e6f
--- /dev/null
+++ b/dnsapi/dns_openstack.sh
@@ -0,0 +1,348 @@
+#!/usr/bin/env sh
+
+# OpenStack Designate API plugin
+#
+# This requires you to have OpenStackClient and python-desginateclient
+# installed.
+#
+# You will require Keystone V3 credentials loaded into your environment, which
+# could be either password or v3applicationcredential type.
+#
+# Author: Andy Botting
+
+######## Public functions #####################
+
+# Usage: dns_openstack_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+dns_openstack_add() {
+ fulldomain=$1
+ txtvalue=$2
+ _debug fulldomain "$fulldomain"
+ _debug txtvalue "$txtvalue"
+
+ _dns_openstack_credentials || return $?
+ _dns_openstack_check_setup || return $?
+ _dns_openstack_find_zone || return $?
+ _dns_openstack_get_recordset || return $?
+ _debug _recordset_id "$_recordset_id"
+ if [ -n "$_recordset_id" ]; then
+ _dns_openstack_get_records || return $?
+ _debug _records "$_records"
+ fi
+ _dns_openstack_create_recordset || return $?
+}
+
+# Usage: dns_openstack_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+# Remove the txt record after validation.
+dns_openstack_rm() {
+ fulldomain=$1
+ txtvalue=$2
+ _debug fulldomain "$fulldomain"
+ _debug txtvalue "$txtvalue"
+
+ _dns_openstack_credentials || return $?
+ _dns_openstack_check_setup || return $?
+ _dns_openstack_find_zone || return $?
+ _dns_openstack_get_recordset || return $?
+ _debug _recordset_id "$_recordset_id"
+ if [ -n "$_recordset_id" ]; then
+ _dns_openstack_get_records || return $?
+ _debug _records "$_records"
+ fi
+ _dns_openstack_delete_recordset || return $?
+}
+
+#################### Private functions below ##################################
+
+_dns_openstack_create_recordset() {
+
+ if [ -z "$_recordset_id" ]; then
+ _info "Creating a new recordset"
+ if ! _recordset_id=$(openstack recordset create -c id -f value --type TXT --record "$txtvalue" "$_zone_id" "$fulldomain."); then
+ _err "No recordset ID found after create"
+ return 1
+ fi
+ else
+ _info "Updating existing recordset"
+ # Build new list of --record args for update
+ _record_args="--record $txtvalue"
+ for _rec in $_records; do
+ _record_args="$_record_args --record $_rec"
+ done
+ # shellcheck disable=SC2086
+ if ! _recordset_id=$(openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain."); then
+ _err "Recordset update failed"
+ return 1
+ fi
+ fi
+
+ _max_retries=60
+ _sleep_sec=5
+ _retry_times=0
+ while [ "$_retry_times" -lt "$_max_retries" ]; do
+ _retry_times=$(_math "$_retry_times" + 1)
+ _debug3 _retry_times "$_retry_times"
+
+ _record_status=$(openstack recordset show -c status -f value "$_zone_id" "$_recordset_id")
+ _info "Recordset status is $_record_status"
+ if [ "$_record_status" = "ACTIVE" ]; then
+ return 0
+ elif [ "$_record_status" = "ERROR" ]; then
+ return 1
+ else
+ _sleep $_sleep_sec
+ fi
+ done
+
+ _err "Recordset failed to become ACTIVE"
+ return 1
+}
+
+_dns_openstack_delete_recordset() {
+
+ if [ "$_records" = "$txtvalue" ]; then
+ _info "Only one record found, deleting recordset"
+ if ! openstack recordset delete "$_zone_id" "$fulldomain." >/dev/null; then
+ _err "Failed to delete recordset"
+ return 1
+ fi
+ else
+ _info "Found existing records, updating recordset"
+ # Build new list of --record args for update
+ _record_args=""
+ for _rec in $_records; do
+ if [ "$_rec" = "$txtvalue" ]; then
+ continue
+ fi
+ _record_args="$_record_args --record $_rec"
+ done
+ # shellcheck disable=SC2086
+ if ! openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain." >/dev/null; then
+ _err "Recordset update failed"
+ return 1
+ fi
+ fi
+}
+
+_dns_openstack_get_root() {
+ # Take the full fqdn and strip away pieces until we get an exact zone name
+ # match. For example, _acme-challenge.something.domain.com might need to go
+ # into something.domain.com or domain.com
+ _zone_name=$1
+ _zone_list=$2
+ while [ "$_zone_name" != "" ]; do
+ _zone_name="$(echo "$_zone_name" | sed 's/[^.]*\.*//')"
+ echo "$_zone_list" | while read -r id name; do
+ if _startswith "$_zone_name." "$name"; then
+ echo "$id"
+ fi
+ done
+ done | _head_n 1
+}
+
+_dns_openstack_find_zone() {
+ if ! _zone_list="$(openstack zone list -c id -c name -f value)"; then
+ _err "Can't list zones. Check your OpenStack credentials"
+ return 1
+ fi
+ _debug _zone_list "$_zone_list"
+
+ if ! _zone_id="$(_dns_openstack_get_root "$fulldomain" "$_zone_list")"; then
+ _err "Can't find a matching zone. Check your OpenStack credentials"
+ return 1
+ fi
+ _debug _zone_id "$_zone_id"
+}
+
+_dns_openstack_get_records() {
+ if ! _records=$(openstack recordset show -c records -f value "$_zone_id" "$fulldomain."); then
+ _err "Failed to get records"
+ return 1
+ fi
+ return 0
+}
+
+_dns_openstack_get_recordset() {
+ if ! _recordset_id=$(openstack recordset list -c id -f value --name "$fulldomain." "$_zone_id"); then
+ _err "Failed to get recordset"
+ return 1
+ fi
+ return 0
+}
+
+_dns_openstack_check_setup() {
+ if ! _exists openstack; then
+ _err "OpenStack client not found"
+ return 1
+ fi
+}
+
+_dns_openstack_credentials() {
+ _debug "Check OpenStack credentials"
+
+ # If we have OS_AUTH_URL already set in the environment, then assume we want
+ # to use those, otherwise use stored credentials
+ if [ -n "$OS_AUTH_URL" ]; then
+ _debug "OS_AUTH_URL env var found, using environment"
+ else
+ _debug "OS_AUTH_URL not found, loading stored credentials"
+ OS_AUTH_URL="${OS_AUTH_URL:-$(_readaccountconf_mutable OS_AUTH_URL)}"
+ OS_IDENTITY_API_VERSION="${OS_IDENTITY_API_VERSION:-$(_readaccountconf_mutable OS_IDENTITY_API_VERSION)}"
+ OS_AUTH_TYPE="${OS_AUTH_TYPE:-$(_readaccountconf_mutable OS_AUTH_TYPE)}"
+ OS_APPLICATION_CREDENTIAL_ID="${OS_APPLICATION_CREDENTIAL_ID:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID)}"
+ OS_APPLICATION_CREDENTIAL_SECRET="${OS_APPLICATION_CREDENTIAL_SECRET:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET)}"
+ OS_USERNAME="${OS_USERNAME:-$(_readaccountconf_mutable OS_USERNAME)}"
+ OS_PASSWORD="${OS_PASSWORD:-$(_readaccountconf_mutable OS_PASSWORD)}"
+ OS_PROJECT_NAME="${OS_PROJECT_NAME:-$(_readaccountconf_mutable OS_PROJECT_NAME)}"
+ OS_PROJECT_ID="${OS_PROJECT_ID:-$(_readaccountconf_mutable OS_PROJECT_ID)}"
+ OS_USER_DOMAIN_NAME="${OS_USER_DOMAIN_NAME:-$(_readaccountconf_mutable OS_USER_DOMAIN_NAME)}"
+ OS_USER_DOMAIN_ID="${OS_USER_DOMAIN_ID:-$(_readaccountconf_mutable OS_USER_DOMAIN_ID)}"
+ OS_PROJECT_DOMAIN_NAME="${OS_PROJECT_DOMAIN_NAME:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_NAME)}"
+ OS_PROJECT_DOMAIN_ID="${OS_PROJECT_DOMAIN_ID:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_ID)}"
+ fi
+
+ # Check each var and either save or clear it depending on whether its set.
+ # The helps us clear out old vars in the case where a user may want
+ # to switch between password and app creds
+ _debug "OS_AUTH_URL" "$OS_AUTH_URL"
+ if [ -n "$OS_AUTH_URL" ]; then
+ export OS_AUTH_URL
+ _saveaccountconf_mutable OS_AUTH_URL "$OS_AUTH_URL"
+ else
+ unset OS_AUTH_URL
+ _clearaccountconf SAVED_OS_AUTH_URL
+ fi
+
+ _debug "OS_IDENTITY_API_VERSION" "$OS_IDENTITY_API_VERSION"
+ if [ -n "$OS_IDENTITY_API_VERSION" ]; then
+ export OS_IDENTITY_API_VERSION
+ _saveaccountconf_mutable OS_IDENTITY_API_VERSION "$OS_IDENTITY_API_VERSION"
+ else
+ unset OS_IDENTITY_API_VERSION
+ _clearaccountconf SAVED_OS_IDENTITY_API_VERSION
+ fi
+
+ _debug "OS_AUTH_TYPE" "$OS_AUTH_TYPE"
+ if [ -n "$OS_AUTH_TYPE" ]; then
+ export OS_AUTH_TYPE
+ _saveaccountconf_mutable OS_AUTH_TYPE "$OS_AUTH_TYPE"
+ else
+ unset OS_AUTH_TYPE
+ _clearaccountconf SAVED_OS_AUTH_TYPE
+ fi
+
+ _debug "OS_APPLICATION_CREDENTIAL_ID" "$OS_APPLICATION_CREDENTIAL_ID"
+ if [ -n "$OS_APPLICATION_CREDENTIAL_ID" ]; then
+ export OS_APPLICATION_CREDENTIAL_ID
+ _saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID "$OS_APPLICATION_CREDENTIAL_ID"
+ else
+ unset OS_APPLICATION_CREDENTIAL_ID
+ _clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_ID
+ fi
+
+ _secure_debug "OS_APPLICATION_CREDENTIAL_SECRET" "$OS_APPLICATION_CREDENTIAL_SECRET"
+ if [ -n "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then
+ export OS_APPLICATION_CREDENTIAL_SECRET
+ _saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET "$OS_APPLICATION_CREDENTIAL_SECRET"
+ else
+ unset OS_APPLICATION_CREDENTIAL_SECRET
+ _clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_SECRET
+ fi
+
+ _debug "OS_USERNAME" "$OS_USERNAME"
+ if [ -n "$OS_USERNAME" ]; then
+ export OS_USERNAME
+ _saveaccountconf_mutable OS_USERNAME "$OS_USERNAME"
+ else
+ unset OS_USERNAME
+ _clearaccountconf SAVED_OS_USERNAME
+ fi
+
+ _secure_debug "OS_PASSWORD" "$OS_PASSWORD"
+ if [ -n "$OS_PASSWORD" ]; then
+ export OS_PASSWORD
+ _saveaccountconf_mutable OS_PASSWORD "$OS_PASSWORD"
+ else
+ unset OS_PASSWORD
+ _clearaccountconf SAVED_OS_PASSWORD
+ fi
+
+ _debug "OS_PROJECT_NAME" "$OS_PROJECT_NAME"
+ if [ -n "$OS_PROJECT_NAME" ]; then
+ export OS_PROJECT_NAME
+ _saveaccountconf_mutable OS_PROJECT_NAME "$OS_PROJECT_NAME"
+ else
+ unset OS_PROJECT_NAME
+ _clearaccountconf SAVED_OS_PROJECT_NAME
+ fi
+
+ _debug "OS_PROJECT_ID" "$OS_PROJECT_ID"
+ if [ -n "$OS_PROJECT_ID" ]; then
+ export OS_PROJECT_ID
+ _saveaccountconf_mutable OS_PROJECT_ID "$OS_PROJECT_ID"
+ else
+ unset OS_PROJECT_ID
+ _clearaccountconf SAVED_OS_PROJECT_ID
+ fi
+
+ _debug "OS_USER_DOMAIN_NAME" "$OS_USER_DOMAIN_NAME"
+ if [ -n "$OS_USER_DOMAIN_NAME" ]; then
+ export OS_USER_DOMAIN_NAME
+ _saveaccountconf_mutable OS_USER_DOMAIN_NAME "$OS_USER_DOMAIN_NAME"
+ else
+ unset OS_USER_DOMAIN_NAME
+ _clearaccountconf SAVED_OS_USER_DOMAIN_NAME
+ fi
+
+ _debug "OS_USER_DOMAIN_ID" "$OS_USER_DOMAIN_ID"
+ if [ -n "$OS_USER_DOMAIN_ID" ]; then
+ export OS_USER_DOMAIN_ID
+ _saveaccountconf_mutable OS_USER_DOMAIN_ID "$OS_USER_DOMAIN_ID"
+ else
+ unset OS_USER_DOMAIN_ID
+ _clearaccountconf SAVED_OS_USER_DOMAIN_ID
+ fi
+
+ _debug "OS_PROJECT_DOMAIN_NAME" "$OS_PROJECT_DOMAIN_NAME"
+ if [ -n "$OS_PROJECT_DOMAIN_NAME" ]; then
+ export OS_PROJECT_DOMAIN_NAME
+ _saveaccountconf_mutable OS_PROJECT_DOMAIN_NAME "$OS_PROJECT_DOMAIN_NAME"
+ else
+ unset OS_PROJECT_DOMAIN_NAME
+ _clearaccountconf SAVED_OS_PROJECT_DOMAIN_NAME
+ fi
+
+ _debug "OS_PROJECT_DOMAIN_ID" "$OS_PROJECT_DOMAIN_ID"
+ if [ -n "$OS_PROJECT_DOMAIN_ID" ]; then
+ export OS_PROJECT_DOMAIN_ID
+ _saveaccountconf_mutable OS_PROJECT_DOMAIN_ID "$OS_PROJECT_DOMAIN_ID"
+ else
+ unset OS_PROJECT_DOMAIN_ID
+ _clearaccountconf SAVED_OS_PROJECT_DOMAIN_ID
+ fi
+
+ if [ "$OS_AUTH_TYPE" = "v3applicationcredential" ]; then
+ # Application Credential auth
+ if [ -z "$OS_APPLICATION_CREDENTIAL_ID" ] || [ -z "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then
+ _err "When using OpenStack application credentials, OS_APPLICATION_CREDENTIAL_ID"
+ _err "and OS_APPLICATION_CREDENTIAL_SECRET must be set."
+ _err "Please check your credentials and try again."
+ return 1
+ fi
+ else
+ # Password auth
+ if [ -z "$OS_USERNAME" ] || [ -z "$OS_PASSWORD" ]; then
+ _err "OpenStack username or password not found."
+ _err "Please check your credentials and try again."
+ return 1
+ fi
+
+ if [ -z "$OS_PROJECT_NAME" ] && [ -z "$OS_PROJECT_ID" ]; then
+ _err "When using password authentication, OS_PROJECT_NAME or"
+ _err "OS_PROJECT_ID must be set."
+ _err "Please check your credentials and try again."
+ return 1
+ fi
+ fi
+
+ return 0
+}
diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh
index 7c18d009..f6f9689a 100755
--- a/dnsapi/dns_ovh.sh
+++ b/dnsapi/dns_ovh.sh
@@ -41,40 +41,40 @@ _ovh_get_api() {
case "${_ogaep}" in
- ovh-eu | ovheu)
- printf "%s" $OVH_EU
- return
- ;;
- ovh-ca | ovhca)
- printf "%s" $OVH_CA
- return
- ;;
- kimsufi-eu | kimsufieu)
- printf "%s" $KSF_EU
- return
- ;;
- kimsufi-ca | kimsufica)
- printf "%s" $KSF_CA
- return
- ;;
- soyoustart-eu | soyoustarteu)
- printf "%s" $SYS_EU
- return
- ;;
- soyoustart-ca | soyoustartca)
- printf "%s" $SYS_CA
- return
- ;;
- runabove-ca | runaboveca)
- printf "%s" $RAV_CA
- return
- ;;
-
- *)
-
- _err "Unknown parameter : $1"
- return 1
- ;;
+ ovh-eu | ovheu)
+ printf "%s" $OVH_EU
+ return
+ ;;
+ ovh-ca | ovhca)
+ printf "%s" $OVH_CA
+ return
+ ;;
+ kimsufi-eu | kimsufieu)
+ printf "%s" $KSF_EU
+ return
+ ;;
+ kimsufi-ca | kimsufica)
+ printf "%s" $KSF_CA
+ return
+ ;;
+ soyoustart-eu | soyoustarteu)
+ printf "%s" $SYS_EU
+ return
+ ;;
+ soyoustart-ca | soyoustartca)
+ printf "%s" $SYS_CA
+ return
+ ;;
+ runabove-ca | runaboveca)
+ printf "%s" $RAV_CA
+ return
+ ;;
+
+ *)
+
+ _err "Unknown parameter : $1"
+ return 1
+ ;;
esac
}
@@ -248,7 +248,7 @@ _ovh_authentication() {
# _domain=domain.com
_get_root() {
domain=$1
- i=2
+ i=1
p=1
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
diff --git a/dnsapi/dns_pleskxml.sh b/dnsapi/dns_pleskxml.sh
index fe18bef4..f5986827 100644
--- a/dnsapi/dns_pleskxml.sh
+++ b/dnsapi/dns_pleskxml.sh
@@ -136,11 +136,12 @@ dns_pleskxml_rm() {
# Reduce output to one line per DNS record, filtered for TXT records with a record ID only (which they should all have)
# Also strip out spaces between tags, redundant and group tags and any tags
- reclist="$(_api_response_split "$pleskxml_prettyprint_result" 'result' 'ok' \
- | sed 's# \{1,\}<\([a-zA-Z]\)#<\1#g;s#\{0,1\}data>##g;s#<[a-z][^/<>]*/>##g' \
- | grep "${root_domain_id}" \
- | grep '[0-9]\{1,\}' \
- | grep 'TXT'
+ reclist="$(
+ _api_response_split "$pleskxml_prettyprint_result" 'result' 'ok' |
+ sed 's# \{1,\}<\([a-zA-Z]\)#<\1#g;s#\{0,1\}data>##g;s#<[a-z][^/<>]*/>##g' |
+ grep "${root_domain_id}" |
+ grep '[0-9]\{1,\}' |
+ grep 'TXT'
)"
if [ -z "$reclist" ]; then
@@ -151,10 +152,11 @@ dns_pleskxml_rm() {
_debug "Got list of DNS TXT records for root domain '$root_domain_name':"
_debug "$reclist"
- recid="$(_value "$reclist" \
- | grep "${fulldomain}." \
- | grep "${txtvalue}" \
- | sed 's/^.*\([0-9]\{1,\}\)<\/id>.*$/\1/'
+ recid="$(
+ _value "$reclist" |
+ grep "${fulldomain}." |
+ grep "${txtvalue}" |
+ sed 's/^.*\([0-9]\{1,\}\)<\/id>.*$/\1/'
)"
if ! _value "$recid" | grep '^[0-9]\{1,\}$' >/dev/null; then
@@ -220,11 +222,11 @@ _countdots() {
# Last line could change to instead, with suitable escaping of ['"/$],
# if future Plesk XML API changes ever require extended regex
_api_response_split() {
- printf '%s' "$1" \
- | sed 's/^ +//;s/ +$//' \
- | tr -d '\n\r' \
- | sed "s/<\/\{0,1\}$2>/${NEWLINE}/g" \
- | grep "$3"
+ printf '%s' "$1" |
+ sed 's/^ +//;s/ +$//' |
+ tr -d '\n\r' |
+ sed "s/<\/\{0,1\}$2>/${NEWLINE}/g" |
+ grep "$3"
}
#################### Private functions below (DNS functions) ##################################
@@ -261,14 +263,15 @@ _call_api() {
elif [ "$statuslines_count_okay" -ne "$statuslines_count_total" ]; then
# We have some status lines that aren't "ok". Any available details are in API response fields "status" "errcode" and "errtext"
- # Workaround for basic regex:
+ # Workaround for basic regex:
# - filter output to keep only lines like this: "SPACEStextSPACES" (shouldn't be necessary with prettyprint but guarantees subsequent code is ok)
# - then edit the 3 "useful" error tokens individually and remove closing tags on all lines
# - then filter again to remove all lines not edited (which will be the lines not starting A-Z)
- errtext="$(_value "$pleskxml_prettyprint_result" \
- | grep '^ *<[a-z]\{1,\}>[^<]*<\/[a-z]\{1,\}> *$' \
- | sed 's/^ */Status: /;s/^ */Error code: /;s/^ */Error text: /;s/<\/.*$//' \
- | grep '^[A-Z]'
+ errtext="$(
+ _value "$pleskxml_prettyprint_result" |
+ grep '^ *<[a-z]\{1,\}>[^<]*<\/[a-z]\{1,\}> *$' |
+ sed 's/^ */Status: /;s/^ */Error code: /;s/^ */Error text: /;s/<\/.*$//' |
+ grep '^[A-Z]'
)"
fi
diff --git a/dnsapi/dns_regru.sh b/dnsapi/dns_regru.sh
index b5729fda..29f758ea 100644
--- a/dnsapi/dns_regru.sh
+++ b/dnsapi/dns_regru.sh
@@ -33,8 +33,11 @@ dns_regru_add() {
fi
_debug _domain "$_domain"
+ _subdomain=$(echo "$fulldomain" | sed -r "s/.$_domain//")
+ _debug _subdomain "$_subdomain"
+
_info "Adding TXT record to ${fulldomain}"
- _regru_rest POST "zone/add_txt" "input_data={%22username%22:%22${REGRU_API_Username}%22,%22password%22:%22${REGRU_API_Password}%22,%22domains%22:[{%22dname%22:%22${_domain}%22}],%22subdomain%22:%22_acme-challenge%22,%22text%22:%22${txtvalue}%22,%22output_content_type%22:%22plain%22}&input_format=json"
+ _regru_rest POST "zone/add_txt" "input_data={%22username%22:%22${REGRU_API_Username}%22,%22password%22:%22${REGRU_API_Password}%22,%22domains%22:[{%22dname%22:%22${_domain}%22}],%22subdomain%22:%22${_subdomain}%22,%22text%22:%22${txtvalue}%22,%22output_content_type%22:%22plain%22}&input_format=json"
if ! _contains "${response}" 'error'; then
return 0
@@ -64,8 +67,11 @@ dns_regru_rm() {
fi
_debug _domain "$_domain"
+ _subdomain=$(echo "$fulldomain" | sed -r "s/.$_domain//")
+ _debug _subdomain "$_subdomain"
+
_info "Deleting resource record $fulldomain"
- _regru_rest POST "zone/remove_record" "input_data={%22username%22:%22${REGRU_API_Username}%22,%22password%22:%22${REGRU_API_Password}%22,%22domains%22:[{%22dname%22:%22${_domain}%22}],%22subdomain%22:%22_acme-challenge%22,%22content%22:%22${txtvalue}%22,%22record_type%22:%22TXT%22,%22output_content_type%22:%22plain%22}&input_format=json"
+ _regru_rest POST "zone/remove_record" "input_data={%22username%22:%22${REGRU_API_Username}%22,%22password%22:%22${REGRU_API_Password}%22,%22domains%22:[{%22dname%22:%22${_domain}%22}],%22subdomain%22:%22${_subdomain}%22,%22content%22:%22${txtvalue}%22,%22record_type%22:%22TXT%22,%22output_content_type%22:%22plain%22}&input_format=json"
if ! _contains "${response}" 'error'; then
return 0
@@ -87,11 +93,11 @@ _get_root() {
for ITEM in ${domains_list}; do
case "${domain}" in
- *${ITEM}*)
- _domain=${ITEM}
- _debug _domain "${_domain}"
- return 0
- ;;
+ *${ITEM}*)
+ _domain=${ITEM}
+ _debug _domain "${_domain}"
+ return 0
+ ;;
esac
done
diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh
index 5721f994..0a2c3330 100755
--- a/dnsapi/dns_yandex.sh
+++ b/dnsapi/dns_yandex.sh
@@ -25,7 +25,7 @@ dns_yandex_add() {
_PDD_get_record_ids || return 1
_debug "Record_ids: $record_ids"
- if [ ! -z "$record_ids" ]; then
+ if [ -n "$record_ids" ]; then
_info "All existing $subdomain records from $domain will be removed at the very end."
fi
diff --git a/notify/mail.sh b/notify/mail.sh
index 54b2a6d4..d33fd0d2 100644
--- a/notify/mail.sh
+++ b/notify/mail.sh
@@ -98,24 +98,24 @@ _mail_cmnd() {
_MAIL_ARGS=""
case $(basename "$_MAIL_BIN") in
- sendmail)
- if [ -n "$MAIL_FROM" ]; then
- _MAIL_ARGS="-f '$MAIL_FROM'"
- fi
- ;;
- mutt | mail)
- _MAIL_ARGS="-s '$_subject'"
- ;;
- msmtp)
- if [ -n "$MAIL_FROM" ]; then
- _MAIL_ARGS="-f '$MAIL_FROM'"
- fi
-
- if [ -n "$MAIL_MSMTP_ACCOUNT" ]; then
- _MAIL_ARGS="$_MAIL_ARGS -a '$MAIL_MSMTP_ACCOUNT'"
- fi
- ;;
- *) ;;
+ sendmail)
+ if [ -n "$MAIL_FROM" ]; then
+ _MAIL_ARGS="-f '$MAIL_FROM'"
+ fi
+ ;;
+ mutt | mail)
+ _MAIL_ARGS="-s '$_subject'"
+ ;;
+ msmtp)
+ if [ -n "$MAIL_FROM" ]; then
+ _MAIL_ARGS="-f '$MAIL_FROM'"
+ fi
+
+ if [ -n "$MAIL_MSMTP_ACCOUNT" ]; then
+ _MAIL_ARGS="$_MAIL_ARGS -a '$MAIL_MSMTP_ACCOUNT'"
+ fi
+ ;;
+ *) ;;
esac
echo "'$_MAIL_BIN' $_MAIL_ARGS '$MAIL_TO'"
@@ -123,16 +123,16 @@ _mail_cmnd() {
_mail_body() {
case $(basename "$_MAIL_BIN") in
- sendmail | ssmtp | msmtp)
- if [ -n "$MAIL_FROM" ]; then
- echo "From: $MAIL_FROM"
- fi
-
- echo "To: $MAIL_TO"
- echo "Subject: $subject"
- echo "Content-Type: $contenttype"
- echo
- ;;
+ sendmail | ssmtp | msmtp)
+ if [ -n "$MAIL_FROM" ]; then
+ echo "From: $MAIL_FROM"
+ fi
+
+ echo "To: $MAIL_TO"
+ echo "Subject: $subject"
+ echo "Content-Type: $contenttype"
+ echo
+ ;;
esac
echo "$_content"
diff --git a/notify/teams.sh b/notify/teams.sh
index e50ea703..1bc5ed08 100644
--- a/notify/teams.sh
+++ b/notify/teams.sh
@@ -52,15 +52,15 @@ teams_send() {
_content=$(echo "$_content" | _json_encode)
case "$_statusCode" in
- 0)
- _color="${TEAMS_SUCCESS_COLOR:-$_color_success}"
- ;;
- 1)
- _color="${TEAMS_ERROR_COLOR:-$_color_danger}"
- ;;
- 2)
- _color="${TEAMS_SKIP_COLOR:-$_color_muted}"
- ;;
+ 0)
+ _color="${TEAMS_SUCCESS_COLOR:-$_color_success}"
+ ;;
+ 1)
+ _color="${TEAMS_ERROR_COLOR:-$_color_danger}"
+ ;;
+ 2)
+ _color="${TEAMS_SKIP_COLOR:-$_color_muted}"
+ ;;
esac
_color=$(echo "$_color" | tr -cd 'a-fA-F0-9')
diff --git a/notify/xmpp.sh b/notify/xmpp.sh
index 580f471e..0ce1119e 100644
--- a/notify/xmpp.sh
+++ b/notify/xmpp.sh
@@ -71,13 +71,13 @@ _xmpp_bin() {
_xmpp_cmnd() {
case $(basename "$_XMPP_BIN") in
- sendxmpp)
- echo "'$_XMPP_BIN' '$XMPP_TO' $XMPP_BIN_ARGS"
- ;;
- *)
- _err "Command $XMPP_BIN is not supported, use sendxmpp."
- return 1
- ;;
+ sendxmpp)
+ echo "'$_XMPP_BIN' '$XMPP_TO' $XMPP_BIN_ARGS"
+ ;;
+ *)
+ _err "Command $XMPP_BIN is not supported, use sendxmpp."
+ return 1
+ ;;
esac
}