diff --git a/acme.sh b/acme.sh index f03d79d4..2cf681eb 100755 --- a/acme.sh +++ b/acme.sh @@ -5005,9 +5005,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 @@ -7018,7 +7020,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. 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 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={ }\ 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 +} 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 +} 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) 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 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" "")" 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')