From 778ee02803098904be7dc5ec608665ad56060215 Mon Sep 17 00:00:00 2001 From: Frank Wall Date: Mon, 7 Nov 2022 23:43:37 +0100 Subject: [PATCH 01/13] update documentation for --cert-home Although the main use-case may be the --install command, this command also proves to be useful for the --signcsr and --issue commands. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d6d8e48c..9d6dfecc 100755 --- a/acme.sh +++ b/acme.sh @@ -6897,7 +6897,7 @@ Parameters: --accountconf Specifies a customized account config file. --home Specifies the home dir for $PROJECT_NAME. - --cert-home Specifies the home dir to save all the certs, only valid for '--install' command. + --cert-home Specifies the home dir to save all the certs. --config-home Specifies the home dir to save all the configurations. --useragent Specifies the user agent string. it will be saved for future use too. -m, --email Specifies the account email, only valid for the '--install' and '--update-account' command. From 22dfedf6ae447404616102b14c01bdf9ddb70caf Mon Sep 17 00:00:00 2001 From: Kevin Locke Date: Mon, 13 Feb 2017 14:09:25 -0700 Subject: [PATCH 02/13] Avoid permissions errors for chown .well-known When acme.sh is run as a non-root user different from the owner of the webroot directory it is unable to change the owner of the files in .well-known to that user, causing permissions errors. Avoid this by making the files world-readable. These files should pose no disclosure risk since they are sent in cleartext during the HTTP Identifier Validation Challenge[1] and may already be exposed by directory enumeration, depending on server settings. AFAIK they should be safe to expose as world-readable in all cases. 1. https://ietf-wg-acme.github.io/acme/#rfc.section.7.2 Fixes Neilpang/acme.sh#32 Signed-off-by: Kevin Locke --- acme.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 9842e3f1..3e1c85bd 100755 --- a/acme.sh +++ b/acme.sh @@ -5002,9 +5002,11 @@ $_authorizations_map" _debug "Writing token: $token to $wellknown_path/$token" - mkdir -p "$wellknown_path" - - if ! printf "%s" "$keyauthorization" >"$wellknown_path/$token"; then + # Ensure .well-known is visible to web server user/group + # https://github.com/Neilpang/acme.sh/pull/32 + if ! (umask ugo+rx && + mkdir -p "$wellknown_path" && + printf "%s" "$keyauthorization" >"$wellknown_path/$token"); then _err "$d: Cannot write token to file: $wellknown_path/$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup From 6c555cb6663ff5903af9ae7149813c8095335206 Mon Sep 17 00:00:00 2001 From: Lindsay Zhou Date: Mon, 13 Jan 2025 10:22:46 +0800 Subject: [PATCH 03/13] fix regex of matching hetzner dns api error responses --- dnsapi/dns_hetzner.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 dnsapi/dns_hetzner.sh diff --git a/dnsapi/dns_hetzner.sh b/dnsapi/dns_hetzner.sh old mode 100644 new mode 100755 index 5a9cf2d9..f1bddc61 --- a/dnsapi/dns_hetzner.sh +++ b/dnsapi/dns_hetzner.sh @@ -212,7 +212,7 @@ _get_root() { _response_has_error() { unset _response_error - err_part="$(echo "$response" | _egrep_o '"error":{[^}]*}')" + err_part="$(echo "$response" | _egrep_o '"error":\{[^\}]*\}')" if [ -n "$err_part" ]; then err_code=$(echo "$err_part" | _egrep_o '"code":[0-9]+' | cut -d : -f 2) From 5236e810687b79cf15fb05ff501ca99b9f64aff3 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 23 Feb 2025 09:28:14 +0100 Subject: [PATCH 04/13] version 3.1.1 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 51d6f886..3d4e6108 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=3.1.0 +VER=3.1.1 PROJECT_NAME="acme.sh" From 661c3bbdb0f956f154fc0658348d30ed3f57ef09 Mon Sep 17 00:00:00 2001 From: aafbsd <45147422+aafbsd@users.noreply.github.com> Date: Mon, 24 Feb 2025 12:33:42 +0000 Subject: [PATCH 05/13] Support FreeBSD's sed -i FreeBSD's sed requires an extension for the backup file when -i is used. However, it may be zero-length to indicate that no backup is desired. --- acme.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/acme.sh b/acme.sh index 3d4e6108..f03d79d4 100755 --- a/acme.sh +++ b/acme.sh @@ -921,6 +921,9 @@ _sed_i() { if sed -h 2>&1 | grep "\-i\[SUFFIX]" >/dev/null 2>&1; then _debug "Using sed -i" sed -i "$options" "$filename" + elif sed -h 2>&1 | grep "\-i extension" >/dev/null 2>&1; then + _debug "Using FreeBSD sed -i" + sed -i "" "$options" "$filename" else _debug "No -i support in sed" text="$(cat "$filename")" From dd2199c4725797fae6f70131370ca9e40abf7a0e Mon Sep 17 00:00:00 2001 From: Giovannimaria Gandossi Date: Wed, 19 Feb 2025 14:39:36 +0100 Subject: [PATCH 06/13] Adding support for FreeMyIP dns API --- dnsapi/dns_freemyip.sh | 105 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 dnsapi/dns_freemyip.sh diff --git a/dnsapi/dns_freemyip.sh b/dnsapi/dns_freemyip.sh new file mode 100644 index 00000000..0bad3809 --- /dev/null +++ b/dnsapi/dns_freemyip.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_freemyip_info='FreeMyIP.com +Site: freemyip.com +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_freemyip +Options: + FREEMYIP_Token API Token +Issues: github.com/acmesh-official/acme.sh/issues/{XXXX} +Author: Recolic Keghart , @Giova96 +' + +FREEMYIP_DNS_API="https://freemyip.com/update?" + +################ Public functions ################ + +#Usage: dns_freemyip_add fulldomain txtvalue +dns_freemyip_add() { + fulldomain="$1" + txtvalue="$2" + + _info "Add TXT record $txtvalue for $fulldomain using freemyip.com api" + + FREEMYIP_Token="${FREEMYIP_Token:-$(_readaccountconf_mutable FREEMYIP_Token)}" + if [ -z "$FREEMYIP_Token" ]; then + FREEMYIP_Token="" + _err "You don't specify FREEMYIP_Token yet." + _err "Please specify your token and try again." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable FREEMYIP_Token "$FREEMYIP_Token" + + if _is_root_domain_published "$fulldomain"; then + _err "freemyip API don't allow you to set multiple TXT record for the same subdomain!" + _err "You must apply certificate for only one domain at a time!" + _err "====" + _err "For example, aaa.yourdomain.freemyip.com and bbb.yourdomain.freemyip.com and yourdomain.freemyip.com ALWAYS share the same TXT record. They will overwrite each other if you apply multiple domain at the same time." + _debug "If you are testing this workflow in github pipeline or acmetest, please set TEST_DNS_NO_SUBDOMAIN=1 and TEST_DNS_NO_WILDCARD=1" + return 1 + fi + + # txtvalue must be url-encoded. But it's not necessary for acme txt value. + _freemyip_get_until_ok "${FREEMYIP_DNS_API}token=$FREEMYIP_Token&domain=$fulldomain&txt=$txtvalue" 2>&1 + return $? +} + +#Usage: dns_freemyip_rm fulldomain txtvalue +dns_freemyip_rm() { + fulldomain="$1" + txtvalue="$2" + + _info "Delete TXT record $txtvalue for $fulldomain using freemyip.com api" + + FREEMYIP_Token="${FREEMYIP_Token:-$(_readaccountconf_mutable FREEMYIP_Token)}" + if [ -z "$FREEMYIP_Token" ]; then + FREEMYIP_Token="" + _err "You don't specify FREEMYIP_Token yet." + _err "Please specify your token and try again." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable FREEMYIP_Token "$FREEMYIP_Token" + + # Leave the TXT record as empty or "null" to delete the record. + _freemyip_get_until_ok "${FREEMYIP_DNS_API}token=$FREEMYIP_Token&domain=$fulldomain&txt=" 2>&1 + return $? +} + +################ Private functions below ################ +_get_root() { + _fmi_d="$1" + + echo "$_fmi_d" | rev | cut -d '.' -f 1-3 | rev +} + +# There is random failure while calling freemyip API too fast. This function automatically retry until success. +_freemyip_get_until_ok() { + _fmi_url="$1" + for i in $(seq 1 8); do + _debug "HTTP GET freemyip.com API '$_fmi_url', retry $i/8..." + _get "$_fmi_url" | tee /dev/fd/2 | grep OK && return 0 + _sleep 1 # DO NOT send the request too fast + done + _err "Failed to request freemyip API: $_fmi_url . Server does not say 'OK'" + return 1 +} + +# Verify in public dns if domain is already there. +_is_root_domain_published() { + _fmi_d="$1" + _webroot="$(_get_root "$_fmi_d")" + + _info "Verifying '""$_fmi_d""' freemyip webroot (""$_webroot"") is not published yet" + for i in $(seq 1 3); do + _debug "'$_webroot' ns lookup, retry $i/3..." + if [ "$(_ns_lookup "$_fmi_d" TXT)" ]; then + _debug "'$_webroot' already has a TXT record published!" + return 0 + fi + _sleep 10 # Give it some time to propagate the TXT record + done + return 1 +} From dc8cf0e02ec2b41892bd1b2e82cd492b16dfe46a Mon Sep 17 00:00:00 2001 From: metaforget <97219459+metaforget@users.noreply.github.com> Date: Mon, 3 Mar 2025 10:37:38 +0800 Subject: [PATCH 07/13] =?UTF-8?q?cqhttp=20notify-hook=EF=BC=9ACompatibilit?= =?UTF-8?q?y=20with=20QQ=20Headless=20Project=20Napcat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notify/cqhttp.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notify/cqhttp.sh b/notify/cqhttp.sh index ac76f5b8..28010ffd 100644 --- a/notify/cqhttp.sh +++ b/notify/cqhttp.sh @@ -52,7 +52,7 @@ cqhttp_send() { _finalUrl="$CQHTTP_APIROOT$CQHTTP_APIPATH?access_token=$_access_token&user_id=$_user_id&message=$_message" response="$(_get "$_finalUrl")" - if [ "$?" = "0" ] && _contains "$response" "\"retcode\":0,\"status\":\"ok\""; then + if [ "$?" = "0" ] && _contains "$response" "\"retcode\":0" && _contains "$response" "\"status\":\"ok\""; then _info "QQ send success." return 0 fi From ebdd221c72c3db413aacba7fe92c0d6bf064b204 Mon Sep 17 00:00:00 2001 From: copyliu <1076640+copyliu@users.noreply.github.com> Date: Wed, 5 Mar 2025 11:33:41 +0800 Subject: [PATCH 08/13] routeros: file-name should in quotes in newer (7.18) version --- deploy/routeros.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/routeros.sh b/deploy/routeros.sh index 90f0ad1a..ef9c6954 100644 --- a/deploy/routeros.sh +++ b/deploy/routeros.sh @@ -144,8 +144,8 @@ source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\ \n/certificate remove [ find name=$_cdomain.cer_1 ];\ \n/certificate remove [ find name=$_cdomain.cer_2 ];\ \ndelay 1;\ -\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\";\ -\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\";\ +\n/certificate import file-name=\\\"$_cdomain.cer\\\" passphrase=\\\"\\\";\ +\n/certificate import file-name=\\\"$_cdomain.key\\\" passphrase=\\\"\\\";\ \ndelay 1;\ \n:do {/file remove $_cdomain.cer; } on-error={ }\ \n:do {/file remove $_cdomain.key; } on-error={ }\ From 262fa74f5e7ba00ba1f23e9f5921c6412ab35cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markku=20Leini=C3=B6?= Date: Wed, 5 Mar 2025 19:45:01 +0200 Subject: [PATCH 09/13] dns_he_ddns: Add empty dns_he_ddns_rm() to remove warnings --- dnsapi/dns_he_ddns.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_he_ddns.sh b/dnsapi/dns_he_ddns.sh index 7d56104c..cd7d1ec2 100644 --- a/dnsapi/dns_he_ddns.sh +++ b/dnsapi/dns_he_ddns.sh @@ -34,5 +34,11 @@ dns_he_ddns_add() { _contains "$response" "good" && return 0 || return 1 } -# dns_he_ddns_rm() is not implemented because the API call always updates the +# dns_he_ddns_rm() is not doing anything because the API call always updates the # contents of the existing record (that the API key gives access to). + +dns_he_ddns_rm() { + fulldomain=$1 + _debug "Delete TXT record called for '${fulldomain}', not doing anything." + return 0 +} From 7e320d274859d7b90acb6004f3abd19c28ad3914 Mon Sep 17 00:00:00 2001 From: William Lallemand Date: Tue, 11 Mar 2025 12:04:00 +0100 Subject: [PATCH 10/13] haproxy: don't leak private keys when doing --debug It was reported in issue #6267 that the private key was leaked when using the DEPLOY_HAPROXY_HOT_UPDATE=yes feature. Indeed, the debugging code which sends commands to HAProxy was using _debug even when passing the private key. This patch fixes the issue by using _secure_debug when doing that. --- deploy/haproxy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index c8491d92..19509e3b 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -357,7 +357,7 @@ haproxy_deploy() { _info "Update existing certificate '${_pem}' over HAProxy ${_socketname}." fi _socat_cert_set_cmd="echo -e '${_cmdpfx}set ssl cert ${_pem} <<\n$(cat "${_pem}")\n' | socat '${_statssock}' - | grep -q 'Transaction created'" - _debug _socat_cert_set_cmd "${_socat_cert_set_cmd}" + _secure_debug _socat_cert_set_cmd "${_socat_cert_set_cmd}" eval "${_socat_cert_set_cmd}" _ret=$? if [ "${_ret}" != "0" ]; then From f1dc79f0b51ca3e727d397c601a0cc85ab8d03b1 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Thu, 20 Mar 2025 10:13:12 +0100 Subject: [PATCH 11/13] support NTFY_TOKEN --- notify/ntfy.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/notify/ntfy.sh b/notify/ntfy.sh index 650d1c74..21e39559 100644 --- a/notify/ntfy.sh +++ b/notify/ntfy.sh @@ -4,6 +4,7 @@ #NTFY_URL="https://ntfy.sh" #NTFY_TOPIC="xxxxxxxxxxxxx" +#NTFY_TOKEN="xxxxxxxxxxxxx" ntfy_send() { _subject="$1" @@ -23,6 +24,12 @@ ntfy_send() { _saveaccountconf_mutable NTFY_TOPIC "$NTFY_TOPIC" fi + NTFY_TOKEN="${NTFY_TOKEN:-$(_readaccountconf_mutable NTFY_TOKEN)}" + if [ "$NTFY_TOKEN" ]; then + _saveaccountconf_mutable NTFY_TOKEN "$NTFY_TOKEN" + export _H1="Authorization: Bearer $NTFY_TOKEN" + fi + _data="${_subject}. $_content" response="$(_post "$_data" "$NTFY_URL/$NTFY_TOPIC" "" "POST" "")" From 5c7b1cd5f2d2aaa7ba9810e81294bcabbfbfc3ad Mon Sep 17 00:00:00 2001 From: Sikro Date: Tue, 3 Dec 2024 15:07:37 +0800 Subject: [PATCH 12/13] add environment variable for notify/telegram.sh Since the server in mainland China cannot connect to Telegram, add the TELEGRAM_BOT_URLBASE environment variable Please add the proxy address you set. If this variable is not added, it will be the default value (https://api.telegram.org) --- notify/telegram.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/notify/telegram.sh b/notify/telegram.sh index cca8ee25..ccbd1533 100644 --- a/notify/telegram.sh +++ b/notify/telegram.sh @@ -4,6 +4,7 @@ #TELEGRAM_BOT_APITOKEN="" #TELEGRAM_BOT_CHATID="" +#TELEGRAM_BOT_URLBASE="" telegram_send() { _subject="$1" @@ -27,6 +28,12 @@ telegram_send() { fi _saveaccountconf_mutable TELEGRAM_BOT_CHATID "$TELEGRAM_BOT_CHATID" + TELEGRAM_BOT_URLBASE="${TELEGRAM_BOT_URLBASE:-$(_readaccountconf_mutable TELEGRAM_BOT_URLBASE)}" + if [ -z "$TELEGRAM_BOT_URLBASE" ]; then + TELEGRAM_BOT_URLBASE="https://api.telegram.org" + 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')" _content="$(printf "*%s*\n%s" "$_subject" "$_content" | _json_encode)" @@ -38,7 +45,7 @@ telegram_send() { _debug "$_data" export _H1="Content-Type: application/json" - _telegram_bot_url="https://api.telegram.org/bot${TELEGRAM_BOT_APITOKEN}/sendMessage" + _telegram_bot_url="${TELEGRAM_BOT_URLBASE}/bot${TELEGRAM_BOT_APITOKEN}/sendMessage" if _post "$_data" "$_telegram_bot_url" >/dev/null; then # shellcheck disable=SC2154 _message=$(printf "%s\n" "$response" | sed -n 's/.*"ok":\([^,]*\).*/\1/p') From a1de13657e79c5471dbc8fa3539ea39160937389 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 28 Mar 2025 20:50:08 +0100 Subject: [PATCH 13/13] minor, just copy necessary files --- Dockerfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3f400283..4d7d22b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,11 @@ ARG AUTO_UPGRADE=1 ENV AUTO_UPGRADE=$AUTO_UPGRADE #Install -COPY ./ /install_acme.sh/ +COPY ./acme.sh /install_acme.sh/acme.sh +COPY ./deploy /install_acme.sh/deploy +COPY ./dnsapi /install_acme.sh/dnsapi +COPY ./notify /install_acme.sh/notify + RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/