Browse Source

Merge branch 'acmesh-official:master' into master

pull/5128/head
Владимир Алексеев 2 days ago
committed by GitHub
parent
commit
b29cb08956
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      .github/workflows/pr_dns.yml
  2. 14
      acme.sh
  3. 172
      deploy/ruckus.sh
  4. 111
      deploy/strongswan.sh
  5. 177
      deploy/truenas.sh
  6. 15
      dnsapi/dns_alviy.sh
  7. 135
      dnsapi/dns_azure.sh
  8. 24
      dnsapi/dns_fornex.sh
  9. 14
      dnsapi/dns_ionos_cloud.sh
  10. 42
      dnsapi/dns_linode_v4.sh
  11. 20
      dnsapi/dns_omglol.sh
  12. 18
      dnsapi/dns_pdns.sh
  13. 56
      dnsapi/dns_technitium.sh
  14. 21
      dnsapi/dns_timeweb.sh
  15. 5
      dnsapi/dns_world4you.sh
  16. 145
      dnsapi/dns_zoneedit.sh

1
.github/workflows/pr_dns.yml

@ -23,6 +23,7 @@ jobs:
First thing: don't send PR to the master branch, please send to the dev branch instead. First thing: don't send PR to the master branch, please send to the dev branch instead.
Please make sure you've read our [DNS API Dev Guide](../wiki/DNS-API-Dev-Guide) and [DNS-API-Test](../wiki/DNS-API-Test). Please make sure you've read our [DNS API Dev Guide](../wiki/DNS-API-Dev-Guide) and [DNS-API-Test](../wiki/DNS-API-Test).
Then reply on this message, otherwise, your code will not be reviewed or merged. Then reply on this message, otherwise, your code will not be reviewed or merged.
Please also make sure to add/update the usage here: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2
We look forward to reviewing your Pull request shortly ✨ We look forward to reviewing your Pull request shortly ✨
注意: 必须通过了 [DNS-API-Test](../wiki/DNS-API-Test) 才会被 review. 无论是修改, 还是新加的 dns api, 都必须确保通过这个测试. 注意: 必须通过了 [DNS-API-Test](../wiki/DNS-API-Test) 才会被 review. 无论是修改, 还是新加的 dns api, 都必须确保通过这个测试.
` `

14
acme.sh

