Browse Source

Merge pull request #6160 from acmesh-official/dev

sync
neil 10 months ago
parent
commit
f981c782bb
6 changed files with 378 additions and 3 deletions
  1. 1 0
      .github/workflows/pr_dns.yml
  2. 172 0
      deploy/ruckus.sh
  3. 1 1
      dnsapi/dns_fornex.sh
  4. 56 0
      dnsapi/dns_technitium.sh
  5. 3 2
      dnsapi/dns_world4you.sh
  6. 145 0
      dnsapi/dns_zoneedit.sh

+ 1 - 0
.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, 都必须确保通过这个测试.
                 `

+ 172 - 0
deploy/ruckus.sh

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

+ 1 - 1
dnsapi/dns_fornex.sh

@@ -88,7 +88,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

+ 56 - 0
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 <[email protected]>
+'
+
+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"
+}

+ 3 - 2
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 '<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 - 0
dnsapi/dns_zoneedit.sh

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