diff --git a/.github/workflows/DNS.yml b/.github/workflows/DNS.yml index 727ba315..be9d3aae 100644 --- a/.github/workflows/DNS.yml +++ b/.github/workflows/DNS.yml @@ -1,5 +1,6 @@ name: DNS on: + workflow_dispatch: push: paths: - 'dnsapi/*.sh' @@ -280,7 +281,7 @@ jobs: - uses: vmactions/openbsd-vm@v1 with: envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' - prepare: pkg_add socat curl + prepare: pkg_add socat curl libiconv usesh: true copyback: false run: | diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index ea446d84..435fd6b5 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -15,6 +15,8 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + DOCKER_IMAGE: neilpang/acme.sh jobs: CheckToken: @@ -44,6 +46,11 @@ jobs: uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v2 + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5.5.1 + with: + images: ${DOCKER_IMAGE} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: login to docker hub @@ -51,8 +58,6 @@ jobs: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin - name: build and push the image run: | - DOCKER_IMAGE=neilpang/acme.sh - if [[ $GITHUB_REF == refs/tags/* ]]; then DOCKER_IMAGE_TAG=${GITHUB_REF#refs/tags/} fi @@ -66,8 +71,14 @@ jobs: fi fi + DOCKER_LABELS=() + while read -r label; do + DOCKER_LABELS+=(--label "${label}") + done <<<"${DOCKER_METADATA_OUTPUT_LABELS}" + docker buildx build \ --tag ${DOCKER_IMAGE}:${DOCKER_IMAGE_TAG} \ + "${DOCKER_LABELS[@]}" \ --output "type=image,push=true" \ --build-arg AUTO_UPGRADE=${AUTO_UPGRADE} \ --platform linux/arm64/v8,linux/amd64,linux/arm/v6,linux/arm/v7,linux/386,linux/ppc64le,linux/s390x . diff --git a/.github/workflows/pr_dns.yml b/.github/workflows/pr_dns.yml index 4d7a325d..58630e8b 100644 --- a/.github/workflows/pr_dns.yml +++ b/.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. 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. + 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 ✨ 注意: 必须通过了 [DNS-API-Test](../wiki/DNS-API-Test) 才会被 review. 无论是修改, 还是新加的 dns api, 都必须确保通过这个测试. ` diff --git a/.github/workflows/pr_notify.yml b/.github/workflows/pr_notify.yml index 3b0e3e4b..b6b03c67 100644 --- a/.github/workflows/pr_notify.yml +++ b/.github/workflows/pr_notify.yml @@ -1,4 +1,4 @@ -name: Check dns api +name: Check notify api on: pull_request_target: diff --git a/acme.sh b/acme.sh index 4cf407f2..9842e3f1 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=3.0.8 +VER=3.1.0 PROJECT_NAME="acme.sh" @@ -672,8 +672,10 @@ _hex_dump() { #0 1 2 3 4 5 6 7 8 9 - _ . ~ #30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e +#_url_encode [upper-hex] the encoded hex will be upper-case if the argument upper-hex is followed #stdin stdout _url_encode() { + _upper_hex=$1 _hex_str=$(_hex_dump) _debug3 "_url_encode" _debug3 "_hex_str" "$_hex_str" @@ -883,6 +885,9 @@ _url_encode() { ;; #other hex *) + if [ "$_upper_hex" = "upper-hex" ]; then + _hex_code=$(printf "%s" "$_hex_code" | _upper_case) + fi printf '%%%s' "$_hex_code" ;; esac @@ -1437,7 +1442,7 @@ _toPkcs() { else ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" fi - if [ "$?" == "0" ]; then + if [ "$?" = "0" ]; then _savedomainconf "Le_PFXPassword" "$pfxPassword" fi @@ -1623,6 +1628,11 @@ _time2str() { return fi + #Omnios + if date -u -r "$1" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null; then + return + fi + #Solaris if printf "%(%Y-%m-%dT%H:%M:%SZ)T\n" $1 2>/dev/null; then return @@ -1806,7 +1816,11 @@ _date2time() { return fi #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 fi _err "Cannot parse _date2time $1" @@ -2188,7 +2202,6 @@ _send_signed_request() { _debug2 _headers "$_headers" _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" fi - _debug2 _CACHED_NONCE "$_CACHED_NONCE" if [ "$?" != "0" ]; then _err "Cannot connect to $nonceurl to get nonce." return 1 @@ -2361,7 +2374,7 @@ _clear_conf() { _sdkey="$2" if [ "$_c_c_f" ]; then _conf_data="$(cat "$_c_c_f")" - echo "$_conf_data" | sed "s/^$_sdkey *=.*$//" >"$_c_c_f" + echo "$_conf_data" | sed "/^$_sdkey *=.*$/d" >"$_c_c_f" else _err "Config file is empty, cannot clear" fi @@ -5111,6 +5124,19 @@ $_authorizations_map" _on_issue_err "$_post_hook" "$vlist" return 1 fi + _retryafter=$(echo "$responseHeaders" | grep -i "^Retry-After *: *[0-9]\+ *" | cut -d : -f 2 | tr -d ' ' | tr -d '\r') + _sleep_overload_retry_sec=$_retryafter + if [ "$_sleep_overload_retry_sec" ]; then + if [ $_sleep_overload_retry_sec -le 600 ]; then + _sleep $_sleep_overload_retry_sec + else + _info "The retryafter=$_retryafter value is too large (> 600), will not retry anymore." + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi + fi done done diff --git a/deploy/ali_cdn.sh b/deploy/ali_cdn.sh new file mode 100644 index 00000000..70a2e532 --- /dev/null +++ b/deploy/ali_cdn.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034,SC2154 + +# Script to create certificate to Alibaba Cloud CDN +# +# Docs: https://github.com/acmesh-official/acme.sh/wiki/deployhooks#33-deploy-your-certificate-to-cdn-or-dcdn-of-alibaba-cloud-aliyun +# +# This deployment required following variables +# export Ali_Key="ALIACCESSKEY" +# export Ali_Secret="ALISECRETKEY" +# The credentials are shared with all the Alibaba Cloud deploy hooks and dnsapi +# +# To specify the CDN domain that is different from the certificate CN, usually used for multi-domain or wildcard certificates +# export DEPLOY_ALI_CDN_DOMAIN="cdn.example.com" +# If you have multiple CDN domains using the same certificate, just +# export DEPLOY_ALI_CDN_DOMAIN="cdn1.example.com cdn2.example.com" +# +# For DCDN, see ali_dcdn deploy hook + +Ali_CDN_API="https://cdn.aliyuncs.com/" + +ali_cdn_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + # Load dnsapi/dns_ali.sh to reduce the duplicated codes + # https://github.com/acmesh-official/acme.sh/pull/5205#issuecomment-2357867276 + dnsapi_ali="$(_findHook "$_cdomain" "$_SUB_FOLDER_DNSAPI" dns_ali)" + # shellcheck source=/dev/null + if ! . "$dnsapi_ali"; then + _err "Error loading file $dnsapi_ali. Please check your API file and try again." + return 1 + fi + + _prepare_ali_credentials || return 1 + + _getdeployconf DEPLOY_ALI_CDN_DOMAIN + if [ "$DEPLOY_ALI_CDN_DOMAIN" ]; then + _savedeployconf DEPLOY_ALI_CDN_DOMAIN "$DEPLOY_ALI_CDN_DOMAIN" + else + DEPLOY_ALI_CDN_DOMAIN="$_cdomain" + fi + + # read cert and key files and urlencode both + _cert=$(_url_encode upper-hex <"$_cfullchain") + _key=$(_url_encode upper-hex <"$_ckey") + + _debug2 _cert "$_cert" + _debug2 _key "$_key" + + ## update domain ssl config + for domain in $DEPLOY_ALI_CDN_DOMAIN; do + _set_cdn_domain_ssl_certificate_query "$domain" "$_cert" "$_key" + if _ali_rest "Set CDN domain SSL certificate for $domain" "" POST; then + _info "Domain $domain certificate has been deployed successfully" + fi + done + + return 0 +} + +# domain pub pri +_set_cdn_domain_ssl_certificate_query() { + endpoint=$Ali_CDN_API + query='' + query=$query'AccessKeyId='$Ali_Key + query=$query'&Action=SetCdnDomainSSLCertificate' + query=$query'&CertType=upload' + query=$query'&DomainName='$1 + query=$query'&Format=json' + query=$query'&SSLPri='$3 + query=$query'&SSLProtocol=on' + query=$query'&SSLPub='$2 + query=$query'&SignatureMethod=HMAC-SHA1' + query=$query"&SignatureNonce=$(_ali_nonce)" + query=$query'&SignatureVersion=1.0' + query=$query'&Timestamp='$(_timestamp) + query=$query'&Version=2018-05-10' +} diff --git a/deploy/ali_dcdn.sh b/deploy/ali_dcdn.sh new file mode 100644 index 00000000..14ac500a --- /dev/null +++ b/deploy/ali_dcdn.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034,SC2154 + +# Script to create certificate to Alibaba Cloud DCDN +# +# Docs: https://github.com/acmesh-official/acme.sh/wiki/deployhooks#33-deploy-your-certificate-to-cdn-or-dcdn-of-alibaba-cloud-aliyun +# +# This deployment required following variables +# export Ali_Key="ALIACCESSKEY" +# export Ali_Secret="ALISECRETKEY" +# The credentials are shared with all the Alibaba Cloud deploy hooks and dnsapi +# +# To specify the DCDN domain that is different from the certificate CN, usually used for multi-domain or wildcard certificates +# export DEPLOY_ALI_DCDN_DOMAIN="dcdn.example.com" +# If you have multiple CDN domains using the same certificate, just +# export DEPLOY_ALI_DCDN_DOMAIN="dcdn1.example.com dcdn2.example.com" +# +# For regular CDN, see ali_cdn deploy hook + +Ali_DCDN_API="https://dcdn.aliyuncs.com/" + +ali_dcdn_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + # Load dnsapi/dns_ali.sh to reduce the duplicated codes + # https://github.com/acmesh-official/acme.sh/pull/5205#issuecomment-2357867276 + dnsapi_ali="$(_findHook "$_cdomain" "$_SUB_FOLDER_DNSAPI" dns_ali)" + # shellcheck source=/dev/null + if ! . "$dnsapi_ali"; then + _err "Error loading file $dnsapi_ali. Please check your API file and try again." + return 1 + fi + + _prepare_ali_credentials || return 1 + + _getdeployconf DEPLOY_ALI_DCDN_DOMAIN + if [ "$DEPLOY_ALI_DCDN_DOMAIN" ]; then + _savedeployconf DEPLOY_ALI_DCDN_DOMAIN "$DEPLOY_ALI_DCDN_DOMAIN" + else + DEPLOY_ALI_DCDN_DOMAIN="$_cdomain" + fi + + # read cert and key files and urlencode both + _cert=$(_url_encode upper-hex <"$_cfullchain") + _key=$(_url_encode upper-hex <"$_ckey") + + _debug2 _cert "$_cert" + _debug2 _key "$_key" + + ## update domain ssl config + for domain in $DEPLOY_ALI_DCDN_DOMAIN; do + _set_dcdn_domain_ssl_certificate_query "$domain" "$_cert" "$_key" + if _ali_rest "Set DCDN domain SSL certificate for $domain" "" POST; then + _info "Domain $domain certificate has been deployed successfully" + fi + done + + return 0 +} + +# domain pub pri +_set_dcdn_domain_ssl_certificate_query() { + endpoint=$Ali_DCDN_API + query='' + query=$query'AccessKeyId='$Ali_Key + query=$query'&Action=SetDcdnDomainSSLCertificate' + query=$query'&CertType=upload' + query=$query'&DomainName='$1 + query=$query'&Format=json' + query=$query'&SSLPri='$3 + query=$query'&SSLProtocol=on' + query=$query'&SSLPub='$2 + query=$query'&SignatureMethod=HMAC-SHA1' + query=$query"&SignatureNonce=$(_ali_nonce)" + query=$query'&SignatureVersion=1.0' + query=$query'&Timestamp='$(_timestamp) + query=$query'&Version=2018-01-15' +} diff --git a/deploy/exim4.sh b/deploy/exim4.sh index 260b8798..cf664d79 100644 --- a/deploy/exim4.sh +++ b/deploy/exim4.sh @@ -109,6 +109,5 @@ exim4_deploy() { fi return 1 fi - return 0 } diff --git a/deploy/ruckus.sh b/deploy/ruckus.sh new file mode 100755 index 00000000..f62e2fc0 --- /dev/null +++ b/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 +# +# ```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='' + _post "$_replace_cert_ajax" "$_base_url/_cmdstat.jsp" >/dev/null + + _info "Rebooting" + _cert_reboot_ajax='' + _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 +} diff --git a/deploy/strongswan.sh b/deploy/strongswan.sh index 3d5f1b34..14567d17 100644 --- a/deploy/strongswan.sh +++ b/deploy/strongswan.sh @@ -10,46 +10,89 @@ #domain keyfile certfile cafile fullchain 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" - - 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 swanctl is detected" return 1 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 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 } diff --git a/deploy/synology_dsm.sh b/deploy/synology_dsm.sh index 3ddb8de1..0d01e199 100644 --- a/deploy/synology_dsm.sh +++ b/deploy/synology_dsm.sh @@ -113,9 +113,9 @@ synology_dsm_deploy() { # Default values for scheme, hostname and port # Defaulting to localhost and http, because it's localhost… - [ -n "$SYNO_SCHEME" ] || SYNO_SCHEME="http" - [ -n "$SYNO_HOSTNAME" ] || SYNO_HOSTNAME="localhost" - [ -n "$SYNO_PORT" ] || SYNO_PORT="5000" + [ -n "$SYNO_SCHEME" ] || SYNO_SCHEME=http + [ -n "$SYNO_HOSTNAME" ] || SYNO_HOSTNAME=localhost + [ -n "$SYNO_PORT" ] || SYNO_PORT=5000 _savedeployconf SYNO_SCHEME "$SYNO_SCHEME" _savedeployconf SYNO_HOSTNAME "$SYNO_HOSTNAME" _savedeployconf SYNO_PORT "$SYNO_PORT" diff --git a/deploy/truenas.sh b/deploy/truenas.sh index c79e6dac..407395a3 100644 --- a/deploy/truenas.sh +++ b/deploy/truenas.sh @@ -9,7 +9,7 @@ # # Following environment variables must be set: # -# export DEPLOY_TRUENAS_APIKEY="/dev/null 2>&1 # fail quietly if we're not running as root + fi + + # Update unifi service for certificate cipher compatibility + if ${ACME_OPENSSL_BIN:-openssl} pkcs12 \ + -in "$_import_pkcs12" \ + -password pass:aircontrolenterprise \ + -nokeys | ${ACME_OPENSSL_BIN:-openssl} x509 -text \ + -noout | grep -i "signature" | grep -iq ecdsa >/dev/null 2>&1; then + if [ -f "$(dirname "${DEPLOY_UNIFI_KEYSTORE}")/system.properties" ]; then + _unifi_system_properties="$(dirname "${DEPLOY_UNIFI_KEYSTORE}")/system.properties" + else + _unifi_system_properties="/usr/lib/unifi/data/system.properties" + fi + if [ -f "${_unifi_system_properties}" ]; then + cp -f "${_unifi_system_properties}" "${_unifi_system_properties}"_original + _info "Updating system configuration for cipher compatibility." + _info "Saved original system config to ${_unifi_system_properties}_original" + sed -i '/unifi\.https\.ciphers/d' "${_unifi_system_properties}" + echo "unifi.https.ciphers=ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES128-GCM-SHA256" >>"${_unifi_system_properties}" + sed -i '/unifi\.https\.sslEnabledProtocols/d' "${_unifi_system_properties}" + echo "unifi.https.sslEnabledProtocols=TLSv1.3,TLSv1.2" >>"${_unifi_system_properties}" + _info "System configuration updated." + fi + fi + + rm "$_import_pkcs12" + + # Restarting unifi-core will bring up unifi, doing it out of order results in + # a certificate error, and breaks wifiman. + # Restart if we aren't doing unifi-core, otherwise stop for later restart. if systemctl -q is-active unifi; then - _reload_cmd="${_reload_cmd:+$_reload_cmd && }service unifi restart" + if [ ! -f "${DEPLOY_UNIFI_CORE_CONFIG:-/data/unifi-core/config}/unifi-core.key" ]; then + _reload_cmd="${_reload_cmd:+$_reload_cmd && }systemctl restart unifi" + else + _reload_cmd="${_reload_cmd:+$_reload_cmd && }systemctl stop unifi" + fi fi _services_updated="${_services_updated} unifi" _info "Install Unifi Controller certificate success!" @@ -165,6 +228,11 @@ unifi_deploy() { return 1 fi + # Save the existing certs in case something goes wrong. + cp -f "${_unifi_core_config}"/unifi-core.crt "${_unifi_core_config}"/unifi-core_original.crt + cp -f "${_unifi_core_config}"/unifi-core.key "${_unifi_core_config}"/unifi-core_original.key + _info "Previous certificate and key saved to ${_unifi_core_config}/unifi-core_original.crt/key." + cat "$_cfullchain" >"${_unifi_core_config}/unifi-core.crt" cat "$_ckey" >"${_unifi_core_config}/unifi-core.key" diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh index 8cf24e4f..570495cc 100644 --- a/deploy/vsftpd.sh +++ b/deploy/vsftpd.sh @@ -106,5 +106,5 @@ vsftpd_deploy() { fi return 1 fi - return 0 + } diff --git a/dnsapi/dns_active24.sh b/dnsapi/dns_active24.sh index 1a6f97f0..c56dd363 100755 --- a/dnsapi/dns_active24.sh +++ b/dnsapi/dns_active24.sh @@ -83,10 +83,10 @@ _get_root() { return 1 fi - i=2 + i=1 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug "h" "$h" if [ -z "$h" ]; then #not valid @@ -94,7 +94,7 @@ _get_root() { fi if _contains "$response" "\"$h\"" >/dev/null; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index ccd8226f..850af5b4 100755 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -95,7 +95,7 @@ _get_root() { if _ad_rest GET "domain/"; then response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -106,7 +106,7 @@ _get_root() { if [ "$hostedzone" ]; then _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh index 9bdfc20b..53a82f91 100755 --- a/dnsapi/dns_ali.sh +++ b/dnsapi/dns_ali.sh @@ -9,25 +9,19 @@ Options: Ali_Secret API Secret ' -Ali_API="https://alidns.aliyuncs.com/" +# NOTICE: +# This file is referenced by Alibaba Cloud Services deploy hooks +# https://github.com/acmesh-official/acme.sh/pull/5205#issuecomment-2357867276 +# Be careful when modifying this file, especially when making breaking changes for common functions + +Ali_DNS_API="https://alidns.aliyuncs.com/" #Usage: dns_ali_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_ali_add() { fulldomain=$1 txtvalue=$2 - Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}" - Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}" - if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then - Ali_Key="" - Ali_Secret="" - _err "You don't specify aliyun api key and secret yet." - return 1 - fi - - #save the api key and secret to the account conf file. - _saveaccountconf_mutable Ali_Key "$Ali_Key" - _saveaccountconf_mutable Ali_Secret "$Ali_Secret" + _prepare_ali_credentials || return 1 _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -52,14 +46,74 @@ dns_ali_rm() { _clean } -#################### Private functions below ################################## +#################### Alibaba Cloud common functions below #################### + +_prepare_ali_credentials() { + Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}" + Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}" + if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then + Ali_Key="" + Ali_Secret="" + _err "You don't specify aliyun api key and secret yet." + return 1 + fi + + #save the api key and secret to the account conf file. + _saveaccountconf_mutable Ali_Key "$Ali_Key" + _saveaccountconf_mutable Ali_Secret "$Ali_Secret" +} + +# act ign mtd +_ali_rest() { + act="$1" + ign="$2" + mtd="${3:-GET}" + + signature=$(printf "%s" "$mtd&%2F&$(printf "%s" "$query" | _url_encode upper-hex)" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64) + signature=$(printf "%s" "$signature" | _url_encode upper-hex) + url="$endpoint?Signature=$signature" + + if [ "$mtd" = "GET" ]; then + url="$url&$query" + response="$(_get "$url")" + else + response="$(_post "$query" "$url" "" "$mtd" "application/x-www-form-urlencoded")" + fi + + _ret="$?" + _debug2 response "$response" + if [ "$_ret" != "0" ]; then + _err "Error <$act>" + return 1 + fi + + if [ -z "$ign" ]; then + message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" + if [ "$message" ]; then + _err "$message" + return 1 + fi + fi +} + +_ali_nonce() { + #_head_n 1 " - return 1 - fi - - _debug2 response "$response" - if [ -z "$2" ]; then - message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" - if [ "$message" ]; then - _err "$message" - return 1 - fi - fi -} - -_ali_urlencode() { - _str="$1" - _str_len=${#_str} - _u_i=1 - while [ "$_u_i" -le "$_str_len" ]; do - _str_c="$(printf "%s" "$_str" | cut -c "$_u_i")" - case $_str_c in [a-zA-Z0-9.~_-]) - printf "%s" "$_str_c" - ;; - *) - printf "%%%02X" "'$_str_c" - ;; - esac - _u_i="$(_math "$_u_i" + 1)" - done -} - -_ali_nonce() { - #_head_n 1 1" >/dev/null; then _zone="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" _system_ns="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") return 0 fi diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index c599b4e0..c88c9d9c 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -158,7 +158,7 @@ _get_root() { # iterate over names (a.b.c.d -> b.c.d -> c.d -> d) while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100 | sed 's/\./\\./g') + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100 | sed 's/\./\\./g') _debug "Checking domain: $h" if [ -z "$h" ]; then _error "invalid domain" @@ -174,7 +174,7 @@ _get_root() { if [ "$hostedzone" ]; then _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_azion.sh b/dnsapi/dns_azion.sh index 2371833e..1375e32f 100644 --- a/dnsapi/dns_azion.sh +++ b/dnsapi/dns_azion.sh @@ -100,7 +100,7 @@ _get_root() { fi while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then # not valid @@ -111,7 +111,7 @@ _get_root() { _domain_id=$(echo "$response" | tr '{' "\n" | grep "\"domain\":\"$h\"" | _egrep_o "\"id\":[0-9]*" | _head_n 1 | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 00ccd798..3f0dfa3d 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -9,14 +9,17 @@ Options: AZUREDNS_APPID App ID. App ID of 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_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 + ######## Public functions ##################### # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" # Used to add txt record # -# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate +# Ref: https://learn.microsoft.com/en-us/rest/api/dns/record-sets/create-or-update?view=rest-dns-2018-05-01&tabs=HTTP # dns_azure_add() { @@ -29,6 +32,7 @@ dns_azure_add() { AZUREDNS_TENANTID="" AZUREDNS_APPID="" AZUREDNS_CLIENTSECRET="" + AZUREDNS_BEARERTOKEN="" _err "You didn't specify the Azure Subscription ID" return 1 fi @@ -43,37 +47,45 @@ dns_azure_add() { _saveaccountconf_mutable AZUREDNS_TENANTID "" _saveaccountconf_mutable AZUREDNS_APPID "" _saveaccountconf_mutable AZUREDNS_CLIENTSECRET "" + _saveaccountconf_mutable AZUREDNS_BEARERTOKEN "" 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_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" 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 #save account details to account conf file, don't opt in for azure manages identity check. @@ -81,9 +93,14 @@ dns_azure_add() { _saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID" _saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID" _saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET" + _saveaccountconf_mutable AZUREDNS_BEARERTOKEN "$AZUREDNS_BEARERTOKEN" 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 _err "invalid domain" @@ -133,7 +150,7 @@ dns_azure_add() { # Usage: fulldomain txtvalue # Used to remove the txt record after validation # -# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/delete +# Ref: https://learn.microsoft.com/en-us/rest/api/dns/record-sets/delete?view=rest-dns-2018-05-01&tabs=HTTP # dns_azure_rm() { fulldomain=$1 @@ -145,6 +162,7 @@ dns_azure_rm() { AZUREDNS_TENANTID="" AZUREDNS_APPID="" AZUREDNS_CLIENTSECRET="" + AZUREDNS_BEARERTOKEN="" _err "You didn't specify the Azure Subscription ID " return 1 fi @@ -153,40 +171,51 @@ dns_azure_rm() { if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then _info "Using Azure managed identity" 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_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" 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 - 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 _err "invalid domain" @@ -265,10 +294,10 @@ _azure_rest() { if [ "$_code" = "401" ]; then # we have an invalid access token set to expired _saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "0" - _err "access denied make sure your Azure settings are correct. See $WIKI" + _err "Access denied. Invalid access token. Make sure your Azure settings are correct. See: $wiki" return 1 fi - # See https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes + # See https://learn.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes if [ "$_ret" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then _request_retry_times="$(_math "$_request_retry_times" + 1)" _info "REST call error $_code retrying $ep in $_request_retry_times s" @@ -286,14 +315,14 @@ _azure_rest() { return 0 } -## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token +## Ref: https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow#request-an-access-token _azure_getaccess_token() { managedIdentity=$1 tenantID=$2 clientID=$3 clientSecret=$4 - accesstoken="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}" + accesstoken="${AZUREDNS_ACCESSTOKEN:-$(_readaccountconf_mutable AZUREDNS_ACCESSTOKEN)}" expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}" # can we reuse the bearer token? @@ -310,7 +339,7 @@ _azure_getaccess_token() { _debug "getting new bearer token" if [ "$managedIdentity" = true ]; then - # https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http + # https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http export _H1="Metadata: true" response="$(_get http://169.254.169.254/metadata/identity/oauth2/token\?api-version=2018-02-01\&resource=https://management.azure.com/)" response="$(echo "$response" | _normalizeJson)" @@ -330,14 +359,14 @@ _azure_getaccess_token() { fi if [ -z "$accesstoken" ]; then - _err "no acccess token received. Check your Azure settings see $WIKI" + _err "No acccess token received. Check your Azure settings. See: $wiki" return 1 fi if [ "$_ret" != "0" ]; then _err "error $response" return 1 fi - _saveaccountconf_mutable AZUREDNS_BEARERTOKEN "$accesstoken" + _saveaccountconf_mutable AZUREDNS_ACCESSTOKEN "$accesstoken" _saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "$expires_on" printf "%s" "$accesstoken" return 0 @@ -350,15 +379,18 @@ _get_root() { i=1 p=1 - ## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list - ## returns up to 100 zones in one response therefore handling more results is not not implemented - ## (ZoneListResult with continuation token for the next page of results) - ## Per https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#dns-limits you are limited to 100 Zone/subscriptions anyways + ## Ref: https://learn.microsoft.com/en-us/rest/api/dns/zones/list?view=rest-dns-2018-05-01&tabs=HTTP + ## returns up to 100 zones in one response. Handling more results is not implemented + ## (ZoneListResult with continuation token for the next page of results) + ## + ## TODO: handle more than 100 results, as per: + ## https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#azure-dns-limits + ## The new limit is 250 Public DNS zones per subscription, while the old limit was only 100 ## _azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?\$top=500&api-version=2017-09-01" "" "$accesstoken" # Find matching domain name in Json response while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug2 "Checking domain: $h" if [ -z "$h" ]; then #not valid @@ -373,7 +405,7 @@ _get_root() { #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) + _sub_domain=$(echo "$domain" | cut -d . -f 1-"$p") fi _domain=$h return 0 diff --git a/dnsapi/dns_bunny.sh b/dnsapi/dns_bunny.sh index 681f748a..780198e1 100644 --- a/dnsapi/dns_bunny.sh +++ b/dnsapi/dns_bunny.sh @@ -196,7 +196,7 @@ _get_base_domain() { _debug2 domain_list "$domain_list" i=1 - while [ $i -gt 0 ]; do + while [ "$i" -gt 0 ]; do ## get next longest domain _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM") ## check we got something back from our cut (or are we at the end) @@ -208,7 +208,7 @@ _get_base_domain() { ## check if it exists if [ -n "$found" ]; then ## exists - exit loop returning the parts - sub_point=$(_math $i - 1) + sub_point=$(_math "$i" - 1) _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point") _domain_id="$(echo "$found" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")" _debug _domain_id "$_domain_id" @@ -218,11 +218,11 @@ _get_base_domain() { return 0 fi ## increment cut point $i - i=$(_math $i + 1) + i=$(_math "$i" + 1) done if [ -z "$found" ]; then - page=$(_math $page + 1) + page=$(_math "$page" + 1) nextpage="https://api.bunny.net/dnszone?page=$page" ## Find the next page if we don't have a match. hasnextpage="$(echo "$domain_list" | _egrep_o "\"HasMoreItems\"\s*:\s*true")" diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index da63e771..736742f3 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -186,7 +186,7 @@ _get_root() { fi while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -206,7 +206,7 @@ _get_root() { if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_count":1'; then _domain_id=$(echo "$response" | _egrep_o "\[.\"id\": *\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \" | tr -d " ") if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 145a85be..8bb0e00d 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -164,7 +164,7 @@ _dns_cloudns_get_zone_info() { _dns_cloudns_get_zone_name() { i=2 while true; do - zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) + zoneForCheck=$(printf "%s" "$1" | cut -d . -f "$i"-100) if [ -z "$zoneForCheck" ]; then return 1 diff --git a/dnsapi/dns_cn.sh b/dnsapi/dns_cn.sh index 797f788e..79698e88 100644 --- a/dnsapi/dns_cn.sh +++ b/dnsapi/dns_cn.sh @@ -131,7 +131,7 @@ _cn_get_root() { p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" _debug _H1 "${_H1}" @@ -149,7 +149,7 @@ _cn_get_root() { fi if _contains "$_cn_zonelist" "\"name\":\"$h\"" >/dev/null; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 else diff --git a/dnsapi/dns_conoha.sh b/dnsapi/dns_conoha.sh index 6ceca829..ecd56fc8 100755 --- a/dnsapi/dns_conoha.sh +++ b/dnsapi/dns_conoha.sh @@ -237,7 +237,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100). + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100). _debug h "$h" if [ -z "$h" ]; then #not valid @@ -251,7 +251,7 @@ _get_root() { if _contains "$response" "\"name\":\"$h\"" >/dev/null; then _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_constellix.sh b/dnsapi/dns_constellix.sh index 0376dda1..6a50e199 100644 --- a/dnsapi/dns_constellix.sh +++ b/dnsapi/dns_constellix.sh @@ -122,7 +122,7 @@ _get_root() { p=1 _debug "Detecting root zone" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then return 1 fi @@ -134,7 +134,7 @@ _get_root() { if _contains "$response" "\"name\":\"$h\""; then _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]*" | cut -d ':' -f 2) if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d '.' -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d '.' -f 1-"$p") _domain="$h" _debug _domain_id "$_domain_id" diff --git a/dnsapi/dns_curanet.sh b/dnsapi/dns_curanet.sh index a530d304..f57afa1f 100644 --- a/dnsapi/dns_curanet.sh +++ b/dnsapi/dns_curanet.sh @@ -142,7 +142,7 @@ _get_root() { i=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid diff --git a/dnsapi/dns_da.sh b/dnsapi/dns_da.sh index b2789a6f..36251b05 100755 --- a/dnsapi/dns_da.sh +++ b/dnsapi/dns_da.sh @@ -61,7 +61,7 @@ _get_root() { # response will contain "list[]=example.com&list[]=example.org" _da_api CMD_API_SHOW_DOMAINS "" "${domain}" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then # not valid @@ -69,7 +69,7 @@ _get_root() { return 1 fi if _contains "$response" "$h" >/dev/null; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_desec.sh b/dnsapi/dns_desec.sh index 0d6a6c2f..d6b9c355 100644 --- a/dnsapi/dns_desec.sh +++ b/dnsapi/dns_desec.sh @@ -176,7 +176,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -188,7 +188,7 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\"" >/dev/null; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_dgon.sh b/dnsapi/dns_dgon.sh index 9aaa9606..cb887cfa 100755 --- a/dnsapi/dns_dgon.sh +++ b/dnsapi/dns_dgon.sh @@ -203,7 +203,7 @@ _get_base_domain() { _debug2 domain_list "$domain_list" i=1 - while [ $i -gt 0 ]; do + while [ "$i" -gt 0 ]; do ## get next longest domain _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM") ## check we got something back from our cut (or are we at the end) @@ -215,14 +215,14 @@ _get_base_domain() { ## check if it exists if [ -n "$found" ]; then ## exists - exit loop returning the parts - sub_point=$(_math $i - 1) + sub_point=$(_math "$i" - 1) _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point") _debug _domain "$_domain" _debug _sub_domain "$_sub_domain" return 0 fi ## increment cut point $i - i=$(_math $i + 1) + i=$(_math "$i" + 1) done if [ -z "$found" ]; then diff --git a/dnsapi/dns_dnsexit.sh b/dnsapi/dns_dnsexit.sh index 9f2871b4..ec3b07a4 100644 --- a/dnsapi/dns_dnsexit.sh +++ b/dnsapi/dns_dnsexit.sh @@ -84,7 +84,7 @@ _get_root() { domain=$1 i=1 while true; do - _domain=$(printf "%s" "$domain" | cut -d . -f $i-100) + _domain=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$_domain" if [ -z "$_domain" ]; then return 1 diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index e080ecf0..10a3821d 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -92,7 +92,7 @@ _get_root() { i=2 previous=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then # not valid return 1 @@ -105,7 +105,7 @@ _get_root() { if _contains "$response" 'not found'; then _debug "$h not found" else - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$previous) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$previous") _domain="$h" _debug _domain "$_domain" diff --git a/dnsapi/dns_doapi.sh b/dnsapi/dns_doapi.sh index 9bc6a4a4..0804f2e6 100755 --- a/dnsapi/dns_doapi.sh +++ b/dnsapi/dns_doapi.sh @@ -2,7 +2,6 @@ # shellcheck disable=SC2034 dns_doapi_info='Domain-Offensive do.de Official LetsEncrypt API for do.de / Domain-Offensive. - This is different from the dns_do adapter, because dns_do is only usable for enterprise customers. This API is also available to private customers/individuals. Site: do.de Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_doapi @@ -11,7 +10,7 @@ Options: Issues: github.com/acmesh-official/acme.sh/issues/2057 ' -DO_API="https://www.do.de/api/letsencrypt" +DO_API="https://my.do.de/api/letsencrypt" ######## Public functions ##################### diff --git a/dnsapi/dns_domeneshop.sh b/dnsapi/dns_domeneshop.sh index 16d3dbe5..925ca335 100644 --- a/dnsapi/dns_domeneshop.sh +++ b/dnsapi/dns_domeneshop.sh @@ -93,7 +93,7 @@ _get_domainid() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug "h" "$h" if [ -z "$h" ]; then #not valid @@ -102,7 +102,7 @@ _get_domainid() { if _contains "$response" "\"$h\"" >/dev/null; then # We have found the domain name. - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h _domainid=$(printf "%s" "$response" | _egrep_o "[^{]*\"domain\":\"$_domain\"[^}]*" | _egrep_o "\"id\":[0-9]+" | cut -d : -f 2) return 0 diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 29d32c27..7bc331e2 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -109,7 +109,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 @@ -123,7 +123,7 @@ _get_root() { _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _debug _sub_domain "$_sub_domain" _domain="$h" _debug _domain "$_domain" diff --git a/dnsapi/dns_dpi.sh b/dnsapi/dns_dpi.sh index 521f2d69..e8b9b5a5 100755 --- a/dnsapi/dns_dpi.sh +++ b/dnsapi/dns_dpi.sh @@ -109,7 +109,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 @@ -123,7 +123,7 @@ _get_root() { _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _debug _sub_domain "$_sub_domain" _domain="$h" _debug _domain "$_domain" diff --git a/dnsapi/dns_durabledns.sh b/dnsapi/dns_durabledns.sh index cd4bd2eb..d71f0ccb 100644 --- a/dnsapi/dns_durabledns.sh +++ b/dnsapi/dns_durabledns.sh @@ -110,7 +110,7 @@ _get_root() { i=1 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -118,7 +118,7 @@ _get_root() { fi if _contains "$response" ">$h."; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 0dbeda24..1d1fc311 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -126,7 +126,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -140,7 +140,7 @@ _get_root() { if _contains "$response" "\"domainName\":\"$h\"" >/dev/null; then dnsId=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 2 | cut -d : -f 2) _domain_name=$h - _node=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _node=$(printf "%s" "$domain" | cut -d . -f 1-"$p") return 0 fi p=$i diff --git a/dnsapi/dns_dynv6.sh b/dnsapi/dns_dynv6.sh index 8b94dae7..76af17f5 100644 --- a/dnsapi/dns_dynv6.sh +++ b/dnsapi/dns_dynv6.sh @@ -16,8 +16,8 @@ dynv6_api="https://dynv6.com/api/v2" # Please Read this guide first: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide #Usage: dns_dynv6_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_dynv6_add() { - fulldomain=$1 - txtvalue=$2 + fulldomain="$(echo "$1" | _lower_case)" + txtvalue="$2" _info "Using dynv6 api" _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" @@ -43,15 +43,14 @@ dns_dynv6_add() { _err "Something went wrong! it does not seem like the record was added successfully" return 1 fi - return 1 fi - return 1 + } #Usage: fulldomain txtvalue #Remove the txt record after validation. dns_dynv6_rm() { - fulldomain=$1 - txtvalue=$2 + fulldomain="$(echo "$1" | _lower_case)" + txtvalue="$2" _info "Using dynv6 API" _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" @@ -206,7 +205,7 @@ _get_zone_id() { return 1 fi - zone_id="$(echo "$response" | tr '}' '\n' | grep "$selected" | tr ',' '\n' | grep id | tr -d '"')" + zone_id="$(echo "$response" | tr '}' '\n' | grep "$selected" | tr ',' '\n' | grep '"id":' | tr -d '"')" _zone_id="${zone_id#id:}" _debug "zone id: $_zone_id" } diff --git a/dnsapi/dns_easydns.sh b/dnsapi/dns_easydns.sh index d168054a..1c96ac8f 100644 --- a/dnsapi/dns_easydns.sh +++ b/dnsapi/dns_easydns.sh @@ -121,7 +121,7 @@ _get_root() { i=1 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -133,7 +133,7 @@ _get_root() { fi if _contains "$response" "\"status\":200"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_euserv.sh b/dnsapi/dns_euserv.sh index 2da00c3d..744f6ca6 100644 --- a/dnsapi/dns_euserv.sh +++ b/dnsapi/dns_euserv.sh @@ -151,7 +151,7 @@ _get_root() { response="$_euserv_domain_orders" while true; do - h=$(echo "$domain" | cut -d . -f $i-100) + h=$(echo "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -159,7 +159,7 @@ _get_root() { fi if _contains "$response" "$h"; then - _sub_domain=$(echo "$domain" | cut -d . -f 1-$p) + _sub_domain=$(echo "$domain" | cut -d . -f 1-"$p") _domain="$h" if ! _euserv_get_domain_id "$_domain"; then _err "invalid domain" diff --git a/dnsapi/dns_exoscale.sh b/dnsapi/dns_exoscale.sh index 4cc5a513..6898ce38 100755 --- a/dnsapi/dns_exoscale.sh +++ b/dnsapi/dns_exoscale.sh @@ -119,7 +119,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -130,7 +130,7 @@ _get_root() { _domain_id=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \") _domain_token=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") if [ "$_domain_token" ] && [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_fornex.sh b/dnsapi/dns_fornex.sh index 38cdf5e6..91e5491b 100644 --- a/dnsapi/dns_fornex.sh +++ b/dnsapi/dns_fornex.sh @@ -9,7 +9,7 @@ Issues: github.com/acmesh-official/acme.sh/issues/3998 Author: Timur Umarov ' -FORNEX_API_URL="https://fornex.com/api/dns/v0.1" +FORNEX_API_URL="https://fornex.com/api" ######## Public functions ##################### @@ -30,12 +30,10 @@ dns_fornex_add() { fi _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" - if _contains "$response" '"ok": true' || _contains "$response" 'Такая запись уже существует.'; then - _info "Added, OK" - return 0 - fi + _info "Added, OK" + return 0 fi _err "Add txt record error." return 1 @@ -58,21 +56,21 @@ dns_fornex_rm() { fi _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 _err "Txt record not found" return 1 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" if [ -z "$_record_id" ]; then _err "can not find _record_id" return 1 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." return 1 fi @@ -90,18 +88,18 @@ _get_root() { i=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid return 1 fi - if ! _rest GET "domain_list.json?q=$h&apikey=$FORNEX_API_KEY"; then + if ! _rest GET "dns/domain/"; then return 1 fi - if _contains "$response" "\"$h\"" >/dev/null; then + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then _domain=$h return 0 else @@ -134,7 +132,9 @@ _rest() { data="$3" _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 _debug data "$data" diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 141ddccf..0516fee9 100644 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -95,7 +95,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -112,7 +112,7 @@ _get_root() { elif _contains "$response" '"code": 404'; then _debug "$h not found" else - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_gcore.sh b/dnsapi/dns_gcore.sh index ac2e614c..fbdba7ee 100755 --- a/dnsapi/dns_gcore.sh +++ b/dnsapi/dns_gcore.sh @@ -28,7 +28,7 @@ dns_gcore_add() { fi #save the api key to the account conf file. - _saveaccountconf_mutable GCORE_Key "$GCORE_Key" + _saveaccountconf_mutable GCORE_Key "$GCORE_Key" "base64" _debug "First detect the zone name" if ! _get_root "$fulldomain"; then @@ -138,7 +138,7 @@ _get_root() { p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -152,7 +152,7 @@ _get_root() { if _contains "$response" "\"name\":\"$h\""; then _zone_name=$h if [ "$_zone_name" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 08afa8f5..ee66ee19 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -148,7 +148,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 @@ -161,7 +161,7 @@ _get_root() { if _contains "$response" '"code":"NOT_FOUND"'; then _debug "$h not found" else - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_geoscaling.sh b/dnsapi/dns_geoscaling.sh index 96b3e218..05887c7e 100755 --- a/dnsapi/dns_geoscaling.sh +++ b/dnsapi/dns_geoscaling.sh @@ -202,7 +202,7 @@ find_zone() { # Walk through all possible zone names strip_counter=1 while true; do - attempted_zone=$(echo "${domain}" | cut -d . -f ${strip_counter}-) + attempted_zone=$(echo "${domain}" | cut -d . -f "${strip_counter}"-) # All possible zone names have been tried if [ -z "${attempted_zone}" ]; then diff --git a/dnsapi/dns_googledomains.sh b/dnsapi/dns_googledomains.sh index 7d241ab6..07a37e07 100755 --- a/dnsapi/dns_googledomains.sh +++ b/dnsapi/dns_googledomains.sh @@ -132,7 +132,7 @@ _dns_googledomains_get_zone() { i=2 while true; do - curr=$(printf "%s" "$domain" | cut -d . -f $i-100) + curr=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug curr "$curr" if [ -z "$curr" ]; then diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index cfb6efb8..a768f352 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -143,7 +143,7 @@ _find_zone() { # Walk through all possible zone names _strip_counter=1 while true; do - _attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-) + _attempted_zone=$(echo "$_domain" | cut -d . -f "${_strip_counter}"-) # All possible zone names have been tried if [ -z "$_attempted_zone" ]; then diff --git a/dnsapi/dns_hetzner.sh b/dnsapi/dns_hetzner.sh index a60bd55d..5a9cf2d9 100644 --- a/dnsapi/dns_hetzner.sh +++ b/dnsapi/dns_hetzner.sh @@ -181,7 +181,7 @@ _get_root() { _debug "Trying to get zone id by domain name for '$domain_without_acme'." while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 @@ -193,7 +193,7 @@ _get_root() { if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_entries":1'; then _domain_id=$(echo "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h HETZNER_Zone_ID=$_domain_id _savedomainconf "$domain_param_name" "$HETZNER_Zone_ID" diff --git a/dnsapi/dns_hexonet.sh b/dnsapi/dns_hexonet.sh index 6c86e6a4..017641fd 100755 --- a/dnsapi/dns_hexonet.sh +++ b/dnsapi/dns_hexonet.sh @@ -123,7 +123,7 @@ _get_root() { i=1 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -135,7 +135,7 @@ _get_root() { fi if _contains "$response" "CODE=200"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_huaweicloud.sh b/dnsapi/dns_huaweicloud.sh index f3df41f4..ee2d2b8e 100644 --- a/dnsapi/dns_huaweicloud.sh +++ b/dnsapi/dns_huaweicloud.sh @@ -210,7 +210,7 @@ _get_recordset_id() { _zoneid=$3 export _H1="X-Auth-Token: ${_token}" - response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}") + response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}&status=ACTIVE") if _contains "${response}" '"id"'; then _id="$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")" printf "%s" "${_id}" @@ -227,7 +227,7 @@ _add_record() { # Get Existing Records export _H1="X-Auth-Token: ${_token}" - response=$(_get "${dns_api}/v2/zones/${zoneid}/recordsets?name=${_domain}") + response=$(_get "${dns_api}/v2/zones/${zoneid}/recordsets?name=${_domain}&status=ACTIVE") _debug2 "${response}" _exist_record=$(echo "${response}" | _egrep_o '"records":[^]]*' | sed 's/\"records\"\:\[//g') diff --git a/dnsapi/dns_internetbs.sh b/dnsapi/dns_internetbs.sh index 84dfd70f..4238bfe4 100755 --- a/dnsapi/dns_internetbs.sh +++ b/dnsapi/dns_internetbs.sh @@ -133,7 +133,7 @@ _get_root() { fi while true; do - h=$(printf "%s" "$domain" | cut -d . -f ${i}-100) + h=$(printf "%s" "$domain" | cut -d . -f "${i}"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -141,7 +141,7 @@ _get_root() { fi if _contains "$response" "\"$h\""; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-${p}) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"${p}") _domain=${h} return 0 fi diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index 8c89a697..808fc3a9 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -163,6 +163,15 @@ _inwx_check_cookie() { return 1 } +_htmlEscape() { + _s="$1" + _s=$(echo "$_s" | sed "s/&/&/g") + _s=$(echo "$_s" | sed "s//\>/g") + _s=$(echo "$_s" | sed 's/"/\"/g') + printf -- %s "$_s" +} + _inwx_login() { if _inwx_check_cookie; then @@ -170,6 +179,8 @@ _inwx_login() { return 0 fi + XML_PASS=$(_htmlEscape "$INWX_Password") + xml_content=$(printf ' account.login @@ -193,7 +204,7 @@ _inwx_login() { - ' "$INWX_User" "$INWX_Password") + ' "$INWX_User" "$XML_PASS") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" @@ -282,7 +293,7 @@ _get_root() { response="$(_post "$xml_content" "$INWX_Api" "" "POST")" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -290,7 +301,7 @@ _get_root() { fi if _contains "$response" "$h"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_ionos.sh b/dnsapi/dns_ionos.sh index e4d28e11..9a464253 100755 --- a/dnsapi/dns_ionos.sh +++ b/dnsapi/dns_ionos.sh @@ -87,7 +87,7 @@ _get_root() { _response="$(echo "$_response" | tr -d "\n")" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then return 1 fi @@ -96,7 +96,7 @@ _get_root() { if [ "$_zone" ]; then _zone_id=$(printf "%s\n" "$_zone" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"') if [ "$_zone_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 diff --git a/dnsapi/dns_ionos_cloud.sh b/dnsapi/dns_ionos_cloud.sh index fa229e03..f255092f 100644 --- a/dnsapi/dns_ionos_cloud.sh +++ b/dnsapi/dns_ionos_cloud.sh @@ -1,12 +1,14 @@ #!/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 -# -# 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_ROUTE_ZONES="/zones" diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh index 7fd0d99c..edc789e1 100755 --- a/dnsapi/dns_ispconfig.sh +++ b/dnsapi/dns_ispconfig.sh @@ -14,6 +14,8 @@ Options: # User must provide login data and URL to the ISPConfig installation incl. port. # The remote user in ISPConfig must have access to: # - DNS txt Functions +# - DNS zone functions +# - Client functions ######## Public functions ##################### diff --git a/dnsapi/dns_jd.sh b/dnsapi/dns_jd.sh index a45aa2ca..4b9067f2 100644 --- a/dnsapi/dns_jd.sh +++ b/dnsapi/dns_jd.sh @@ -135,7 +135,7 @@ _get_root() { p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug2 "Checking domain: $h" if ! jd_rest GET "domain"; then _err "error get domain list" @@ -153,7 +153,7 @@ _get_root() { if [ "$hostedzone" ]; then _domain_id="$(echo "$hostedzone" | tr ',' '\n' | grep "\"id\":" | cut -d : -f 2)" if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_joker.sh b/dnsapi/dns_joker.sh index 49c544b9..1fe33c67 100644 --- a/dnsapi/dns_joker.sh +++ b/dnsapi/dns_joker.sh @@ -80,7 +80,7 @@ _get_root() { fulldomain=$1 i=1 while true; do - h=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + h=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then return 1 diff --git a/dnsapi/dns_kappernet.sh b/dnsapi/dns_kappernet.sh index 7b6fb8a6..762ba8b3 100644 --- a/dnsapi/dns_kappernet.sh +++ b/dnsapi/dns_kappernet.sh @@ -102,7 +102,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 @@ -113,7 +113,7 @@ _get_root() { if _contains "$response" '"OK":false'; then _debug "$h not found" else - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_la.sh b/dnsapi/dns_la.sh index 7a1c0a1c..f19333c4 100644 --- a/dnsapi/dns_la.sh +++ b/dnsapi/dns_la.sh @@ -113,7 +113,7 @@ _get_root() { p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 @@ -126,7 +126,7 @@ _get_root() { if _contains "$response" '"domainid":'; then _domain_id=$(printf "%s" "$response" | grep '"domainid":' | cut -d : -f 2 | cut -d , -f 1 | tr -d '\r' | tr -d '\n') if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_limacity.sh b/dnsapi/dns_limacity.sh index 649550ae..fb12f8c6 100644 --- a/dnsapi/dns_limacity.sh +++ b/dnsapi/dns_limacity.sh @@ -69,7 +69,7 @@ _lima_get_domain_id() { if [ "$(echo "$domains" | _egrep_o "\{.*""domains""")" ]; then response="$(echo "$domains" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -80,7 +80,7 @@ _lima_get_domain_id() { if [ "$hostedzone" ]; then LIMACITY_DOMAINID=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) if [ "$LIMACITY_DOMAINID" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index 5e4c694b..d74d1fc8 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -136,7 +136,7 @@ _get_root() { if _rest GET "domain.list"; 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) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -147,7 +147,7 @@ _get_root() { if [ "$hostedzone" ]; then _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_linode_v4.sh b/dnsapi/dns_linode_v4.sh index e562f80f..3c6997a0 100755 --- a/dnsapi/dns_linode_v4.sh +++ b/dnsapi/dns_linode_v4.sh @@ -76,7 +76,7 @@ dns_linode_v4_rm() { _debug _sub_domain "$_sub_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")" resource="$(echo "$response" | _egrep_o "\{.*\"name\": *\"$_sub_domain\".*}")" @@ -131,34 +131,42 @@ _Linode_API() { # _domain=domain.com # _domain_id=12345 _get_root() { - domain=$1 + full_host_str="$1" + i=2 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 _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 - _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 fi return 1 fi + p=$i i=$(_math "$i" + 1) - done - fi + fi + done + return 1 } diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh index 1f943e51..98a4f3ab 100644 --- a/dnsapi/dns_loopia.sh +++ b/dnsapi/dns_loopia.sh @@ -180,14 +180,14 @@ _get_root() { response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" while true; do - h=$(echo "$domain" | cut -d . -f $i-100) + h=$(echo "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 fi if _contains "$response" "$h"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index b037e90f..34cce6a1 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -110,7 +110,7 @@ _get_root() { return 1 fi while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -121,7 +121,7 @@ _get_root() { _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1) _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_maradns.sh b/dnsapi/dns_maradns.sh index 09d7248e..9eefb175 100755 --- a/dnsapi/dns_maradns.sh +++ b/dnsapi/dns_maradns.sh @@ -72,7 +72,7 @@ _reload_maradns() { pidpath="$1" kill -s HUP -- "$(cat "$pidpath")" if [ $? -ne 0 ]; then - _err "Unable to reload MaraDNS, kill returned $?" + _err "Unable to reload MaraDNS, kill returned" return 1 fi } diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 66545c46..43c903cd 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -107,7 +107,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 @@ -120,7 +120,7 @@ _get_root() { if _contains "$response" "\"name\":\"$h\""; then _domain_id=$(printf "%s\n" "$response" | sed 's/^{//; s/}$//; s/{.*}//' | sed -r 's/^.*"id":([0-9]+).*$/\1/') if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index ec9867db..0824a4e7 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -17,7 +17,7 @@ Author: Darven Dissek, William Gertz dns_miab_add() { fulldomain=$1 txtvalue=$2 - _info "Using miab challange add" + _info "Using miab challenge add" _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" @@ -26,7 +26,7 @@ dns_miab_add() { return 1 fi - #check domain and seperate into doamin and host + #check domain and seperate into domain and host if ! _get_root "$fulldomain"; then _err "Cannot find any part of ${fulldomain} is hosted on ${MIAB_Server}" return 1 @@ -55,7 +55,7 @@ dns_miab_rm() { fulldomain=$1 txtvalue=$2 - _info "Using miab challage delete" + _info "Using miab challenge delete" _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" @@ -112,7 +112,7 @@ _get_root() { #cycle through the passed domain seperating out a test domain discarding # the subdomain by marching thorugh the dots while true; do - _test_domain=$(printf "%s" "$_passed_domain" | cut -d . -f ${_i}-100) + _test_domain=$(printf "%s" "$_passed_domain" | cut -d . -f "${_i}"-100) _debug _test_domain "$_test_domain" if [ -z "$_test_domain" ]; then @@ -122,7 +122,7 @@ _get_root() { #report found if the test domain is in the json response and # report the subdomain if _contains "$response" "\"$_test_domain\""; then - _sub_domain=$(printf "%s" "$_passed_domain" | cut -d . -f 1-${_p}) + _sub_domain=$(printf "%s" "$_passed_domain" | cut -d . -f 1-"${_p}") _domain=${_test_domain} return 0 fi diff --git a/dnsapi/dns_misaka.sh b/dnsapi/dns_misaka.sh index c6c0f5f3..50ed4360 100755 --- a/dnsapi/dns_misaka.sh +++ b/dnsapi/dns_misaka.sh @@ -116,7 +116,7 @@ _get_root() { return 1 fi while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -124,7 +124,7 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\""; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_mydnsjp.sh b/dnsapi/dns_mydnsjp.sh index 4fa646e8..336c4889 100755 --- a/dnsapi/dns_mydnsjp.sh +++ b/dnsapi/dns_mydnsjp.sh @@ -126,7 +126,7 @@ _get_root() { fi while true; do - _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-100) if [ -z "$_domain" ]; then # not valid @@ -134,7 +134,7 @@ _get_root() { fi if [ "$_domain" = "$_root_domain" ]; then - _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$p") return 0 fi diff --git a/dnsapi/dns_mythic_beasts.sh b/dnsapi/dns_mythic_beasts.sh index b85401f4..1529e1e7 100755 --- a/dnsapi/dns_mythic_beasts.sh +++ b/dnsapi/dns_mythic_beasts.sh @@ -107,7 +107,7 @@ _get_root() { _debug "Detect the root zone" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then _err "Domain exhausted" return 1 @@ -118,7 +118,7 @@ _get_root() { _mb_rest GET "$h/records" ret="$?" if [ "$ret" -eq 0 ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index abe64d09..5527b357 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -109,7 +109,7 @@ _get_root_by_getList() { while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -123,7 +123,7 @@ _get_root_by_getList() { if ! _contains "$response" "$h"; then _debug "$h not found" else - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi @@ -137,14 +137,14 @@ _get_root_by_getHosts() { i=100 p=99 - while [ $p -ne 0 ]; do + while [ "$p" -ne 0 ]; do - h=$(printf "%s" "$1" | cut -d . -f $i-100) + h=$(printf "%s" "$1" | cut -d . -f "$i"-100) if [ -n "$h" ]; then if _contains "$h" "\\."; then _debug h "$h" if _namecheap_set_tld_sld "$h"; then - _sub_domain=$(printf "%s" "$1" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$1" | cut -d . -f 1-"$p") _domain="$h" return 0 else @@ -378,7 +378,7 @@ _namecheap_set_tld_sld() { while true; do - _tld=$(printf "%s" "$domain" | cut -d . -f $i-100) + _tld=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug tld "$_tld" if [ -z "$_tld" ]; then diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 2d146974..44549c9e 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -159,15 +159,15 @@ _namecom_get_root() { # Need to exclude the last field (tld) numfields=$(echo "$domain" | _egrep_o "\." | wc -l) - while [ $i -le "$numfields" ]; do - host=$(printf "%s" "$domain" | cut -d . -f $i-100) + while [ "$i" -le "$numfields" ]; do + host=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug host "$host" if [ -z "$host" ]; then return 1 fi if _contains "$response" "$host"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$host" return 0 fi diff --git a/dnsapi/dns_namesilo.sh b/dnsapi/dns_namesilo.sh index 2995e7dc..b31e32a1 100755 --- a/dnsapi/dns_namesilo.sh +++ b/dnsapi/dns_namesilo.sh @@ -109,15 +109,15 @@ _get_root() { # Need to exclude the last field (tld) numfields=$(echo "$domain" | _egrep_o "\." | wc -l) - while [ $i -le "$numfields" ]; do - host=$(printf "%s" "$domain" | cut -d . -f $i-100) + while [ "$i" -le "$numfields" ]; do + host=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug host "$host" if [ -z "$host" ]; then return 1 fi if _contains "$response" ">$host"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$host" return 0 fi diff --git a/dnsapi/dns_nederhost.sh b/dnsapi/dns_nederhost.sh index d0b97d3c..b16c36ec 100755 --- a/dnsapi/dns_nederhost.sh +++ b/dnsapi/dns_nederhost.sh @@ -88,8 +88,8 @@ _get_root() { i=2 p=1 while true; do - _domain=$(printf "%s" "$domain" | cut -d . -f $i-100) - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$(printf "%s" "$domain" | cut -d . -f "$i"-100) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _debug _domain "$_domain" if [ -z "$_domain" ]; then #not valid diff --git a/dnsapi/dns_neodigit.sh b/dnsapi/dns_neodigit.sh index 1119f916..a31f8c9b 100644 --- a/dnsapi/dns_neodigit.sh +++ b/dnsapi/dns_neodigit.sh @@ -126,7 +126,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -142,7 +142,7 @@ _get_root() { if _contains "$response" "\"name\":\"$h\"" >/dev/null; then _domain_id=$(echo "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_netlify.sh b/dnsapi/dns_netlify.sh index bb5f5809..322f10ad 100644 --- a/dnsapi/dns_netlify.sh +++ b/dnsapi/dns_netlify.sh @@ -55,8 +55,6 @@ dns_netlify_add() { return 1 fi - _err "Not fully implemented!" - return 1 } #Usage: dns_myapi_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" @@ -95,7 +93,6 @@ dns_netlify_rm() { _err "error removing validation value ($_code)" return 1 fi - return 0 fi return 1 } @@ -111,7 +108,7 @@ _get_root() { _netlify_rest GET "dns_zones" "" "$accesstoken" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug2 "Checking domain: $h" if [ -z "$h" ]; then #not valid @@ -126,7 +123,7 @@ _get_root() { #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) + _sub_domain=$(echo "$domain" | cut -d . -f 1-"$p") fi _domain=$h return 0 diff --git a/dnsapi/dns_nic.sh b/dnsapi/dns_nic.sh index 42f35cb0..5f3e7d5d 100644 --- a/dnsapi/dns_nic.sh +++ b/dnsapi/dns_nic.sh @@ -169,7 +169,7 @@ _get_root() { fi if _contains "$_all_domains" "^$h$"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h _service=$(printf "%s" "$response" | grep -m 1 "idn-name=\"$_domain\"" | sed -r "s/.*service=\"(.*)\".*$/\1/") return 0 diff --git a/dnsapi/dns_njalla.sh b/dnsapi/dns_njalla.sh index 5d241ebf..c410447d 100644 --- a/dnsapi/dns_njalla.sh +++ b/dnsapi/dns_njalla.sh @@ -126,7 +126,7 @@ _get_root() { p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -140,7 +140,7 @@ _get_root() { if _contains "$response" "\"$h\""; then _domain_returned=$(echo "$response" | _egrep_o "\{\"name\": *\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \" | tr -d " ") if [ "$_domain_returned" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index 2a073950..e1bfa531 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -119,7 +119,7 @@ _get_root() { return 1 fi while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -127,7 +127,7 @@ _get_root() { fi if _contains "$response" "\"zone\":\"$h\""; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 9df6262e..d5dbbcbc 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -20,6 +20,7 @@ dns_nsupdate_add() { NSUPDATE_SERVER_PORT="${NSUPDATE_SERVER_PORT:-$(_readaccountconf_mutable NSUPDATE_SERVER_PORT)}" NSUPDATE_KEY="${NSUPDATE_KEY:-$(_readaccountconf_mutable NSUPDATE_KEY)}" NSUPDATE_ZONE="${NSUPDATE_ZONE:-$(_readaccountconf_mutable NSUPDATE_ZONE)}" + NSUPDATE_OPT="${NSUPDATE_OPT:-$(_readaccountconf_mutable NSUPDATE_OPT)}" _checkKeyFile || return 1 @@ -28,21 +29,25 @@ dns_nsupdate_add() { _saveaccountconf_mutable NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}" _saveaccountconf_mutable NSUPDATE_KEY "${NSUPDATE_KEY}" _saveaccountconf_mutable NSUPDATE_ZONE "${NSUPDATE_ZONE}" + _saveaccountconf_mutable NSUPDATE_OPT "${NSUPDATE_OPT}" [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 + [ -n "${NSUPDATE_OPT}" ] || NSUPDATE_OPT="" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d" [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D" if [ -z "${NSUPDATE_ZONE}" ]; then - nsupdate -k "${NSUPDATE_KEY}" $nsdebug </dev/null; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" _real_dns_version=$(echo "$response" | _egrep_o '"uuid_ref":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) return 0 diff --git a/dnsapi/dns_openprovider.sh b/dnsapi/dns_openprovider.sh index 0e93ecf8..b584fad2 100755 --- a/dnsapi/dns_openprovider.sh +++ b/dnsapi/dns_openprovider.sh @@ -68,7 +68,7 @@ dns_openprovider_add() { new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" fi - if [ -z "$(echo "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA|NS)<\/type>.*")" ]; then + if [ -z "$(echo "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA)<\/type>.*")" ]; then _debug "not an allowed record type, skipping" "$new_item" continue fi @@ -152,7 +152,7 @@ dns_openprovider_rm() { new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" fi - if [ -z "$(echo "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA|NS)<\/type>.*")" ]; then + if [ -z "$(echo "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA)<\/type>.*")" ]; then _debug "not an allowed record type, skipping" "$new_item" continue fi @@ -186,7 +186,7 @@ _get_root() { results_retrieved=0 while true; do - h=$(echo "$domain" | cut -d . -f $i-100) + h=$(echo "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid diff --git a/dnsapi/dns_opnsense.sh b/dnsapi/dns_opnsense.sh index 6d3d3eec..d1e9c0ac 100755 --- a/dnsapi/dns_opnsense.sh +++ b/dnsapi/dns_opnsense.sh @@ -144,7 +144,7 @@ _get_root() { fi while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 @@ -153,13 +153,13 @@ _get_root() { id=$(echo "$_domain_response" | _egrep_o "\"uuid\":\"[a-z0-9\-]*\",\"enabled\":\"1\",\"type\":\"primary\",\"domainname\":\"${h}\"" | cut -d ':' -f 2 | cut -d '"' -f 2) if [ -n "$id" ]; then _debug id "$id" - _host=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _host=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="${h}" _domainid="${id}" return 0 fi p=$i - i=$(_math $i + 1) + i=$(_math "$i" + 1) done _debug "$domain not found" diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 7f62c05e..24ad0904 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -113,7 +113,7 @@ _initAuth() { _saveaccountconf_mutable OVH_END_POINT "$OVH_END_POINT" fi - OVH_API="$(_ovh_get_api $OVH_END_POINT)" + OVH_API="$(_ovh_get_api "$OVH_END_POINT")" _debug OVH_API "$OVH_API" OVH_CK="${OVH_CK:-$(_readaccountconf_mutable OVH_CK)}" @@ -260,7 +260,7 @@ _get_root() { i=1 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 @@ -273,7 +273,7 @@ _get_root() { if ! _contains "$response" "This service does not exist" >/dev/null && ! _contains "$response" "This call has not been granted" >/dev/null && ! _contains "$response" "NOT_GRANTED_CALL" >/dev/null; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index cde3b1a6..2478e19f 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -20,6 +20,11 @@ dns_pdns_add() { fulldomain=$1 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 PDNS_Url="" _err "You don't specify PowerDNS address." @@ -46,12 +51,12 @@ dns_pdns_add() { fi #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 - _saveaccountconf PDNS_Ttl "$PDNS_Ttl" + _saveaccountconf_mutable PDNS_Ttl "$PDNS_Ttl" fi _debug "Detect root zone" @@ -73,6 +78,11 @@ dns_pdns_rm() { fulldomain=$1 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 PDNS_Ttl="$DEFAULT_PDNS_TTL" fi @@ -181,7 +191,7 @@ _get_root() { fi while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if _contains "$_zones_response" "\"name\":\"$h.\""; then _domain="$h." @@ -194,7 +204,7 @@ _get_root() { if [ -z "$h" ]; then return 1 fi - i=$(_math $i + 1) + i=$(_math "$i" + 1) done _debug "$domain not found" diff --git a/dnsapi/dns_pointhq.sh b/dnsapi/dns_pointhq.sh index fe95cd52..0abc087b 100644 --- a/dnsapi/dns_pointhq.sh +++ b/dnsapi/dns_pointhq.sh @@ -118,7 +118,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -130,7 +130,7 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\"" >/dev/null; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_porkbun.sh b/dnsapi/dns_porkbun.sh index 0a443855..1681ca9a 100644 --- a/dnsapi/dns_porkbun.sh +++ b/dnsapi/dns_porkbun.sh @@ -9,7 +9,7 @@ Options: Issues: github.com/acmesh-official/acme.sh/issues/3450 ' -PORKBUN_Api="https://porkbun.com/api/json/v3" +PORKBUN_Api="https://api.porkbun.com/api/json/v3" ######## Public functions ##################### @@ -107,7 +107,7 @@ _get_root() { domain=$1 i=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then return 1 diff --git a/dnsapi/dns_rackcorp.sh b/dnsapi/dns_rackcorp.sh index e1e4f27d..b8fc73ab 100644 --- a/dnsapi/dns_rackcorp.sh +++ b/dnsapi/dns_rackcorp.sh @@ -83,7 +83,7 @@ _get_root() { return 1 fi while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug searchhost "$h" if [ -z "$h" ]; then _err "Could not find domain for record $domain in RackCorp using the provided credentials" @@ -95,7 +95,7 @@ _get_root() { if _contains "$response" "\"matches\":1"; then if _contains "$response" "\"name\":\"$h\""; then - _lookup=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _lookup=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_rackspace.sh b/dnsapi/dns_rackspace.sh index 03edce0d..05ec14a6 100644 --- a/dnsapi/dns_rackspace.sh +++ b/dnsapi/dns_rackspace.sh @@ -72,7 +72,7 @@ _get_root_zone() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -88,7 +88,7 @@ _get_root_zone() { _domain_id=$(echo "$response" | sed -n "s/^.*\"id\":\"\([^,]*\)\",\"accountId\":\"[0-9]*\",\"name\":\"$h\",.*/\1/p") _debug2 domain_id "$_domain_id" if [ -n "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_rcode0.sh b/dnsapi/dns_rcode0.sh index 131a22b1..4ffdf572 100755 --- a/dnsapi/dns_rcode0.sh +++ b/dnsapi/dns_rcode0.sh @@ -171,7 +171,7 @@ _get_root() { i=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug "try to find: $h" if _rcode0_rest "GET" "/api/v1/acme/zones/$h"; then @@ -189,7 +189,7 @@ _get_root() { if [ -z "$h" ]; then return 1 fi - i=$(_math $i + 1) + i=$(_math "$i" + 1) done _debug "no matching domain for $domain found" diff --git a/dnsapi/dns_scaleway.sh b/dnsapi/dns_scaleway.sh index 64bfcc38..4cbf68d2 100755 --- a/dnsapi/dns_scaleway.sh +++ b/dnsapi/dns_scaleway.sh @@ -41,9 +41,7 @@ dns_scaleway_add() { _err error "$response" return 1 fi - _info "Record added." - return 0 } dns_scaleway_rm() { @@ -71,9 +69,7 @@ dns_scaleway_rm() { _err error "$response" return 1 fi - _info "Record deleted." - return 0 } #################### Private functions below ################################## @@ -104,7 +100,7 @@ _get_root() { i=1 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 @@ -113,7 +109,7 @@ _get_root() { _scaleway_rest GET "dns-zones/$h/records" if ! _contains "$response" "subdomain not found" >/dev/null; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_schlundtech.sh b/dnsapi/dns_schlundtech.sh index 02146494..6d2930a2 100644 --- a/dnsapi/dns_schlundtech.sh +++ b/dnsapi/dns_schlundtech.sh @@ -106,7 +106,7 @@ _get_autodns_zone() { p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then @@ -124,7 +124,7 @@ _get_autodns_zone() { if _contains "$autodns_response" "1" >/dev/null; then _zone="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" _system_ns="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") return 0 fi diff --git a/dnsapi/dns_selectel.sh b/dnsapi/dns_selectel.sh index 32b0737f..8b52b24e 100644 --- a/dnsapi/dns_selectel.sh +++ b/dnsapi/dns_selectel.sh @@ -117,7 +117,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -125,7 +125,7 @@ _get_root() { fi if _contains "$response" "\"name\" *: *\"$h\","; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h _debug "Getting domain id for $h" if ! _sl_rest GET "/$h"; then diff --git a/dnsapi/dns_servercow.sh b/dnsapi/dns_servercow.sh index 37c2a97b..d6994681 100755 --- a/dnsapi/dns_servercow.sh +++ b/dnsapi/dns_servercow.sh @@ -81,7 +81,6 @@ dns_servercow_add() { return 1 fi - return 1 } # Usage fulldomain txtvalue @@ -137,7 +136,7 @@ _get_root() { p=1 while true; do - _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-100) _debug _domain "$_domain" if [ -z "$_domain" ]; then @@ -150,7 +149,7 @@ _get_root() { fi if ! _contains "$response" '"error":"no such domain in user context"' >/dev/null; then - _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$p") if [ -z "$_sub_domain" ]; then # not valid return 1 diff --git a/dnsapi/dns_simply.sh b/dnsapi/dns_simply.sh index 9fac3ef7..e0ad16e2 100644 --- a/dnsapi/dns_simply.sh +++ b/dnsapi/dns_simply.sh @@ -166,7 +166,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 @@ -179,7 +179,7 @@ _get_root() { if ! _contains "$response" "$SIMPLY_SUCCESS_CODE"; then _debug "$h not found" else - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_technitium.sh b/dnsapi/dns_technitium.sh new file mode 100755 index 00000000..a50db97c --- /dev/null +++ b/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 +' + +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" +} diff --git a/dnsapi/dns_timeweb.sh b/dnsapi/dns_timeweb.sh new file mode 100644 index 00000000..544564ea --- /dev/null +++ b/dnsapi/dns_timeweb.sh @@ -0,0 +1,403 @@ +#!/usr/bin/env sh +# 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 +' + +TW_Api="https://api.timeweb.cloud/api/v1" + +################ Public functions ################ + +# Adds an ACME DNS-01 challenge DNS TXT record via the Timeweb Cloud API. +# +# Param1: The ACME DNS-01 challenge FQDN. +# Param2: The value of the ACME DNS-01 challenge TXT record. +# +# Example: dns_timeweb_add "_acme-challenge.sub.domain.com" "D-52Wm...4uYM" +dns_timeweb_add() { + _debug "$(__green "Timeweb DNS API"): \"dns_timeweb_add\" started." + + _timeweb_set_acme_fqdn "$1" || return 1 + _timeweb_set_acme_txt "$2" || return 1 + _timeweb_check_token || return 1 + _timeweb_split_acme_fqdn || return 1 + _timeweb_dns_txt_add || return 1 + + _debug "$(__green "Timeweb DNS API"): \"dns_timeweb_add\" finished." +} + +# Removes a DNS TXT record via the Timeweb Cloud API. +# +# Param1: The ACME DNS-01 challenge FQDN. +# Param2: The value of the ACME DNS-01 challenge TXT record. +# +# Example: dns_timeweb_rm "_acme-challenge.sub.domain.com" "D-52Wm...4uYM" +dns_timeweb_rm() { + _debug "$(__green "Timeweb DNS API"): \"dns_timeweb_rm\" started." + + _timeweb_set_acme_fqdn "$1" || return 1 + _timeweb_set_acme_txt "$2" || return 1 + _timeweb_check_token || return 1 + _timeweb_split_acme_fqdn || return 1 + _timeweb_get_dns_txt || return 1 + _timeweb_dns_txt_remove || return 1 + + _debug "$(__green "Timeweb DNS API"): \"dns_timeweb_rm\" finished." +} + +################ Private functions ################ + +# Checks and sets the ACME DNS-01 challenge FQDN. +# +# Param1: The ACME DNS-01 challenge FQDN. +# +# Example: _timeweb_set_acme_fqdn "_acme-challenge.sub.domain.com" +# +# Sets the "Acme_Fqdn" variable (_acme-challenge.sub.domain.com) +_timeweb_set_acme_fqdn() { + Acme_Fqdn=$1 + _debug "Setting ACME DNS-01 challenge FQDN \"$Acme_Fqdn\"." + [ -z "$Acme_Fqdn" ] && { + _err "ACME DNS-01 challenge FQDN is empty." + return 1 + } + return 0 +} + +# Checks and sets the value of the ACME DNS-01 challenge TXT record. +# +# Param1: Value of the ACME DNS-01 challenge TXT record. +# +# Example: _timeweb_set_acme_txt "D-52Wm...4uYM" +# +# Sets the "Acme_Txt" variable to the provided value (D-52Wm...4uYM) +_timeweb_set_acme_txt() { + Acme_Txt=$1 + _debug "Setting the value of the ACME DNS-01 challenge TXT record to \"$Acme_Txt\"." + [ -z "$Acme_Txt" ] && { + _err "ACME DNS-01 challenge TXT record value is empty." + return 1 + } + return 0 +} + +# Checks if the Timeweb Cloud API JWT token is present (refer to the script description). +# Adds or updates the token in the acme.sh account configuration. +_timeweb_check_token() { + _debug "Checking for the presence of the Timeweb Cloud API JWT token." + + TW_Token="${TW_Token:-$(_readaccountconf_mutable TW_Token)}" + + [ -z "$TW_Token" ] && { + _err "Timeweb Cloud API JWT token was not found." + return 1 + } + + _saveaccountconf_mutable TW_Token "$TW_Token" +} + +# Divides the ACME DNS-01 challenge FQDN into its main domain and subdomain components. +_timeweb_split_acme_fqdn() { + _debug "Trying to divide \"$Acme_Fqdn\" into its main domain and subdomain components." + + TW_Page_Limit=100 + TW_Page_Offset=0 + TW_Domains_Returned="" + + while [ -z "$TW_Domains_Returned" ] || [ "$TW_Domains_Returned" -ge "$TW_Page_Limit" ]; do + + _timeweb_list_domains "$TW_Page_Limit" "$TW_Page_Offset" || return 1 + + # Remove the 'subdomains' subarray to prevent confusion with FQDNs. + + TW_Domains=$( + echo "$TW_Domains" | + sed 's/"subdomains":\[[^]]*]//g' + ) + + [ -z "$TW_Domains" ] && { + _err "Failed to parse the list of domains." + return 1 + } + + while + TW_Domain=$( + echo "$TW_Domains" | + sed -n 's/.*{[^{]*"fqdn":"\([^"]*\)"[^}]*}.*/\1/p' + ) + + [ -n "$TW_Domain" ] && { + _timeweb_is_main_domain "$TW_Domain" && return 0 + + TW_Domains=$( + echo "$TW_Domains" | + sed 's/{\([^{]*"fqdn":"'"$TW_Domain"'"[^}]*\)}//' + ) + continue + } + do :; done + + TW_Page_Offset=$(_math "$TW_Page_Offset" + "$TW_Page_Limit") + done + + _err "Failed to divide \"$Acme_Fqdn\" into its main domain and subdomain components." + return 1 +} + +# Searches for a previously added DNS TXT record. +# +# Sets the "TW_Dns_Txt_Id" variable. +_timeweb_get_dns_txt() { + _debug "Trying to locate a DNS TXT record with the value \"$Acme_Txt\"." + + TW_Page_Limit=100 + TW_Page_Offset=0 + TW_Dns_Records_Returned="" + + while [ -z "$TW_Dns_Records_Returned" ] || [ "$TW_Dns_Records_Returned" -ge "$TW_Page_Limit" ]; do + + _timeweb_list_dns_records "$TW_Page_Limit" "$TW_Page_Offset" || return 1 + + while + Dns_Record=$( + echo "$TW_Dns_Records" | + sed -n 's/.*{\([^{]*{[^{]*'"$Acme_Txt"'[^}]*}[^}]*\)}.*/\1/p' + ) + + [ -n "$Dns_Record" ] && { + _timeweb_is_added_txt "$Dns_Record" && return 0 + + TW_Dns_Records=$( + echo "$TW_Dns_Records" | + sed 's/{\([^{]*{[^{]*'"$Acme_Txt"'[^}]*}[^}]*\)}//' + ) + continue + } + do :; done + + TW_Page_Offset=$(_math "$TW_Page_Offset" + "$TW_Page_Limit") + done + + _err "DNS TXT record was not found." + return 1 +} + +# Lists domains via the Timeweb Cloud API. +# +# Param 1: Limit for listed domains. +# Param 2: Offset for domains list. +# +# Sets the "TW_Domains" variable. +# Sets the "TW_Domains_Returned" variable. +_timeweb_list_domains() { + _debug "Listing domains via Timeweb Cloud API. Limit: $1, offset: $2." + + export _H1="Authorization: Bearer $TW_Token" + + if ! TW_Domains=$(_get "$TW_Api/domains?limit=$1&offset=$2"); then + _err "The request to the Timeweb Cloud API failed." + return 1 + fi + + [ -z "$TW_Domains" ] && { + _err "Empty response from the Timeweb Cloud API." + return 1 + } + + TW_Domains_Returned=$( + echo "$TW_Domains" | + sed 's/.*"meta":{"total":\([0-9]*\)[^0-9].*/\1/' + ) + + [ -z "$TW_Domains_Returned" ] && { + _err "Failed to extract the total count of domains." + return 1 + } + + [ "$TW_Domains_Returned" -eq "0" ] && { + _err "Domains are missing." + return 1 + } + + _debug "Domains returned by Timeweb Cloud API: $TW_Domains_Returned." +} + +# Lists domain DNS records via the Timeweb Cloud API. +# +# Param 1: Limit for listed DNS records. +# Param 2: Offset for DNS records list. +# +# Sets the "TW_Dns_Records" variable. +# Sets the "TW_Dns_Records_Returned" variable. +_timeweb_list_dns_records() { + _debug "Listing domain DNS records via the Timeweb Cloud API. Limit: $1, offset: $2." + + export _H1="Authorization: Bearer $TW_Token" + + if ! TW_Dns_Records=$(_get "$TW_Api/domains/$TW_Main_Domain/dns-records?limit=$1&offset=$2"); then + _err "The request to the Timeweb Cloud API failed." + return 1 + fi + + [ -z "$TW_Dns_Records" ] && { + _err "Empty response from the Timeweb Cloud API." + return 1 + } + + TW_Dns_Records_Returned=$( + echo "$TW_Dns_Records" | + sed 's/.*"meta":{"total":\([0-9]*\)[^0-9].*/\1/' + ) + + [ -z "$TW_Dns_Records_Returned" ] && { + _err "Failed to extract the total count of DNS records." + return 1 + } + + [ "$TW_Dns_Records_Returned" -eq "0" ] && { + _err "DNS records are missing." + return 1 + } + + _debug "DNS records returned by Timeweb Cloud API: $TW_Dns_Records_Returned." +} + +# Verifies whether the domain is the primary domain for the ACME DNS-01 challenge FQDN. +# The requirement is that the provided domain is the top-level domain +# for the ACME DNS-01 challenge FQDN. +# +# Param 1: Domain object returned by Timeweb Cloud API. +# +# Sets the "TW_Main_Domain" variable (e.g. "_acme-challenge.s1.domain.co.uk" → "domain.co.uk"). +# Sets the "TW_Subdomains" variable (e.g. "_acme-challenge.s1.domain.co.uk" → "_acme-challenge.s1"). +_timeweb_is_main_domain() { + _debug "Checking if \"$1\" is the main domain of the ACME DNS-01 challenge FQDN." + + [ -z "$1" ] && { + _debug "Failed to extract FQDN. Skipping domain." + return 1 + } + + ! echo ".$Acme_Fqdn" | grep -qi "\.$1$" && { + _debug "Domain does not match the ACME DNS-01 challenge FQDN. Skipping domain." + return 1 + } + + TW_Main_Domain=$1 + TW_Subdomains=$( + echo "$Acme_Fqdn" | + sed "s/\.*.\{${#1}\}$//" + ) + + _debug "Matched domain. ACME DNS-01 challenge FQDN split as [$TW_Subdomains].[$TW_Main_Domain]." + return 0 +} + +# Verifies whether a DNS record was previously added based on the following criteria: +# - The value matches the ACME DNS-01 challenge TXT record value; +# - The record type is TXT; +# - The subdomain matches the ACME DNS-01 challenge FQDN. +# +# Param 1: DNS record object returned by Timeweb Cloud API. +# +# Sets the "TW_Dns_Txt_Id" variable. +_timeweb_is_added_txt() { + _debug "Checking if \"$1\" is a previously added DNS TXT record." + + echo "$1" | grep -qv '"type":"TXT"' && { + _debug "Not a TXT record. Skipping the record." + return 1 + } + + if [ -n "$TW_Subdomains" ]; then + echo "$1" | grep -qvi "\"subdomain\":\"$TW_Subdomains\"" && { + _debug "Subdomains do not match. Skipping the record." + return 1 + } + else + echo "$1" | grep -q '"subdomain\":"..*"' && { + _debug "Subdomains do not match. Skipping the record." + return 1 + } + fi + + TW_Dns_Txt_Id=$( + echo "$1" | + sed 's/.*"id":\([0-9]*\)[^0-9].*/\1/' + ) + + [ -z "$TW_Dns_Txt_Id" ] && { + _debug "Failed to extract the DNS record ID. Skipping the record." + return 1 + } + + _debug "Matching DNS TXT record ID is \"$TW_Dns_Txt_Id\"." + return 0 +} + +# Adds a DNS TXT record via the Timeweb Cloud API. +_timeweb_dns_txt_add() { + _debug "Adding a new DNS TXT record via the Timeweb Cloud API." + + export _H1="Authorization: Bearer $TW_Token" + export _H2="Content-Type: application/json" + + if ! TW_Response=$( + _post "{ + \"subdomain\":\"$TW_Subdomains\", + \"type\":\"TXT\", + \"value\":\"$Acme_Txt\" + }" \ + "$TW_Api/domains/$TW_Main_Domain/dns-records" + ); then + _err "The request to the Timeweb Cloud API failed." + return 1 + fi + + [ -z "$TW_Response" ] && { + _err "An unexpected empty response was received from the Timeweb Cloud API." + return 1 + } + + TW_Dns_Txt_Id=$( + echo "$TW_Response" | + sed 's/.*"id":\([0-9]*\)[^0-9].*/\1/' + ) + + [ -z "$TW_Dns_Txt_Id" ] && { + _err "Failed to extract the DNS TXT Record ID." + return 1 + } + + _debug "DNS TXT record has been added. ID: \"$TW_Dns_Txt_Id\"." +} + +# Removes a DNS record via the Timeweb Cloud API. +_timeweb_dns_txt_remove() { + _debug "Removing DNS record via the Timeweb Cloud API." + + export _H1="Authorization: Bearer $TW_Token" + + if ! TW_Response=$( + _post \ + "" \ + "$TW_Api/domains/$TW_Main_Domain/dns-records/$TW_Dns_Txt_Id" \ + "" \ + "DELETE" + ); then + _err "The request to the Timeweb Cloud API failed." + return 1 + fi + + [ -n "$TW_Response" ] && { + _err "Received an unexpected response body from the Timeweb Cloud API." + return 1 + } + + _debug "DNS TXT record with ID \"$TW_Dns_Txt_Id\" has been removed." +} diff --git a/dnsapi/dns_transip.sh b/dnsapi/dns_transip.sh index 6171678e..2abbe34d 100644 --- a/dnsapi/dns_transip.sh +++ b/dnsapi/dns_transip.sh @@ -55,14 +55,14 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 fi - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" if _transip_rest GET "domains/$h/dns" && _contains "$response" "dnsEntries"; then diff --git a/dnsapi/dns_udr.sh b/dnsapi/dns_udr.sh index 24a843b9..f9772e10 100644 --- a/dnsapi/dns_udr.sh +++ b/dnsapi/dns_udr.sh @@ -115,7 +115,7 @@ _get_root() { fi while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then diff --git a/dnsapi/dns_ultra.sh b/dnsapi/dns_ultra.sh index 8b8c9122..e8da431c 100644 --- a/dnsapi/dns_ultra.sh +++ b/dnsapi/dns_ultra.sh @@ -115,7 +115,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" _debug response "$response" if [ -z "$h" ]; then @@ -128,7 +128,7 @@ _get_root() { if _contains "${response}" "${h}." >/dev/null; then _domain_id=$(echo "$response" | _egrep_o "${h}" | head -1) if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="${h}" _debug sub_domain "${_sub_domain}" _debug domain "${_domain}" diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index a1263abe..ff70c8b6 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -133,7 +133,7 @@ _get_root() { i=2 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -147,7 +147,7 @@ _get_root() { if _contains "$response" "\"status\": 200"; then _domain_id=$h if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_variomedia.sh b/dnsapi/dns_variomedia.sh index 23ec29bf..fa38bbb6 100644 --- a/dnsapi/dns_variomedia.sh +++ b/dnsapi/dns_variomedia.sh @@ -102,7 +102,7 @@ _get_root() { i=1 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then return 1 fi @@ -112,7 +112,7 @@ _get_root() { fi if _contains "$response" "\"id\":\"$h\""; then - _sub_domain=$(printf "%s" "$domain" | cut -d '.' -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d '.' -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_veesp.sh b/dnsapi/dns_veesp.sh index 5ea6e718..1afeeb30 100644 --- a/dnsapi/dns_veesp.sh +++ b/dnsapi/dns_veesp.sh @@ -112,7 +112,7 @@ _get_root() { return 1 fi while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -125,7 +125,7 @@ _get_root() { _service_id=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$h\",\"service_id\":[^}]*" | cut -d : -f 3 | cut -d '"' -f 2) _debug _service_id "$_service_id" if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" return 0 fi diff --git a/dnsapi/dns_vercel.sh b/dnsapi/dns_vercel.sh index 46a4cb7e..469f7670 100644 --- a/dnsapi/dns_vercel.sh +++ b/dnsapi/dns_vercel.sh @@ -94,7 +94,7 @@ _get_root() { i=1 p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) if [ -z "$h" ]; then #not valid return 1 @@ -105,7 +105,7 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\"" >/dev/null; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_vscale.sh b/dnsapi/dns_vscale.sh index 54abb439..c3915c69 100755 --- a/dnsapi/dns_vscale.sh +++ b/dnsapi/dns_vscale.sh @@ -97,7 +97,7 @@ _get_root() { if _vscale_rest GET "domains/"; then response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -108,7 +108,7 @@ _get_root() { if [ "$hostedzone" ]; then _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_vultr.sh b/dnsapi/dns_vultr.sh index 94d14f02..61ec3f60 100644 --- a/dnsapi/dns_vultr.sh +++ b/dnsapi/dns_vultr.sh @@ -112,7 +112,7 @@ _get_root() { domain=$1 i=1 while true; do - _domain=$(printf "%s" "$domain" | cut -d . -f $i-100) + _domain=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$_domain" if [ -z "$_domain" ]; then return 1 diff --git a/dnsapi/dns_websupport.sh b/dnsapi/dns_websupport.sh index 3df8d81c..bfc4b23a 100644 --- a/dnsapi/dns_websupport.sh +++ b/dnsapi/dns_websupport.sh @@ -121,7 +121,7 @@ _get_root() { p=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -135,7 +135,7 @@ _get_root() { if _contains "$response" "\"name\":\"$h\""; then _domain_id=$(echo "$response" | _egrep_o "\[.\"id\": *[^,]*" | _head_n 1 | cut -d : -f 2 | tr -d \" | tr -d " ") if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain=$h return 0 fi diff --git a/dnsapi/dns_world4you.sh b/dnsapi/dns_world4you.sh index be6ef5c8..0febbad9 100644 --- a/dnsapi/dns_world4you.sh +++ b/dnsapi/dns_world4you.sh @@ -115,7 +115,7 @@ dns_world4you_rm() { _resethttp 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..." ret=$(_post "$body" "$WORLD4YOU_API/$paketnr/dns/record/delete" '' POST 'application/x-www-form-urlencoded') _resethttp @@ -203,6 +203,7 @@ _get_paketnr() { form="$2" domains=$(echo "$form" | grep '