@ -1442,7 +1442,7 @@ _toPkcs() {
else else
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca"
fi fi
if [ "$?" == "0" ]; then
if [ "$?" = "0" ]; then
_savedomainconf "Le_PFXPassword" "$pfxPassword" _savedomainconf "Le_PFXPassword" "$pfxPassword"
fi fi
@ -1628,6 +1628,11 @@ _time2str() {
return return
fi fi
#Omnios
if date -u -r "$1" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null; then
return
fi
#Solaris #Solaris
if printf "%(%Y-%m-%dT%H:%M:%SZ)T\n" $1 2>/dev/null; then if printf "%(%Y-%m-%dT%H:%M:%SZ)T\n" $1 2>/dev/null; then
return return
@ -1811,7 +1816,11 @@ _date2time() {
return return
fi fi
#Omnios #Omnios
if da="$(echo "$1" | tr -d "Z" | tr "T" ' ')" perl -MTime::Piece -e 'print Time::Piece->strptime($ENV{da}, "%Y-%m-%d %H:%M:%S")->epoch, "\n";' 2>/dev/null; then
if python3 -c "import datetime; print(int(datetime.datetime.strptime(\"$1\", \"%Y-%m-%d %H:%M:%S\").replace(tzinfo=datetime.timezone.utc).timestamp()))" 2>/dev/null; then
return
fi
#Omnios
if python3 -c "import datetime; print(int(datetime.datetime.strptime(\"$1\", \"%Y-%m-%dT%H:%M:%SZ\").replace(tzinfo=datetime.timezone.utc).timestamp()))" 2>/dev/null; then
return return
fi fi
_err "Cannot parse _date2time $1" _err "Cannot parse _date2time $1"
@ -2193,7 +2202,6 @@ _send_signed_request() {
_debug2 _headers "$_headers" _debug2 _headers "$_headers"
_CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
fi fi
_debug2 _CACHED_NONCE "$_CACHED_NONCE"
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
_err "Cannot connect to $nonceurl to get nonce." _err "Cannot connect to $nonceurl to get nonce."
return 1 return 1

172
deploy/ruckus.sh

@ -0,0 +1,172 @@
#!/usr/bin/env sh
# Here is a script to deploy cert to Ruckus ZoneDirector / Unleashed.
#
# Public domain, 2024, Tony Rielly <https://github.com/ms264556>
#
# ```sh
# acme.sh --deploy -d ruckus.example.com --deploy-hook ruckus
# ```
#
# Then you need to set the environment variables for the
# deploy script to work.
#
# ```sh
# export RUCKUS_HOST=myruckus.example.com
# export RUCKUS_USER=myruckususername
# export RUCKUS_PASS=myruckuspassword
#
# acme.sh --deploy -d myruckus.example.com --deploy-hook ruckus
# ```
#
# returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
ruckus_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_err_code=0
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_getdeployconf RUCKUS_HOST
_getdeployconf RUCKUS_USER
_getdeployconf RUCKUS_PASS
if [ -z "$RUCKUS_HOST" ]; then
_debug "Using _cdomain as RUCKUS_HOST, please set if not correct."
RUCKUS_HOST="$_cdomain"
fi
if [ -z "$RUCKUS_USER" ]; then
_err "Need to set the env variable RUCKUS_USER"
return 1
fi
if [ -z "$RUCKUS_PASS" ]; then
_err "Need to set the env variable RUCKUS_PASS"
return 1
fi
_savedeployconf RUCKUS_HOST "$RUCKUS_HOST"
_savedeployconf RUCKUS_USER "$RUCKUS_USER"
_savedeployconf RUCKUS_PASS "$RUCKUS_PASS"
_debug RUCKUS_HOST "$RUCKUS_HOST"
_debug RUCKUS_USER "$RUCKUS_USER"
_secure_debug RUCKUS_PASS "$RUCKUS_PASS"
export ACME_HTTP_NO_REDIRECTS=1
_info "Discovering the login URL"
_get "https://$RUCKUS_HOST" >/dev/null
_login_url="$(_response_header 'Location')"
if [ -n "$_login_url" ]; then
_login_path=$(echo "$_login_url" | sed 's|https\?://[^/]\+||')
if [ -z "$_login_path" ]; then
# redirect was to a different host
_err "Connection failed: redirected to a different host. Configure Unleashed with a Preferred Master or Management Interface."
return 1
fi
fi
if [ -z "${_login_url}" ]; then
_err "Connection failed: couldn't find login page."
return 1
fi
_base_url=$(dirname "$_login_url")
_login_page=$(basename "$_login_url")
if [ "$_login_page" = "index.html" ]; then
_err "Connection temporarily unavailable: Unleashed Rebuilding."
return 1
fi
if [ "$_login_page" = "wizard.jsp" ]; then
_err "Connection failed: Setup Wizard not complete."
return 1
fi
_info "Login"
_username_encoded="$(printf "%s" "$RUCKUS_USER" | _url_encode)"
_password_encoded="$(printf "%s" "$RUCKUS_PASS" | _url_encode)"
_login_query="$(printf "%s" "username=${_username_encoded}&password=${_password_encoded}&ok=Log+In")"
_post "$_login_query" "$_login_url" >/dev/null
_login_code="$(_response_code)"
if [ "$_login_code" = "200" ]; then
_err "Login failed: incorrect credentials."
return 1
fi
_info "Collect Session Cookie"
_H1="Cookie: $(_response_cookie)"
export _H1
_info "Collect CSRF Token"
_H2="X-CSRF-Token: $(_response_header 'HTTP_X_CSRF_TOKEN')"
export _H2
_info "Uploading certificate"
_post_upload "uploadcert" "$_cfullchain"
_info "Uploading private key"
_post_upload "uploadprivatekey" "$_ckey"
_info "Replacing certificate"
_replace_cert_ajax='<ajax-request action="docmd" comp="system" updater="rid.0.5" xcmd="replace-cert" checkAbility="6" timeout="-1"><xcmd cmd="replace-cert" cn="'$RUCKUS_HOST'"/></ajax-request>'
_post "$_replace_cert_ajax" "$_base_url/_cmdstat.jsp" >/dev/null
_info "Rebooting"
_cert_reboot_ajax='<ajax-request action="docmd" comp="worker" updater="rid.0.5" xcmd="cert-reboot" checkAbility="6"><xcmd cmd="cert-reboot" action="undefined"/></ajax-request>'
_post "$_cert_reboot_ajax" "$_base_url/_cmdstat.jsp" >/dev/null
return 0
}
_response_code() {
_egrep_o <"$HTTP_HEADER" "^HTTP[^ ]* .*$" | cut -d " " -f 2-100 | tr -d "\f\n" | _egrep_o "^[0-9]*"
}
_response_header() {
grep <"$HTTP_HEADER" -i "^$1:" | cut -d ':' -f 2- | tr -d "\r\n\t "
}
_response_cookie() {
_response_header 'Set-Cookie' | sed 's/;.*//'
}
_post_upload() {
_post_action="$1"
_post_file="$2"
_post_boundary="----FormBoundary$(date "+%s%N")"
_post_data="$({
printf -- "--%s\r\n" "$_post_boundary"
printf -- "Content-Disposition: form-data; name=\"u\"; filename=\"%s\"\r\n" "$_post_action"
printf -- "Content-Type: application/octet-stream\r\n\r\n"
printf -- "%s\r\n" "$(cat "$_post_file")"
printf -- "--%s\r\n" "$_post_boundary"
printf -- "Content-Disposition: form-data; name=\"action\"\r\n\r\n"
printf -- "%s\r\n" "$_post_action"
printf -- "--%s\r\n" "$_post_boundary"
printf -- "Content-Disposition: form-data; name=\"callback\"\r\n\r\n"
printf -- "%s\r\n" "uploader_$_post_action"
printf -- "--%s--\r\n\r\n" "$_post_boundary"
})"
_post "$_post_data" "$_base_url/_upload.jsp?request_type=xhr" "" "" "multipart/form-data; boundary=$_post_boundary" >/dev/null
}

111
deploy/strongswan.sh

@ -10,46 +10,89 @@
#domain keyfile certfile cafile fullchain #domain keyfile certfile cafile fullchain
strongswan_deploy() { strongswan_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_cdomain="${1}"
_ckey="${2}"
_ccert="${3}"
_cca="${4}"
_cfullchain="${5}"
_info "Using strongswan" _info "Using strongswan"
if [ -x /usr/sbin/ipsec ]; then
_ipsec=/usr/sbin/ipsec
elif [ -x /usr/sbin/strongswan ]; then
_ipsec=/usr/sbin/strongswan
elif [ -x /usr/local/sbin/ipsec ]; then
_ipsec=/usr/local/sbin/ipsec
else
if _exists ipsec; then
_ipsec=ipsec
elif _exists strongswan; then
_ipsec=strongswan
fi
if _exists swanctl; then
_swanctl=swanctl
fi
# For legacy stroke mode
if [ -n "${_ipsec}" ]; then
_info "${_ipsec} command detected"
_confdir=$(${_ipsec} --confdir)
if [ -z "${_confdir}" ]; then
_err "no strongswan --confdir is detected"
return 1
fi
_info _confdir "${_confdir}"
__deploy_cert "$@" "stroke" "${_confdir}"
${_ipsec} reload
fi
# For modern vici mode
if [ -n "${_swanctl}" ]; then
_info "${_swanctl} command detected"
for _dir in /usr/local/etc/swanctl /etc/swanctl /etc/strongswan/swanctl; do
if [ -d ${_dir} ]; then
_confdir=${_dir}
_info _confdir "${_confdir}"
break
fi
done
if [ -z "${_confdir}" ]; then
_err "no swanctl config dir is found"
return 1
fi
__deploy_cert "$@" "vici" "${_confdir}"
${_swanctl} --load-creds
fi
if [ -z "${_swanctl}" ] && [ -z "${_ipsec}" ]; then
_err "no strongswan or ipsec command is detected" _err "no strongswan or ipsec command is detected"
_err "no swanctl is detected"
return 1 return 1
fi fi
}
_info _ipsec "$_ipsec"
#################### Private functions below ##################################
_confdir=$($_ipsec --confdir)
if [ $? -ne 0 ] || [ -z "$_confdir" ]; then
_err "no strongswan --confdir is detected"
__deploy_cert() {
_cdomain="${1}"
_ckey="${2}"
_ccert="${3}"
_cca="${4}"
_cfullchain="${5}"
_swan_mode="${6}"
_confdir="${7}"
_debug _cdomain "${_cdomain}"
_debug _ckey "${_ckey}"
_debug _ccert "${_ccert}"
_debug _cca "${_cca}"
_debug _cfullchain "${_cfullchain}"
_debug _swan_mode "${_swan_mode}"
_debug _confdir "${_confdir}"
if [ "${_swan_mode}" = "vici" ]; then
_dir_private="private"
_dir_cert="x509"
_dir_ca="x509ca"
elif [ "${_swan_mode}" = "stroke" ]; then
_dir_private="ipsec.d/private"
_dir_cert="ipsec.d/certs"
_dir_ca="ipsec.d/cacerts"
else
_err "unknown StrongSwan mode ${_swan_mode}"
return 1 return 1
fi fi
_info _confdir "$_confdir"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
cat "$_ckey" >"${_confdir}/ipsec.d/private/$(basename "$_ckey")"
cat "$_ccert" >"${_confdir}/ipsec.d/certs/$(basename "$_ccert")"
cat "$_cca" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cca")"
cat "$_cfullchain" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cfullchain")"
$_ipsec reload
cat "${_ckey}" >"${_confdir}/${_dir_private}/$(basename "${_ckey}")"
cat "${_ccert}" >"${_confdir}/${_dir_cert}/$(basename "${_ccert}")"
cat "${_cca}" >"${_confdir}/${_dir_ca}/$(basename "${_cca}")"
if [ "${_swan_mode}" = "stroke" ]; then
cat "${_cfullchain}" >"${_confdir}/${_dir_ca}/$(basename "${_cfullchain}")"
fi
} }

