neil
2 weeks ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 378 additions and 3 deletions
-
1.github/workflows/pr_dns.yml
-
172deploy/ruckus.sh
-
2dnsapi/dns_fornex.sh
-
56dnsapi/dns_technitium.sh
-
5dnsapi/dns_world4you.sh
-
145dnsapi/dns_zoneedit.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 |
|||
} |
@ -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" |
|||
} |
@ -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 |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue