From b0ca4435fdbee019ac72f8df0cb304e1de5deffc Mon Sep 17 00:00:00 2001 From: Ciaran Walsh Date: Wed, 21 Feb 2024 00:21:09 +0000 Subject: [PATCH 01/53] Fix for empty error objects in response breaking extraction of domain validation types Fix for empty error objects in the response which mess up the extraction of domain validation types due to the closing brace in the error object prematurely matching the end of the search pattern. This seems to be a recent change with ZeroSSL in particular where "error":{} is being included in responses. There could potentially be a related issue if there is a complex error object ever returned in the validation check response where an embedded sub-object could lead to an incomplete extraction of the error message, roughly around line 5040. Adapted from fix suggested here: https://github.com/acmesh-official/acme.sh/issues/4933#issuecomment-1870499018 --- acme.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 38ccaade..34ac49e8 100755 --- a/acme.sh +++ b/acme.sh @@ -4722,7 +4722,8 @@ $_authorizations_map" _debug keyauthorization "$keyauthorization" fi - entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" + # Fix for empty error objects in response which mess up the original code, adapted from fix suggested here: https://github.com/acmesh-official/acme.sh/issues/4933#issuecomment-1870499018 + entry="$(echo "$response" | sed s/'"error":{}'/'"error":null'/ | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$keyauthorization" -a -z "$entry" ]; then @@ -6283,7 +6284,8 @@ _deactivate() { fi _debug "Trigger validation." vtype="$(_getIdType "$_d_domain")" - entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" + # Fix for empty error objects in response which mess up the original code, adapted from fix suggested here: https://github.com/acmesh-official/acme.sh/issues/4933#issuecomment-1870499018 + entry="$(echo "$response" | sed s/'"error":{}'/'"error":null'/ | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ]; then _err "Error, can not get domain token $d" From 2beb2f5659e968423f91c8db2d634d85177fff2a Mon Sep 17 00:00:00 2001 From: Manuel Sanchez Pinar Date: Thu, 4 Jul 2024 14:03:20 +0200 Subject: [PATCH 02/53] fix: rage4 - add error 400 and TXT cleanup The following error happens if the header is set to 'Content-Type: application/json': {"statusCode":400,"message":"One or more errors occurred!", "errors":{"serializerErrors":["The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. LineNumber: 0 | BytePositionInLine: 0."]}} Fix TXT removal --- dnsapi/dns_rage4.sh | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_rage4.sh b/dnsapi/dns_rage4.sh index ad312759..c27fbc5f 100755 --- a/dnsapi/dns_rage4.sh +++ b/dnsapi/dns_rage4.sh @@ -42,6 +42,14 @@ dns_rage4_add() { _debug _domain_id "$_domain_id" _rage4_rest "createrecord/?id=$_domain_id&name=$fulldomain&content=$unquotedtxtvalue&type=TXT&active=true&ttl=1" + + # Response after adding a TXT record should be something like this: + # {"status":true,"id":28160443,"error":null} + if ! _contains "$response" '"error":null' >/dev/null; then + _err "Error while adding TXT record: '$response'" + return 1 + fi + return 0 } @@ -63,7 +71,12 @@ dns_rage4_rm() { _debug "Getting txt records" _rage4_rest "getrecords/?id=${_domain_id}" - _record_id=$(echo "$response" | sed -rn 's/.*"id":([[:digit:]]+)[^\}]*'"$txtvalue"'.*/\1/p') + _record_id=$(echo "$response" | tr '{' '\n' | grep '"TXT"' | grep "\"$txtvalue" | sed -rn 's/.*"id":([[:digit:]]+),.*/\1/p') + if [ -z "$_record_id" ]; then + _err "error retrieving the record_id of the new TXT record in order to delete it, got: '$_record_id'." + return 1 + fi + _rage4_rest "deleterecord/?id=${_record_id}" return 0 } @@ -105,8 +118,7 @@ _rage4_rest() { token_trimmed=$(echo "$RAGE4_TOKEN" | tr -d '"') auth=$(printf '%s:%s' "$username_trimmed" "$token_trimmed" | _base64) - export _H1="Content-Type: application/json" - export _H2="Authorization: Basic $auth" + export _H1="Authorization: Basic $auth" response="$(_get "$RAGE4_Api$ep")" From 29342e036f5b3e821be3770686bdef022623ef61 Mon Sep 17 00:00:00 2001 From: kir Date: Tue, 11 Mar 2025 08:07:38 +0000 Subject: [PATCH 03/53] Update _get_root url in dnsapi/dns_fornex.sh --- dnsapi/dns_fornex.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_fornex.sh b/dnsapi/dns_fornex.sh index 91e5491b..dcaa2297 100644 --- a/dnsapi/dns_fornex.sh +++ b/dnsapi/dns_fornex.sh @@ -95,7 +95,7 @@ _get_root() { return 1 fi - if ! _rest GET "dns/domain/"; then + if ! _rest GET "dns/domain/?q=$h"; then return 1 fi From e0da5f170304dc373a4a647d83fbe0a13a53ec7e Mon Sep 17 00:00:00 2001 From: OPPO9008 <41640509+OPPO9008@users.noreply.github.com> Date: Mon, 19 May 2025 09:49:21 +0800 Subject: [PATCH 04/53] Update dns_la.sh --- dnsapi/dns_la.sh | 109 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 26 deletions(-) diff --git a/dnsapi/dns_la.sh b/dnsapi/dns_la.sh index f19333c4..97437897 100644 --- a/dnsapi/dns_la.sh +++ b/dnsapi/dns_la.sh @@ -1,14 +1,18 @@ #!/usr/bin/env sh -# shellcheck disable=SC2034 -dns_la_info='dns.la -Site: dns.la -Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_la -Options: - LA_Id API ID - LA_Key API key -Issues: github.com/acmesh-official/acme.sh/issues/4257 -' +# LA_Id="123" +# LA_Sk="456" +# LA_Token="" +# +#Site: dns.la +#Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_la +#Options: +#我的账户 API 密钥 中获取 APIID APISecret +# LA_Id APIID +# LA_Key APISecret +# LA_Token 用冒号连接 APIID APISecret 再base64生成 +#Issues: github.com/acmesh-official/acme.sh/issues/4257 +#' LA_Api="https://api.dns.la/api" ######## Public functions ##################### @@ -19,18 +23,23 @@ dns_la_add() { txtvalue=$2 LA_Id="${LA_Id:-$(_readaccountconf_mutable LA_Id)}" - LA_Key="${LA_Key:-$(_readaccountconf_mutable LA_Key)}" + LA_Sk="${LA_Sk:-$(_readaccountconf_mutable LA_Sk)}" + _log "LA_Id=$LA_Id" + _log "LA_Sk=$LA_Sk" - if [ -z "$LA_Id" ] || [ -z "$LA_Key" ]; then + if [ -z "$LA_Id" ] || [ -z "$LA_Sk" ]; then LA_Id="" - LA_Key="" + LA_Sk="" _err "You didn't specify a dnsla api id and key yet." return 1 fi #save the api key and email to the account conf file. _saveaccountconf_mutable LA_Id "$LA_Id" - _saveaccountconf_mutable LA_Key "$LA_Key" + _saveaccountconf_mutable LA_Sk "$LA_Sk" + + # generate dnsla token + _la_token _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -42,11 +51,13 @@ dns_la_add() { _debug _domain "$_domain" _info "Adding record" - if _la_rest "record.ashx?cmd=create&apiid=$LA_Id&apipass=$LA_Key&rtype=json&domainid=$_domain_id&host=$_sub_domain&recordtype=TXT&recorddata=$txtvalue&recordline="; then - if _contains "$response" '"resultid":'; then + + # record type is enum in new api, 16 for TXT + if _la_post "{\"domainId\":\"$_domain_id\",\"type\":16,\"host\":\"$_sub_domain\",\"data\":\"$txtvalue\",\"ttl\":600}" "record"; then + if _contains "$response" '"id":'; then _info "Added, OK" return 0 - elif _contains "$response" '"code":532'; then + elif _contains "$response" '"msg":"与已有记录冲突"'; then _info "Already exists, OK" return 0 else @@ -54,7 +65,7 @@ dns_la_add() { return 1 fi fi - _err "Add txt record error." + _err "Add txt record failed." return 1 } @@ -65,7 +76,9 @@ dns_la_rm() { txtvalue=$2 LA_Id="${LA_Id:-$(_readaccountconf_mutable LA_Id)}" - LA_Key="${LA_Key:-$(_readaccountconf_mutable LA_Key)}" + LA_Sk="${LA_Sk:-$(_readaccountconf_mutable LA_Sk)}" + + _la_token _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -77,27 +90,29 @@ dns_la_rm() { _debug _domain "$_domain" _debug "Getting txt records" - if ! _la_rest "record.ashx?cmd=listn&apiid=$LA_Id&apipass=$LA_Key&rtype=json&domainid=$_domain_id&domain=$_domain&host=$_sub_domain&recordtype=TXT&recorddata=$txtvalue"; then + # record type is enum in new api, 16 for TXT + if ! _la_get "recordList?pageIndex=1&pageSize=10&domainId=$_domain_id&host=$_sub_domain&type=16&data=$txtvalue"; then _err "Error" return 1 fi - if ! _contains "$response" '"recordid":'; then + if ! _contains "$response" '"id":'; then _info "Don't need to remove." return 0 fi - record_id=$(printf "%s" "$response" | grep '"recordid":' | cut -d : -f 2 | cut -d , -f 1 | tr -d '\r' | tr -d '\n') + record_id=$(printf "%s" "$response" | grep '"id":' | head -n1 | sed 's/.*"id": *"\([^"]*\)".*/\1/') _debug "record_id" "$record_id" if [ -z "$record_id" ]; then _err "Can not get record id to remove." return 1 fi - if ! _la_rest "record.ashx?cmd=remove&apiid=$LA_Id&apipass=$LA_Key&rtype=json&domainid=$_domain_id&domain=$_domain&recordid=$record_id"; then + # remove record in new api is RESTful + if ! _la_post "" "record?id=$record_id" "DELETE"; then _err "Delete record error." return 1 fi - _contains "$response" '"code":300' + _contains "$response" '"code":200' } @@ -119,12 +134,13 @@ _get_root() { return 1 fi - if ! _la_rest "domain.ashx?cmd=get&apiid=$LA_Id&apipass=$LA_Key&rtype=json&domain=$h"; then + if ! _la_get "domain?domain=$h"; then return 1 fi - if _contains "$response" '"domainid":'; then - _domain_id=$(printf "%s" "$response" | grep '"domainid":' | cut -d : -f 2 | cut -d , -f 1 | tr -d '\r' | tr -d '\n') + if _contains "$response" '"domain":'; then + _domain_id=$(echo "$response" | sed -n 's/.*"id":"\([^"]*\)".*/\1/p') + _log "_domain_id" "$_domain_id" if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _domain="$h" @@ -143,6 +159,21 @@ _la_rest() { url="$LA_Api/$1" _debug "$url" + if ! response="$(_get "$url" "Authorization: Basic $LA_Token" | tr -d ' ' | tr "}" ",")"; then + _err "Error: $url" + return 1 + fi + + _debug2 response "$response" + return 0 +} + +_la_get() { + url="$LA_Api/$1" + _debug "$url" + + export _H1="Authorization: Basic $LA_Token" + if ! response="$(_get "$url" | tr -d ' ' | tr "}" ",")"; then _err "Error: $url" return 1 @@ -151,3 +182,29 @@ _la_rest() { _debug2 response "$response" return 0 } + +# Usage: _la_post body url [POST|PUT|DELETE] +_la_post() { + body=$1 + url="$LA_Api/$2" + http_method=$3 + _debug "$body" + _debug "$url" + + export _H1="Authorization: Basic $LA_Token" + + if ! response="$(_post "$body" "$url" "" "$http_method")"; then + _err "Error: $url" + return 1 + fi + + _debug2 response "$response" + return 0 +} + +_la_token() { + LA_Token=$(printf "%s:%s" "$LA_Id" "$LA_Sk" | base64 -w 0) + _debug "$LA_Token" + + return 0 +} From 9e7d1b9ce75373c4233790527054925f42da5d16 Mon Sep 17 00:00:00 2001 From: OPPO9008 <41640509+OPPO9008@users.noreply.github.com> Date: Mon, 19 May 2025 13:16:30 +0800 Subject: [PATCH 05/53] Update dns_la.sh --- dnsapi/dns_la.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_la.sh b/dnsapi/dns_la.sh index 97437897..ba8ebcac 100644 --- a/dnsapi/dns_la.sh +++ b/dnsapi/dns_la.sh @@ -203,7 +203,7 @@ _la_post() { } _la_token() { - LA_Token=$(printf "%s:%s" "$LA_Id" "$LA_Sk" | base64 -w 0) + LA_Token=$(printf "%s:%s" "$LA_Id" "$LA_Sk" | _base64) _debug "$LA_Token" return 0 From 500cfbc19c08feab8763fd141181a5820290747e Mon Sep 17 00:00:00 2001 From: OPPO9008 <41640509+OPPO9008@users.noreply.github.com> Date: Mon, 19 May 2025 21:29:33 +0800 Subject: [PATCH 06/53] Update dns_la.sh --- dnsapi/dns_la.sh | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_la.sh b/dnsapi/dns_la.sh index ba8ebcac..7c3765cd 100644 --- a/dnsapi/dns_la.sh +++ b/dnsapi/dns_la.sh @@ -2,17 +2,16 @@ # LA_Id="123" # LA_Sk="456" -# LA_Token="" -# -#Site: dns.la -#Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_la -#Options: -#我的账户 API 密钥 中获取 APIID APISecret -# LA_Id APIID -# LA_Key APISecret -# LA_Token 用冒号连接 APIID APISecret 再base64生成 -#Issues: github.com/acmesh-official/acme.sh/issues/4257 -#' +# shellcheck disable=SC2034 +LA_Token='dns.la +Site: dns.la +Docs: https://www.dns.la/docs/ApiDoc +Options: + LA_Id APIID + LA_Key APISecret + LA_Token 用冒号连接 APIID APISecret 再base64生成 +Issues: github.com/acmesh-official/acme.sh/issues/4257 +' LA_Api="https://api.dns.la/api" ######## Public functions ##################### From cddf098f47cde203dee97335176ef04bc7f3cdcc Mon Sep 17 00:00:00 2001 From: OPPO9008 <41640509+OPPO9008@users.noreply.github.com> Date: Tue, 20 May 2025 20:28:59 +0800 Subject: [PATCH 07/53] Update dns_la.sh --- dnsapi/dns_la.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_la.sh b/dnsapi/dns_la.sh index 7c3765cd..651b74c0 100644 --- a/dnsapi/dns_la.sh +++ b/dnsapi/dns_la.sh @@ -5,10 +5,10 @@ # shellcheck disable=SC2034 LA_Token='dns.la Site: dns.la -Docs: https://www.dns.la/docs/ApiDoc +Docs: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_la Options: LA_Id APIID - LA_Key APISecret + LA_Sk APISecret LA_Token 用冒号连接 APIID APISecret 再base64生成 Issues: github.com/acmesh-official/acme.sh/issues/4257 ' From c8f1e4119719a911087dc266090ca04eb7dd20c1 Mon Sep 17 00:00:00 2001 From: OPPO9008 <41640509+OPPO9008@users.noreply.github.com> Date: Tue, 20 May 2025 20:29:44 +0800 Subject: [PATCH 08/53] Update dns_la.sh --- dnsapi/dns_la.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_la.sh b/dnsapi/dns_la.sh index 651b74c0..c2934b54 100644 --- a/dnsapi/dns_la.sh +++ b/dnsapi/dns_la.sh @@ -5,7 +5,7 @@ # shellcheck disable=SC2034 LA_Token='dns.la Site: dns.la -Docs: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_la +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_la Options: LA_Id APIID LA_Sk APISecret From 19678db9333f901219befcbd388fc454aa6b7119 Mon Sep 17 00:00:00 2001 From: OPPO9008 <41640509+OPPO9008@users.noreply.github.com> Date: Fri, 6 Jun 2025 02:06:27 +0800 Subject: [PATCH 09/53] Update dns_la.sh --- dnsapi/dns_la.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_la.sh b/dnsapi/dns_la.sh index c2934b54..772f8845 100644 --- a/dnsapi/dns_la.sh +++ b/dnsapi/dns_la.sh @@ -3,7 +3,7 @@ # LA_Id="123" # LA_Sk="456" # shellcheck disable=SC2034 -LA_Token='dns.la +dns_la_info='dns.la Site: dns.la Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_la Options: From bff1064dbd205db86832c876151304b97bf9d78f Mon Sep 17 00:00:00 2001 From: Lambiek12 Date: Sun, 8 Jun 2025 15:39:10 +0200 Subject: [PATCH 10/53] Add new dnsapi support for OpenProvider.eu using new REST API --- dnsapi/dns_openprovider_rest.sh | 193 ++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 dnsapi/dns_openprovider_rest.sh diff --git a/dnsapi/dns_openprovider_rest.sh b/dnsapi/dns_openprovider_rest.sh new file mode 100644 index 00000000..a6725fcc --- /dev/null +++ b/dnsapi/dns_openprovider_rest.sh @@ -0,0 +1,193 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_openprovider_rest_info='OpenProvider (REST) +Domains: OpenProvider.com +Site: OpenProvider.eu +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_openprovider_rest +Options: + OPENPROVIDER_REST_USERNAME Openprovider Account Username + OPENPROVIDER_REST_PASSWORD Openprovider Account Password +Issues: github.com/acmesh-official/acme.sh/issues/6122 +Author: Lambiek12 +' + +OPENPROVIDER_API_URL="https://api.openprovider.eu/v1beta" + +######## Public functions ##################### + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_openprovider_rest_add() { + fulldomain=$1 + txtvalue=$2 + + _openprovider_prepare_credentials || return 1 + + _debug "Try fetch OpenProvider DNS zone details" + if ! _get_dns_zone "$fulldomain"; then + _err "DNS zone not found within configured OpenProvider account." + return 1 + fi + + if [ -n "$_domain_id" ]; then + addzonerecordrequestparameters="dns/zones/$_domain_name" + addzonerecordrequestbody="{\"id\":$_domain_id,\"name\":\"$_domain_name\",\"records\":{\"add\":[{\"name\":\"$_sub_domain\",\"ttl\":900,\"type\":\"TXT\",\"value\":\"$txtvalue\"}]}}" + + if _openprovider_rest PUT "$addzonerecordrequestparameters" "$addzonerecordrequestbody"; then + if _contains "$response" "\"success\":true"; then + return 0 + elif _contains "$response" "\"Duplicate record\""; then + _debug "Record already existed" + return 0 + else + _err "Adding TXT record failed due to errors." + return 1 + fi + fi + fi + + _err "Adding TXT record failed due to errors." + return 1 +} + +# Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to remove the txt record after validation +dns_openprovider_rest_rm() { + fulldomain=$1 + txtvalue=$2 + + _openprovider_prepare_credentials || return 1 + + _debug "Try fetch OpenProvider DNS zone details" + if ! _get_dns_zone "$fulldomain"; then + _err "DNS zone not found within configured OpenProvider account." + return 1 + fi + + if [ -n "$_domain_id" ]; then + removezonerecordrequestparameters="dns/zones/$_domain_name" + removezonerecordrequestbody="{\"id\":$_domain_id,\"name\":\"$_domain_name\",\"records\":{\"remove\":[{\"name\":\"$_sub_domain\",\"ttl\":900,\"type\":\"TXT\",\"value\":\"\\\"$txtvalue\\\"\"}]}}" + + if _openprovider_rest PUT "$removezonerecordrequestparameters" "$removezonerecordrequestbody"; then + if _contains "$response" "\"success\":true"; then + return 0 + else + _err "Removing TXT record failed due to errors." + return 1 + fi + fi + fi + + _err "Removing TXT record failed due to errors." + return 1 +} + +#################### OpenProvider API common functions #################### +_openprovider_prepare_credentials() { + OPENPROVIDER_REST_USERNAME="${OPENPROVIDER_REST_USERNAME:-$(_readaccountconf_mutable OPENPROVIDER_REST_USERNAME)}" + OPENPROVIDER_REST_PASSWORD="${OPENPROVIDER_REST_PASSWORD:-$(_readaccountconf_mutable OPENPROVIDER_REST_PASSWORD)}" + + if [ -z "$OPENPROVIDER_REST_USERNAME" ] || [ -z "$OPENPROVIDER_REST_PASSWORD" ]; then + OPENPROVIDER_REST_USERNAME="" + OPENPROVIDER_REST_PASSWORD="" + _err "You didn't specify the Openprovider username or password yet." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable OPENPROVIDER_REST_USERNAME "$OPENPROVIDER_REST_USERNAME" + _saveaccountconf_mutable OPENPROVIDER_REST_PASSWORD "$OPENPROVIDER_REST_PASSWORD" +} + +_openprovider_rest() { + httpmethod=$1 + queryparameters=$2 + requestbody=$3 + + _openprovider_rest_login + if [ -z "$openproviderauthtoken" ]; then + _err "Unable to fetch authentication token from Openprovider API." + return 1 + fi + + export _H1="Content-Type: application/json" + export _H2="Accept: application/json" + export _H3="Authorization: Bearer $openproviderauthtoken" + + _debug httpmethod "$httpmethod" + _debug requestfullurl "$OPENPROVIDER_API_URL/$queryparameters" + _debug queryparameters "$queryparameters" + + if [ "$httpmethod" != "GET" ]; then + _debug requestbody "$requestbody" + + response="$(_post "$requestbody" "$OPENPROVIDER_API_URL/$queryparameters" "" "$httpmethod")" + else + response="$(_get "$OPENPROVIDER_API_URL/$queryparameters")" + fi + + if [ "$?" != "0" ]; then + _err "No valid parameters supplied for Openprovider API: Error $queryparameters" + return 1 + fi + + _debug2 response "$response" + + return 0 +} + +_openprovider_rest_login() { + export _H1="Content-Type: application/json" + export _H2="Accept: application/json" + + loginrequesturl="$OPENPROVIDER_API_URL/auth/login" + loginrequestbody="{\"ip\":\"0.0.0.0\",\"password\":\"$OPENPROVIDER_REST_PASSWORD\",\"username\":\"$OPENPROVIDER_REST_USERNAME\"}" + loginresponse="$(_post "$loginrequestbody" "$loginrequesturl" "" "POST")" + + openproviderauthtoken="$(printf "%s\n" "$loginresponse" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')" + _debug openproviderauthtoken "$openproviderauthtoken" + + export openproviderauthtoken +} + +#################### Private functions ################################## + +# Usage: _get_dns_zone _acme-challenge.www.domain.com +# Returns: +# _domain_id=123456789 +# _domain_name=domain.com +# _sub_domain=_acme-challenge.www +_get_dns_zone() { + domain=$1 + i=1 + p=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) + if [ -z "$h" ]; then + # Empty value not allowed + return 1 + fi + + if ! _openprovider_rest GET "dns/zones/$h" ""; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\""; then + _domain_id="$(printf "%s\n" "$response" | _egrep_o '"id" *: *[^,]*' | _head_n 1 | sed 's#^"id" *: *##')" + _debug _domain_id "$_domain_id" + + _domain_name="$h" + _debug _domain_name "$_domain_name" + + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") + _debug _sub_domain "$_sub_domain" + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} From 06d3739a8dc9b235aadc0460d7ddcbb2e867a04e Mon Sep 17 00:00:00 2001 From: Lambiek12 Date: Sun, 8 Jun 2025 17:29:39 +0200 Subject: [PATCH 11/53] Cleanup duplicate debug log output based on DNS test run --- dnsapi/dns_openprovider_rest.sh | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/dnsapi/dns_openprovider_rest.sh b/dnsapi/dns_openprovider_rest.sh index a6725fcc..3b8d20d2 100644 --- a/dnsapi/dns_openprovider_rest.sh +++ b/dnsapi/dns_openprovider_rest.sh @@ -113,14 +113,8 @@ _openprovider_rest() { export _H1="Content-Type: application/json" export _H2="Accept: application/json" export _H3="Authorization: Bearer $openproviderauthtoken" - - _debug httpmethod "$httpmethod" - _debug requestfullurl "$OPENPROVIDER_API_URL/$queryparameters" - _debug queryparameters "$queryparameters" - + if [ "$httpmethod" != "GET" ]; then - _debug requestbody "$requestbody" - response="$(_post "$requestbody" "$OPENPROVIDER_API_URL/$queryparameters" "" "$httpmethod")" else response="$(_get "$OPENPROVIDER_API_URL/$queryparameters")" @@ -145,7 +139,6 @@ _openprovider_rest_login() { loginresponse="$(_post "$loginrequestbody" "$loginrequesturl" "" "POST")" openproviderauthtoken="$(printf "%s\n" "$loginresponse" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')" - _debug openproviderauthtoken "$openproviderauthtoken" export openproviderauthtoken } From fcd358eb71e0c8ca49b11e2fbca133c9c5937844 Mon Sep 17 00:00:00 2001 From: Lambiek12 Date: Sun, 8 Jun 2025 17:35:09 +0200 Subject: [PATCH 12/53] Resolve spellcheck error --- dnsapi/dns_openprovider_rest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_openprovider_rest.sh b/dnsapi/dns_openprovider_rest.sh index 3b8d20d2..210dc6fc 100644 --- a/dnsapi/dns_openprovider_rest.sh +++ b/dnsapi/dns_openprovider_rest.sh @@ -113,7 +113,7 @@ _openprovider_rest() { export _H1="Content-Type: application/json" export _H2="Accept: application/json" export _H3="Authorization: Bearer $openproviderauthtoken" - + if [ "$httpmethod" != "GET" ]; then response="$(_post "$requestbody" "$OPENPROVIDER_API_URL/$queryparameters" "" "$httpmethod")" else From 2bea808251d3e0c65fab47dafba0fec636128a6a Mon Sep 17 00:00:00 2001 From: OPPO9008 <41640509+OPPO9008@users.noreply.github.com> Date: Wed, 2 Jul 2025 21:15:46 +0800 Subject: [PATCH 13/53] Update dns_la.sh --- dnsapi/dns_la.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_la.sh b/dnsapi/dns_la.sh index 772f8845..9cb6327e 100644 --- a/dnsapi/dns_la.sh +++ b/dnsapi/dns_la.sh @@ -100,7 +100,7 @@ dns_la_rm() { return 0 fi - record_id=$(printf "%s" "$response" | grep '"id":' | head -n1 | sed 's/.*"id": *"\([^"]*\)".*/\1/') + record_id=$(printf "%s" "$response" | grep '"id":' | _head_n 1 | sed 's/.*"id": *"\([^"]*\)".*/\1/') _debug "record_id" "$record_id" if [ -z "$record_id" ]; then _err "Can not get record id to remove." From 76b68f7ccb3063a0d065ab1009d70156d3f5d135 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 6 Jul 2025 01:34:21 +0300 Subject: [PATCH 14/53] dnsapi: dns_mydnsjp.sh fix author The @epgdatacapbon was renamed to @tkmsst Signed-off-by: Sergey Ponomarev --- dnsapi/dns_mydnsjp.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ##################### From 01ed3c332648104652c6b7af3ff4518ebe3a32f2 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 6 Jul 2025 01:36:40 +0300 Subject: [PATCH 15/53] dnsapi: dns_ddnss.sh remove RaidenII from authors He made the DuckDNS script that was used for this script but he can't support the script. Signed-off-by: Sergey Ponomarev --- dnsapi/dns_ddnss.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ddnss.sh b/dnsapi/dns_ddnss.sh index 118b148b..a624a268 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" From c6819cbd6b40d95e1b0f03273ee6a598cd9794a6 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 6 Jul 2025 01:40:53 +0300 Subject: [PATCH 16/53] dnsapi: fix authors: use @ for GitHub profiles Signed-off-by: Sergey Ponomarev --- dnsapi/dns_bookmyname.sh | 2 +- dnsapi/dns_ddnss.sh | 2 +- dnsapi/dns_dnshome.sh | 2 +- dnsapi/dns_duckdns.sh | 2 +- dnsapi/dns_dyn.sh | 2 +- dnsapi/dns_dynv6.sh | 2 +- dnsapi/dns_easydns.sh | 2 +- dnsapi/dns_freedns.sh | 2 +- dnsapi/dns_joker.sh | 2 +- dnsapi/dns_mijnhost.sh | 2 +- dnsapi/dns_namecom.sh | 2 +- dnsapi/dns_namesilo.sh | 2 +- dnsapi/dns_pleskxml.sh | 2 +- dnsapi/dns_schlundtech.sh | 2 +- dnsapi/dns_spaceship.sh | 2 +- dnsapi/dns_tele3.sh | 2 +- dnsapi/dns_timeweb.sh | 2 +- dnsapi/dns_udr.sh | 2 +- dnsapi/dns_vscale.sh | 2 +- dnsapi/dns_websupport.sh | 2 +- dnsapi/dns_world4you.sh | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) 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_ddnss.sh b/dnsapi/dns_ddnss.sh index a624a268..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: 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_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_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..52a81632 100644 --- a/dnsapi/dns_mijnhost.sh +++ b/dnsapi/dns_mijnhost.sh @@ -5,7 +5,7 @@ Domains: mijn.host Site: mijn.host Docs: https://mijn.host/api/doc/ Issues: https://github.com/acmesh-official/acme.sh/issues/6177 -Author: peterv99 +Author: @peterv99 Options: MIJNHOST_API_KEY API Key ' 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_spaceship.sh b/dnsapi/dns_spaceship.sh index 770e22cc..5e92a4fe 100644 --- a/dnsapi/dns_spaceship.sh +++ b/dnsapi/dns_spaceship.sh @@ -8,7 +8,7 @@ Options: SPACESHIP_API_SECRET Spaceship API Secret SPACESHIP_ROOT_DOMAIN (Optional) Manually specify the root domain if auto-detection fails 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_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_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_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" From daf183e2cc8b1e11ecb754fd8eddd56c1b954c12 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 6 Jul 2025 01:41:58 +0300 Subject: [PATCH 17/53] dnsapi: dns_vultr.sh remove empty author Signed-off-by: Sergey Ponomarev --- dnsapi/dns_vultr.sh | 1 - 1 file changed, 1 deletion(-) 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" From 85ec6343ff2f4388bf4e5cae77d5481f5dfcb46d Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 6 Jul 2025 01:42:39 +0300 Subject: [PATCH 18/53] dnsapi: dns_mijnhost.sh rearrange fields, use user docs instead of API docs Signed-off-by: Sergey Ponomarev --- dnsapi/dns_mijnhost.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_mijnhost.sh b/dnsapi/dns_mijnhost.sh index 52a81632..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 From 8113711b7aff45ac243492c1b3f49282727ac1b1 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 6 Jul 2025 01:43:16 +0300 Subject: [PATCH 19/53] dnsapi: fix Structured DNS Info Signed-off-by: Sergey Ponomarev --- dnsapi/dns_beget.sh | 2 +- dnsapi/dns_he_ddns.sh | 1 + dnsapi/dns_selectel.sh | 38 ++++++++++++++++---------------------- dnsapi/dns_spaceship.sh | 6 +++--- 4 files changed, 21 insertions(+), 26 deletions(-) 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_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_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 5e92a4fe..8fff4037 100644 --- a/dnsapi/dns_spaceship.sh +++ b/dnsapi/dns_spaceship.sh @@ -4,9 +4,9 @@ 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 <@Meo597> ' From 3b0f624302294c3d817e5c3218a263905dff9f67 Mon Sep 17 00:00:00 2001 From: Jens Spanier Date: Thu, 10 Jul 2025 10:55:05 +0200 Subject: [PATCH 20/53] Support certificate profile selection --- acme.sh | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index d70e323b..46c1124c 100755 --- a/acme.sh +++ b/acme.sh @@ -4416,6 +4416,7 @@ issue() { _preferred_chain="${15}" _valid_from="${16}" _valid_to="${17}" + _certificate_profile="${18}" if [ -z "$_ACME_IS_RENEW" ]; then _initpath "$_main_domain" "$_key_length" @@ -4491,6 +4492,11 @@ issue() { else _cleardomainconf "Le_Preferred_Chain" fi + if [ "$_certificate_profile" ]; then + _savedomainconf "Le_Certificate_Profile" "$_certificate_profile" + else + _cleardomainconf "Le_Certificate_Profile" + fi Le_API="$ACME_DIRECTORY" _savedomainconf "Le_API" "$Le_API" @@ -4622,6 +4628,9 @@ issue() { if [ "$_notAfter" ]; then _newOrderObj="$_newOrderObj,\"notAfter\": \"$_notAfter\"" fi + if [ "$_certificate_profile" ]; then + _newOrderObj="$_newOrderObj,\"profile\": \"$_certificate_profile\"" + fi _debug "STEP 1, Ordering a Certificate" if ! _send_signed_request "$ACME_NEW_ORDER" "$_newOrderObj}"; then _err "Error creating new order." @@ -5503,6 +5512,7 @@ renew() { Le_PostHook="$(_readdomainconf Le_PostHook)" Le_RenewHook="$(_readdomainconf Le_RenewHook)" Le_Preferred_Chain="$(_readdomainconf Le_Preferred_Chain)" + Le_Certificate_Profile="$(_readdomainconf Le_Certificate_Profile)" # 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. @@ -5517,7 +5527,7 @@ renew() { _cleardomainconf Le_OCSP_Staple fi fi - issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" "$Le_ChallengeAlias" "$Le_Preferred_Chain" "$Le_Valid_From" "$Le_Valid_To" + issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" "$Le_ChallengeAlias" "$Le_Preferred_Chain" "$Le_Valid_From" "$Le_Valid_To" "$Le_Certificate_Profile" res="$?" if [ "$res" != "0" ]; then return "$res" @@ -6989,6 +6999,8 @@ Parameters: If no match, the default offered chain will be used. (default: empty) See: $_PREFERRED_CHAIN_WIKI + --certificate-profile If the CA offers profiles, select the desired profile + --valid-to Request the NotAfter field of the cert. See: $_VALIDITY_WIKI --valid-from Request the NotBefore field of the cert. @@ -7364,6 +7376,7 @@ _process() { _preferred_chain="" _valid_from="" _valid_to="" + _certificate_profile="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -7682,6 +7695,10 @@ _process() { _valid_to="$2" shift ;; + --certificate-profile) + _certificate_profile="$2" + shift + ;; --httpport) _httpport="$2" Le_HTTPPort="$_httpport" @@ -7957,7 +7974,7 @@ _process() { uninstall) uninstall "$_nocron" ;; upgrade) upgrade ;; issue) - issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_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" + issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_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" ;; deploy) deploy "$_domain" "$_deploy_hook" "$_ecc" From 0c98dc54fee5194e5240e9e71e6d13f105894cb8 Mon Sep 17 00:00:00 2001 From: David Beitey Date: Sun, 13 Jul 2025 11:18:10 +1000 Subject: [PATCH 21/53] Fix logged typo when running pre hook --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d70e323b..252d0227 100755 --- a/acme.sh +++ b/acme.sh @@ -3513,7 +3513,7 @@ _on_before_issue() { _debug _chk_alt_domains "$_chk_alt_domains" #run pre hook if [ "$_chk_pre_hook" ]; then - _info "Runing pre hook:'$_chk_pre_hook'" + _info "Running pre hook:'$_chk_pre_hook'" if ! ( export Le_Domain="$_chk_main_domain" export Le_Alt="$_chk_alt_domains" From 40e58ed12d14319f5e355055b7a1c973519dedcb Mon Sep 17 00:00:00 2001 From: David Beitey Date: Sun, 13 Jul 2025 11:40:34 +1000 Subject: [PATCH 22/53] Run post hook when _on_before_issue errors --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index d70e323b..8ce5bacc 100755 --- a/acme.sh +++ b/acme.sh @@ -4502,6 +4502,7 @@ issue() { if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then _err "_on_before_issue." + _on_issue_err "$_post_hook" return 1 fi From 1f486fc9a524ead28d4b801f450b097eb3a58311 Mon Sep 17 00:00:00 2001 From: keryfan <35259207+keryfan@users.noreply.github.com> Date: Tue, 12 Aug 2025 11:12:09 +0300 Subject: [PATCH 23/53] Upload latest dev branch to master (#3) * Fix for empty error objects in response breaking extraction of domain validation types Fix for empty error objects in the response which mess up the extraction of domain validation types due to the closing brace in the error object prematurely matching the end of the search pattern. This seems to be a recent change with ZeroSSL in particular where "error":{} is being included in responses. There could potentially be a related issue if there is a complex error object ever returned in the validation check response where an embedded sub-object could lead to an incomplete extraction of the error message, roughly around line 5040. Adapted from fix suggested here: https://github.com/acmesh-official/acme.sh/issues/4933#issuecomment-1870499018 * Add new dnsapi support for OpenProvider.eu using new REST API * Cleanup duplicate debug log output based on DNS test run * Resolve spellcheck error * Configure 10 second timeout to ACME_DIRECTORY API call * add support for AIX style netstat * add * fix for wiki * minor * minor * wiki * wiki * dnsapi: dns_mydnsjp.sh fix author The @epgdatacapbon was renamed to @tkmsst Signed-off-by: Sergey Ponomarev * dnsapi: dns_ddnss.sh remove RaidenII from authors He made the DuckDNS script that was used for this script but he can't support the script. Signed-off-by: Sergey Ponomarev * dnsapi: fix authors: use @ for GitHub profiles Signed-off-by: Sergey Ponomarev * dnsapi: dns_vultr.sh remove empty author Signed-off-by: Sergey Ponomarev * dnsapi: dns_mijnhost.sh rearrange fields, use user docs instead of API docs Signed-off-by: Sergey Ponomarev * dnsapi: fix Structured DNS Info Signed-off-by: Sergey Ponomarev * Fix logged typo when running pre hook * Run post hook when _on_before_issue errors --------- Signed-off-by: Sergey Ponomarev Co-authored-by: Ciaran Walsh Co-authored-by: Lambiek12 Co-authored-by: Erwin Oegema Co-authored-by: laDanz Co-authored-by: neil Co-authored-by: neil Co-authored-by: Sergey Ponomarev Co-authored-by: David Beitey Co-authored-by: Jan-willem van Kampen --- .github/workflows/wiki-monitor.yml | 60 ++++++++++ acme.sh | 17 ++- dnsapi/dns_beget.sh | 2 +- dnsapi/dns_bookmyname.sh | 2 +- dnsapi/dns_ddnss.sh | 2 +- dnsapi/dns_dnshome.sh | 2 +- dnsapi/dns_duckdns.sh | 2 +- dnsapi/dns_dyn.sh | 2 +- dnsapi/dns_dynv6.sh | 2 +- dnsapi/dns_easydns.sh | 2 +- dnsapi/dns_freedns.sh | 2 +- dnsapi/dns_he_ddns.sh | 1 + dnsapi/dns_joker.sh | 2 +- dnsapi/dns_mijnhost.sh | 9 +- dnsapi/dns_mydnsjp.sh | 2 +- dnsapi/dns_namecom.sh | 2 +- dnsapi/dns_namesilo.sh | 2 +- dnsapi/dns_openprovider_rest.sh | 186 +++++++++++++++++++++++++++++ dnsapi/dns_pleskxml.sh | 2 +- dnsapi/dns_schlundtech.sh | 2 +- dnsapi/dns_selectel.sh | 38 +++--- dnsapi/dns_spaceship.sh | 8 +- dnsapi/dns_tele3.sh | 2 +- dnsapi/dns_timeweb.sh | 2 +- dnsapi/dns_udr.sh | 2 +- dnsapi/dns_vscale.sh | 2 +- dnsapi/dns_vultr.sh | 1 - dnsapi/dns_websupport.sh | 2 +- dnsapi/dns_world4you.sh | 2 +- 29 files changed, 305 insertions(+), 57 deletions(-) create mode 100644 .github/workflows/wiki-monitor.yml create mode 100644 dnsapi/dns_openprovider_rest.sh 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..d9ae208a 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." @@ -3507,7 +3513,7 @@ _on_before_issue() { _debug _chk_alt_domains "$_chk_alt_domains" #run pre hook if [ "$_chk_pre_hook" ]; then - _info "Runing pre hook:'$_chk_pre_hook'" + _info "Running pre hook:'$_chk_pre_hook'" if ! ( export Le_Domain="$_chk_main_domain" export Le_Alt="$_chk_alt_domains" @@ -4496,6 +4502,7 @@ issue() { if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then _err "_on_before_issue." + _on_issue_err "$_post_hook" return 1 fi @@ -4755,7 +4762,8 @@ $_authorizations_map" _debug keyauthorization "$keyauthorization" fi - entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" + # Fix for empty error objects in response which mess up the original code, adapted from fix suggested here: https://github.com/acmesh-official/acme.sh/issues/4933#issuecomment-1870499018 + entry="$(echo "$response" | sed s/'"error":{}'/'"error":null'/ | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$keyauthorization" -a -z "$entry" ]; then @@ -6344,7 +6352,8 @@ _deactivate() { fi _debug "Trigger validation." vtype="$(_getIdType "$_d_domain")" - entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" + # Fix for empty error objects in response which mess up the original code, adapted from fix suggested here: https://github.com/acmesh-official/acme.sh/issues/4933#issuecomment-1870499018 + entry="$(echo "$response" | sed s/'"error":{}'/'"error":null'/ | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ]; then _err "$d: Cannot get domain token" 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_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_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_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_openprovider_rest.sh b/dnsapi/dns_openprovider_rest.sh new file mode 100644 index 00000000..210dc6fc --- /dev/null +++ b/dnsapi/dns_openprovider_rest.sh @@ -0,0 +1,186 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_openprovider_rest_info='OpenProvider (REST) +Domains: OpenProvider.com +Site: OpenProvider.eu +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_openprovider_rest +Options: + OPENPROVIDER_REST_USERNAME Openprovider Account Username + OPENPROVIDER_REST_PASSWORD Openprovider Account Password +Issues: github.com/acmesh-official/acme.sh/issues/6122 +Author: Lambiek12 +' + +OPENPROVIDER_API_URL="https://api.openprovider.eu/v1beta" + +######## Public functions ##################### + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_openprovider_rest_add() { + fulldomain=$1 + txtvalue=$2 + + _openprovider_prepare_credentials || return 1 + + _debug "Try fetch OpenProvider DNS zone details" + if ! _get_dns_zone "$fulldomain"; then + _err "DNS zone not found within configured OpenProvider account." + return 1 + fi + + if [ -n "$_domain_id" ]; then + addzonerecordrequestparameters="dns/zones/$_domain_name" + addzonerecordrequestbody="{\"id\":$_domain_id,\"name\":\"$_domain_name\",\"records\":{\"add\":[{\"name\":\"$_sub_domain\",\"ttl\":900,\"type\":\"TXT\",\"value\":\"$txtvalue\"}]}}" + + if _openprovider_rest PUT "$addzonerecordrequestparameters" "$addzonerecordrequestbody"; then + if _contains "$response" "\"success\":true"; then + return 0 + elif _contains "$response" "\"Duplicate record\""; then + _debug "Record already existed" + return 0 + else + _err "Adding TXT record failed due to errors." + return 1 + fi + fi + fi + + _err "Adding TXT record failed due to errors." + return 1 +} + +# Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to remove the txt record after validation +dns_openprovider_rest_rm() { + fulldomain=$1 + txtvalue=$2 + + _openprovider_prepare_credentials || return 1 + + _debug "Try fetch OpenProvider DNS zone details" + if ! _get_dns_zone "$fulldomain"; then + _err "DNS zone not found within configured OpenProvider account." + return 1 + fi + + if [ -n "$_domain_id" ]; then + removezonerecordrequestparameters="dns/zones/$_domain_name" + removezonerecordrequestbody="{\"id\":$_domain_id,\"name\":\"$_domain_name\",\"records\":{\"remove\":[{\"name\":\"$_sub_domain\",\"ttl\":900,\"type\":\"TXT\",\"value\":\"\\\"$txtvalue\\\"\"}]}}" + + if _openprovider_rest PUT "$removezonerecordrequestparameters" "$removezonerecordrequestbody"; then + if _contains "$response" "\"success\":true"; then + return 0 + else + _err "Removing TXT record failed due to errors." + return 1 + fi + fi + fi + + _err "Removing TXT record failed due to errors." + return 1 +} + +#################### OpenProvider API common functions #################### +_openprovider_prepare_credentials() { + OPENPROVIDER_REST_USERNAME="${OPENPROVIDER_REST_USERNAME:-$(_readaccountconf_mutable OPENPROVIDER_REST_USERNAME)}" + OPENPROVIDER_REST_PASSWORD="${OPENPROVIDER_REST_PASSWORD:-$(_readaccountconf_mutable OPENPROVIDER_REST_PASSWORD)}" + + if [ -z "$OPENPROVIDER_REST_USERNAME" ] || [ -z "$OPENPROVIDER_REST_PASSWORD" ]; then + OPENPROVIDER_REST_USERNAME="" + OPENPROVIDER_REST_PASSWORD="" + _err "You didn't specify the Openprovider username or password yet." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable OPENPROVIDER_REST_USERNAME "$OPENPROVIDER_REST_USERNAME" + _saveaccountconf_mutable OPENPROVIDER_REST_PASSWORD "$OPENPROVIDER_REST_PASSWORD" +} + +_openprovider_rest() { + httpmethod=$1 + queryparameters=$2 + requestbody=$3 + + _openprovider_rest_login + if [ -z "$openproviderauthtoken" ]; then + _err "Unable to fetch authentication token from Openprovider API." + return 1 + fi + + export _H1="Content-Type: application/json" + export _H2="Accept: application/json" + export _H3="Authorization: Bearer $openproviderauthtoken" + + if [ "$httpmethod" != "GET" ]; then + response="$(_post "$requestbody" "$OPENPROVIDER_API_URL/$queryparameters" "" "$httpmethod")" + else + response="$(_get "$OPENPROVIDER_API_URL/$queryparameters")" + fi + + if [ "$?" != "0" ]; then + _err "No valid parameters supplied for Openprovider API: Error $queryparameters" + return 1 + fi + + _debug2 response "$response" + + return 0 +} + +_openprovider_rest_login() { + export _H1="Content-Type: application/json" + export _H2="Accept: application/json" + + loginrequesturl="$OPENPROVIDER_API_URL/auth/login" + loginrequestbody="{\"ip\":\"0.0.0.0\",\"password\":\"$OPENPROVIDER_REST_PASSWORD\",\"username\":\"$OPENPROVIDER_REST_USERNAME\"}" + loginresponse="$(_post "$loginrequestbody" "$loginrequesturl" "" "POST")" + + openproviderauthtoken="$(printf "%s\n" "$loginresponse" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')" + + export openproviderauthtoken +} + +#################### Private functions ################################## + +# Usage: _get_dns_zone _acme-challenge.www.domain.com +# Returns: +# _domain_id=123456789 +# _domain_name=domain.com +# _sub_domain=_acme-challenge.www +_get_dns_zone() { + domain=$1 + i=1 + p=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) + if [ -z "$h" ]; then + # Empty value not allowed + return 1 + fi + + if ! _openprovider_rest GET "dns/zones/$h" ""; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\""; then + _domain_id="$(printf "%s\n" "$response" | _egrep_o '"id" *: *[^,]*' | _head_n 1 | sed 's#^"id" *: *##')" + _debug _domain_id "$_domain_id" + + _domain_name="$h" + _debug _domain_name "$_domain_name" + + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") + _debug _sub_domain "$_sub_domain" + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} 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_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_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" From 1b5e66f9c2e4907408c05164010d7cd4422d6051 Mon Sep 17 00:00:00 2001 From: wout Date: Wed, 23 Jul 2025 10:12:32 +0200 Subject: [PATCH 24/53] Add sleep before each REST call to Constellix to prevent rate limit --- dnsapi/dns_constellix.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dnsapi/dns_constellix.sh b/dnsapi/dns_constellix.sh index 6a50e199..480541ed 100644 --- a/dnsapi/dns_constellix.sh +++ b/dnsapi/dns_constellix.sh @@ -156,6 +156,9 @@ _constellix_rest() { data="$3" _debug "$ep" + # Prevent rate limit + _sleep 2 + rdate=$(date +"%s")"000" hmac=$(printf "%s" "$rdate" | _hmac sha1 "$(printf "%s" "$CONSTELLIX_Secret" | _hex_dump | tr -d ' ')" | _base64) From ab22c8ca1cb89cda5e47d510de10e12ffabd39a0 Mon Sep 17 00:00:00 2001 From: wout Date: Tue, 12 Aug 2025 19:04:19 +0200 Subject: [PATCH 25/53] Convert domain to lower case, needed for Constellix REST API --- dnsapi/dns_constellix.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_constellix.sh b/dnsapi/dns_constellix.sh index 480541ed..7251f8b2 100644 --- a/dnsapi/dns_constellix.sh +++ b/dnsapi/dns_constellix.sh @@ -117,7 +117,7 @@ dns_constellix_rm() { #################### Private functions below ################################## _get_root() { - domain=$1 + domain=$(echo "$1" | _lower_case) i=2 p=1 _debug "Detecting root zone" From bcf0afb25ef9f159da397db73f1050c3b92f56d0 Mon Sep 17 00:00:00 2001 From: Tobias Grave Date: Fri, 15 Aug 2025 09:02:57 +0200 Subject: [PATCH 26/53] Variomedia API: Fix DNS deletion issues --- dnsapi/dns_variomedia.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_variomedia.sh b/dnsapi/dns_variomedia.sh index fa38bbb6..4620b854 100644 --- a/dnsapi/dns_variomedia.sh +++ b/dnsapi/dns_variomedia.sh @@ -74,7 +74,7 @@ dns_variomedia_rm() { return 1 fi - _record_id="$(echo "$response" | sed -E 's/,"tags":\[[^]]*\]//g' | cut -d '[' -f2 | cut -d']' -f1 | sed 's/},[ \t]*{/\},§\{/g' | tr § '\n' | grep "$_sub_domain" | grep -- "$txtvalue" | sed 's/^{//;s/}[,]?$//' | tr , '\n' | tr -d '\"' | grep ^id | cut -d : -f2 | tr -d ' ')" + _record_id="$(echo "$response" | sed -E 's/,"tags":\[[^]]*\]//g' | cut -d '[' -f3 | cut -d']' -f1 | sed 's/},[ \t]*{/\},§\{/g' | tr § '\n' | grep -i "$_sub_domain" | grep -- "$txtvalue" | sed 's/^{//;s/}[,]?$//' | tr , '\n' | tr -d '\"' | grep ^id | cut -d : -f2 | tr -d ' ')" _debug _record_id "$_record_id" if [ "$_record_id" ]; then _info "Successfully retrieved the record id for ACME challenge." From 5b02e8633441ece592bc2b9f21bd52b7ea38af25 Mon Sep 17 00:00:00 2001 From: asauerwein Date: Wed, 20 Aug 2025 17:47:36 +0200 Subject: [PATCH 27/53] add template_stack option to push to device --- deploy/panos.sh | 75 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index 0dc1b2f0..2ed6a230 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -7,20 +7,26 @@ # # Firewall admin with superuser and IP address is required. # -# REQURED: +# REQUIRED: # export PANOS_HOST="" # export PANOS_USER="" #User *MUST* have Commit and Import Permissions in XML API for Admin Role # export PANOS_PASS="" # # OPTIONAL -# export PANOS_TEMPLATE="" #Template Name of panorama managed devices +# export PANOS_TEMPLATE="" # Template Name of panorama managed devices +# export PANOS_TEMPLATE_STACK="" # set a Template Stack if certificate should also be pushed automatically +# export PANOS_VSYS="Shared" # name of the vsys to import the certificate # # The script will automatically generate a new API key if # no key is found, or if a saved key has expired or is invalid. + + + # This function is to parse the XML response from the firewall parse_response() { type=$2 + _debug "API Response: $1" if [ "$type" = 'keygen' ]; then status=$(echo "$1" | sed 's/^.*\(['\'']\)\([a-z]*\)'\''.*/\2/g') if [ "$status" = "success" ]; then @@ -30,6 +36,13 @@ parse_response() { message="PAN-OS Key could not be set." fi else + if [ "$type" = 'commit' ]; then + job_id=$(echo "$1" | sed 's/^.*\(\)\(.*\)<\/job>.*/\2/g') + _commit_job_id=$job_id + elif [ "$type" = 'job_status' ]; then + job_status=$(echo "$1" | tr -d '\n' | sed 's/^.*\([^<]*\)<\/result>.*/\1/g') + _commit_job_status=$job_status + fi status=$(echo "$1" | tr -d '\n' | sed 's/^.*"\([a-z]*\)".*/\1/g') message=$(echo "$1" | tr -d '\n' | sed 's/.*\(\|\|\)\([^<]*\).*/\2/g') _debug "Firewall message: $message" @@ -44,7 +57,7 @@ parse_response() { #This function is used to deploy to the firewall deployer() { content="" - type=$1 # Types are keytest, keygen, cert, key, commit + type=$1 # Types are keytest, keygen, cert, key, commit, job_status, push panos_url="https://$_panos_host/api/" #Test API Key by performing a lookup @@ -84,6 +97,9 @@ deployer() { if [ "$_panos_template" ]; then content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl\"\r\n\r\n$_panos_template" fi + if [ "$_panos_vsys" ]; then + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl-vsys\"\r\n\r\n$_panos_vsys" + fi fi if [ "$type" = 'key' ]; then panos_url="${panos_url}?type=import" @@ -96,6 +112,9 @@ deployer() { if [ "$_panos_template" ]; then content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl\"\r\n\r\n$_panos_template" fi + if [ "$_panos_vsys" ]; then + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl-vsys\"\r\n\r\n$_panos_vsys" + fi fi #Close multipart content="$content${nl}--$delim--${nl}${nl}" @@ -118,6 +137,22 @@ deployer() { content="type=commit&action=partial&key=$_panos_key&cmd=$cmd" fi + # Query job status + if [ "$type" = 'job_status' ]; then + echo "**** Querying job $_commit_job_id status ****" + H1="Content-Type: application/x-www-form-urlencoded" + cmd=$(printf "%s" "$_commit_job_id" | _url_encode) + content="type=op&key=$_panos_key&cmd=$cmd" + fi + + # Push changes + if [ "$type" = 'push' ]; then + echo "**** Pushing changes ****" + H1="Content-Type: application/x-www-form-urlencoded" + cmd=$(printf "%s" "$_panos_template_stack$_panos_user" | _url_encode) + content="type=commit&action=all&key=$_panos_key&cmd=$cmd" + fi + response=$(_post "$content" "$panos_url" "" "POST") parse_response "$response" "$type" # Saving response to variables @@ -126,6 +161,8 @@ deployer() { if [ "$response_status" = "success" ]; then _debug "Successfully deployed $type" return 0 + elif [ "$_commit_job_status" ]; then + _debug "Commit Job Status = $_commit_job_status" else _err "Deploy of type $type failed. Try deploying with --debug to troubleshoot." _debug "$message" @@ -191,11 +228,31 @@ panos_deploy() { _getdeployconf PANOS_TEMPLATE fi + # PANOS_TEMPLATE_STACK + if [ "$PANOS_TEMPLATE_STACK" ]; then + _debug "Detected ENV variable PANOS_TEMPLATE_STACK. Saving to file." + _savedeployconf PANOS_TEMPLATE_STACK "$PANOS_TEMPLATE_STACK" 1 + else + _debug "Attempting to load variable PANOS_TEMPLATE_STACK from file." + _getdeployconf PANOS_TEMPLATE_STACK + fi + + # PANOS_TEMPLATE_STACK + if [ "$PANOS_VSYS" ]; then + _debug "Detected ENV variable PANOS_VSYS. Saving to file." + _savedeployconf PANOS_VSYS "$PANOS_VSYS" 1 + else + _debug "Attempting to load variable PANOS_VSYS from file." + _getdeployconf PANOS_VSYS + fi + #Store variables _panos_host=$PANOS_HOST _panos_user=$PANOS_USER _panos_pass=$PANOS_PASS _panos_template=$PANOS_TEMPLATE + _panos_template_stack=$PANOS_TEMPLATE_STACK + _panos_vsys=$PANOS_VSYS #Test API Key if found. If the key is invalid, the variable _panos_key will be unset. if [ "$_panos_host" ] && [ "$_panos_key" ]; then @@ -229,6 +286,18 @@ panos_deploy() { deployer cert deployer key deployer commit + if [ "$_panos_template_stack" ]; then + # try to get job status for 20 times in 30 sec interval + for ((i = 0 ; i < 20 ; i++ )); do + deployer job_status + if [[ "$_commit_job_status" == "OK" ]]; then + echo "Commit finished!" + break + fi + sleep 30 + done + deployer push + fi fi fi } From fdb1e8c2e46143a84aa8d26d49d5c1dce50aea74 Mon Sep 17 00:00:00 2001 From: asauerwein Date: Wed, 20 Aug 2025 18:37:25 +0200 Subject: [PATCH 28/53] fix usage of H1 header change to while loop use global variable for loop fix if statement to be sh compliant shfmt --- deploy/panos.sh | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index 2ed6a230..a9232e79 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -20,8 +20,8 @@ # The script will automatically generate a new API key if # no key is found, or if a saved key has expired or is invalid. - - +_COMMIT_WAIT_INTERVAL=30 # query commit status every 30 seconds +_COMMIT_WAIT_ITERATIONS=20 # query commit status 20 times (20*30 = 600 seconds = 10 minutes) # This function is to parse the XML response from the firewall parse_response() { @@ -59,11 +59,11 @@ deployer() { content="" type=$1 # Types are keytest, keygen, cert, key, commit, job_status, push panos_url="https://$_panos_host/api/" + export _H1="Content-Type: application/x-www-form-urlencoded" #Test API Key by performing a lookup if [ "$type" = 'keytest' ]; then _debug "**** Testing saved API Key ****" - _H1="Content-Type: application/x-www-form-urlencoded" # Get Version Info to test key content="type=version&key=$_panos_key" ## Exclude all scopes for the empty commit @@ -74,7 +74,6 @@ deployer() { # Generate API Key if [ "$type" = 'keygen' ]; then _debug "**** Generating new API Key ****" - _H1="Content-Type: application/x-www-form-urlencoded" content="type=keygen&user=$_panos_user&password=$_panos_pass" # content="$content${nl}--$delim${nl}Content-Disposition: form-data; type=\"keygen\"; user=\"$_panos_user\"; password=\"$_panos_pass\"${nl}Content-Type: application/octet-stream${nl}${nl}" fi @@ -99,7 +98,7 @@ deployer() { fi if [ "$_panos_vsys" ]; then content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl-vsys\"\r\n\r\n$_panos_vsys" - fi + fi fi if [ "$type" = 'key' ]; then panos_url="${panos_url}?type=import" @@ -114,7 +113,7 @@ deployer() { fi if [ "$_panos_vsys" ]; then content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl-vsys\"\r\n\r\n$_panos_vsys" - fi + fi fi #Close multipart content="$content${nl}--$delim--${nl}${nl}" @@ -125,7 +124,6 @@ deployer() { # Commit changes if [ "$type" = 'commit' ]; then _debug "**** Committing changes ****" - export _H1="Content-Type: application/x-www-form-urlencoded" #Check for force commit - will commit ALL uncommited changes to the firewall. Use with caution! if [ "$FORCE" ]; then _debug "Force switch detected. Committing ALL changes to the firewall." @@ -140,7 +138,6 @@ deployer() { # Query job status if [ "$type" = 'job_status' ]; then echo "**** Querying job $_commit_job_id status ****" - H1="Content-Type: application/x-www-form-urlencoded" cmd=$(printf "%s" "$_commit_job_id" | _url_encode) content="type=op&key=$_panos_key&cmd=$cmd" fi @@ -148,7 +145,6 @@ deployer() { # Push changes if [ "$type" = 'push' ]; then echo "**** Pushing changes ****" - H1="Content-Type: application/x-www-form-urlencoded" cmd=$(printf "%s" "$_panos_template_stack$_panos_user" | _url_encode) content="type=commit&action=all&key=$_panos_key&cmd=$cmd" fi @@ -288,13 +284,15 @@ panos_deploy() { deployer commit if [ "$_panos_template_stack" ]; then # try to get job status for 20 times in 30 sec interval - for ((i = 0 ; i < 20 ; i++ )); do - deployer job_status - if [[ "$_commit_job_status" == "OK" ]]; then - echo "Commit finished!" - break - fi - sleep 30 + i=0 + while [ "$i" -lt $_COMMIT_WAIT_ITERATIONS ]; do + deployer job_status + if [ "$_commit_job_status" = "OK" ]; then + echo "Commit finished!" + break + fi + sleep $_COMMIT_WAIT_INTERVAL + i=$((i + 1)) done deployer push fi From d7c428fc8d6bb123b890ec669b606eaf620b9c25 Mon Sep 17 00:00:00 2001 From: Richard Glidden Date: Mon, 30 Jun 2025 14:14:26 -0400 Subject: [PATCH 29/53] feat: Add ability to deploy to remote TrueNAS instances --- deploy/truenas_ws.sh | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/deploy/truenas_ws.sh b/deploy/truenas_ws.sh index bdc1b846..74a46530 100644 --- a/deploy/truenas_ws.sh +++ b/deploy/truenas_ws.sh @@ -39,13 +39,13 @@ _ws_call() { _debug "_ws_call arg2" "$2" _debug "_ws_call arg3" "$3" if [ $# -eq 3 ]; then - _ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2" "$3") + _ws_response=$(midclt --uri $_ws_uri -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2" "$3") fi if [ $# -eq 2 ]; then - _ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2") + _ws_response=$(midclt --uri $_ws_uri -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2") fi if [ $# -eq 1 ]; then - _ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1") + _ws_response=$(midclt --uri $_ws_uri -K "$DEPLOY_TRUENAS_APIKEY" call "$1") fi _debug "_ws_response" "$_ws_response" printf "%s" "$_ws_response" @@ -60,7 +60,7 @@ _ws_upload_cert() { import sys from truenas_api_client import Client -with Client() as c: +with Client(uri="$_ws_uri") as c: ### Login with API key print("I:Trying to upload new certificate...") @@ -175,6 +175,16 @@ truenas_ws_deploy() { _debug _file_ca "$_file_ca" _debug _file_fullchain "$_file_fullchain" + ########## Default values for hostname and protocol + [ -n "${DEPLOY_TRUENAS_HOSTNAME}" ] || DEPLOY_TRUENAS_HOSTNAME="localhost" + [ -n "${DEPLOY_TRUENAS_PROTOCOL}" ] || DEPLOY_TRUENAS_PROTOCOL="ws" + + _debug2 DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME" + _debug2 DEPLOY_TRUENAS_PROTOCOL "$DEPLOY_TRUENAS_PROTOCOL" + + _ws_uri="$DEPLOY_TRUENAS_PROTOCOL://$DEPLOY_TRUENAS_HOSTNAME/websocket" + _debug _ws_uri "$_ws_uri" + ########## Environment check _info "Checking environment variables..." @@ -304,7 +314,7 @@ truenas_ws_deploy() { _info "Restarting WebUI..." _ws_response=$(_ws_call "system.general.ui_restart") _info "Waiting for UI restart..." - sleep 6 + sleep 15 ########## Certificates From 6d40ac86449cdb80b52c6ffb647eac560174c84c Mon Sep 17 00:00:00 2001 From: Richard Glidden Date: Mon, 30 Jun 2025 14:51:36 -0400 Subject: [PATCH 30/53] chore: Fix shellcheck errors --- deploy/truenas_ws.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deploy/truenas_ws.sh b/deploy/truenas_ws.sh index 74a46530..ea6fc7e6 100644 --- a/deploy/truenas_ws.sh +++ b/deploy/truenas_ws.sh @@ -39,13 +39,13 @@ _ws_call() { _debug "_ws_call arg2" "$2" _debug "_ws_call arg3" "$3" if [ $# -eq 3 ]; then - _ws_response=$(midclt --uri $_ws_uri -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2" "$3") + _ws_response=$(midclt --uri "$_ws_uri" -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2" "$3") fi if [ $# -eq 2 ]; then - _ws_response=$(midclt --uri $_ws_uri -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2") + _ws_response=$(midclt --uri "$_ws_uri" -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2") fi if [ $# -eq 1 ]; then - _ws_response=$(midclt --uri $_ws_uri -K "$DEPLOY_TRUENAS_APIKEY" call "$1") + _ws_response=$(midclt --uri "$_ws_uri" -K "$DEPLOY_TRUENAS_APIKEY" call "$1") fi _debug "_ws_response" "$_ws_response" printf "%s" "$_ws_response" From 5aae3333bc653340c45981b6bd798ec90509301a Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Sun, 31 Aug 2025 20:44:24 +0100 Subject: [PATCH 31/53] Show proxmox deploy scripts response only on debug --- deploy/proxmoxbs.sh | 12 +++++++++++- deploy/proxmoxve.sh | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/deploy/proxmoxbs.sh b/deploy/proxmoxbs.sh index d1146454..e8528e8f 100644 --- a/deploy/proxmoxbs.sh +++ b/deploy/proxmoxbs.sh @@ -115,6 +115,16 @@ HEREDOC _info "Push certificates to server" export HTTPS_INSECURE=1 export _H1="Authorization: PBSAPIToken=${_proxmoxbs_header_api_token}" - _post "$_json_payload" "$_target_url" "" POST "application/json" + response=$(_post "$_json_payload" "$_target_url" "" POST "application/json") + _retval=$? + if [ "${_retval}" -eq 0 ]; then + _debug3 response "$response" + _info "Certificate successfully deployed" + return 0 + else + _err "Certificate deployment failed" + _debug "Response" "$response" + return 1 + fi } diff --git a/deploy/proxmoxve.sh b/deploy/proxmoxve.sh index f9de590c..8c67f7de 100644 --- a/deploy/proxmoxve.sh +++ b/deploy/proxmoxve.sh @@ -127,6 +127,16 @@ HEREDOC _info "Push certificates to server" export HTTPS_INSECURE=1 export _H1="Authorization: PVEAPIToken=${_proxmoxve_header_api_token}" - _post "$_json_payload" "$_target_url" "" POST "application/json" + response=$(_post "$_json_payload" "$_target_url" "" POST "application/json") + _retval=$? + if [ "${_retval}" -eq 0 ]; then + _debug3 response "$response" + _info "Certificate successfully deployed" + return 0 + else + _err "Certificate deployment failed" + _debug "Response" "$response" + return 1 + fi } From d366b7e4fc7799bcb1a43213e2566096e1c19a28 Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Mon, 1 Sep 2025 19:54:36 +0100 Subject: [PATCH 32/53] Fix diff in wiki notifications (use full clone) The checkout action fetches one single commit, so attempts to find previous states of a page result in error. Adding fetch-depth:0 to the configuration fetches all commits and makes finding the previous commit that changed a page possible in the github action. --- .github/workflows/wiki-monitor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/wiki-monitor.yml b/.github/workflows/wiki-monitor.yml index 89497580..b0332775 100644 --- a/.github/workflows/wiki-monitor.yml +++ b/.github/workflows/wiki-monitor.yml @@ -12,6 +12,7 @@ jobs: with: repository: ${{ github.repository }}.wiki path: wiki + fetch-depth: 0 - name: Generate wiki change message run: | @@ -58,3 +59,4 @@ jobs: + From 04e254923939d0d600cd8b29dfe3b34ca7421052 Mon Sep 17 00:00:00 2001 From: Guillaume PELURE Date: Tue, 2 Sep 2025 21:13:38 +0200 Subject: [PATCH 33/53] socat rejects TCP-LISTEN on ipv6 only networks --- acme.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d70e323b..5c4d6543 100755 --- a/acme.sh +++ b/acme.sh @@ -2538,15 +2538,17 @@ _startserver() { _NC="socat" if [ "$Le_Listen_V6" ]; then _NC="$_NC -6" + SOCAT_OPTIONS=TCP6-LISTEN else _NC="$_NC -4" + SOCAT_OPTIONS=TCP4-LISTEN fi if [ "$DEBUG" ] && [ "$DEBUG" -gt "1" ]; then _NC="$_NC -d -d -v" fi - SOCAT_OPTIONS=TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork + SOCAT_OPTIONS=$SOCAT_OPTIONS:$Le_HTTPPort,crlf,reuseaddr,fork #Adding bind to local-address if [ "$ncaddr" ]; then From 39cb87dc4bf481460ddba4d2754f07d351da07e4 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 5 Sep 2025 22:08:55 +0200 Subject: [PATCH 34/53] fix for DragonflyBSD just move "date -u -j -f" before the linux branch. --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index d9ae208a..bfd26bd6 100755 --- a/acme.sh +++ b/acme.sh @@ -1811,6 +1811,10 @@ _time() { # 2022-04-01 08:10:33 to 1648800633 #or 2022-04-01T08:10:33Z to 1648800633 _date2time() { + #Mac/BSD + if date -u -j -f "%Y-%m-%d %H:%M:%S" "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then + return + fi #Linux if date -u -d "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then return @@ -1820,10 +1824,6 @@ _date2time() { if gdate -u -d "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then return fi - #Mac/BSD - if date -u -j -f "%Y-%m-%d %H:%M:%S" "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then - return - fi #Omnios if python3 -c "import datetime; print(int(datetime.datetime.strptime(\"$1\", \"%Y-%m-%d %H:%M:%S\").replace(tzinfo=datetime.timezone.utc).timestamp()))" 2>/dev/null; then return From e0e3cdc316f75af54e411f844093a9cff08781ac Mon Sep 17 00:00:00 2001 From: Eric Fu Date: Sat, 6 Sep 2025 22:31:50 +0800 Subject: [PATCH 35/53] Fix sed command in telegram notifier --- notify/telegram.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notify/telegram.sh b/notify/telegram.sh index ccbd1533..c0621ae7 100644 --- a/notify/telegram.sh +++ b/notify/telegram.sh @@ -34,8 +34,8 @@ telegram_send() { fi _saveaccountconf_mutable TELEGRAM_BOT_URLBASE "$TELEGRAM_BOT_URLBASE" - _subject="$(printf "%s" "$_subject" | sed 's/\\/\\\\\\\\/g' | sed 's/\]/\\\\\]/g' | sed 's/\([_*[()~`>#+--=|{}.!]\)/\\\\\1/g')" - _content="$(printf "%s" "$_content" | sed 's/\\/\\\\\\\\/g' | sed 's/\]/\\\\\]/g' | sed 's/\([_*[()~`>#+--=|{}.!]\)/\\\\\1/g')" + _subject="$(printf "%s" "$_subject" | sed 's/\\/\\\\\\\\/g' | sed 's/\]/\\\\\]/g' | sed 's/\([_*[()~`>#+\-=|{}.!]\)/\\\\\1/g')" + _content="$(printf "%s" "$_content" | sed 's/\\/\\\\\\\\/g' | sed 's/\]/\\\\\]/g' | sed 's/\([_*[()~`>#+\-=|{}.!]\)/\\\\\1/g')" _content="$(printf "*%s*\n%s" "$_subject" "$_content" | _json_encode)" _data="{\"text\": \"$_content\", " _data="$_data\"chat_id\": \"$TELEGRAM_BOT_CHATID\", " From 30faf500eb4f9394c3d43dbbba5eda43e4947e34 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 7 Sep 2025 10:09:27 +0200 Subject: [PATCH 36/53] fix https://github.com/acmesh-official/acme.sh/pull/6499#issuecomment-3259771356 --- acme.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d335990c..3316b25f 100755 --- a/acme.sh +++ b/acme.sh @@ -2539,9 +2539,11 @@ _startserver() { if [ "$Le_Listen_V6" ]; then _NC="$_NC -6" SOCAT_OPTIONS=TCP6-LISTEN - else + elif [ "$Le_Listen_V4" ]; then _NC="$_NC -4" SOCAT_OPTIONS=TCP4-LISTEN + else + SOCAT_OPTIONS=TCP-LISTEN fi if [ "$DEBUG" ] && [ "$DEBUG" -gt "1" ]; then From 8608e9cd3a49c1a9f948e19ea3a62fac62a24aef Mon Sep 17 00:00:00 2001 From: Richard Glidden Date: Fri, 12 Sep 2025 22:22:30 -0400 Subject: [PATCH 37/53] Save and read variables --- deploy/truenas_ws.sh | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/deploy/truenas_ws.sh b/deploy/truenas_ws.sh index ea6fc7e6..a204d352 100644 --- a/deploy/truenas_ws.sh +++ b/deploy/truenas_ws.sh @@ -175,25 +175,31 @@ truenas_ws_deploy() { _debug _file_ca "$_file_ca" _debug _file_fullchain "$_file_fullchain" - ########## Default values for hostname and protocol - [ -n "${DEPLOY_TRUENAS_HOSTNAME}" ] || DEPLOY_TRUENAS_HOSTNAME="localhost" - [ -n "${DEPLOY_TRUENAS_PROTOCOL}" ] || DEPLOY_TRUENAS_PROTOCOL="ws" - - _debug2 DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME" - _debug2 DEPLOY_TRUENAS_PROTOCOL "$DEPLOY_TRUENAS_PROTOCOL" - - _ws_uri="$DEPLOY_TRUENAS_PROTOCOL://$DEPLOY_TRUENAS_HOSTNAME/websocket" - _debug _ws_uri "$_ws_uri" - ########## Environment check _info "Checking environment variables..." _getdeployconf DEPLOY_TRUENAS_APIKEY + _getdeployconf DEPLOY_TRUENAS_HOSTNAME + _getdeployconf DEPLOY_TRUENAS_PROTOCOL # Check API Key if [ -z "$DEPLOY_TRUENAS_APIKEY" ]; then _err "TrueNAS API key not found, please set the DEPLOY_TRUENAS_APIKEY environment variable." return 1 fi + # Check Hostname, default to localhost if not set + if [ -z "$DEPLOY_TRUENAS_HOSTNAME" ]; then + _info "TrueNAS hostname not set. Using 'localhost'." + DEPLOY_TRUENAS_HOSTNAME="localhost" + fi + # Check protocol, default to ws if not set + if [ -z "$DEPLOY_TRUENAS_PROTOCOL" ]; then + _info "TrueNAS protocol not set. Using 'ws'." + DEPLOY_TRUENAS_PROTOCOL="ws" + fi + _ws_uri="$DEPLOY_TRUENAS_PROTOCOL://$DEPLOY_TRUENAS_HOSTNAME/websocket" + _debug2 DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME" + _debug2 DEPLOY_TRUENAS_PROTOCOL "$DEPLOY_TRUENAS_PROTOCOL" + _debug _ws_uri "$_ws_uri" _secure_debug2 DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY" _info "Environment variables: OK" @@ -215,6 +221,8 @@ truenas_ws_deploy() { return 2 fi _savedeployconf DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY" + _savedeployconf DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME" + _savedeployconf DEPLOY_TRUENAS_PROTOCOL "$DEPLOY_TRUENAS_PROTOCOL" _info "TrueNAS health: OK" ########## System info From a1ea2a5aa6a63c1c99daffc66c1463e3a2ac88ab Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 14 Sep 2025 10:35:21 +0200 Subject: [PATCH 38/53] fix tr https://github.com/acmesh-official/acme.sh/issues/6511#issuecomment-3282521860 --- acme.sh | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 3316b25f..02986a33 100755 --- a/acme.sh +++ b/acme.sh @@ -436,14 +436,28 @@ _secure_debug3() { fi } +__USE_TR_TAG="" +if [ "$(echo "abc" | LANG=C tr a-z A-Z 2>/dev/null)" != "ABC" ] ; then + __USE_TR_TAG="1" +fi +export __USE_TR_TAG + _upper_case() { + if [ "$__USE_TR_TAG" ]; then + LANG=C tr '[:lower:]' '[:upper:]' + else # shellcheck disable=SC2018,SC2019 - tr '[a-z]' '[A-Z]' + LANG=C tr '[a-z]' '[A-Z]' + fi } _lower_case() { - # shellcheck disable=SC2018,SC2019 - tr '[A-Z]' '[a-z]' + if [ "$__USE_TR_TAG" ]; then + LANG=C tr '[:upper:]' '[:lower:]' + else + # shellcheck disable=SC2018,SC2019 + LANG=C tr '[A-Z]' '[a-z]' + fi } _startswith() { From d76f4b27b0f2eae8b75d41459eff6e51094045ca Mon Sep 17 00:00:00 2001 From: benyamin-codez <115509179+benyamin-codez@users.noreply.github.com> Date: Sun, 7 Sep 2025 23:54:45 +1000 Subject: [PATCH 39/53] dnsapi/dns_opnsense.sh: Refresh for OPNsense v25.7 series Updates the dns_opnsense.sh Bourne shell script for OPNSense v25.7 series: 1. Fixes historical error in rm_record() [used incorrect response variable] 2. Improves debug messaging in rm_record() 3. Fixes _get_root() for change in OPNsense API * Response is now split into pseudo-rows * We now iterate through pseudo-rows for matching domainname field 4. Fixes _existingchallenge() for change in OPNsense API * Fixes unreliable regex for uuid * Adds domain regex and %domain field 5. Fixes historical error in _existingchallenge() [incorrect variable syntax] Resolves #6467 Signed-off-by: benyamin-codez <115509179+benyamin-codez@users.noreply.github.com> --- dnsapi/dns_opnsense.sh | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/dnsapi/dns_opnsense.sh b/dnsapi/dns_opnsense.sh index d1e9c0ac..a11cfae5 100755 --- a/dnsapi/dns_opnsense.sh +++ b/dnsapi/dns_opnsense.sh @@ -110,15 +110,16 @@ rm_record() { if _existingchallenge "$_domain" "$_host" "$new_challenge"; then # Delete if _opns_rest "POST" "/record/delRecord/${_uuid}" "\{\}"; then - if echo "$_return_str" | _egrep_o "\"result\":\"deleted\"" >/dev/null; then - _opns_rest "POST" "/service/reconfigure" "{}" + if echo "$response" | _egrep_o "\"result\":\"deleted\"" >/dev/null; then _debug "Record deleted" + _opns_rest "POST" "/service/reconfigure" "{}" + _debug "Service reconfigured" else _err "Error deleting record $_host from domain $fulldomain" return 1 fi else - _err "Error deleting record $_host from domain $fulldomain" + _err "Error requesting deletion of record $_host from domain $fulldomain" return 1 fi else @@ -150,14 +151,17 @@ _get_root() { return 1 fi _debug h "$h" - id=$(echo "$_domain_response" | _egrep_o "\"uuid\":\"[a-z0-9\-]*\",\"enabled\":\"1\",\"type\":\"primary\",\"domainname\":\"${h}\"" | cut -d ':' -f 2 | cut -d '"' -f 2) - if [ -n "$id" ]; then - _debug id "$id" - _host=$(printf "%s" "$domain" | cut -d . -f 1-"$p") - _domain="${h}" - _domainid="${id}" - return 0 - fi + lines=$(echo "$_domain_response" | sed 's/{/\n/g') + for line in $lines; do + id=$(echo "$line" | _egrep_o "\"uuid\":\"[a-z0-9\-]*\",\"enabled\":\"1\",\"type\":\"primary\",.*\"domainname\":\"${h}\"" | cut -d ':' -f 2 | cut -d '"' -f 2) + if [ -n "$id" ]; then + _debug id "$id" + _host=$(printf "%s" "$domain" | cut -d . -f 1-"$p") + _domain="${h}" + _domainid="${id}" + return 0 + fi + done p=$i i=$(_math "$i" + 1) done @@ -206,13 +210,13 @@ _existingchallenge() { return 1 fi _uuid="" - _uuid=$(echo "$_record_response" | _egrep_o "\"uuid\":\"[^\"]*\",\"enabled\":\"[01]\",\"domain\":\"$1\",\"name\":\"$2\",\"type\":\"TXT\",\"value\":\"$3\"" | cut -d ':' -f 2 | cut -d '"' -f 2) + _uuid=$(echo "$_record_response" | _egrep_o "\"uuid\":\"[a-z0-9\-]*\",\"enabled\":\"[01]\",\"domain\":\"[a-z0-9\-]*\",\"%domain\":\"$1\",\"name\":\"$2\",\"type\":\"TXT\",\"value\":\"$3\"" | cut -d ':' -f 2 | cut -d '"' -f 2) if [ -n "$_uuid" ]; then _debug uuid "$_uuid" return 0 fi - _debug "${2}.$1{1} record not found" + _debug "${2}.${1} record not found" return 1 } From df350e6660df5b61e353a5daed7d7a1ee1f5ba4a Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 15 Sep 2025 19:34:54 +0200 Subject: [PATCH 40/53] fix format --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 02986a33..9105a0a4 100755 --- a/acme.sh +++ b/acme.sh @@ -437,7 +437,7 @@ _secure_debug3() { } __USE_TR_TAG="" -if [ "$(echo "abc" | LANG=C tr a-z A-Z 2>/dev/null)" != "ABC" ] ; then +if [ "$(echo "abc" | LANG=C tr a-z A-Z 2>/dev/null)" != "ABC" ]; then __USE_TR_TAG="1" fi export __USE_TR_TAG @@ -446,7 +446,7 @@ _upper_case() { if [ "$__USE_TR_TAG" ]; then LANG=C tr '[:lower:]' '[:upper:]' else - # shellcheck disable=SC2018,SC2019 + # shellcheck disable=SC2018,SC2019 LANG=C tr '[a-z]' '[A-Z]' fi } From 44c7473ef97bcae83e829a4a7e6b2ddcfc0d8369 Mon Sep 17 00:00:00 2001 From: Min Wang Date: Tue, 16 Sep 2025 15:09:12 +0800 Subject: [PATCH 41/53] fix bug for #6510 --- notify/telegram.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notify/telegram.sh b/notify/telegram.sh index c0621ae7..7da05729 100644 --- a/notify/telegram.sh +++ b/notify/telegram.sh @@ -34,8 +34,8 @@ telegram_send() { fi _saveaccountconf_mutable TELEGRAM_BOT_URLBASE "$TELEGRAM_BOT_URLBASE" - _subject="$(printf "%s" "$_subject" | sed 's/\\/\\\\\\\\/g' | sed 's/\]/\\\\\]/g' | sed 's/\([_*[()~`>#+\-=|{}.!]\)/\\\\\1/g')" - _content="$(printf "%s" "$_content" | sed 's/\\/\\\\\\\\/g' | sed 's/\]/\\\\\]/g' | sed 's/\([_*[()~`>#+\-=|{}.!]\)/\\\\\1/g')" + _subject="$(printf "%s" "$_subject" | sed 's/\\/\\\\\\\\/g' | sed 's/\]/\\\\\]/g' | sed 's/\([-_*[()~`>#+\-=|{}.!]\)/\\\\\1/g')" + _content="$(printf "%s" "$_content" | sed 's/\\/\\\\\\\\/g' | sed 's/\]/\\\\\]/g' | sed 's/\([-_*[()~`>#+\-=|{}.!]\)/\\\\\1/g')" _content="$(printf "*%s*\n%s" "$_subject" "$_content" | _json_encode)" _data="{\"text\": \"$_content\", " _data="$_data\"chat_id\": \"$TELEGRAM_BOT_CHATID\", " From 1b00ced7adf0c9ffe39c2f5e883395f7abefc2cc Mon Sep 17 00:00:00 2001 From: Jens Spanier Date: Tue, 16 Sep 2025 09:20:31 +0200 Subject: [PATCH 42/53] Add `--profile` as option for selecting certificate profile --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index ead7602b..7a8e4e9b 100755 --- a/acme.sh +++ b/acme.sh @@ -7702,7 +7702,7 @@ _process() { _valid_to="$2" shift ;; - --certificate-profile) + --certificate-profile | --profile) _certificate_profile="$2" shift ;; From 070cd0f4dfe983d093e1661aab8b73678cf5b259 Mon Sep 17 00:00:00 2001 From: Richard Glidden Date: Tue, 16 Sep 2025 22:19:16 -0400 Subject: [PATCH 43/53] Use _sleep instead of sleep --- deploy/truenas_ws.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/truenas_ws.sh b/deploy/truenas_ws.sh index a204d352..d334853e 100644 --- a/deploy/truenas_ws.sh +++ b/deploy/truenas_ws.sh @@ -121,7 +121,7 @@ _ws_check_jobid() { # n/a _ws_get_job_result() { while true; do - sleep 2 + _sleep 2 _ws_response=$(_ws_call "core.get_jobs" "[[\"id\", \"=\", $1]]") if [ "$(printf "%s" "$_ws_response" | jq -r '.[]."state"')" != "RUNNING" ]; then _ws_result="$(printf "%s" "$_ws_response" | jq '.[]."result"')" @@ -322,7 +322,7 @@ truenas_ws_deploy() { _info "Restarting WebUI..." _ws_response=$(_ws_call "system.general.ui_restart") _info "Waiting for UI restart..." - sleep 15 + _sleep 15 ########## Certificates From c3ec827fdd87ae7a595f7c84aa7395a52321f6df Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 19 Sep 2025 20:54:09 +0200 Subject: [PATCH 44/53] remove buypass --- acme.sh | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index 9105a0a4..4d849845 100755 --- a/acme.sh +++ b/acme.sh @@ -23,9 +23,6 @@ _SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY" CA_LETSENCRYPT_V2="https://acme-v02.api.letsencrypt.org/directory" CA_LETSENCRYPT_V2_TEST="https://acme-staging-v02.api.letsencrypt.org/directory" -CA_BUYPASS="https://api.buypass.com/acme/directory" -CA_BUYPASS_TEST="https://api.test4.buypass.no/acme/directory" - CA_ZEROSSL="https://acme.zerossl.com/v2/DV90" _ZERO_EAB_ENDPOINT="https://api.zerossl.com/acme/eab-credentials-email" @@ -42,14 +39,12 @@ CA_NAMES=" ZeroSSL.com,zerossl LetsEncrypt.org,letsencrypt LetsEncrypt.org_test,letsencrypt_test,letsencrypttest -BuyPass.com,buypass -BuyPass.com_test,buypass_test,buypasstest SSL.com,sslcom Google.com,google Google.com_test,googletest,google_test " -CA_SERVERS="$CA_ZEROSSL,$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_BUYPASS,$CA_BUYPASS_TEST,$CA_SSLCOM_RSA,$CA_GOOGLE,$CA_GOOGLE_TEST" +CA_SERVERS="$CA_ZEROSSL,$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_SSLCOM_RSA,$CA_GOOGLE,$CA_GOOGLE_TEST" DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" @@ -5478,10 +5473,6 @@ renew() { _info "Switching back to $CA_LETSENCRYPT_V2" Le_API="$CA_LETSENCRYPT_V2" ;; - "$CA_BUYPASS_TEST") - _info "Switching back to $CA_BUYPASS" - Le_API="$CA_BUYPASS" - ;; "$CA_GOOGLE_TEST") _info "Switching back to $CA_GOOGLE" Le_API="$CA_GOOGLE" From 471e0c05f9b69dd2ae2ce7c7968b7f497334c18d Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 20 Sep 2025 10:38:43 +0200 Subject: [PATCH 45/53] remove mageia --- .github/workflows/Linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Linux.yml b/.github/workflows/Linux.yml index c74e9d3e..f3352a41 100644 --- a/.github/workflows/Linux.yml +++ b/.github/workflows/Linux.yml @@ -26,7 +26,7 @@ jobs: Linux: strategy: matrix: - os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3"] + os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "gentoo/stage3"] runs-on: ubuntu-latest env: TEST_LOCAL: 1 From f22b490a10bf07317096511e59d7791fc13b4fb7 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 21 Sep 2025 18:04:59 +0200 Subject: [PATCH 46/53] remove buypass --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 9a5c106b..a8cb5403 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,6 @@ https://github.com/acmesh-official/acmetest - [ZeroSSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA)(default) - Letsencrypt.org CA -- [BuyPass.com CA](https://github.com/acmesh-official/acme.sh/wiki/BuyPass.com-CA) - [SSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/SSL.com-CA) - [Google.com Public CA](https://github.com/acmesh-official/acme.sh/wiki/Google-Public-CA) - [Pebble strict Mode](https://github.com/letsencrypt/pebble) From 5954f0dde54488d68bdd4c92ea2f0ab8ea1ee869 Mon Sep 17 00:00:00 2001 From: Jens Spanier Date: Mon, 22 Sep 2025 12:11:50 +0200 Subject: [PATCH 47/53] Change to `--cert-profile` --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7a8e4e9b..d157c2a4 100755 --- a/acme.sh +++ b/acme.sh @@ -7702,7 +7702,7 @@ _process() { _valid_to="$2" shift ;; - --certificate-profile | --profile) + --certificate-profile | --cert-profile) _certificate_profile="$2" shift ;; From 604e6873ba43609dc686f869e5c42a7d31547030 Mon Sep 17 00:00:00 2001 From: Jens Spanier Date: Mon, 22 Sep 2025 12:12:17 +0200 Subject: [PATCH 48/53] Add short name + wiki link to help --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d157c2a4..ef3c592d 100755 --- a/acme.sh +++ b/acme.sh @@ -180,6 +180,8 @@ _VALIDITY_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Validity" _DNSCHECK_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dnscheck" +_PROFILESELECTION_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Profile-selection" + _DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead." _DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR" @@ -7006,7 +7008,8 @@ Parameters: If no match, the default offered chain will be used. (default: empty) See: $_PREFERRED_CHAIN_WIKI - --certificate-profile If the CA offers profiles, select the desired profile + --cert-profile, --certificate-profile If the CA offers profiles, select the desired profile + See: $_PROFILESELECTION_WIKI --valid-to Request the NotAfter field of the cert. See: $_VALIDITY_WIKI From 11995b958ab560b2e8e60c816ba79200163047e9 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 27 Sep 2025 22:57:42 +0200 Subject: [PATCH 49/53] add actalis.com CA --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e895bbdc..23b03039 100755 --- a/acme.sh +++ b/acme.sh @@ -32,6 +32,8 @@ CA_SSLCOM_ECC="https://acme.ssl.com/sslcom-dv-ecc" CA_GOOGLE="https://dv.acme-v02.api.pki.goog/directory" CA_GOOGLE_TEST="https://dv.acme-v02.test-api.pki.goog/directory" +CA_ACTALIS="https://acme-api.actalis.com/acme/directory" + DEFAULT_CA=$CA_ZEROSSL DEFAULT_STAGING_CA=$CA_LETSENCRYPT_V2_TEST @@ -42,9 +44,10 @@ LetsEncrypt.org_test,letsencrypt_test,letsencrypttest SSL.com,sslcom Google.com,google Google.com_test,googletest,google_test +Actalis.com,actalis.com,actalis " -CA_SERVERS="$CA_ZEROSSL,$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_SSLCOM_RSA,$CA_GOOGLE,$CA_GOOGLE_TEST" +CA_SERVERS="$CA_ZEROSSL,$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_SSLCOM_RSA,$CA_GOOGLE,$CA_GOOGLE_TEST,$CA_ACTALIS" DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" From e5214ea2e58c9a7fd5fb95f651a5cfc1193787f4 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 27 Sep 2025 23:12:05 +0200 Subject: [PATCH 50/53] add Actalis.com CA --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a8cb5403..f7038f59 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ https://github.com/acmesh-official/acmetest - Letsencrypt.org CA - [SSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/SSL.com-CA) - [Google.com Public CA](https://github.com/acmesh-official/acme.sh/wiki/Google-Public-CA) +- [Actalis.com CA](https://github.com/acmesh-official/acme.sh/wiki/Actalis.com-CA) - [Pebble strict Mode](https://github.com/letsencrypt/pebble) - Any other [RFC8555](https://tools.ietf.org/html/rfc8555)-compliant CA From b244c76dd5f316c55812c9ebd41012625e58e5a0 Mon Sep 17 00:00:00 2001 From: Steven Zhu Date: Sat, 27 Sep 2025 17:29:12 -0400 Subject: [PATCH 51/53] Add --list-profiles command to show CA profiles This commit introduces a new command, `--list-profiles`, to allow users to discover the certificate profiles supported by a Certificate Authority. The command queries the `meta.profiles` object within the ACME directory JSON for the selected server and formats the output for readability. If a CA does not publish profiles in its directory, the command reports that none were found. Usage: acme.sh --list-profiles [--server letsencrypt] --- acme.sh | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/acme.sh b/acme.sh index 23b03039..24ebc5d4 100755 --- a/acme.sh +++ b/acme.sh @@ -5838,6 +5838,49 @@ list() { } +list_profiles() { + _initpath + _initAPI + + _l_server_url="$ACME_DIRECTORY" + _l_server_name="$(_getCAShortName "$_l_server_url")" + _info "Fetching profiles from $_l_server_name ($_l_server_url)..." + + # _initAPI fetches the directory, so we just need to parse its response. + response=$(_get "$_l_server_url" "" 10) + if [ "$?" != "0" ]; then + _err "Failed to connect to CA directory: $_l_server_url" + return 1 + fi + + # Isolate the profiles object using the script's regex tool + profiles_json=$(echo "$response" | _egrep_o '"profiles" *: *\{[^\}]*\}') + + if [ -z "$profiles_json" ]; then + _info "The CA '$_l_server_name' does not publish certificate profiles via its directory endpoint." + return 0 + fi + + # Strip the outer layer to get the key-value pairs + profiles_kv=$(echo "$profiles_json" | sed 's/"profiles" *: *{//' | sed 's/}$//' | tr ',' '\n') + + printf "\n%-15s %s\n" "name" "info" + printf -- "--------------------------------------------------------------------\n" + + _old_IFS="$IFS" + IFS=' +' + for pair in $profiles_kv; do + # Trim quotes and whitespace + _name=$(echo "$pair" | cut -d: -f1 | tr -d '" \t') + _info_url=$(echo "$pair" | cut -d: -f2- | sed 's/^ *//' | tr -d '"') + printf "%-15s %s\n" "$_name" "$_info_url" + done + IFS="$_old_IFS" + + return 0 +} + _deploy() { _d="$1" _hooks="$2" @@ -7498,6 +7541,9 @@ _process() { --set-default-chain) _CMD="setdefaultchain" ;; + --list-profiles) + _CMD="list_profiles" + ;; -d | --domain) _dvalue="$2" @@ -8063,6 +8109,9 @@ _process() { setdefaultchain) setdefaultchain "$_preferred_chain" ;; + list_profiles) + list_profiles + ;; *) if [ "$_CMD" ]; then _err "Invalid command: $_CMD" From 80748b9fe0a3e9af6f8db7b97fb9bea69e8d7206 Mon Sep 17 00:00:00 2001 From: Steven Zhu Date: Sat, 27 Sep 2025 17:37:37 -0400 Subject: [PATCH 52/53] Quick Patch --- acme.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 24ebc5d4..308db1aa 100755 --- a/acme.sh +++ b/acme.sh @@ -5846,15 +5846,14 @@ list_profiles() { _l_server_name="$(_getCAShortName "$_l_server_url")" _info "Fetching profiles from $_l_server_name ($_l_server_url)..." - # _initAPI fetches the directory, so we just need to parse its response. response=$(_get "$_l_server_url" "" 10) if [ "$?" != "0" ]; then _err "Failed to connect to CA directory: $_l_server_url" return 1 fi - # Isolate the profiles object using the script's regex tool - profiles_json=$(echo "$response" | _egrep_o '"profiles" *: *\{[^\}]*\}') + normalized_response=$(echo "$response" | _normalizeJson) + profiles_json=$(echo "$normalized_response" | _egrep_o '"profiles" *: *\{[^\}]*\}') if [ -z "$profiles_json" ]; then _info "The CA '$_l_server_name' does not publish certificate profiles via its directory endpoint." From 0f5093c0b7555c149ae2d7ab01d548dfd7844b2c Mon Sep 17 00:00:00 2001 From: Steven Zhu Date: Sat, 27 Sep 2025 17:52:44 -0400 Subject: [PATCH 53/53] Remove space --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 308db1aa..e5a0885f 100755 --- a/acme.sh +++ b/acme.sh @@ -7542,7 +7542,7 @@ _process() { ;; --list-profiles) _CMD="list_profiles" - ;; + ;; -d | --domain) _dvalue="$2" @@ -8110,7 +8110,7 @@ _process() { ;; list_profiles) list_profiles - ;; + ;; *) if [ "$_CMD" ]; then _err "Invalid command: $_CMD"