|
@@ -9,6 +9,9 @@ PROJECT_ENTRY="acme.sh"
|
|
|
PROJECT="https://github.com/Neilpang/$PROJECT_NAME"
|
|
|
|
|
|
DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME"
|
|
|
+
|
|
|
+_WINDOWS_SCHEDULER_NAME="$PROJECT_NAME.cron"
|
|
|
+
|
|
|
_SCRIPT_="$0"
|
|
|
|
|
|
_SUB_FOLDERS="dnsapi deploy"
|
|
@@ -19,8 +22,8 @@ LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory"
|
|
|
LETSENCRYPT_CA_V2="https://acme-v02.api.letsencrypt.org/directory"
|
|
|
LETSENCRYPT_STAGING_CA_V2="https://acme-staging-v02.api.letsencrypt.org/directory"
|
|
|
|
|
|
-DEFAULT_CA=$LETSENCRYPT_CA_V1
|
|
|
-DEFAULT_STAGING_CA=$LETSENCRYPT_STAGING_CA_V1
|
|
|
+DEFAULT_CA=$LETSENCRYPT_CA_V2
|
|
|
+DEFAULT_STAGING_CA=$LETSENCRYPT_STAGING_CA_V2
|
|
|
|
|
|
DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
|
|
|
DEFAULT_ACCOUNT_EMAIL=""
|
|
@@ -66,6 +69,9 @@ END_CERT="-----END CERTIFICATE-----"
|
|
|
CONTENT_TYPE_JSON="application/jose+json"
|
|
|
RENEW_SKIP=2
|
|
|
|
|
|
+B64CONF_START="__ACME_BASE64__START_"
|
|
|
+B64CONF_END="__ACME_BASE64__END_"
|
|
|
+
|
|
|
ECC_SEP="_"
|
|
|
ECC_SUFFIX="${ECC_SEP}ecc"
|
|
|
|
|
@@ -1827,23 +1833,29 @@ _send_signed_request() {
|
|
|
nonceurl="$ACME_NEW_NONCE"
|
|
|
if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then
|
|
|
_headers="$(cat "$HTTP_HEADER")"
|
|
|
+ _debug2 _headers "$_headers"
|
|
|
+ _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
|
|
|
fi
|
|
|
fi
|
|
|
- if [ -z "$_headers" ]; then
|
|
|
+ if [ -z "$_CACHED_NONCE" ]; then
|
|
|
_debug2 "Get nonce with GET. ACME_DIRECTORY" "$ACME_DIRECTORY"
|
|
|
nonceurl="$ACME_DIRECTORY"
|
|
|
_headers="$(_get "$nonceurl" "onlyheader")"
|
|
|
+ _debug2 _headers "$_headers"
|
|
|
+ _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
|
|
|
fi
|
|
|
-
|
|
|
+ if [ -z "$_CACHED_NONCE" ] && [ "$ACME_NEW_NONCE" ]; then
|
|
|
+ _debug2 "Get nonce with GET. ACME_NEW_NONCE" "$ACME_NEW_NONCE"
|
|
|
+ nonceurl="$ACME_NEW_NONCE"
|
|
|
+ _headers="$(_get "$nonceurl" "onlyheader")"
|
|
|
+ _debug2 _headers "$_headers"
|
|
|
+ _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
|
|
|
+ fi
|
|
|
+ _debug2 _CACHED_NONCE "$_CACHED_NONCE"
|
|
|
if [ "$?" != "0" ]; then
|
|
|
_err "Can not connect to $nonceurl to get nonce."
|
|
|
return 1
|
|
|
fi
|
|
|
-
|
|
|
- _debug2 _headers "$_headers"
|
|
|
-
|
|
|
- _CACHED_NONCE="$(echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
|
|
|
- _debug2 _CACHED_NONCE "$_CACHED_NONCE"
|
|
|
else
|
|
|
_debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE"
|
|
|
fi
|
|
@@ -1958,12 +1970,16 @@ _setopt() {
|
|
|
_debug3 "$(grep -n "^$__opt$__sep" "$__conf")"
|
|
|
}
|
|
|
|
|
|
-#_save_conf file key value
|
|
|
+#_save_conf file key value base64encode
|
|
|
#save to conf
|
|
|
_save_conf() {
|
|
|
_s_c_f="$1"
|
|
|
_sdkey="$2"
|
|
|
_sdvalue="$3"
|
|
|
+ _b64encode="$4"
|
|
|
+ if [ "$_sdvalue" ] && [ "$_b64encode" ]; then
|
|
|
+ _sdvalue="${B64CONF_START}$(printf "%s" "${_sdvalue}" | _base64)${B64CONF_END}"
|
|
|
+ fi
|
|
|
if [ "$_s_c_f" ]; then
|
|
|
_setopt "$_s_c_f" "$_sdkey" "=" "'$_sdvalue'"
|
|
|
else
|
|
@@ -1988,19 +2004,20 @@ _read_conf() {
|
|
|
_r_c_f="$1"
|
|
|
_sdkey="$2"
|
|
|
if [ -f "$_r_c_f" ]; then
|
|
|
- (
|
|
|
- eval "$(grep "^$_sdkey *=" "$_r_c_f")"
|
|
|
- eval "printf \"%s\" \"\$$_sdkey\""
|
|
|
- )
|
|
|
+ _sdv="$(grep "^$_sdkey *=" "$_r_c_f" | cut -d = -f 2-1000 | tr -d "'")"
|
|
|
+ if _startswith "$_sdv" "${B64CONF_START}" && _endswith "$_sdv" "${B64CONF_END}"; then
|
|
|
+ _sdv="$(echo "$_sdv" | sed "s/${B64CONF_START}//" | sed "s/${B64CONF_END}//" | _dbase64)"
|
|
|
+ fi
|
|
|
+ printf "%s" "$_sdv"
|
|
|
else
|
|
|
_debug "config file is empty, can not read $_sdkey"
|
|
|
fi
|
|
|
}
|
|
|
|
|
|
-#_savedomainconf key value
|
|
|
+#_savedomainconf key value base64encode
|
|
|
#save to domain.conf
|
|
|
_savedomainconf() {
|
|
|
- _save_conf "$DOMAIN_CONF" "$1" "$2"
|
|
|
+ _save_conf "$DOMAIN_CONF" "$@"
|
|
|
}
|
|
|
|
|
|
#_cleardomainconf key
|
|
@@ -2013,14 +2030,14 @@ _readdomainconf() {
|
|
|
_read_conf "$DOMAIN_CONF" "$1"
|
|
|
}
|
|
|
|
|
|
-#_saveaccountconf key value
|
|
|
+#_saveaccountconf key value base64encode
|
|
|
_saveaccountconf() {
|
|
|
- _save_conf "$ACCOUNT_CONF_PATH" "$1" "$2"
|
|
|
+ _save_conf "$ACCOUNT_CONF_PATH" "$@"
|
|
|
}
|
|
|
|
|
|
-#key value
|
|
|
+#key value base64encode
|
|
|
_saveaccountconf_mutable() {
|
|
|
- _save_conf "$ACCOUNT_CONF_PATH" "SAVED_$1" "$2"
|
|
|
+ _save_conf "$ACCOUNT_CONF_PATH" "SAVED_$1" "$2" "$3"
|
|
|
#remove later
|
|
|
_clearaccountconf "$1"
|
|
|
}
|
|
@@ -2060,6 +2077,7 @@ _clearcaconf() {
|
|
|
_startserver() {
|
|
|
content="$1"
|
|
|
ncaddr="$2"
|
|
|
+ _debug "content" "$content"
|
|
|
_debug "ncaddr" "$ncaddr"
|
|
|
|
|
|
_debug "startserver: $$"
|
|
@@ -2086,8 +2104,14 @@ _startserver() {
|
|
|
SOCAT_OPTIONS="$SOCAT_OPTIONS,bind=${ncaddr}"
|
|
|
fi
|
|
|
|
|
|
+ _content_len="$(printf "%s" "$content" | wc -c)"
|
|
|
+ _debug _content_len "$_content_len"
|
|
|
_debug "_NC" "$_NC $SOCAT_OPTIONS"
|
|
|
- $_NC $SOCAT_OPTIONS SYSTEM:"sleep 1; echo HTTP/1.0 200 OK; echo ; echo $content; echo;" &
|
|
|
+ $_NC $SOCAT_OPTIONS SYSTEM:"sleep 1; \
|
|
|
+echo 'HTTP/1.0 200 OK'; \
|
|
|
+echo 'Content-Length\: $_content_len'; \
|
|
|
+echo ''; \
|
|
|
+printf -- '$content';" &
|
|
|
serverproc="$!"
|
|
|
}
|
|
|
|
|
@@ -3062,6 +3086,7 @@ _on_before_issue() {
|
|
|
_info "Standalone mode."
|
|
|
if [ -z "$Le_HTTPPort" ]; then
|
|
|
Le_HTTPPort=80
|
|
|
+ _cleardomainconf "Le_HTTPPort"
|
|
|
else
|
|
|
_savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
|
|
|
fi
|
|
@@ -3269,7 +3294,7 @@ _regAccount() {
|
|
|
fi
|
|
|
|
|
|
_debug2 responseHeaders "$responseHeaders"
|
|
|
- _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
|
|
|
+ _accUri="$(echo "$responseHeaders" | grep -i "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
|
|
|
_debug "_accUri" "$_accUri"
|
|
|
if [ -z "$_accUri" ]; then
|
|
|
_err "Can not find account id url."
|
|
@@ -3435,7 +3460,7 @@ __trigger_validation() {
|
|
|
_t_vtype="$3"
|
|
|
_debug2 _t_vtype "$_t_vtype"
|
|
|
if [ "$ACME_VERSION" = "2" ]; then
|
|
|
- _send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}"
|
|
|
+ _send_signed_request "$_t_url" "{}"
|
|
|
else
|
|
|
_send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"type\": \"$_t_vtype\", \"keyAuthorization\": \"$_t_key_authz\"}"
|
|
|
fi
|
|
@@ -3628,9 +3653,9 @@ issue() {
|
|
|
_savedomainconf "Le_Alt" "$_alt_domains"
|
|
|
_savedomainconf "Le_Webroot" "$_web_roots"
|
|
|
|
|
|
- _savedomainconf "Le_PreHook" "$_pre_hook"
|
|
|
- _savedomainconf "Le_PostHook" "$_post_hook"
|
|
|
- _savedomainconf "Le_RenewHook" "$_renew_hook"
|
|
|
+ _savedomainconf "Le_PreHook" "$_pre_hook" "base64"
|
|
|
+ _savedomainconf "Le_PostHook" "$_post_hook" "base64"
|
|
|
+ _savedomainconf "Le_RenewHook" "$_renew_hook" "base64"
|
|
|
|
|
|
if [ "$_local_addr" ]; then
|
|
|
_savedomainconf "Le_LocalAddress" "$_local_addr"
|
|
@@ -3643,8 +3668,12 @@ issue() {
|
|
|
_cleardomainconf "Le_ChallengeAlias"
|
|
|
fi
|
|
|
|
|
|
- Le_API="$ACME_DIRECTORY"
|
|
|
- _savedomainconf "Le_API" "$Le_API"
|
|
|
+ if [ "$ACME_DIRECTORY" != "$DEFAULT_CA" ]; then
|
|
|
+ Le_API="$ACME_DIRECTORY"
|
|
|
+ _savedomainconf "Le_API" "$Le_API"
|
|
|
+ else
|
|
|
+ _cleardomainconf Le_API
|
|
|
+ fi
|
|
|
|
|
|
if [ "$_alt_domains" = "$NO_VALUE" ]; then
|
|
|
_alt_domains=""
|
|
@@ -3722,7 +3751,7 @@ issue() {
|
|
|
return 1
|
|
|
fi
|
|
|
|
|
|
- Le_OrderFinalize="$(echo "$response" | tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)"
|
|
|
+ Le_OrderFinalize="$(echo "$response" | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)"
|
|
|
_debug Le_OrderFinalize "$Le_OrderFinalize"
|
|
|
if [ -z "$Le_OrderFinalize" ]; then
|
|
|
_err "Create new order error. Le_OrderFinalize not found. $response"
|
|
@@ -3734,7 +3763,7 @@ issue() {
|
|
|
#for dns manual mode
|
|
|
_savedomainconf "Le_OrderFinalize" "$Le_OrderFinalize"
|
|
|
|
|
|
- _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')"
|
|
|
+ _authorizations_seg="$(echo "$response" | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')"
|
|
|
_debug2 _authorizations_seg "$_authorizations_seg"
|
|
|
if [ -z "$_authorizations_seg" ]; then
|
|
|
_err "_authorizations_seg not found."
|
|
@@ -3820,7 +3849,7 @@ $_authorizations_map"
|
|
|
thumbprint="$(__calc_account_thumbprint)"
|
|
|
fi
|
|
|
|
|
|
- entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
|
|
|
+ entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
|
|
|
_debug entry "$entry"
|
|
|
if [ -z "$entry" ]; then
|
|
|
_err "Error, can not get domain token entry $d"
|
|
@@ -3832,7 +3861,7 @@ $_authorizations_map"
|
|
|
_on_issue_err "$_post_hook"
|
|
|
return 1
|
|
|
fi
|
|
|
- token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
|
|
|
+ token="$(echo "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
|
|
|
_debug token "$token"
|
|
|
|
|
|
if [ -z "$token" ]; then
|
|
@@ -3842,9 +3871,9 @@ $_authorizations_map"
|
|
|
return 1
|
|
|
fi
|
|
|
if [ "$ACME_VERSION" = "2" ]; then
|
|
|
- uri="$(printf "%s\n" "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)"
|
|
|
+ uri="$(echo "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)"
|
|
|
else
|
|
|
- uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)"
|
|
|
+ uri="$(echo "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)"
|
|
|
fi
|
|
|
_debug uri "$uri"
|
|
|
|
|
@@ -3902,21 +3931,21 @@ $_authorizations_map"
|
|
|
else
|
|
|
txtdomain="_acme-challenge.$_d_alias"
|
|
|
fi
|
|
|
- dns_entries="${dns_entries}${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$txtdomain$dvsep$_currentRoot"
|
|
|
+ dns_entry="${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$txtdomain$dvsep$_currentRoot"
|
|
|
else
|
|
|
txtdomain="_acme-challenge.$_dns_root_d"
|
|
|
- dns_entries="${dns_entries}${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$dvsep$_currentRoot"
|
|
|
+ dns_entry="${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$dvsep$_currentRoot"
|
|
|
fi
|
|
|
+
|
|
|
_debug txtdomain "$txtdomain"
|
|
|
txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)"
|
|
|
_debug txt "$txt"
|
|
|
|
|
|
d_api="$(_findHook "$_dns_root_d" dnsapi "$_currentRoot")"
|
|
|
-
|
|
|
_debug d_api "$d_api"
|
|
|
- dns_entries="$dns_entries$dvsep$txt${dvsep}$d_api
|
|
|
-"
|
|
|
- _debug2 "$dns_entries"
|
|
|
+
|
|
|
+ dns_entry="$dns_entry$dvsep$txt${dvsep}$d_api"
|
|
|
+ _debug2 dns_entry "$dns_entry"
|
|
|
if [ "$d_api" ]; then
|
|
|
_info "Found domain api file: $d_api"
|
|
|
else
|
|
@@ -3955,6 +3984,9 @@ $_authorizations_map"
|
|
|
_clearup
|
|
|
return 1
|
|
|
fi
|
|
|
+ dns_entries="$dns_entries$dns_entry
|
|
|
+"
|
|
|
+ _debug2 "$dns_entries"
|
|
|
dnsadded='1'
|
|
|
fi
|
|
|
done
|
|
@@ -4165,7 +4197,7 @@ $_authorizations_map"
|
|
|
fi
|
|
|
|
|
|
if [ "$status" = "invalid" ]; then
|
|
|
- error="$(echo "$response" | tr -d "\r\n" | _egrep_o '"error":\{[^\}]*')"
|
|
|
+ error="$(echo "$response" | _egrep_o '"error":\{[^\}]*')"
|
|
|
_debug2 error "$error"
|
|
|
errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)"
|
|
|
_debug2 errordetail "$errordetail"
|
|
@@ -4205,20 +4237,66 @@ $_authorizations_map"
|
|
|
der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)"
|
|
|
|
|
|
if [ "$ACME_VERSION" = "2" ]; then
|
|
|
+ _info "Lets finalize the order, Le_OrderFinalize: $Le_OrderFinalize"
|
|
|
if ! _send_signed_request "${Le_OrderFinalize}" "{\"csr\": \"$der\"}"; then
|
|
|
_err "Sign failed."
|
|
|
_on_issue_err "$_post_hook"
|
|
|
return 1
|
|
|
fi
|
|
|
if [ "$code" != "200" ]; then
|
|
|
- _err "Sign failed, code is not 200."
|
|
|
+ _err "Sign failed, finalize code is not 200."
|
|
|
_err "$response"
|
|
|
_on_issue_err "$_post_hook"
|
|
|
return 1
|
|
|
fi
|
|
|
- Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)"
|
|
|
+ Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
|
|
|
+ if [ -z "$Le_LinkOrder" ]; then
|
|
|
+ _err "Sign error, can not get order link location header"
|
|
|
+ _err "responseHeaders" "$responseHeaders"
|
|
|
+ _on_issue_err "$_post_hook"
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ _savedomainconf "Le_LinkOrder" "$Le_LinkOrder"
|
|
|
+
|
|
|
+ _link_cert_retry=0
|
|
|
+ _MAX_CERT_RETRY=5
|
|
|
+ while [ "$_link_cert_retry" -lt "$_MAX_CERT_RETRY" ]; do
|
|
|
+ if _contains "$response" "\"status\":\"valid\""; then
|
|
|
+ _debug "Order status is valid."
|
|
|
+ Le_LinkCert="$(echo "$response" | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)"
|
|
|
+ _debug Le_LinkCert "$Le_LinkCert"
|
|
|
+ if [ -z "$Le_LinkCert" ]; then
|
|
|
+ _err "Sign error, can not find Le_LinkCert"
|
|
|
+ _err "$response"
|
|
|
+ _on_issue_err "$_post_hook"
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ break
|
|
|
+ elif _contains "$response" "\"processing\""; then
|
|
|
+ _info "Order status is processing, lets sleep and retry."
|
|
|
+ _sleep 2
|
|
|
+ else
|
|
|
+ _err "Sign error, wrong status"
|
|
|
+ _err "$response"
|
|
|
+ _on_issue_err "$_post_hook"
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ if ! _send_signed_request "$Le_LinkOrder"; then
|
|
|
+ _err "Sign failed, can not post to Le_LinkOrder cert:$Le_LinkOrder."
|
|
|
+ _err "$response"
|
|
|
+ _on_issue_err "$_post_hook"
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ _link_cert_retry="$(_math $_link_cert_retry + 1)"
|
|
|
+ done
|
|
|
|
|
|
- _tempSignedResponse="$response"
|
|
|
+ if [ -z "$Le_LinkCert" ]; then
|
|
|
+ _err "Sign failed, can not get Le_LinkCert, retry time limit."
|
|
|
+ _err "$response"
|
|
|
+ _on_issue_err "$_post_hook"
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ _info "Download cert, Le_LinkCert: $Le_LinkCert"
|
|
|
if ! _send_signed_request "$Le_LinkCert"; then
|
|
|
_err "Sign failed, can not download cert:$Le_LinkCert."
|
|
|
_err "$response"
|
|
@@ -4237,7 +4315,7 @@ $_authorizations_map"
|
|
|
_end_n="$(_math $_end_n + 1)"
|
|
|
sed -n "${_end_n},9999p" "$CERT_FULLCHAIN_PATH" >"$CA_CERT_PATH"
|
|
|
fi
|
|
|
- response="$_tempSignedResponse"
|
|
|
+
|
|
|
else
|
|
|
if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
|
|
|
_err "Sign failed. $response"
|
|
@@ -4395,7 +4473,7 @@ $_authorizations_map"
|
|
|
_savedomainconf "Le_RealCertPath" "$_real_cert"
|
|
|
_savedomainconf "Le_RealCACertPath" "$_real_ca"
|
|
|
_savedomainconf "Le_RealKeyPath" "$_real_key"
|
|
|
- _savedomainconf "Le_ReloadCmd" "$_reload_cmd"
|
|
|
+ _savedomainconf "Le_ReloadCmd" "$_reload_cmd" "base64"
|
|
|
_savedomainconf "Le_RealFullChainPath" "$_real_fullchain"
|
|
|
if ! _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"; then
|
|
|
return 1
|
|
@@ -4432,6 +4510,16 @@ renew() {
|
|
|
|
|
|
. "$DOMAIN_CONF"
|
|
|
_debug Le_API "$Le_API"
|
|
|
+
|
|
|
+ if [ "$Le_API" = "$LETSENCRYPT_CA_V1" ]; then
|
|
|
+ _cleardomainconf Le_API
|
|
|
+ Le_API="$DEFAULT_CA"
|
|
|
+ fi
|
|
|
+ if [ "$Le_API" = "$LETSENCRYPT_STAGING_CA_V1" ]; then
|
|
|
+ _cleardomainconf Le_API
|
|
|
+ Le_API="$DEFAULT_STAGING_CA"
|
|
|
+ fi
|
|
|
+
|
|
|
if [ "$Le_API" ]; then
|
|
|
if [ "$_OLD_CA_HOST" = "$Le_API" ]; then
|
|
|
export Le_API="$DEFAULT_CA"
|
|
@@ -4462,6 +4550,10 @@ renew() {
|
|
|
fi
|
|
|
|
|
|
IS_RENEW="1"
|
|
|
+ Le_ReloadCmd="$(_readdomainconf Le_ReloadCmd)"
|
|
|
+ Le_PreHook="$(_readdomainconf Le_PreHook)"
|
|
|
+ Le_PostHook="$(_readdomainconf Le_PostHook)"
|
|
|
+ Le_RenewHook="$(_readdomainconf Le_RenewHook)"
|
|
|
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"
|
|
|
res="$?"
|
|
|
if [ "$res" != "0" ]; then
|
|
@@ -4742,7 +4834,7 @@ installcert() {
|
|
|
_savedomainconf "Le_RealCertPath" "$_real_cert"
|
|
|
_savedomainconf "Le_RealCACertPath" "$_real_ca"
|
|
|
_savedomainconf "Le_RealKeyPath" "$_real_key"
|
|
|
- _savedomainconf "Le_ReloadCmd" "$_reload_cmd"
|
|
|
+ _savedomainconf "Le_ReloadCmd" "$_reload_cmd" "base64"
|
|
|
_savedomainconf "Le_RealFullChainPath" "$_real_fullchain"
|
|
|
|
|
|
_installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"
|
|
@@ -4826,7 +4918,7 @@ _installcert() {
|
|
|
export CERT_KEY_PATH
|
|
|
export CA_CERT_PATH
|
|
|
export CERT_FULLCHAIN_PATH
|
|
|
- export Le_Domain
|
|
|
+ export Le_Domain="$_main_domain"
|
|
|
cd "$DOMAIN_PATH" && eval "$_reload_cmd"
|
|
|
); then
|
|
|
_info "$(__green "Reload success")"
|
|
@@ -4837,35 +4929,107 @@ _installcert() {
|
|
|
|
|
|
}
|
|
|
|
|
|
+__read_password() {
|
|
|
+ unset _pp
|
|
|
+ prompt="Enter Password:"
|
|
|
+ while IFS= read -p "$prompt" -r -s -n 1 char; do
|
|
|
+ if [ "$char" = $'\0' ]; then
|
|
|
+ break
|
|
|
+ fi
|
|
|
+ prompt='*'
|
|
|
+ _pp="$_pp$char"
|
|
|
+ done
|
|
|
+ echo "$_pp"
|
|
|
+}
|
|
|
+
|
|
|
+_install_win_taskscheduler() {
|
|
|
+ _lesh="$1"
|
|
|
+ _centry="$2"
|
|
|
+ _randomminute="$3"
|
|
|
+ if ! _exists cygpath; then
|
|
|
+ _err "cygpath not found"
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ if ! _exists schtasks; then
|
|
|
+ _err "schtasks.exe is not found, are you on Windows?"
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ _winbash="$(cygpath -w $(which bash))"
|
|
|
+ _debug _winbash "$_winbash"
|
|
|
+ if [ -z "$_winbash" ]; then
|
|
|
+ _err "can not find bash path"
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ _myname="$(whoami)"
|
|
|
+ _debug "_myname" "$_myname"
|
|
|
+ if [ -z "$_myname" ]; then
|
|
|
+ _err "can not find my user name"
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ _debug "_lesh" "$_lesh"
|
|
|
+
|
|
|
+ _info "To install scheduler task in your Windows account, you must input your windows password."
|
|
|
+ _info "$PROJECT_NAME doesn't save your password."
|
|
|
+ _info "Please input your Windows password for: $(__green "$_myname")"
|
|
|
+ _password="$(__read_password)"
|
|
|
+ #SCHTASKS.exe '/create' '/SC' 'DAILY' '/TN' "$_WINDOWS_SCHEDULER_NAME" '/F' '/ST' "00:$_randomminute" '/RU' "$_myname" '/RP' "$_password" '/TR' "$_winbash -l -c '$_lesh --cron --home \"$LE_WORKING_DIR\" $_centry'" >/dev/null
|
|
|
+ echo SCHTASKS.exe '/create' '/SC' 'DAILY' '/TN' "$_WINDOWS_SCHEDULER_NAME" '/F' '/ST' "00:$_randomminute" '/RU' "$_myname" '/RP' "$_password" '/TR' "\"$_winbash -l -c '$_lesh --cron --home \"$LE_WORKING_DIR\" $_centry'\"" | cmd.exe >/dev/null
|
|
|
+ echo
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+_uninstall_win_taskscheduler() {
|
|
|
+ if ! _exists schtasks; then
|
|
|
+ _err "schtasks.exe is not found, are you on Windows?"
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ if ! echo SCHTASKS /query /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null; then
|
|
|
+ _debug "scheduler $_WINDOWS_SCHEDULER_NAME is not found."
|
|
|
+ else
|
|
|
+ _info "Removing $_WINDOWS_SCHEDULER_NAME"
|
|
|
+ echo SCHTASKS /delete /f /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
#confighome
|
|
|
installcronjob() {
|
|
|
_c_home="$1"
|
|
|
_initpath
|
|
|
_CRONTAB="crontab"
|
|
|
+ if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then
|
|
|
+ lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY"
|
|
|
+ else
|
|
|
+ _err "Can not install cronjob, $PROJECT_ENTRY not found."
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ if [ "$_c_home" ]; then
|
|
|
+ _c_entry="--config-home \"$_c_home\" "
|
|
|
+ fi
|
|
|
+ _t=$(_time)
|
|
|
+ random_minute=$(_math $_t % 60)
|
|
|
+
|
|
|
if ! _exists "$_CRONTAB" && _exists "fcrontab"; then
|
|
|
_CRONTAB="fcrontab"
|
|
|
fi
|
|
|
+
|
|
|
if ! _exists "$_CRONTAB"; then
|
|
|
+ if _exists cygpath && _exists schtasks.exe; then
|
|
|
+ _info "It seems you are on Windows, let's install Windows scheduler task."
|
|
|
+ if _install_win_taskscheduler "$lesh" "$_c_entry" "$random_minute"; then
|
|
|
+ _info "Install Windows scheduler task success."
|
|
|
+ return 0
|
|
|
+ else
|
|
|
+ _err "Install Windows scheduler task failed."
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ fi
|
|
|
_err "crontab/fcrontab doesn't exist, so, we can not install cron jobs."
|
|
|
_err "All your certs will not be renewed automatically."
|
|
|
_err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday."
|
|
|
return 1
|
|
|
fi
|
|
|
-
|
|
|
_info "Installing cron job"
|
|
|
if ! $_CRONTAB -l | grep "$PROJECT_ENTRY --cron"; then
|
|
|
- if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then
|
|
|
- lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY"
|
|
|
- else
|
|
|
- _err "Can not install cronjob, $PROJECT_ENTRY not found."
|
|
|
- return 1
|
|
|
- fi
|
|
|
-
|
|
|
- if [ "$_c_home" ]; then
|
|
|
- _c_entry="--config-home \"$_c_home\" "
|
|
|
- fi
|
|
|
- _t=$(_time)
|
|
|
- random_minute=$(_math $_t % 60)
|
|
|
if _exists uname && uname -a | grep SunOS >/dev/null; then
|
|
|
$_CRONTAB -l | {
|
|
|
cat
|
|
@@ -4893,6 +5057,16 @@ uninstallcronjob() {
|
|
|
fi
|
|
|
|
|
|
if ! _exists "$_CRONTAB"; then
|
|
|
+ if _exists cygpath && _exists schtasks.exe; then
|
|
|
+ _info "It seems you are on Windows, let's uninstall Windows scheduler task."
|
|
|
+ if _uninstall_win_taskscheduler; then
|
|
|
+ _info "Uninstall Windows scheduler task success."
|
|
|
+ return 0
|
|
|
+ else
|
|
|
+ _err "Uninstall Windows scheduler task failed."
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
+ fi
|
|
|
return
|
|
|
fi
|
|
|
_info "Removing cron job"
|
|
@@ -5024,7 +5198,7 @@ _deactivate() {
|
|
|
_err "Can not get domain new order."
|
|
|
return 1
|
|
|
fi
|
|
|
- _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')"
|
|
|
+ _authorizations_seg="$(echo "$response" | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')"
|
|
|
_debug2 _authorizations_seg "$_authorizations_seg"
|
|
|
if [ -z "$_authorizations_seg" ]; then
|
|
|
_err "_authorizations_seg not found."
|
|
@@ -5070,16 +5244,16 @@ _deactivate() {
|
|
|
fi
|
|
|
_debug "Trigger validation."
|
|
|
vtype="$VTYPE_DNS"
|
|
|
- entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
|
|
|
+ entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
|
|
|
_debug entry "$entry"
|
|
|
if [ -z "$entry" ]; then
|
|
|
_err "Error, can not get domain token $d"
|
|
|
return 1
|
|
|
fi
|
|
|
- token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
|
|
|
+ token="$(echo "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
|
|
|
_debug token "$token"
|
|
|
|
|
|
- uri="$(printf "%s\n" "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')"
|
|
|
+ uri="$(echo "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')"
|
|
|
_debug uri "$uri"
|
|
|
|
|
|
keyauthorization="$token.$thumbprint"
|
|
@@ -5101,11 +5275,11 @@ _deactivate() {
|
|
|
break
|
|
|
fi
|
|
|
|
|
|
- _vtype="$(printf "%s\n" "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')"
|
|
|
+ _vtype="$(echo "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')"
|
|
|
_debug _vtype "$_vtype"
|
|
|
_info "Found $_vtype"
|
|
|
|
|
|
- uri="$(printf "%s\n" "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')"
|
|
|
+ uri="$(echo "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')"
|
|
|
_debug uri "$uri"
|
|
|
|
|
|
if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then
|
|
@@ -5220,13 +5394,17 @@ _precheck() {
|
|
|
|
|
|
if [ -z "$_nocron" ]; then
|
|
|
if ! _exists "crontab" && ! _exists "fcrontab"; then
|
|
|
- _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'."
|
|
|
- _err "We need to set cron job to renew the certs automatically."
|
|
|
- _err "Otherwise, your certs will not be able to be renewed automatically."
|
|
|
- if [ -z "$FORCE" ]; then
|
|
|
- _err "Please add '--force' and try install again to go without crontab."
|
|
|
- _err "./$PROJECT_ENTRY --install --force"
|
|
|
- return 1
|
|
|
+ if _exists cygpath && _exists schtasks.exe; then
|
|
|
+ _info "It seems you are on Windows, we will install Windows scheduler task."
|
|
|
+ else
|
|
|
+ _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'."
|
|
|
+ _err "We need to set cron job to renew the certs automatically."
|
|
|
+ _err "Otherwise, your certs will not be able to be renewed automatically."
|
|
|
+ if [ -z "$FORCE" ]; then
|
|
|
+ _err "Please add '--force' and try install again to go without crontab."
|
|
|
+ _err "./$PROJECT_ENTRY --install --force"
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
fi
|
|
|
fi
|
|
|
fi
|