177
deploy/truenas.sh

@ -9,7 +9,7 @@
# #
# Following environment variables must be set: # Following environment variables must be set:
# #
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI"
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI>"
# #
# The following environmental variables may be set if you don't like their # The following environmental variables may be set if you don't like their
# default values: # default values:
@ -64,6 +64,20 @@ truenas_deploy() {
_response=$(_get "$_api_url/system/state") _response=$(_get "$_api_url/system/state")
_info "TrueNAS system state: $_response." _info "TrueNAS system state: $_response."
_info "Getting TrueNAS version"
_response=$(_get "$_api_url/system/version")
if echo "$_response" | grep -q "SCALE"; then
_truenas_os=$(echo "$_response" | cut -d '-' -f 2)
_truenas_version=$(echo "$_response" | cut -d '-' -f 3 | tr -d '"' | cut -d '.' -f 1,2)
else
_truenas_os="unknown"
_truenas_version="unknown"
fi
_info "Detected TrueNAS system os: $_truenas_os"
_info "Detected TrueNAS system version: $_truenas_version"
if [ -z "$_response" ]; then if [ -z "$_response" ]; then
_err "Unable to authenticate to $_api_url." _err "Unable to authenticate to $_api_url."
_err 'Check your connection settings are correct, e.g.' _err 'Check your connection settings are correct, e.g.'
@ -115,27 +129,106 @@ truenas_deploy() {
_debug3 _activate_result "$_activate_result" _debug3 _activate_result "$_activate_result"
_info "Checking if WebDAV certificate is the same as the TrueNAS web UI"
_webdav_list=$(_get "$_api_url/webdav")
_webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,')
if [ "$_webdav_cert_id" = "$_active_cert_id" ]; then
_info "Updating the WebDAV certificate"
_debug _webdav_cert_id "$_webdav_cert_id"
_webdav_data="{\"certssl\": \"${_cert_id}\"}"
_activate_webdav_cert="$(_post "$_webdav_data" "$_api_url/webdav" "" "PUT" "application/json")"
_webdav_new_cert_id=$(echo "$_activate_webdav_cert" | _json_decode | grep '"certssl":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
if [ "$_webdav_new_cert_id" -eq "$_cert_id" ]; then
_info "WebDAV certificate updated successfully"
else
_err "Unable to set WebDAV certificate"
_debug3 _activate_webdav_cert "$_activate_webdav_cert"
_truenas_version_23_10="23.10"
_truenas_version_24_10="24.10"
_check_version=$(printf "%s\n%s" "$_truenas_version_23_10" "$_truenas_version" | sort -V | head -n 1)
if [ "$_truenas_os" != "SCALE" ] || [ "$_check_version" != "$_truenas_version_23_10" ]; then
_info "Checking if WebDAV certificate is the same as the TrueNAS web UI"
_webdav_list=$(_get "$_api_url/webdav")
_webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,')
if [ "$_webdav_cert_id" = "$_active_cert_id" ]; then
_info "Updating the WebDAV certificate"
_debug _webdav_cert_id "$_webdav_cert_id"
_webdav_data="{\"certssl\": \"${_cert_id}\"}"
_activate_webdav_cert="$(_post "$_webdav_data" "$_api_url/webdav" "" "PUT" "application/json")"
_webdav_new_cert_id=$(echo "$_activate_webdav_cert" | _json_decode | grep '"certssl":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
if [ "$_webdav_new_cert_id" -eq "$_cert_id" ]; then
_info "WebDAV certificate updated successfully"
else
_err "Unable to set WebDAV certificate"
_debug3 _activate_webdav_cert "$_activate_webdav_cert"
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
return 1
fi
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id" _debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
return 1
else
_info "WebDAV certificate is not configured or is not the same as TrueNAS web UI"
fi
_info "Checking if S3 certificate is the same as the TrueNAS web UI"
_s3_list=$(_get "$_api_url/s3")
_s3_cert_id=$(echo "$_s3_list" | grep '"certificate":' | tr -d -- '"certifa:_ ,')
if [ "$_s3_cert_id" = "$_active_cert_id" ]; then
_info "Updating the S3 certificate"
_debug _s3_cert_id "$_s3_cert_id"
_s3_data="{\"certificate\": \"${_cert_id}\"}"
_activate_s3_cert="$(_post "$_s3_data" "$_api_url/s3" "" "PUT" "application/json")"
_s3_new_cert_id=$(echo "$_activate_s3_cert" | _json_decode | grep '"certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
if [ "$_s3_new_cert_id" -eq "$_cert_id" ]; then
_info "S3 certificate updated successfully"
else
_err "Unable to set S3 certificate"
_debug3 _activate_s3_cert "$_activate_s3_cert"
_debug3 _s3_new_cert_id "$_s3_new_cert_id"
return 1
fi
_debug3 _activate_s3_cert "$_activate_s3_cert"
else
_info "S3 certificate is not configured or is not the same as TrueNAS web UI"
fi
fi
if [ "$_truenas_os" = "SCALE" ]; then
_check_version=$(printf "%s\n%s" "$_truenas_version_24_10" "$_truenas_version" | sort -V | head -n 1)
if [ "$_check_version" != "$_truenas_version_24_10" ]; then
_info "Checking if any chart release Apps is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
if _exists jq; then
_info "Query all chart release"
_release_list=$(_get "$_api_url/chart/release")
_related_name_list=$(printf "%s" "$_release_list" | jq -r "[.[] | {name,certId: .config.ingress?.main.tls[]?.scaleCert} | select(.certId==$_active_cert_id) | .name ] | unique")
_release_length=$(printf "%s" "$_related_name_list" | jq -r "length")
_info "Found $_release_length related chart release in list: $_related_name_list"
for i in $(seq 0 $((_release_length - 1))); do
_release_name=$(echo "$_related_name_list" | jq -r ".[$i]")
_info "Updating certificate from $_active_cert_id to $_cert_id for chart release: $_release_name"
#Read the chart release configuration
_chart_config=$(printf "%s" "$_release_list" | jq -r ".[] | select(.name==\"$_release_name\")")
#Replace the old certificate id with the new one in path .config.ingress.main.tls[].scaleCert. Then update .config.ingress
_updated_chart_config=$(printf "%s" "$_chart_config" | jq "(.config.ingress?.main.tls[]? | select(.scaleCert==$_active_cert_id) | .scaleCert ) |= $_cert_id | .config.ingress ")
_update_chart_result="$(_post "{\"values\" : { \"ingress\" : $_updated_chart_config } }" "$_api_url/chart/release/id/$_release_name" "" "PUT" "application/json")"
_debug3 _update_chart_result "$_update_chart_result"
done
else
_info "Tool 'jq' does not exists, skip chart release checking"
fi
else
_info "Checking if any app is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
if _exists jq; then
_info "Query all apps"
_app_list=$(_get "$_api_url/app")
_app_id_list=$(printf "%s" "$_app_list" | jq -r '.[].name')
_app_length=$(echo "$_app_id_list" | wc -l)
_info "Found $_app_length apps"
_info "Checking for each app if an update is needed"
for i in $(seq 1 "$_app_length"); do
_app_id=$(echo "$_app_id_list" | sed -n "${i}p")
_app_config="$(_post "\"$_app_id\"" "$_api_url/app/config" "" "POST" "application/json")"
# Check if the app use the same certificate TrueNAS web UI
_app_active_cert_config=$(echo "$_app_config" | _json_decode | jq -r ".ix_certificates[\"$_active_cert_id\"]")
if [ "$_app_active_cert_config" != "null" ]; then
_info "Updating certificate from $_active_cert_id to $_cert_id for app: $_app_id"
#Replace the old certificate id with the new one in path
_update_app_result="$(_post "{\"values\" : { \"network\": { \"certificate_id\": $_cert_id } } }" "$_api_url/app/id/$_app_id" "" "PUT" "application/json")"
_debug3 _update_app_result "$_update_app_result"
fi
done
else
_info "Tool 'jq' does not exists, skip app checking"
fi
fi fi
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
else
_info "WebDAV certificate is not configured or is not the same as TrueNAS web UI"
fi fi
_info "Checking if FTP certificate is the same as the TrueNAS web UI" _info "Checking if FTP certificate is the same as the TrueNAS web UI"
@ -161,50 +254,6 @@ truenas_deploy() {
_info "FTP certificate is not configured or is not the same as TrueNAS web UI" _info "FTP certificate is not configured or is not the same as TrueNAS web UI"
fi fi
_info "Checking if S3 certificate is the same as the TrueNAS web UI"
_s3_list=$(_get "$_api_url/s3")
_s3_cert_id=$(echo "$_s3_list" | grep '"certificate":' | tr -d -- '"certifa:_ ,')
if [ "$_s3_cert_id" = "$_active_cert_id" ]; then
_info "Updating the S3 certificate"
_debug _s3_cert_id "$_s3_cert_id"
_s3_data="{\"certificate\": \"${_cert_id}\"}"
_activate_s3_cert="$(_post "$_s3_data" "$_api_url/s3" "" "PUT" "application/json")"
_s3_new_cert_id=$(echo "$_activate_s3_cert" | _json_decode | grep '"certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
if [ "$_s3_new_cert_id" -eq "$_cert_id" ]; then
_info "S3 certificate updated successfully"
else
_err "Unable to set S3 certificate"
_debug3 _activate_s3_cert "$_activate_s3_cert"
_debug3 _s3_new_cert_id "$_s3_new_cert_id"
return 1
fi
_debug3 _activate_s3_cert "$_activate_s3_cert"
else
_info "S3 certificate is not configured or is not the same as TrueNAS web UI"
fi
_info "Checking if any chart release Apps is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
if _exists jq; then
_info "Query all chart release"
_release_list=$(_get "$_api_url/chart/release")
_related_name_list=$(printf "%s" "$_release_list" | jq -r "[.[] | {name,certId: .config.ingress?.main.tls[]?.scaleCert} | select(.certId==$_active_cert_id) | .name ] | unique")
_release_length=$(printf "%s" "$_related_name_list" | jq -r "length")
_info "Found $_release_length related chart release in list: $_related_name_list"
for i in $(seq 0 $((_release_length - 1))); do
_release_name=$(echo "$_related_name_list" | jq -r ".[$i]")
_info "Updating certificate from $_active_cert_id to $_cert_id for chart release: $_release_name"
#Read the chart release configuration
_chart_config=$(printf "%s" "$_release_list" | jq -r ".[] | select(.name==\"$_release_name\")")
#Replace the old certificate id with the new one in path .config.ingress.main.tls[].scaleCert. Then update .config.ingress
_updated_chart_config=$(printf "%s" "$_chart_config" | jq "(.config.ingress?.main.tls[]? | select(.scaleCert==$_active_cert_id) | .scaleCert ) |= $_cert_id | .config.ingress ")
_update_chart_result="$(_post "{\"values\" : { \"ingress\" : $_updated_chart_config } }" "$_api_url/chart/release/id/$_release_name" "" "PUT" "application/json")"
_debug3 _update_chart_result "$_update_chart_result"
done
else
_info "Tool 'jq' does not exists, skip chart release checking"
fi
_info "Deleting old certificate" _info "Deleting old certificate"
_delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")" _delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")"

15
dnsapi/dns_alviy.sh

@ -1,11 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# Alviy domain api
#
# Get API key and secret from https://cloud.alviy.com/token
#
# Alviy_token="some-secret-key"
#
# Ex.: acme.sh --issue --staging --dns dns_alviy -d "*.s.example.com" -d "s.example.com"
# shellcheck disable=SC2034
dns_alviy_info='Alviy.com
Site: Alviy.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_alviy
Options:
Alviy_token API token. Get it from the https://cloud.alviy.com/token
Issues: github.com/acmesh-official/acme.sh/issues/5115
'
Alviy_Api="https://cloud.alviy.com/api/v1" Alviy_Api="https://cloud.alviy.com/api/v1"

135
dnsapi/dns_azure.sh

@ -9,6 +9,7 @@ Options:
AZUREDNS_APPID App ID. App ID of the service principal AZUREDNS_APPID App ID. App ID of the service principal
AZUREDNS_CLIENTSECRET Client Secret. Secret from creating the service principal AZUREDNS_CLIENTSECRET Client Secret. Secret from creating the service principal
AZUREDNS_MANAGEDIDENTITY Use Managed Identity. Use Managed Identity assigned to a resource instead of a service principal. "true"/"false" AZUREDNS_MANAGEDIDENTITY Use Managed Identity. Use Managed Identity assigned to a resource instead of a service principal. "true"/"false"
AZUREDNS_BEARERTOKEN Optional Bearer Token. Used instead of service principal credentials or managed identity
' '
wiki=https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS wiki=https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS
@ -31,6 +32,7 @@ dns_azure_add() {
AZUREDNS_TENANTID="" AZUREDNS_TENANTID=""
AZUREDNS_APPID="" AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET="" AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure Subscription ID" _err "You didn't specify the Azure Subscription ID"
return 1 return 1
fi fi
@ -45,37 +47,45 @@ dns_azure_add() {
_saveaccountconf_mutable AZUREDNS_TENANTID "" _saveaccountconf_mutable AZUREDNS_TENANTID ""
_saveaccountconf_mutable AZUREDNS_APPID "" _saveaccountconf_mutable AZUREDNS_APPID ""
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "" _saveaccountconf_mutable AZUREDNS_CLIENTSECRET ""
_saveaccountconf_mutable AZUREDNS_BEARERTOKEN ""
else else
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
_info "You didn't ask to use Azure managed identity, checking service principal credentials or provided bearer token"
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
AZUREDNS_BEARERTOKEN="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
if [ -z "$AZUREDNS_BEARERTOKEN" ]; then
if [ -z "$AZUREDNS_TENANTID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure Tenant ID "
return 1
fi
if [ -z "$AZUREDNS_TENANTID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Tenant ID "
return 1
fi
if [ -z "$AZUREDNS_APPID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure App ID"
return 1
fi
if [ -z "$AZUREDNS_APPID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure App ID"
return 1
fi
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Client Secret"
return 1
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure Client Secret"
return 1
fi
else
_info "Using provided bearer token"
fi fi
#save account details to account conf file, don't opt in for azure manages identity check. #save account details to account conf file, don't opt in for azure manages identity check.
@ -83,9 +93,14 @@ dns_azure_add() {
_saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID" _saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID"
_saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID" _saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID"
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET" _saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET"
_saveaccountconf_mutable AZUREDNS_BEARERTOKEN "$AZUREDNS_BEARERTOKEN"
fi fi
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
if [ -z "$AZUREDNS_BEARERTOKEN" ]; then
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
else
accesstoken=$(echo "$AZUREDNS_BEARERTOKEN" | sed "s/Bearer //g")
fi
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
_err "invalid domain" _err "invalid domain"
@ -147,6 +162,7 @@ dns_azure_rm() {
AZUREDNS_TENANTID="" AZUREDNS_TENANTID=""
AZUREDNS_APPID="" AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET="" AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure Subscription ID " _err "You didn't specify the Azure Subscription ID "
return 1 return 1
fi fi
@ -155,40 +171,51 @@ dns_azure_rm() {
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
_info "Using Azure managed identity" _info "Using Azure managed identity"
else else
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
_info "You didn't ask to use Azure managed identity, checking service principal credentials or provided bearer token"
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
AZUREDNS_BEARERTOKEN="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
if [ -z "$AZUREDNS_BEARERTOKEN" ]; then
if [ -z "$AZUREDNS_TENANTID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure Tenant ID "
return 1
fi
if [ -z "$AZUREDNS_TENANTID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Tenant ID "
return 1
fi
if [ -z "$AZUREDNS_APPID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure App ID"
return 1
fi
if [ -z "$AZUREDNS_APPID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure App ID"
return 1
fi
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Client Secret"
return 1
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure Client Secret"
return 1
fi
else
_info "Using provided bearer token"
fi fi
fi fi
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
if [ -z "$AZUREDNS_BEARERTOKEN" ]; then
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
else
accesstoken=$(echo "$AZUREDNS_BEARERTOKEN" | sed "s/Bearer //g")
fi
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
_err "invalid domain" _err "invalid domain"
@ -295,7 +322,7 @@ _azure_getaccess_token() {
clientID=$3 clientID=$3
clientSecret=$4 clientSecret=$4
accesstoken="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
accesstoken="${AZUREDNS_ACCESSTOKEN:-$(_readaccountconf_mutable AZUREDNS_ACCESSTOKEN)}"
expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}" expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}"
# can we reuse the bearer token? # can we reuse the bearer token?
@ -339,7 +366,7 @@ _azure_getaccess_token() {
_err "error $response" _err "error $response"
return 1 return 1
fi fi
_saveaccountconf_mutable AZUREDNS_BEARERTOKEN "$accesstoken"
_saveaccountconf_mutable AZUREDNS_ACCESSTOKEN "$accesstoken"
_saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "$expires_on" _saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "$expires_on"
printf "%s" "$accesstoken" printf "%s" "$accesstoken"
return 0 return 0

24
dnsapi/dns_fornex.sh

@ -9,7 +9,7 @@ Issues: github.com/acmesh-official/acme.sh/issues/3998
Author: Timur Umarov <inbox@tumarov.com> Author: Timur Umarov <inbox@tumarov.com>
' '
FORNEX_API_URL="https://fornex.com/api/dns/v0.1"
FORNEX_API_URL="https://fornex.com/api"
######## Public functions ##################### ######## Public functions #####################
@ -30,12 +30,10 @@ dns_fornex_add() {
fi fi
_info "Adding record" _info "Adding record"
if _rest POST "$_domain/entry_set/add/" "host=$fulldomain&type=TXT&value=$txtvalue&apikey=$FORNEX_API_KEY"; then
if _rest POST "dns/domain/$_domain/entry_set/" "{\"host\" : \"${fulldomain}\" , \"type\" : \"TXT\" , \"value\" : \"${txtvalue}\" , \"ttl\" : null}"; then
_debug _response "$response" _debug _response "$response"
if _contains "$response" '"ok": true' || _contains "$response" 'Такая запись уже существует.'; then
_info "Added, OK"
return 0
fi
_info "Added, OK"
return 0
fi fi
_err "Add txt record error." _err "Add txt record error."
return 1 return 1
@ -58,21 +56,21 @@ dns_fornex_rm() {
fi fi
_debug "Getting txt records" _debug "Getting txt records"
_rest GET "$_domain/entry_set.json?apikey=$FORNEX_API_KEY"
_rest GET "dns/domain/$_domain/entry_set?type=TXT&q=$fulldomain"
if ! _contains "$response" "$txtvalue"; then if ! _contains "$response" "$txtvalue"; then
_err "Txt record not found" _err "Txt record not found"
return 1 return 1
fi fi
_record_id="$(echo "$response" | _egrep_o "{[^{]*\"value\"*:*\"$txtvalue\"[^}]*}" | sed -n -e 's#.*"id": \([0-9]*\).*#\1#p')"
_record_id="$(echo "$response" | _egrep_o "\{[^\{]*\"value\"*:*\"$txtvalue\"[^\}]*\}" | sed -n -e 's#.*"id":\([0-9]*\).*#\1#p')"
_debug "_record_id" "$_record_id" _debug "_record_id" "$_record_id"
if [ -z "$_record_id" ]; then if [ -z "$_record_id" ]; then
_err "can not find _record_id" _err "can not find _record_id"
return 1 return 1
fi fi
if ! _rest POST "$_domain/entry_set/$_record_id/delete/" "apikey=$FORNEX_API_KEY"; then
if ! _rest DELETE "dns/domain/$_domain/entry_set/$_record_id/"; then
_err "Delete record error." _err "Delete record error."
return 1 return 1
fi fi
@ -97,11 +95,11 @@ _get_root() {
return 1 return 1
fi fi
if ! _rest GET "domain_list.json?q=$h&apikey=$FORNEX_API_KEY"; then
if ! _rest GET "dns/domain/"; then
return 1 return 1
fi fi
if _contains "$response" "\"$h\"" >/dev/null; then
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
_domain=$h _domain=$h
return 0 return 0
else else
@ -134,7 +132,9 @@ _rest() {
data="$3" data="$3"
_debug "$ep" _debug "$ep"
export _H1="Accept: application/json"
export _H1="Authorization: Api-Key $FORNEX_API_KEY"
export _H2="Content-Type: application/json"
export _H3="Accept: application/json"
if [ "$m" != "GET" ]; then if [ "$m" != "GET" ]; then
_debug data "$data" _debug data "$data"

14
dnsapi/dns_ionos_cloud.sh

@ -1,12 +1,14 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_ionos_cloud_info='IONOS Cloud DNS
Site: ionos.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_ionos_cloud
Options:
IONOS_TOKEN API Token.
Issues: github.com/acmesh-official/acme.sh/issues/5243
'
# Supports IONOS Cloud DNS API v1.15.4 # Supports IONOS Cloud DNS API v1.15.4
#
# Usage:
# Export IONOS_TOKEN before calling acme.sh:
# $ export IONOS_TOKEN="..."
#
# $ acme.sh --issue --dns dns_ionos_cloud ...
IONOS_CLOUD_API="https://dns.de-fra.ionos.com" IONOS_CLOUD_API="https://dns.de-fra.ionos.com"
IONOS_CLOUD_ROUTE_ZONES="/zones" IONOS_CLOUD_ROUTE_ZONES="/zones"

42
dnsapi/dns_linode_v4.sh

@ -76,7 +76,7 @@ dns_linode_v4_rm() {
_debug _sub_domain "$_sub_domain" _debug _sub_domain "$_sub_domain"
_debug _domain "$_domain" _debug _domain "$_domain"
if _rest GET "/$_domain_id/records" && [ -n "$response" ]; then
if _H4="X-Filter: { \"type\": \"TXT\", \"name\": \"$_sub_domain\" }" _rest GET "/$_domain_id/records" && [ -n "$response" ]; then
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
resource="$(echo "$response" | _egrep_o "\{.*\"name\": *\"$_sub_domain\".*}")" resource="$(echo "$response" | _egrep_o "\{.*\"name\": *\"$_sub_domain\".*}")"
@ -131,34 +131,42 @@ _Linode_API() {
# _domain=domain.com # _domain=domain.com
# _domain_id=12345 # _domain_id=12345
_get_root() { _get_root() {
domain=$1
full_host_str="$1"
i=2 i=2
p=1 p=1
while true; do
# loop through the received string (e.g. _acme-challenge.sub3.sub2.sub1.domain.tld),
# starting from the lowest subdomain, and check if it's a hosted domain
tst_hosted_domain=$(printf "%s" "$full_host_str" | cut -d . -f "$i"-100)
_debug tst_hosted_domain "$tst_hosted_domain"
if [ -z "$tst_hosted_domain" ]; then
#not valid
_err "Couldn't get domain from string '$full_host_str'."
return 1
fi
if _rest GET; then
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
while true; do
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
hostedzone="$(echo "$response" | _egrep_o "\{.*\"domain\": *\"$h\".*}")"
_debug "Querying Linode APIv4 for hosted zone: $tst_hosted_domain"
if _H4="X-Filter: {\"domain\":\"$tst_hosted_domain\"}" _rest GET; then
_debug "Got response from API: $response"
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
hostedzone="$(echo "$response" | _egrep_o "\{.*\"domain\": *\"$tst_hosted_domain\".*}")"
if [ "$hostedzone" ]; then if [ "$hostedzone" ]; then
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\": *[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\": *[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
_debug "Found domain hosted on Linode DNS. Zone: $tst_hosted_domain, id: $_domain_id"
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h
_sub_domain=$(printf "%s" "$full_host_str" | cut -d . -f 1-"$p")
_domain=$tst_hosted_domain
return 0 return 0
fi fi
return 1 return 1
fi fi
p=$i p=$i
i=$(_math "$i" + 1) i=$(_math "$i" + 1)
done
fi
fi
done
return 1 return 1
} }

20
dnsapi/dns_omglol.sh

@ -1,23 +1,19 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034 # shellcheck disable=SC2034
dns_myapi_info='omg.lol
Based on the omg.lol API, defined at https://api.omg.lol/
Domains: omg.lol
Site: github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_duckdns
dns_omglol_info='omg.lol
Site: omg.lol
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_omglol
Options: Options:
OMG_ApiKey API Key from omg.lol. This is accesible from the bottom of the account page at https://home.omg.lol/account
OMG_ApiKey API Key from omg.lol. This is accessible from the bottom of the account page at https://home.omg.lol/account
OMG_Address This is your omg.lol address, without the preceding @ - you can see your list on your dashboard at https://home.omg.lol/dashboard OMG_Address This is your omg.lol address, without the preceding @ - you can see your list on your dashboard at https://home.omg.lol/dashboard
Issues: github.com/acmesh-official/acme.sh
Issues: github.com/acmesh-official/acme.sh/issues/5299
Author: @Kholin <kholin+acme.omglolapi@omg.lol> Author: @Kholin <kholin+acme.omglolapi@omg.lol>
' '
#returns 0 means success, otherwise error.
# See API Docs https://api.omg.lol/
######## Public functions ##################### ######## Public functions #####################
# Please Read this guide first: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_omglol_add() { dns_omglol_add() {
fulldomain=$1 fulldomain=$1
@ -244,8 +240,8 @@ omg_delete() {
omg_validate_delete "$output" omg_validate_delete "$output"
} }
# Validate the response on request to delete. Confirm stastus is success and
# Message indicates deletion was successful
# Validate the response on request to delete.
# Confirm status is success and message indicates deletion was successful.
# Input: Response - HTTP response received from delete request # Input: Response - HTTP response received from delete request
omg_validate_delete() { omg_validate_delete() {
response=$1 response=$1

18
dnsapi/dns_pdns.sh

@ -20,6 +20,11 @@ dns_pdns_add() {
fulldomain=$1 fulldomain=$1
txtvalue=$2 txtvalue=$2
PDNS_Url="${PDNS_Url:-$(_readaccountconf_mutable PDNS_Url)}"
PDNS_ServerId="${PDNS_ServerId:-$(_readaccountconf_mutable PDNS_ServerId)}"
PDNS_Token="${PDNS_Token:-$(_readaccountconf_mutable PDNS_Token)}"
PDNS_Ttl="${PDNS_Ttl:-$(_readaccountconf_mutable PDNS_Ttl)}"
if [ -z "$PDNS_Url" ]; then if [ -z "$PDNS_Url" ]; then
PDNS_Url="" PDNS_Url=""
_err "You don't specify PowerDNS address." _err "You don't specify PowerDNS address."
@ -46,12 +51,12 @@ dns_pdns_add() {
fi fi
#save the api addr and key to the account conf file. #save the api addr and key to the account conf file.
_saveaccountconf PDNS_Url "$PDNS_Url"
_saveaccountconf PDNS_ServerId "$PDNS_ServerId"
_saveaccountconf PDNS_Token "$PDNS_Token"
_saveaccountconf_mutable PDNS_Url "$PDNS_Url"
_saveaccountconf_mutable PDNS_ServerId "$PDNS_ServerId"
_saveaccountconf_mutable PDNS_Token "$PDNS_Token"
if [ "$PDNS_Ttl" != "$DEFAULT_PDNS_TTL" ]; then if [ "$PDNS_Ttl" != "$DEFAULT_PDNS_TTL" ]; then
_saveaccountconf PDNS_Ttl "$PDNS_Ttl"
_saveaccountconf_mutable PDNS_Ttl "$PDNS_Ttl"
fi fi
_debug "Detect root zone" _debug "Detect root zone"
@ -73,6 +78,11 @@ dns_pdns_rm() {
fulldomain=$1 fulldomain=$1
txtvalue=$2 txtvalue=$2
PDNS_Url="${PDNS_Url:-$(_readaccountconf_mutable PDNS_Url)}"
PDNS_ServerId="${PDNS_ServerId:-$(_readaccountconf_mutable PDNS_ServerId)}"
PDNS_Token="${PDNS_Token:-$(_readaccountconf_mutable PDNS_Token)}"
PDNS_Ttl="${PDNS_Ttl:-$(_readaccountconf_mutable PDNS_Ttl)}"
if [ -z "$PDNS_Ttl" ]; then if [ -z "$PDNS_Ttl" ]; then
PDNS_Ttl="$DEFAULT_PDNS_TTL" PDNS_Ttl="$DEFAULT_PDNS_TTL"
fi fi

56
dnsapi/dns_technitium.sh

@ -0,0 +1,56 @@
#!/usr/bin/env sh
# shellcheck disable=SC2034
dns_Technitium_info='Technitium DNS Server
Site: https://technitium.com/dns/
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_technitium
Options:
Technitium_Server Server Address
Technitium_Token API Token
Issues:https://github.com/acmesh-official/acme.sh/issues/6116
Author: Henning Reich <acmesh@qupfer.de>
'
dns_technitium_add() {
_info "add txt Record using Technitium"
_Technitium_account
fulldomain=$1
txtvalue=$2
response="$(_get "$Technitium_Server/api/zones/records/add?token=$Technitium_Token&domain=$fulldomain&type=TXT&text=${txtvalue}")"
if _contains "$response" '"status":"ok"'; then
return 0
fi
_err "Could not add txt record."
return 1
}
dns_technitium_rm() {
_info "remove txt record using Technitium"
_Technitium_account
fulldomain=$1
txtvalue=$2
response="$(_get "$Technitium_Server/api/zones/records/delete?token=$Technitium_Token&domain=$fulldomain&type=TXT&text=${txtvalue}")"
if _contains "$response" '"status":"ok"'; then
return 0
fi
_err "Could not remove txt record"
return 1
}
#################### Private functions below ##################################
_Technitium_account() {
Technitium_Server="${Technitium_Server:-$(_readaccountconf_mutable Technitium_Server)}"
Technitium_Token="${Technitium_Token:-$(_readaccountconf_mutable Technitium_Token)}"
if [ -z "$Technitium_Server" ] || [ -z "$Technitium_Token" ]; then
Technitium_Server=""
Technitium_Token=""
_err "You don't specify Technitium Server and Token yet."
_err "Please create your Token and add server address and try again."
return 1
fi
#save the credentials to the account conf file.
_saveaccountconf_mutable Technitium_Server "$Technitium_Server"
_saveaccountconf_mutable Technitium_Token "$Technitium_Token"
}

21
dnsapi/dns_timeweb.sh

@ -1,16 +1,13 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# acme.sh DNS API for Timeweb Cloud provider (https://timeweb.cloud).
#
# Author: https://github.com/nikolaypronchev.
#
# Prerequisites:
# Timeweb Cloud API JWT token. Obtain one from the Timeweb Cloud control panel
# ("API and Terraform" section: https://timeweb.cloud/my/api-keys). The JWT token
# must be provided to this script in one of two ways:
# 1. As the "TW_Token" variable, for example: "export TW_Token=eyJhbG...zUxMiIs";
# 2. As a "TW_Token" config entry in acme.sh account config file
# (usually located at ~/.acme.sh/account.conf by default).
# shellcheck disable=SC2034
dns_timeweb_info='Timeweb.Cloud
Site: Timeweb.Cloud
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_timeweb
Options:
TW_Token API JWT token. Get it from the control panel at https://timeweb.cloud/my/api-keys
Issues: github.com/acmesh-official/acme.sh/issues/5140
Author: Nikolay Pronchev <https://github.com/nikolaypronchev>
'
TW_Api="https://api.timeweb.cloud/api/v1" TW_Api="https://api.timeweb.cloud/api/v1"

5
dnsapi/dns_world4you.sh

@ -115,7 +115,7 @@ dns_world4you_rm() {
_resethttp _resethttp
export ACME_HTTP_NO_REDIRECTS=1 export ACME_HTTP_NO_REDIRECTS=1
body="DeleteDnsRecordForm[recordId]=$recordid&DeleteDnsRecordForm[uniqueFormIdDP]=$formiddp&DeleteDnsRecordForm[_token]=$form_token"
body="DeleteDnsRecordForm[id]=$recordid&DeleteDnsRecordForm[uniqueFormIdDP]=$formiddp&DeleteDnsRecordForm[_token]=$form_token"
_info "Removing record..." _info "Removing record..."
ret=$(_post "$body" "$WORLD4YOU_API/$paketnr/dns/record/delete" '' POST 'application/x-www-form-urlencoded') ret=$(_post "$body" "$WORLD4YOU_API/$paketnr/dns/record/delete" '' POST 'application/x-www-form-urlencoded')
_resethttp _resethttp
@ -203,6 +203,7 @@ _get_paketnr() {
form="$2" form="$2"
domains=$(echo "$form" | grep '<ul class="nav header-paket-list">' | sed 's/<li/\n<li/g' | sed 's/<[^>]*>/ /g' | sed 's/^.*>\([^>]*\)$/\1/') domains=$(echo "$form" | grep '<ul class="nav header-paket-list">' | sed 's/<li/\n<li/g' | sed 's/<[^>]*>/ /g' | sed 's/^.*>\([^>]*\)$/\1/')
_debug domains "$domains"
domain='' domain=''
for domain in $domains; do for domain in $domains; do
if _contains "$fqdn" "$domain\$"; then if _contains "$fqdn" "$domain\$"; then
@ -217,7 +218,7 @@ _get_paketnr() {
TLD="$domain" TLD="$domain"
_debug domain "$domain" _debug domain "$domain"
RECORD=$(echo "$fqdn" | cut -c"1-$((${#fqdn} - ${#TLD} - 1))") RECORD=$(echo "$fqdn" | cut -c"1-$((${#fqdn} - ${#TLD} - 1))")
PAKETNR=$(echo "$domains" | grep "$domain" | sed 's/^[^,]*, *\([0-9]*\).*$/\1/')
PAKETNR=$(echo "$domains" | grep -o " $domain.*" | sed 's/^[^,]*, *\([0-9]*\).*$/\1/')
return 0 return 0
} }

145
dnsapi/dns_zoneedit.sh

@ -0,0 +1,145 @@
#!/usr/bin/env sh
# https://github.com/blueslow/sslcertzoneedit
# Only need to export the credentials once, acme.sh will save for automatic renewal.
# export ZONEEDIT_ID="Your id"
# export ZONEEDIT_Token="Your token"
# acme.sh --issue --dns dns_zoneedit -d example.com -d www.example.com
######## Public functions #####################
# Usage: dns_zoneedit_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_zoneedit_add() {
fulldomain=$1
txtvalue=$2
_info "Using Zoneedit"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
# Load the credentials from the account conf file
ZONEEDIT_ID="${ZONEEDIT_ID:-$(_readaccountconf_mutable ZONEEDIT_ID)}"
ZONEEDIT_Token="${ZONEEDIT_Token:-$(_readaccountconf_mutable ZONEEDIT_Token)}"
if [ -z "$ZONEEDIT_ID" ] || [ -z "$ZONEEDIT_Token" ]; then
ZONEEDIT_ID=""
ZONEEDIT_Token=""
_err "Please specify ZONEEDIT_ID and _Token."
_err "Please export as ZONEEDIT_ID and ZONEEDIT_Token then try again."
return 1
fi
# Save the credentials to the account conf file
_saveaccountconf_mutable ZONEEDIT_ID "$ZONEEDIT_ID"
_saveaccountconf_mutable ZONEEDIT_Token "$ZONEEDIT_Token"
if _zoneedit_api "CREATE" "$fulldomain" "$txtvalue"; then
_info "Added, OK"
return 0
else
_err "Add txt record error."
return 1
fi
}
# Usage: dns_zoneedit_rm fulldomain txtvalue
dns_zoneedit_rm() {
fulldomain=$1
txtvalue=$2
_info "Using Zoneedit"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
# Load the credentials from the account conf file
ZONEEDIT_ID="${ZONEEDIT_ID:-$(_readaccountconf_mutable ZONEEDIT_ID)}"
ZONEEDIT_Token="${ZONEEDIT_Token:-$(_readaccountconf_mutable ZONEEDIT_Token)}"
if [ -z "$ZONEEDIT_ID" ] || [ -z "$ZONEEDIT_Token" ]; then
ZONEEDIT_ID=""
ZONEEDIT_Token=""
_err "Please specify ZONEEDIT_ID and _Token."
_err "Please export as ZONEEDIT_ID and ZONEEDIT_Token then try again."
return 1
fi
if _zoneedit_api "DELETE" "$fulldomain" "$txtvalue"; then
_info "Deleted, OK"
return 0
else
_err "Delete txt record error."
return 1
fi
}
#################### Private functions below ##################################
#Usage: _zoneedit_api <CREATE|DELETE> fulldomain txtvalue
_zoneedit_api() {
cmd=$1
fulldomain=$2
txtvalue=$3
# Construct basic authorization header
credentials=$(printf "%s:%s" "$ZONEEDIT_ID" "$ZONEEDIT_Token" | _base64)
export _H1="Authorization: Basic ${credentials}"
# Generate request URL
case "$cmd" in
"CREATE")
# https://dynamic.zoneedit.com/txt-create.php?host=_acme-challenge.example.com&rdata=depE1VF_xshMm1IVY1Y56Kk9Zb_7jA2VFkP65WuNgu8W
geturl="https://dynamic.zoneedit.com/txt-create.php?host=${fulldomain}&rdata=${txtvalue}"
;;
"DELETE")
# https://dynamic.zoneedit.com/txt-delete.php?host=_acme-challenge.example.com&rdata=depE1VF_xshMm1IVY1Y56Kk9Zb_7jA2VFkP65WuNgu8W
geturl="https://dynamic.zoneedit.com/txt-delete.php?host=${fulldomain}&rdata=${txtvalue}"
ze_sleep=2
;;
*)
_err "Unknown parameter : $cmd"
return 1
;;
esac
# Execute request
i=3 # Tries
while [ "$i" -gt 0 ]; do
i=$(_math "$i" - 1)
if ! response=$(_get "$geturl"); then
_err "_get() failed ($response)"
return 1
fi
_debug2 response "$response"
if _contains "$response" "SUCCESS.*200"; then
# Sleep (when needed) to work around a Zonedit API bug
# https://forum.zoneedit.com/threads/automating-changes-of-txt-records-in-dns.7394/page-2#post-23855
if [ "$ze_sleep" ]; then _sleep "$ze_sleep"; fi
return 0
elif _contains "$response" "ERROR.*Minimum.*seconds"; then
_info "Zoneedit responded with a rate limit of..."
ze_ratelimit=$(echo "$response" | sed -n 's/.*Minimum \([0-9]\+\) seconds.*/\1/p')
if [ "$ze_ratelimit" ] && [ ! "$(echo "$ze_ratelimit" | tr -d '0-9')" ]; then
_info "$ze_ratelimit seconds."
else
_err "$response"
_err "not a number, or blank ($ze_ratelimit), API change?"
unset ze_ratelimit
fi
else
_err "$response"
_err "Unknown response, API change?"
fi
# Retry
if [ "$i" -lt 1 ]; then
_err "Tries exceeded, giving up."
return 1
fi
if [ "$ze_ratelimit" ]; then
_info "Waiting $ze_ratelimit seconds..."
_sleep "$ze_ratelimit"
else
_err "Going to retry after 10 seconds..."
_sleep 10
fi
done
return 1
}
Loading…
Cancel
Save