mirror of
				https://github.com/acmesh-official/acme.sh
				synced 2025-11-04 13:55:56 +08:00 
			
		
		
		
	Merge branch 'acmesh-official:master' into master
This commit is contained in:
		
							
								
								
									
										1
									
								
								.github/workflows/pr_dns.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/pr_dns.yml
									
									
									
									
										vendored
									
									
								
							@@ -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, 都必须确保通过这个测试.
 | 
			
		||||
                `
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								acme.sh
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								acme.sh
									
									
									
									
									
								
							@@ -1442,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
 | 
			
		||||
 | 
			
		||||
@@ -1628,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
 | 
			
		||||
@@ -1811,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"
 | 
			
		||||
@@ -2193,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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										172
									
								
								deploy/ruckus.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										172
									
								
								deploy/ruckus.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,172 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Here is a script to deploy cert to Ruckus ZoneDirector / Unleashed.
 | 
			
		||||
#
 | 
			
		||||
# Public domain, 2024, Tony Rielly <https://github.com/ms264556>
 | 
			
		||||
#
 | 
			
		||||
# ```sh
 | 
			
		||||
# acme.sh --deploy -d ruckus.example.com --deploy-hook ruckus
 | 
			
		||||
# ```
 | 
			
		||||
#
 | 
			
		||||
# Then you need to set the environment variables for the
 | 
			
		||||
# deploy script to work.
 | 
			
		||||
#
 | 
			
		||||
# ```sh
 | 
			
		||||
# export RUCKUS_HOST=myruckus.example.com
 | 
			
		||||
# export RUCKUS_USER=myruckususername
 | 
			
		||||
# export RUCKUS_PASS=myruckuspassword
 | 
			
		||||
#
 | 
			
		||||
# acme.sh --deploy -d myruckus.example.com --deploy-hook ruckus
 | 
			
		||||
# ```
 | 
			
		||||
#
 | 
			
		||||
# returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
ruckus_deploy() {
 | 
			
		||||
  _cdomain="$1"
 | 
			
		||||
  _ckey="$2"
 | 
			
		||||
  _ccert="$3"
 | 
			
		||||
  _cca="$4"
 | 
			
		||||
  _cfullchain="$5"
 | 
			
		||||
  _err_code=0
 | 
			
		||||
 | 
			
		||||
  _debug _cdomain "$_cdomain"
 | 
			
		||||
  _debug _ckey "$_ckey"
 | 
			
		||||
  _debug _ccert "$_ccert"
 | 
			
		||||
  _debug _cca "$_cca"
 | 
			
		||||
  _debug _cfullchain "$_cfullchain"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf RUCKUS_HOST
 | 
			
		||||
  _getdeployconf RUCKUS_USER
 | 
			
		||||
  _getdeployconf RUCKUS_PASS
 | 
			
		||||
 | 
			
		||||
  if [ -z "$RUCKUS_HOST" ]; then
 | 
			
		||||
    _debug "Using _cdomain as RUCKUS_HOST, please set if not correct."
 | 
			
		||||
    RUCKUS_HOST="$_cdomain"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$RUCKUS_USER" ]; then
 | 
			
		||||
    _err "Need to set the env variable RUCKUS_USER"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$RUCKUS_PASS" ]; then
 | 
			
		||||
    _err "Need to set the env variable RUCKUS_PASS"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _savedeployconf RUCKUS_HOST "$RUCKUS_HOST"
 | 
			
		||||
  _savedeployconf RUCKUS_USER "$RUCKUS_USER"
 | 
			
		||||
  _savedeployconf RUCKUS_PASS "$RUCKUS_PASS"
 | 
			
		||||
 | 
			
		||||
  _debug RUCKUS_HOST "$RUCKUS_HOST"
 | 
			
		||||
  _debug RUCKUS_USER "$RUCKUS_USER"
 | 
			
		||||
  _secure_debug RUCKUS_PASS "$RUCKUS_PASS"
 | 
			
		||||
 | 
			
		||||
  export ACME_HTTP_NO_REDIRECTS=1
 | 
			
		||||
 | 
			
		||||
  _info "Discovering the login URL"
 | 
			
		||||
  _get "https://$RUCKUS_HOST" >/dev/null
 | 
			
		||||
  _login_url="$(_response_header 'Location')"
 | 
			
		||||
  if [ -n "$_login_url" ]; then
 | 
			
		||||
    _login_path=$(echo "$_login_url" | sed 's|https\?://[^/]\+||')
 | 
			
		||||
    if [ -z "$_login_path" ]; then
 | 
			
		||||
      # redirect was to a different host
 | 
			
		||||
      _err "Connection failed: redirected to a different host. Configure Unleashed with a Preferred Master or Management Interface."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "${_login_url}" ]; then
 | 
			
		||||
    _err "Connection failed: couldn't find login page."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _base_url=$(dirname "$_login_url")
 | 
			
		||||
  _login_page=$(basename "$_login_url")
 | 
			
		||||
 | 
			
		||||
  if [ "$_login_page" = "index.html" ]; then
 | 
			
		||||
    _err "Connection temporarily unavailable: Unleashed Rebuilding."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$_login_page" = "wizard.jsp" ]; then
 | 
			
		||||
    _err "Connection failed: Setup Wizard not complete."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Login"
 | 
			
		||||
  _username_encoded="$(printf "%s" "$RUCKUS_USER" | _url_encode)"
 | 
			
		||||
  _password_encoded="$(printf "%s" "$RUCKUS_PASS" | _url_encode)"
 | 
			
		||||
  _login_query="$(printf "%s" "username=${_username_encoded}&password=${_password_encoded}&ok=Log+In")"
 | 
			
		||||
  _post "$_login_query" "$_login_url" >/dev/null
 | 
			
		||||
 | 
			
		||||
  _login_code="$(_response_code)"
 | 
			
		||||
  if [ "$_login_code" = "200" ]; then
 | 
			
		||||
    _err "Login failed: incorrect credentials."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Collect Session Cookie"
 | 
			
		||||
  _H1="Cookie: $(_response_cookie)"
 | 
			
		||||
  export _H1
 | 
			
		||||
  _info "Collect CSRF Token"
 | 
			
		||||
  _H2="X-CSRF-Token: $(_response_header 'HTTP_X_CSRF_TOKEN')"
 | 
			
		||||
  export _H2
 | 
			
		||||
 | 
			
		||||
  _info "Uploading certificate"
 | 
			
		||||
  _post_upload "uploadcert" "$_cfullchain"
 | 
			
		||||
 | 
			
		||||
  _info "Uploading private key"
 | 
			
		||||
  _post_upload "uploadprivatekey" "$_ckey"
 | 
			
		||||
 | 
			
		||||
  _info "Replacing certificate"
 | 
			
		||||
  _replace_cert_ajax='<ajax-request action="docmd" comp="system" updater="rid.0.5" xcmd="replace-cert" checkAbility="6" timeout="-1"><xcmd cmd="replace-cert" cn="'$RUCKUS_HOST'"/></ajax-request>'
 | 
			
		||||
  _post "$_replace_cert_ajax" "$_base_url/_cmdstat.jsp" >/dev/null
 | 
			
		||||
 | 
			
		||||
  _info "Rebooting"
 | 
			
		||||
  _cert_reboot_ajax='<ajax-request action="docmd" comp="worker" updater="rid.0.5" xcmd="cert-reboot" checkAbility="6"><xcmd cmd="cert-reboot" action="undefined"/></ajax-request>'
 | 
			
		||||
  _post "$_cert_reboot_ajax" "$_base_url/_cmdstat.jsp" >/dev/null
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_response_code() {
 | 
			
		||||
  _egrep_o <"$HTTP_HEADER" "^HTTP[^ ]* .*$" | cut -d " " -f 2-100 | tr -d "\f\n" | _egrep_o "^[0-9]*"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_response_header() {
 | 
			
		||||
  grep <"$HTTP_HEADER" -i "^$1:" | cut -d ':' -f 2- | tr -d "\r\n\t "
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_response_cookie() {
 | 
			
		||||
  _response_header 'Set-Cookie' | sed 's/;.*//'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_post_upload() {
 | 
			
		||||
  _post_action="$1"
 | 
			
		||||
  _post_file="$2"
 | 
			
		||||
 | 
			
		||||
  _post_boundary="----FormBoundary$(date "+%s%N")"
 | 
			
		||||
 | 
			
		||||
  _post_data="$({
 | 
			
		||||
    printf -- "--%s\r\n" "$_post_boundary"
 | 
			
		||||
    printf -- "Content-Disposition: form-data; name=\"u\"; filename=\"%s\"\r\n" "$_post_action"
 | 
			
		||||
    printf -- "Content-Type: application/octet-stream\r\n\r\n"
 | 
			
		||||
    printf -- "%s\r\n" "$(cat "$_post_file")"
 | 
			
		||||
 | 
			
		||||
    printf -- "--%s\r\n" "$_post_boundary"
 | 
			
		||||
    printf -- "Content-Disposition: form-data; name=\"action\"\r\n\r\n"
 | 
			
		||||
    printf -- "%s\r\n" "$_post_action"
 | 
			
		||||
 | 
			
		||||
    printf -- "--%s\r\n" "$_post_boundary"
 | 
			
		||||
    printf -- "Content-Disposition: form-data; name=\"callback\"\r\n\r\n"
 | 
			
		||||
    printf -- "%s\r\n" "uploader_$_post_action"
 | 
			
		||||
 | 
			
		||||
    printf -- "--%s--\r\n\r\n" "$_post_boundary"
 | 
			
		||||
  })"
 | 
			
		||||
 | 
			
		||||
  _post "$_post_data" "$_base_url/_upload.jsp?request_type=xhr" "" "" "multipart/form-data; boundary=$_post_boundary" >/dev/null
 | 
			
		||||
}
 | 
			
		||||
@@ -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"
 | 
			
		||||
 | 
			
		||||
  _confdir=$($_ipsec --confdir)
 | 
			
		||||
  if [ $? -ne 0 ] || [ -z "$_confdir" ]; then
 | 
			
		||||
    _err "no strongswan --confdir is detected"
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
__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
 | 
			
		||||
  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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
#
 | 
			
		||||
# Following environment variables must be set:
 | 
			
		||||
#
 | 
			
		||||
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI"
 | 
			
		||||
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI>"
 | 
			
		||||
#
 | 
			
		||||
# The following environmental variables may be set if you don't like their
 | 
			
		||||
# default values:
 | 
			
		||||
@@ -64,6 +64,20 @@ truenas_deploy() {
 | 
			
		||||
  _response=$(_get "$_api_url/system/state")
 | 
			
		||||
  _info "TrueNAS system state: $_response."
 | 
			
		||||
 | 
			
		||||
  _info "Getting TrueNAS version"
 | 
			
		||||
  _response=$(_get "$_api_url/system/version")
 | 
			
		||||
 | 
			
		||||
  if echo "$_response" | grep -q "SCALE"; then
 | 
			
		||||
    _truenas_os=$(echo "$_response" | cut -d '-' -f 2)
 | 
			
		||||
    _truenas_version=$(echo "$_response" | cut -d '-' -f 3 | tr -d '"' | cut -d '.' -f 1,2)
 | 
			
		||||
  else
 | 
			
		||||
    _truenas_os="unknown"
 | 
			
		||||
    _truenas_version="unknown"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Detected TrueNAS system os: $_truenas_os"
 | 
			
		||||
  _info "Detected TrueNAS system version: $_truenas_version"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$_response" ]; then
 | 
			
		||||
    _err "Unable to authenticate to $_api_url."
 | 
			
		||||
    _err 'Check your connection settings are correct, e.g.'
 | 
			
		||||
@@ -115,27 +129,106 @@ truenas_deploy() {
 | 
			
		||||
 | 
			
		||||
  _debug3 _activate_result "$_activate_result"
 | 
			
		||||
 | 
			
		||||
  _info "Checking if WebDAV certificate is the same as the TrueNAS web UI"
 | 
			
		||||
  _webdav_list=$(_get "$_api_url/webdav")
 | 
			
		||||
  _webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,')
 | 
			
		||||
  _truenas_version_23_10="23.10"
 | 
			
		||||
  _truenas_version_24_10="24.10"
 | 
			
		||||
 | 
			
		||||
  if [ "$_webdav_cert_id" = "$_active_cert_id" ]; then
 | 
			
		||||
    _info "Updating the WebDAV certificate"
 | 
			
		||||
    _debug _webdav_cert_id "$_webdav_cert_id"
 | 
			
		||||
    _webdav_data="{\"certssl\": \"${_cert_id}\"}"
 | 
			
		||||
    _activate_webdav_cert="$(_post "$_webdav_data" "$_api_url/webdav" "" "PUT" "application/json")"
 | 
			
		||||
    _webdav_new_cert_id=$(echo "$_activate_webdav_cert" | _json_decode | grep '"certssl":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
 | 
			
		||||
    if [ "$_webdav_new_cert_id" -eq "$_cert_id" ]; then
 | 
			
		||||
      _info "WebDAV certificate updated successfully"
 | 
			
		||||
    else
 | 
			
		||||
      _err "Unable to set WebDAV certificate"
 | 
			
		||||
      _debug3 _activate_webdav_cert "$_activate_webdav_cert"
 | 
			
		||||
  _check_version=$(printf "%s\n%s" "$_truenas_version_23_10" "$_truenas_version" | sort -V | head -n 1)
 | 
			
		||||
  if [ "$_truenas_os" != "SCALE" ] || [ "$_check_version" != "$_truenas_version_23_10" ]; then
 | 
			
		||||
    _info "Checking if WebDAV certificate is the same as the TrueNAS web UI"
 | 
			
		||||
    _webdav_list=$(_get "$_api_url/webdav")
 | 
			
		||||
    _webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,')
 | 
			
		||||
 | 
			
		||||
    if [ "$_webdav_cert_id" = "$_active_cert_id" ]; then
 | 
			
		||||
      _info "Updating the WebDAV certificate"
 | 
			
		||||
      _debug _webdav_cert_id "$_webdav_cert_id"
 | 
			
		||||
      _webdav_data="{\"certssl\": \"${_cert_id}\"}"
 | 
			
		||||
      _activate_webdav_cert="$(_post "$_webdav_data" "$_api_url/webdav" "" "PUT" "application/json")"
 | 
			
		||||
      _webdav_new_cert_id=$(echo "$_activate_webdav_cert" | _json_decode | grep '"certssl":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
 | 
			
		||||
      if [ "$_webdav_new_cert_id" -eq "$_cert_id" ]; then
 | 
			
		||||
        _info "WebDAV certificate updated successfully"
 | 
			
		||||
      else
 | 
			
		||||
        _err "Unable to set WebDAV certificate"
 | 
			
		||||
        _debug3 _activate_webdav_cert "$_activate_webdav_cert"
 | 
			
		||||
        _debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
      _debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
 | 
			
		||||
      return 1
 | 
			
		||||
    else
 | 
			
		||||
      _info "WebDAV certificate is not configured or is not the same as TrueNAS web UI"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _info "Checking if S3 certificate is the same as the TrueNAS web UI"
 | 
			
		||||
    _s3_list=$(_get "$_api_url/s3")
 | 
			
		||||
    _s3_cert_id=$(echo "$_s3_list" | grep '"certificate":' | tr -d -- '"certifa:_ ,')
 | 
			
		||||
 | 
			
		||||
    if [ "$_s3_cert_id" = "$_active_cert_id" ]; then
 | 
			
		||||
      _info "Updating the S3 certificate"
 | 
			
		||||
      _debug _s3_cert_id "$_s3_cert_id"
 | 
			
		||||
      _s3_data="{\"certificate\": \"${_cert_id}\"}"
 | 
			
		||||
      _activate_s3_cert="$(_post "$_s3_data" "$_api_url/s3" "" "PUT" "application/json")"
 | 
			
		||||
      _s3_new_cert_id=$(echo "$_activate_s3_cert" | _json_decode | grep '"certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
 | 
			
		||||
      if [ "$_s3_new_cert_id" -eq "$_cert_id" ]; then
 | 
			
		||||
        _info "S3 certificate updated successfully"
 | 
			
		||||
      else
 | 
			
		||||
        _err "Unable to set S3 certificate"
 | 
			
		||||
        _debug3 _activate_s3_cert "$_activate_s3_cert"
 | 
			
		||||
        _debug3 _s3_new_cert_id "$_s3_new_cert_id"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
      _debug3 _activate_s3_cert "$_activate_s3_cert"
 | 
			
		||||
    else
 | 
			
		||||
      _info "S3 certificate is not configured or is not the same as TrueNAS web UI"
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$_truenas_os" = "SCALE" ]; then
 | 
			
		||||
    _check_version=$(printf "%s\n%s" "$_truenas_version_24_10" "$_truenas_version" | sort -V | head -n 1)
 | 
			
		||||
    if [ "$_check_version" != "$_truenas_version_24_10" ]; then
 | 
			
		||||
      _info "Checking if any chart release Apps is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
 | 
			
		||||
      if _exists jq; then
 | 
			
		||||
        _info "Query all chart release"
 | 
			
		||||
        _release_list=$(_get "$_api_url/chart/release")
 | 
			
		||||
        _related_name_list=$(printf "%s" "$_release_list" | jq -r "[.[] | {name,certId: .config.ingress?.main.tls[]?.scaleCert} | select(.certId==$_active_cert_id) | .name ] | unique")
 | 
			
		||||
        _release_length=$(printf "%s" "$_related_name_list" | jq -r "length")
 | 
			
		||||
        _info "Found $_release_length related chart release in list: $_related_name_list"
 | 
			
		||||
        for i in $(seq 0 $((_release_length - 1))); do
 | 
			
		||||
          _release_name=$(echo "$_related_name_list" | jq -r ".[$i]")
 | 
			
		||||
          _info "Updating certificate from $_active_cert_id to $_cert_id for chart release: $_release_name"
 | 
			
		||||
          #Read the chart release configuration
 | 
			
		||||
          _chart_config=$(printf "%s" "$_release_list" | jq -r ".[] | select(.name==\"$_release_name\")")
 | 
			
		||||
          #Replace the old certificate id with the new one in path .config.ingress.main.tls[].scaleCert. Then update .config.ingress
 | 
			
		||||
          _updated_chart_config=$(printf "%s" "$_chart_config" | jq "(.config.ingress?.main.tls[]? | select(.scaleCert==$_active_cert_id) | .scaleCert  ) |= $_cert_id | .config.ingress ")
 | 
			
		||||
          _update_chart_result="$(_post "{\"values\" : { \"ingress\" : $_updated_chart_config } }" "$_api_url/chart/release/id/$_release_name" "" "PUT" "application/json")"
 | 
			
		||||
          _debug3 _update_chart_result "$_update_chart_result"
 | 
			
		||||
        done
 | 
			
		||||
      else
 | 
			
		||||
        _info "Tool 'jq' does not exists, skip chart release checking"
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      _info "Checking if any app is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
 | 
			
		||||
      if _exists jq; then
 | 
			
		||||
        _info "Query all apps"
 | 
			
		||||
        _app_list=$(_get "$_api_url/app")
 | 
			
		||||
        _app_id_list=$(printf "%s" "$_app_list" | jq -r '.[].name')
 | 
			
		||||
        _app_length=$(echo "$_app_id_list" | wc -l)
 | 
			
		||||
        _info "Found $_app_length apps"
 | 
			
		||||
        _info "Checking for each app if an update is needed"
 | 
			
		||||
        for i in $(seq 1 "$_app_length"); do
 | 
			
		||||
          _app_id=$(echo "$_app_id_list" | sed -n "${i}p")
 | 
			
		||||
          _app_config="$(_post "\"$_app_id\"" "$_api_url/app/config" "" "POST" "application/json")"
 | 
			
		||||
          # Check if the app use the same certificate TrueNAS web UI
 | 
			
		||||
          _app_active_cert_config=$(echo "$_app_config" | _json_decode | jq -r ".ix_certificates[\"$_active_cert_id\"]")
 | 
			
		||||
          if [ "$_app_active_cert_config" != "null" ]; then
 | 
			
		||||
            _info "Updating certificate from $_active_cert_id to $_cert_id for app: $_app_id"
 | 
			
		||||
            #Replace the old certificate id with the new one in path
 | 
			
		||||
            _update_app_result="$(_post "{\"values\" : { \"network\": { \"certificate_id\": $_cert_id } } }" "$_api_url/app/id/$_app_id" "" "PUT" "application/json")"
 | 
			
		||||
            _debug3 _update_app_result "$_update_app_result"
 | 
			
		||||
          fi
 | 
			
		||||
        done
 | 
			
		||||
      else
 | 
			
		||||
        _info "Tool 'jq' does not exists, skip app checking"
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    _debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
 | 
			
		||||
  else
 | 
			
		||||
    _info "WebDAV certificate is not configured or is not the same as TrueNAS web UI"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Checking if FTP certificate is the same as the TrueNAS web UI"
 | 
			
		||||
@@ -161,50 +254,6 @@ truenas_deploy() {
 | 
			
		||||
    _info "FTP certificate is not configured or is not the same as TrueNAS web UI"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Checking if S3 certificate is the same as the TrueNAS web UI"
 | 
			
		||||
  _s3_list=$(_get "$_api_url/s3")
 | 
			
		||||
  _s3_cert_id=$(echo "$_s3_list" | grep '"certificate":' | tr -d -- '"certifa:_ ,')
 | 
			
		||||
 | 
			
		||||
  if [ "$_s3_cert_id" = "$_active_cert_id" ]; then
 | 
			
		||||
    _info "Updating the S3 certificate"
 | 
			
		||||
    _debug _s3_cert_id "$_s3_cert_id"
 | 
			
		||||
    _s3_data="{\"certificate\": \"${_cert_id}\"}"
 | 
			
		||||
    _activate_s3_cert="$(_post "$_s3_data" "$_api_url/s3" "" "PUT" "application/json")"
 | 
			
		||||
    _s3_new_cert_id=$(echo "$_activate_s3_cert" | _json_decode | grep '"certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
 | 
			
		||||
    if [ "$_s3_new_cert_id" -eq "$_cert_id" ]; then
 | 
			
		||||
      _info "S3 certificate updated successfully"
 | 
			
		||||
    else
 | 
			
		||||
      _err "Unable to set S3 certificate"
 | 
			
		||||
      _debug3 _activate_s3_cert "$_activate_s3_cert"
 | 
			
		||||
      _debug3 _s3_new_cert_id "$_s3_new_cert_id"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _debug3 _activate_s3_cert "$_activate_s3_cert"
 | 
			
		||||
  else
 | 
			
		||||
    _info "S3 certificate is not configured or is not the same as TrueNAS web UI"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Checking if any chart release Apps is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
 | 
			
		||||
  if _exists jq; then
 | 
			
		||||
    _info "Query all chart release"
 | 
			
		||||
    _release_list=$(_get "$_api_url/chart/release")
 | 
			
		||||
    _related_name_list=$(printf "%s" "$_release_list" | jq -r "[.[] | {name,certId: .config.ingress?.main.tls[]?.scaleCert} | select(.certId==$_active_cert_id) | .name ] | unique")
 | 
			
		||||
    _release_length=$(printf "%s" "$_related_name_list" | jq -r "length")
 | 
			
		||||
    _info "Found $_release_length related chart release in list: $_related_name_list"
 | 
			
		||||
    for i in $(seq 0 $((_release_length - 1))); do
 | 
			
		||||
      _release_name=$(echo "$_related_name_list" | jq -r ".[$i]")
 | 
			
		||||
      _info "Updating certificate from $_active_cert_id to $_cert_id for chart release: $_release_name"
 | 
			
		||||
      #Read the chart release configuration
 | 
			
		||||
      _chart_config=$(printf "%s" "$_release_list" | jq -r ".[] | select(.name==\"$_release_name\")")
 | 
			
		||||
      #Replace the old certificate id with the new one in path .config.ingress.main.tls[].scaleCert. Then update .config.ingress
 | 
			
		||||
      _updated_chart_config=$(printf "%s" "$_chart_config" | jq "(.config.ingress?.main.tls[]? | select(.scaleCert==$_active_cert_id) | .scaleCert  ) |= $_cert_id | .config.ingress ")
 | 
			
		||||
      _update_chart_result="$(_post "{\"values\" : { \"ingress\" : $_updated_chart_config } }" "$_api_url/chart/release/id/$_release_name" "" "PUT" "application/json")"
 | 
			
		||||
      _debug3 _update_chart_result "$_update_chart_result"
 | 
			
		||||
    done
 | 
			
		||||
  else
 | 
			
		||||
    _info "Tool 'jq' does not exists, skip chart release checking"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Deleting old certificate"
 | 
			
		||||
  _delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,12 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# Alviy domain api
 | 
			
		||||
#
 | 
			
		||||
# Get API key and secret from https://cloud.alviy.com/token
 | 
			
		||||
#
 | 
			
		||||
# Alviy_token="some-secret-key"
 | 
			
		||||
#
 | 
			
		||||
# Ex.: acme.sh --issue --staging --dns dns_alviy -d "*.s.example.com" -d "s.example.com"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_alviy_info='Alviy.com
 | 
			
		||||
Site: Alviy.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_alviy
 | 
			
		||||
Options:
 | 
			
		||||
 Alviy_token API token. Get it from the https://cloud.alviy.com/token
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/5115
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
Alviy_Api="https://cloud.alviy.com/api/v1"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ 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
 | 
			
		||||
@@ -31,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
 | 
			
		||||
@@ -45,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=""
 | 
			
		||||
        AZUREDNS_BEARERTOKEN=""
 | 
			
		||||
        _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=""
 | 
			
		||||
      _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.
 | 
			
		||||
@@ -83,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"
 | 
			
		||||
@@ -147,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
 | 
			
		||||
@@ -155,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=""
 | 
			
		||||
        AZUREDNS_BEARERTOKEN=""
 | 
			
		||||
        _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=""
 | 
			
		||||
      _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"
 | 
			
		||||
@@ -295,7 +322,7 @@ _azure_getaccess_token() {
 | 
			
		||||
  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?
 | 
			
		||||
@@ -339,7 +366,7 @@ _azure_getaccess_token() {
 | 
			
		||||
    _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
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ Issues: github.com/acmesh-official/acme.sh/issues/3998
 | 
			
		||||
Author: Timur Umarov <inbox@tumarov.com>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
FORNEX_API_URL="https://fornex.com/api/dns/v0.1"
 | 
			
		||||
FORNEX_API_URL="https://fornex.com/api"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -97,11 +95,11 @@ _get_root() {
 | 
			
		||||
      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"
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,19 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_myapi_info='omg.lol
 | 
			
		||||
 Based on the omg.lol API, defined at https://api.omg.lol/
 | 
			
		||||
Domains: omg.lol
 | 
			
		||||
Site: github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_duckdns
 | 
			
		||||
dns_omglol_info='omg.lol
 | 
			
		||||
Site: omg.lol
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_omglol
 | 
			
		||||
Options:
 | 
			
		||||
 OMG_ApiKey API Key from omg.lol.  This is accesible from the bottom of the account page at https://home.omg.lol/account
 | 
			
		||||
 OMG_ApiKey API Key from omg.lol. This is accessible from the bottom of the account page at https://home.omg.lol/account
 | 
			
		||||
 OMG_Address This is your omg.lol address, without the preceding @ - you can see your list on your dashboard at https://home.omg.lol/dashboard
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/5299
 | 
			
		||||
Author: @Kholin <kholin+acme.omglolapi@omg.lol>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
# See API Docs https://api.omg.lol/
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
# Please Read this guide first: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
 | 
			
		||||
 | 
			
		||||
#Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_omglol_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
@@ -244,8 +240,8 @@ omg_delete() {
 | 
			
		||||
  omg_validate_delete "$output"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Validate the response on request to delete.  Confirm stastus is success and
 | 
			
		||||
# Message indicates deletion was successful
 | 
			
		||||
# Validate the response on request to delete.
 | 
			
		||||
# Confirm status is success and message indicates deletion was successful.
 | 
			
		||||
# Input: Response - HTTP response received from delete request
 | 
			
		||||
omg_validate_delete() {
 | 
			
		||||
  response=$1
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										56
									
								
								dnsapi/dns_technitium.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										56
									
								
								dnsapi/dns_technitium.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_Technitium_info='Technitium DNS Server
 | 
			
		||||
 | 
			
		||||
Site: https://technitium.com/dns/
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_technitium
 | 
			
		||||
Options:
 | 
			
		||||
 Technitium_Server Server Address
 | 
			
		||||
 Technitium_Token API Token
 | 
			
		||||
Issues:https://github.com/acmesh-official/acme.sh/issues/6116
 | 
			
		||||
Author: Henning Reich <acmesh@qupfer.de>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
dns_technitium_add() {
 | 
			
		||||
  _info "add txt Record using Technitium"
 | 
			
		||||
  _Technitium_account
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  response="$(_get "$Technitium_Server/api/zones/records/add?token=$Technitium_Token&domain=$fulldomain&type=TXT&text=${txtvalue}")"
 | 
			
		||||
  if _contains "$response" '"status":"ok"'; then
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
  _err "Could not add txt record."
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dns_technitium_rm() {
 | 
			
		||||
  _info "remove txt record using Technitium"
 | 
			
		||||
  _Technitium_account
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  response="$(_get "$Technitium_Server/api/zones/records/delete?token=$Technitium_Token&domain=$fulldomain&type=TXT&text=${txtvalue}")"
 | 
			
		||||
  if _contains "$response" '"status":"ok"'; then
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
  _err "Could not remove txt record"
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
_Technitium_account() {
 | 
			
		||||
  Technitium_Server="${Technitium_Server:-$(_readaccountconf_mutable Technitium_Server)}"
 | 
			
		||||
  Technitium_Token="${Technitium_Token:-$(_readaccountconf_mutable Technitium_Token)}"
 | 
			
		||||
  if [ -z "$Technitium_Server" ] || [ -z "$Technitium_Token" ]; then
 | 
			
		||||
    Technitium_Server=""
 | 
			
		||||
    Technitium_Token=""
 | 
			
		||||
    _err "You don't specify Technitium Server and Token yet."
 | 
			
		||||
    _err "Please create your Token and add server address and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the credentials to the account conf file.
 | 
			
		||||
  _saveaccountconf_mutable Technitium_Server "$Technitium_Server"
 | 
			
		||||
  _saveaccountconf_mutable Technitium_Token "$Technitium_Token"
 | 
			
		||||
}
 | 
			
		||||
@@ -1,16 +1,13 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# acme.sh DNS API for Timeweb Cloud provider (https://timeweb.cloud).
 | 
			
		||||
#
 | 
			
		||||
# Author: https://github.com/nikolaypronchev.
 | 
			
		||||
#
 | 
			
		||||
# Prerequisites:
 | 
			
		||||
# Timeweb Cloud API JWT token. Obtain one from the Timeweb Cloud control panel
 | 
			
		||||
# ("API and Terraform" section: https://timeweb.cloud/my/api-keys). The JWT token
 | 
			
		||||
# must be provided to this script in one of two ways:
 | 
			
		||||
# 1.  As the "TW_Token" variable, for example: "export TW_Token=eyJhbG...zUxMiIs";
 | 
			
		||||
# 2.  As a "TW_Token" config entry in acme.sh account config file
 | 
			
		||||
#     (usually located at ~/.acme.sh/account.conf by default).
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_timeweb_info='Timeweb.Cloud
 | 
			
		||||
Site: Timeweb.Cloud
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_timeweb
 | 
			
		||||
Options:
 | 
			
		||||
 TW_Token API JWT token. Get it from the control panel at https://timeweb.cloud/my/api-keys
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/5140
 | 
			
		||||
Author: Nikolay Pronchev <https://github.com/nikolaypronchev>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
TW_Api="https://api.timeweb.cloud/api/v1"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 '<ul class="nav header-paket-list">' | sed 's/<li/\n<li/g' | sed 's/<[^>]*>/ /g' | sed 's/^.*>\([^>]*\)$/\1/')
 | 
			
		||||
  _debug domains "$domains"
 | 
			
		||||
  domain=''
 | 
			
		||||
  for domain in $domains; do
 | 
			
		||||
    if _contains "$fqdn" "$domain\$"; then
 | 
			
		||||
@@ -217,7 +218,7 @@ _get_paketnr() {
 | 
			
		||||
  TLD="$domain"
 | 
			
		||||
  _debug domain "$domain"
 | 
			
		||||
  RECORD=$(echo "$fqdn" | cut -c"1-$((${#fqdn} - ${#TLD} - 1))")
 | 
			
		||||
  PAKETNR=$(echo "$domains" | grep "$domain" | sed 's/^[^,]*, *\([0-9]*\).*$/\1/')
 | 
			
		||||
  PAKETNR=$(echo "$domains" | grep -o " $domain.*" | sed 's/^[^,]*, *\([0-9]*\).*$/\1/')
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										145
									
								
								dnsapi/dns_zoneedit.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								dnsapi/dns_zoneedit.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# https://github.com/blueslow/sslcertzoneedit
 | 
			
		||||
 | 
			
		||||
# Only need to export the credentials once, acme.sh will save for automatic renewal.
 | 
			
		||||
# export ZONEEDIT_ID="Your id"
 | 
			
		||||
# export ZONEEDIT_Token="Your token"
 | 
			
		||||
# acme.sh --issue --dns dns_zoneedit -d example.com -d www.example.com
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
# Usage: dns_zoneedit_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_zoneedit_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _info "Using Zoneedit"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  # Load the credentials from the account conf file
 | 
			
		||||
  ZONEEDIT_ID="${ZONEEDIT_ID:-$(_readaccountconf_mutable ZONEEDIT_ID)}"
 | 
			
		||||
  ZONEEDIT_Token="${ZONEEDIT_Token:-$(_readaccountconf_mutable ZONEEDIT_Token)}"
 | 
			
		||||
  if [ -z "$ZONEEDIT_ID" ] || [ -z "$ZONEEDIT_Token" ]; then
 | 
			
		||||
    ZONEEDIT_ID=""
 | 
			
		||||
    ZONEEDIT_Token=""
 | 
			
		||||
    _err "Please specify ZONEEDIT_ID and _Token."
 | 
			
		||||
    _err "Please export as ZONEEDIT_ID and ZONEEDIT_Token then try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Save the credentials to the account conf file
 | 
			
		||||
  _saveaccountconf_mutable ZONEEDIT_ID "$ZONEEDIT_ID"
 | 
			
		||||
  _saveaccountconf_mutable ZONEEDIT_Token "$ZONEEDIT_Token"
 | 
			
		||||
 | 
			
		||||
  if _zoneedit_api "CREATE" "$fulldomain" "$txtvalue"; then
 | 
			
		||||
    _info "Added, OK"
 | 
			
		||||
    return 0
 | 
			
		||||
  else
 | 
			
		||||
    _err "Add txt record error."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Usage: dns_zoneedit_rm   fulldomain   txtvalue
 | 
			
		||||
dns_zoneedit_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _info "Using Zoneedit"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  # Load the credentials from the account conf file
 | 
			
		||||
  ZONEEDIT_ID="${ZONEEDIT_ID:-$(_readaccountconf_mutable ZONEEDIT_ID)}"
 | 
			
		||||
  ZONEEDIT_Token="${ZONEEDIT_Token:-$(_readaccountconf_mutable ZONEEDIT_Token)}"
 | 
			
		||||
  if [ -z "$ZONEEDIT_ID" ] || [ -z "$ZONEEDIT_Token" ]; then
 | 
			
		||||
    ZONEEDIT_ID=""
 | 
			
		||||
    ZONEEDIT_Token=""
 | 
			
		||||
    _err "Please specify ZONEEDIT_ID and _Token."
 | 
			
		||||
    _err "Please export as ZONEEDIT_ID and ZONEEDIT_Token then try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if _zoneedit_api "DELETE" "$fulldomain" "$txtvalue"; then
 | 
			
		||||
    _info "Deleted, OK"
 | 
			
		||||
    return 0
 | 
			
		||||
  else
 | 
			
		||||
    _err "Delete txt record error."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
#Usage: _zoneedit_api   <CREATE|DELETE>   fulldomain   txtvalue
 | 
			
		||||
_zoneedit_api() {
 | 
			
		||||
  cmd=$1
 | 
			
		||||
  fulldomain=$2
 | 
			
		||||
  txtvalue=$3
 | 
			
		||||
 | 
			
		||||
  # Construct basic authorization header
 | 
			
		||||
  credentials=$(printf "%s:%s" "$ZONEEDIT_ID" "$ZONEEDIT_Token" | _base64)
 | 
			
		||||
  export _H1="Authorization: Basic ${credentials}"
 | 
			
		||||
 | 
			
		||||
  # Generate request URL
 | 
			
		||||
  case "$cmd" in
 | 
			
		||||
  "CREATE")
 | 
			
		||||
    # https://dynamic.zoneedit.com/txt-create.php?host=_acme-challenge.example.com&rdata=depE1VF_xshMm1IVY1Y56Kk9Zb_7jA2VFkP65WuNgu8W
 | 
			
		||||
    geturl="https://dynamic.zoneedit.com/txt-create.php?host=${fulldomain}&rdata=${txtvalue}"
 | 
			
		||||
    ;;
 | 
			
		||||
  "DELETE")
 | 
			
		||||
    # https://dynamic.zoneedit.com/txt-delete.php?host=_acme-challenge.example.com&rdata=depE1VF_xshMm1IVY1Y56Kk9Zb_7jA2VFkP65WuNgu8W
 | 
			
		||||
    geturl="https://dynamic.zoneedit.com/txt-delete.php?host=${fulldomain}&rdata=${txtvalue}"
 | 
			
		||||
    ze_sleep=2
 | 
			
		||||
    ;;
 | 
			
		||||
  *)
 | 
			
		||||
    _err "Unknown parameter : $cmd"
 | 
			
		||||
    return 1
 | 
			
		||||
    ;;
 | 
			
		||||
  esac
 | 
			
		||||
 | 
			
		||||
  # Execute request
 | 
			
		||||
  i=3 # Tries
 | 
			
		||||
  while [ "$i" -gt 0 ]; do
 | 
			
		||||
    i=$(_math "$i" - 1)
 | 
			
		||||
 | 
			
		||||
    if ! response=$(_get "$geturl"); then
 | 
			
		||||
      _err "_get() failed ($response)"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _debug2 response "$response"
 | 
			
		||||
    if _contains "$response" "SUCCESS.*200"; then
 | 
			
		||||
      # Sleep (when needed) to work around a Zonedit API bug
 | 
			
		||||
      # https://forum.zoneedit.com/threads/automating-changes-of-txt-records-in-dns.7394/page-2#post-23855
 | 
			
		||||
      if [ "$ze_sleep" ]; then _sleep "$ze_sleep"; fi
 | 
			
		||||
      return 0
 | 
			
		||||
    elif _contains "$response" "ERROR.*Minimum.*seconds"; then
 | 
			
		||||
      _info "Zoneedit responded with a rate limit of..."
 | 
			
		||||
      ze_ratelimit=$(echo "$response" | sed -n 's/.*Minimum \([0-9]\+\) seconds.*/\1/p')
 | 
			
		||||
      if [ "$ze_ratelimit" ] && [ ! "$(echo "$ze_ratelimit" | tr -d '0-9')" ]; then
 | 
			
		||||
        _info "$ze_ratelimit seconds."
 | 
			
		||||
      else
 | 
			
		||||
        _err "$response"
 | 
			
		||||
        _err "not a number, or blank ($ze_ratelimit), API change?"
 | 
			
		||||
        unset ze_ratelimit
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      _err "$response"
 | 
			
		||||
      _err "Unknown response, API change?"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Retry
 | 
			
		||||
    if [ "$i" -lt 1 ]; then
 | 
			
		||||
      _err "Tries exceeded, giving up."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$ze_ratelimit" ]; then
 | 
			
		||||
      _info "Waiting $ze_ratelimit seconds..."
 | 
			
		||||
      _sleep "$ze_ratelimit"
 | 
			
		||||
    else
 | 
			
		||||
      _err "Going to retry after 10 seconds..."
 | 
			
		||||
      _sleep 10
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user