#!/usr/bin/env sh
-VER=3.0.0
+VER=3.0.1
PROJECT_NAME="acme.sh"
_SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY"
+CA_LETSENCRYPT_V1="https://acme-v01.api.letsencrypt.org/directory"
+
CA_LETSENCRYPT_V2="https://acme-v02.api.letsencrypt.org/directory"
CA_LETSENCRYPT_V2_TEST="https://acme-staging-v02.api.letsencrypt.org/directory"
if [ -z "$ACME_HTTP_NO_REDIRECTS" ]; then
_ACME_CURL="$_ACME_CURL -L "
fi
- if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
+ if [ "$DEBUG" ] && [ "$DEBUG" -ge 2 ]; then
_CURL_DUMP="$(_mktemp)"
_ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP "
fi
}
+_HTTP_MAX_RETRY=8
+
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
_post() {
body="$1"
needbase64="$3"
httpmethod="$4"
_postContentType="$5"
+ _sleep_retry_sec=1
+ _http_retry_times=0
+ _hcode=0
+ while [ "${_http_retry_times}" -le "$_HTTP_MAX_RETRY" ]; do
+ [ "$_http_retry_times" = "$_HTTP_MAX_RETRY" ]
+ _lastHCode="$?"
+ _debug "Retrying post"
+ _post_impl "$body" "$_post_url" "$needbase64" "$httpmethod" "$_postContentType" "$_lastHCode"
+ _hcode="$?"
+ _debug _hcode "$_hcode"
+ if [ "$_hcode" = "0" ]; then
+ break
+ fi
+ _http_retry_times=$(_math $_http_retry_times + 1)
+ _sleep $_sleep_retry_sec
+ done
+ return $_hcode
+}
+
+# body url [needbase64] [POST|PUT|DELETE] [ContentType] [displayError]
+_post_impl() {
+ body="$1"
+ _post_url="$2"
+ needbase64="$3"
+ httpmethod="$4"
+ _postContentType="$5"
+ displayError="$6"
if [ -z "$httpmethod" ]; then
httpmethod="POST"
fi
_ret="$?"
if [ "$_ret" != "0" ]; then
- _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
+ if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
+ _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
+ fi
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
_err "Here is the curl dump log:"
_err "$(cat "$_CURL_DUMP")"
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
fi
if [ "$_ret" != "0" ]; then
- _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
+ if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
+ _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
+ fi
fi
_sed_i "s/^ *//g" "$HTTP_HEADER"
else
# url getheader timeout
_get() {
+ url="$1"
+ onlyheader="$2"
+ t="$3"
+ _sleep_retry_sec=1
+ _http_retry_times=0
+ _hcode=0
+ while [ "${_http_retry_times}" -le "$_HTTP_MAX_RETRY" ]; do
+ [ "$_http_retry_times" = "$_HTTP_MAX_RETRY" ]
+ _lastHCode="$?"
+ _debug "Retrying GET"
+ _get_impl "$url" "$onlyheader" "$t" "$_lastHCode"
+ _hcode="$?"
+ _debug _hcode "$_hcode"
+ if [ "$_hcode" = "0" ]; then
+ break
+ fi
+ _http_retry_times=$(_math $_http_retry_times + 1)
+ _sleep $_sleep_retry_sec
+ done
+ return $_hcode
+}
+
+# url getheader timeout displayError
+_get_impl() {
_debug GET
url="$1"
onlyheader="$2"
t="$3"
+ displayError="$4"
_debug url "$url"
_debug "timeout=$t"
-
+ _debug "displayError" "$displayError"
_inithttp
if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then
fi
ret=$?
if [ "$ret" != "0" ]; then
- _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
+ if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
+ _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
+ fi
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
_err "Here is the curl dump log:"
_err "$(cat "$_CURL_DUMP")"
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
fi
if [ "$ret" != "0" ]; then
- _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
+ if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
+ _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
+ fi
fi
else
ret=$?
fi
}
+_clearAPI() {
+ ACME_NEW_ACCOUNT=""
+ ACME_KEY_CHANGE=""
+ ACME_NEW_AUTHZ=""
+ ACME_NEW_ORDER=""
+ ACME_REVOKE_CERT=""
+ ACME_NEW_NONCE=""
+ ACME_AGREEMENT=""
+}
+
#server
_initAPI() {
_api_server="${1:-$ACME_DIRECTORY}"
_info "Sleep $_sleep_retry_sec and retry."
_sleep "$_sleep_retry_sec"
done
+ if [ "$ACME_NEW_ACCOUNT" ] && [ "$ACME_NEW_ORDER" ]; then
+ return 0
+ fi
_err "Can not init api, for $_api_server"
return 1
}
if ! _startswith "$included" "/" && _exists dirname; then
_relpath="$(dirname "$_c_file")"
_debug "_relpath" "$_relpath"
- included="$_relpath/included"
+ included="$_relpath/$included"
fi
if _checkConf "$1" "$included"; then
return 0
if [ "$_chk_pre_hook" ]; then
_info "Run pre hook:'$_chk_pre_hook'"
if ! (
+ export Le_Domain="$_chk_main_domain"
+ export Le_Alt="$_chk_alt_domains"
cd "$DOMAIN_PATH" && eval "$_chk_pre_hook"
); then
_err "Error when run pre hook."
_netprc="$(_ss "$_checkport" | grep "$_checkport")"
netprc="$(echo "$_netprc" | grep "$_checkaddr")"
if [ -z "$netprc" ]; then
- netprc="$(echo "$_netprc" | grep "$LOCAL_ANY_ADDRESS")"
+ netprc="$(echo "$_netprc" | grep "$LOCAL_ANY_ADDRESS:$_checkport")"
fi
if [ "$netprc" ]; then
_err "$netprc"
return 1
fi
_secure_debug2 _eabresp "$_eabresp"
- _eab_id="$(echo "$_eabresp" | tr ',}' '\n' | grep '"eab_kid"' | cut -d : -f 2 | tr -d '"')"
+ _eab_id="$(echo "$_eabresp" | tr ',}' '\n\n' | grep '"eab_kid"' | cut -d : -f 2 | tr -d '"')"
_secure_debug2 _eab_id "$_eab_id"
if [ -z "$_eab_id" ]; then
_err "Can not resolve _eab_id"
}
_ns_is_available_dp() {
- if _get "https://dns.alidns.com" "" 1 >/dev/null 2>&1; then
+ if _get "https://doh.pub" "" 1 >/dev/null 2>&1; then
return 0
else
return 1
if [ -z "$_ACME_IS_RENEW" ]; then
_initpath "$_main_domain" "$_key_length"
mkdir -p "$DOMAIN_PATH"
+ elif ! _hasfield "$_web_roots" "$W_DNS"; then
+ Le_OrderFinalize=""
+ Le_LinkOrder=""
+ Le_LinkCert=""
fi
if _hasfield "$_web_roots" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then
return 1
fi
- _debug "sleep 2 secs to verify"
- sleep 2
- _debug "checking"
-
- _send_signed_request "$uri"
-
- if [ "$?" != "0" ]; then
- _err "$d:Verify error:$response"
- _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
- _clearup
- _on_issue_err "$_post_hook" "$vlist"
- return 1
- fi
_debug2 original "$response"
response="$(echo "$response" | _normalizeJson)"
_debug2 response "$response"
status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"')
-
+ _debug2 status "$status"
if _contains "$status" "invalid"; then
error="$(echo "$response" | _egrep_o '"error":\{[^\}]*')"
_debug2 error "$error"
fi
if [ "$status" = "pending" ]; then
- _info "Pending"
+ _info "Pending, The CA is processing your order, please just wait. ($waittimes/$MAX_RETRY_TIMES)"
elif [ "$status" = "processing" ]; then
- _info "Processing"
+ _info "Processing, The CA is processing your order, please just wait. ($waittimes/$MAX_RETRY_TIMES)"
else
_err "$d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
+ _debug "sleep 2 secs to verify again"
+ sleep 2
+ _debug "checking"
+
+ _send_signed_request "$uri"
+ if [ "$?" != "0" ]; then
+ _err "$d:Verify error:$response"
+ _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
+ _clearup
+ _on_issue_err "$_post_hook" "$vlist"
+ return 1
+ fi
done
done
echo "$response" >"$CERT_PATH"
_split_cert_chain "$CERT_PATH" "$CERT_FULLCHAIN_PATH" "$CA_CERT_PATH"
-
+ if [ -z "$_preferred_chain" ]; then
+ _preferred_chain=$(_readcaconf DEFAULT_PREFERRED_CHAIN)
+ fi
if [ "$_preferred_chain" ] && [ -f "$CERT_FULLCHAIN_PATH" ]; then
if [ "$DEBUG" ]; then
_debug "default chain issuers: " "$(_get_chain_issuers "$CERT_FULLCHAIN_PATH")"
_info "$(__green "Cert success.")"
cat "$CERT_PATH"
- _info "Your cert is in $(__green " $CERT_PATH ")"
+ _info "Your cert is in: $(__green "$CERT_PATH")"
if [ -f "$CERT_KEY_PATH" ]; then
- _info "Your cert key is in $(__green " $CERT_KEY_PATH ")"
+ _info "Your cert key is in: $(__green "$CERT_KEY_PATH")"
fi
if [ ! "$USER_PATH" ] || [ ! "$_ACME_IN_CRON" ]; then
fi
fi
- [ -f "$CA_CERT_PATH" ] && _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")"
- [ -f "$CERT_FULLCHAIN_PATH" ] && _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")"
+ [ -f "$CA_CERT_PATH" ] && _info "The intermediate CA cert is in: $(__green "$CA_CERT_PATH")"
+ [ -f "$CERT_FULLCHAIN_PATH" ] && _info "And the full chain certs is there: $(__green "$CERT_FULLCHAIN_PATH")"
Le_CertCreateTime=$(_time)
_savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime"
. "$DOMAIN_CONF"
_debug Le_API "$Le_API"
+ if [ -z "$Le_API" ] || [ "$CA_LETSENCRYPT_V1" = "$Le_API" ]; then
+ #if this is from an old version, Le_API is empty,
+ #so, we force to use letsencrypt server
+ Le_API="$CA_LETSENCRYPT_V2"
+ fi
if [ "$Le_API" ]; then
+ if [ "$Le_API" != "$ACME_DIRECTORY" ]; then
+ _clearAPI
+ fi
export ACME_DIRECTORY="$Le_API"
#reload ca configs
ACCOUNT_KEY_PATH=""
CA_CONF=""
_debug3 "initpath again."
_initpath "$Le_Domain" "$_isEcc"
+ _initAPI
fi
if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
mkdir -p "$_backup_path"
if [ "$_real_cert" ]; then
- _info "Installing cert to:$_real_cert"
+ _info "Installing cert to: $_real_cert"
if [ -f "$_real_cert" ] && [ ! "$_ACME_IS_RENEW" ]; then
cp "$_real_cert" "$_backup_path/cert.bak"
fi
fi
if [ "$_real_ca" ]; then
- _info "Installing CA to:$_real_ca"
+ _info "Installing CA to: $_real_ca"
if [ "$_real_ca" = "$_real_cert" ]; then
echo "" >>"$_real_ca"
cat "$CA_CERT_PATH" >>"$_real_ca" || return 1
fi
if [ "$_real_key" ]; then
- _info "Installing key to:$_real_key"
+ _info "Installing key to: $_real_key"
if [ -f "$_real_key" ] && [ ! "$_ACME_IS_RENEW" ]; then
cp "$_real_key" "$_backup_path/key.bak"
fi
fi
if [ "$_real_fullchain" ]; then
- _info "Installing full chain to:$_real_fullchain"
+ _info "Installing full chain to: $_real_fullchain"
if [ -f "$_real_fullchain" ] && [ ! "$_ACME_IS_RENEW" ]; then
cp "$_real_fullchain" "$_backup_path/fullchain.bak"
fi
_info "Removing cron job"
cr="$($_CRONTAB -l | grep "$PROJECT_ENTRY --cron")"
if [ "$cr" ]; then
- if _exists uname && uname -a | grep solaris >/dev/null; then
+ if _exists uname && uname -a | grep SunOS >/dev/null; then
$_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB --
else
$_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB -
return 1
fi
+ . "$DOMAIN_CONF"
+ _debug Le_API "$Le_API"
+
+ if [ "$Le_API" ]; then
+ if [ "$Le_API" != "$ACME_DIRECTORY" ]; then
+ _clearAPI
+ fi
+ export ACME_DIRECTORY="$Le_API"
+ #reload ca configs
+ ACCOUNT_KEY_PATH=""
+ ACCOUNT_JSON_PATH=""
+ CA_CONF=""
+ _debug3 "initpath again."
+ _initpath "$Le_Domain" "$_isEcc"
+ _initAPI
+ fi
+
cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _url_replace)"
if [ -z "$cert" ]; then
_deactivate() {
_d_domain="$1"
_d_type="$2"
- _initpath
+ _initpath "$_d_domain" "$_d_type"
+
+ . "$DOMAIN_CONF"
+ _debug Le_API "$Le_API"
+
+ if [ "$Le_API" ]; then
+ if [ "$Le_API" != "$ACME_DIRECTORY" ]; then
+ _clearAPI
+ fi
+ export ACME_DIRECTORY="$Le_API"
+ #reload ca configs
+ ACCOUNT_KEY_PATH=""
+ ACCOUNT_JSON_PATH=""
+ CA_CONF=""
+ _debug3 "initpath again."
+ _initpath "$Le_Domain" "$_d_type"
+ _initAPI
+ fi
_identifiers="{\"type\":\"dns\",\"value\":\"$_d_domain\"}"
if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then
_debug2 response "$response"
_URL_NAME="url"
- entries="$(echo "$response" | tr '][' '==' | _egrep_o "challenges\": *=[^=]*=" | tr '}{' '\n' | grep "\"status\": *\"valid\"")"
+ entries="$(echo "$response" | tr '][' '==' | _egrep_o "challenges\": *=[^=]*=" | tr '}{' '\n\n' | grep "\"status\": *\"valid\"")"
if [ -z "$entries" ]; then
_info "No valid entries found."
if [ -z "$thumbprint" ]; then
--deactivate Deactivate the domain authz, professional use.
--set-default-ca Used with '--server', Set the default CA to use.
See: $_SERVER_WIKI
+ --set-default-chain Set the default preferred chain for a CA.
+ See: $_PREFERRED_CHAIN_WIKI
Parameters:
_hash_path=$1
shift
_hash_url="https://api.github.com/repos/acmesh-official/$PROJECT_NAME/git/refs/$_hash_path"
- _get $_hash_url | tr -d "\r\n" | tr '{},' '\n' | grep '"sha":' | cut -d '"' -f 4
+ _get $_hash_url | tr -d "\r\n" | tr '{},' '\n\n\n' | grep '"sha":' | cut -d '"' -f 4
}
_getUpgradeHash() {
_info "Changed default CA to: $(__green "$ACME_DIRECTORY")"
}
+#preferred-chain
+setdefaultchain() {
+ _initpath
+ _preferred_chain="$1"
+ if [ -z "$_preferred_chain" ]; then
+ _err "Please give a '--preferred-chain value' value."
+ return 1
+ fi
+ mkdir -p "$CA_DIR"
+ _savecaconf "DEFAULT_PREFERRED_CHAIN" "$_preferred_chain"
+}
+
_process() {
_CMD=""
_domain=""
--set-default-ca)
_CMD="setdefaultca"
;;
+ --set-default-chain)
+ _CMD="setdefaultchain"
+ ;;
-d | --domain)
_dvalue="$2"
setdefaultca)
setdefaultca
;;
+ setdefaultchain)
+ setdefaultchain "$_preferred_chain"
+ ;;
*)
if [ "$_CMD" ]; then
_err "Invalid command: $_CMD"