From d5b5bcef5631ae2e04d9df7c19be0947351145ab Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 10 Dec 2024 20:54:20 +0100 Subject: [PATCH 01/53] support ARI, not finished yet https://github.com/acmesh-official/acme.sh/issues/4944 --- acme.sh | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/acme.sh b/acme.sh index 9842e3f1..bc146996 100755 --- a/acme.sh +++ b/acme.sh @@ -2746,6 +2746,7 @@ _clearAPI() { ACME_REVOKE_CERT="" ACME_NEW_NONCE="" ACME_AGREEMENT="" + ACME_RENEWAL_INFO="" } #server @@ -2790,6 +2791,9 @@ _initAPI() { ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_AGREEMENT + ACME_RENEWAL_INFO=$(echo "$response" | _egrep_o 'renewalInfo" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_RENEWAL_INFO + _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" @@ -2797,6 +2801,7 @@ _initAPI() { _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" _debug "ACME_AGREEMENT" "$ACME_AGREEMENT" _debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE" + _debug "ACME_RENEWAL_INFO" "$ACME_RENEWAL_INFO" if [ "$ACME_NEW_ACCOUNT" ] && [ "$ACME_NEW_ORDER" ]; then return 0 fi @@ -6416,6 +6421,36 @@ deactivate() { done } +#cert +_getAKI() { + _cert="$1" + openssl x509 -in "$_cert" -text -noout | grep "X509v3 Authority Key Identifier" -A 1 | _tail_n 1 | tr -d ' :' +} + +#cert +_getSerial() { + _cert="$1" + openssl x509 -in "$_cert" -serial -noout | cut -d = -f 2 +} + +#cert +_get_ARI() { + _cert="$1" + _aki=$(_getAKI "$_cert") + _ser=$(_getSerial "$_cert") + _debug2 "_aki" "$_aki" + _debug2 "_ser" "$_ser" + + _akiurl="$(echo "$_aki" | _h2b | _base64 | tr -d = | _url_encode)" + _debug2 "_akiurl" "$_akiurl" + _serurl="$(echo "$_ser" | _h2b | _base64 | tr -d = | _url_encode)" + _debug2 "_serurl" "$_serurl" + + _ARI_URL="$ACME_RENEWAL_INFO/$_akiurl.$_serurl" + _get "$_ARI_URL" + +} + # Detect profile file if not specified as environment variable _detect_profile() { if [ -n "$PROFILE" -a -f "$PROFILE" ]; then From 5ddffc9172e9dd00c90f4251e0e37310525db337 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 10 Dec 2024 21:01:37 +0100 Subject: [PATCH 02/53] fix format --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index bc146996..4290d7a1 100755 --- a/acme.sh +++ b/acme.sh @@ -6441,9 +6441,9 @@ _get_ARI() { _debug2 "_aki" "$_aki" _debug2 "_ser" "$_ser" - _akiurl="$(echo "$_aki" | _h2b | _base64 | tr -d = | _url_encode)" + _akiurl="$(echo "$_aki" | _h2b | _base64 | tr -d = | _url_encode)" _debug2 "_akiurl" "$_akiurl" - _serurl="$(echo "$_ser" | _h2b | _base64 | tr -d = | _url_encode)" + _serurl="$(echo "$_ser" | _h2b | _base64 | tr -d = | _url_encode)" _debug2 "_serurl" "$_serurl" _ARI_URL="$ACME_RENEWAL_INFO/$_akiurl.$_serurl" From ee661e5d7112674cf432a6dacc6455b11c54f38e Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 10 Dec 2024 21:02:54 +0100 Subject: [PATCH 03/53] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4290d7a1..b7558ee5 100755 --- a/acme.sh +++ b/acme.sh @@ -6445,7 +6445,7 @@ _get_ARI() { _debug2 "_akiurl" "$_akiurl" _serurl="$(echo "$_ser" | _h2b | _base64 | tr -d = | _url_encode)" _debug2 "_serurl" "$_serurl" - + _ARI_URL="$ACME_RENEWAL_INFO/$_akiurl.$_serurl" _get "$_ARI_URL" From 7ca8a9e449a16969b30f5c69420f55b14edec6b0 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 24 Oct 2025 11:34:25 -0400 Subject: [PATCH 04/53] QUIC.cloud support for acme.sh --- dnsapi/dns_qc.sh | 188 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100755 dnsapi/dns_qc.sh diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh new file mode 100755 index 00000000..64956bd5 --- /dev/null +++ b/dnsapi/dns_qc.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_qc_info='QUIC.cloud +Site: quic.cloud +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_qc +Options: + QC_API_KEY QC API Key + QC_API_EMAIL Your account email +' + +QC_Api="https://api.quic.cloud/v2" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_qc_add() { + fulldomain=$1 + txtvalue=$2 + + _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue" + QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" + QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" + + if [ "$QC_API_KEY" ]; then + _savedomainconf QC_API_KEY "$QC_API_KEY" + else + _err "You didn't specify a QUIC.cloud are api key and email yet." + _err "You can get yours from here https://my.quic.cloud/up/api." + return 1 + fi + + if ! _contains "$QC_API_EMAIL" "@"; then + _err "It seems that the QC_API_EMAIL=$QC_API_EMAIL is not a valid email address." + _err "Please check and retry." + return 1 + fi + #save the api key and email to the account conf file. + _savedomainconf QC_API_EMAIL "$QC_API_EMAIL" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _qc_rest GET "zones/${_domain_id}/records" + + if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then + _err "Error failed response from QC GET: $response" + return 1 + fi + + # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so + # we can not use updating anymore. + # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) + # _debug count "$count" + # if [ "$count" = "0" ]; then + _info "Adding record" + if _qc_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":1800}"; then + if _contains "$response" "$txtvalue"; then + _info "Added, OK" + return 0 + elif _contains "$response" "Same record already exists"; then + _info "Already exists, OK" + return 0 + else + _err "Add txt record error: $response" + return 1 + fi + fi + _err "Add txt record error: POST failed: $response" + return 1 + +} + +#fulldomain txtvalue +dns_qc_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "Enter dns_qc_rm fulldomain: $fulldomain, txtvalue: $txtvalue" + QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" + QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _qc_rest GET "zones/${_domain_id}/records" + + if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then + _err "Error rm GET response: $response" + return 1 + fi + + response=$(echo "$response"|jq ".result[] | select(.content == \"$txtvalue\") | select(.type == \"TXT\")") + if [ "${response}" = "" ]; then + _info "Don't need to remove." + else + record_id=$(echo "$response" | grep \"id\"| awk -F ' ' '{print $2}'| sed 's/,$//') + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _info "TXT Record ID: $record_id successfully deleted" + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=1 + p=1 + + h=$(printf "%s" "$domain" | cut -d . -f2-) + _debug h "$h" + if [ -z "$h" ]; then + _err "$h ($domain) is an invalid domain" + return 1 + fi + + if ! _qc_rest GET "zones"; then + _debug "qc_rest failed" + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" || _contains "$response" "\"name\":\"$h.\""; then + _domain_id=$h + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") + _domain=$h + return 0 + fi + _err "Empty domain_id $h" + return 1 + fi + _err "Missing domain_id $h" + return 1 +} + +_qc_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + email_trimmed=$(echo "$QC_API_EMAIL" | tr -d '"') + token_trimmed=$(echo "$QC_API_KEY" | tr -d '"') + + export _H1="Content-Type: application/json" + export _H2="X-Auth-Email: $email_trimmed" + export _H3="X-Auth-Key: $token_trimmed" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$QC_Api/$ep" "" "$m")" + else + response="$(_get "$QC_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From e25e30dcdd5e20ab3ff27f9fb1abe1027090e103 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Mon, 27 Oct 2025 12:00:01 -0400 Subject: [PATCH 05/53] Added wiki doc --- wiki/dnsapi/dns_qc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 wiki/dnsapi/dns_qc diff --git a/wiki/dnsapi/dns_qc b/wiki/dnsapi/dns_qc new file mode 100644 index 00000000..50b1879e --- /dev/null +++ b/wiki/dnsapi/dns_qc @@ -0,0 +1,27 @@ +# Use QUIC.cloud DNS API + +This uses the QUIC.cloud DNS API. + +## Obtain an API key from the QUIC.cloude system. If you do not already have one, once logged into QUIC.cloud: + +- Select the Human icon at the top right of the screen and select **Edit Profile** +- On the left side of the screen, press the **API Access** item. +- Press the **Generate Key** button. It will present you with a token you will need below. + +## Use the API + +You will need to provide 2 environment variables to acme.sh: + +- **QC_API_KEY**: This is the API Token value obtained in the QUIC.cloud screens. +- **QC_API_EMAIL**: This is the email you used in your QUIC.cloud configuration + +## Using in OpenLiteSpeed + +This feature is fully supported and documented in version 1.9 and later of OpenLiteSpeed. See the OpenLiteSpeed (documentation)[https://docs.openlitespeed.org/config/advanced/acme/). + +## License + +Copyright: acme.sh wiki contributors + +License: GNU General Public License version 3 or any later version + From 68eb6defd356a62dd0b6c8255846f2851e667da3 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Mon, 27 Oct 2025 12:04:08 -0400 Subject: [PATCH 06/53] Removed false wiki page --- wiki/dnsapi/dns_qc | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 wiki/dnsapi/dns_qc diff --git a/wiki/dnsapi/dns_qc b/wiki/dnsapi/dns_qc deleted file mode 100644 index 50b1879e..00000000 --- a/wiki/dnsapi/dns_qc +++ /dev/null @@ -1,27 +0,0 @@ -# Use QUIC.cloud DNS API - -This uses the QUIC.cloud DNS API. - -## Obtain an API key from the QUIC.cloude system. If you do not already have one, once logged into QUIC.cloud: - -- Select the Human icon at the top right of the screen and select **Edit Profile** -- On the left side of the screen, press the **API Access** item. -- Press the **Generate Key** button. It will present you with a token you will need below. - -## Use the API - -You will need to provide 2 environment variables to acme.sh: - -- **QC_API_KEY**: This is the API Token value obtained in the QUIC.cloud screens. -- **QC_API_EMAIL**: This is the email you used in your QUIC.cloud configuration - -## Using in OpenLiteSpeed - -This feature is fully supported and documented in version 1.9 and later of OpenLiteSpeed. See the OpenLiteSpeed (documentation)[https://docs.openlitespeed.org/config/advanced/acme/). - -## License - -Copyright: acme.sh wiki contributors - -License: GNU General Public License version 3 or any later version - From 9a74c86327bd4731f1bfc3494df2b8a911548555 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Wed, 19 Nov 2025 09:06:55 -0500 Subject: [PATCH 07/53] Commit to force initial test --- dnsapi/dns_qc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 64956bd5..aa4ff891 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -141,7 +141,7 @@ _get_root() { fi if ! _qc_rest GET "zones"; then - _debug "qc_rest failed" + _err "qc_rest failed" return 1 fi From 9381835a7c48e432b440d0dab24ed5aba683ee35 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 24 Oct 2025 11:34:25 -0400 Subject: [PATCH 08/53] QUIC.cloud support for acme.sh --- dnsapi/dns_qc.sh | 188 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100755 dnsapi/dns_qc.sh diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh new file mode 100755 index 00000000..64956bd5 --- /dev/null +++ b/dnsapi/dns_qc.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_qc_info='QUIC.cloud +Site: quic.cloud +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_qc +Options: + QC_API_KEY QC API Key + QC_API_EMAIL Your account email +' + +QC_Api="https://api.quic.cloud/v2" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_qc_add() { + fulldomain=$1 + txtvalue=$2 + + _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue" + QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" + QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" + + if [ "$QC_API_KEY" ]; then + _savedomainconf QC_API_KEY "$QC_API_KEY" + else + _err "You didn't specify a QUIC.cloud are api key and email yet." + _err "You can get yours from here https://my.quic.cloud/up/api." + return 1 + fi + + if ! _contains "$QC_API_EMAIL" "@"; then + _err "It seems that the QC_API_EMAIL=$QC_API_EMAIL is not a valid email address." + _err "Please check and retry." + return 1 + fi + #save the api key and email to the account conf file. + _savedomainconf QC_API_EMAIL "$QC_API_EMAIL" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _qc_rest GET "zones/${_domain_id}/records" + + if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then + _err "Error failed response from QC GET: $response" + return 1 + fi + + # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so + # we can not use updating anymore. + # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) + # _debug count "$count" + # if [ "$count" = "0" ]; then + _info "Adding record" + if _qc_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":1800}"; then + if _contains "$response" "$txtvalue"; then + _info "Added, OK" + return 0 + elif _contains "$response" "Same record already exists"; then + _info "Already exists, OK" + return 0 + else + _err "Add txt record error: $response" + return 1 + fi + fi + _err "Add txt record error: POST failed: $response" + return 1 + +} + +#fulldomain txtvalue +dns_qc_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "Enter dns_qc_rm fulldomain: $fulldomain, txtvalue: $txtvalue" + QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" + QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _qc_rest GET "zones/${_domain_id}/records" + + if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then + _err "Error rm GET response: $response" + return 1 + fi + + response=$(echo "$response"|jq ".result[] | select(.content == \"$txtvalue\") | select(.type == \"TXT\")") + if [ "${response}" = "" ]; then + _info "Don't need to remove." + else + record_id=$(echo "$response" | grep \"id\"| awk -F ' ' '{print $2}'| sed 's/,$//') + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _info "TXT Record ID: $record_id successfully deleted" + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=1 + p=1 + + h=$(printf "%s" "$domain" | cut -d . -f2-) + _debug h "$h" + if [ -z "$h" ]; then + _err "$h ($domain) is an invalid domain" + return 1 + fi + + if ! _qc_rest GET "zones"; then + _debug "qc_rest failed" + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" || _contains "$response" "\"name\":\"$h.\""; then + _domain_id=$h + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") + _domain=$h + return 0 + fi + _err "Empty domain_id $h" + return 1 + fi + _err "Missing domain_id $h" + return 1 +} + +_qc_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + email_trimmed=$(echo "$QC_API_EMAIL" | tr -d '"') + token_trimmed=$(echo "$QC_API_KEY" | tr -d '"') + + export _H1="Content-Type: application/json" + export _H2="X-Auth-Email: $email_trimmed" + export _H3="X-Auth-Key: $token_trimmed" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$QC_Api/$ep" "" "$m")" + else + response="$(_get "$QC_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From 72a6a5ce047d6376744bc9a7813f58fbdbf036fc Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Mon, 27 Oct 2025 12:00:01 -0400 Subject: [PATCH 09/53] Added wiki doc --- wiki/dnsapi/dns_qc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 wiki/dnsapi/dns_qc diff --git a/wiki/dnsapi/dns_qc b/wiki/dnsapi/dns_qc new file mode 100644 index 00000000..50b1879e --- /dev/null +++ b/wiki/dnsapi/dns_qc @@ -0,0 +1,27 @@ +# Use QUIC.cloud DNS API + +This uses the QUIC.cloud DNS API. + +## Obtain an API key from the QUIC.cloude system. If you do not already have one, once logged into QUIC.cloud: + +- Select the Human icon at the top right of the screen and select **Edit Profile** +- On the left side of the screen, press the **API Access** item. +- Press the **Generate Key** button. It will present you with a token you will need below. + +## Use the API + +You will need to provide 2 environment variables to acme.sh: + +- **QC_API_KEY**: This is the API Token value obtained in the QUIC.cloud screens. +- **QC_API_EMAIL**: This is the email you used in your QUIC.cloud configuration + +## Using in OpenLiteSpeed + +This feature is fully supported and documented in version 1.9 and later of OpenLiteSpeed. See the OpenLiteSpeed (documentation)[https://docs.openlitespeed.org/config/advanced/acme/). + +## License + +Copyright: acme.sh wiki contributors + +License: GNU General Public License version 3 or any later version + From cf5fd403e85c06c1c5ec4110e8112b50308b1fa2 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Mon, 27 Oct 2025 12:04:08 -0400 Subject: [PATCH 10/53] Removed false wiki page --- wiki/dnsapi/dns_qc | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 wiki/dnsapi/dns_qc diff --git a/wiki/dnsapi/dns_qc b/wiki/dnsapi/dns_qc deleted file mode 100644 index 50b1879e..00000000 --- a/wiki/dnsapi/dns_qc +++ /dev/null @@ -1,27 +0,0 @@ -# Use QUIC.cloud DNS API - -This uses the QUIC.cloud DNS API. - -## Obtain an API key from the QUIC.cloude system. If you do not already have one, once logged into QUIC.cloud: - -- Select the Human icon at the top right of the screen and select **Edit Profile** -- On the left side of the screen, press the **API Access** item. -- Press the **Generate Key** button. It will present you with a token you will need below. - -## Use the API - -You will need to provide 2 environment variables to acme.sh: - -- **QC_API_KEY**: This is the API Token value obtained in the QUIC.cloud screens. -- **QC_API_EMAIL**: This is the email you used in your QUIC.cloud configuration - -## Using in OpenLiteSpeed - -This feature is fully supported and documented in version 1.9 and later of OpenLiteSpeed. See the OpenLiteSpeed (documentation)[https://docs.openlitespeed.org/config/advanced/acme/). - -## License - -Copyright: acme.sh wiki contributors - -License: GNU General Public License version 3 or any later version - From d0d97a40a62c85efcfdb96c9affd682847889c1f Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Wed, 19 Nov 2025 09:06:55 -0500 Subject: [PATCH 11/53] Commit to force initial test --- dnsapi/dns_qc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 64956bd5..aa4ff891 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -141,7 +141,7 @@ _get_root() { fi if ! _qc_rest GET "zones"; then - _debug "qc_rest failed" + _err "qc_rest failed" return 1 fi From b500ac3dbbd20d70de487636c2486375aade488a Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Thu, 20 Nov 2025 15:38:56 -0500 Subject: [PATCH 12/53] Updated secret and dns_qc.sh --- dnsapi/dns_qc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index aa4ff891..1eeef97f 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -107,7 +107,7 @@ dns_qc_rm() { if [ "${response}" = "" ]; then _info "Don't need to remove." else - record_id=$(echo "$response" | grep \"id\"| awk -F ' ' '{print $2}'| sed 's/,$//') + record_id=$(echo "$response" | grep \"id\"| awk -F ' ' '{print $2}'| sed 's/,$//') _debug "record_id" "$record_id" if [ -z "$record_id" ]; then _err "Can not get record id to remove." From 0f42b06b48b488fc3b90fd40671673acd1066735 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 21 Nov 2025 08:02:59 -0500 Subject: [PATCH 13/53] Trying again to fix shfmt error --- dnsapi/dns_qc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 1eeef97f..66444aa6 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -103,7 +103,7 @@ dns_qc_rm() { return 1 fi - response=$(echo "$response"|jq ".result[] | select(.content == \"$txtvalue\") | select(.type == \"TXT\")") + response=$(echo "$response"|jq ".result[]" | select(.content == \"$txtvalue\") | select(.type == \"TXT\")) if [ "${response}" = "" ]; then _info "Don't need to remove." else From 90d2ff8fad85f4bd92aafabaf24928435421c455 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 21 Nov 2025 15:27:38 -0500 Subject: [PATCH 14/53] Better fixes for shfmt errors --- dnsapi/dns_qc.sh | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 66444aa6..0ec53864 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -59,13 +59,13 @@ dns_qc_add() { # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) # _debug count "$count" # if [ "$count" = "0" ]; then - _info "Adding record" + _info "Adding txt record" if _qc_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":1800}"; then if _contains "$response" "$txtvalue"; then - _info "Added, OK" + _info "Added txt record, OK" return 0 elif _contains "$response" "Same record already exists"; then - _info "Already exists, OK" + _info "txt record already exists, OK" return 0 else _err "Add txt record error: $response" @@ -103,18 +103,19 @@ dns_qc_rm() { return 1 fi - response=$(echo "$response"|jq ".result[]" | select(.content == \"$txtvalue\") | select(.type == \"TXT\")) + response=$(echo "$response"|jq ".result[] | select(.id) | select(.content == \"$txtvalue\") | select(.type == \"TXT\")") + _debug get txt response "$response" if [ "${response}" = "" ]; then - _info "Don't need to remove." + _info "Don't need to remove txt records." else record_id=$(echo "$response" | grep \"id\"| awk -F ' ' '{print $2}'| sed 's/,$//') - _debug "record_id" "$record_id" + _debug "txt record_id" "$record_id" if [ -z "$record_id" ]; then - _err "Can not get record id to remove." + _err "Can not get txt record id to remove." return 1 fi if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then - _err "Delete record error." + _err "Delete txt record error." return 1 fi _info "TXT Record ID: $record_id successfully deleted" From 5e76ea820ca42f76055e57de5769325a4c34531b Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 21 Nov 2025 16:01:14 -0500 Subject: [PATCH 15/53] Additional shfmt issues --- dnsapi/dns_qc.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 0ec53864..ab02f17e 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -104,18 +104,18 @@ dns_qc_rm() { fi response=$(echo "$response"|jq ".result[] | select(.id) | select(.content == \"$txtvalue\") | select(.type == \"TXT\")") - _debug get txt response "$response" + _debug "get txt response" "$response" if [ "${response}" = "" ]; then _info "Don't need to remove txt records." else record_id=$(echo "$response" | grep \"id\"| awk -F ' ' '{print $2}'| sed 's/,$//') _debug "txt record_id" "$record_id" if [ -z "$record_id" ]; then - _err "Can not get txt record id to remove." + _info "Can not get txt record id to remove." return 1 fi if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then - _err "Delete txt record error." + _info "Delete txt record error." return 1 fi _info "TXT Record ID: $record_id successfully deleted" From ded539b11c365359082c3801fb2057593cae535f Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 21 Nov 2025 16:04:23 -0500 Subject: [PATCH 16/53] Additional shfmt issues --- dnsapi/dns_qc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index ab02f17e..723bbea8 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -112,7 +112,7 @@ dns_qc_rm() { _debug "txt record_id" "$record_id" if [ -z "$record_id" ]; then _info "Can not get txt record id to remove." - return 1 + return 0 fi if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then _info "Delete txt record error." From 20ef8cd369f712d08bbb094f1dd95809065fcd6d Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 21 Nov 2025 16:22:42 -0500 Subject: [PATCH 17/53] Additional shfmt issues --- dnsapi/dns_qc.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 723bbea8..ef246a2b 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -111,7 +111,7 @@ dns_qc_rm() { record_id=$(echo "$response" | grep \"id\"| awk -F ' ' '{print $2}'| sed 's/,$//') _debug "txt record_id" "$record_id" if [ -z "$record_id" ]; then - _info "Can not get txt record id to remove." + #_info "Can not get txt record id to remove." return 0 fi if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then @@ -120,7 +120,7 @@ dns_qc_rm() { fi _info "TXT Record ID: $record_id successfully deleted" fi - + return 0 } #################### Private functions below ################################## From 88e9681481b3694b2fab4cf7663306eca8c6e386 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 21 Nov 2025 16:26:24 -0500 Subject: [PATCH 18/53] Additional shfmt issues --- dnsapi/dns_qc.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index ef246a2b..c30d4595 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -110,10 +110,6 @@ dns_qc_rm() { else record_id=$(echo "$response" | grep \"id\"| awk -F ' ' '{print $2}'| sed 's/,$//') _debug "txt record_id" "$record_id" - if [ -z "$record_id" ]; then - #_info "Can not get txt record id to remove." - return 0 - fi if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then _info "Delete txt record error." return 1 From d3930639db5a0a0cd6fbf75d02d8c538568a1816 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 5 Dec 2025 08:58:41 -0500 Subject: [PATCH 19/53] Updated secrets and put back guards --- dnsapi/dns_qc.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index c30d4595..3ea8403c 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -110,6 +110,10 @@ dns_qc_rm() { else record_id=$(echo "$response" | grep \"id\"| awk -F ' ' '{print $2}'| sed 's/,$//') _debug "txt record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get txt record id to remove." + return 1 + fi if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then _info "Delete txt record error." return 1 From 67a389cbbf781492bbb9d554d8f0da45c77e5da3 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 5 Dec 2025 10:35:52 -0500 Subject: [PATCH 20/53] Minor change and setup secrets again --- dnsapi/dns_qc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 3ea8403c..6d1a9eb4 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -111,7 +111,7 @@ dns_qc_rm() { record_id=$(echo "$response" | grep \"id\"| awk -F ' ' '{print $2}'| sed 's/,$//') _debug "txt record_id" "$record_id" if [ -z "$record_id" ]; then - _err "Can not get txt record id to remove." + _err "Can not get txt record id to remove. Run in debug mode." return 1 fi if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then From 6b6d22c5ba0d7645444d26629793d22f51e19841 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 5 Dec 2025 13:52:59 -0500 Subject: [PATCH 21/53] shfmt updates --- dnsapi/dns_qc.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 6d1a9eb4..6d4f7299 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -34,7 +34,7 @@ dns_qc_add() { _err "Please check and retry." return 1 fi - #save the api key and email to the account conf file. + #save the api key and email to the account conf file. _savedomainconf QC_API_EMAIL "$QC_API_EMAIL" _debug "First detect the root zone" @@ -103,12 +103,12 @@ dns_qc_rm() { return 1 fi - response=$(echo "$response"|jq ".result[] | select(.id) | select(.content == \"$txtvalue\") | select(.type == \"TXT\")") + response=$(echo "$response" | jq ".result[] | select(.id) | select(.content == \"$txtvalue\") | select(.type == \"TXT\")") _debug "get txt response" "$response" if [ "${response}" = "" ]; then _info "Don't need to remove txt records." else - record_id=$(echo "$response" | grep \"id\"| awk -F ' ' '{print $2}'| sed 's/,$//') + record_id=$(echo "$response" | grep \"id\" | awk -F ' ' '{print $2}' | sed 's/,$//') _debug "txt record_id" "$record_id" if [ -z "$record_id" ]; then _err "Can not get txt record id to remove. Run in debug mode." From a1857af6de5dcee0ec109a36b45dbb4b0326e067 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 5 Dec 2025 15:53:17 -0500 Subject: [PATCH 22/53] Update error message and secrets --- dnsapi/dns_qc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 6d4f7299..cea411e8 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -24,7 +24,7 @@ dns_qc_add() { if [ "$QC_API_KEY" ]; then _savedomainconf QC_API_KEY "$QC_API_KEY" else - _err "You didn't specify a QUIC.cloud are api key and email yet." + _err "You didn't specify a QUIC.cloud api key as QC_API_KEY." _err "You can get yours from here https://my.quic.cloud/up/api." return 1 fi From ed1bd01592afba97749f2b51573b8c35f2372c31 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Fri, 5 Dec 2025 16:29:49 -0500 Subject: [PATCH 23/53] Save account information differently --- dnsapi/dns_qc.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index cea411e8..7ae2f1cd 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -22,7 +22,7 @@ dns_qc_add() { QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" if [ "$QC_API_KEY" ]; then - _savedomainconf QC_API_KEY "$QC_API_KEY" + _saveaccountconf_mutable QC_API_KEY "$QC_API_KEY" else _err "You didn't specify a QUIC.cloud api key as QC_API_KEY." _err "You can get yours from here https://my.quic.cloud/up/api." @@ -35,7 +35,7 @@ dns_qc_add() { return 1 fi #save the api key and email to the account conf file. - _savedomainconf QC_API_EMAIL "$QC_API_EMAIL" + _saveaccountconf_mutable QC_API_EMAIL "$QC_API_EMAIL" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then From 875cf056b7e293c67b4ae9549455a20fa798da62 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Mon, 8 Dec 2025 08:40:44 -0500 Subject: [PATCH 24/53] Submit dns_qc.sh for review --- dns_qc.sh | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100755 dns_qc.sh diff --git a/dns_qc.sh b/dns_qc.sh new file mode 100755 index 00000000..78a243ae --- /dev/null +++ b/dns_qc.sh @@ -0,0 +1,201 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_qc_info='QUIC.cloud +Site: quic.cloud +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_qc +Options: + QC_API_KEY QC API Key + QC_API_EMAIL Your account email +' + +QC_Api="https://api.quic.cloud/v2" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_qc_add() { + fulldomain=$1 + txtvalue=$2 + + _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue" + QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" + QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" + + if [ "$QC_API_KEY" ]; then + _savedomainconf QC_API_KEY "$QC_API_KEY" + else + _err "You didn't specify a QUIC.cloud are api key and email yet." + _err "You can get yours from here https://my.quic.cloud/up/api." + return 1 + fi + + if ! _contains "$QC_API_EMAIL" "@"; then + _err "It seems that the QC_API_EMAIL=$QC_API_EMAIL is not a valid email address." + _err "Please check and retry." + return 1 + fi + #save the api key and email to the account conf file. + _savedomainconf QC_API_EMAIL "$QC_API_EMAIL" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _qc_rest GET "zones/${_domain_id}/records" + + if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then + _err "Error failed response from QC GET: $response" + return 1 + fi + + # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so + # we can not use updating anymore. + # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) + # _debug count "$count" + # if [ "$count" = "0" ]; then + _info "Adding txt record" + if _qc_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":1800}"; then + if _contains "$response" "$txtvalue"; then + _info "Added txt record, OK" + return 0 + elif _contains "$response" "Same record already exists"; then + _info "txt record already exists, OK" + return 0 + else + _err "Add txt record error: $response" + return 1 + fi + fi + _err "Add txt record error: POST failed: $response" + return 1 + +} + +#fulldomain txtvalue +dns_qc_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "Enter dns_qc_rm fulldomain: $fulldomain, txtvalue: $txtvalue" + QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" + QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _qc_rest GET "zones/${_domain_id}/records" + + if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then + _err "Error rm GET response: $response" + return 1 + fi + + response=$(echo "$response" | jq ".result[] | select(.id) | select(.content == \"$txtvalue\") | select(.type == \"TXT\")") + _debug "get txt response" "$response" + if [ "${response}" = "" ]; then + _info "Don't need to remove txt records." + else + record_id=$(echo "$response" | grep \"id\" | awk -F ' ' '{print $2}' | sed 's/,$//') + _debug "txt record_id" "$record_id" + + if [[ -z "$record_id" ]]; then + _err "Can not get txt record id to remove. Run in debug mode." + return 1 + fi + + if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then + _info "Delete txt record error." + return 1 + fi + + _info "TXT Record ID: $record_id successfully deleted" + fi + +} + +#################### Private functions below ################################# +#_acme-challenge.www.domain.com +#returns +#_sub_domain=_acme-challenge.www +#_domain=domain.com +#_domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + p=1 + h=$(printf "%s" "$domain" | cut -d . -f2-) + _debug h "$h" + + if [[ -z "$h" ]]; then + _err "$h ($domain) is an invalid domain" + return 1 + fi + + if ! _qc_rest GET "zones"; then + _err "qc_rest failed" + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" || _contains "$response" "\"name\":\"$h.\""; then + _domain_id=$h + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") + _domain=$h + return 0 + fi + + _err "Empty domain_id $h" + return 1 + fi + _err "Missing domain_id $h" + return 1 + +} + +_qc_rest() { + + m="$1" + ep="$2" + data="$3" + + _debug "$ep" + + email_trimmed=$(echo "$QC_API_EMAIL" | tr -d '"') + + token_trimmed=$(echo "$QC_API_KEY" | tr -d '"') + + export _H1="Content-Type: application/json" + + export _H2="X-Auth-Email: $email_trimmed" + + export _H3="X-Auth-Key: $token_trimmed" + + if [[ "$m" != "GET" ]]; then + _debug data "$data" + response="$(_post "$data" "$QC_Api/$ep" "" "$m")" + + else + response="$(_get "$QC_Api/$ep")" + + fi + + if [[ "$?" != "0" ]]; then + _err "error $ep" + return 1 + fi + + _debug2 response "$response" + +} From 5fcca7c7e0e8144e555987328caccf60eaa533d3 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Mon, 8 Dec 2025 08:48:30 -0500 Subject: [PATCH 25/53] Retry correct commit --- dnsapi/dns_qc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 7ae2f1cd..0765c697 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -17,7 +17,7 @@ dns_qc_add() { fulldomain=$1 txtvalue=$2 - _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue" + _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue." QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" From e5dea48d3cc3bdb49696398e5d17edb515046279 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 9 Dec 2025 07:40:00 -0500 Subject: [PATCH 26/53] Retry pull request with HTTPS_INSECURE=1 --- dnsapi/dns_qc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 0765c697..7ae2f1cd 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -17,7 +17,7 @@ dns_qc_add() { fulldomain=$1 txtvalue=$2 - _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue." + _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue" QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" From 5017c12324967423cb44ae7d0b6d5b9ee354317d Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Thu, 11 Dec 2025 09:03:38 -0500 Subject: [PATCH 27/53] Trying verification again --- dnsapi/dns_qc.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 7ae2f1cd..2376d718 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -39,7 +39,7 @@ dns_qc_add() { _debug "First detect the root zone" if ! _get_root "$fulldomain"; then - _err "invalid domain" + _err "invalid domain during add" return 1 fi _debug _domain_id "$_domain_id" @@ -59,7 +59,7 @@ dns_qc_add() { # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) # _debug count "$count" # if [ "$count" = "0" ]; then - _info "Adding txt record" + _info "Adding txt record." if _qc_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":1800}"; then if _contains "$response" "$txtvalue"; then _info "Added txt record, OK" @@ -88,7 +88,7 @@ dns_qc_rm() { _debug "First detect the root zone" if ! _get_root "$fulldomain"; then - _err "invalid domain" + _err "invalid domain during rm" return 1 fi _debug _domain_id "$_domain_id" From 6f66e294defe1b0e1d5de1ff57cd596308ce013a Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Thu, 11 Dec 2025 15:43:15 -0500 Subject: [PATCH 28/53] Yet another try --- dns_qc.sh | 201 ----------------------------------------------- dnsapi/dns_qc.sh | 2 +- 2 files changed, 1 insertion(+), 202 deletions(-) delete mode 100755 dns_qc.sh diff --git a/dns_qc.sh b/dns_qc.sh deleted file mode 100755 index 78a243ae..00000000 --- a/dns_qc.sh +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/env sh -# shellcheck disable=SC2034 -dns_qc_info='QUIC.cloud -Site: quic.cloud -Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_qc -Options: - QC_API_KEY QC API Key - QC_API_EMAIL Your account email -' - -QC_Api="https://api.quic.cloud/v2" - -######## Public functions ##################### - -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_qc_add() { - fulldomain=$1 - txtvalue=$2 - - _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue" - QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" - QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" - - if [ "$QC_API_KEY" ]; then - _savedomainconf QC_API_KEY "$QC_API_KEY" - else - _err "You didn't specify a QUIC.cloud are api key and email yet." - _err "You can get yours from here https://my.quic.cloud/up/api." - return 1 - fi - - if ! _contains "$QC_API_EMAIL" "@"; then - _err "It seems that the QC_API_EMAIL=$QC_API_EMAIL is not a valid email address." - _err "Please check and retry." - return 1 - fi - #save the api key and email to the account conf file. - _savedomainconf QC_API_EMAIL "$QC_API_EMAIL" - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" - return 1 - fi - _debug _domain_id "$_domain_id" - _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - - _debug "Getting txt records" - _qc_rest GET "zones/${_domain_id}/records" - - if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then - _err "Error failed response from QC GET: $response" - return 1 - fi - - # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so - # we can not use updating anymore. - # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) - # _debug count "$count" - # if [ "$count" = "0" ]; then - _info "Adding txt record" - if _qc_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":1800}"; then - if _contains "$response" "$txtvalue"; then - _info "Added txt record, OK" - return 0 - elif _contains "$response" "Same record already exists"; then - _info "txt record already exists, OK" - return 0 - else - _err "Add txt record error: $response" - return 1 - fi - fi - _err "Add txt record error: POST failed: $response" - return 1 - -} - -#fulldomain txtvalue -dns_qc_rm() { - fulldomain=$1 - txtvalue=$2 - - _debug "Enter dns_qc_rm fulldomain: $fulldomain, txtvalue: $txtvalue" - QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" - QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" - return 1 - fi - _debug _domain_id "$_domain_id" - _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - - _debug "Getting txt records" - _qc_rest GET "zones/${_domain_id}/records" - - if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then - _err "Error rm GET response: $response" - return 1 - fi - - response=$(echo "$response" | jq ".result[] | select(.id) | select(.content == \"$txtvalue\") | select(.type == \"TXT\")") - _debug "get txt response" "$response" - if [ "${response}" = "" ]; then - _info "Don't need to remove txt records." - else - record_id=$(echo "$response" | grep \"id\" | awk -F ' ' '{print $2}' | sed 's/,$//') - _debug "txt record_id" "$record_id" - - if [[ -z "$record_id" ]]; then - _err "Can not get txt record id to remove. Run in debug mode." - return 1 - fi - - if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then - _info "Delete txt record error." - return 1 - fi - - _info "TXT Record ID: $record_id successfully deleted" - fi - -} - -#################### Private functions below ################################# -#_acme-challenge.www.domain.com -#returns -#_sub_domain=_acme-challenge.www -#_domain=domain.com -#_domain_id=sdjkglgdfewsdfg -_get_root() { - domain=$1 - p=1 - h=$(printf "%s" "$domain" | cut -d . -f2-) - _debug h "$h" - - if [[ -z "$h" ]]; then - _err "$h ($domain) is an invalid domain" - return 1 - fi - - if ! _qc_rest GET "zones"; then - _err "qc_rest failed" - return 1 - fi - - if _contains "$response" "\"name\":\"$h\"" || _contains "$response" "\"name\":\"$h.\""; then - _domain_id=$h - if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") - _domain=$h - return 0 - fi - - _err "Empty domain_id $h" - return 1 - fi - _err "Missing domain_id $h" - return 1 - -} - -_qc_rest() { - - m="$1" - ep="$2" - data="$3" - - _debug "$ep" - - email_trimmed=$(echo "$QC_API_EMAIL" | tr -d '"') - - token_trimmed=$(echo "$QC_API_KEY" | tr -d '"') - - export _H1="Content-Type: application/json" - - export _H2="X-Auth-Email: $email_trimmed" - - export _H3="X-Auth-Key: $token_trimmed" - - if [[ "$m" != "GET" ]]; then - _debug data "$data" - response="$(_post "$data" "$QC_Api/$ep" "" "$m")" - - else - response="$(_get "$QC_Api/$ep")" - - fi - - if [[ "$?" != "0" ]]; then - _err "error $ep" - return 1 - fi - - _debug2 response "$response" - -} diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 2376d718..b7267f63 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -59,7 +59,7 @@ dns_qc_add() { # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) # _debug count "$count" # if [ "$count" = "0" ]; then - _info "Adding txt record." + _info "Adding txt record" if _qc_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":1800}"; then if _contains "$response" "$txtvalue"; then _info "Added txt record, OK" From 1d26d4fc913abf6358e449fc4713b16cc0781b1f Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Mon, 22 Dec 2025 16:42:26 -0500 Subject: [PATCH 29/53] Detect missing jq --- dnsapi/dns_qc.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index b7267f63..81a1e636 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -18,6 +18,11 @@ dns_qc_add() { txtvalue=$2 _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue" + if ! _exists jq; then + _err "jq not found" + return 1 + fi + QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" From 94783f46ad0c512b74a4f3ac760860c4ef0c2d61 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 23 Dec 2025 07:53:33 -0500 Subject: [PATCH 30/53] Retry to pass workflow --- dnsapi/dns_qc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 81a1e636..aa58d0dc 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -19,7 +19,7 @@ dns_qc_add() { _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue" if ! _exists jq; then - _err "jq not found" + _err "In dns_qc jq not found" return 1 fi From f1aac43f0f9c701e47b8ab52d64495cd9b1d0287 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 23 Dec 2025 09:10:49 -0500 Subject: [PATCH 31/53] Retry for workflow --- dnsapi/dns_qc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index aa58d0dc..ed784f28 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -19,7 +19,7 @@ dns_qc_add() { _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue" if ! _exists jq; then - _err "In dns_qc jq not found" + _err "In dns_qc jq not found." return 1 fi From f4a575fee15054eec1b02c82836ed41053a52e81 Mon Sep 17 00:00:00 2001 From: jwaterwater Date: Thu, 25 Dec 2025 14:48:44 +0800 Subject: [PATCH 32/53] bug fixed --- deploy/ali_cdn.sh | 2 +- deploy/ali_dcdn.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/ali_cdn.sh b/deploy/ali_cdn.sh index 70a2e532..3c28674e 100644 --- a/deploy/ali_cdn.sh +++ b/deploy/ali_cdn.sh @@ -83,6 +83,6 @@ _set_cdn_domain_ssl_certificate_query() { query=$query'&SignatureMethod=HMAC-SHA1' query=$query"&SignatureNonce=$(_ali_nonce)" query=$query'&SignatureVersion=1.0' - query=$query'&Timestamp='$(_timestamp) + query=$query'&Timestamp='$(_ali_timestamp) query=$query'&Version=2018-05-10' } diff --git a/deploy/ali_dcdn.sh b/deploy/ali_dcdn.sh index 14ac500a..27d3a726 100644 --- a/deploy/ali_dcdn.sh +++ b/deploy/ali_dcdn.sh @@ -83,6 +83,6 @@ _set_dcdn_domain_ssl_certificate_query() { query=$query'&SignatureMethod=HMAC-SHA1' query=$query"&SignatureNonce=$(_ali_nonce)" query=$query'&SignatureVersion=1.0' - query=$query'&Timestamp='$(_timestamp) + query=$query'&Timestamp='$(_ali_timestamp) query=$query'&Version=2018-01-15' } From 21d52b5995b94f873c074662988972ad8392c5f9 Mon Sep 17 00:00:00 2001 From: Hugo Haakseth Date: Tue, 30 Dec 2025 10:57:12 +0100 Subject: [PATCH 33/53] Store pfx password base64 encoded --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 5cd2cb3f..1401870b 100755 --- a/acme.sh +++ b/acme.sh @@ -1466,7 +1466,7 @@ _toPkcs() { ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" fi if [ "$?" = "0" ]; then - _savedomainconf "Le_PFXPassword" "$pfxPassword" + _savedomainconf "Le_PFXPassword" "$pfxPassword" "base64" fi } @@ -5450,10 +5450,10 @@ $_authorizations_map" _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" #convert to pkcs12 + Le_PFXPassword="$(_readdomainconf Le_PFXPassword)" if [ "$Le_PFXPassword" ]; then _toPkcs "$CERT_PFX_PATH" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$Le_PFXPassword" fi - export CERT_PFX_PATH if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then _savedomainconf "Le_RealCertPath" "$_real_cert" From 162cfebbbb1122a53f3b62f46365084a5052cf05 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 30 Dec 2025 15:36:06 -0500 Subject: [PATCH 34/53] Removed jq requirement --- dnsapi/dns_qc.sh | 55 ++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index ed784f28..1073200f 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -18,11 +18,6 @@ dns_qc_add() { txtvalue=$2 _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue" - if ! _exists jq; then - _err "In dns_qc jq not found." - return 1 - fi - QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" @@ -108,23 +103,43 @@ dns_qc_rm() { return 1 fi - response=$(echo "$response" | jq ".result[] | select(.id) | select(.content == \"$txtvalue\") | select(.type == \"TXT\")") - _debug "get txt response" "$response" - if [ "${response}" = "" ]; then - _info "Don't need to remove txt records." - else - record_id=$(echo "$response" | grep \"id\" | awk -F ' ' '{print $2}' | sed 's/,$//') - _debug "txt record_id" "$record_id" - if [ -z "$record_id" ]; then - _err "Can not get txt record id to remove. Run in debug mode." - return 1 - fi - if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then - _info "Delete txt record error." - return 1 + _debug "Pre-jq response:" "$response" + # Do not use jq or subsequent code + #response=$(echo "$response" | jq ".result[] | select(.id) | select(.content == \"$txtvalue\") | select(.type == \"TXT\")") + #_debug "get txt response" "$response" + #if [ "${response}" = "" ]; then + # _info "Don't need to remove txt records." + # return 0 + #fi + #record_id=$(echo "$response" | grep \"id\" | awk -F ' ' '{print $2}' | sed 's/,$//') + #_debug "txt record_id" "$record_id" + #Instead of jq + array=$(echo $response | grep -o '\[[^]]*\]' | sed 's/^\[\(.*\)\]$/\1/') + if [ -z "$array" ]; then + _err "Expected array in QC response: $response" + return 1 + fi + # Temporary file to hold matched content (one per line) + tmpfile=$(_mktemp) + echo $array | grep -o '{[^}]*}' | sed 's/^{//;s/}$//' > "$tmpfile" + while IFS= read -r obj || [ -n "$obj" ]; do + if echo $obj | grep -q '"TXT"' && echo $obj | grep -q '"id"' && echo $obj | grep -q $txtvalue ; then + _debug "response includes" "$obj" + record_id=$(echo $obj | sed 's/^\"id\":\([0-9]\+\).*/\1/' ) + break fi - _info "TXT Record ID: $record_id successfully deleted" + done < $tmpfile + rm $tmpfile + if [ -z "$record_id" ]; then + _info "TXT record, or $txtvalue not found, noting to remove" + return 0 + fi + #End of jq replacement + if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then + _info "Delete txt record error." + return 1 fi + _info "TXT Record ID: $record_id successfully deleted" return 0 } From e031457cfacbf3abd35a51bbc56d443c09a975b4 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 30 Dec 2025 15:48:29 -0500 Subject: [PATCH 35/53] shfmt fixes --- dnsapi/dns_qc.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 1073200f..35e99fa2 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -130,15 +130,18 @@ dns_qc_rm() { fi done < $tmpfile rm $tmpfile + if [ -z "$record_id" ]; then - _info "TXT record, or $txtvalue not found, noting to remove" + _info "TXT record, or $txtvalue not found, nothing to remove" return 0 fi + #End of jq replacement if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then _info "Delete txt record error." return 1 fi + _info "TXT Record ID: $record_id successfully deleted" return 0 } From 185d92f1e7d7ad62d84178d06bce9ae0be49775e Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 30 Dec 2025 15:50:39 -0500 Subject: [PATCH 36/53] shfmt fixes --- dnsapi/dns_qc.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 35e99fa2..68c33ebc 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -141,9 +141,10 @@ dns_qc_rm() { _info "Delete txt record error." return 1 fi - + _info "TXT Record ID: $record_id successfully deleted" return 0 + } #################### Private functions below ################################## From 0b66acf332c539466ea4039b8e473246b3a26eba Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 30 Dec 2025 15:54:23 -0500 Subject: [PATCH 37/53] shfmt fixes --- dnsapi/dns_qc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 68c33ebc..9fcf977a 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -144,7 +144,7 @@ dns_qc_rm() { _info "TXT Record ID: $record_id successfully deleted" return 0 - + } #################### Private functions below ################################## From b4f30ff02678035e56339b44d0238d7583abaead Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 30 Dec 2025 16:07:01 -0500 Subject: [PATCH 38/53] Updated for shfmt --- dnsapi/dns_qc.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 9fcf977a..65e1c90b 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -121,14 +121,14 @@ dns_qc_rm() { fi # Temporary file to hold matched content (one per line) tmpfile=$(_mktemp) - echo $array | grep -o '{[^}]*}' | sed 's/^{//;s/}$//' > "$tmpfile" + echo $array | grep -o '{[^}]*}' | sed 's/^{//;s/}$//' >"$tmpfile" while IFS= read -r obj || [ -n "$obj" ]; do - if echo $obj | grep -q '"TXT"' && echo $obj | grep -q '"id"' && echo $obj | grep -q $txtvalue ; then + if echo $obj | grep -q '"TXT"' && echo $obj | grep -q '"id"' && echo $obj | grep -q $txtvalue; then _debug "response includes" "$obj" - record_id=$(echo $obj | sed 's/^\"id\":\([0-9]\+\).*/\1/' ) + record_id=$(echo $obj | sed 's/^\"id\":\([0-9]\+\).*/\1/') break fi - done < $tmpfile + done <$tmpfile rm $tmpfile if [ -z "$record_id" ]; then From 397c0605e575b70f9d76c4863a40c7dde374d5b4 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 30 Dec 2025 16:11:39 -0500 Subject: [PATCH 39/53] Double quote for globbing --- dnsapi/dns_qc.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 65e1c90b..efa54fda 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -121,15 +121,15 @@ dns_qc_rm() { fi # Temporary file to hold matched content (one per line) tmpfile=$(_mktemp) - echo $array | grep -o '{[^}]*}' | sed 's/^{//;s/}$//' >"$tmpfile" + echo $array | grep -o '{[^}]*}' | sed 's/^{//;s/}$//' > "$tmpfile" while IFS= read -r obj || [ -n "$obj" ]; do - if echo $obj | grep -q '"TXT"' && echo $obj | grep -q '"id"' && echo $obj | grep -q $txtvalue; then + if echo $obj | grep -q '"TXT"' && echo $obj | grep -q '"id"' && echo $obj | grep -q $txtvalue ; then _debug "response includes" "$obj" record_id=$(echo $obj | sed 's/^\"id\":\([0-9]\+\).*/\1/') break fi - done <$tmpfile - rm $tmpfile + done < "$tmpfile" + rm "$tmpfile" if [ -z "$record_id" ]; then _info "TXT record, or $txtvalue not found, nothing to remove" From 778b4a38edef9f8d4aa5f6d9494af37db838f6fc Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 30 Dec 2025 16:17:03 -0500 Subject: [PATCH 40/53] Missed several double quote issues --- dnsapi/dns_qc.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index efa54fda..f48eeb08 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -114,18 +114,18 @@ dns_qc_rm() { #record_id=$(echo "$response" | grep \"id\" | awk -F ' ' '{print $2}' | sed 's/,$//') #_debug "txt record_id" "$record_id" #Instead of jq - array=$(echo $response | grep -o '\[[^]]*\]' | sed 's/^\[\(.*\)\]$/\1/') + array=$(echo "$response" | grep -o '\[[^]]*\]' | sed 's/^\[\(.*\)\]$/\1/') if [ -z "$array" ]; then _err "Expected array in QC response: $response" return 1 fi # Temporary file to hold matched content (one per line) tmpfile=$(_mktemp) - echo $array | grep -o '{[^}]*}' | sed 's/^{//;s/}$//' > "$tmpfile" + echo "$array" | grep -o '{[^}]*}' | sed 's/^{//;s/}$//' > "$tmpfile" while IFS= read -r obj || [ -n "$obj" ]; do - if echo $obj | grep -q '"TXT"' && echo $obj | grep -q '"id"' && echo $obj | grep -q $txtvalue ; then + if echo "$obj" | grep -q '"TXT"' && echo $obj | grep -q '"id"' && echo $obj | grep -q $txtvalue ; then _debug "response includes" "$obj" - record_id=$(echo $obj | sed 's/^\"id\":\([0-9]\+\).*/\1/') + record_id=$(echo "$obj" | sed 's/^\"id\":\([0-9]\+\).*/\1/') break fi done < "$tmpfile" From f9ffdbe4074bce3bab40220cdfb2fa337c303360 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 30 Dec 2025 16:23:01 -0500 Subject: [PATCH 41/53] Initialize record_id --- dnsapi/dns_qc.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index f48eeb08..ecf5d387 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -122,6 +122,8 @@ dns_qc_rm() { # Temporary file to hold matched content (one per line) tmpfile=$(_mktemp) echo "$array" | grep -o '{[^}]*}' | sed 's/^{//;s/}$//' > "$tmpfile" + record_id="" + while IFS= read -r obj || [ -n "$obj" ]; do if echo "$obj" | grep -q '"TXT"' && echo $obj | grep -q '"id"' && echo $obj | grep -q $txtvalue ; then _debug "response includes" "$obj" @@ -129,6 +131,7 @@ dns_qc_rm() { break fi done < "$tmpfile" + rm "$tmpfile" if [ -z "$record_id" ]; then From cf2f9ef2518dcefa3fa8f2bb50841fc56bb01b43 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 30 Dec 2025 16:27:21 -0500 Subject: [PATCH 42/53] Missed additional quotes --- dnsapi/dns_qc.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index ecf5d387..756939cb 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -125,13 +125,13 @@ dns_qc_rm() { record_id="" while IFS= read -r obj || [ -n "$obj" ]; do - if echo "$obj" | grep -q '"TXT"' && echo $obj | grep -q '"id"' && echo $obj | grep -q $txtvalue ; then + if echo "$obj" | grep -q '"TXT"' && echo "$obj" | grep -q '"id"' && echo "$obj" | grep -q "$txtvalue" ; then _debug "response includes" "$obj" record_id=$(echo "$obj" | sed 's/^\"id\":\([0-9]\+\).*/\1/') break fi done < "$tmpfile" - + rm "$tmpfile" if [ -z "$record_id" ]; then From 6a37f23b143f8701b19631c7d3052a63b450f602 Mon Sep 17 00:00:00 2001 From: Bob Perper Date: Tue, 30 Dec 2025 16:31:16 -0500 Subject: [PATCH 43/53] Ran shfmt locally --- dnsapi/dns_qc.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh index 756939cb..78756a35 100755 --- a/dnsapi/dns_qc.sh +++ b/dnsapi/dns_qc.sh @@ -121,16 +121,16 @@ dns_qc_rm() { fi # Temporary file to hold matched content (one per line) tmpfile=$(_mktemp) - echo "$array" | grep -o '{[^}]*}' | sed 's/^{//;s/}$//' > "$tmpfile" + echo "$array" | grep -o '{[^}]*}' | sed 's/^{//;s/}$//' >"$tmpfile" record_id="" while IFS= read -r obj || [ -n "$obj" ]; do - if echo "$obj" | grep -q '"TXT"' && echo "$obj" | grep -q '"id"' && echo "$obj" | grep -q "$txtvalue" ; then + if echo "$obj" | grep -q '"TXT"' && echo "$obj" | grep -q '"id"' && echo "$obj" | grep -q "$txtvalue"; then _debug "response includes" "$obj" record_id=$(echo "$obj" | sed 's/^\"id\":\([0-9]\+\).*/\1/') break fi - done < "$tmpfile" + done <"$tmpfile" rm "$tmpfile" From 2ad984d8ada9cf4e67ee0c6e61fd76c92d195291 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 1 Jan 2026 13:26:02 +0000 Subject: [PATCH 44/53] feat(qiniu): make forceHttps configurable via environment variable Add QINIU_FORCE_HTTPS environment variable (default: false) to allow configuring HTTPS redirect behavior for CDN domains. --- deploy/qiniu.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index 02250ed3..3737ed4e 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -8,6 +8,8 @@ # export QINIU_CDN_DOMAIN="cdn.example.com" # If you have more than one domain, just # export QINIU_CDN_DOMAIN="cdn1.example.com cdn2.example.com" +# Optional: force HTTPS redirect (default: false) +# export QINIU_FORCE_HTTPS="true" QINIU_API_BASE="https://api.qiniu.com" @@ -44,6 +46,12 @@ qiniu_deploy() { QINIU_CDN_DOMAIN="$_cdomain" fi + if [ -z "$QINIU_FORCE_HTTPS" ]; then + QINIU_FORCE_HTTPS="false" + else + _savedomainconf QINIU_FORCE_HTTPS "$QINIU_FORCE_HTTPS" + fi + ## upload certificate string_fullchain=$(sed 's/$/\\n/' "$_cfullchain" | tr -d '\n') string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n') @@ -69,7 +77,7 @@ qiniu_deploy() { _debug certId "$_certId" ## update domain ssl config - update_body="{\"certid\":$_certId,\"forceHttps\":false}" + update_body="{\"certid\":$_certId,\"forceHttps\":$QINIU_FORCE_HTTPS}" for domain in $QINIU_CDN_DOMAIN; do update_path="/domain/$domain/httpsconf" update_access_token="$(_make_access_token "$update_path")" From b08bb2ef69b087ebf36f0cae37471b1e0561f68c Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Fri, 2 Jan 2026 12:08:22 +0000 Subject: [PATCH 45/53] Fix list command for POSIX sh by avoiding brace expansion --- acme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index fc2afcc8..645de117 100755 --- a/acme.sh +++ b/acme.sh @@ -5845,7 +5845,8 @@ list() { if [ -z "$_domain" ]; then printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Profile${_sep}CA${_sep}Created${_sep}Renew" fi - for di in "${CERT_HOME}"/{*.*,*:*}/; do + for di in "${CERT_HOME}"/*.* "${CERT_HOME}"/*:*; do + [ -d "$di" ] || continue d=$(basename "$di") _debug d "$d" ( From 045e4dee2ed765a8a9d8f8c44fdd6358ce9aae70 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 2 Jan 2026 16:24:06 +0100 Subject: [PATCH 46/53] use openindiana-vm@v1 --- .github/workflows/DNS.yml | 2 +- .github/workflows/OpenIndiana.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/DNS.yml b/.github/workflows/DNS.yml index b200f56b..c0c51a84 100644 --- a/.github/workflows/DNS.yml +++ b/.github/workflows/DNS.yml @@ -539,7 +539,7 @@ jobs: - uses: actions/checkout@v4 - name: Clone acmetest run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ - - uses: vmactions/openindiana-vm@v0 + - uses: vmactions/openindiana-vm@v1 with: envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' sync: nfs diff --git a/.github/workflows/OpenIndiana.yml b/.github/workflows/OpenIndiana.yml index 19b1efaa..d17803de 100644 --- a/.github/workflows/OpenIndiana.yml +++ b/.github/workflows/OpenIndiana.yml @@ -61,7 +61,7 @@ jobs: run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV - name: Clone acmetest run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ - - uses: vmactions/openindiana-vm@v0 + - uses: vmactions/openindiana-vm@v1 with: envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET' nat: | From 94c670a759eadc1e9acb88f3dfa61c8a340c7b61 Mon Sep 17 00:00:00 2001 From: Jens Spanier <42373861+JensSpanier@users.noreply.github.com> Date: Sun, 4 Jan 2026 11:49:35 +0100 Subject: [PATCH 47/53] Remove asterisks and line breaks --- notify/pushover.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notify/pushover.sh b/notify/pushover.sh index 0f99739a..c59ec026 100644 --- a/notify/pushover.sh +++ b/notify/pushover.sh @@ -46,8 +46,8 @@ pushover_send() { fi export _H1="Content-Type: application/json" - _content="$(printf "*%s*\n" "$_content" | _json_encode)" - _subject="$(printf "*%s*\n" "$_subject" | _json_encode)" + _content="$(printf "%s" "$_content" | _json_encode)" + _subject="$(printf "%s" "$_subject" | _json_encode)" _data="{\"token\": \"$PUSHOVER_TOKEN\",\"user\": \"$PUSHOVER_USER\",\"title\": \"$_subject\",\"message\": \"$_content\",\"sound\": \"$PUSHOVER_SOUND\", \"device\": \"$PUSHOVER_DEVICE\", \"priority\": \"$PUSHOVER_PRIORITY\"}" response="$(_post "$_data" "$PUSHOVER_URI")" From 877cbe04c915bdb00c48612e0f6f3e51082c89d4 Mon Sep 17 00:00:00 2001 From: Amin Sharifi Date: Sun, 4 Jan 2026 16:18:18 +0330 Subject: [PATCH 48/53] Add VirakCloud DNS API support with add and remove TXT record functions --- dnsapi/dns_virakcloud.sh | 229 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100755 dnsapi/dns_virakcloud.sh diff --git a/dnsapi/dns_virakcloud.sh b/dnsapi/dns_virakcloud.sh new file mode 100755 index 00000000..ade4796b --- /dev/null +++ b/dnsapi/dns_virakcloud.sh @@ -0,0 +1,229 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_virakcloud_info='VirakCloud DNS API +Site: VirakCloud.com +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_virakcloud +Options: + VIRAKCLOUD_API_TOKEN VirakCloud API Bearer Token +' + +VIRAKCLOUD_API_URL="https://public-api.virakcloud.com/dns" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +#Used to add txt record +dns_virakcloud_add() { + fulldomain=$1 + txtvalue=$2 + + VIRAKCLOUD_API_TOKEN="${VIRAKCLOUD_API_TOKEN:-$(_readaccountconf_mutable VIRAKCLOUD_API_TOKEN)}" + + if [ -z "$VIRAKCLOUD_API_TOKEN" ]; then + _err "You haven't configured your VirakCloud API token yet." + _err "Please set VIRAKCLOUD_API_TOKEN environment variable or run:" + _err " export VIRAKCLOUD_API_TOKEN=\"your-api-token\"" + return 1 + fi + + _saveaccountconf_mutable VIRAKCLOUD_API_TOKEN "$VIRAKCLOUD_API_TOKEN" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + http_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + if [ "$http_code" = "401" ]; then + return 1 + fi + _err "Invalid domain" + return 1 + fi + + _debug _domain "$_domain" + _debug fulldomain "$fulldomain" + + _info "Adding TXT record" + + if _virakcloud_rest POST "domains/${_domain}/records" "{\"record\":\"${fulldomain}\",\"type\":\"TXT\",\"ttl\":3600,\"content\":\"${txtvalue}\"}"; then + if echo "$response" | grep -q "success" || echo "$response" | grep -q "\"data\""; then + _info "Added, OK" + return 0 + elif echo "$response" | grep -q "already exists" || echo "$response" | grep -q "duplicate"; then + _info "Record already exists, OK" + return 0 + else + _err "Add TXT record error." + _err "Response: $response" + return 1 + fi + fi + + _err "Add TXT record error." + return 1 +} + +#Usage: fulldomain txtvalue +#Used to remove the txt record after validation +dns_virakcloud_rm() { + fulldomain=$1 + txtvalue=$2 + + VIRAKCLOUD_API_TOKEN="${VIRAKCLOUD_API_TOKEN:-$(_readaccountconf_mutable VIRAKCLOUD_API_TOKEN)}" + + if [ -z "$VIRAKCLOUD_API_TOKEN" ]; then + _err "You haven't configured your VirakCloud API token yet." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + http_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + if [ "$http_code" = "401" ]; then + return 1 + fi + _err "Invalid domain" + return 1 + fi + + _debug _domain "$_domain" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _info "Removing TXT record" + + _debug "Getting list of records to find content ID" + if ! _virakcloud_rest GET "domains/${_domain}/records" ""; then + return 1 + fi + + _debug2 "Records response" "$response" + + contentid="" + # Extract innermost objects (content objects) which look like {"id":"...","content_raw":"..."} + # We filter for the one containing txtvalue + + target_obj=$(echo "$response" | grep -o '{[^}]*}' | grep "$txtvalue" | _head_n 1) + + if [ -n "$target_obj" ]; then + contentid=$(echo "$target_obj" | _egrep_o '"id":"[^"]*"' | cut -d '"' -f 4) + fi + + if [ -z "$contentid" ]; then + _debug "Could not find matching record ID in response" + _info "Record not found, may have been already removed" + return 0 + fi + + _debug contentid "$contentid" + + if _virakcloud_rest DELETE "domains/${_domain}/records/${fulldomain}/TXT/${contentid}" ""; then + if echo "$response" | grep -q "success" || [ -z "$response" ]; then + _info "Removed, OK" + return 0 + elif echo "$response" | grep -q "not found" || echo "$response" | grep -q "404"; then + _info "Record not found, OK" + return 0 + else + _err "Remove TXT record error." + _err "Response: $response" + return 1 + fi + fi + + _err "Remove TXT record error." + return 1 +} + +#################### Private functions below ################################## + +#_acme-challenge.www.domain.com +#returns +# _domain=domain.com +_get_root() { + domain=$1 + i=1 + p=1 + + # Optimization: skip _acme-challenge subdomain to avoid 422 errors + if echo "$domain" | grep -q "^_acme-challenge."; then + i=2 + fi + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) + _debug h "$h" + + if [ -z "$h" ]; then + return 1 + fi + + if ! _virakcloud_rest GET "domains/$h" ""; then + http_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + if [ "$http_code" = "401" ]; then + return 1 + fi + p=$i + i=$(_math "$i" + 1) + continue + fi + + if echo "$response" | grep -q "\"name\""; then + _domain="$h" + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +_virakcloud_rest() { + m=$1 + ep="$2" + data="$3" + + _debug "$ep" + + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $VIRAKCLOUD_API_TOKEN" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$VIRAKCLOUD_API_URL/$ep" "" "$m")" + else + response="$(_get "$VIRAKCLOUD_API_URL/$ep")" + fi + + _ret="$?" + + if [ "$_ret" != "0" ]; then + _err "error on $m $ep" + return 1 + fi + + http_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + _debug "http response code" "$http_code" + + if [ "$http_code" = "401" ]; then + _err "VirakCloud API returned 401 Unauthorized." + _err "Your VIRAKCLOUD_API_TOKEN is invalid or expired." + _err "Please check your API token and try again." + return 1 + fi + + if [ "$http_code" = "403" ]; then + _err "VirakCloud API returned 403 Forbidden." + _err "Your API token does not have permission to access this resource." + return 1 + fi + + if [ -n "$http_code" ] && [ "$http_code" -ge 400 ]; then + _err "VirakCloud API error. HTTP code: $http_code" + _err "Response: $response" + return 1 + fi + + _debug2 response "$response" + return 0 +} From ef035248c35976ff849eda4011e67f08bac41831 Mon Sep 17 00:00:00 2001 From: Amin Sharifi Date: Sun, 4 Jan 2026 16:29:30 +0330 Subject: [PATCH 49/53] Add VirakCloud DNS API support --- dnsapi/dns_virakcloud.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_virakcloud.sh b/dnsapi/dns_virakcloud.sh index ade4796b..84da5773 100755 --- a/dnsapi/dns_virakcloud.sh +++ b/dnsapi/dns_virakcloud.sh @@ -43,6 +43,7 @@ dns_virakcloud_add() { _info "Adding TXT record" + if _virakcloud_rest POST "domains/${_domain}/records" "{\"record\":\"${fulldomain}\",\"type\":\"TXT\",\"ttl\":3600,\"content\":\"${txtvalue}\"}"; then if echo "$response" | grep -q "success" || echo "$response" | grep -q "\"data\""; then _info "Added, OK" From 70462b5ac3f257d8814002427b0693f67b437b3c Mon Sep 17 00:00:00 2001 From: Amin Sharifi Date: Sun, 4 Jan 2026 16:33:37 +0330 Subject: [PATCH 50/53] run `~/shfmt -l -w -i 2 dnsapi/dns_virakcloud.sh` and Remove unnecessary blank lines in dns_virakcloud.sh --- dnsapi/dns_virakcloud.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_virakcloud.sh b/dnsapi/dns_virakcloud.sh index 84da5773..7ae665d2 100755 --- a/dnsapi/dns_virakcloud.sh +++ b/dnsapi/dns_virakcloud.sh @@ -43,7 +43,6 @@ dns_virakcloud_add() { _info "Adding TXT record" - if _virakcloud_rest POST "domains/${_domain}/records" "{\"record\":\"${fulldomain}\",\"type\":\"TXT\",\"ttl\":3600,\"content\":\"${txtvalue}\"}"; then if echo "$response" | grep -q "success" || echo "$response" | grep -q "\"data\""; then _info "Added, OK" @@ -101,11 +100,11 @@ dns_virakcloud_rm() { contentid="" # Extract innermost objects (content objects) which look like {"id":"...","content_raw":"..."} # We filter for the one containing txtvalue - + target_obj=$(echo "$response" | grep -o '{[^}]*}' | grep "$txtvalue" | _head_n 1) - + if [ -n "$target_obj" ]; then - contentid=$(echo "$target_obj" | _egrep_o '"id":"[^"]*"' | cut -d '"' -f 4) + contentid=$(echo "$target_obj" | _egrep_o '"id":"[^"]*"' | cut -d '"' -f 4) fi if [ -z "$contentid" ]; then @@ -197,7 +196,7 @@ _virakcloud_rest() { fi _ret="$?" - + if [ "$_ret" != "0" ]; then _err "error on $m $ep" return 1 From 35f99c545c2c9dd9bca8211e3ab29bbcd123d259 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 5 Jan 2026 21:10:58 +0100 Subject: [PATCH 51/53] add debug wiki --- .github/workflows/DNS.yml | 42 +++++++++++++++++++++++++++--- .github/workflows/DragonFlyBSD.yml | 6 ++++- .github/workflows/FreeBSD.yml | 6 ++++- .github/workflows/NetBSD.yml | 8 ++++-- .github/workflows/Omnios.yml | 6 ++++- .github/workflows/OpenBSD.yml | 6 ++++- .github/workflows/OpenIndiana.yml | 6 ++++- .github/workflows/Solaris.yml | 6 ++++- 8 files changed, 74 insertions(+), 12 deletions(-) diff --git a/.github/workflows/DNS.yml b/.github/workflows/DNS.yml index c0c51a84..4634ed96 100644 --- a/.github/workflows/DNS.yml +++ b/.github/workflows/DNS.yml @@ -251,7 +251,11 @@ jobs: fi cd ../acmetest ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" @@ -302,7 +306,11 @@ jobs: fi cd ../acmetest ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" @@ -354,7 +362,11 @@ jobs: fi cd ../acmetest ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" @@ -406,7 +418,11 @@ jobs: fi cd ../acmetest ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" @@ -464,6 +480,11 @@ jobs: fi cd ../acmetest ./letest.sh + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" Omnios: @@ -513,6 +534,12 @@ jobs: fi cd ../acmetest ./letest.sh + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" + OpenIndiana: @@ -562,5 +589,12 @@ jobs: fi cd ../acmetest ./letest.sh + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" + + diff --git a/.github/workflows/DragonFlyBSD.yml b/.github/workflows/DragonFlyBSD.yml index b047a210..dda8c99f 100644 --- a/.github/workflows/DragonFlyBSD.yml +++ b/.github/workflows/DragonFlyBSD.yml @@ -67,5 +67,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" diff --git a/.github/workflows/FreeBSD.yml b/.github/workflows/FreeBSD.yml index a4fca67c..21123c4a 100644 --- a/.github/workflows/FreeBSD.yml +++ b/.github/workflows/FreeBSD.yml @@ -72,5 +72,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" diff --git a/.github/workflows/NetBSD.yml b/.github/workflows/NetBSD.yml index 13b70350..40421552 100644 --- a/.github/workflows/NetBSD.yml +++ b/.github/workflows/NetBSD.yml @@ -67,5 +67,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" + diff --git a/.github/workflows/Omnios.yml b/.github/workflows/Omnios.yml index 5d0af1b1..20eb24d7 100644 --- a/.github/workflows/Omnios.yml +++ b/.github/workflows/Omnios.yml @@ -71,5 +71,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml index 98e18545..fab6e4fd 100644 --- a/.github/workflows/OpenBSD.yml +++ b/.github/workflows/OpenBSD.yml @@ -72,5 +72,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" diff --git a/.github/workflows/OpenIndiana.yml b/.github/workflows/OpenIndiana.yml index d17803de..abad376c 100644 --- a/.github/workflows/OpenIndiana.yml +++ b/.github/workflows/OpenIndiana.yml @@ -71,5 +71,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" diff --git a/.github/workflows/Solaris.yml b/.github/workflows/Solaris.yml index 21a16d1a..2388da71 100644 --- a/.github/workflows/Solaris.yml +++ b/.github/workflows/Solaris.yml @@ -73,5 +73,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" From 2092d6061b0ec963534b8a39b0624be96c07e2c4 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 5 Jan 2026 21:38:37 +0100 Subject: [PATCH 52/53] fix https://github.com/acmesh-official/acme.sh/issues/6736#issuecomment-3707981300 --- acme.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 645de117..2d2ef796 100755 --- a/acme.sh +++ b/acme.sh @@ -5749,6 +5749,10 @@ signcsr() { _local_addr="${11}" _challenge_alias="${12}" _preferred_chain="${13}" + _valid_f="${14}" + _valid_t="${15}" + _cert_prof="${16}" + _en_key_usage="${17}" _csrsubj=$(_readSubjectFromCSR "$_csrfile") if [ "$?" != "0" ]; then @@ -5792,7 +5796,7 @@ signcsr() { _info "Copying CSR to: $CSR_PATH" cp "$_csrfile" "$CSR_PATH" - issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_addr" "$_challenge_alias" "$_preferred_chain" + issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_addr" "$_challenge_alias" "$_preferred_chain" "$_valid_f" "$_valid_t" "$_cert_prof" "$_en_key_usage" } @@ -8148,7 +8152,7 @@ _process() { deploy "$_domain" "$_deploy_hook" "$_ecc" ;; signcsr) - signcsr "$_csr" "$_webroot" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" "$_preferred_chain" + signcsr "$_csr" "$_webroot" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" "$_preferred_chain" "$_valid_from" "$_valid_to" "$_certificate_profile" "$_extended_key_usage" ;; showcsr) showcsr "$_csr" "$_domain" From 903a53991d6cf01170864d09585b2406f5c5f16e Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 5 Jan 2026 22:06:33 +0100 Subject: [PATCH 53/53] fix bugs --- acme.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 2cec6592..d2e3b766 100755 --- a/acme.sh +++ b/acme.sh @@ -4470,7 +4470,7 @@ issue() { Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then - _valid_to_saved=$(_readdomainconf Le_Valid_to) + _valid_to_saved=$(_readdomainconf Le_Valid_To) if [ "$_valid_to_saved" ] && ! _startswith "$_valid_to_saved" "+"; then _info "The domain is set to be valid to: $_valid_to_saved" _info "It cannot be renewed automatically" @@ -5568,6 +5568,10 @@ renew() { Le_RenewHook="$(_readdomainconf Le_RenewHook)" Le_Preferred_Chain="$(_readdomainconf Le_Preferred_Chain)" Le_Certificate_Profile="$(_readdomainconf Le_Certificate_Profile)" + Le_Valid_From="$(_readdomainconf Le_Valid_From)" + Le_Valid_To="$(_readdomainconf Le_Valid_To)" + Le_ExtKeyUse="$(_readdomainconf Le_ExtKeyUse)" + # When renewing from an old version, the empty Le_Keylength means 2048. # Note, do not use DEFAULT_DOMAIN_KEY_LENGTH as that value may change over # time but an empty value implies 2048 specifically.