diff --git a/.github/workflows/wiki-monitor.yml b/.github/workflows/wiki-monitor.yml new file mode 100644 index 00000000..89497580 --- /dev/null +++ b/.github/workflows/wiki-monitor.yml @@ -0,0 +1,60 @@ +name: Notify via Issue on Wiki Edit + +on: + gollum: + +jobs: + notify: + runs-on: ubuntu-latest + steps: + - name: Checkout wiki repository + uses: actions/checkout@v4 + with: + repository: ${{ github.repository }}.wiki + path: wiki + + - name: Generate wiki change message + run: | + actor="${{ github.actor }}" + sender_url=$(jq -r '.sender.html_url' "$GITHUB_EVENT_PATH") + page_name=$(jq -r '.pages[0].page_name' "$GITHUB_EVENT_PATH") + page_sha=$(jq -r '.pages[0].sha' "$GITHUB_EVENT_PATH") + page_url=$(jq -r '.pages[0].html_url' "$GITHUB_EVENT_PATH") + page_action=$(jq -r '.pages[0].action' "$GITHUB_EVENT_PATH") + now="$(date '+%Y-%m-%d %H:%M:%S')" + + cd wiki + prev_sha=$(git rev-list $page_sha^ -- "$page_name.md" | head -n 1) + if [ -n "$prev_sha" ]; then + git diff $prev_sha $page_sha -- "$page_name.md" > ../wiki.diff || echo "(No diff found)" > ../wiki.diff + else + echo "(no diff)" > ../wiki.diff + fi + cd .. + { + echo "Wiki edited" + echo -n "User: " + echo "[$actor]($sender_url)" + echo "Time: $now" + echo "Page: [$page_name]($page_url) (Action: $page_action)" + echo "" + echo "----" + echo "### diff:" + echo '```diff' + cat wiki.diff + echo '```' + } > wiki-change-msg.txt + + - name: Create issue to notify Neilpang + uses: peter-evans/create-issue-from-file@v5 + with: + title: "Wiki edited" + content-filepath: ./wiki-change-msg.txt + assignees: Neilpang + env: + TZ: Asia/Shanghai + + + + + diff --git a/acme.sh b/acme.sh index e9eb6b94..d70e323b 100755 --- a/acme.sh +++ b/acme.sh @@ -1401,6 +1401,12 @@ _ss() { return 0 fi + if [ "$(uname)" = "AIX" ]; then + _debug "Using: AIX netstat" + netstat -an | grep "^tcp" | grep "LISTEN" | grep "\.$_port " + return 0 + fi + if _exists "netstat"; then _debug "Using: netstat" if netstat -help 2>&1 | grep "\-p proto" >/dev/null; then @@ -2761,7 +2767,7 @@ _initAPI() { _request_retry_times=0 while [ -z "$ACME_NEW_ACCOUNT" ] && [ "${_request_retry_times}" -lt "$MAX_API_RETRY_TIMES" ]; do _request_retry_times=$(_math "$_request_retry_times" + 1) - response=$(_get "$_api_server") + response=$(_get "$_api_server" "" 10) if [ "$?" != "0" ]; then _debug2 "response" "$response" _info "Cannot init API for: $_api_server." diff --git a/deploy/kemplm.sh b/deploy/kemplm.sh new file mode 100755 index 00000000..e44e06dc --- /dev/null +++ b/deploy/kemplm.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to a Kemp Loadmaster. + +#returns 0 means success, otherwise error. + +#DEPLOY_KEMP_TOKEN="token" +#DEPLOY_KEMP_URL="https://kemplm.example.com" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +kemplm_deploy() { + _domain="$1" + _key_file="$2" + _cert_file="$3" + _ca_file="$4" + _fullchain_file="$5" + + _debug _domain "$_domain" + _debug _key_file "$_key_file" + _debug _cert_file "$_cert_file" + _debug _ca_file "$_ca_file" + _debug _fullchain_file "$_fullchain_file" + + if ! _exists jq; then + _err "jq not found" + return 1 + fi + + # Rename wildcard certs, kemp accepts only alphanumeric names so we delete '*.' from filename + _kemp_domain=$(echo "${_domain}" | sed 's/\*\.//') + _debug _kemp_domain "$_kemp_domain" + + # Read config from saved values or env + _getdeployconf DEPLOY_KEMP_TOKEN + _getdeployconf DEPLOY_KEMP_URL + + _debug DEPLOY_KEMP_URL "$DEPLOY_KEMP_URL" + _secure_debug DEPLOY_KEMP_TOKEN "$DEPLOY_KEMP_TOKEN" + + if [ -z "$DEPLOY_KEMP_TOKEN" ]; then + _err "Kemp Loadmaster token is not found, please define DEPLOY_KEMP_TOKEN." + return 1 + fi + if [ -z "$DEPLOY_KEMP_URL" ]; then + _err "Kemp Loadmaster URL is not found, please define DEPLOY_KEMP_URL." + return 1 + fi + + # Save current values + _savedeployconf DEPLOY_KEMP_TOKEN "$DEPLOY_KEMP_TOKEN" + _savedeployconf DEPLOY_KEMP_URL "$DEPLOY_KEMP_URL" + + # Check if certificate is already installed + _info "Check if certificate is already present" + _list_request="{\"cmd\": \"listcert\", \"apikey\": \"${DEPLOY_KEMP_TOKEN}\"}" + _debug3 _list_request "${_list_request}" + _kemp_cert_count=$(HTTPS_INSECURE=1 _post "${_list_request}" "${DEPLOY_KEMP_URL}/accessv2" | jq -r '.cert[] | .name' | grep -c "${_kemp_domain}") + _debug2 _kemp_cert_count "${_kemp_cert_count}" + + _kemp_replace_cert=1 + if [ "${_kemp_cert_count}" -eq 0 ]; then + _kemp_replace_cert=0 + _info "Certificate does not exist on Kemp Loadmaster" + else + _info "Certificate already exists on Kemp Loadmaster" + fi + _debug _kemp_replace_cert "${_kemp_replace_cert}" + + # Upload new certificate to Kemp Loadmaster + _kemp_upload_cert=$(_mktemp) + cat "${_fullchain_file}" "${_key_file}" | base64 | tr -d '\n' >"${_kemp_upload_cert}" + + _info "Uploading certificate to Kemp Loadmaster" + _add_data=$(cat "${_kemp_upload_cert}") + _add_request="{\"cmd\": \"addcert\", \"apikey\": \"${DEPLOY_KEMP_TOKEN}\", \"replace\": ${_kemp_replace_cert}, \"cert\": \"${_kemp_domain}\", \"data\": \"${_add_data}\"}" + _debug3 _add_request "${_add_request}" + _kemp_post_result=$(HTTPS_INSECURE=1 _post "${_add_request}" "${DEPLOY_KEMP_URL}/accessv2") + _retval=$? + _debug2 _kemp_post_result "${_kemp_post_result}" + if [ "${_retval}" -eq 0 ]; then + _kemp_post_status=$(echo "${_kemp_post_result}" | jq -r '.status') + _kemp_post_message=$(echo "${_kemp_post_result}" | jq -r '.message') + if [ "${_kemp_post_status}" = "ok" ]; then + _info "Upload successful" + else + _err "Upload failed: ${_kemp_post_message}" + fi + else + _err "Upload failed" + _retval=1 + fi + + rm "${_kemp_upload_cert}" + + return $_retval +} diff --git a/deploy/zyxel_gs1900.sh b/deploy/zyxel_gs1900.sh new file mode 100644 index 00000000..37cf6005 --- /dev/null +++ b/deploy/zyxel_gs1900.sh @@ -0,0 +1,500 @@ +#!/usr/bin/env sh + +# Deploy certificates to Zyxel GS1900 series switches +# +# This script uses the https web administration interface in order +# to upload updated certificates to Zyxel GS1900 series switches. +# Only a few models have been tested but untested switches from the +# same model line may work as well. If you test and confirm a switch +# as working please submit a pull request updating this compatibility +# list! +# +# Known Issues: +# 1. This is a consumer grade switch and is a bit underpowered +# the longer the RSA key size the slower your switch web UI +# will be. RSA 2048 will work, RSA 4096 will work but you may +# experience performance problems. +# 2. You must use RSA certificates. The switch will reject EC-256 +# and EC-384 certificates in firmware 2.80 +# See: https://community.zyxel.com/en/discussion/21506/bug-cannot-import-ssl-cert-on-gs1900-8-and-gs1900-24e-firmware-v2-80/ +# +# Current GS1900 Switch Compatibility: +# GS1900-8 - Working as of firmware V2.80 +# GS1900-8HP - Untested +# GS1900-10HP - Untested +# GS1900-16 - Untested +# GS1900-24 - Untested +# GS1900-24E - Working as of firmware V2.80 +# GS1900-24EP - Untested +# GS1900-24HP - Untested +# GS1900-48 - Untested +# GS1900-48HP - Untested +# +# Prerequisite Setup Steps: +# 1. Install at least firmware V2.80 on your switch +# 2. Enable HTTPS web management on your switch +# +# Usage: +# 1. Ensure the switch has firmware V2.80 or later. +# 2. Ensure the switch has HTTPS management enabled. +# 3. Set the appropriate environment variables for your environment. +# +# DEPLOY_ZYXEL_SWITCH - The switch hostname. (Default: _cdomain) +# DEPLOY_ZYXEL_SWITCH_USER - The webadmin user. (Default: admin) +# DEPLOY_ZYXEL_SWITCH_PASSWORD - The webadmin password for the switch. +# DEPLOY_ZYXEL_SWITCH_REBOOT - If "1" reboot after update. (Default: "0") +# +# 4. Run the deployment plugin: +# acme.sh --deploy --deploy-hook zyxel_gs1900 -d example.com +# +# returns 0 means success, otherwise error. + +#domain keyfile certfile cafile fullchain +zyxel_gs1900_deploy() { + _zyxel_gs1900_minimum_firmware_version="v2.80" + + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug2 _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _getdeployconf DEPLOY_ZYXEL_SWITCH + _getdeployconf DEPLOY_ZYXEL_SWITCH_USER + _getdeployconf DEPLOY_ZYXEL_SWITCH_PASSWORD + _getdeployconf DEPLOY_ZYXEL_SWITCH_REBOOT + + if [ -z "$DEPLOY_ZYXEL_SWITCH" ]; then + DEPLOY_ZYXEL_SWITCH="$_cdomain" + fi + + if [ -z "$DEPLOY_ZYXEL_SWITCH_USER" ]; then + DEPLOY_ZYXEL_SWITCH_USER="admin" + fi + + if [ -z "$DEPLOY_ZYXEL_SWITCH_PASSWORD" ]; then + DEPLOY_ZYXEL_SWITCH_PASSWORD="1234" + fi + + if [ -z "$DEPLOY_ZYXEL_SWITCH_REBOOT" ]; then + DEPLOY_ZYXEL_SWITCH_REBOOT="0" + fi + + _savedeployconf DEPLOY_ZYXEL_SWITCH "$DEPLOY_ZYXEL_SWITCH" + _savedeployconf DEPLOY_ZYXEL_SWITCH_USER "$DEPLOY_ZYXEL_SWITCH_USER" + _savedeployconf DEPLOY_ZYXEL_SWITCH_PASSWORD "$DEPLOY_ZYXEL_SWITCH_PASSWORD" + _savedeployconf DEPLOY_ZYXEL_SWITCH_REBOOT "$DEPLOY_ZYXEL_SWITCH_REBOOT" + + _debug DEPLOY_ZYXEL_SWITCH "$DEPLOY_ZYXEL_SWITCH" + _debug DEPLOY_ZYXEL_SWITCH_USER "$DEPLOY_ZYXEL_SWITCH_USER" + _secure_debug DEPLOY_ZYXEL_SWITCH_PASSWORD "$DEPLOY_ZYXEL_SWITCH_PASSWORD" + _debug DEPLOY_ZYXEL_SWITCH_REBOOT "$DEPLOY_ZYXEL_SWITCH_REBOOT" + + _zyxel_switch_base_uri="https://${DEPLOY_ZYXEL_SWITCH}" + + _info "Beginning to deploy to a Zyxel GS1900 series switch at ${_zyxel_switch_base_uri}." + _zyxel_gs1900_deployment_precheck || return $? + + _zyxel_gs1900_should_update + if [ "$?" != "0" ]; then + _info "The switch already has our certificate installed. No update required." + return 0 + else + _info "The switch does not yet have our certificate installed." + fi + + _info "Logging into the switch web interface." + _zyxel_gs1900_login || return $? + + _info "Validating the switch is compatible with this deployment process." + _zyxel_gs1900_validate_device_compatibility || return $? + + _info "Uploading the certificate." + _zyxel_gs1900_upload_certificate || return $? + + if [ "$DEPLOY_ZYXEL_SWITCH_REBOOT" = "1" ]; then + _info "Rebooting the switch." + _zyxel_gs1900_trigger_reboot || return $? + fi + + return 0 +} + +_zyxel_gs1900_deployment_precheck() { + # Initialize the keylength if it isn't already + if [ -z "$Le_Keylength" ]; then + Le_Keylength="" + fi + + if _isEccKey "$Le_Keylength"; then + _info "Warning: Zyxel GS1900 switches are not currently known to work with ECC keys!" + _info "You can continue, but your switch may reject your key." + elif [ -n "$Le_Keylength" ] && [ "$Le_Keylength" -gt "2048" ]; then + _info "Warning: Your RSA key length is greater than 2048!" + _info "You can continue, but you may experience performance issues in the web administration interface." + fi + + # Check the server for some common failure modes prior to authentication and certificate upload in order to avoid + # sending a certificate when we may not want to. + test_login_response=$(_post "username=test&password=test&login=true;" "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi?cmd=0.html" '' "POST" "application/x-www-form-urlencoded" 2>&1) + test_login_page_exitcode="$?" + _debug3 "Test Login Response: ${test_login_response}" + if [ "$test_login_page_exitcode" -ne "0" ]; then + if { [ "${ACME_USE_WGET:-0}" = "0" ] && [ "$test_login_page_exitcode" = "60" ]; } || { [ "${ACME_USE_WGET:-0}" = "1" ] && [ "$test_login_page_exitcode" = "5" ]; }; then + _err "The SSL certificate at $_zyxel_switch_base_uri could not be validated." + _err "Please double check your hostname, port, and that you are actually connecting to your switch." + _err "If the problem persists then please ensure that the certificate is not self-signed, has not" + _err "expired, and matches the switch hostname. If you expect validation to fail then you can disable" + _err "certificate validation by running with --insecure." + return 1 + elif [ "${ACME_USE_WGET:-0}" = "0" ] && [ "$test_login_page_exitcode" = "56" ]; then + _debug3 "Intentionally ignore curl exit code 56 in our precheck" + else + _err "Failed to submit the initial login attempt to $_zyxel_switch_base_uri." + return 1 + fi + fi +} + +_zyxel_gs1900_login() { + # Login to the switch and set the appropriate auth cookie in _H1 + username_encoded=$(printf "%s" "$DEPLOY_ZYXEL_SWITCH_USER" | _url_encode) + password_encoded=$(_zyxel_gs1900_password_obfuscate "$DEPLOY_ZYXEL_SWITCH_PASSWORD" | _url_encode) + + login_response=$(_post "username=${username_encoded}&password=${password_encoded}&login=true;" "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi?cmd=0.html" '' "POST" "application/x-www-form-urlencoded" | tr -d '\n') + auth_response=$(_post "authId=${login_response}&login_chk=true" "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi?cmd=0.html" '' "POST" "application/x-www-form-urlencoded" | tr -d '\n') + if [ "$auth_response" != "OK" ]; then + _err "Login failed due to invalid credentials." + _err "Please double check the configured username and password and try again." + return 1 + fi + + sessionid=$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'HTTPS_XSSID=[^;]*;' | tr -d ';') + _secure_debug2 "sessionid" "$sessionid" + + export _H1="Cookie: $sessionid" + _secure_debug2 "_H1" "$_H1" + + return 0 +} + +_zyxel_gs1900_validate_device_compatibility() { + # Check the switches model and firmware version and throw errors + # if this script isn't compatible. + device_info_html=$(_get "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi?cmd=12" | tr -d '\n') + + model_name=$(_zyxel_gs1900_get_model "$device_info_html") + _debug2 "model_name" "$model_name" + if [ -z "$model_name" ]; then + _err "Could not find the switch model name." + _err "Please re-run with --debug and report a bug." + return $? + fi + + if ! expr "$model_name" : "GS1900-" >/dev/null; then + _err "Switch is an unsupported model: $model_name" + return 1 + fi + + firmware_version=$(_zyxel_gs1900_get_firmware_version "$device_info_html") + _debug2 "firmware_version" "$firmware_version" + if [ -z "$firmware_version" ]; then + _err "Could not find the switch firmware version." + _err "Please re-run with --debug and report a bug." + return $? + fi + + _debug2 "_zyxel_gs1900_minimum_firmware_version" "$_zyxel_gs1900_minimum_firmware_version" + minimum_major_version=$(_zyxel_gs1900_parse_major_version "$_zyxel_gs1900_minimum_firmware_version") + _debug2 "minimum_major_version" "$minimum_major_version" + minimum_minor_version=$(_zyxel_gs1900_parse_minor_version "$_zyxel_gs1900_minimum_firmware_version") + _debug2 "minimum_minor_version" "$minimum_minor_version" + + _debug2 "firmware_version" "$firmware_version" + firmware_major_version=$(_zyxel_gs1900_parse_major_version "$firmware_version") + _debug2 "firmware_major_version" "$firmware_major_version" + firmware_minor_version=$(_zyxel_gs1900_parse_minor_version "$firmware_version") + _debug2 "firmware_minor_version" "$firmware_minor_version" + + _ret=0 + if [ "$firmware_major_version" -lt "$minimum_major_version" ]; then + _ret=1 + elif [ "$firmware_major_version" -eq "$minimum_major_version" ] && [ "$firmware_minor_version" -lt "$minimum_minor_version" ]; then + _ret=1 + fi + + if [ "$_ret" != "0" ]; then + _err "Unsupported firmware version $firmware_version. Please upgrade to at least version $_zyxel_gs1900_minimum_firmware_version." + fi + + return $? +} + +_zyxel_gs1900_should_update() { + # Get the remote certificate serial number + _remote_cert=$(${ACME_OPENSSL_BIN:-openssl} s_client -showcerts -connect "${DEPLOY_ZYXEL_SWITCH}:443" 2>/dev/null "${upload_post_request}" + + _info "Upload certificate to the switch" + + # Unfortunately we cannot rely upon the switch response across switch models + # to return a consistent body return - so we cannot inspect the result of this + # upload to determine success. + upload_response=$(_zyxel_upload_pkcs12 "${upload_post_request}" "${upload_post_boundary}" 2>&1) + _debug3 "Upload response: ${upload_response}" + rm "${upload_post_request}" + + # Pause for a few seconds to give the switch a chance to process the certificate + # For some reason I've found this to be necessary on my GS1900-24E + _debug2 "Waiting 4 seconds for the switch to process the newly uploaded certificate." + sleep "4" + + # Check to see whether or not our update was successful + _ret=0 + _zyxel_gs1900_should_update + if [ "$?" != "0" ]; then + _info "The certificate was updated successfully" + else + _ret=1 + _err "The certificate upload does not appear to have worked." + _err "The remote certificate does not match the certificate we tried to upload." + _err "Please re-run with --debug 2 and review for unexpected errors. If none can be found please submit a bug." + fi + + # ensure the temporary files are cleaned up + [ -f "${temp_pkcs12}" ] && rm -f "${temp_pkcs12}" + + return $_ret +} + +# make the certificate upload request using either +# --data binary with @ for file access in CURL +# or using --post-file for wget to ensure we upload +# the pkcs12 without getting tripped up on null bytes +# +# Usage _zyxel_upload_pkcs12 [body file name] [post boundary marker] +_zyxel_upload_pkcs12() { + bodyfilename="$1" + multipartformmarker="$2" + _post_url="${_zyxel_switch_base_uri}/cgi-bin/httpuploadcert.cgi" + httpmethod="POST" + _postContentType="multipart/form-data; boundary=${multipartformmarker}" + + if [ -z "$httpmethod" ]; then + httpmethod="POST" + fi + _debug $httpmethod + _debug "_post_url" "$_post_url" + _debug2 "bodyfilename" "$bodyfilename" + _debug2 "_postContentType" "$_postContentType" + + _inithttp + + if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then + _CURL="$_ACME_CURL" + if [ "$HTTPS_INSECURE" ]; then + _CURL="$_CURL --insecure " + fi + if [ "$httpmethod" = "HEAD" ]; then + _CURL="$_CURL -I " + fi + _debug "_CURL" "$_CURL" + + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data-binary "@${bodyfilename}" "$_post_url")" + + _ret="$?" + if [ "$_ret" != "0" ]; then + _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + _err "Here is the curl dump log:" + _err "$(cat "$_CURL_DUMP")" + fi + fi + elif [ "$_ACME_WGET" ]; then + _WGET="$_ACME_WGET" + if [ "$HTTPS_INSECURE" ]; then + _WGET="$_WGET --no-check-certificate " + fi + _debug "_WGET" "$_WGET" + + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-file="${bodyfilename}" "$_post_url" 2>"$HTTP_HEADER")" + + _ret="$?" + if [ "$_ret" = "8" ]; then + _ret=0 + _debug "wget returned 8 as the server returned a 'Bad Request' response. Let's process the response later." + fi + if [ "$_ret" != "0" ]; then + _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" + fi + if _contains "$_WGET" " -d "; then + # Demultiplex wget debug output + cat "$HTTP_HEADER" >&2 + _sed_i '/^[^ ][^ ]/d; /^ *$/d' "$HTTP_HEADER" + fi + # remove leading whitespaces from header to match curl format + _sed_i 's/^ //g' "$HTTP_HEADER" + else + _ret="$?" + _err "Neither curl nor wget have been found, cannot make $httpmethod request." + fi + _debug "_ret" "$_ret" + printf "%s" "$response" + return $_ret +} + +_zyxel_gs1900_trigger_reboot() { + # Trigger a reboot via the management reboot page in the web ui + reboot_page_html=$(_get "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi?cmd=5888" | tr -d '\n') + reboot_xss_value=$(printf "%s" "$reboot_page_html" | _egrep_o 'name="XSSID"\s*value="[^"]+"' | sed 's/^.*="\([^"]\{1,\}\)"$/\1/g') + _secure_debug2 "reboot_xss_value" "$reboot_xss_value" + + reboot_response_html=$(_post "XSSID=${reboot_xss_value}&cmd=5889&sysSubmit=Reboot" "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi" '' "POST" "application/x-www-form-urlencoded") + reboot_message=$(printf "%s" "$reboot_response_html" | tr -d '\t\r\n\v\f' | _egrep_o "Rebooting now...") + + if [ -z "$reboot_message" ]; then + _err "Failed to trigger switch reboot!" + return 1 + fi + + return 0 +} + +# password +_zyxel_gs1900_password_obfuscate() { + # Return the password obfuscated via the same method used by the + # switch's web UI login process + echo "$1" | awk '{ + encoded = ""; + password = $1; + allowed = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + len = length($1); + pwi = length($1); + + for (i=1; i <= (321 - pwi); i++) + { + if (0 == i % 5 && pwi > 0) + { + encoded = (encoded)(substr(password, pwi--, 1)); + } + else if (i == 123) + { + if (len < 10) + { + encoded = (encoded)(0); + } + else + { + encoded = (encoded)(int(len / 10)); + } + } + else if (i == 289) + { + encoded = (encoded)(len % 10) + } + else + { + encoded = (encoded)(substr(allowed, int(rand() * length(allowed)), 1)) + } + } + printf("%s", encoded); + }' +} + +# html label +_zyxel_html_table_lookup() { + # Look up a value in the html representing the status page of the switch + # when provided with the html of the page and the label (i.e. "Model Name:") + html="$1" + label=$(printf "%s" "$2" | tr -d ' ') + lookup_result=$(printf "%s" "$html" | tr -d "\t\r\n\v\f" | sed 's//\n/g' | sed 's/]*>//g' | tr -d ' ' | grep -i "$label" | sed "s/$label<\/td>\([^<]\{1,\}\)<\/td><\/tr>/\1/i") + printf "%s" "$lookup_result" + return 0 +} + +# html +_zyxel_gs1900_get_model() { + html="$1" + model_name=$(_zyxel_html_table_lookup "$html" "Model Name:") + printf "%s" "$model_name" +} + +# html +_zyxel_gs1900_get_firmware_version() { + html="$1" + firmware_version=$(_zyxel_html_table_lookup "$html" "Firmware Version:" | _egrep_o "V[^.]+.[^(]+") + printf "%s" "$firmware_version" +} + +# version_number +_zyxel_gs1900_parse_major_version() { + printf "%s" "$1" | sed 's/^V\([0-9]\{1,\}\).\{1,\}$/\1/gi' +} + +# version_number +_zyxel_gs1900_parse_minor_version() { + printf "%s" "$1" | sed 's/^.\{1,\}\.\([0-9]\{1,\}\)$/\1/gi' +} diff --git a/dnsapi/dns_beget.sh b/dnsapi/dns_beget.sh index aa43caed..5f3b1eb1 100755 --- a/dnsapi/dns_beget.sh +++ b/dnsapi/dns_beget.sh @@ -7,7 +7,7 @@ Options: BEGET_User API user BEGET_Password API password Issues: github.com/acmesh-official/acme.sh/issues/6200 -Author: ARNik arnik@arnik.ru +Author: ARNik ' Beget_Api="https://api.beget.com/api" diff --git a/dnsapi/dns_bookmyname.sh b/dnsapi/dns_bookmyname.sh index 668cf074..cf3f1e3e 100644 --- a/dnsapi/dns_bookmyname.sh +++ b/dnsapi/dns_bookmyname.sh @@ -7,7 +7,7 @@ Options: BOOKMYNAME_USERNAME Username BOOKMYNAME_PASSWORD Password Issues: github.com/acmesh-official/acme.sh/issues/3209 -Author: Neilpang +Author: @Neilpang ' ######## Public functions ##################### diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 8bb0e00d..23a219da 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -197,10 +197,11 @@ _dns_cloudns_http_api_call() { auth_user="auth-id=$CLOUDNS_AUTH_ID" fi + encoded_password=$(echo "$CLOUDNS_AUTH_PASSWORD" | tr -d "\n\r" | _url_encode) if [ -z "$2" ]; then - data="$auth_user&auth-password=$CLOUDNS_AUTH_PASSWORD" + data="$auth_user&auth-password=$encoded_password" else - data="$auth_user&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + data="$auth_user&auth-password=$encoded_password&$2" fi response="$(_get "$CLOUDNS_API/$method?$data")" diff --git a/dnsapi/dns_ddnss.sh b/dnsapi/dns_ddnss.sh index 118b148b..0ac353d4 100644 --- a/dnsapi/dns_ddnss.sh +++ b/dnsapi/dns_ddnss.sh @@ -6,7 +6,7 @@ Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ddnss Options: DDNSS_Token API Token Issues: github.com/acmesh-official/acme.sh/issues/2230 -Author: RaidenII, helbgd, mod242 +Author: @helbgd, @mod242 ' DDNSS_DNS_API="https://ddnss.de/upd.php" diff --git a/dnsapi/dns_dnshome.sh b/dnsapi/dns_dnshome.sh index 59828796..6d583246 100755 --- a/dnsapi/dns_dnshome.sh +++ b/dnsapi/dns_dnshome.sh @@ -7,7 +7,7 @@ Options: DNSHOME_Subdomain Subdomain DNSHOME_SubdomainPassword Subdomain Password Issues: github.com/acmesh-official/acme.sh/issues/3819 -Author: dnsHome.de https://github.com/dnsHome-de +Author: @dnsHome-de ' # Usage: add subdomain.ddnsdomain.tld "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index 71594873..33d401b0 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -5,7 +5,7 @@ Site: www.DuckDNS.org Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_duckdns Options: DuckDNS_Token API Token -Author: RaidenII +Author: @RaidenII ' DuckDNS_API="https://www.duckdns.org/update" diff --git a/dnsapi/dns_dyn.sh b/dnsapi/dns_dyn.sh index 94201923..9b1a97a2 100644 --- a/dnsapi/dns_dyn.sh +++ b/dnsapi/dns_dyn.sh @@ -8,7 +8,7 @@ Options: DYN_Customer Customer DYN_Username API Username DYN_Password Secret -Author: Gerd Naschenweng +Author: Gerd Naschenweng <@magicdude4eva> ' # Dyn Managed DNS API diff --git a/dnsapi/dns_dynv6.sh b/dnsapi/dns_dynv6.sh index 76af17f5..0c9491f8 100644 --- a/dnsapi/dns_dynv6.sh +++ b/dnsapi/dns_dynv6.sh @@ -8,7 +8,7 @@ Options: OptionsAlt: KEY Path to SSH private key file. E.g. "/root/.ssh/dynv6" Issues: github.com/acmesh-official/acme.sh/issues/2702 -Author: StefanAbl +Author: @StefanAbl ' dynv6_api="https://dynv6.com/api/v2" diff --git a/dnsapi/dns_easydns.sh b/dnsapi/dns_easydns.sh index 1c96ac8f..423def2b 100644 --- a/dnsapi/dns_easydns.sh +++ b/dnsapi/dns_easydns.sh @@ -7,7 +7,7 @@ Options: EASYDNS_Token API Token EASYDNS_Key API Key Issues: github.com/acmesh-official/acme.sh/issues/2647 -Author: Neilpang, wurzelpanzer +Author: @Neilpang, wurzelpanzer ' # API Documentation: https://sandbox.rest.easydns.net:3001/ diff --git a/dnsapi/dns_edgecenter.sh b/dnsapi/dns_edgecenter.sh index cdd150df..8f4ad171 100644 --- a/dnsapi/dns_edgecenter.sh +++ b/dnsapi/dns_edgecenter.sh @@ -1,13 +1,13 @@ #!/usr/bin/env sh # shellcheck disable=SC2034 - -# EdgeCenter DNS API integration for acme.sh -# Author: Konstantin Ruchev -dns_edgecenter_info='edgecenter DNS API -Site: https://edgecenter.ru -Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_edgecenter +dns_edgecenter_info='EdgeCenter.ru +Site: EdgeCenter.ru +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_edgecenter Options: - EDGECENTER_API_KEY auth APIKey' + EDGECENTER_API_KEY API Key +Issues: github.com/acmesh-official/acme.sh/issues/6313 +Author: Konstantin Ruchev +' EDGECENTER_API="https://api.edgecenter.ru" DOMAIN_TYPE= diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 114f30e0..13d9f68b 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -7,7 +7,7 @@ Options: FREEDNS_User Username FREEDNS_Password Password Issues: github.com/acmesh-official/acme.sh/issues/2305 -Author: David Kerr +Author: David Kerr <@dkerr64> ' ######## Public functions ##################### diff --git a/dnsapi/dns_freemyip.sh b/dnsapi/dns_freemyip.sh index 0bad3809..d598a657 100644 --- a/dnsapi/dns_freemyip.sh +++ b/dnsapi/dns_freemyip.sh @@ -1,11 +1,11 @@ #!/usr/bin/env sh # shellcheck disable=SC2034 dns_freemyip_info='FreeMyIP.com -Site: freemyip.com +Site: FreeMyIP.com Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_freemyip Options: FREEMYIP_Token API Token -Issues: github.com/acmesh-official/acme.sh/issues/{XXXX} +Issues: github.com/acmesh-official/acme.sh/issues/6247 Author: Recolic Keghart , @Giova96 ' diff --git a/dnsapi/dns_he_ddns.sh b/dnsapi/dns_he_ddns.sh index cd7d1ec2..1fe9a7fd 100644 --- a/dnsapi/dns_he_ddns.sh +++ b/dnsapi/dns_he_ddns.sh @@ -5,6 +5,7 @@ Site: dns.he.net Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_he_ddns Options: HE_DDNS_KEY The DDNS key +Issues: https://github.com/acmesh-official/acme.sh/issues/5238 Author: Markku Leiniö ' diff --git a/dnsapi/dns_joker.sh b/dnsapi/dns_joker.sh index 1fe33c67..401471be 100644 --- a/dnsapi/dns_joker.sh +++ b/dnsapi/dns_joker.sh @@ -7,7 +7,7 @@ Options: JOKER_USERNAME Username JOKER_PASSWORD Password Issues: github.com/acmesh-official/acme.sh/issues/2840 -Author: +Author: @aattww ' JOKER_API="https://svc.joker.com/nic/replace" diff --git a/dnsapi/dns_mijnhost.sh b/dnsapi/dns_mijnhost.sh index 9dafc702..9f5e7710 100644 --- a/dnsapi/dns_mijnhost.sh +++ b/dnsapi/dns_mijnhost.sh @@ -1,16 +1,15 @@ #!/usr/bin/env sh # shellcheck disable=SC2034 dns_mijnhost_info='mijn.host -Domains: mijn.host Site: mijn.host -Docs: https://mijn.host/api/doc/ -Issues: https://github.com/acmesh-official/acme.sh/issues/6177 -Author: peterv99 +Docs: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_mijnhost Options: MIJNHOST_API_KEY API Key +Issues: github.com/acmesh-official/acme.sh/issues/6177 +Author: @peterv99 ' -######## Public functions ###################### Constants for your mijn-host API +######## Public functions ###################### MIJNHOST_API="https://mijn.host/api/v2" # Add TXT record for domain verification diff --git a/dnsapi/dns_mydnsjp.sh b/dnsapi/dns_mydnsjp.sh index 336c4889..4dfffaaa 100755 --- a/dnsapi/dns_mydnsjp.sh +++ b/dnsapi/dns_mydnsjp.sh @@ -6,7 +6,7 @@ Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_mydnsjp Options: MYDNSJP_MasterID Master ID MYDNSJP_Password Password -Author: epgdatacapbon +Author: @tkmsst ' ######## Public functions ##################### diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 44549c9e..1062c849 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -6,7 +6,7 @@ Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_namecom Options: Namecom_Username Username Namecom_Token API Token -Author: RaidenII +Author: @RaidenII ' ######## Public functions ##################### diff --git a/dnsapi/dns_namesilo.sh b/dnsapi/dns_namesilo.sh index b31e32a1..5d47a59a 100755 --- a/dnsapi/dns_namesilo.sh +++ b/dnsapi/dns_namesilo.sh @@ -5,7 +5,7 @@ Site: NameSilo.com Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_namesilo Options: Namesilo_Key API Key -Author: meowthink +Author: @meowthink ' #Utilize API to finish dns-01 verifications. diff --git a/dnsapi/dns_pleskxml.sh b/dnsapi/dns_pleskxml.sh index 6b38abcb..465bcc60 100644 --- a/dnsapi/dns_pleskxml.sh +++ b/dnsapi/dns_pleskxml.sh @@ -8,7 +8,7 @@ Options: pleskxml_user Username pleskxml_pass Password Issues: github.com/acmesh-official/acme.sh/issues/2577 -Author: Stilez, +Author: @Stilez, @romanlum ' ## Plesk XML API described at: diff --git a/dnsapi/dns_schlundtech.sh b/dnsapi/dns_schlundtech.sh index 6d2930a2..21930110 100644 --- a/dnsapi/dns_schlundtech.sh +++ b/dnsapi/dns_schlundtech.sh @@ -7,7 +7,7 @@ Options: SCHLUNDTECH_USER Username SCHLUNDTECH_PASSWORD Password Issues: github.com/acmesh-official/acme.sh/issues/2246 -Author: +Author: @mod242 ' SCHLUNDTECH_API="https://gateway.schlundtech.de" diff --git a/dnsapi/dns_selectel.sh b/dnsapi/dns_selectel.sh index 434bc483..565f541b 100644 --- a/dnsapi/dns_selectel.sh +++ b/dnsapi/dns_selectel.sh @@ -1,27 +1,21 @@ #!/usr/bin/env sh # shellcheck disable=SC2034 - -# dns_selectel_info='Selectel.com -# Domains: Selectel.ru -# Site: Selectel.com -# Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_selectel -# Options: -# Variables that must be defined before running -# SL_Ver can take one of the values 'v1' or 'v2', default is 'v1' -# SL_Ver='v1', when using version API legacy (v1) -# SL_Ver='v2', when using version API actual (v2) -# when using API version v1, i.e. SL_Ver is 'v1' or not defined: -# SL_Key - API Key, required -# when using API version v2: -# SL_Ver - required as 'v2' -# SL_Login_ID - account ID, required -# SL_Project_Name - name project, required -# SL_Login_Name - service user name, required -# SL_Pswd - service user password, required -# SL_Expire - token lifetime in minutes (0-1440), default 1400 minutes -# -# Issues: github.com/acmesh-official/acme.sh/issues/5126 -# +dns_selectel_info='Selectel.com +Domains: Selectel.ru +Site: Selectel.com +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_selectel +Options: For old API version v1 (deprecated) + SL_Ver API version. Use "v1". + SL_Key API Key +OptionsAlt: For the current API version v2 + SL_Ver API version. Use "v2". + SL_Login_ID Account ID + SL_Project_Name Project name + SL_Login_Name Service user name + SL_Pswd Service user password + SL_Expire Token lifetime. In minutes (0-1440). Default "1400" +Issues: github.com/acmesh-official/acme.sh/issues/5126 +' SL_Api="https://api.selectel.ru/domains" auth_uri="https://cloud.api.selcloud.ru/identity/v3/auth/tokens" diff --git a/dnsapi/dns_spaceship.sh b/dnsapi/dns_spaceship.sh index 770e22cc..8fff4037 100644 --- a/dnsapi/dns_spaceship.sh +++ b/dnsapi/dns_spaceship.sh @@ -4,11 +4,11 @@ dns_spaceship_info='Spaceship.com Site: Spaceship.com Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_spaceship Options: - SPACESHIP_API_KEY Spaceship API Key - SPACESHIP_API_SECRET Spaceship API Secret - SPACESHIP_ROOT_DOMAIN (Optional) Manually specify the root domain if auto-detection fails + SPACESHIP_API_KEY API Key + SPACESHIP_API_SECRET API Secret + SPACESHIP_ROOT_DOMAIN Root domain. Manually specify the root domain if auto-detection fails. Optional. Issues: github.com/acmesh-official/acme.sh/issues/6304 -Author: Meow +Author: Meow <@Meo597> ' # Spaceship API diff --git a/dnsapi/dns_tele3.sh b/dnsapi/dns_tele3.sh index e5974951..3a3ccf8c 100644 --- a/dnsapi/dns_tele3.sh +++ b/dnsapi/dns_tele3.sh @@ -6,7 +6,7 @@ Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#tele3 Options: TELE3_Key API Key TELE3_Secret API Secret -Author: Roman Blizik +Author: Roman Blizik <@par-pa> ' TELE3_API="https://www.tele3.cz/acme/" diff --git a/dnsapi/dns_tencent.sh b/dnsapi/dns_tencent.sh index d82768b9..b148adc3 100644 --- a/dnsapi/dns_tencent.sh +++ b/dnsapi/dns_tencent.sh @@ -2,7 +2,7 @@ # shellcheck disable=SC2034 dns_tencent_info='Tencent.com Site: cloud.Tencent.com -Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_tencent +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_tencent Options: Tencent_SecretId Secret ID Tencent_SecretKey Secret Key diff --git a/dnsapi/dns_timeweb.sh b/dnsapi/dns_timeweb.sh index 544564ea..7040ac9a 100644 --- a/dnsapi/dns_timeweb.sh +++ b/dnsapi/dns_timeweb.sh @@ -6,7 +6,7 @@ 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 +Author: Nikolay Pronchev <@nikolaypronchev> ' TW_Api="https://api.timeweb.cloud/api/v1" diff --git a/dnsapi/dns_transip.sh b/dnsapi/dns_transip.sh index 2abbe34d..b3c5ed70 100644 --- a/dnsapi/dns_transip.sh +++ b/dnsapi/dns_transip.sh @@ -24,7 +24,7 @@ dns_transip_add() { _debug txtvalue="$txtvalue" _transip_setup "$fulldomain" || return 1 _info "Creating TXT record." - if ! _transip_rest POST "domains/$_domain/dns" "{\"dnsEntry\":{\"name\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"expire\":300}}"; then + if ! _transip_rest POST "domains/$_domain/dns" "{\"dnsEntry\":{\"name\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"expire\":60}}"; then _err "Could not add TXT record." return 1 fi @@ -38,7 +38,7 @@ dns_transip_rm() { _debug txtvalue="$txtvalue" _transip_setup "$fulldomain" || return 1 _info "Removing TXT record." - if ! _transip_rest DELETE "domains/$_domain/dns" "{\"dnsEntry\":{\"name\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"expire\":300}}"; then + if ! _transip_rest DELETE "domains/$_domain/dns" "{\"dnsEntry\":{\"name\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"expire\":60}}"; then _err "Could not remove TXT record $_sub_domain for $domain" return 1 fi diff --git a/dnsapi/dns_udr.sh b/dnsapi/dns_udr.sh index f9772e10..656a0557 100644 --- a/dnsapi/dns_udr.sh +++ b/dnsapi/dns_udr.sh @@ -7,7 +7,7 @@ Options: UDR_USER Username UDR_PASS Password Issues: github.com/acmesh-official/acme.sh/issues/3923 -Author: Andreas Scherer +Author: Andreas Scherer <@andischerer> ' UDR_API="https://api.domainreselling.de/api/call.cgi" diff --git a/dnsapi/dns_vscale.sh b/dnsapi/dns_vscale.sh index c3915c69..faf3105d 100755 --- a/dnsapi/dns_vscale.sh +++ b/dnsapi/dns_vscale.sh @@ -5,7 +5,7 @@ Site: vscale.io Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_vscale Options: VSCALE_API_KEY API Key -Author: Alex Loban +Author: Alex Loban <@LAV45> ' VSCALE_API_URL="https://api.vscale.io/v1" diff --git a/dnsapi/dns_vultr.sh b/dnsapi/dns_vultr.sh index 61ec3f60..4002e5de 100644 --- a/dnsapi/dns_vultr.sh +++ b/dnsapi/dns_vultr.sh @@ -6,7 +6,6 @@ Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_vultr Options: VULTR_API_KEY API Key Issues: github.com/acmesh-official/acme.sh/issues/2374 -Author: ' VULTR_Api="https://api.vultr.com/v2" diff --git a/dnsapi/dns_websupport.sh b/dnsapi/dns_websupport.sh index bfc4b23a..2374afc3 100644 --- a/dnsapi/dns_websupport.sh +++ b/dnsapi/dns_websupport.sh @@ -7,7 +7,7 @@ Options: WS_ApiKey API Key. Called "Identifier" in the WS Admin WS_ApiSecret API Secret. Called "Secret key" in the WS Admin Issues: github.com/acmesh-official/acme.sh/issues/3486 -Author: trgo.sk , akulumbeg +Author: trgo.sk <@trgosk>, @akulumbeg ' # Requirements: API Key and Secret from https://admin.websupport.sk/en/auth/apiKey diff --git a/dnsapi/dns_world4you.sh b/dnsapi/dns_world4you.sh index 46cdc4fe..dc295330 100644 --- a/dnsapi/dns_world4you.sh +++ b/dnsapi/dns_world4you.sh @@ -7,7 +7,7 @@ Options: WORLD4YOU_USERNAME Username WORLD4YOU_PASSWORD Password Issues: github.com/acmesh-official/acme.sh/issues/3269 -Author: Lorenz Stechauner +Author: Lorenz Stechauner <@NerLOR> ' WORLD4YOU_API="https://my.world4you.com/en"