acme.sh/acme.sh

7450 lines
201 KiB
Bash
Raw Normal View History

#!/usr/bin/env sh
2016-04-25 14:01:37 +02:00
2020-05-04 02:43:47 +02:00
VER=2.8.7
2016-04-13 14:37:18 +02:00
2016-04-14 15:44:26 +02:00
PROJECT_NAME="acme.sh"
2016-04-13 14:37:18 +02:00
2016-04-14 15:44:26 +02:00
PROJECT_ENTRY="acme.sh"
2020-01-30 03:50:39 +01:00
PROJECT="https://github.com/acmesh-official/$PROJECT_NAME"
2016-03-08 13:44:12 +01:00
DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME"
_WINDOWS_SCHEDULER_NAME="$PROJECT_NAME.cron"
_SCRIPT_="$0"
_SUB_FOLDER_NOTIFY="notify"
_SUB_FOLDER_DNSAPI="dnsapi"
_SUB_FOLDER_DEPLOY="deploy"
_SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY"
2018-01-06 05:45:24 +01:00
LETSENCRYPT_CA_V1="https://acme-v01.api.letsencrypt.org/directory"
LETSENCRYPT_STAGING_CA_V1="https://acme-staging.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"
2018-01-06 05:45:24 +01:00
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="http://api.zerossl.com/acme/eab-credentials-email"
DEFAULT_CA=$CA_LETSENCRYPT_V2
DEFAULT_STAGING_CA=$CA_LETSENCRYPT_V2_TEST
CA_NAMES="
Letsencrypt.org,letsencrypt
Letsencrypt.org_test,letsencrypt_test,letsencrypttest
BuyPass.com,buypass
BuyPass.com_test,buypass_test,buypasstest
ZeroSSL.com,zerossl
"
CA_SERVERS="$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_BUYPASS,$CA_BUYPASS_TEST,$CA_ZEROSSL"
2016-11-13 14:47:58 +01:00
DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
2016-03-19 15:04:03 +01:00
DEFAULT_ACCOUNT_KEY_LENGTH=2048
DEFAULT_DOMAIN_KEY_LENGTH=2048
DEFAULT_OPENSSL_BIN="openssl"
2016-03-08 13:44:12 +01:00
VTYPE_HTTP="http-01"
VTYPE_DNS="dns-01"
VTYPE_ALPN="tls-alpn-01"
LOCAL_ANY_ADDRESS="0.0.0.0"
DEFAULT_RENEW=60
2016-06-26 04:09:51 +02:00
2016-09-23 16:35:13 +02:00
NO_VALUE="no"
W_DNS="dns"
W_ALPN="alpn"
2018-02-12 14:49:22 +01:00
DNS_ALIAS_PREFIX="="
2016-03-08 13:44:12 +01:00
2017-02-06 13:42:54 +01:00
MODE_STATELESS="stateless"
STATE_VERIFIED="verified_ok"
2017-02-13 16:29:37 +01:00
NGINX="nginx:"
NGINX_START="#ACME_NGINX_START"
NGINX_END="#ACME_NGINX_END"
2017-02-13 16:29:37 +01:00
2016-03-17 14:18:09 +01:00
BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----"
END_CSR="-----END CERTIFICATE REQUEST-----"
BEGIN_CERT="-----BEGIN CERTIFICATE-----"
END_CERT="-----END CERTIFICATE-----"
CONTENT_TYPE_JSON="application/jose+json"
2016-06-18 05:29:28 +02:00
RENEW_SKIP=2
B64CONF_START="__ACME_BASE64__START_"
B64CONF_END="__ACME_BASE64__END_"
ECC_SEP="_"
ECC_SUFFIX="${ECC_SEP}ecc"
2016-09-25 15:58:59 +02:00
LOG_LEVEL_1=1
LOG_LEVEL_2=2
LOG_LEVEL_3=3
DEFAULT_LOG_LEVEL="$LOG_LEVEL_1"
2017-02-19 05:13:18 +01:00
DEBUG_LEVEL_1=1
DEBUG_LEVEL_2=2
DEBUG_LEVEL_3=3
DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1
DEBUG_LEVEL_NONE=0
2019-10-03 14:37:46 +02:00
DOH_CLOUDFLARE=1
DOH_GOOGLE=2
2017-02-19 06:24:00 +01:00
HIDDEN_VALUE="[hidden](please add '--output-insecure' to see this value)"
2017-02-11 14:15:36 +01:00
SYSLOG_ERROR="user.error"
2017-02-19 05:13:18 +01:00
SYSLOG_INFO="user.info"
2017-02-11 14:15:36 +01:00
SYSLOG_DEBUG="user.debug"
2017-02-19 05:13:18 +01:00
#error
2017-02-19 05:42:37 +01:00
SYSLOG_LEVEL_ERROR=3
2017-02-19 05:13:18 +01:00
#info
2017-02-19 05:42:37 +01:00
SYSLOG_LEVEL_INFO=6
2017-02-19 05:13:18 +01:00
#debug
2017-02-19 05:42:37 +01:00
SYSLOG_LEVEL_DEBUG=7
2017-02-19 05:13:18 +01:00
#debug2
2017-02-19 05:42:37 +01:00
SYSLOG_LEVEL_DEBUG_2=8
2017-02-19 05:13:18 +01:00
#debug3
2017-02-19 05:42:37 +01:00
SYSLOG_LEVEL_DEBUG_3=9
2017-02-19 05:13:18 +01:00
2017-02-19 05:42:37 +01:00
SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_ERROR
2017-02-19 05:13:18 +01:00
#none
SYSLOG_LEVEL_NONE=0
NOTIFY_LEVEL_DISABLE=0
NOTIFY_LEVEL_ERROR=1
NOTIFY_LEVEL_RENEW=2
NOTIFY_LEVEL_SKIP=3
NOTIFY_LEVEL_DEFAULT=$NOTIFY_LEVEL_RENEW
NOTIFY_MODE_BULK=0
NOTIFY_MODE_CERT=1
NOTIFY_MODE_DEFAULT=$NOTIFY_MODE_BULK
2020-01-30 03:50:39 +01:00
_DEBUG_WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh"
2016-03-08 13:44:12 +01:00
2020-01-30 03:50:39 +01:00
_PREPARE_LINK="https://github.com/acmesh-official/acme.sh/wiki/Install-preparations"
2020-01-30 03:50:39 +01:00
_STATELESS_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Stateless-Mode"
2017-02-06 13:42:54 +01:00
2020-01-30 03:50:39 +01:00
_DNS_ALIAS_WIKI="https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode"
2018-02-10 03:45:29 +01:00
2020-01-30 03:50:39 +01:00
_DNS_MANUAL_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dns-manual-mode"
_DNS_API_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dnsapi"
2020-01-30 03:50:39 +01:00
_NOTIFY_WIKI="https://github.com/acmesh-official/acme.sh/wiki/notify"
2020-01-30 03:50:39 +01:00
_SUDO_WIKI="https://github.com/acmesh-official/acme.sh/wiki/sudo"
2019-08-11 08:07:36 +02:00
_REVOKE_WIKI="https://github.com/acmesh-official/acme.sh/wiki/revokecert"
_ZEROSSL_WIKI="https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA"
2020-08-12 15:17:15 +02:00
_SERVER_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Server"
_PREFERRED_CHAIN_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Preferred-Chain"
2017-08-22 14:27:13 +02:00
_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"
_DNS_MANUAL_ERROR="It seems that you are using dns manual mode. Read this link first: $_DNS_MANUAL_WIKI"
2016-09-06 13:37:41 +02:00
__INTERACTIVE=""
2016-11-09 12:30:39 +01:00
if [ -t 1 ]; then
2016-09-06 13:37:41 +02:00
__INTERACTIVE="1"
fi
2016-04-17 11:33:08 +02:00
__green() {
if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then
2019-10-27 04:43:40 +01:00
printf '\33[1;32m%b\33[0m' "$1"
return
2016-09-02 14:55:11 +02:00
fi
printf -- "%b" "$1"
}
__red() {
if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then
2019-10-27 04:43:40 +01:00
printf '\33[1;31m%b\33[0m' "$1"
return
2016-09-02 14:55:11 +02:00
fi
printf -- "%b" "$1"
}
2016-04-17 11:33:08 +02:00
2016-09-25 15:58:59 +02:00
_printargs() {
2018-03-14 09:52:58 +01:00
_exitstatus="$?"
if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then
printf -- "%s" "[$(date)] "
fi
2016-11-09 12:30:39 +01:00
if [ -z "$2" ]; then
printf -- "%s" "$1"
else
printf -- "%s" "$1='$2'"
fi
2016-09-25 15:58:59 +02:00
printf "\n"
# return the saved exit status
return "$_exitstatus"
}
2016-11-04 15:03:41 +01:00
_dlg_versions() {
echo "Diagnosis versions: "
2017-02-25 12:08:00 +01:00
echo "openssl:$ACME_OPENSSL_BIN"
2017-03-30 15:16:25 +02:00
if _exists "${ACME_OPENSSL_BIN:-openssl}"; then
${ACME_OPENSSL_BIN:-openssl} version 2>&1
2016-11-04 15:03:41 +01:00
else
echo "$ACME_OPENSSL_BIN doesn't exist."
2016-11-04 15:03:41 +01:00
fi
2016-11-09 12:30:39 +01:00
2016-11-04 15:03:41 +01:00
echo "apache:"
2016-11-09 12:30:39 +01:00
if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then
2017-03-03 15:03:19 +01:00
$_APACHECTL -V 2>&1
2016-11-04 15:03:41 +01:00
else
echo "apache doesn't exist."
2016-11-04 15:03:41 +01:00
fi
2016-11-09 12:30:39 +01:00
2017-06-15 15:44:10 +02:00
echo "nginx:"
if _exists "nginx"; then
nginx -V 2>&1
else
echo "nginx doesn't exist."
2017-06-15 15:44:10 +02:00
fi
echo "socat:"
if _exists "socat"; then
socat -V 2>&1
2016-11-04 15:03:41 +01:00
else
_debug "socat doesn't exist."
2016-11-04 15:03:41 +01:00
fi
}
2017-02-11 14:15:36 +01:00
#class
_syslog() {
2018-03-14 09:52:58 +01:00
_exitstatus="$?"
2017-02-19 05:13:18 +01:00
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" = "$SYSLOG_LEVEL_NONE" ]; then
2017-02-11 14:15:36 +01:00
return
fi
_logclass="$1"
shift
if [ -z "$__logger_i" ]; then
if _contains "$(logger --help 2>&1)" "-i"; then
__logger_i="logger -i"
else
__logger_i="logger"
fi
fi
$__logger_i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1
2018-03-14 09:52:58 +01:00
return "$_exitstatus"
2017-02-11 14:15:36 +01:00
}
2016-09-25 15:58:59 +02:00
_log() {
[ -z "$LOG_FILE" ] && return
2016-11-09 13:45:57 +01:00
_printargs "$@" >>"$LOG_FILE"
2016-09-25 15:58:59 +02:00
}
_info() {
2017-02-19 05:13:18 +01:00
_log "$@"
2017-02-19 05:42:37 +01:00
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_INFO" ]; then
2017-02-19 05:13:18 +01:00
_syslog "$SYSLOG_INFO" "$@"
fi
2016-09-25 15:58:59 +02:00
_printargs "$@"
2016-03-08 13:44:12 +01:00
}
_err() {
2017-02-19 05:13:18 +01:00
_syslog "$SYSLOG_ERROR" "$@"
_log "$@"
if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then
printf -- "%s" "[$(date)] " >&2
fi
2016-11-09 12:30:39 +01:00
if [ -z "$2" ]; then
2016-09-28 07:13:08 +02:00
__red "$1" >&2
else
__red "$1='$2'" >&2
fi
2016-09-27 15:27:43 +02:00
printf "\n" >&2
2016-03-08 13:44:12 +01:00
return 1
}
_usage() {
2016-11-09 12:30:39 +01:00
__red "$@" >&2
2016-09-28 07:13:08 +02:00
printf "\n" >&2
}
__debug_bash_helper() {
# At this point only do for --debug 3
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -lt "$DEBUG_LEVEL_3" ]; then
return
fi
# Return extra debug info when running with bash, otherwise return empty
# string.
if [ -z "${BASH_VERSION}" ]; then
return
fi
# We are a bash shell at this point, return the filename, function name, and
# line number as a string
_dbh_saveIFS=$IFS
IFS=" "
# Must use eval or syntax error happens under dash. The eval should use
# single quotes as older versions of busybox had a bug with double quotes and
# eval.
# Use 'caller 1' as we want one level up the stack as we should be called
# by one of the _debug* functions
eval '_dbh_called=($(caller 1))'
IFS=$_dbh_saveIFS
eval '_dbh_file=${_dbh_called[2]}'
if [ -n "${_script_home}" ]; then
# Trim off the _script_home directory name
eval '_dbh_file=${_dbh_file#$_script_home/}'
fi
eval '_dbh_function=${_dbh_called[1]}'
eval '_dbh_lineno=${_dbh_called[0]}'
printf "%-40s " "$_dbh_file:${_dbh_function}:${_dbh_lineno}"
}
_debug() {
2017-02-19 05:13:18 +01:00
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then
_log "$@"
2016-09-25 15:58:59 +02:00
fi
2017-02-19 05:42:37 +01:00
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then
2017-02-19 05:13:18 +01:00
_syslog "$SYSLOG_DEBUG" "$@"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then
_bash_debug=$(__debug_bash_helper)
_printargs "${_bash_debug}$@" >&2
fi
}
2017-02-19 06:24:00 +01:00
#output the sensitive messages
_secure_debug() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_log "$@"
else
_log "$1" "$HIDDEN_VALUE"
fi
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then
_syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_printargs "$@" >&2
else
_printargs "$1" "$HIDDEN_VALUE" >&2
fi
fi
}
_debug2() {
2017-02-19 05:13:18 +01:00
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then
_log "$@"
2016-09-25 15:58:59 +02:00
fi
2017-02-19 05:42:37 +01:00
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then
2017-02-19 05:13:18 +01:00
_syslog "$SYSLOG_DEBUG" "$@"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then
_bash_debug=$(__debug_bash_helper)
_printargs "${_bash_debug}$@" >&2
fi
}
2017-02-19 06:24:00 +01:00
_secure_debug2() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_log "$@"
else
_log "$1" "$HIDDEN_VALUE"
fi
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then
_syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_printargs "$@" >&2
else
_printargs "$1" "$HIDDEN_VALUE" >&2
fi
fi
}
_debug3() {
2017-02-19 05:13:18 +01:00
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then
_log "$@"
fi
2017-02-19 05:42:37 +01:00
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then
2017-02-19 05:13:18 +01:00
_syslog "$SYSLOG_DEBUG" "$@"
2016-09-25 15:58:59 +02:00
fi
2017-02-19 05:13:18 +01:00
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then
_bash_debug=$(__debug_bash_helper)
_printargs "${_bash_debug}$@" >&2
fi
}
2017-02-19 06:24:00 +01:00
_secure_debug3() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_log "$@"
else
_log "$1" "$HIDDEN_VALUE"
fi
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then
_syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_printargs "$@" >&2
else
_printargs "$1" "$HIDDEN_VALUE" >&2
fi
fi
}
2017-03-08 14:51:25 +01:00
_upper_case() {
# shellcheck disable=SC2018,SC2019
tr 'a-z' 'A-Z'
}
_lower_case() {
# shellcheck disable=SC2018,SC2019
tr 'A-Z' 'a-z'
}
2016-11-09 12:30:39 +01:00
_startswith() {
2016-04-16 15:52:24 +02:00
_str="$1"
_sub="$2"
2016-05-13 15:14:00 +02:00
echo "$_str" | grep "^$_sub" >/dev/null 2>&1
2016-04-16 15:52:24 +02:00
}
2016-11-09 12:30:39 +01:00
_endswith() {
_str="$1"
_sub="$2"
echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1
}
2016-11-09 12:30:39 +01:00
_contains() {
2016-04-16 15:52:24 +02:00
_str="$1"
_sub="$2"
echo "$_str" | grep -- "$_sub" >/dev/null 2>&1
2016-04-16 15:52:24 +02:00
}
_hasfield() {
_str="$1"
_field="$2"
_sep="$3"
2016-11-09 12:30:39 +01:00
if [ -z "$_field" ]; then
_usage "Usage: str field [sep]"
return 1
fi
2016-11-09 12:30:39 +01:00
if [ -z "$_sep" ]; then
_sep=","
fi
2016-11-09 12:30:39 +01:00
for f in $(echo "$_str" | tr "$_sep" ' '); do
2016-11-09 12:30:39 +01:00
if [ "$f" = "$_field" ]; then
_debug2 "'$_str' contains '$_field'"
return 0 #contains ok
fi
done
_debug2 "'$_str' does not contain '$_field'"
2017-04-17 13:08:34 +02:00
return 1 #not contains
}
# str index [sep]
2016-11-09 12:30:39 +01:00
_getfield() {
_str="$1"
_findex="$2"
_sep="$3"
2016-11-09 12:30:39 +01:00
if [ -z "$_findex" ]; then
_usage "Usage: str field [sep]"
return 1
fi
2016-11-09 12:30:39 +01:00
if [ -z "$_sep" ]; then
_sep=","
fi
2016-11-09 15:28:12 +01:00
_ffi="$_findex"
2016-11-09 12:30:39 +01:00
while [ "$_ffi" -gt "0" ]; do
2016-11-09 15:28:12 +01:00
_fv="$(echo "$_str" | cut -d "$_sep" -f "$_ffi")"
2016-11-09 12:30:39 +01:00
if [ "$_fv" ]; then
printf -- "%s" "$_fv"
return 0
fi
2016-11-09 13:45:57 +01:00
_ffi="$(_math "$_ffi" - 1)"
done
2016-11-09 12:30:39 +01:00
printf -- "%s" "$_str"
}
2016-11-09 12:30:39 +01:00
_exists() {
cmd="$1"
2016-11-09 12:30:39 +01:00
if [ -z "$cmd" ]; then
_usage "Usage: _exists cmd"
return 1
fi
2016-11-17 06:17:29 +01:00
if eval type type >/dev/null 2>&1; then
eval type "$cmd" >/dev/null 2>&1
elif command >/dev/null 2>&1; then
2016-05-13 15:14:00 +02:00
command -v "$cmd" >/dev/null 2>&1
2016-11-17 06:20:20 +01:00
else
2016-11-11 14:13:33 +01:00
which "$cmd" >/dev/null 2>&1
2016-04-16 13:38:11 +02:00
fi
ret="$?"
_debug3 "$cmd exists=$ret"
return $ret
}
2016-04-17 11:33:08 +02:00
#a + b
2016-11-09 12:30:39 +01:00
_math() {
2016-11-12 03:58:20 +01:00
_m_opts="$@"
printf "%s" "$(($_m_opts))"
2016-04-17 11:33:08 +02:00
}
_h_char_2_dec() {
_ch=$1
case "${_ch}" in
2020-08-17 16:18:20 +02:00
a | A)
printf "10"
;;
b | B)
printf "11"
;;
c | C)
printf "12"
;;
d | D)
printf "13"
;;
e | E)
printf "14"
;;
f | F)
printf "15"
;;
*)
printf "%s" "$_ch"
;;
2016-05-13 15:14:00 +02:00
esac
2016-04-17 11:33:08 +02:00
}
2016-08-14 16:37:21 +02:00
_URGLY_PRINTF=""
2016-11-09 12:30:39 +01:00
if [ "$(printf '\x41')" != 'A' ]; then
2016-08-14 16:37:21 +02:00
_URGLY_PRINTF=1
fi
_ESCAPE_XARGS=""
2017-06-23 12:11:11 +02:00
if _exists xargs && [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then
_ESCAPE_XARGS=1
fi
2016-03-08 13:44:12 +01:00
_h2b() {
if _exists xxd && xxd -r -p 2>/dev/null; then
2017-05-17 07:16:53 +02:00
return
fi
2016-03-08 13:44:12 +01:00
hex=$(cat)
2017-05-20 05:02:48 +02:00
ic=""
jc=""
2017-05-17 07:16:53 +02:00
_debug2 _URGLY_PRINTF "$_URGLY_PRINTF"
if [ -z "$_URGLY_PRINTF" ]; then
if [ "$_ESCAPE_XARGS" ] && _exists xargs; then
2017-05-20 05:02:48 +02:00
_debug2 "xargs"
echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf
2017-05-20 05:02:48 +02:00
else
for h in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/ \1/g'); do
2017-05-20 05:02:48 +02:00
if [ -z "$h" ]; then
break
fi
printf "\x$h%s"
done
fi
2017-05-17 07:16:53 +02:00
else
for c in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\)/ \1/g'); do
2017-05-20 05:02:48 +02:00
if [ -z "$ic" ]; then
ic=$c
continue
2016-04-17 11:33:08 +02:00
fi
2017-05-20 05:02:48 +02:00
jc=$c
2016-05-13 15:14:00 +02:00
ic="$(_h_char_2_dec "$ic")"
jc="$(_h_char_2_dec "$jc")"
2016-11-11 15:00:15 +01:00
printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s"
2017-05-20 05:02:48 +02:00
ic=""
jc=""
2017-05-17 07:16:53 +02:00
done
fi
2016-11-11 14:13:33 +01:00
2016-03-08 13:44:12 +01:00
}
2017-01-30 05:07:50 +01:00
_is_solaris() {
_contains "${__OS__:=$(uname -a)}" "solaris" || _contains "${__OS__:=$(uname -a)}" "SunOS"
}
2017-02-05 06:16:51 +01:00
#_ascii_hex str
#this can only process ascii chars, should only be used when od command is missing as a backup way.
_ascii_hex() {
_debug2 "Using _ascii_hex"
_str="$1"
_str_len=${#_str}
_h_i=1
while [ "$_h_i" -le "$_str_len" ]; do
_str_c="$(printf "%s" "$_str" | cut -c "$_h_i")"
printf " %02x" "'$_str_c"
_h_i="$(_math "$_h_i" + 1)"
done
}
2017-01-30 05:07:50 +01:00
#stdin output hexstr splited by one space
#input:"abc"
#output: " 61 62 63"
_hex_dump() {
if _exists od; then
od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n"
elif _exists hexdump; then
_debug3 "using hexdump"
hexdump -v -e '/1 ""' -e '/1 " %02x" ""'
elif _exists xxd; then
_debug3 "using xxd"
xxd -ps -c 20 -i | sed "s/ 0x/ /g" | tr -d ",\n" | tr -s " "
else
_debug3 "using _ascii_hex"
2017-02-05 06:16:51 +01:00
str=$(cat)
_ascii_hex "$str"
fi
2017-01-30 05:07:50 +01:00
}
#url encode, no-preserved chars
#A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
#41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a
#a b c d e f g h i j k l m n o p q r s t u v w x y z
#61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a
#0 1 2 3 4 5 6 7 8 9 - _ . ~
#30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e
#stdin stdout
_url_encode() {
_hex_str=$(_hex_dump)
_debug3 "_url_encode"
_debug3 "_hex_str" "$_hex_str"
for _hex_code in $_hex_str; do
#upper case
case "${_hex_code}" in
2020-08-17 16:18:20 +02:00
"41")
printf "%s" "A"
;;
"42")
printf "%s" "B"
;;
"43")
printf "%s" "C"
;;
"44")
printf "%s" "D"
;;
"45")
printf "%s" "E"
;;
"46")
printf "%s" "F"
;;
"47")
printf "%s" "G"
;;
"48")
printf "%s" "H"
;;
"49")
printf "%s" "I"
;;
"4a")
printf "%s" "J"
;;
"4b")
printf "%s" "K"
;;
"4c")
printf "%s" "L"
;;
"4d")
printf "%s" "M"
;;
"4e")
printf "%s" "N"
;;
"4f")
printf "%s" "O"
;;
"50")
printf "%s" "P"
;;
"51")
printf "%s" "Q"
;;
"52")
printf "%s" "R"
;;
"53")
printf "%s" "S"
;;
"54")
printf "%s" "T"
;;
"55")
printf "%s" "U"
;;
"56")
printf "%s" "V"
;;
"57")
printf "%s" "W"
;;
"58")
printf "%s" "X"
;;
"59")
printf "%s" "Y"
;;
"5a")
printf "%s" "Z"
;;
2017-01-30 05:25:56 +01:00
#lower case
2020-08-17 16:18:20 +02:00
"61")
printf "%s" "a"
;;
"62")
printf "%s" "b"
;;
"63")
printf "%s" "c"
;;
"64")
printf "%s" "d"
;;
"65")
printf "%s" "e"
;;
"66")
printf "%s" "f"
;;
"67")
printf "%s" "g"
;;
"68")
printf "%s" "h"
;;
"69")
printf "%s" "i"
;;
"6a")
printf "%s" "j"
;;
"6b")
printf "%s" "k"
;;
"6c")
printf "%s" "l"
;;
"6d")
printf "%s" "m"
;;
"6e")
printf "%s" "n"
;;
"6f")
printf "%s" "o"
;;
"70")
printf "%s" "p"
;;
"71")
printf "%s" "q"
;;
"72")
printf "%s" "r"
;;
"73")
printf "%s" "s"
;;
"74")
printf "%s" "t"
;;
"75")
printf "%s" "u"
;;
"76")
printf "%s" "v"
;;
"77")
printf "%s" "w"
;;
"78")
printf "%s" "x"
;;
"79")
printf "%s" "y"
;;
"7a")
printf "%s" "z"
;;
2017-01-30 05:25:56 +01:00
#numbers
2020-08-17 16:18:20 +02:00
"30")
printf "%s" "0"
;;
"31")
printf "%s" "1"
;;
"32")
printf "%s" "2"
;;
"33")
printf "%s" "3"
;;
"34")
printf "%s" "4"
;;
"35")
printf "%s" "5"
;;
"36")
printf "%s" "6"
;;
"37")
printf "%s" "7"
;;
"38")
printf "%s" "8"
;;
"39")
printf "%s" "9"
;;
"2d")
printf "%s" "-"
;;
"5f")
printf "%s" "_"
;;
"2e")
printf "%s" "."
;;
"7e")
printf "%s" "~"
;;
#other hex
*)
printf '%%%s' "$_hex_code"
;;
2017-01-30 05:07:50 +01:00
esac
2016-11-20 15:57:07 +01:00
done
}
_json_encode() {
_j_str="$(sed 's/"/\\"/g' | sed "s/\r/\\r/g")"
_debug3 "_json_encode"
_debug3 "_j_str" "$_j_str"
echo "$_j_str" | _hex_dump | _lower_case | sed 's/0a/5c 6e/g' | tr -d ' ' | _h2b | tr -d "\r\n"
}
#from: http:\/\/ to http://
_json_decode() {
_j_str="$(sed 's#\\/#/#g')"
_debug3 "_json_decode"
_debug3 "_j_str" "$_j_str"
echo "$_j_str"
}
#options file
_sed_i() {
options="$1"
filename="$2"
2016-11-09 12:30:39 +01:00
if [ -z "$filename" ]; then
_usage "Usage:_sed_i options filename"
return 1
fi
2016-04-22 14:50:43 +02:00
_debug2 options "$options"
if sed -h 2>&1 | grep "\-i\[SUFFIX]" >/dev/null 2>&1; then
_debug "Using sed -i"
2016-04-22 14:50:43 +02:00
sed -i "$options" "$filename"
else
_debug "No -i support in sed"
2016-05-13 15:14:00 +02:00
text="$(cat "$filename")"
2016-11-09 12:30:39 +01:00
echo "$text" | sed "$options" >"$filename"
fi
}
_egrep_o() {
2016-11-18 13:14:08 +01:00
if ! egrep -o "$1" 2>/dev/null; then
sed -n 's/.*\('"$1"'\).*/\1/p'
fi
}
2016-03-17 14:18:09 +01:00
#Usage: file startline endline
_getfile() {
filename="$1"
startline="$2"
endline="$3"
2016-11-09 12:30:39 +01:00
if [ -z "$endline" ]; then
_usage "Usage: file startline endline"
2016-03-17 14:18:09 +01:00
return 1
fi
2016-11-09 12:30:39 +01:00
i="$(grep -n -- "$startline" "$filename" | cut -d : -f 1)"
if [ -z "$i" ]; then
2016-03-17 14:18:09 +01:00
_err "Can not find start line: $startline"
return 1
fi
2016-05-13 15:14:00 +02:00
i="$(_math "$i" + 1)"
_debug i "$i"
2016-11-09 12:30:39 +01:00
j="$(grep -n -- "$endline" "$filename" | cut -d : -f 1)"
if [ -z "$j" ]; then
2016-03-17 14:18:09 +01:00
_err "Can not find end line: $endline"
return 1
fi
2016-05-13 15:14:00 +02:00
j="$(_math "$j" - 1)"
_debug j "$j"
2016-11-09 12:30:39 +01:00
sed -n "$i,${j}p" "$filename"
2016-03-17 14:18:09 +01:00
}
#Usage: multiline
2016-03-08 13:44:12 +01:00
_base64() {
2016-12-27 14:29:44 +01:00
[ "" ] #urgly
2016-11-09 12:30:39 +01:00
if [ "$1" ]; then
2016-12-13 13:27:49 +01:00
_debug3 "base64 multiline:'$1'"
2017-03-30 15:16:25 +02:00
${ACME_OPENSSL_BIN:-openssl} base64 -e
2016-03-17 14:18:09 +01:00
else
2016-12-13 13:04:43 +01:00
_debug3 "base64 single line."
2017-03-30 15:16:25 +02:00
${ACME_OPENSSL_BIN:-openssl} base64 -e | tr -d '\r\n'
2016-03-17 14:18:09 +01:00
fi
}
#Usage: multiline
_dbase64() {
2016-11-09 12:30:39 +01:00
if [ "$1" ]; then
2017-03-30 15:16:25 +02:00
${ACME_OPENSSL_BIN:-openssl} base64 -d -A
2016-03-17 14:18:09 +01:00
else
2017-03-30 15:16:25 +02:00
${ACME_OPENSSL_BIN:-openssl} base64 -d
2016-03-17 14:18:09 +01:00
fi
}
2018-03-09 01:06:42 +01:00
#file
_checkcert() {
_cf="$1"
if [ "$DEBUG" ]; then
2018-03-09 01:09:32 +01:00
openssl x509 -noout -text -in "$_cf"
2018-03-09 01:06:42 +01:00
else
2018-03-09 01:09:32 +01:00
openssl x509 -noout -text -in "$_cf" >/dev/null 2>&1
2018-03-09 01:06:42 +01:00
fi
}
#Usage: hashalg [outputhex]
2016-03-17 14:18:09 +01:00
#Output Base64-encoded digest
_digest() {
alg="$1"
2016-11-09 12:30:39 +01:00
if [ -z "$alg" ]; then
_usage "Usage: _digest hashalg"
2016-03-17 14:18:09 +01:00
return 1
fi
2016-11-09 12:30:39 +01:00
outputhex="$2"
2016-11-09 12:30:39 +01:00
2016-11-11 16:30:14 +01:00
if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then
2016-11-09 12:30:39 +01:00
if [ "$outputhex" ]; then
2017-03-30 15:16:25 +02:00
${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' '
else
2017-03-30 15:16:25 +02:00
${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -binary | _base64
2016-11-08 14:27:39 +01:00
fi
else
_err "$alg is not supported yet"
return 1
fi
}
2016-11-20 15:57:07 +01:00
#Usage: hashalg secret_hex [outputhex]
#Output binary hmac
2016-11-08 14:27:39 +01:00
_hmac() {
alg="$1"
2016-11-20 15:57:07 +01:00
secret_hex="$2"
2016-11-08 14:27:39 +01:00
outputhex="$3"
2016-11-09 12:30:39 +01:00
2016-11-20 15:57:07 +01:00
if [ -z "$secret_hex" ]; then
2016-11-09 12:30:39 +01:00
_usage "Usage: _hmac hashalg secret [outputhex]"
2016-11-08 14:27:39 +01:00
return 1
fi
2016-08-24 12:46:23 +02:00
if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then
2016-11-09 12:30:39 +01:00
if [ "$outputhex" ]; then
2017-03-30 15:16:25 +02:00
(${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' '
else
2017-03-30 15:16:25 +02:00
${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary
fi
2016-03-17 14:18:09 +01:00
else
_err "$alg is not supported yet"
return 1
fi
}
#Usage: keyfile hashalg
#Output: Base64-encoded signature value
_sign() {
keyfile="$1"
alg="$2"
2016-11-09 12:30:39 +01:00
if [ -z "$alg" ]; then
_usage "Usage: _sign keyfile hashalg"
2016-03-17 14:18:09 +01:00
return 1
fi
2016-11-09 12:30:39 +01:00
2017-03-30 15:16:25 +02:00
_sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile "
2016-11-09 12:30:39 +01:00
2020-05-19 20:04:23 +02:00
if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || grep "BEGIN PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
$_sign_openssl -$alg | _base64
2016-11-09 12:30:39 +01:00
elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
if ! _signedECText="$($_sign_openssl -sha$__ECC_KEY_LEN | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then
2016-11-04 16:34:06 +01:00
_err "Sign failed: $_sign_openssl"
_err "Key file: $keyfile"
2017-03-26 07:28:04 +02:00
_err "Key content:$(wc -l <"$keyfile") lines"
2016-11-04 16:34:06 +01:00
return 1
fi
_debug3 "_signedECText" "$_signedECText"
_ec_r="$(echo "$_signedECText" | _head_n 2 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")"
_ec_s="$(echo "$_signedECText" | _head_n 3 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")"
if [ "$__ECC_KEY_LEN" -eq "256" ]; then
while [ "${#_ec_r}" -lt "64" ]; do
2020-07-13 15:03:57 +02:00
_ec_r="0${_ec_r}"
2020-07-13 14:56:58 +02:00
done
while [ "${#_ec_s}" -lt "64" ]; do
2020-07-13 15:03:57 +02:00
_ec_s="0${_ec_s}"
done
fi
if [ "$__ECC_KEY_LEN" -eq "384" ]; then
while [ "${#_ec_r}" -lt "96" ]; do
2020-07-13 15:03:57 +02:00
_ec_r="0${_ec_r}"
2020-07-13 14:56:58 +02:00
done
while [ "${#_ec_s}" -lt "96" ]; do
2020-07-13 15:03:57 +02:00
_ec_s="0${_ec_s}"
done
fi
if [ "$__ECC_KEY_LEN" -eq "512" ]; then
while [ "${#_ec_r}" -lt "132" ]; do
2020-07-13 15:03:57 +02:00
_ec_r="0${_ec_r}"
2020-07-13 14:56:58 +02:00
done
while [ "${#_ec_s}" -lt "132" ]; do
2020-07-13 15:03:57 +02:00
_ec_s="0${_ec_s}"
done
fi
2020-07-14 15:49:50 +02:00
_debug3 "_ec_r" "$_ec_r"
_debug3 "_ec_s" "$_ec_s"
printf "%s" "$_ec_r$_ec_s" | _h2b | _base64
else
_err "Unknown key file format."
return 1
fi
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
}
#keylength or isEcc flag (empty str => not ecc)
_isEccKey() {
_length="$1"
2016-11-09 12:30:39 +01:00
if [ -z "$_length" ]; then
return 1
fi
2020-08-17 16:18:20 +02:00
[ "$_length" != "1024" ] &&
[ "$_length" != "2048" ] &&
[ "$_length" != "3072" ] &&
[ "$_length" != "4096" ] &&
[ "$_length" != "8192" ]
}
# _createkey 2048|ec-256 file
_createkey() {
length="$1"
f="$2"
2016-12-10 14:32:47 +01:00
_debug2 "_createkey for file:$f"
eccname="$length"
2016-11-09 12:30:39 +01:00
if _startswith "$length" "ec-"; then
2016-11-09 14:06:22 +01:00
length=$(printf "%s" "$length" | cut -d '-' -f 2-100)
2016-11-09 12:30:39 +01:00
if [ "$length" = "256" ]; then
eccname="prime256v1"
fi
2016-11-09 12:30:39 +01:00
if [ "$length" = "384" ]; then
eccname="secp384r1"
fi
2016-11-09 12:30:39 +01:00
if [ "$length" = "521" ]; then
eccname="secp521r1"
fi
fi
2016-11-09 12:30:39 +01:00
if [ -z "$length" ]; then
length=2048
fi
2016-11-09 12:30:39 +01:00
2016-08-25 16:27:48 +02:00
_debug "Use length $length"
if ! touch "$f" >/dev/null 2>&1; then
_f_path="$(dirname "$f")"
_debug _f_path "$_f_path"
if ! mkdir -p "$_f_path"; then
_err "Can not create path: $_f_path"
return 1
fi
fi
2016-11-09 12:30:39 +01:00
if _isEccKey "$length"; then
2016-08-25 16:27:48 +02:00
_debug "Using ec name: $eccname"
if _opkey="$(${ACME_OPENSSL_BIN:-openssl} ecparam -name "$eccname" -genkey 2>/dev/null)"; then
echo "$_opkey" >"$f"
else
_err "error ecc key name: $eccname"
return 1
fi
else
2016-08-25 16:27:48 +02:00
_debug "Using RSA: $length"
if _opkey="$(${ACME_OPENSSL_BIN:-openssl} genrsa "$length" 2>/dev/null)"; then
echo "$_opkey" >"$f"
else
_err "error rsa key: $length"
return 1
fi
fi
2016-11-09 12:30:39 +01:00
if [ "$?" != "0" ]; then
_err "Create key error."
return 1
fi
}
#domain
_is_idn() {
_is_idn_d="$1"
_debug2 _is_idn_d "$_is_idn_d"
2019-04-29 15:44:25 +02:00
_idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '*.,-_')
_debug2 _idn_temp "$_idn_temp"
[ "$_idn_temp" ]
}
#aa.com
#aa.com,bb.com,cc.com
_idn() {
__idn_d="$1"
2016-11-09 12:30:39 +01:00
if ! _is_idn "$__idn_d"; then
printf "%s" "$__idn_d"
return 0
fi
2016-11-09 12:30:39 +01:00
if _exists idn; then
if _contains "$__idn_d" ','; then
_i_first="1"
2016-11-09 12:30:39 +01:00
for f in $(echo "$__idn_d" | tr ',' ' '); do
[ -z "$f" ] && continue
2016-11-09 12:30:39 +01:00
if [ -z "$_i_first" ]; then
printf "%s" ","
else
_i_first=""
fi
2016-10-31 14:22:04 +01:00
idn --quiet "$f" | tr -d "\r\n"
done
else
idn "$__idn_d" | tr -d "\r\n"
fi
else
_err "Please install idn to process IDN names."
fi
}
#_createcsr cn san_list keyfile csrfile conf acmeValidationv1
_createcsr() {
_debug _createcsr
domain="$1"
domainlist="$2"
csrkey="$3"
csr="$4"
csrconf="$5"
acmeValidationv1="$6"
_debug2 domain "$domain"
_debug2 domainlist "$domainlist"
_debug2 csrkey "$csrkey"
_debug2 csr "$csr"
_debug2 csrconf "$csrconf"
2016-11-09 12:30:39 +01:00
printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf"
if [ "$acmeValidationv1" ]; then
2019-04-26 17:44:25 +02:00
domainlist="$(_idn "$domainlist")"
printf -- "\nsubjectAltName=DNS:$domainlist" >>"$csrconf"
elif [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
#single domain
_info "Single domain" "$domain"
printf -- "\nsubjectAltName=DNS:$(_idn "$domain")" >>"$csrconf"
else
2016-11-09 14:06:22 +01:00
domainlist="$(_idn "$domainlist")"
_debug2 domainlist "$domainlist"
2016-11-09 12:30:39 +01:00
if _contains "$domainlist" ","; then
alt="DNS:$(_idn "$domain"),DNS:$(echo "$domainlist" | sed "s/,,/,/g" | sed "s/,/,DNS:/g")"
else
alt="DNS:$(_idn "$domain"),DNS:$domainlist"
fi
2017-04-17 13:08:34 +02:00
#multi
_info "Multi domain" "$alt"
2016-11-09 12:30:39 +01:00
printf -- "\nsubjectAltName=$alt" >>"$csrconf"
fi
if [ "$Le_OCSP_Staple" = "1" ]; then
2016-12-18 03:17:35 +01:00
_savedomainconf Le_OCSP_Staple "$Le_OCSP_Staple"
2016-11-09 12:30:39 +01:00
printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf"
fi
2016-11-09 12:30:39 +01:00
if [ "$acmeValidationv1" ]; then
printf "\n1.3.6.1.5.5.7.1.31=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}"
fi
_csr_cn="$(_idn "$domain")"
_debug2 _csr_cn "$_csr_cn"
2017-02-10 11:20:15 +01:00
if _contains "$(uname -a)" "MINGW"; then
2017-03-30 15:16:25 +02:00
${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr"
2017-02-10 11:20:15 +01:00
else
2017-03-30 15:16:25 +02:00
${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr"
2017-02-10 11:20:15 +01:00
fi
}
#_signcsr key csr conf cert
_signcsr() {
key="$1"
csr="$2"
conf="$3"
cert="$4"
2016-06-18 06:28:23 +02:00
_debug "_signcsr"
2016-11-09 12:30:39 +01:00
2017-03-30 15:16:25 +02:00
_msg="$(${ACME_OPENSSL_BIN:-openssl} x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)"
2016-06-18 06:28:23 +02:00
_ret="$?"
_debug "$_msg"
return $_ret
}
#_csrfile
_readSubjectFromCSR() {
_csrfile="$1"
2016-11-09 12:30:39 +01:00
if [ -z "$_csrfile" ]; then
_usage "_readSubjectFromCSR mycsr.csr"
return 1
fi
2017-06-18 04:07:23 +02:00
${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | tr ',' "\n" | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d ' \n'
}
#_csrfile
#echo comma separated domain list
_readSubjectAltNamesFromCSR() {
_csrfile="$1"
2016-11-09 12:30:39 +01:00
if [ -z "$_csrfile" ]; then
_usage "_readSubjectAltNamesFromCSR mycsr.csr"
return 1
fi
2016-11-09 12:30:39 +01:00
_csrsubj="$(_readSubjectFromCSR "$_csrfile")"
_debug _csrsubj "$_csrsubj"
2016-11-09 12:30:39 +01:00
2017-03-30 15:16:25 +02:00
_dnsAltnames="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')"
_debug _dnsAltnames "$_dnsAltnames"
2016-11-09 12:30:39 +01:00
if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then
_debug "AltNames contains subject"
_excapedAlgnames="$(echo "$_dnsAltnames" | tr '*' '#')"
_debug _excapedAlgnames "$_excapedAlgnames"
_escapedSubject="$(echo "$_csrsubj" | tr '*' '#')"
_debug _escapedSubject "$_escapedSubject"
_dnsAltnames="$(echo "$_excapedAlgnames," | sed "s/DNS:$_escapedSubject,//g" | tr '#' '*' | sed "s/,\$//g")"
_debug _dnsAltnames "$_dnsAltnames"
else
_debug "AltNames doesn't contain subject"
fi
2016-11-09 12:30:39 +01:00
echo "$_dnsAltnames" | sed "s/DNS://g"
}
2017-04-17 13:08:34 +02:00
#_csrfile
_readKeyLengthFromCSR() {
_csrfile="$1"
2016-11-09 12:30:39 +01:00
if [ -z "$_csrfile" ]; then
2016-08-27 14:00:47 +02:00
_usage "_readKeyLengthFromCSR mycsr.csr"
return 1
fi
2016-11-09 12:30:39 +01:00
2017-03-30 15:16:25 +02:00
_outcsr="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile")"
2017-04-04 16:33:26 +02:00
_debug2 _outcsr "$_outcsr"
2016-11-09 12:30:39 +01:00
if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then
_debug "ECC CSR"
echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' '
else
_debug "RSA CSR"
_rkl="$(echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1)"
if [ "$_rkl" ]; then
echo "$_rkl"
else
echo "$_outcsr" | tr "\t" " " | _egrep_o "RSA Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1
fi
fi
}
2016-03-13 11:17:13 +01:00
_ss() {
_port="$1"
2016-11-09 12:30:39 +01:00
if _exists "ss"; then
2016-03-23 15:23:24 +01:00
_debug "Using: ss"
2017-07-01 15:47:30 +02:00
ss -ntpl 2>/dev/null | grep ":$_port "
2016-03-23 15:23:24 +01:00
return 0
fi
2016-11-09 12:30:39 +01:00
if _exists "netstat"; then
2016-03-13 11:24:03 +01:00
_debug "Using: netstat"
if netstat -help 2>&1 | grep "\-p proto" >/dev/null; then
2016-03-23 13:23:56 +01:00
#for windows version netstat tool
netstat -an -p tcp | grep "LISTENING" | grep ":$_port "
2016-03-23 13:23:56 +01:00
else
2016-11-09 12:30:39 +01:00
if netstat -help 2>&1 | grep "\-p protocol" >/dev/null; then
2016-05-13 15:14:00 +02:00
netstat -an -p tcp | grep LISTEN | grep ":$_port "
2016-11-09 12:30:39 +01:00
elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then
#for solaris
2016-08-10 17:13:14 +02:00
netstat -an -P tcp | grep "\.$_port " | grep "LISTEN"
2017-03-20 18:51:45 +01:00
elif netstat -help 2>&1 | grep "\-p" >/dev/null; then
#for full linux
2016-05-13 15:14:00 +02:00
netstat -ntpl | grep ":$_port "
else
#for busybox (embedded linux; no pid support)
netstat -ntl 2>/dev/null | grep ":$_port "
2016-03-23 15:23:24 +01:00
fi
2016-03-23 13:23:56 +01:00
fi
2016-03-13 11:17:13 +01:00
return 0
fi
2016-03-23 15:23:24 +01:00
2016-03-13 11:17:13 +01:00
return 1
}
#outfile key cert cacert [password [name [caname]]]
_toPkcs() {
_cpfx="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
pfxPassword="$5"
pfxName="$6"
pfxCaname="$7"
if [ "$pfxCaname" ]; then
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName" -caname "$pfxCaname"
elif [ "$pfxName" ]; then
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName"
elif [ "$pfxPassword" ]; then
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword"
else
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca"
fi
}
#domain [password] [isEcc]
toPkcs() {
domain="$1"
pfxPassword="$2"
2016-11-09 12:30:39 +01:00
if [ -z "$domain" ]; then
_usage "Usage: $PROJECT_ENTRY --toPkcs -d domain [--password pfx-password]"
return 1
fi
_isEcc="$3"
2016-11-09 12:30:39 +01:00
_initpath "$domain" "$_isEcc"
_toPkcs "$CERT_PFX_PATH" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$pfxPassword"
2016-11-09 12:30:39 +01:00
if [ "$?" = "0" ]; then
_info "Success, Pfx is exported to: $CERT_PFX_PATH"
fi
}
#domain [isEcc]
toPkcs8() {
domain="$1"
if [ -z "$domain" ]; then
_usage "Usage: $PROJECT_ENTRY --toPkcs8 -d domain [--ecc]"
return 1
fi
_isEcc="$2"
_initpath "$domain" "$_isEcc"
2017-03-30 15:16:25 +02:00
${ACME_OPENSSL_BIN:-openssl} pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH"
if [ "$?" = "0" ]; then
_info "Success, $CERT_PKCS8_PATH"
fi
}
2017-04-17 13:08:34 +02:00
#[2048]
2016-03-08 13:44:12 +01:00
createAccountKey() {
_info "Creating account key"
2016-11-09 12:30:39 +01:00
if [ -z "$1" ]; then
_usage "Usage: $PROJECT_ENTRY --createAccountKey --accountkeylength 2048"
2016-03-08 13:44:12 +01:00
return
fi
2016-11-09 12:30:39 +01:00
length=$1
_create_account_key "$length"
}
_create_account_key() {
length=$1
2016-11-09 12:30:39 +01:00
if [ -z "$length" ] || [ "$length" = "$NO_VALUE" ]; then
_debug "Use default length $DEFAULT_ACCOUNT_KEY_LENGTH"
length="$DEFAULT_ACCOUNT_KEY_LENGTH"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
_debug length "$length"
2016-03-08 13:44:12 +01:00
_initpath
mkdir -p "$CA_DIR"
if [ -s "$ACCOUNT_KEY_PATH" ]; then
2016-03-08 13:44:12 +01:00
_info "Account key exists, skip"
return 0
2016-03-08 13:44:12 +01:00
else
#generate account key
if _createkey "$length" "$ACCOUNT_KEY_PATH"; then
chmod 600 "$ACCOUNT_KEY_PATH"
_info "Create account key ok."
return 0
else
_err "Create account key error."
return 1
fi
2016-03-08 13:44:12 +01:00
fi
}
#domain [length]
2016-03-08 13:44:12 +01:00
createDomainKey() {
_info "Creating domain key"
2016-11-09 12:30:39 +01:00
if [ -z "$1" ]; then
_usage "Usage: $PROJECT_ENTRY --createDomainKey -d domain.com [ --keylength 2048 ]"
2016-03-08 13:44:12 +01:00
return
fi
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
domain=$1
_cdl=$2
if [ -z "$_cdl" ]; then
_debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH"
_cdl="$DEFAULT_DOMAIN_KEY_LENGTH"
fi
_initpath "$domain" "$_cdl"
2016-11-09 12:30:39 +01:00
2020-08-16 11:36:24 +02:00
if [ ! -f "$CERT_KEY_PATH" ] || [ ! -s "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$_ACME_IS_RENEW" ]) || [ "$Le_ForceNewDomainKey" = "1" ]; then
if _createkey "$_cdl" "$CERT_KEY_PATH"; then
_savedomainconf Le_Keylength "$_cdl"
_info "The domain key is here: $(__green $CERT_KEY_PATH)"
return 0
else
2019-04-27 03:17:26 +02:00
_err "Can not create domain key"
return 1
fi
2016-03-08 13:44:12 +01:00
else
2020-08-16 11:36:24 +02:00
if [ "$_ACME_IS_RENEW" ]; then
2016-03-08 13:44:12 +01:00
_info "Domain key exists, skip"
return 0
else
_err "Domain key exists, do you want to overwrite the key?"
_err "Add '--force', and try again."
2016-03-08 13:44:12 +01:00
return 1
fi
fi
}
# domain domainlist isEcc
2016-03-08 13:44:12 +01:00
createCSR() {
_info "Creating csr"
2016-11-09 12:30:39 +01:00
if [ -z "$1" ]; then
_usage "Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ]"
2016-03-08 13:44:12 +01:00
return
fi
2016-11-09 12:30:39 +01:00
domain="$1"
domainlist="$2"
_isEcc="$3"
2016-11-09 12:30:39 +01:00
_initpath "$domain" "$_isEcc"
2016-11-09 12:30:39 +01:00
2020-08-16 11:36:24 +02:00
if [ -f "$CSR_PATH" ] && [ "$_ACME_IS_RENEW" ] && [ -z "$FORCE" ]; then
2016-03-08 13:44:12 +01:00
_info "CSR exists, skip"
return
fi
2016-11-09 12:30:39 +01:00
if [ ! -f "$CERT_KEY_PATH" ]; then
_err "The key file is not found: $CERT_KEY_PATH"
_err "Please create the key file first."
return 1
fi
_createcsr "$domain" "$domainlist" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
}
2017-01-29 04:47:04 +01:00
_url_replace() {
2016-11-09 14:06:22 +01:00
tr '/+' '_-' | tr -d '= '
2016-03-08 13:44:12 +01:00
}
2020-08-09 03:34:43 +02:00
#base64 string
_durl_replace_base64() {
_l=$((${#1} % 4))
if [ $_l -eq 2 ]; then
_s="$1"'=='
elif [ $_l -eq 3 ]; then
_s="$1"'='
else
_s="$1"
fi
echo "$_s" | tr '_-' '/+'
}
2016-03-08 13:44:12 +01:00
_time2str() {
#BSD
if date -u -r "$1" 2>/dev/null; then
2016-03-08 13:44:12 +01:00
return
fi
2016-11-09 12:30:39 +01:00
#Linux
if date -u -d@"$1" 2>/dev/null; then
2016-03-08 13:44:12 +01:00
return
fi
2016-11-09 12:30:39 +01:00
#Solaris
2016-11-09 12:30:39 +01:00
if _exists adb; then
2016-11-11 15:36:16 +01:00
_t_s_a=$(echo "0t${1}=Y" | adb)
echo "$_t_s_a"
fi
2016-11-09 12:30:39 +01:00
#Busybox
if echo "$1" | awk '{ print strftime("%c", $0); }' 2>/dev/null; then
return
fi
2016-03-08 13:44:12 +01:00
}
2016-05-23 16:02:43 +02:00
_normalizeJson() {
sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n"
}
2016-03-09 16:16:46 +01:00
_stat() {
#Linux
2016-11-09 12:30:39 +01:00
if stat -c '%U:%G' "$1" 2>/dev/null; then
2016-03-09 16:16:46 +01:00
return
fi
2016-11-09 12:30:39 +01:00
2016-03-09 16:16:46 +01:00
#BSD
2016-11-09 12:30:39 +01:00
if stat -f '%Su:%Sg' "$1" 2>/dev/null; then
2016-03-09 16:16:46 +01:00
return
fi
2016-11-09 12:30:39 +01:00
return 1 #error, 'stat' not found
2016-03-09 16:16:46 +01:00
}
#keyfile
_calcjwk() {
keyfile="$1"
2016-11-09 12:30:39 +01:00
if [ -z "$keyfile" ]; then
_usage "Usage: _calcjwk keyfile"
return 1
fi
2016-11-09 12:30:39 +01:00
if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ]; then
2016-10-29 06:14:48 +02:00
_debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE"
return 0
fi
2016-11-09 12:30:39 +01:00
if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
_debug "RSA key"
2017-03-30 15:16:25 +02:00
pub_exp=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
2016-11-09 12:30:39 +01:00
if [ "${#pub_exp}" = "5" ]; then
pub_exp=0$pub_exp
fi
_debug3 pub_exp "$pub_exp"
2016-11-09 12:30:39 +01:00
2016-11-09 14:06:22 +01:00
e=$(echo "$pub_exp" | _h2b | _base64)
_debug3 e "$e"
2016-11-09 12:30:39 +01:00
2017-03-30 15:16:25 +02:00
modulus=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2)
_debug3 modulus "$modulus"
2017-01-29 04:47:04 +01:00
n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)"
2016-12-13 13:04:43 +01:00
_debug3 n "$n"
jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}'
_debug3 jwk "$jwk"
2016-11-09 12:30:39 +01:00
2016-10-28 12:07:04 +02:00
JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}'
JWK_HEADERPLACE_PART1='{"nonce": "'
2018-01-06 05:45:24 +01:00
JWK_HEADERPLACE_PART2='", "alg": "RS256"'
2016-11-09 12:30:39 +01:00
elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
_debug "EC key"
2017-03-30 15:16:25 +02:00
crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")"
_debug3 crv "$crv"
__ECC_KEY_LEN=$(echo "$crv" | cut -d "-" -f 2)
if [ "$__ECC_KEY_LEN" = "521" ]; then
__ECC_KEY_LEN=512
fi
_debug3 __ECC_KEY_LEN "$__ECC_KEY_LEN"
2016-11-09 12:30:39 +01:00
if [ -z "$crv" ]; then
_debug "Let's try ASN1 OID"
2017-03-30 15:16:25 +02:00
crv_oid="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")"
2016-11-04 15:53:33 +01:00
_debug3 crv_oid "$crv_oid"
case "${crv_oid}" in
2020-08-17 16:18:20 +02:00
"prime256v1")
crv="P-256"
__ECC_KEY_LEN=256
;;
"secp384r1")
crv="P-384"
__ECC_KEY_LEN=384
;;
"secp521r1")
crv="P-521"
__ECC_KEY_LEN=512
;;
*)
_err "ECC oid : $crv_oid"
return 1
;;
2016-11-04 15:47:45 +01:00
esac
_debug3 crv "$crv"
fi
2016-11-09 12:30:39 +01:00
2017-03-30 15:16:25 +02:00
pubi="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)"
2016-11-09 14:18:47 +01:00
pubi=$(_math "$pubi" + 1)
_debug3 pubi "$pubi"
2016-11-09 12:30:39 +01:00
2017-03-30 15:16:25 +02:00
pubj="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)"
2016-11-09 14:18:47 +01:00
pubj=$(_math "$pubj" - 1)
_debug3 pubj "$pubj"
2016-11-09 12:30:39 +01:00
2017-03-30 15:16:25 +02:00
pubtext="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")"
_debug3 pubtext "$pubtext"
2016-11-09 12:30:39 +01:00
2016-11-09 13:45:57 +01:00
xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)"
2016-11-09 14:18:47 +01:00
xlen=$(_math "$xlen" / 4)
_debug3 xlen "$xlen"
2016-04-17 11:33:08 +02:00
xend=$(_math "$xlen" + 1)
2016-11-09 14:06:22 +01:00
x="$(printf "%s" "$pubtext" | cut -d : -f 2-"$xend")"
_debug3 x "$x"
2016-11-09 12:30:39 +01:00
2017-01-29 04:47:04 +01:00
x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _url_replace)"
_debug3 x64 "$x64"
2016-04-17 11:33:08 +02:00
2016-05-13 15:14:00 +02:00
xend=$(_math "$xend" + 1)
2016-11-09 14:06:22 +01:00
y="$(printf "%s" "$pubtext" | cut -d : -f "$xend"-10000)"
_debug3 y "$y"
2016-11-09 12:30:39 +01:00
2017-01-29 04:47:04 +01:00
y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _url_replace)"
_debug3 y64 "$y64"
2016-11-09 12:30:39 +01:00
2016-10-29 06:14:48 +02:00
jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}'
_debug3 jwk "$jwk"
2016-11-09 12:30:39 +01:00
JWK_HEADER='{"alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}'
2016-10-28 12:07:04 +02:00
JWK_HEADERPLACE_PART1='{"nonce": "'
2018-01-06 05:45:24 +01:00
JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"'
else
_err "Only RSA or EC key is supported. keyfile=$keyfile"
_debug2 "$(cat "$keyfile")"
return 1
fi
2016-10-28 12:07:04 +02:00
_debug3 JWK_HEADER "$JWK_HEADER"
2016-10-29 06:14:48 +02:00
__CACHED_JWK_KEY_FILE="$keyfile"
}
2016-08-14 16:37:21 +02:00
2016-08-25 15:46:31 +02:00
_time() {
date -u "+%s"
}
2016-08-14 16:37:21 +02:00
2017-02-06 12:30:53 +01:00
_utc_date() {
date -u "+%Y-%m-%d %H:%M:%S"
}
2016-08-14 16:37:21 +02:00
_mktemp() {
2016-11-09 12:30:39 +01:00
if _exists mktemp; then
if mktemp 2>/dev/null; then
2016-11-01 13:29:58 +01:00
return 0
2016-11-09 12:30:39 +01:00
elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null; then
2016-09-27 17:43:18 +02:00
#for Mac osx
2016-11-01 13:29:58 +01:00
return 0
2016-09-27 15:27:43 +02:00
fi
2016-08-14 16:37:21 +02:00
fi
2016-11-09 12:30:39 +01:00
if [ -d "/tmp" ]; then
2016-08-25 15:46:31 +02:00
echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp"
return 0
2016-11-09 12:30:39 +01:00
elif [ "$LE_TEMP_DIR" ] && mkdir -p "$LE_TEMP_DIR"; then
2016-11-01 13:29:58 +01:00
echo "/$LE_TEMP_DIR/wefADf24sf.$(_time).tmp"
return 0
2016-08-25 15:46:31 +02:00
fi
_err "Can not create temp file."
2016-08-14 16:37:21 +02:00
}
_inithttp() {
2016-11-09 12:30:39 +01:00
if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER"; then
2016-08-14 16:37:21 +02:00
HTTP_HEADER="$(_mktemp)"
_debug2 HTTP_HEADER "$HTTP_HEADER"
fi
2016-11-09 12:30:39 +01:00
if [ "$__HTTP_INITIALIZED" ]; then
if [ "$_ACME_CURL$_ACME_WGET" ]; then
2016-10-28 14:56:18 +02:00
_debug2 "Http already initialized."
return 0
fi
fi
2016-11-09 12:30:39 +01:00
if [ -z "$_ACME_CURL" ] && _exists "curl"; then
2016-10-28 14:56:18 +02:00
_ACME_CURL="curl -L --silent --dump-header $HTTP_HEADER "
2016-11-09 12:30:39 +01:00
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
2016-08-14 16:37:21 +02:00
_CURL_DUMP="$(_mktemp)"
2016-10-28 14:56:18 +02:00
_ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP "
2016-08-14 16:37:21 +02:00
fi
if [ "$CA_PATH" ]; then
_ACME_CURL="$_ACME_CURL --capath $CA_PATH "
elif [ "$CA_BUNDLE" ]; then
2016-10-28 14:56:18 +02:00
_ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE "
fi
if _contains "$(curl --help 2>&1)" "--globoff"; then
_ACME_CURL="$_ACME_CURL -g "
fi
2016-08-14 16:37:21 +02:00
fi
2016-11-09 12:30:39 +01:00
2016-10-28 14:56:18 +02:00
if [ -z "$_ACME_WGET" ] && _exists "wget"; then
_ACME_WGET="wget -q"
2016-11-09 12:30:39 +01:00
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
2016-10-28 14:56:18 +02:00
_ACME_WGET="$_ACME_WGET -d "
2016-08-14 16:37:21 +02:00
fi
if [ "$CA_PATH" ]; then
_ACME_WGET="$_ACME_WGET --ca-directory=$CA_PATH "
elif [ "$CA_BUNDLE" ]; then
_ACME_WGET="$_ACME_WGET --ca-certificate=$CA_BUNDLE "
fi
2016-08-14 16:37:21 +02:00
fi
2017-02-28 14:35:20 +01:00
#from wget 1.14: do not skip body on 404 error
2017-03-01 06:12:29 +01:00
if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help 2>&1)" "--content-on-error"; then
2017-02-28 14:35:20 +01:00
_ACME_WGET="$_ACME_WGET --content-on-error "
fi
2016-10-28 14:56:18 +02:00
__HTTP_INITIALIZED=1
2016-08-14 16:37:21 +02:00
}
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
_post() {
body="$1"
2018-01-06 05:45:24 +01:00
_post_url="$2"
needbase64="$3"
2016-05-07 17:33:42 +02:00
httpmethod="$4"
_postContentType="$5"
2016-11-09 12:30:39 +01:00
if [ -z "$httpmethod" ]; then
2016-05-07 17:33:42 +02:00
httpmethod="POST"
fi
_debug $httpmethod
2018-01-06 05:45:24 +01:00
_debug "_post_url" "$_post_url"
2016-07-29 12:07:16 +02:00
_debug2 "body" "$body"
_debug2 "_postContentType" "$_postContentType"
2016-11-09 12:30:39 +01:00
2016-08-14 16:37:21 +02:00
_inithttp
2016-11-09 12:30:39 +01:00
if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then
2016-10-28 14:56:18 +02:00
_CURL="$_ACME_CURL"
2016-11-21 13:56:50 +01:00
if [ "$HTTPS_INSECURE" ]; then
_CURL="$_CURL --insecure "
fi
if [ "$httpmethod" = "HEAD" ]; then
_CURL="$_CURL -I "
fi
2016-05-31 15:38:41 +02:00
_debug "_CURL" "$_CURL"
2016-11-09 12:30:39 +01:00
if [ "$needbase64" ]; then
if [ "$body" ]; then
if [ "$_postContentType" ]; then
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
else
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
fi
2018-03-18 12:29:02 +01:00
else
if [ "$_postContentType" ]; then
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)"
else
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)"
fi
2018-03-18 12:29:02 +01:00
fi
else
if [ "$body" ]; then
if [ "$_postContentType" ]; then
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
else
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
fi
2018-03-18 12:29:02 +01:00
else
if [ "$_postContentType" ]; then
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")"
else
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")"
fi
2018-03-18 12:29:02 +01:00
fi
fi
2016-05-31 06:12:30 +02:00
_ret="$?"
2016-11-09 12:30:39 +01:00
if [ "$_ret" != "0" ]; then
2016-06-25 03:40:00 +02:00
_err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
2016-11-09 12:30:39 +01:00
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
2016-06-25 03:40:00 +02:00
_err "Here is the curl dump log:"
_err "$(cat "$_CURL_DUMP")"
fi
2016-06-25 03:29:23 +02:00
fi
2016-11-09 12:30:39 +01:00
elif [ "$_ACME_WGET" ]; then
2016-11-21 13:56:50 +01:00
_WGET="$_ACME_WGET"
if [ "$HTTPS_INSECURE" ]; then
_WGET="$_WGET --no-check-certificate "
fi
if [ "$httpmethod" = "HEAD" ]; then
_WGET="$_WGET --read-timeout=3.0 --tries=2 "
fi
2016-11-21 13:56:50 +01:00
_debug "_WGET" "$_WGET"
2016-11-09 12:30:39 +01:00
if [ "$needbase64" ]; then
if [ "$httpmethod" = "POST" ]; then
if [ "$_postContentType" ]; then
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)"
else
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)"
fi
else
if [ "$_postContentType" ]; then
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)"
else
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)"
fi
fi
else
2016-11-09 12:30:39 +01:00
if [ "$httpmethod" = "POST" ]; then
if [ "$_postContentType" ]; then
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
else
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
fi
elif [ "$httpmethod" = "HEAD" ]; then
if [ "$_postContentType" ]; then
response="$($_WGET --spider -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
else
response="$($_WGET --spider -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
fi
else
if [ "$_postContentType" ]; then
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
else
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
fi
fi
fi
2016-05-31 06:12:30 +02:00
_ret="$?"
2016-11-09 12:30:39 +01:00
if [ "$_ret" = "8" ]; then
2016-10-03 16:08:40 +02:00
_ret=0
2017-02-28 14:08:20 +01:00
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
2016-10-03 16:08:40 +02:00
fi
2016-11-09 12:30:39 +01:00
if [ "$_ret" != "0" ]; then
_err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
2016-06-25 03:29:23 +02:00
fi
_sed_i "s/^ *//g" "$HTTP_HEADER"
2016-07-02 07:46:35 +02:00
else
_ret="$?"
_err "Neither curl nor wget is found, can not do $httpmethod."
fi
2016-05-31 06:12:30 +02:00
_debug "_ret" "$_ret"
2016-05-13 15:14:00 +02:00
printf "%s" "$response"
2016-05-31 06:12:30 +02:00
return $_ret
}
# url getheader timeout
_get() {
2016-05-07 17:33:42 +02:00
_debug GET
url="$1"
onlyheader="$2"
t="$3"
2016-11-09 14:18:47 +01:00
_debug url "$url"
2018-01-06 10:39:15 +01:00
_debug "timeout=$t"
2016-08-14 16:37:21 +02:00
_inithttp
if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then
2016-10-28 14:56:18 +02:00
_CURL="$_ACME_CURL"
2016-11-21 13:56:50 +01:00
if [ "$HTTPS_INSECURE" ]; then
_CURL="$_CURL --insecure "
fi
2016-11-09 12:30:39 +01:00
if [ "$t" ]; then
_CURL="$_CURL --connect-timeout $t"
fi
_debug "_CURL" "$_CURL"
2016-11-09 12:30:39 +01:00
if [ "$onlyheader" ]; then
2016-11-09 14:06:22 +01:00
$_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url"
else
2016-11-09 14:06:22 +01:00
$_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url"
fi
2016-05-31 15:20:10 +02:00
ret=$?
2016-11-09 12:30:39 +01:00
if [ "$ret" != "0" ]; then
2016-08-14 17:20:53 +02:00
_err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
2016-11-09 12:30:39 +01:00
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
2016-08-14 16:37:21 +02:00
_err "Here is the curl dump log:"
_err "$(cat "$_CURL_DUMP")"
fi
fi
2016-11-09 12:30:39 +01:00
elif [ "$_ACME_WGET" ]; then
2016-10-28 14:56:18 +02:00
_WGET="$_ACME_WGET"
2016-11-21 13:56:50 +01:00
if [ "$HTTPS_INSECURE" ]; then
_WGET="$_WGET --no-check-certificate "
fi
2016-11-09 12:30:39 +01:00
if [ "$t" ]; then
_WGET="$_WGET --timeout=$t"
fi
_debug "_WGET" "$_WGET"
2016-11-09 12:30:39 +01:00
if [ "$onlyheader" ]; then
2016-11-09 14:06:22 +01:00
$_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null "$url" 2>&1 | sed 's/^[ ]*//g'
else
2016-11-09 14:06:22 +01:00
$_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - "$url"
fi
2016-05-31 15:20:10 +02:00
ret=$?
2017-02-28 14:06:02 +01:00
if [ "$ret" = "8" ]; then
2017-02-28 14:04:33 +01:00
ret=0
2017-02-28 14:08:20 +01:00
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
2016-10-03 16:08:40 +02:00
fi
2016-11-09 12:30:39 +01:00
if [ "$ret" != "0" ]; then
_err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
2016-08-14 16:37:21 +02:00
fi
2016-07-02 07:46:35 +02:00
else
ret=$?
_err "Neither curl nor wget is found, can not do GET."
2016-05-31 15:20:10 +02:00
fi
2016-05-31 15:38:41 +02:00
_debug "ret" "$ret"
return $ret
}
2016-10-03 16:29:48 +02:00
_head_n() {
2016-11-09 14:18:47 +01:00
head -n "$1"
2016-10-03 16:29:48 +02:00
}
_tail_n() {
2016-11-09 14:06:22 +01:00
if ! tail -n "$1" 2>/dev/null; then
2016-10-05 07:03:45 +02:00
#fix for solaris
2016-11-09 14:06:22 +01:00
tail -"$1"
2016-10-05 07:03:45 +02:00
fi
2016-10-03 16:29:48 +02:00
}
2016-08-14 16:37:21 +02:00
# url payload needbase64 keyfile
2016-03-08 13:44:12 +01:00
_send_signed_request() {
url=$1
payload=$2
needbase64=$3
keyfile=$4
2016-11-09 12:30:39 +01:00
if [ -z "$keyfile" ]; then
keyfile="$ACCOUNT_KEY_PATH"
fi
2016-11-09 14:06:22 +01:00
_debug url "$url"
2016-03-08 13:44:12 +01:00
_debug payload "$payload"
2016-11-09 12:30:39 +01:00
if ! _calcjwk "$keyfile"; then
return 1
fi
__request_conent_type="$CONTENT_TYPE_JSON"
2017-01-29 04:47:04 +01:00
payload64=$(printf "%s" "$payload" | _base64 | _url_replace)
2016-11-09 14:06:22 +01:00
_debug3 payload64 "$payload64"
2016-11-09 12:30:39 +01:00
2018-07-28 16:02:03 +02:00
MAX_REQUEST_RETRY_TIMES=20
_sleep_retry_sec=1
_request_retry_times=0
while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do
_request_retry_times=$(_math "$_request_retry_times" + 1)
2017-02-17 07:40:58 +01:00
_debug3 _request_retry_times "$_request_retry_times"
if [ -z "$_CACHED_NONCE" ]; then
2017-06-19 14:24:31 +02:00
_headers=""
if [ "$ACME_NEW_NONCE" ]; then
_debug2 "Get nonce with HEAD. ACME_NEW_NONCE" "$ACME_NEW_NONCE"
nonceurl="$ACME_NEW_NONCE"
if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type" >/dev/null; 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 "$_CACHED_NONCE" ]; then
2018-09-25 17:42:04 +02:00
_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
else
_debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE"
fi
nonce="$_CACHED_NONCE"
_debug2 nonce "$nonce"
if [ -z "$nonce" ]; then
_info "Could not get nonce, let's try again."
_sleep 2
continue
fi
2018-01-06 05:45:24 +01:00
if [ "$ACME_VERSION" = "2" ]; then
if [ "$url" = "$ACME_NEW_ACCOUNT" ]; then
protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}'
elif [ "$url" = "$ACME_REVOKE_CERT" ] && [ "$keyfile" != "$ACCOUNT_KEY_PATH" ]; then
2018-01-06 05:45:24 +01:00
protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}'
else
protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"kid\": \"${ACCOUNT_URL}\""'}'
2018-01-06 05:45:24 +01:00
fi
else
protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}'
fi
_debug3 protected "$protected"
2016-05-31 14:16:57 +02:00
protected64="$(printf "%s" "$protected" | _base64 | _url_replace)"
_debug3 protected64 "$protected64"
2016-11-09 12:30:39 +01:00
if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then
_err "Sign request failed."
return 1
fi
_debug3 _sig_t "$_sig_t"
sig="$(printf "%s" "$_sig_t" | _url_replace)"
_debug3 sig "$sig"
2016-11-09 12:30:39 +01:00
body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
_debug3 body "$body"
2016-11-09 12:30:39 +01:00
response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")"
_CACHED_NONCE=""
2016-03-19 15:04:03 +01:00
if [ "$?" != "0" ]; then
_err "Can not post to $url"
return 1
fi
2016-03-08 13:44:12 +01:00
2017-02-18 03:31:18 +01:00
responseHeaders="$(cat "$HTTP_HEADER")"
_debug2 responseHeaders "$responseHeaders"
2019-02-17 07:19:14 +01:00
code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")"
_debug code "$code"
2016-11-09 12:30:39 +01:00
2019-02-17 07:19:14 +01:00
_debug2 original "$response"
if echo "$responseHeaders" | grep -i "Content-Type: *application/json" >/dev/null 2>&1; then
response="$(echo "$response" | _normalizeJson | _json_decode)"
fi
2019-02-17 07:19:14 +01:00
_debug2 response "$response"
2017-09-11 15:28:37 +02:00
2019-02-17 07:19:14 +01:00
_CACHED_NONCE="$(echo "$responseHeaders" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
2019-02-17 07:26:27 +01:00
if ! _startswith "$code" "2"; then
2019-02-17 07:19:14 +01:00
_body="$response"
if [ "$needbase64" ]; then
_body="$(echo "$_body" | _dbase64 multiline)"
_debug3 _body "$_body"
fi
if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then
_info "It seems the CA server is busy now, let's wait and retry. Sleeping $_sleep_retry_sec seconds."
_CACHED_NONCE=""
_sleep $_sleep_retry_sec
continue
fi
fi
return 0
done
_info "Giving up sending to CA server after $MAX_REQUEST_RETRY_TIMES retries."
return 1
2016-03-08 13:44:12 +01:00
}
#setopt "file" "opt" "=" "value" [";"]
_setopt() {
__conf="$1"
__opt="$2"
__sep="$3"
__val="$4"
__end="$5"
2016-11-09 12:30:39 +01:00
if [ -z "$__opt" ]; then
_usage usage: _setopt '"file" "opt" "=" "value" [";"]'
2016-03-08 13:44:12 +01:00
return
fi
2016-11-09 12:30:39 +01:00
if [ ! -f "$__conf" ]; then
2016-03-08 13:44:12 +01:00
touch "$__conf"
fi
2016-11-09 12:30:39 +01:00
if grep -n "^$__opt$__sep" "$__conf" >/dev/null; then
_debug3 OK
2016-11-09 12:30:39 +01:00
if _contains "$__val" "&"; then
2016-11-09 14:18:47 +01:00
__val="$(echo "$__val" | sed 's/&/\\&/g')"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 14:18:47 +01:00
text="$(cat "$__conf")"
printf -- "%s\n" "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf"
2016-03-08 13:44:12 +01:00
2016-11-09 12:30:39 +01:00
elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then
if _contains "$__val" "&"; then
2016-11-09 14:18:47 +01:00
__val="$(echo "$__val" | sed 's/&/\\&/g')"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 14:18:47 +01:00
text="$(cat "$__conf")"
printf -- "%s\n" "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf"
2016-03-08 13:44:12 +01:00
else
_debug3 APP
2016-11-09 12:30:39 +01:00
echo "$__opt$__sep$__val$__end" >>"$__conf"
2016-03-08 13:44:12 +01:00
fi
2017-02-20 13:18:58 +01:00
_debug3 "$(grep -n "^$__opt$__sep" "$__conf")"
2016-03-08 13:44:12 +01:00
}
#_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
2016-11-09 12:30:39 +01:00
if [ "$_s_c_f" ]; then
_setopt "$_s_c_f" "$_sdkey" "=" "'$_sdvalue'"
2016-04-27 16:14:15 +02:00
else
_err "config file is empty, can not save $_sdkey=$_sdvalue"
2016-04-27 16:14:15 +02:00
fi
}
#_clear_conf file key
_clear_conf() {
_c_c_f="$1"
_sdkey="$2"
2016-11-09 12:30:39 +01:00
if [ "$_c_c_f" ]; then
2016-11-14 10:47:22 +01:00
_conf_data="$(cat "$_c_c_f")"
2016-11-16 15:44:39 +01:00
echo "$_conf_data" | sed "s/^$_sdkey *=.*$//" >"$_c_c_f"
2016-03-08 13:44:12 +01:00
else
_err "config file is empty, can not clear"
2016-03-08 13:44:12 +01:00
fi
}
#_read_conf file key
_read_conf() {
_r_c_f="$1"
_sdkey="$2"
2016-11-09 12:30:39 +01:00
if [ -f "$_r_c_f" ]; then
2019-04-06 10:48:17 +02:00
_sdv="$(
eval "$(grep "^$_sdkey *=" "$_r_c_f")"
eval "printf \"%s\" \"\$$_sdkey\""
2019-04-06 10:45:58 +02:00
)"
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"
2016-03-08 13:44:12 +01:00
fi
}
#_savedomainconf key value base64encode
2016-03-08 13:44:12 +01:00
#save to domain.conf
_savedomainconf() {
_save_conf "$DOMAIN_CONF" "$@"
2016-04-27 16:14:15 +02:00
}
#_cleardomainconf key
_cleardomainconf() {
_clear_conf "$DOMAIN_CONF" "$1"
2016-03-08 13:44:12 +01:00
}
#_readdomainconf key
_readdomainconf() {
_read_conf "$DOMAIN_CONF" "$1"
}
2019-06-02 13:36:11 +02:00
#key value base64encode
_savedeployconf() {
_savedomainconf "SAVED_$1" "$2" "$3"
#remove later
2019-06-02 14:04:36 +02:00
_cleardomainconf "$1"
2019-06-02 13:36:11 +02:00
}
#key
_getdeployconf() {
_rac_key="$1"
2019-06-03 14:55:22 +02:00
_rac_value="$(eval echo \$"$_rac_key")"
if [ "$_rac_value" ]; then
if _startswith "$_rac_value" '"' && _endswith "$_rac_value" '"'; then
_debug2 "trim quotation marks"
2019-06-10 16:40:14 +02:00
eval "export $_rac_key=$_rac_value"
2019-06-03 14:55:22 +02:00
fi
2019-06-02 13:36:11 +02:00
return 0 # do nothing
fi
_saved=$(_readdomainconf "SAVED_$_rac_key")
eval "export $_rac_key=\"$_saved\""
2019-06-02 13:36:11 +02:00
}
#_saveaccountconf key value base64encode
2016-03-08 13:44:12 +01:00
_saveaccountconf() {
_save_conf "$ACCOUNT_CONF_PATH" "$@"
2016-03-08 13:44:12 +01:00
}
#key value base64encode
2017-04-11 15:37:56 +02:00
_saveaccountconf_mutable() {
_save_conf "$ACCOUNT_CONF_PATH" "SAVED_$1" "$2" "$3"
2017-04-11 15:37:56 +02:00
#remove later
_clearaccountconf "$1"
}
#key
_readaccountconf() {
_read_conf "$ACCOUNT_CONF_PATH" "$1"
}
#key
_readaccountconf_mutable() {
_rac_key="$1"
_readaccountconf "SAVED_$_rac_key"
}
2016-08-14 16:37:21 +02:00
#_clearaccountconf key
_clearaccountconf() {
_clear_conf "$ACCOUNT_CONF_PATH" "$1"
}
#_savecaconf key value
_savecaconf() {
_save_conf "$CA_CONF" "$1" "$2"
}
#_readcaconf key
_readcaconf() {
_read_conf "$CA_CONF" "$1"
}
#_clearaccountconf key
_clearcaconf() {
_clear_conf "$CA_CONF" "$1"
2016-08-14 16:37:21 +02:00
}
# content localaddress
2016-03-08 13:44:12 +01:00
_startserver() {
content="$1"
ncaddr="$2"
_debug "content" "$content"
_debug "ncaddr" "$ncaddr"
2016-04-12 17:18:22 +02:00
_debug "startserver: $$"
2016-11-09 12:30:39 +01:00
_debug Le_HTTPPort "$Le_HTTPPort"
_debug Le_Listen_V4 "$Le_Listen_V4"
_debug Le_Listen_V6 "$Le_Listen_V6"
2016-11-09 12:30:39 +01:00
_NC="socat"
2016-11-09 12:30:39 +01:00
if [ "$Le_Listen_V4" ]; then
_NC="$_NC -4"
2016-11-09 12:30:39 +01:00
elif [ "$Le_Listen_V6" ]; then
_NC="$_NC -6"
fi
2016-11-09 12:30:39 +01:00
if [ "$DEBUG" ] && [ "$DEBUG" -gt "1" ]; then
_NC="$_NC -d -d -v"
fi
SOCAT_OPTIONS=TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork
#Adding bind to local-address
if [ "$ncaddr" ]; then
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 'Content-Length\: $_content_len'; \
echo ''; \
2019-03-16 07:28:24 +01:00
printf -- '$content';" &
serverproc="$!"
2016-03-08 13:44:12 +01:00
}
2016-11-09 12:30:39 +01:00
_stopserver() {
2016-03-08 13:44:12 +01:00
pid="$1"
2016-04-12 17:18:22 +02:00
_debug "pid" "$pid"
2016-11-09 12:30:39 +01:00
if [ -z "$pid" ]; then
2016-04-12 17:18:22 +02:00
return
fi
kill $pid
2016-03-08 13:44:12 +01:00
}
2016-09-30 16:13:27 +02:00
# sleep sec
_sleep() {
_sleep_sec="$1"
2016-11-09 12:30:39 +01:00
if [ "$__INTERACTIVE" ]; then
2016-09-30 16:13:27 +02:00
_sleep_c="$_sleep_sec"
2016-11-09 12:30:39 +01:00
while [ "$_sleep_c" -ge "0" ]; do
2016-09-30 16:43:24 +02:00
printf "\r \r"
2016-09-30 16:13:27 +02:00
__green "$_sleep_c"
2016-11-09 14:18:47 +01:00
_sleep_c="$(_math "$_sleep_c" - 1)"
2016-09-30 16:13:27 +02:00
sleep 1
done
2016-09-30 16:43:24 +02:00
printf "\r"
2016-09-30 16:13:27 +02:00
else
sleep "$_sleep_sec"
fi
}
# _starttlsserver san_a san_b port content _ncaddr acmeValidationv1
_starttlsserver() {
_info "Starting tls server."
san_a="$1"
san_b="$2"
port="$3"
content="$4"
opaddr="$5"
acmeValidationv1="$6"
2016-11-09 12:30:39 +01:00
_debug san_a "$san_a"
_debug san_b "$san_b"
_debug port "$port"
_debug acmeValidationv1 "$acmeValidationv1"
2016-11-09 12:30:39 +01:00
#create key TLS_KEY
2016-11-09 12:30:39 +01:00
if ! _createkey "2048" "$TLS_KEY"; then
_err "Create tls validation key error."
return 1
fi
2016-11-09 12:30:39 +01:00
#create csr
alt="$san_a"
2016-11-09 12:30:39 +01:00
if [ "$san_b" ]; then
alt="$alt,$san_b"
fi
if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$acmeValidationv1"; then
_err "Create tls validation csr error."
return 1
fi
2016-11-09 12:30:39 +01:00
#self signed
2016-11-09 12:30:39 +01:00
if ! _signcsr "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$TLS_CERT"; then
_err "Create tls validation cert error."
return 1
fi
2016-11-09 12:30:39 +01:00
__S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -www -cert $TLS_CERT -key $TLS_KEY "
if [ "$opaddr" ]; then
__S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port"
else
__S_OPENSSL="$__S_OPENSSL -accept $port"
fi
_debug Le_Listen_V4 "$Le_Listen_V4"
_debug Le_Listen_V6 "$Le_Listen_V6"
2016-11-09 12:30:39 +01:00
if [ "$Le_Listen_V4" ]; then
__S_OPENSSL="$__S_OPENSSL -4"
2016-11-09 12:30:39 +01:00
elif [ "$Le_Listen_V6" ]; then
__S_OPENSSL="$__S_OPENSSL -6"
fi
2016-11-09 12:30:39 +01:00
if [ "$acmeValidationv1" ]; then
__S_OPENSSL="$__S_OPENSSL -alpn acme-tls/1"
fi
_debug "$__S_OPENSSL"
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
$__S_OPENSSL -tlsextdebug &
else
$__S_OPENSSL >/dev/null 2>&1 &
fi
2016-06-17 14:54:22 +02:00
serverproc="$!"
2016-10-29 04:53:45 +02:00
sleep 1
2016-11-09 14:44:46 +01:00
_debug serverproc "$serverproc"
}
#file
_readlink() {
_rf="$1"
if ! readlink -f "$_rf" 2>/dev/null; then
2017-02-03 04:13:38 +01:00
if _startswith "$_rf" "/"; then
echo "$_rf"
2016-09-22 15:38:11 +02:00
return 0
fi
2017-02-03 04:13:38 +01:00
echo "$(pwd)/$_rf" | _conapath
fi
}
2017-02-03 04:13:38 +01:00
_conapath() {
sed "s#/\./#/#g"
}
2016-09-19 17:07:43 +02:00
__initHome() {
2016-11-09 12:30:39 +01:00
if [ -z "$_SCRIPT_HOME" ]; then
if _exists readlink && _exists dirname; then
2016-10-09 16:27:25 +02:00
_debug "Lets find script dir."
_debug "_SCRIPT_" "$_SCRIPT_"
_script="$(_readlink "$_SCRIPT_")"
_debug "_script" "$_script"
_script_home="$(dirname "$_script")"
_debug "_script_home" "$_script_home"
2016-11-09 12:30:39 +01:00
if [ -d "$_script_home" ]; then
_SCRIPT_HOME="$_script_home"
else
_err "It seems the script home is not correct:$_script_home"
fi
fi
fi
2016-12-02 13:30:52 +01:00
# if [ -z "$LE_WORKING_DIR" ]; then
# if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then
# _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME"
# LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
# else
# LE_WORKING_DIR="$_SCRIPT_HOME"
# fi
# fi
2016-11-09 12:30:39 +01:00
if [ -z "$LE_WORKING_DIR" ]; then
_debug "Using default home:$DEFAULT_INSTALL_HOME"
LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
fi
2016-09-22 15:38:11 +02:00
export LE_WORKING_DIR
2017-01-21 04:28:10 +01:00
if [ -z "$LE_CONFIG_HOME" ]; then
LE_CONFIG_HOME="$LE_WORKING_DIR"
2017-01-16 15:31:24 +01:00
fi
2017-01-21 04:28:10 +01:00
_debug "Using config home:$LE_CONFIG_HOME"
export LE_CONFIG_HOME
2017-01-16 15:31:24 +01:00
2017-01-21 04:28:10 +01:00
_DEFAULT_ACCOUNT_CONF_PATH="$LE_CONFIG_HOME/account.conf"
2016-04-11 16:33:57 +02:00
2016-11-09 12:30:39 +01:00
if [ -z "$ACCOUNT_CONF_PATH" ]; then
if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]; then
. "$_DEFAULT_ACCOUNT_CONF_PATH"
fi
2016-04-11 16:33:57 +02:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$ACCOUNT_CONF_PATH" ]; then
2016-04-11 16:33:57 +02:00
ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH"
2016-03-08 13:44:12 +01:00
fi
2020-01-15 15:01:34 +01:00
_debug3 ACCOUNT_CONF_PATH "$ACCOUNT_CONF_PATH"
2017-01-21 04:28:10 +01:00
DEFAULT_LOG_FILE="$LE_CONFIG_HOME/$PROJECT_NAME.log"
2016-11-09 12:30:39 +01:00
2017-01-21 04:28:10 +01:00
DEFAULT_CA_HOME="$LE_CONFIG_HOME/ca"
2016-11-09 12:30:39 +01:00
if [ -z "$LE_TEMP_DIR" ]; then
2017-01-21 04:28:10 +01:00
LE_TEMP_DIR="$LE_CONFIG_HOME/tmp"
2016-11-01 13:29:58 +01:00
fi
2016-09-19 17:07:43 +02:00
}
2017-06-17 09:49:45 +02:00
#server
_initAPI() {
_api_server="${1:-$ACME_DIRECTORY}"
_debug "_init api for server: $_api_server"
2017-06-17 09:59:27 +02:00
if [ -z "$ACME_NEW_ACCOUNT" ]; then
2017-06-17 09:49:45 +02:00
response=$(_get "$_api_server")
if [ "$?" != "0" ]; then
_debug2 "response" "$response"
_err "Can not init api."
return 1
fi
response=$(echo "$response" | _json_decode)
2017-06-17 09:49:45 +02:00
_debug2 "response" "$response"
ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3)
2018-01-06 05:45:24 +01:00
if [ -z "$ACME_KEY_CHANGE" ]; then
ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'keyChange" *: *"[^"]*"' | cut -d '"' -f 3)
fi
2017-06-17 09:49:45 +02:00
export ACME_KEY_CHANGE
ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3)
2018-01-06 05:45:24 +01:00
if [ -z "$ACME_NEW_AUTHZ" ]; then
ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'newAuthz" *: *"[^"]*"' | cut -d '"' -f 3)
fi
2017-06-17 09:49:45 +02:00
export ACME_NEW_AUTHZ
ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3)
2017-07-02 12:05:55 +02:00
ACME_NEW_ORDER_RES="new-cert"
if [ -z "$ACME_NEW_ORDER" ]; then
ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3)
2017-07-02 12:05:55 +02:00
ACME_NEW_ORDER_RES="new-order"
2018-01-06 05:45:24 +01:00
if [ -z "$ACME_NEW_ORDER" ]; then
ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'newOrder" *: *"[^"]*"' | cut -d '"' -f 3)
fi
fi
export ACME_NEW_ORDER
2017-07-02 12:05:55 +02:00
export ACME_NEW_ORDER_RES
2017-06-17 09:49:45 +02:00
ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3)
2017-07-02 12:05:55 +02:00
ACME_NEW_ACCOUNT_RES="new-reg"
if [ -z "$ACME_NEW_ACCOUNT" ]; then
ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3)
2017-07-02 12:05:55 +02:00
ACME_NEW_ACCOUNT_RES="new-account"
2018-01-06 05:45:24 +01:00
if [ -z "$ACME_NEW_ACCOUNT" ]; then
ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'newAccount" *: *"[^"]*"' | cut -d '"' -f 3)
if [ "$ACME_NEW_ACCOUNT" ]; then
export ACME_VERSION=2
fi
fi
fi
export ACME_NEW_ACCOUNT
2017-07-02 12:05:55 +02:00
export ACME_NEW_ACCOUNT_RES
2017-06-17 09:49:45 +02:00
ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3)
2018-01-06 05:45:24 +01:00
if [ -z "$ACME_REVOKE_CERT" ]; then
ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revokeCert" *: *"[^"]*"' | cut -d '"' -f 3)
fi
2017-06-17 09:49:45 +02:00
export ACME_REVOKE_CERT
ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3)
2018-01-06 05:45:24 +01:00
if [ -z "$ACME_NEW_NONCE" ]; then
ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'newNonce" *: *"[^"]*"' | cut -d '"' -f 3)
fi
export ACME_NEW_NONCE
2017-12-08 12:54:25 +01:00
ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3)
2018-01-06 05:45:24 +01:00
if [ -z "$ACME_AGREEMENT" ]; then
ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3)
fi
export ACME_AGREEMENT
_debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE"
_debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ"
_debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER"
_debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT"
_debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT"
_debug "ACME_AGREEMENT" "$ACME_AGREEMENT"
2018-01-06 05:45:24 +01:00
_debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE"
_debug "ACME_VERSION" "$ACME_VERSION"
2017-06-17 09:49:45 +02:00
fi
2017-06-17 09:49:45 +02:00
}
#[domain] [keylength or isEcc flag]
2016-09-19 17:07:43 +02:00
_initpath() {
domain="$1"
_ilength="$2"
2016-09-19 17:07:43 +02:00
__initHome
2016-11-09 12:30:39 +01:00
if [ -f "$ACCOUNT_CONF_PATH" ]; then
. "$ACCOUNT_CONF_PATH"
2016-03-08 13:44:12 +01:00
fi
2020-08-16 11:36:24 +02:00
if [ "$_ACME_IN_CRON" ]; then
2016-11-09 12:30:39 +01:00
if [ ! "$_USER_PATH_EXPORTED" ]; then
2016-04-05 15:08:19 +02:00
_USER_PATH_EXPORTED=1
export PATH="$USER_PATH:$PATH"
fi
fi
2016-11-09 12:30:39 +01:00
if [ -z "$CA_HOME" ]; then
2016-09-27 17:43:18 +02:00
CA_HOME="$DEFAULT_CA_HOME"
fi
2016-04-05 15:08:19 +02:00
2017-06-17 09:49:45 +02:00
if [ -z "$ACME_DIRECTORY" ]; then
2020-08-15 04:33:24 +02:00
if [ "$STAGE" ]; then
ACME_DIRECTORY="$DEFAULT_STAGING_CA"
2020-08-16 11:36:24 +02:00
_info "Using ACME_DIRECTORY: $ACME_DIRECTORY"
2016-03-08 13:44:12 +01:00
else
2020-08-15 04:33:24 +02:00
default_acme_server=$(_readaccountconf "DEFAULT_ACME_SERVER")
_debug default_acme_server "$default_acme_server"
if [ "$default_acme_server" ]; then
ACME_DIRECTORY="$default_acme_server"
else
2020-08-15 04:33:24 +02:00
ACME_DIRECTORY="$DEFAULT_CA"
fi
2016-11-09 12:30:39 +01:00
fi
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
2018-03-14 13:52:18 +01:00
_debug ACME_DIRECTORY "$ACME_DIRECTORY"
2017-06-19 14:19:30 +02:00
_ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)"
2017-06-17 09:49:45 +02:00
_debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST"
CA_DIR="$CA_HOME/$_ACME_SERVER_HOST"
2016-11-09 12:30:39 +01:00
2016-09-27 17:43:18 +02:00
_DEFAULT_CA_CONF="$CA_DIR/ca.conf"
2016-11-09 12:30:39 +01:00
if [ -z "$CA_CONF" ]; then
2016-09-27 17:43:18 +02:00
CA_CONF="$_DEFAULT_CA_CONF"
fi
2016-12-10 14:32:47 +01:00
_debug3 CA_CONF "$CA_CONF"
2016-11-09 12:30:39 +01:00
if [ -f "$CA_CONF" ]; then
2016-09-27 17:43:18 +02:00
. "$CA_CONF"
fi
2016-11-09 12:30:39 +01:00
if [ -z "$ACME_DIR" ]; then
2016-03-08 13:44:12 +01:00
ACME_DIR="/home/.acme"
fi
2016-11-09 12:30:39 +01:00
if [ -z "$APACHE_CONF_BACKUP_DIR" ]; then
2017-01-21 04:28:10 +01:00
APACHE_CONF_BACKUP_DIR="$LE_CONFIG_HOME"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$USER_AGENT" ]; then
2016-03-19 15:04:03 +01:00
USER_AGENT="$DEFAULT_USER_AGENT"
fi
2016-11-09 12:30:39 +01:00
if [ -z "$HTTP_HEADER" ]; then
2017-01-21 04:28:10 +01:00
HTTP_HEADER="$LE_CONFIG_HOME/http.header"
2016-08-17 07:17:06 +02:00
fi
2016-09-27 17:43:18 +02:00
_OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key"
_OLD_ACCOUNT_JSON="$LE_WORKING_DIR/account.json"
2016-11-09 12:30:39 +01:00
2016-09-27 17:43:18 +02:00
_DEFAULT_ACCOUNT_KEY_PATH="$CA_DIR/account.key"
_DEFAULT_ACCOUNT_JSON_PATH="$CA_DIR/account.json"
2016-11-09 12:30:39 +01:00
if [ -z "$ACCOUNT_KEY_PATH" ]; then
ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$ACCOUNT_JSON_PATH" ]; then
2016-09-27 17:43:18 +02:00
ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH"
fi
2016-11-09 12:30:39 +01:00
2017-01-21 04:28:10 +01:00
_DEFAULT_CERT_HOME="$LE_CONFIG_HOME"
2016-11-09 12:30:39 +01:00
if [ -z "$CERT_HOME" ]; then
CERT_HOME="$_DEFAULT_CERT_HOME"
fi
2017-02-25 12:12:20 +01:00
if [ -z "$ACME_OPENSSL_BIN" ] || [ ! -f "$ACME_OPENSSL_BIN" ] || [ ! -x "$ACME_OPENSSL_BIN" ]; then
2017-02-25 12:08:00 +01:00
ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN"
fi
if [ -z "$domain" ]; then
2016-03-08 13:44:12 +01:00
return 0
fi
2016-11-09 12:30:39 +01:00
if [ -z "$DOMAIN_PATH" ]; then
domainhome="$CERT_HOME/$domain"
domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX"
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
DOMAIN_PATH="$domainhome"
2016-11-09 12:30:39 +01:00
if _isEccKey "$_ilength"; then
DOMAIN_PATH="$domainhomeecc"
else
2016-11-09 12:30:39 +01:00
if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ]; then
_info "The domain '$domain' seems to have a ECC cert already, please add '$(__red "--ecc")' parameter if you want to use that cert."
fi
fi
_debug DOMAIN_PATH "$DOMAIN_PATH"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$DOMAIN_BACKUP_PATH" ]; then
2017-02-12 03:20:50 +01:00
DOMAIN_BACKUP_PATH="$DOMAIN_PATH/backup"
fi
2016-11-09 12:30:39 +01:00
if [ -z "$DOMAIN_CONF" ]; then
DOMAIN_CONF="$DOMAIN_PATH/$domain.conf"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$DOMAIN_SSL_CONF" ]; then
DOMAIN_SSL_CONF="$DOMAIN_PATH/$domain.csr.conf"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$CSR_PATH" ]; then
CSR_PATH="$DOMAIN_PATH/$domain.csr"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$CERT_KEY_PATH" ]; then
CERT_KEY_PATH="$DOMAIN_PATH/$domain.key"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$CERT_PATH" ]; then
CERT_PATH="$DOMAIN_PATH/$domain.cer"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$CA_CERT_PATH" ]; then
CA_CERT_PATH="$DOMAIN_PATH/ca.cer"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$CERT_FULLCHAIN_PATH" ]; then
CERT_FULLCHAIN_PATH="$DOMAIN_PATH/fullchain.cer"
2016-03-13 04:37:14 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$CERT_PFX_PATH" ]; then
CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx"
fi
if [ -z "$CERT_PKCS8_PATH" ]; then
CERT_PKCS8_PATH="$DOMAIN_PATH/$domain.pkcs8"
fi
2016-11-09 12:30:39 +01:00
if [ -z "$TLS_CONF" ]; then
2017-03-26 07:32:29 +02:00
TLS_CONF="$DOMAIN_PATH/tls.validation.conf"
fi
2016-11-09 12:30:39 +01:00
if [ -z "$TLS_CERT" ]; then
2017-03-26 07:32:29 +02:00
TLS_CERT="$DOMAIN_PATH/tls.validation.cert"
fi
2016-11-09 12:30:39 +01:00
if [ -z "$TLS_KEY" ]; then
2017-03-26 07:32:29 +02:00
TLS_KEY="$DOMAIN_PATH/tls.validation.key"
fi
2016-11-09 12:30:39 +01:00
if [ -z "$TLS_CSR" ]; then
2017-03-26 07:32:29 +02:00
TLS_CSR="$DOMAIN_PATH/tls.validation.csr"
fi
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
}
2016-11-01 13:29:58 +01:00
_exec() {
2016-11-09 12:30:39 +01:00
if [ -z "$_EXEC_TEMP_ERR" ]; then
2016-11-01 13:29:58 +01:00
_EXEC_TEMP_ERR="$(_mktemp)"
fi
2016-11-09 12:30:39 +01:00
if [ "$_EXEC_TEMP_ERR" ]; then
2016-11-16 15:20:47 +01:00
eval "$@ 2>>$_EXEC_TEMP_ERR"
2016-11-01 13:29:58 +01:00
else
2016-11-16 15:20:47 +01:00
eval "$@"
2016-11-01 13:29:58 +01:00
fi
}
_exec_err() {
2016-11-16 15:20:47 +01:00
[ "$_EXEC_TEMP_ERR" ] && _err "$(cat "$_EXEC_TEMP_ERR")" && echo "" >"$_EXEC_TEMP_ERR"
2016-11-01 13:29:58 +01:00
}
2016-03-08 13:44:12 +01:00
_apachePath() {
2016-07-20 16:18:07 +02:00
_APACHECTL="apachectl"
2016-11-09 12:30:39 +01:00
if ! _exists apachectl; then
if _exists apache2ctl; then
_APACHECTL="apache2ctl"
2016-06-26 05:49:41 +02:00
else
2016-06-27 04:32:51 +02:00
_err "'apachectl not found. It seems that apache is not installed, or you are not root user.'"
2016-06-26 05:49:41 +02:00
_err "Please use webroot mode to try again."
return 1
fi
fi
2016-11-09 12:30:39 +01:00
if ! _exec $_APACHECTL -V >/dev/null; then
2016-11-01 13:29:58 +01:00
_exec_err
return 1
fi
2016-11-09 12:30:39 +01:00
if [ "$APACHE_HTTPD_CONF" ]; then
_saveaccountconf APACHE_HTTPD_CONF "$APACHE_HTTPD_CONF"
httpdconf="$APACHE_HTTPD_CONF"
2016-11-09 14:18:47 +01:00
httpdconfname="$(basename "$httpdconfname")"
else
2016-11-09 12:30:39 +01:00
httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"')"
_debug httpdconfname "$httpdconfname"
2016-11-09 12:30:39 +01:00
if [ -z "$httpdconfname" ]; then
_err "Can not read apache config file."
return 1
fi
2016-11-09 12:30:39 +01:00
if _startswith "$httpdconfname" '/'; then
httpdconf="$httpdconfname"
2016-11-09 14:18:47 +01:00
httpdconfname="$(basename "$httpdconfname")"
else
2016-11-09 12:30:39 +01:00
httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"')"
_debug httpdroot "$httpdroot"
httpdconf="$httpdroot/$httpdconfname"
2016-11-09 14:18:47 +01:00
httpdconfname="$(basename "$httpdconfname")"
fi
fi
2016-05-21 08:47:23 +02:00
_debug httpdconf "$httpdconf"
2016-05-21 09:33:10 +02:00
_debug httpdconfname "$httpdconfname"
2016-11-09 12:30:39 +01:00
if [ ! -f "$httpdconf" ]; then
2016-05-21 08:47:23 +02:00
_err "Apache Config file not found" "$httpdconf"
2016-03-08 13:44:12 +01:00
return 1
fi
return 0
}
_restoreApache() {
2016-11-09 12:30:39 +01:00
if [ -z "$usingApache" ]; then
2016-03-08 13:44:12 +01:00
return 0
fi
_initpath
2016-11-09 12:30:39 +01:00
if ! _apachePath; then
2016-03-08 13:44:12 +01:00
return 1
fi
2016-11-09 12:30:39 +01:00
if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ]; then
2016-03-08 13:44:12 +01:00
_debug "No config file to restore."
return 0
fi
2016-11-09 12:30:39 +01:00
cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" >"$httpdconf"
2016-04-16 12:31:00 +02:00
_debug "Restored: $httpdconf."
2016-11-09 12:30:39 +01:00
if ! _exec $_APACHECTL -t; then
2016-11-01 13:29:58 +01:00
_exec_err
2016-03-08 13:44:12 +01:00
_err "Sorry, restore apache config error, please contact me."
2016-11-09 12:30:39 +01:00
return 1
2016-03-08 13:44:12 +01:00
fi
2016-04-16 12:31:00 +02:00
_debug "Restored successfully."
2016-03-08 13:44:12 +01:00
rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname"
2016-11-09 12:30:39 +01:00
return 0
2016-03-08 13:44:12 +01:00
}
_setApache() {
_initpath
2016-11-09 12:30:39 +01:00
if ! _apachePath; then
2016-03-08 13:44:12 +01:00
return 1
fi
2016-06-15 07:46:45 +02:00
#test the conf first
2016-06-15 07:57:27 +02:00
_info "Checking if there is an error in the apache config file before starting."
2016-11-09 12:30:39 +01:00
2016-11-09 15:35:30 +01:00
if ! _exec "$_APACHECTL" -t >/dev/null; then
2016-11-01 13:29:58 +01:00
_exec_err
_err "The apache config file has error, please fix it first, then try again."
2016-06-15 07:57:27 +02:00
_err "Don't worry, there is nothing changed to your system."
2016-11-09 12:30:39 +01:00
return 1
2016-06-15 07:46:45 +02:00
else
_info "OK"
fi
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
#backup the conf
2016-05-16 16:42:32 +02:00
_debug "Backup apache config file" "$httpdconf"
2016-11-09 12:30:39 +01:00
if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/"; then
2016-06-15 07:57:27 +02:00
_err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed."
2017-03-26 07:29:30 +02:00
_err "This might be a bug of $PROJECT_NAME , please report issue: $PROJECT"
2016-05-21 09:33:10 +02:00
return 1
fi
2016-03-08 13:44:12 +01:00
_info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname"
_info "In case there is an error that can not be restored automatically, you may try restore it yourself."
2016-12-14 21:32:24 +01:00
_info "The backup file will be deleted on success, just forget it."
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
#add alias
2016-11-09 12:30:39 +01:00
apacheVer="$($_APACHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2)"
_debug "apacheVer" "$apacheVer"
apacheMajor="$(echo "$apacheVer" | cut -d . -f 1)"
apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)"
if [ "$apacheVer" ] && [ "$apacheMajor$apacheMinor" -ge "24" ]; then
echo "
2016-03-08 13:44:12 +01:00
Alias /.well-known/acme-challenge $ACME_DIR
<Directory $ACME_DIR >
Require all granted
</Directory>
2016-11-09 12:30:39 +01:00
" >>"$httpdconf"
else
echo "
Alias /.well-known/acme-challenge $ACME_DIR
<Directory $ACME_DIR >
Order allow,deny
Allow from all
2016-03-08 13:44:12 +01:00
</Directory>
2016-11-09 12:30:39 +01:00
" >>"$httpdconf"
fi
2016-11-09 12:30:39 +01:00
_msg="$($_APACHECTL -t 2>&1)"
if [ "$?" != "0" ]; then
2016-06-15 07:46:45 +02:00
_err "Sorry, apache config error"
2016-11-09 12:30:39 +01:00
if _restoreApache; then
2016-06-15 07:57:27 +02:00
_err "The apache config file is restored."
2016-06-15 07:46:45 +02:00
else
2016-06-15 07:57:27 +02:00
_err "Sorry, The apache config file can not be restored, please report bug."
2016-06-15 07:46:45 +02:00
fi
2016-11-09 12:30:39 +01:00
return 1
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ ! -d "$ACME_DIR" ]; then
2016-03-08 13:44:12 +01:00
mkdir -p "$ACME_DIR"
chmod 755 "$ACME_DIR"
fi
2016-11-09 12:30:39 +01:00
2016-11-09 15:35:30 +01:00
if ! _exec "$_APACHECTL" graceful; then
2016-11-09 12:30:39 +01:00
_exec_err
2016-11-01 13:29:58 +01:00
_err "$_APACHECTL graceful error, please contact me."
2016-03-08 13:44:12 +01:00
_restoreApache
2016-11-09 12:30:39 +01:00
return 1
2016-03-08 13:44:12 +01:00
fi
usingApache="1"
return 0
}
2017-02-13 16:29:37 +01:00
#find the real nginx conf file
#backup
#set the nginx conf
#returns the real nginx conf file
_setNginx() {
_d="$1"
_croot="$2"
_thumbpt="$3"
2018-01-19 15:41:42 +01:00
2017-02-13 16:29:37 +01:00
FOUND_REAL_NGINX_CONF=""
FOUND_REAL_NGINX_CONF_LN=""
2017-02-13 16:29:37 +01:00
BACKUP_NGINX_CONF=""
_debug _croot "$_croot"
_start_f="$(echo "$_croot" | cut -d : -f 2)"
_debug _start_f "$_start_f"
if [ -z "$_start_f" ]; then
_debug "find start conf from nginx command"
if [ -z "$NGINX_CONF" ]; then
2018-01-19 15:41:42 +01:00
if ! _exists "nginx"; then
_err "nginx command is not found."
return 1
fi
2017-02-13 16:29:37 +01:00
NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "--conf-path=[^ ]* " | tr -d " ")"
_debug NGINX_CONF "$NGINX_CONF"
NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)"
_debug NGINX_CONF "$NGINX_CONF"
if [ -z "$NGINX_CONF" ]; then
_err "Can not find nginx conf."
NGINX_CONF=""
return 1
fi
2017-02-13 16:29:37 +01:00
if [ ! -f "$NGINX_CONF" ]; then
_err "'$NGINX_CONF' doesn't exist."
NGINX_CONF=""
return 1
fi
_debug "Found nginx conf file:$NGINX_CONF"
fi
_start_f="$NGINX_CONF"
fi
_debug "Start detect nginx conf for $_d from:$_start_f"
2017-02-13 16:29:37 +01:00
if ! _checkConf "$_d" "$_start_f"; then
2017-03-08 06:55:01 +01:00
_err "Can not find conf file for domain $d"
2017-02-13 16:29:37 +01:00
return 1
fi
_info "Found conf file: $FOUND_REAL_NGINX_CONF"
_ln=$FOUND_REAL_NGINX_CONF_LN
_debug "_ln" "$_ln"
_lnn=$(_math $_ln + 1)
_debug _lnn "$_lnn"
_start_tag="$(sed -n "$_lnn,${_lnn}p" "$FOUND_REAL_NGINX_CONF")"
_debug "_start_tag" "$_start_tag"
if [ "$_start_tag" = "$NGINX_START" ]; then
_info "The domain $_d is already configured, skip"
FOUND_REAL_NGINX_CONF=""
return 0
fi
2017-02-13 16:29:37 +01:00
mkdir -p "$DOMAIN_BACKUP_PATH"
_backup_conf="$DOMAIN_BACKUP_PATH/$_d.nginx.conf"
_debug _backup_conf "$_backup_conf"
BACKUP_NGINX_CONF="$_backup_conf"
_info "Backup $FOUND_REAL_NGINX_CONF to $_backup_conf"
if ! cp "$FOUND_REAL_NGINX_CONF" "$_backup_conf"; then
_err "backup error."
FOUND_REAL_NGINX_CONF=""
return 1
fi
2018-01-19 15:41:42 +01:00
if ! _exists "nginx"; then
_err "nginx command is not found."
return 1
fi
2017-02-13 16:29:37 +01:00
_info "Check the nginx conf before setting up."
if ! _exec "nginx -t" >/dev/null; then
_exec_err
return 1
fi
_info "OK, Set up nginx config file"
2017-02-14 15:41:34 +01:00
if ! sed -n "1,${_ln}p" "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"; then
cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"
2017-02-13 16:29:37 +01:00
_err "write nginx conf error, but don't worry, the file is restored to the original version."
return 1
fi
echo "$NGINX_START
2017-02-13 16:29:37 +01:00
location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" {
default_type text/plain;
return 200 \"\$1.$_thumbpt\";
2017-04-17 13:08:34 +02:00
}
#NGINX_START
" >>"$FOUND_REAL_NGINX_CONF"
2017-02-13 16:29:37 +01:00
if ! sed -n "${_lnn},99999p" "$_backup_conf" >>"$FOUND_REAL_NGINX_CONF"; then
cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"
2017-02-13 16:29:37 +01:00
_err "write nginx conf error, but don't worry, the file is restored."
return 1
fi
2017-06-04 16:04:43 +02:00
_debug3 "Modified config:$(cat $FOUND_REAL_NGINX_CONF)"
2017-02-13 16:29:37 +01:00
_info "nginx conf is done, let's check it again."
if ! _exec "nginx -t" >/dev/null; then
_exec_err
_err "It seems that nginx conf was broken, let's restore."
2017-02-14 15:41:34 +01:00
cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"
2017-02-13 16:29:37 +01:00
return 1
fi
_info "Reload nginx"
if ! _exec "nginx -s reload" >/dev/null; then
_exec_err
_err "It seems that nginx reload error, let's restore."
2017-02-14 15:41:34 +01:00
cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"
2017-02-13 16:29:37 +01:00
return 1
fi
return 0
}
#d , conf
_checkConf() {
_d="$1"
_c_file="$2"
_debug "Start _checkConf from:$_c_file"
if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then
_debug "wildcard"
for _w_f in $2; do
2017-04-08 08:50:39 +02:00
if [ -f "$_w_f" ] && _checkConf "$1" "$_w_f"; then
2017-02-13 16:29:37 +01:00
return 0
fi
done
#not found
return 1
elif [ -f "$2" ]; then
_debug "single"
if _isRealNginxConf "$1" "$2"; then
_debug "$2 is found."
FOUND_REAL_NGINX_CONF="$2"
return 0
fi
2017-03-08 09:01:14 +01:00
if cat "$2" | tr "\t" " " | grep "^ *include *.*;" >/dev/null; then
2017-02-13 16:29:37 +01:00
_debug "Try include files"
2017-03-08 09:01:14 +01:00
for included in $(cat "$2" | tr "\t" " " | grep "^ *include *.*;" | sed "s/include //" | tr -d " ;"); do
2017-02-13 16:29:37 +01:00
_debug "check included $included"
if _checkConf "$1" "$included"; then
return 0
fi
done
fi
return 1
else
_debug "$2 not found."
return 1
fi
return 1
}
#d , conf
_isRealNginxConf() {
_debug "_isRealNginxConf $1 $2"
2017-02-14 15:41:34 +01:00
if [ -f "$2" ]; then
for _fln in $(tr "\t" ' ' <"$2" | grep -n "^ *server_name.* $1" | cut -d : -f 1); do
2017-02-14 15:41:34 +01:00
_debug _fln "$_fln"
if [ "$_fln" ]; then
_start=$(tr "\t" ' ' <"$2" | _head_n "$_fln" | grep -n "^ *server *" | grep -v server_name | _tail_n 1)
_debug "_start" "$_start"
_start_n=$(echo "$_start" | cut -d : -f 1)
_start_nn=$(_math $_start_n + 1)
_debug "_start_n" "$_start_n"
_debug "_start_nn" "$_start_nn"
_left="$(sed -n "${_start_nn},99999p" "$2")"
_debug2 _left "$_left"
2018-02-12 13:01:40 +01:00
_end="$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *" | grep -v server_name | _head_n 1)"
_debug "_end" "$_end"
if [ "$_end" ]; then
_end_n=$(echo "$_end" | cut -d : -f 1)
_debug "_end_n" "$_end_n"
_seg_n=$(echo "$_left" | sed -n "1,${_end_n}p")
else
_seg_n="$_left"
fi
_debug "_seg_n" "$_seg_n"
_skip_ssl=1
for _listen_i in $(echo "$_seg_n" | tr "\t" ' ' | grep "^ *listen" | tr -d " "); do
if [ "$_listen_i" ]; then
2018-12-06 15:05:26 +01:00
if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl")" ]; then
_debug2 "$_listen_i is ssl"
else
_debug2 "$_listen_i is plain text"
_skip_ssl=""
2018-01-23 12:42:57 +01:00
break
fi
fi
done
if [ "$_skip_ssl" = "1" ]; then
_debug "ssl on, skip"
else
FOUND_REAL_NGINX_CONF_LN=$_fln
_debug3 "found FOUND_REAL_NGINX_CONF_LN" "$FOUND_REAL_NGINX_CONF_LN"
return 0
2017-06-05 16:55:16 +02:00
fi
2017-02-14 15:41:34 +01:00
fi
done
2017-02-13 16:29:37 +01:00
fi
2017-02-14 15:41:34 +01:00
return 1
2017-02-13 16:29:37 +01:00
}
#restore all the nginx conf
_restoreNginx() {
if [ -z "$NGINX_RESTORE_VLIST" ]; then
2017-02-13 16:29:37 +01:00
_debug "No need to restore nginx, skip."
return
fi
_debug "_restoreNginx"
_debug "NGINX_RESTORE_VLIST" "$NGINX_RESTORE_VLIST"
2017-02-13 16:29:37 +01:00
for ng_entry in $(echo "$NGINX_RESTORE_VLIST" | tr "$dvsep" ' '); do
2017-02-13 16:29:37 +01:00
_debug "ng_entry" "$ng_entry"
_nd=$(echo "$ng_entry" | cut -d "$sep" -f 1)
_ngconf=$(echo "$ng_entry" | cut -d "$sep" -f 2)
_ngbackupconf=$(echo "$ng_entry" | cut -d "$sep" -f 3)
_info "Restoring from $_ngbackupconf to $_ngconf"
2017-02-14 15:41:34 +01:00
cat "$_ngbackupconf" >"$_ngconf"
2017-02-13 16:29:37 +01:00
done
_info "Reload nginx"
if ! _exec "nginx -s reload" >/dev/null; then
_exec_err
_err "It seems that nginx reload error, please report bug."
return 1
fi
return 0
}
2016-04-16 12:31:00 +02:00
_clearup() {
2016-11-09 15:35:30 +01:00
_stopserver "$serverproc"
2016-03-08 13:44:12 +01:00
serverproc=""
_restoreApache
2017-02-13 16:29:37 +01:00
_restoreNginx
_clearupdns
2016-11-09 12:30:39 +01:00
if [ -z "$DEBUG" ]; then
rm -f "$TLS_CONF"
rm -f "$TLS_CERT"
rm -f "$TLS_KEY"
rm -f "$TLS_CSR"
fi
2016-03-08 13:44:12 +01:00
}
_clearupdns() {
_debug "_clearupdns"
_debug "dns_entries" "$dns_entries"
if [ -z "$dns_entries" ]; then
2017-06-15 15:26:14 +02:00
_debug "skip dns."
return
fi
2018-02-10 03:45:29 +01:00
_info "Removing DNS records."
for entry in $dns_entries; do
d=$(_getfield "$entry" 1)
txtdomain=$(_getfield "$entry" 2)
aliasDomain=$(_getfield "$entry" 3)
_currentRoot=$(_getfield "$entry" 4)
txt=$(_getfield "$entry" 5)
d_api=$(_getfield "$entry" 6)
_debug "d" "$d"
_debug "txtdomain" "$txtdomain"
_debug "aliasDomain" "$aliasDomain"
_debug "_currentRoot" "$_currentRoot"
_debug "txt" "$txt"
_debug "d_api" "$d_api"
if [ "$d_api" = "$txt" ]; then
d_api=""
fi
2016-11-09 12:30:39 +01:00
if [ -z "$d_api" ]; then
_info "Not Found domain api file: $d_api"
continue
fi
2016-11-09 12:30:39 +01:00
if [ "$aliasDomain" ]; then
txtdomain="$aliasDomain"
fi
(
2016-11-09 14:44:46 +01:00
if ! . "$d_api"; then
_err "Load file $d_api error. Please check your api file and try again."
return 1
fi
2016-11-09 12:30:39 +01:00
rmcommand="${_currentRoot}_rm"
2016-11-09 14:44:46 +01:00
if ! _exists "$rmcommand"; then
_err "It seems that your api file doesn't define $rmcommand"
return 1
fi
2019-05-17 14:16:26 +02:00
_info "Removing txt: $txt for domain: $txtdomain"
2016-12-06 07:58:36 +01:00
if ! $rmcommand "$txtdomain" "$txt"; then
_err "Error removing txt for domain:$txtdomain"
return 1
fi
2019-05-17 14:16:26 +02:00
_info "Removed: Success"
)
2016-11-09 12:30:39 +01:00
done
}
2016-03-08 13:44:12 +01:00
# webroot removelevel tokenfile
_clearupwebbroot() {
__webroot="$1"
2016-11-09 12:30:39 +01:00
if [ -z "$__webroot" ]; then
2016-03-08 13:44:12 +01:00
_debug "no webroot specified, skip"
return 0
fi
2016-11-09 12:30:39 +01:00
2016-07-15 10:40:03 +02:00
_rmpath=""
2016-11-09 12:30:39 +01:00
if [ "$2" = '1' ]; then
2016-07-15 10:40:03 +02:00
_rmpath="$__webroot/.well-known"
2016-11-09 12:30:39 +01:00
elif [ "$2" = '2' ]; then
2016-07-15 10:40:03 +02:00
_rmpath="$__webroot/.well-known/acme-challenge"
2016-11-09 12:30:39 +01:00
elif [ "$2" = '3' ]; then
2016-07-15 10:40:03 +02:00
_rmpath="$__webroot/.well-known/acme-challenge/$3"
2016-03-08 13:44:12 +01:00
else
2016-06-18 05:29:28 +02:00
_debug "Skip for removelevel:$2"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ "$_rmpath" ]; then
if [ "$DEBUG" ]; then
2016-07-15 10:40:03 +02:00
_debug "Debugging, skip removing: $_rmpath"
else
rm -rf "$_rmpath"
fi
fi
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
return 0
}
_on_before_issue() {
2017-02-19 14:13:00 +01:00
_chk_web_roots="$1"
2017-02-19 14:18:00 +01:00
_chk_main_domain="$2"
_chk_alt_domains="$3"
2017-02-19 15:09:22 +01:00
_chk_pre_hook="$4"
_chk_local_addr="$5"
2016-09-26 07:33:09 +02:00
_debug _on_before_issue
2018-03-14 15:03:58 +01:00
_debug _chk_main_domain "$_chk_main_domain"
_debug _chk_alt_domains "$_chk_alt_domains"
2017-01-03 12:31:11 +01:00
#run pre hook
2017-02-19 15:09:22 +01:00
if [ "$_chk_pre_hook" ]; then
_info "Run pre hook:'$_chk_pre_hook'"
2017-01-03 12:31:11 +01:00
if ! (
2017-02-19 15:09:22 +01:00
cd "$DOMAIN_PATH" && eval "$_chk_pre_hook"
2017-01-03 12:31:11 +01:00
); then
_err "Error when run pre hook."
return 1
fi
fi
2017-02-19 14:13:00 +01:00
if _hasfield "$_chk_web_roots" "$NO_VALUE"; then
if ! _exists "socat"; then
_err "Please install socat tools first."
return 1
fi
fi
2017-02-19 15:09:22 +01:00
_debug Le_LocalAddress "$_chk_local_addr"
2016-11-09 12:30:39 +01:00
_index=1
_currentRoot=""
_addrIndex=1
2018-03-14 15:03:58 +01:00
_w_index=1
2018-03-14 14:56:40 +01:00
while true; do
d="$(echo "$_chk_main_domain,$_chk_alt_domains," | cut -d , -f "$_w_index")"
_w_index="$(_math "$_w_index" + 1)"
_debug d "$d"
if [ -z "$d" ]; then
break
fi
2016-11-09 14:44:46 +01:00
_debug "Check for domain" "$d"
2017-02-19 14:13:00 +01:00
_currentRoot="$(_getfield "$_chk_web_roots" $_index)"
_debug "_currentRoot" "$_currentRoot"
_index=$(_math $_index + 1)
_checkport=""
2016-11-09 12:30:39 +01:00
if [ "$_currentRoot" = "$NO_VALUE" ]; then
_info "Standalone mode."
2016-11-09 12:30:39 +01:00
if [ -z "$Le_HTTPPort" ]; then
Le_HTTPPort=80
_cleardomainconf "Le_HTTPPort"
else
2016-11-09 12:30:39 +01:00
_savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
fi
_checkport="$Le_HTTPPort"
2019-01-26 11:32:11 +01:00
elif [ "$_currentRoot" = "$W_ALPN" ]; then
_info "Standalone alpn mode."
2016-11-09 12:30:39 +01:00
if [ -z "$Le_TLSPort" ]; then
Le_TLSPort=443
else
2016-11-09 12:30:39 +01:00
_savedomainconf "Le_TLSPort" "$Le_TLSPort"
fi
_checkport="$Le_TLSPort"
fi
2016-11-09 12:30:39 +01:00
if [ "$_checkport" ]; then
_debug _checkport "$_checkport"
2017-02-19 15:09:22 +01:00
_checkaddr="$(_getfield "$_chk_local_addr" $_addrIndex)"
_debug _checkaddr "$_checkaddr"
2016-11-09 12:30:39 +01:00
_addrIndex="$(_math $_addrIndex + 1)"
2016-11-09 12:30:39 +01:00
_netprc="$(_ss "$_checkport" | grep "$_checkport")"
netprc="$(echo "$_netprc" | grep "$_checkaddr")"
2016-11-09 12:30:39 +01:00
if [ -z "$netprc" ]; then
netprc="$(echo "$_netprc" | grep "$LOCAL_ANY_ADDRESS")"
fi
2016-11-09 12:30:39 +01:00
if [ "$netprc" ]; then
_err "$netprc"
2016-11-09 12:30:39 +01:00
_err "tcp port $_checkport is already used by $(echo "$netprc" | cut -d : -f 4)"
_err "Please stop it first"
return 1
fi
fi
done
2017-02-19 14:13:00 +01:00
if _hasfield "$_chk_web_roots" "apache"; then
2016-11-09 12:30:39 +01:00
if ! _setApache; then
_err "set up apache error. Report error to me."
return 1
fi
else
usingApache=""
fi
}
_on_issue_err() {
2017-02-19 15:09:22 +01:00
_chk_post_hook="$1"
_chk_vlist="$2"
2016-09-26 07:33:09 +02:00
_debug _on_issue_err
2018-01-06 14:50:57 +01:00
2016-11-09 12:30:39 +01:00
if [ "$LOG_FILE" ]; then
2016-09-25 15:58:59 +02:00
_err "Please check log file for more details: $LOG_FILE"
else
2016-11-16 12:45:00 +01:00
_err "Please add '--debug' or '--log' to check more details."
2016-09-25 15:58:59 +02:00
_err "See: $_DEBUG_WIKI"
fi
2016-11-09 12:30:39 +01:00
#run the post hook
2017-02-19 15:09:22 +01:00
if [ "$_chk_post_hook" ]; then
_info "Run post hook:'$_chk_post_hook'"
if ! (
2017-02-19 15:09:22 +01:00
cd "$DOMAIN_PATH" && eval "$_chk_post_hook"
2016-11-09 12:30:39 +01:00
); then
_err "Error when run post hook."
return 1
fi
fi
#trigger the validation to flush the pending authz
2017-07-01 14:31:42 +02:00
_debug2 "_chk_vlist" "$_chk_vlist"
if [ "$_chk_vlist" ]; then
(
2017-02-26 05:15:39 +01:00
_debug2 "start to deactivate authz"
ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ')
for ventry in $ventries; do
d=$(echo "$ventry" | cut -d "$sep" -f 1)
keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
uri=$(echo "$ventry" | cut -d "$sep" -f 3)
vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
_currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
2017-03-26 07:32:29 +02:00
__trigger_validation "$uri" "$keyauthorization"
2017-02-26 05:15:39 +01:00
done
)
fi
2020-08-16 11:36:24 +02:00
if [ "$_ACME_IS_RENEW" = "1" ] && _hasfield "$Le_Webroot" "$W_DNS"; then
2017-08-22 14:27:13 +02:00
_err "$_DNS_MANUAL_ERR"
fi
if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then
_debug "$(_dlg_versions)"
fi
}
_on_issue_success() {
2017-02-19 15:09:22 +01:00
_chk_post_hook="$1"
_chk_renew_hook="$2"
2016-09-26 07:33:09 +02:00
_debug _on_issue_success
#run the post hook
2017-02-19 15:09:22 +01:00
if [ "$_chk_post_hook" ]; then
_info "Run post hook:'$_chk_post_hook'"
if ! (
export CERT_PATH
export CERT_KEY_PATH
export CA_CERT_PATH
export CERT_FULLCHAIN_PATH
export Le_Domain="$_main_domain"
2017-02-19 15:09:22 +01:00
cd "$DOMAIN_PATH" && eval "$_chk_post_hook"
2016-11-09 12:30:39 +01:00
); then
_err "Error when run post hook."
return 1
fi
fi
2016-11-09 12:30:39 +01:00
#run renew hook
2020-08-16 11:36:24 +02:00
if [ "$_ACME_IS_RENEW" ] && [ "$_chk_renew_hook" ]; then
2017-02-19 15:09:22 +01:00
_info "Run renew hook:'$_chk_renew_hook'"
if ! (
export CERT_PATH
export CERT_KEY_PATH
export CA_CERT_PATH
export CERT_FULLCHAIN_PATH
export Le_Domain="$_main_domain"
2017-02-19 15:09:22 +01:00
cd "$DOMAIN_PATH" && eval "$_chk_renew_hook"
2016-11-09 12:30:39 +01:00
); then
_err "Error when run renew hook."
return 1
fi
2016-11-09 12:30:39 +01:00
fi
if _hasfield "$Le_Webroot" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then
2017-08-22 14:27:13 +02:00
_err "$_DNS_MANUAL_WARN"
fi
}
2020-08-09 03:34:43 +02:00
#account_key_length eab-kid eab-hmac-key
registeraccount() {
2020-08-09 03:34:43 +02:00
_account_key_length="$1"
_eab_id="$2"
_eab_hmac_key="$3"
_initpath
2020-08-09 03:34:43 +02:00
_regAccount "$_account_key_length" "$_eab_id" "$_eab_hmac_key"
}
__calcAccountKeyHash() {
2016-11-09 14:56:50 +01:00
[ -f "$ACCOUNT_KEY_PATH" ] && _digest sha256 <"$ACCOUNT_KEY_PATH"
}
2017-02-06 12:53:12 +01:00
__calc_account_thumbprint() {
printf "%s" "$jwk" | tr -d ' ' | _digest "sha256" | _url_replace
}
_getAccountEmail() {
if [ "$ACCOUNT_EMAIL" ]; then
echo "$ACCOUNT_EMAIL"
return 0
fi
if [ -z "$CA_EMAIL" ]; then
CA_EMAIL="$(_readcaconf CA_EMAIL)"
fi
if [ "$CA_EMAIL" ]; then
echo "$CA_EMAIL"
return 0
fi
_readaccountconf "ACCOUNT_EMAIL"
}
#keylength
_regAccount() {
_initpath
_reg_length="$1"
2020-08-09 03:34:43 +02:00
_eab_id="$2"
_eab_hmac_key="$3"
_debug3 _regAccount "$_regAccount"
2018-01-06 05:45:24 +01:00
_initAPI
2017-07-02 12:24:55 +02:00
mkdir -p "$CA_DIR"
2016-09-27 17:43:18 +02:00
if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then
_info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH"
mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH"
fi
2016-11-09 12:30:39 +01:00
2016-09-27 17:43:18 +02:00
if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then
_info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH"
mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH"
fi
2016-11-09 12:30:39 +01:00
if [ ! -f "$ACCOUNT_KEY_PATH" ]; then
if ! _create_account_key "$_reg_length"; then
_err "Create account key error."
return 1
fi
fi
2016-11-09 12:30:39 +01:00
if ! _calcjwk "$ACCOUNT_KEY_PATH"; then
return 1
fi
2020-08-09 03:34:43 +02:00
if [ "$_eab_id" ] && [ "$_eab_hmac_key" ]; then
_savecaconf CA_EAB_KEY_ID "$_eab_id"
_savecaconf CA_EAB_HMAC_KEY "$_eab_hmac_key"
fi
_eab_id=$(_readcaconf "CA_EAB_KEY_ID")
_eab_hmac_key=$(_readcaconf "CA_EAB_HMAC_KEY")
_secure_debug3 _eab_id "$_eab_id"
_secure_debug3 _eab_hmac_key "$_eab_hmac_key"
_email="$(_getAccountEmail)"
if [ "$_email" ]; then
_savecaconf "CA_EMAIL" "$_email"
fi
2018-01-06 05:45:24 +01:00
if [ "$ACME_VERSION" = "2" ]; then
if [ "$ACME_DIRECTORY" = "$CA_ZEROSSL" ]; then
if [ -z "$_eab_id" ] || [ -z "$_eab_hmac_key" ]; then
_info "No EAB credentials found for ZeroSSL, let's get one"
if [ -z "$_email" ]; then
2020-08-12 14:47:17 +02:00
_err "Please provide a email address for ZeroSSL account."
_err "See ZeroSSL usage: $_ZEROSSL_WIKI"
return 1
fi
_eabresp=$(_post "email=$_email" $_ZERO_EAB_ENDPOINT)
if [ "$?" != "0" ]; then
_debug2 "$_eabresp"
2020-08-12 14:47:17 +02:00
_err "Can not get EAB credentials from ZeroSSL."
return 1
fi
_eab_id="$(echo "$_eabresp" | tr ',}' '\n' | grep '"eab_kid"' | cut -d : -f 2 | tr -d '"')"
if [ -z "$_eab_id" ]; then
2020-08-12 14:48:21 +02:00
_err "Can not resolve _eab_id"
return 1
fi
_eab_hmac_key="$(echo "$_eabresp" | tr ',}' '\n' | grep '"eab_hmac_key"' | cut -d : -f 2 | tr -d '"')"
if [ -z "$_eab_hmac_key" ]; then
2020-08-12 14:48:21 +02:00
_err "Can not resolve _eab_hmac_key"
return 1
fi
_savecaconf CA_EAB_KEY_ID "$_eab_id"
_savecaconf CA_EAB_HMAC_KEY "$_eab_hmac_key"
fi
fi
2020-08-09 03:34:43 +02:00
if [ "$_eab_id" ] && [ "$_eab_hmac_key" ]; then
eab_protected="{\"alg\":\"HS256\",\"kid\":\"$_eab_id\",\"url\":\"${ACME_NEW_ACCOUNT}\"}"
_debug3 eab_protected "$eab_protected"
eab_protected64=$(printf "%s" "$eab_protected" | _base64 | _url_replace)
_debug3 eab_protected64 "$eab_protected64"
eab_payload64=$(printf "%s" "$jwk" | _base64 | _url_replace)
_debug3 eab_payload64 "$eab_payload64"
eab_sign_t="$eab_protected64.$eab_payload64"
_debug3 eab_sign_t "$eab_sign_t"
2020-08-11 17:45:12 +02:00
key_hex="$(_durl_replace_base64 "$_eab_hmac_key" | _dbase64 | _hex_dump | tr -d ' ')"
2020-08-09 03:34:43 +02:00
_debug3 key_hex "$key_hex"
2020-08-11 17:45:12 +02:00
eab_signature=$(printf "%s" "$eab_sign_t" | _hmac sha256 $key_hex | _base64 | _url_replace)
2020-08-09 03:34:43 +02:00
_debug3 eab_signature "$eab_signature"
externalBinding=",\"externalAccountBinding\":{\"protected\":\"$eab_protected64\", \"payload\":\"$eab_payload64\", \"signature\":\"$eab_signature\"}"
_debug3 externalBinding "$externalBinding"
fi
if [ "$_email" ]; then
email_sg="\"contact\": [\"mailto:$_email\"], "
2018-01-06 05:45:24 +01:00
fi
2020-08-09 03:34:43 +02:00
regjson="{$email_sg\"termsOfServiceAgreed\": true$externalBinding}"
2018-01-06 05:45:24 +01:00
else
_reg_res="$ACME_NEW_ACCOUNT_RES"
regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
if [ "$_email" ]; then
regjson='{"resource": "'$_reg_res'", "contact": ["mailto:'$_email'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
2018-01-06 05:45:24 +01:00
fi
fi
2016-11-09 12:30:39 +01:00
_info "Registering account: $ACME_DIRECTORY"
if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then
_err "Register account Error: $response"
return 1
fi
_eabAlreadyBound=""
if [ "$code" = "" ] || [ "$code" = '201' ]; then
echo "$response" >"$ACCOUNT_JSON_PATH"
_info "Registered"
elif [ "$code" = '409' ] || [ "$code" = '200' ]; then
_info "Already registered"
elif [ "$code" = '400' ] && _contains "$response" 'The account is not awaiting external account binding'; then
_info "Already register EAB."
_eabAlreadyBound=1
else
_err "Register account Error: $response"
return 1
fi
if [ -z "$_eabAlreadyBound" ]; then
_debug2 responseHeaders "$responseHeaders"
_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."
_err "$responseHeaders"
return 1
fi
_savecaconf "ACCOUNT_URL" "$_accUri"
else
ACCOUNT_URL="$(_readcaconf ACCOUNT_URL)"
fi
export ACCOUNT_URL="$_accUri"
CA_KEY_HASH="$(__calcAccountKeyHash)"
_debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
_savecaconf CA_KEY_HASH "$CA_KEY_HASH"
if [ "$code" = '403' ]; then
_err "It seems that the account key is already deactivated, please use a new account key."
return 1
fi
2016-11-09 12:30:39 +01:00
ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)"
_info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT"
}
2019-04-17 14:51:07 +02:00
#implement updateaccount
updateaccount() {
_initpath
if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then
_info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH"
mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH"
fi
if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then
_info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH"
mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH"
fi
if [ ! -f "$ACCOUNT_KEY_PATH" ]; then
_err "Account key is not found at: $ACCOUNT_KEY_PATH"
return 1
fi
_accUri=$(_readcaconf "ACCOUNT_URL")
_debug _accUri "$_accUri"
if [ -z "$_accUri" ]; then
_err "The account url is empty, please run '--update-account' first to update the account info first,"
_err "Then try again."
return 1
fi
if ! _calcjwk "$ACCOUNT_KEY_PATH"; then
return 1
fi
_initAPI
_email="$(_getAccountEmail)"
2019-04-17 14:51:07 +02:00
if [ "$ACME_VERSION" = "2" ]; then
if [ "$ACCOUNT_EMAIL" ]; then
updjson='{"contact": ["mailto:'$_email'"]}'
else
updjson='{"contact": []}'
2019-04-17 14:51:07 +02:00
fi
else
# ACMEv1: Updates happen the same way a registration is done.
# https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-6.3
_regAccount
return
fi
# this part handles ACMEv2 account updates.
_send_signed_request "$_accUri" "$updjson"
if [ "$code" = '200' ]; then
echo "$response" >"$ACCOUNT_JSON_PATH"
2019-04-17 14:51:07 +02:00
_info "account update success for $_accUri."
else
_info "Error. The account was not updated."
return 1
fi
}
#Implement deactivate account
deactivateaccount() {
_initpath
if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then
_info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH"
mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH"
fi
if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then
_info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH"
mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH"
fi
if [ ! -f "$ACCOUNT_KEY_PATH" ]; then
_err "Account key is not found at: $ACCOUNT_KEY_PATH"
return 1
fi
_accUri=$(_readcaconf "ACCOUNT_URL")
_debug _accUri "$_accUri"
if [ -z "$_accUri" ]; then
_err "The account url is empty, please run '--update-account' first to update the account info first,"
_err "Then try again."
return 1
fi
if ! _calcjwk "$ACCOUNT_KEY_PATH"; then
return 1
fi
_initAPI
if [ "$ACME_VERSION" = "2" ]; then
_djson="{\"status\":\"deactivated\"}"
else
_djson="{\"resource\": \"reg\", \"status\":\"deactivated\"}"
fi
if _send_signed_request "$_accUri" "$_djson" && _contains "$response" '"deactivated"'; then
_info "Deactivate account success for $_accUri."
_accid=$(echo "$response" | _egrep_o "\"id\" *: *[^,]*," | cut -d : -f 2 | tr -d ' ,')
elif [ "$code" = "403" ]; then
_info "The account is already deactivated."
_accid=$(_getfield "$_accUri" "999" "/")
else
_err "Deactivate: account failed for $_accUri."
return 1
fi
_debug "Account id: $_accid"
if [ "$_accid" ]; then
_deactivated_account_path="$CA_DIR/deactivated/$_accid"
_debug _deactivated_account_path "$_deactivated_account_path"
if mkdir -p "$_deactivated_account_path"; then
_info "Moving deactivated account info to $_deactivated_account_path/"
mv "$CA_CONF" "$_deactivated_account_path/"
mv "$ACCOUNT_JSON_PATH" "$_deactivated_account_path/"
mv "$ACCOUNT_KEY_PATH" "$_deactivated_account_path/"
else
_err "Can not create dir: $_deactivated_account_path, try to remove the deactivated account key."
rm -f "$CA_CONF"
rm -f "$ACCOUNT_JSON_PATH"
rm -f "$ACCOUNT_KEY_PATH"
fi
fi
}
2016-10-11 14:56:59 +02:00
# domain folder file
_findHook() {
_hookdomain="$1"
_hookcat="$2"
_hookname="$3"
2016-11-11 16:30:14 +01:00
if [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname" ]; then
d_api="$_SCRIPT_HOME/$_hookcat/$_hookname"
elif [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname.sh" ]; then
d_api="$_SCRIPT_HOME/$_hookcat/$_hookname.sh"
elif [ "$_hookdomain" ] && [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ]; then
2016-10-11 14:56:59 +02:00
d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname"
elif [ "$_hookdomain" ] && [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ]; then
2016-10-11 14:56:59 +02:00
d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname.sh"
2016-11-09 12:30:39 +01:00
elif [ -f "$LE_WORKING_DIR/$_hookname" ]; then
2016-10-11 14:56:59 +02:00
d_api="$LE_WORKING_DIR/$_hookname"
2016-11-09 12:30:39 +01:00
elif [ -f "$LE_WORKING_DIR/$_hookname.sh" ]; then
2016-10-11 14:56:59 +02:00
d_api="$LE_WORKING_DIR/$_hookname.sh"
2016-11-09 12:30:39 +01:00
elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname" ]; then
2016-10-11 14:56:59 +02:00
d_api="$LE_WORKING_DIR/$_hookcat/$_hookname"
2016-11-09 12:30:39 +01:00
elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname.sh" ]; then
2016-10-11 14:56:59 +02:00
d_api="$LE_WORKING_DIR/$_hookcat/$_hookname.sh"
fi
printf "%s" "$d_api"
}
2016-10-27 16:10:58 +02:00
#domain
__get_domain_new_authz() {
_gdnd="$1"
_info "Getting new-authz for domain" "$_gdnd"
2017-06-17 10:20:32 +02:00
_initAPI
2016-10-27 16:10:58 +02:00
_Max_new_authz_retry_times=5
_authz_i=0
2016-11-09 12:30:39 +01:00
while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do
2016-11-11 16:52:02 +01:00
_debug "Try new-authz for the $_authz_i time."
2017-06-17 09:49:45 +02:00
if ! _send_signed_request "${ACME_NEW_AUTHZ}" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then
2016-10-27 16:10:58 +02:00
_err "Can not get domain new authz."
return 1
fi
if _contains "$response" "No registration exists matching provided key"; then
_err "It seems there is an error, but it's recovered now, please try again."
_err "If you see this message for a second time, please report bug: $(__green "$PROJECT")"
_clearcaconf "CA_KEY_HASH"
break
fi
2016-11-09 12:30:39 +01:00
if ! _contains "$response" "An error occurred while processing your request"; then
2016-10-27 16:10:58 +02:00
_info "The new-authz request is ok."
break
fi
_authz_i="$(_math "$_authz_i" + 1)"
2016-10-27 16:47:19 +02:00
_info "The server is busy, Sleep $_authz_i to retry."
2016-10-27 16:10:58 +02:00
_sleep "$_authz_i"
2016-11-09 12:30:39 +01:00
done
2016-10-27 16:10:58 +02:00
2016-11-09 12:30:39 +01:00
if [ "$_authz_i" = "$_Max_new_authz_retry_times" ]; then
2016-11-11 16:52:02 +01:00
_err "new-authz retry reach the max $_Max_new_authz_retry_times times."
2016-10-27 16:10:58 +02:00
fi
2016-11-09 12:30:39 +01:00
2018-02-07 16:49:08 +01:00
if [ "$code" ] && [ "$code" != '201' ]; then
2016-10-27 16:10:58 +02:00
_err "new-authz error: $response"
return 1
fi
}
#uri keyAuthorization
2017-03-26 07:32:29 +02:00
__trigger_validation() {
_debug2 "Trigger domain validation."
_t_url="$1"
_debug2 _t_url "$_t_url"
_t_key_authz="$2"
_debug2 _t_key_authz "$_t_key_authz"
_t_vtype="$3"
_debug2 _t_vtype "$_t_vtype"
2018-01-06 05:45:24 +01:00
if [ "$ACME_VERSION" = "2" ]; then
_send_signed_request "$_t_url" "{}"
2018-01-06 05:45:24 +01:00
else
_send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"type\": \"$_t_vtype\", \"keyAuthorization\": \"$_t_key_authz\"}"
2018-01-06 05:45:24 +01:00
fi
}
#endpoint domain type
2019-10-03 14:37:46 +02:00
_ns_lookup_impl() {
_ns_ep="$1"
_ns_domain="$2"
_ns_type="$3"
_debug2 "_ns_ep" "$_ns_ep"
_debug2 "_ns_domain" "$_ns_domain"
_debug2 "_ns_type" "$_ns_type"
response="$(_H1="accept: application/dns-json" _get "$_ns_ep?name=$_ns_domain&type=$_ns_type")"
_ret=$?
_debug2 "response" "$response"
if [ "$_ret" != "0" ]; then
return $_ret
fi
_answers="$(echo "$response" | tr '{}' '<>' | _egrep_o '"Answer":\[[^]]*]' | tr '<>' '\n\n')"
_debug2 "_answers" "$_answers"
echo "$_answers"
}
#domain, type
_ns_lookup_cf() {
_cf_ld="$1"
_cf_ld_type="$2"
_cf_ep="https://cloudflare-dns.com/dns-query"
2019-10-03 14:37:46 +02:00
_ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type"
}
#domain, type
_ns_purge_cf() {
_cf_d="$1"
_cf_d_type="$2"
_debug "Cloudflare purge $_cf_d_type record for domain $_cf_d"
_cf_purl="https://cloudflare-dns.com/api/v1/purge?domain=$_cf_d&type=$_cf_d_type"
response="$(_post "" "$_cf_purl")"
_debug2 response "$response"
}
2019-10-03 14:37:46 +02:00
#checks if cf server is available
_ns_is_available_cf() {
if _get "https://cloudflare-dns.com" >/dev/null 2>&1; then
2019-10-03 14:37:46 +02:00
return 0
else
return 1
fi
}
#domain, type
_ns_lookup_google() {
_cf_ld="$1"
_cf_ld_type="$2"
_cf_ep="https://dns.google/resolve"
_ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type"
}
#domain, type
_ns_lookup() {
if [ -z "$DOH_USE" ]; then
_debug "Detect dns server first."
if _ns_is_available_cf; then
_debug "Use cloudflare doh server"
export DOH_USE=$DOH_CLOUDFLARE
else
_debug "Use google doh server"
export DOH_USE=$DOH_GOOGLE
fi
fi
if [ "$DOH_USE" = "$DOH_CLOUDFLARE" ] || [ -z "$DOH_USE" ]; then
_ns_lookup_cf "$@"
else
_ns_lookup_google "$@"
fi
}
#txtdomain, alias, txt
__check_txt() {
_c_txtdomain="$1"
_c_aliasdomain="$2"
_c_txt="$3"
_debug "_c_txtdomain" "$_c_txtdomain"
_debug "_c_aliasdomain" "$_c_aliasdomain"
_debug "_c_txt" "$_c_txt"
2019-10-03 14:37:46 +02:00
_answers="$(_ns_lookup "$_c_aliasdomain" TXT)"
_contains "$_answers" "$_c_txt"
}
#txtdomain
__purge_txt() {
_p_txtdomain="$1"
_debug _p_txtdomain "$_p_txtdomain"
2019-10-03 14:37:46 +02:00
if [ "$DOH_USE" = "$DOH_CLOUDFLARE" ] || [ -z "$DOH_USE" ]; then
_ns_purge_cf "$_p_txtdomain" "TXT"
else
_debug "no purge api for google dns api, just sleep 5 secs"
_sleep 5
fi
}
#wait and check each dns entries
_check_dns_entries() {
_success_txt=","
_end_time="$(_time)"
_end_time="$(_math "$_end_time" + 1200)" #let's check no more than 20 minutes.
while [ "$(_time)" -le "$_end_time" ]; do
_left=""
for entry in $dns_entries; do
d=$(_getfield "$entry" 1)
txtdomain=$(_getfield "$entry" 2)
txtdomain=$(_idn "$txtdomain")
aliasDomain=$(_getfield "$entry" 3)
aliasDomain=$(_idn "$aliasDomain")
txt=$(_getfield "$entry" 5)
d_api=$(_getfield "$entry" 6)
_debug "d" "$d"
_debug "txtdomain" "$txtdomain"
_debug "aliasDomain" "$aliasDomain"
_debug "txt" "$txt"
_debug "d_api" "$d_api"
_info "Checking $d for $aliasDomain"
if _contains "$_success_txt" ",$txt,"; then
_info "Already success, continue next one."
continue
fi
if __check_txt "$txtdomain" "$aliasDomain" "$txt"; then
_info "Domain $d '$aliasDomain' success."
_success_txt="$_success_txt,$txt,"
continue
fi
_left=1
_info "Not valid yet, let's wait 10 seconds and check next one."
__purge_txt "$txtdomain"
if [ "$txtdomain" != "$aliasDomain" ]; then
__purge_txt "$aliasDomain"
fi
_sleep 10
done
if [ "$_left" ]; then
_info "Let's wait 10 seconds and check again".
_sleep 10
else
_info "All success, let's return"
return 0
fi
done
_info "Timed out waiting for DNS."
return 1
}
#file
_get_cert_issuers() {
_cfile="$1"
if _contains "$(${ACME_OPENSSL_BIN:-openssl} help crl2pkcs7 2>&1)" "Usage: crl2pkcs7"; then
${ACME_OPENSSL_BIN:-openssl} crl2pkcs7 -nocrl -certfile $_cfile | openssl pkcs7 -print_certs -text -noout | grep 'Issuer:' | _egrep_o "CN *=[^,]*" | cut -d = -f 2
else
${ACME_OPENSSL_BIN:-openssl} x509 -in $_cfile -text -noout | grep 'Issuer:' | _egrep_o "CN *=[^,]*" | cut -d = -f 2
fi
}
#cert issuer
_match_issuer() {
_cfile="$1"
_missuer="$2"
_fissuers="$(_get_cert_issuers $_cfile)"
_debug2 _fissuers "$_fissuers"
_contains "$_fissuers" "$_missuer"
}
2017-04-17 13:08:34 +02:00
#webroot, domain domainlist keylength
2016-03-08 13:44:12 +01:00
issue() {
2016-11-09 12:30:39 +01:00
if [ -z "$2" ]; then
_usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ "
2016-03-08 13:44:12 +01:00
return 1
fi
2017-04-05 14:46:17 +02:00
if [ -z "$1" ]; then
_usage "Please specify at least one validation method: '--webroot', '--standalone', '--apache', '--nginx' or '--dns' etc."
return 1
fi
2017-02-19 14:13:00 +01:00
_web_roots="$1"
_main_domain="$2"
2017-02-19 14:18:00 +01:00
_alt_domains="$3"
2017-02-19 14:13:00 +01:00
if _contains "$_main_domain" ","; then
_main_domain=$(echo "$2,$3" | cut -d , -f 1)
2017-02-19 14:18:00 +01:00
_alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//")
2017-01-17 13:13:15 +01:00
fi
2018-03-14 14:42:12 +01:00
_debug _main_domain "$_main_domain"
_debug _alt_domains "$_alt_domains"
2017-02-19 14:21:11 +01:00
_key_length="$4"
2017-02-19 15:09:22 +01:00
_real_cert="$5"
_real_key="$6"
_real_ca="$7"
_reload_cmd="$8"
_real_fullchain="$9"
_pre_hook="${10}"
_post_hook="${11}"
_renew_hook="${12}"
_local_addr="${13}"
2018-02-10 03:45:29 +01:00
_challenge_alias="${14}"
_preferred_chain="${15}"
2016-11-09 12:30:39 +01:00
2020-08-16 11:36:24 +02:00
if [ -z "$_ACME_IS_RENEW" ]; then
2017-02-19 14:21:11 +01:00
_initpath "$_main_domain" "$_key_length"
mkdir -p "$DOMAIN_PATH"
fi
if _hasfield "$_web_roots" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then
_err "$_DNS_MANUAL_ERROR"
return 1
fi
2017-06-17 09:49:45 +02:00
_debug "Using ACME_DIRECTORY: $ACME_DIRECTORY"
_initAPI
2016-11-09 12:30:39 +01:00
if [ -f "$DOMAIN_CONF" ]; then
Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime)
2016-05-07 17:33:42 +02:00
_debug Le_NextRenewTime "$Le_NextRenewTime"
2016-11-09 13:45:57 +01:00
if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
_saved_domain=$(_readdomainconf Le_Domain)
_debug _saved_domain "$_saved_domain"
_saved_alt=$(_readdomainconf Le_Alt)
_debug _saved_alt "$_saved_alt"
2017-02-19 14:18:00 +01:00
if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$_alt_domains" ]; then
_info "Domains not changed."
_info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")"
2016-11-09 12:30:39 +01:00
_info "Add '$(__red '--force')' to force to renew."
return $RENEW_SKIP
else
_info "Domains have changed."
fi
2016-03-08 13:44:12 +01:00
fi
fi
2017-02-19 14:13:00 +01:00
_savedomainconf "Le_Domain" "$_main_domain"
2017-02-19 14:18:00 +01:00
_savedomainconf "Le_Alt" "$_alt_domains"
2017-02-19 14:13:00 +01:00
_savedomainconf "Le_Webroot" "$_web_roots"
2016-11-09 12:30:39 +01:00
_savedomainconf "Le_PreHook" "$_pre_hook" "base64"
_savedomainconf "Le_PostHook" "$_post_hook" "base64"
_savedomainconf "Le_RenewHook" "$_renew_hook" "base64"
2016-11-09 12:30:39 +01:00
2017-02-19 15:09:22 +01:00
if [ "$_local_addr" ]; then
_savedomainconf "Le_LocalAddress" "$_local_addr"
2016-10-29 11:43:38 +02:00
else
_cleardomainconf "Le_LocalAddress"
fi
2018-02-10 03:45:29 +01:00
if [ "$_challenge_alias" ]; then
_savedomainconf "Le_ChallengeAlias" "$_challenge_alias"
else
_cleardomainconf "Le_ChallengeAlias"
fi
if [ "$_preferred_chain" ]; then
_savedomainconf "Le_Preferred_Chain" "$_preferred_chain" "base64"
else
_cleardomainconf "Le_Preferred_Chain"
fi
Le_API="$ACME_DIRECTORY"
_savedomainconf "Le_API" "$Le_API"
_info "Using CA: $ACME_DIRECTORY"
2017-02-19 14:18:00 +01:00
if [ "$_alt_domains" = "$NO_VALUE" ]; then
_alt_domains=""
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
2017-02-19 14:21:11 +01:00
if [ "$_key_length" = "$NO_VALUE" ]; then
_key_length=""
fi
2016-11-09 12:30:39 +01:00
2017-02-19 15:09:22 +01:00
if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then
_err "_on_before_issue."
return 1
2016-03-08 13:44:12 +01:00
fi
_saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")"
_debug2 _saved_account_key_hash "$_saved_account_key_hash"
2016-11-09 12:30:39 +01:00
2018-03-18 12:32:45 +01:00
if [ -z "$ACCOUNT_URL" ] || [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then
if ! _regAccount "$_accountkeylength"; then
2017-02-19 15:09:22 +01:00
_on_issue_err "$_post_hook"
return 1
fi
else
_debug "_saved_account_key_hash is not changed, skip register account."
fi
2016-11-09 12:30:39 +01:00
if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ]; then
_info "Signing from existing CSR."
else
_key=$(_readdomainconf Le_Keylength)
_debug "Read key length:$_key"
if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ] || [ "$Le_ForceNewDomainKey" = "1" ]; then
2017-02-19 14:21:11 +01:00
if ! createDomainKey "$_main_domain" "$_key_length"; then
_err "Create domain key error."
_clearup
2017-02-19 15:09:22 +01:00
_on_issue_err "$_post_hook"
return 1
fi
fi
2017-02-19 14:18:00 +01:00
if ! _createcsr "$_main_domain" "$_alt_domains" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then
_err "Create CSR error."
2016-04-16 12:31:00 +02:00
_clearup
2017-02-19 15:09:22 +01:00
_on_issue_err "$_post_hook"
return 1
fi
2016-03-08 13:44:12 +01:00
fi
2017-02-19 14:21:11 +01:00
_savedomainconf "Le_Keylength" "$_key_length"
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
vlist="$Le_Vlist"
2019-06-14 16:41:28 +02:00
_cleardomainconf "Le_Vlist"
2016-10-28 17:30:32 +02:00
_info "Getting domain auth token for each domain"
2016-03-08 13:44:12 +01:00
sep='#'
2017-02-13 16:29:37 +01:00
dvsep=','
2016-11-09 12:30:39 +01:00
if [ -z "$vlist" ]; then
if [ "$ACME_VERSION" = "2" ]; then
2018-01-06 05:45:24 +01:00
#make new order request
_identifiers="{\"type\":\"dns\",\"value\":\"$(_idn "$_main_domain")\"}"
2018-03-14 15:03:58 +01:00
_w_index=1
2018-03-14 14:42:12 +01:00
while true; do
2018-03-14 14:45:16 +01:00
d="$(echo "$_alt_domains," | cut -d , -f "$_w_index")"
2018-03-14 14:42:12 +01:00
_w_index="$(_math "$_w_index" + 1)"
_debug d "$d"
if [ -z "$d" ]; then
break
2018-01-06 05:45:24 +01:00
fi
_identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$(_idn "$d")\"}"
2018-01-06 05:45:24 +01:00
done
_debug2 _identifiers "$_identifiers"
if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then
_err "Create new order error."
_clearup
_on_issue_err "$_post_hook"
return 1
fi
2020-01-27 14:22:42 +01:00
Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n " | cut -d ":" -f 2-)"
_debug Le_LinkOrder "$Le_LinkOrder"
2019-03-16 06:38:17 +01:00
Le_OrderFinalize="$(echo "$response" | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)"
_debug Le_OrderFinalize "$Le_OrderFinalize"
if [ -z "$Le_OrderFinalize" ]; then
2018-02-07 16:49:08 +01:00
_err "Create new order error. Le_OrderFinalize not found. $response"
2018-01-06 05:45:24 +01:00
_clearup
_on_issue_err "$_post_hook"
return 1
fi
#for dns manual mode
_savedomainconf "Le_OrderFinalize" "$Le_OrderFinalize"
2018-01-06 05:45:24 +01:00
_authorizations_seg="$(echo "$response" | _json_decode | _egrep_o '"authorizations" *: *\[[^\[]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')"
2018-01-06 05:45:24 +01:00
_debug2 _authorizations_seg "$_authorizations_seg"
if [ -z "$_authorizations_seg" ]; then
_err "_authorizations_seg not found."
_clearup
_on_issue_err "$_post_hook"
return 1
fi
#domain and authz map
_authorizations_map=""
2018-01-06 06:57:35 +01:00
for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' '); do
2018-01-06 05:45:24 +01:00
_debug2 "_authz_url" "$_authz_url"
if ! _send_signed_request "$_authz_url"; then
2018-01-06 05:45:24 +01:00
_err "get to authz error."
2018-03-14 14:27:29 +01:00
_err "_authorizations_seg" "$_authorizations_seg"
_err "_authz_url" "$_authz_url"
2018-01-06 05:45:24 +01:00
_clearup
_on_issue_err "$_post_hook"
return 1
fi
response="$(echo "$response" | _normalizeJson)"
_debug2 response "$response"
_d="$(echo "$response" | _egrep_o '"value" *: *"[^"]*"' | cut -d : -f 2 | tr -d ' "')"
2018-01-06 10:39:15 +01:00
if _contains "$response" "\"wildcard\" *: *true"; then
_d="*.$_d"
fi
2018-01-06 05:45:24 +01:00
_debug2 _d "$_d"
_authorizations_map="$_d,$response
$_authorizations_map"
done
_debug2 _authorizations_map "$_authorizations_map"
fi
_index=0
_currentRoot=""
2018-03-14 15:03:58 +01:00
_w_index=1
while true; do
d="$(echo "$_main_domain,$_alt_domains," | cut -d , -f "$_w_index")"
_w_index="$(_math "$_w_index" + 1)"
_debug d "$d"
if [ -z "$d" ]; then
break
fi
2016-11-09 14:56:50 +01:00
_info "Getting webroot for domain" "$d"
2018-01-06 05:45:24 +01:00
_index=$(_math $_index + 1)
2017-02-19 14:13:00 +01:00
_w="$(echo $_web_roots | cut -d , -f $_index)"
2017-02-13 16:29:37 +01:00
_debug _w "$_w"
2016-11-09 12:30:39 +01:00
if [ "$_w" ]; then
_currentRoot="$_w"
fi
_debug "_currentRoot" "$_currentRoot"
2016-11-09 12:30:39 +01:00
vtype="$VTYPE_HTTP"
2018-01-06 05:45:24 +01:00
#todo, v2 wildcard force to use dns
if _startswith "$_currentRoot" "$W_DNS"; then
vtype="$VTYPE_DNS"
fi
2016-11-09 12:30:39 +01:00
if [ "$_currentRoot" = "$W_ALPN" ]; then
vtype="$VTYPE_ALPN"
fi
2018-01-06 05:45:24 +01:00
if [ "$ACME_VERSION" = "2" ]; then
_idn_d="$(_idn "$d")"
2020-07-07 14:06:37 +02:00
_candidates="$(echo "$_authorizations_map" | grep -i "^$_idn_d,")"
_debug2 _candidates "$_candidates"
if [ "$(echo "$_candidates" | wc -l)" -gt 1 ]; then
for _can in $_candidates; do
if _startswith "$(echo "$_can" | tr '.' '|')" "$(echo "$_idn_d" | tr '.' '|'),"; then
2020-07-07 14:06:37 +02:00
_candidates="$_can"
break
fi
done
fi
2020-07-07 14:06:37 +02:00
response="$(echo "$_candidates" | sed "s/$_idn_d,//")"
2018-01-06 05:45:24 +01:00
_debug2 "response" "$response"
if [ -z "$response" ]; then
_err "get to authz error."
2018-03-14 14:27:29 +01:00
_err "_authorizations_map" "$_authorizations_map"
2018-01-06 05:45:24 +01:00
_clearup
_on_issue_err "$_post_hook"
return 1
fi
else
if ! __get_domain_new_authz "$d"; then
_clearup
_on_issue_err "$_post_hook"
return 1
fi
2016-05-31 14:32:58 +02:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$thumbprint" ]; then
2017-02-06 12:53:12 +01:00
thumbprint="$(__calc_account_thumbprint)"
2016-03-08 13:44:12 +01:00
fi
2019-03-16 06:38:17 +01:00
entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
2016-03-08 13:44:12 +01:00
_debug entry "$entry"
keyauthorization=""
2016-11-09 12:30:39 +01:00
if [ -z "$entry" ]; then
if ! _startswith "$d" '*.'; then
_debug "Not a wildcard domain, lets check whether the validation is already valid."
if echo "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
_debug "$d is already valid."
keyauthorization="$STATE_VERIFIED"
_debug keyauthorization "$keyauthorization"
fi
fi
if [ -z "$keyauthorization" ]; then
2020-01-27 15:22:25 +01:00
_err "Error, can not get domain token entry $d for $vtype"
_supported_vtypes="$(echo "$response" | _egrep_o "\"challenges\":\[[^]]*]" | tr '{' "\n" | grep type | cut -d '"' -f 4 | tr "\n" ' ')"
if [ "$_supported_vtypes" ]; then
_err "The supported validation types are: $_supported_vtypes, but you specified: $vtype"
fi
_clearup
_on_issue_err "$_post_hook"
return 1
fi
2018-01-06 05:45:24 +01:00
fi
2020-01-27 16:30:36 +01:00
if [ -z "$keyauthorization" ]; then
token="$(echo "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
_debug token "$token"
2016-10-28 17:30:32 +02:00
if [ -z "$token" ]; then
_err "Error, can not get domain token $entry"
_clearup
_on_issue_err "$_post_hook"
return 1
fi
if [ "$ACME_VERSION" = "2" ]; then
uri="$(echo "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)"
else
uri="$(echo "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)"
fi
_debug uri "$uri"
2016-03-08 13:44:12 +01:00
if [ -z "$uri" ]; then
_err "Error, can not get domain uri. $entry"
_clearup
_on_issue_err "$_post_hook"
return 1
fi
keyauthorization="$token.$thumbprint"
_debug keyauthorization "$keyauthorization"
if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
_debug "$d is already verified."
keyauthorization="$STATE_VERIFIED"
_debug keyauthorization "$keyauthorization"
fi
fi
dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot"
2016-03-08 13:44:12 +01:00
_debug dvlist "$dvlist"
2016-11-09 12:30:39 +01:00
2017-02-13 16:29:37 +01:00
vlist="$vlist$dvlist$dvsep"
2016-03-08 13:44:12 +01:00
done
2017-02-13 16:29:37 +01:00
_debug vlist "$vlist"
2016-03-08 13:44:12 +01:00
#add entry
dns_entries=""
2016-03-08 13:44:12 +01:00
dnsadded=""
2017-02-13 16:29:37 +01:00
ventries=$(echo "$vlist" | tr "$dvsep" ' ')
2018-02-13 15:26:36 +01:00
_alias_index=1
2016-11-09 12:30:39 +01:00
for ventry in $ventries; do
2016-11-09 14:56:50 +01:00
d=$(echo "$ventry" | cut -d "$sep" -f 1)
keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
_currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
2018-01-06 10:39:15 +01:00
_debug d "$d"
2016-11-09 12:30:39 +01:00
if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
2017-02-15 13:24:24 +01:00
_debug "$d is already verified, skip $vtype."
_alias_index="$(_math "$_alias_index" + 1)"
continue
fi
2016-11-09 12:30:39 +01:00
if [ "$vtype" = "$VTYPE_DNS" ]; then
2016-03-08 13:44:12 +01:00
dnsadded='0'
2018-01-06 10:39:15 +01:00
_dns_root_d="$d"
if _startswith "$_dns_root_d" "*."; then
_dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')"
fi
2018-02-10 03:45:29 +01:00
_d_alias="$(_getfield "$_challenge_alias" "$_alias_index")"
_alias_index="$(_math "$_alias_index" + 1)"
_debug "_d_alias" "$_d_alias"
if [ "$_d_alias" ]; then
2018-02-12 14:49:22 +01:00
if _startswith "$_d_alias" "$DNS_ALIAS_PREFIX"; then
txtdomain="$(echo "$_d_alias" | sed "s/$DNS_ALIAS_PREFIX//")"
else
txtdomain="_acme-challenge.$_d_alias"
fi
dns_entry="${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$txtdomain$dvsep$_currentRoot"
2018-02-10 03:45:29 +01:00
else
txtdomain="_acme-challenge.$_dns_root_d"
dns_entry="${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$dvsep$_currentRoot"
2018-02-10 03:45:29 +01:00
fi
2016-03-08 13:44:12 +01:00
_debug txtdomain "$txtdomain"
2017-01-29 04:47:04 +01:00
txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)"
2016-03-08 13:44:12 +01:00
_debug txt "$txt"
2016-10-11 14:56:59 +02:00
d_api="$(_findHook "$_dns_root_d" $_SUB_FOLDER_DNSAPI "$_currentRoot")"
2016-03-08 13:44:12 +01:00
_debug d_api "$d_api"
dns_entry="$dns_entry$dvsep$txt${dvsep}$d_api"
_debug2 dns_entry "$dns_entry"
2016-11-09 12:30:39 +01:00
if [ "$d_api" ]; then
2019-05-17 14:16:26 +02:00
_debug "Found domain api file: $d_api"
2016-03-08 13:44:12 +01:00
else
if [ "$_currentRoot" != "$W_DNS" ]; then
_err "Can not find dns api hook for: $_currentRoot"
_info "You need to add the txt record manually."
fi
_info "$(__red "Add the following TXT record:")"
2017-07-04 03:08:54 +02:00
_info "$(__red "Domain: '$(__green "$txtdomain")'")"
_info "$(__red "TXT value: '$(__green "$txt")'")"
_info "$(__red "Please be aware that you prepend _acme-challenge. before your domain")"
_info "$(__red "so the resulting subdomain will be: $txtdomain")"
2016-03-08 13:44:12 +01:00
continue
fi
2016-11-09 12:30:39 +01:00
2016-03-31 15:28:54 +02:00
(
2016-11-09 14:56:50 +01:00
if ! . "$d_api"; then
2016-03-31 15:28:54 +02:00
_err "Load file $d_api error. Please check your api file and try again."
return 1
fi
2016-11-09 12:30:39 +01:00
addcommand="${_currentRoot}_add"
2016-11-09 14:56:50 +01:00
if ! _exists "$addcommand"; then
2016-03-31 15:28:54 +02:00
_err "It seems that your api file is not correct, it must have a function named: $addcommand"
return 1
fi
2019-05-17 14:16:26 +02:00
_info "Adding txt value: $txt for domain: $txtdomain"
2016-11-09 14:56:50 +01:00
if ! $addcommand "$txtdomain" "$txt"; then
2016-03-31 15:28:54 +02:00
_err "Error add txt for domain:$txtdomain"
return 1
fi
2019-05-17 14:16:26 +02:00
_info "The txt record is added: Success."
2016-03-31 15:28:54 +02:00
)
2016-11-09 12:30:39 +01:00
if [ "$?" != "0" ]; then
2017-07-01 14:31:42 +02:00
_on_issue_err "$_post_hook" "$vlist"
_clearup
2016-03-08 13:44:12 +01:00
return 1
fi
dns_entries="$dns_entries$dns_entry
"
_debug2 "$dns_entries"
2016-03-08 13:44:12 +01:00
dnsadded='1'
fi
done
2016-11-09 12:30:39 +01:00
if [ "$dnsadded" = '0' ]; then
_savedomainconf "Le_Vlist" "$vlist"
2016-03-08 13:44:12 +01:00
_debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
_err "Please add the TXT records to the domains, and re-run with --renew."
_on_issue_err "$_post_hook"
_clearup
2016-03-08 13:44:12 +01:00
return 1
fi
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ "$dns_entries" ]; then
2016-11-09 12:30:39 +01:00
if [ -z "$Le_DNSSleep" ]; then
2020-05-22 19:28:29 +02:00
_info "Let's check each DNS record now. Sleep 20 seconds first."
_sleep 20
if ! _check_dns_entries; then
_err "check dns error."
_on_issue_err "$_post_hook"
_clearup
return 1
fi
else
2016-11-09 12:30:39 +01:00
_savedomainconf "Le_DNSSleep" "$Le_DNSSleep"
_info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect"
_sleep "$Le_DNSSleep"
fi
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
NGINX_RESTORE_VLIST=""
2016-03-08 13:44:12 +01:00
_debug "ok, let's start to verify"
_ncIndex=1
2017-02-13 16:29:37 +01:00
ventries=$(echo "$vlist" | tr "$dvsep" ' ')
2016-11-09 12:30:39 +01:00
for ventry in $ventries; do
2016-11-09 14:56:50 +01:00
d=$(echo "$ventry" | cut -d "$sep" -f 1)
keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
uri=$(echo "$ventry" | cut -d "$sep" -f 3)
vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
_currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
2016-11-09 12:30:39 +01:00
if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
_info "$d is already verified, skip $vtype."
continue
fi
_info "Verifying: $d"
2016-03-08 13:44:12 +01:00
_debug "d" "$d"
_debug "keyauthorization" "$keyauthorization"
_debug "uri" "$uri"
removelevel=""
token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)"
_debug "_currentRoot" "$_currentRoot"
2016-11-09 12:30:39 +01:00
if [ "$vtype" = "$VTYPE_HTTP" ]; then
if [ "$_currentRoot" = "$NO_VALUE" ]; then
2016-03-08 13:44:12 +01:00
_info "Standalone mode server"
2017-02-19 15:09:22 +01:00
_ncaddr="$(_getfield "$_local_addr" "$_ncIndex")"
_ncIndex="$(_math $_ncIndex + 1)"
_startserver "$keyauthorization" "$_ncaddr"
2016-11-09 12:30:39 +01:00
if [ "$?" != "0" ]; then
2016-04-16 12:31:00 +02:00
_clearup
_on_issue_err "$_post_hook" "$vlist"
2016-04-12 17:18:22 +02:00
return 1
fi
2016-10-29 04:53:45 +02:00
sleep 1
2016-11-09 14:56:50 +01:00
_debug serverproc "$serverproc"
2017-02-06 13:42:54 +01:00
elif [ "$_currentRoot" = "$MODE_STATELESS" ]; then
_info "Stateless mode for domain:$d"
_sleep 1
2017-02-13 16:29:37 +01:00
elif _startswith "$_currentRoot" "$NGINX"; then
_info "Nginx mode for domain:$d"
#set up nginx server
FOUND_REAL_NGINX_CONF=""
BACKUP_NGINX_CONF=""
if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then
_clearup
_on_issue_err "$_post_hook" "$vlist"
2017-02-13 16:29:37 +01:00
return 1
fi
2017-02-14 15:41:34 +01:00
if [ "$FOUND_REAL_NGINX_CONF" ]; then
2017-02-13 16:29:37 +01:00
_realConf="$FOUND_REAL_NGINX_CONF"
_backup="$BACKUP_NGINX_CONF"
_debug _realConf "$_realConf"
NGINX_RESTORE_VLIST="$d$sep$_realConf$sep$_backup$dvsep$NGINX_RESTORE_VLIST"
2017-02-13 16:29:37 +01:00
fi
_sleep 1
2016-03-08 13:44:12 +01:00
else
2016-11-09 12:30:39 +01:00
if [ "$_currentRoot" = "apache" ]; then
2016-04-16 13:23:44 +02:00
wellknown_path="$ACME_DIR"
else
wellknown_path="$_currentRoot/.well-known/acme-challenge"
2016-11-09 12:30:39 +01:00
if [ ! -d "$_currentRoot/.well-known" ]; then
2016-04-16 13:23:44 +02:00
removelevel='1'
2016-11-09 12:30:39 +01:00
elif [ ! -d "$_currentRoot/.well-known/acme-challenge" ]; then
2016-04-16 13:23:44 +02:00
removelevel='2'
else
removelevel='3'
fi
2016-03-08 13:44:12 +01:00
fi
2016-04-16 13:23:44 +02:00
2016-03-08 13:44:12 +01:00
_debug wellknown_path "$wellknown_path"
2016-04-16 13:23:44 +02:00
2016-03-08 13:44:12 +01:00
_debug "writing token:$token to $wellknown_path/$token"
mkdir -p "$wellknown_path"
2016-11-01 12:14:33 +01:00
2016-11-09 12:30:39 +01:00
if ! printf "%s" "$keyauthorization" >"$wellknown_path/$token"; then
2016-11-01 12:14:33 +01:00
_err "$d:Can not write token to file : $wellknown_path/$token"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err "$_post_hook" "$vlist"
2016-11-01 12:14:33 +01:00
return 1
fi
2016-11-09 12:30:39 +01:00
if [ ! "$usingApache" ]; then
2016-11-09 15:35:30 +01:00
if webroot_owner=$(_stat "$_currentRoot"); then
_debug "Changing owner/group of .well-known to $webroot_owner"
if ! _exec "chown -R \"$webroot_owner\" \"$_currentRoot/.well-known\""; then
_debug "$(cat "$_EXEC_TEMP_ERR")"
_exec_err >/dev/null 2>&1
fi
else
2017-03-26 07:25:23 +02:00
_debug "not changing owner/group of webroot"
fi
fi
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
fi
elif [ "$vtype" = "$VTYPE_ALPN" ]; then
acmevalidationv1="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")"
_debug acmevalidationv1 "$acmevalidationv1"
if ! _starttlsserver "$d" "" "$Le_TLSPort" "$keyauthorization" "$_ncaddr" "$acmevalidationv1"; then
_err "Start tls server error."
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if ! __trigger_validation "$uri" "$keyauthorization" "$vtype"; then
2016-05-31 14:32:58 +02:00
_err "$d:Can not get challenge: $response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err "$_post_hook" "$vlist"
2016-05-31 14:32:58 +02:00
return 1
fi
2016-11-09 12:30:39 +01:00
2018-01-06 05:45:24 +01:00
if [ "$code" ] && [ "$code" != '202' ]; then
if [ "$code" = '200' ]; then
2018-01-06 05:45:24 +01:00
_debug "trigger validation code: $code"
else
_err "$d:Challenge error: $response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err "$_post_hook" "$vlist"
return 1
2018-01-06 05:45:24 +01:00
fi
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
2016-04-12 17:18:22 +02:00
waittimes=0
2016-11-09 12:30:39 +01:00
if [ -z "$MAX_RETRY_TIMES" ]; then
2016-04-12 17:18:22 +02:00
MAX_RETRY_TIMES=30
fi
2016-11-09 12:30:39 +01:00
while true; do
2016-11-09 15:07:32 +01:00
waittimes=$(_math "$waittimes" + 1)
2016-11-09 12:30:39 +01:00
if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ]; then
2016-04-12 17:18:22 +02:00
_err "$d:Timeout"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err "$_post_hook" "$vlist"
2016-04-12 17:18:22 +02:00
return 1
fi
2016-11-09 12:30:39 +01:00
2016-10-29 04:53:45 +02:00
_debug "sleep 2 secs to verify"
sleep 2
2016-03-08 13:44:12 +01:00
_debug "checking"
if [ "$ACME_VERSION" = "2" ]; then
_send_signed_request "$uri"
else
response="$(_get "$uri")"
fi
2016-11-09 12:30:39 +01:00
if [ "$?" != "0" ]; then
_err "$d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
2016-03-08 13:44:12 +01:00
_clearup
_on_issue_err "$_post_hook" "$vlist"
2016-03-08 13:44:12 +01:00
return 1
fi
2016-05-31 15:20:10 +02:00
_debug2 original "$response"
2016-11-09 12:30:39 +01:00
response="$(echo "$response" | _normalizeJson)"
2016-05-31 06:28:43 +02:00
_debug2 response "$response"
2016-11-09 12:30:39 +01:00
status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"')
if [ "$status" = "valid" ]; then
2016-11-24 15:36:21 +01:00
_info "$(__green Success)"
2016-11-09 14:56:50 +01:00
_stopserver "$serverproc"
2016-03-08 13:44:12 +01:00
serverproc=""
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
2016-11-09 12:30:39 +01:00
break
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ "$status" = "invalid" ]; then
2019-03-16 07:00:15 +01:00
error="$(echo "$response" | _egrep_o '"error":\{[^\}]*')"
2016-11-09 12:30:39 +01:00
_debug2 error "$error"
errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)"
_debug2 errordetail "$errordetail"
if [ "$errordetail" ]; then
_err "$d:Verify error:$errordetail"
else
_err "$d:Verify error:$error"
fi
if [ "$DEBUG" ]; then
if [ "$vtype" = "$VTYPE_HTTP" ]; then
_debug "Debug: get token url."
_get "http://$d/.well-known/acme-challenge/$token" "" 1
fi
fi
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
2016-03-08 13:44:12 +01:00
_clearup
_on_issue_err "$_post_hook" "$vlist"
2016-11-09 12:30:39 +01:00
return 1
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ "$status" = "pending" ]; then
2016-03-08 13:44:12 +01:00
_info "Pending"
elif [ "$status" = "processing" ]; then
_info "Processing"
2016-03-08 13:44:12 +01:00
else
2016-11-09 12:30:39 +01:00
_err "$d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
2016-03-08 13:44:12 +01:00
_clearup
_on_issue_err "$_post_hook" "$vlist"
2016-03-08 13:44:12 +01:00
return 1
fi
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
done
2016-11-09 12:30:39 +01:00
2016-03-08 13:44:12 +01:00
done
_clearup
_info "Verify finished, start to sign."
2017-01-29 04:47:04 +01:00
der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)"
2016-11-09 12:30:39 +01:00
2018-01-06 05:45:24 +01:00
if [ "$ACME_VERSION" = "2" ]; then
2020-08-16 11:36:24 +02:00
_info "Lets finalize the order."
_info "Le_OrderFinalize" "$Le_OrderFinalize"
if ! _send_signed_request "${Le_OrderFinalize}" "{\"csr\": \"$der\"}"; then
2018-01-06 05:45:24 +01:00
_err "Sign failed."
_on_issue_err "$_post_hook"
return 1
fi
if [ "$code" != "200" ]; then
_err "Sign failed, finalize code is not 200."
2018-03-18 14:06:37 +01:00
_err "$response"
2018-01-06 05:45:24 +01:00
_on_issue_err "$_post_hook"
return 1
fi
if [ -z "$Le_LinkOrder" ]; then
Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n" | cut -d ":" -f 2-)"
fi
_savedomainconf "Le_LinkOrder" "$Le_LinkOrder"
_link_cert_retry=0
2020-03-30 21:10:12 +02:00
_MAX_CERT_RETRY=30
while [ "$_link_cert_retry" -lt "$_MAX_CERT_RETRY" ]; do
if _contains "$response" "\"status\":\"valid\""; then
_debug "Order status is valid."
2019-03-16 07:00:15 +01:00
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."
2020-05-25 20:28:05 +02:00
_retryafter=$(echo "$responseHeaders" | grep -i "^Retry-After *:" | cut -d : -f 2 | tr -d ' ' | tr -d '\r')
_debug "_retryafter" "$_retryafter"
if [ "$_retryafter" ]; then
_info "Retry after: $_retryafter"
_sleep $_retryafter
else
_sleep 2
fi
else
_err "Sign error, wrong status"
_err "$response"
_on_issue_err "$_post_hook"
return 1
fi
#the order is processing, so we are going to poll order status
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
_info "Polling order status: $Le_LinkOrder"
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
2016-11-09 12:30:39 +01:00
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
2020-08-16 11:36:24 +02:00
_info "Downloading cert."
_info "Le_LinkCert" "$Le_LinkCert"
2019-02-17 07:19:14 +01:00
if ! _send_signed_request "$Le_LinkCert"; then
2018-03-18 14:06:37 +01:00
_err "Sign failed, can not download cert:$Le_LinkCert."
_err "$response"
2018-01-06 05:45:24 +01:00
_on_issue_err "$_post_hook"
return 1
fi
2016-03-08 13:44:12 +01:00
2019-02-17 07:19:14 +01:00
echo "$response" >"$CERT_PATH"
_split_cert_chain "$CERT_PATH" "$CERT_FULLCHAIN_PATH" "$CA_CERT_PATH"
if [ "$_preferred_chain" ] && [ -f "$CERT_FULLCHAIN_PATH" ]; then
if ! _match_issuer "$CERT_FULLCHAIN_PATH" "$_preferred_chain"; then
rels="$(echo "$responseHeaders" | tr -d ' <>' | grep -i "^link:" | grep -i 'rel="alternate"' | cut -d : -f 2- | cut -d ';' -f 1)"
_debug2 "rels" "$rels"
for rel in $rels; do
_info "Try rel: $rel"
if ! _send_signed_request "$rel"; then
_err "Sign failed, can not download cert:$rel"
_err "$response"
continue
fi
_relcert="$CERT_PATH.alt"
_relfullchain="$CERT_FULLCHAIN_PATH.alt"
_relca="$CA_CERT_PATH.alt"
echo "$response" >"$_relcert"
_split_cert_chain "$_relcert" "$_relfullchain" "$_relca"
if _match_issuer "$_relfullchain" "$_preferred_chain"; then
_info "Matched issuer in: $rel"
cat $_relcert >"$CERT_PATH"
cat $_relfullchain >"$CERT_FULLCHAIN_PATH"
cat $_relca >"$CA_CERT_PATH"
break
fi
done
fi
fi
2018-01-06 05:45:24 +01:00
else
if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
2018-03-18 04:14:03 +01:00
_err "Sign failed. $response"
2018-01-06 05:45:24 +01:00
_on_issue_err "$_post_hook"
return 1
fi
_rcert="$response"
Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
2016-11-09 12:30:39 +01:00
echo "$BEGIN_CERT" >"$CERT_PATH"
2016-03-08 13:44:12 +01:00
2016-10-29 11:43:38 +02:00
#if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then
# _debug "Get cert failed. Let's try last response."
2017-04-17 13:08:34 +02:00
# printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH"
2016-10-29 11:43:38 +02:00
#fi
2016-11-09 12:30:39 +01:00
if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >>"$CERT_PATH"; then
2016-10-29 11:43:38 +02:00
_debug "Try cert link."
2016-11-09 12:30:39 +01:00
_get "$Le_LinkCert" | _base64 "multiline" >>"$CERT_PATH"
fi
2016-11-09 12:30:39 +01:00
echo "$END_CERT" >>"$CERT_PATH"
2018-01-06 05:45:24 +01:00
fi
_debug "Le_LinkCert" "$Le_LinkCert"
_savedomainconf "Le_LinkCert" "$Le_LinkCert"
2018-03-09 01:06:42 +01:00
if [ -z "$Le_LinkCert" ] || ! _checkcert "$CERT_PATH"; then
response="$(echo "$response" | _dbase64 "multiline" | tr -d '\0' | _normalizeJson)"
2018-03-09 01:06:42 +01:00
_err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')"
_on_issue_err "$_post_hook"
return 1
fi
2018-01-06 05:45:24 +01:00
if [ "$Le_LinkCert" ]; then
_info "$(__green "Cert success.")"
2016-03-08 13:44:12 +01:00
cat "$CERT_PATH"
2016-11-09 12:30:39 +01:00
_info "Your cert is in $(__green " $CERT_PATH ")"
if [ -f "$CERT_KEY_PATH" ]; then
_info "Your cert key is in $(__green " $CERT_KEY_PATH ")"
fi
2020-08-16 11:36:24 +02:00
if [ ! "$USER_PATH" ] || [ ! "$_ACME_IN_CRON" ]; then
2016-04-05 15:08:19 +02:00
USER_PATH="$PATH"
_saveaccountconf "USER_PATH" "$USER_PATH"
fi
2016-03-08 13:44:12 +01:00
fi
if [ "$ACME_VERSION" = "2" ]; then
_debug "v2 chain."
else
2018-03-09 01:06:42 +01:00
cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH"
Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>')
2017-03-30 15:16:25 +02:00
if [ "$Le_LinkIssuer" ]; then
if ! _contains "$Le_LinkIssuer" ":"; then
_info "$(__red "Relative issuer link found.")"
Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer"
2017-03-30 15:16:25 +02:00
fi
_debug Le_LinkIssuer "$Le_LinkIssuer"
_savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer"
2017-03-30 15:16:25 +02:00
_link_issuer_retry=0
_MAX_ISSUER_RETRY=5
while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do
_debug _link_issuer_retry "$_link_issuer_retry"
if [ "$ACME_VERSION" = "2" ]; then
if _send_signed_request "$Le_LinkIssuer"; then
echo "$response" >"$CA_CERT_PATH"
break
fi
else
if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then
echo "$BEGIN_CERT" >"$CA_CERT_PATH"
_base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH"
echo "$END_CERT" >>"$CA_CERT_PATH"
2018-03-14 11:05:57 +01:00
if ! _checkcert "$CA_CERT_PATH"; then
2018-03-09 01:06:42 +01:00
_err "Can not get the ca cert."
break
fi
cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH"
rm -f "$CA_CERT_PATH.der"
break
fi
2018-01-06 05:45:24 +01:00
fi
_link_issuer_retry=$(_math $_link_issuer_retry + 1)
_sleep "$_link_issuer_retry"
done
if [ "$_link_issuer_retry" = "$_MAX_ISSUER_RETRY" ]; then
_err "Max retry for issuer ca cert is reached."
2017-03-30 15:16:25 +02:00
fi
else
_debug "No Le_LinkIssuer header found."
2017-03-30 15:16:25 +02:00
fi
2016-03-08 13:44:12 +01:00
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 ")"
2016-11-09 12:30:39 +01:00
2016-08-25 15:46:31 +02:00
Le_CertCreateTime=$(_time)
2016-11-09 12:30:39 +01:00
_savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime"
Le_CertCreateTimeStr=$(date -u)
_savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr"
if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ]; then
Le_RenewalDays="$DEFAULT_RENEW"
2016-06-13 08:49:00 +02:00
else
2016-11-09 12:30:39 +01:00
_savedomainconf "Le_RenewalDays" "$Le_RenewalDays"
fi
2016-11-09 12:30:39 +01:00
if [ "$CA_BUNDLE" ]; then
_saveaccountconf CA_BUNDLE "$CA_BUNDLE"
else
_clearaccountconf "CA_BUNDLE"
fi
if [ "$CA_PATH" ]; then
_saveaccountconf CA_PATH "$CA_PATH"
else
_clearaccountconf "CA_PATH"
fi
2016-11-09 12:30:39 +01:00
if [ "$HTTPS_INSECURE" ]; then
2016-08-14 16:37:21 +02:00
_saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE"
else
2016-11-09 12:30:39 +01:00
_clearaccountconf "HTTPS_INSECURE"
fi
2016-04-17 11:33:08 +02:00
2016-11-09 12:30:39 +01:00
if [ "$Le_Listen_V4" ]; then
_savedomainconf "Le_Listen_V4" "$Le_Listen_V4"
2016-10-02 17:54:21 +02:00
_cleardomainconf Le_Listen_V6
2016-11-09 12:30:39 +01:00
elif [ "$Le_Listen_V6" ]; then
_savedomainconf "Le_Listen_V6" "$Le_Listen_V6"
2016-10-02 17:54:21 +02:00
_cleardomainconf Le_Listen_V4
fi
2016-09-28 07:07:51 +02:00
if [ "$Le_ForceNewDomainKey" = "1" ]; then
_savedomainconf "Le_ForceNewDomainKey" "$Le_ForceNewDomainKey"
else
_cleardomainconf Le_ForceNewDomainKey
fi
2016-11-09 14:56:50 +01:00
Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60)
2016-11-09 12:30:39 +01:00
2016-11-09 14:56:50 +01:00
Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime")
2016-11-09 12:30:39 +01:00
_savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr"
2016-11-09 14:56:50 +01:00
Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400)
2016-11-09 12:30:39 +01:00
_savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime"
2016-09-28 07:07:51 +02:00
2017-02-19 15:09:22 +01:00
if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then
_savedomainconf "Le_RealCertPath" "$_real_cert"
_savedomainconf "Le_RealCACertPath" "$_real_ca"
_savedomainconf "Le_RealKeyPath" "$_real_key"
_savedomainconf "Le_ReloadCmd" "$_reload_cmd" "base64"
2017-02-19 15:09:22 +01:00
_savedomainconf "Le_RealFullChainPath" "$_real_fullchain"
if ! _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"; then
return 1
fi
2016-04-27 17:34:29 +02:00
fi
if ! _on_issue_success "$_post_hook" "$_renew_hook"; then
_err "Call hook error."
return 1
fi
2016-03-08 13:44:12 +01:00
}
#in_out_cert out_fullchain out out_ca
_split_cert_chain() {
_certf="$1"
_fullchainf="$2"
_caf="$3"
if [ "$(grep -- "$BEGIN_CERT" "$_certf" | wc -l)" -gt "1" ]; then
_debug "Found cert chain"
cat "$_certf" >"$_fullchainf"
_end_n="$(grep -n -- "$END_CERT" "$_fullchainf" | _head_n 1 | cut -d : -f 1)"
_debug _end_n "$_end_n"
sed -n "1,${_end_n}p" "$_fullchainf" >"$_certf"
_end_n="$(_math $_end_n + 1)"
sed -n "${_end_n},9999p" "$_fullchainf" >"$_caf"
fi
}
#domain [isEcc]
2016-03-08 13:44:12 +01:00
renew() {
Le_Domain="$1"
2016-11-09 12:30:39 +01:00
if [ -z "$Le_Domain" ]; then
_usage "Usage: $PROJECT_ENTRY --renew -d domain.com [--ecc]"
2016-03-08 13:44:12 +01:00
return 1
fi
_isEcc="$2"
2016-11-09 15:09:30 +01:00
_initpath "$Le_Domain" "$_isEcc"
2016-08-25 07:06:04 +02:00
_info "$(__green "Renew: '$Le_Domain'")"
2016-11-09 12:30:39 +01:00
if [ ! -f "$DOMAIN_CONF" ]; then
_info "'$Le_Domain' is not a issued domain, skip."
2019-05-04 04:59:00 +02:00
return $RENEW_SKIP
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ "$Le_RenewalDays" ]; then
_savedomainconf Le_RenewalDays "$Le_RenewalDays"
fi
. "$DOMAIN_CONF"
_debug Le_API "$Le_API"
2019-03-12 14:16:15 +01:00
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
2016-11-09 12:30:39 +01:00
if [ "$Le_API" ]; then
2017-06-17 09:49:45 +02:00
export ACME_DIRECTORY="$Le_API"
2016-12-10 14:32:47 +01:00
#reload ca configs
ACCOUNT_KEY_PATH=""
ACCOUNT_JSON_PATH=""
CA_CONF=""
_debug3 "initpath again."
_initpath "$Le_Domain" "$_isEcc"
2016-09-27 17:43:18 +02:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
2016-08-25 07:06:04 +02:00
_info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")"
_info "Add '$(__red '--force')' to force to renew."
2016-11-09 15:09:30 +01:00
return "$RENEW_SKIP"
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
2020-08-16 11:36:24 +02:00
if [ "$_ACME_IN_CRON" = "1" ] && [ -z "$Le_CertCreateTime" ]; then
_info "Skip invalid cert for: $Le_Domain"
2019-05-04 04:59:00 +02:00
return $RENEW_SKIP
fi
2020-08-16 11:36:24 +02:00
_ACME_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" "$Le_Preferred_Chain"
2016-11-09 15:09:30 +01:00
res="$?"
2016-11-09 12:30:39 +01:00
if [ "$res" != "0" ]; then
2016-11-09 15:09:30 +01:00
return "$res"
2016-10-11 14:56:59 +02:00
fi
2016-11-09 12:30:39 +01:00
if [ "$Le_DeployHook" ]; then
_deploy "$Le_Domain" "$Le_DeployHook"
2016-11-09 15:09:30 +01:00
res="$?"
2016-10-11 14:56:59 +02:00
fi
2016-11-09 12:30:39 +01:00
2020-08-16 11:36:24 +02:00
_ACME_IS_RENEW=""
2016-03-08 13:44:12 +01:00
2016-11-09 15:09:30 +01:00
return "$res"
2016-03-08 13:44:12 +01:00
}
2016-06-18 05:29:28 +02:00
#renewAll [stopRenewOnError]
2016-03-08 13:44:12 +01:00
renewAll() {
_initpath
2016-06-18 05:29:28 +02:00
_stopRenewOnError="$1"
_debug "_stopRenewOnError" "$_stopRenewOnError"
_ret="0"
_success_msg=""
_error_msg=""
_skipped_msg=""
_error_level=$NOTIFY_LEVEL_SKIP
_notify_code=$RENEW_SKIP
_set_level=${NOTIFY_LEVEL:-$NOTIFY_LEVEL_DEFAULT}
_debug "_set_level" "$_set_level"
2016-11-11 14:13:33 +01:00
for di in "${CERT_HOME}"/*.*/; do
_debug di "$di"
2016-11-18 12:44:43 +01:00
if ! [ -d "$di" ]; then
_debug "Not directory, skip: $di"
continue
fi
2016-11-11 14:13:33 +01:00
d=$(basename "$di")
2016-11-09 15:28:12 +01:00
_debug d "$d"
(
2016-11-09 15:28:12 +01:00
if _endswith "$d" "$ECC_SUFFIX"; then
_isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2)
d=$(echo "$d" | cut -d "$ECC_SEP" -f 1)
fi
renew "$d" "$_isEcc"
2016-04-27 16:14:15 +02:00
)
2016-06-18 05:29:28 +02:00
rc="$?"
_debug "Return code: $rc"
if [ "$rc" = "0" ]; then
if [ $_error_level -gt $NOTIFY_LEVEL_RENEW ]; then
_error_level="$NOTIFY_LEVEL_RENEW"
_notify_code=0
fi
2020-08-16 11:36:24 +02:00
if [ "$_ACME_IN_CRON" ]; then
if [ $_set_level -ge $NOTIFY_LEVEL_RENEW ]; then
if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then
_send_notify "Renew $d success" "Good, the cert is renewed." "$NOTIFY_HOOK" 0
fi
fi
fi
_success_msg="${_success_msg} $d
"
elif [ "$rc" = "$RENEW_SKIP" ]; then
if [ $_error_level -gt $NOTIFY_LEVEL_SKIP ]; then
_error_level="$NOTIFY_LEVEL_SKIP"
_notify_code=$RENEW_SKIP
fi
2020-08-16 11:36:24 +02:00
if [ "$_ACME_IN_CRON" ]; then
if [ $_set_level -ge $NOTIFY_LEVEL_SKIP ]; then
if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then
_send_notify "Renew $d skipped" "Good, the cert is skipped." "$NOTIFY_HOOK" "$RENEW_SKIP"
fi
fi
2016-06-18 05:29:28 +02:00
fi
_info "Skipped $d"
_skipped_msg="${_skipped_msg} $d
"
else
if [ $_error_level -gt $NOTIFY_LEVEL_ERROR ]; then
_error_level="$NOTIFY_LEVEL_ERROR"
_notify_code=1
fi
2020-08-16 11:36:24 +02:00
if [ "$_ACME_IN_CRON" ]; then
if [ $_set_level -ge $NOTIFY_LEVEL_ERROR ]; then
if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then
_send_notify "Renew $d error" "There is an error." "$NOTIFY_HOOK" 1
fi
fi
fi
_error_msg="${_error_msg} $d
"
if [ "$_stopRenewOnError" ]; then
_err "Error renew $d, stop now."
_ret="$rc"
break
else
_ret="$rc"
_err "Error renew $d."
fi
2016-06-18 05:29:28 +02:00
fi
2016-03-08 13:44:12 +01:00
done
_debug _error_level "$_error_level"
2019-06-19 15:50:41 +02:00
_debug _set_level "$_set_level"
2020-08-16 11:36:24 +02:00
if [ "$_ACME_IN_CRON" ] && [ $_error_level -le $_set_level ]; then
if [ -z "$NOTIFY_MODE" ] || [ "$NOTIFY_MODE" = "$NOTIFY_MODE_BULK" ]; then
_msg_subject="Renew"
if [ "$_error_msg" ]; then
_msg_subject="${_msg_subject} Error"
_msg_data="Error certs:
${_error_msg}
"
fi
if [ "$_success_msg" ]; then
_msg_subject="${_msg_subject} Success"
_msg_data="${_msg_data}Success certs:
${_success_msg}
"
fi
if [ "$_skipped_msg" ]; then
_msg_subject="${_msg_subject} Skipped"
_msg_data="${_msg_data}Skipped certs:
${_skipped_msg}
"
fi
_send_notify "$_msg_subject" "$_msg_data" "$NOTIFY_HOOK" "$_notify_code"
fi
fi
2016-11-09 15:28:12 +01:00
return "$_ret"
2016-03-08 13:44:12 +01:00
}
#csr webroot
2016-11-09 12:30:39 +01:00
signcsr() {
_csrfile="$1"
_csrW="$2"
if [ -z "$_csrfile" ] || [ -z "$_csrW" ]; then
_usage "Usage: $PROJECT_ENTRY --signcsr --csr mycsr.csr -w /path/to/webroot/a.com/ "
return 1
fi
2018-02-10 03:45:29 +01:00
_real_cert="$3"
_real_key="$4"
_real_ca="$5"
_reload_cmd="$6"
_real_fullchain="$7"
_pre_hook="${8}"
_post_hook="${9}"
_renew_hook="${10}"
_local_addr="${11}"
_challenge_alias="${12}"
_csrsubj=$(_readSubjectFromCSR "$_csrfile")
2016-11-09 12:30:39 +01:00
if [ "$?" != "0" ]; then
_err "Can not read subject from csr: $_csrfile"
return 1
fi
_debug _csrsubj "$_csrsubj"
if _contains "$_csrsubj" ' ' || ! _contains "$_csrsubj" '.'; then
_info "It seems that the subject: $_csrsubj is not a valid domain name. Drop it."
_csrsubj=""
fi
_csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile")
2016-11-09 12:30:39 +01:00
if [ "$?" != "0" ]; then
_err "Can not read domain list from csr: $_csrfile"
return 1
fi
_debug "_csrdomainlist" "$_csrdomainlist"
2016-11-09 12:30:39 +01:00
if [ -z "$_csrsubj" ]; then
_csrsubj="$(_getfield "$_csrdomainlist" 1)"
_debug _csrsubj "$_csrsubj"
_csrdomainlist="$(echo "$_csrdomainlist" | cut -d , -f 2-)"
_debug "_csrdomainlist" "$_csrdomainlist"
fi
2016-11-09 12:30:39 +01:00
if [ -z "$_csrsubj" ]; then
_err "Can not read subject from csr: $_csrfile"
return 1
fi
2016-11-09 12:30:39 +01:00
_csrkeylength=$(_readKeyLengthFromCSR "$_csrfile")
2016-11-09 12:30:39 +01:00
if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then
_err "Can not read key length from csr: $_csrfile"
return 1
fi
2016-11-09 12:30:39 +01:00
if [ -z "$ACME_VERSION" ] && _contains "$_csrsubj,$_csrdomainlist" "*."; then
export ACME_VERSION=2
fi
_initpath "$_csrsubj" "$_csrkeylength"
mkdir -p "$DOMAIN_PATH"
2016-11-09 12:30:39 +01:00
_info "Copy csr to: $CSR_PATH"
cp "$_csrfile" "$CSR_PATH"
2016-11-09 12:30:39 +01:00
2018-02-10 03:45:29 +01:00
issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_addr" "$_challenge_alias"
2016-11-09 12:30:39 +01:00
}
showcsr() {
2016-11-09 12:30:39 +01:00
_csrfile="$1"
_csrd="$2"
if [ -z "$_csrfile" ] && [ -z "$_csrd" ]; then
_usage "Usage: $PROJECT_ENTRY --showcsr --csr mycsr.csr"
return 1
fi
_initpath
2016-11-09 12:30:39 +01:00
_csrsubj=$(_readSubjectFromCSR "$_csrfile")
2016-11-09 12:30:39 +01:00
if [ "$?" != "0" ] || [ -z "$_csrsubj" ]; then
_err "Can not read subject from csr: $_csrfile"
return 1
fi
2016-11-09 12:30:39 +01:00
_info "Subject=$_csrsubj"
_csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile")
2016-11-09 12:30:39 +01:00
if [ "$?" != "0" ]; then
_err "Can not read domain list from csr: $_csrfile"
return 1
fi
_debug "_csrdomainlist" "$_csrdomainlist"
_info "SubjectAltNames=$_csrdomainlist"
_csrkeylength=$(_readKeyLengthFromCSR "$_csrfile")
2016-11-09 12:30:39 +01:00
if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then
_err "Can not read key length from csr: $_csrfile"
return 1
fi
_info "KeyLength=$_csrkeylength"
}
#listraw domain
2016-06-09 08:18:54 +02:00
list() {
_raw="$1"
_domain="$2"
2016-06-09 08:18:54 +02:00
_initpath
2016-11-09 12:30:39 +01:00
2016-06-14 07:07:33 +02:00
_sep="|"
2016-11-09 12:30:39 +01:00
if [ "$_raw" ]; then
if [ -z "$_domain" ]; then
printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}CA${_sep}Created${_sep}Renew"
fi
2016-11-11 14:13:33 +01:00
for di in "${CERT_HOME}"/*.*/; do
d=$(basename "$di")
2016-11-09 15:28:12 +01:00
_debug d "$d"
2016-06-14 07:07:33 +02:00
(
2016-11-09 15:28:12 +01:00
if _endswith "$d" "$ECC_SUFFIX"; then
_isEcc="ecc"
2016-11-09 15:28:12 +01:00
d=$(echo "$d" | cut -d "$ECC_SEP" -f 1)
fi
DOMAIN_CONF="$di/$d.conf"
2016-11-09 12:30:39 +01:00
if [ -f "$DOMAIN_CONF" ]; then
2016-06-14 07:07:33 +02:00
. "$DOMAIN_CONF"
_ca="$(_getCAShortName "$Le_API")"
if [ -z "$_domain" ]; then
printf "%s\n" "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$_ca${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr"
else
if [ "$_domain" = "$d" ]; then
cat "$DOMAIN_CONF"
fi
fi
2016-06-14 07:07:33 +02:00
fi
)
done
else
2016-11-09 12:30:39 +01:00
if _exists column; then
list "raw" "$_domain" | column -t -s "$_sep"
else
list "raw" "$_domain" | tr "$_sep" '\t'
fi
2016-06-14 07:07:33 +02:00
fi
2016-06-09 08:18:54 +02:00
}
_deploy() {
_d="$1"
_hooks="$2"
for _d_api in $(echo "$_hooks" | tr ',' " "); do
_deployApi="$(_findHook "$_d" $_SUB_FOLDER_DEPLOY "$_d_api")"
if [ -z "$_deployApi" ]; then
_err "The deploy hook $_d_api is not found."
return 1
fi
_debug _deployApi "$_deployApi"
if ! (
if ! . "$_deployApi"; then
_err "Load file $_deployApi error. Please check your api file and try again."
return 1
fi
d_command="${_d_api}_deploy"
if ! _exists "$d_command"; then
_err "It seems that your api file is not correct, it must have a function named: $d_command"
return 1
fi
if ! $d_command "$_d" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then
_err "Error deploy for domain:$_d"
return 1
fi
); then
_err "Deploy error."
return 1
else
_info "$(__green Success)"
fi
done
}
#domain hooks
2016-10-11 14:56:59 +02:00
deploy() {
_d="$1"
_hooks="$2"
2016-10-11 14:56:59 +02:00
_isEcc="$3"
if [ -z "$_hooks" ]; then
2016-10-11 14:56:59 +02:00
_usage "Usage: $PROJECT_ENTRY --deploy -d domain.com --deploy-hook cpanel [--ecc] "
return 1
fi
_initpath "$_d" "$_isEcc"
2016-11-09 12:30:39 +01:00
if [ ! -d "$DOMAIN_PATH" ]; then
_err "The domain '$_d' is not a cert name. You must use the cert name to specify the cert to install."
_err "Can not find path:'$DOMAIN_PATH'"
2016-10-11 14:56:59 +02:00
return 1
fi
2016-11-09 12:30:39 +01:00
. "$DOMAIN_CONF"
2016-11-09 12:30:39 +01:00
_savedomainconf Le_DeployHook "$_hooks"
2016-11-09 12:30:39 +01:00
_deploy "$_d" "$_hooks"
2016-10-11 14:56:59 +02:00
}
2016-03-08 13:44:12 +01:00
installcert() {
2017-02-19 15:09:22 +01:00
_main_domain="$1"
if [ -z "$_main_domain" ]; then
2017-03-22 14:20:35 +01:00
_usage "Usage: $PROJECT_ENTRY --installcert -d domain.com [--ecc] [--cert-file cert-file-path] [--key-file key-file-path] [--ca-file ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchain-file fullchain-path]"
2016-03-08 13:44:12 +01:00
return 1
fi
2017-02-19 15:09:22 +01:00
_real_cert="$2"
_real_key="$3"
_real_ca="$4"
_reload_cmd="$5"
_real_fullchain="$6"
_isEcc="$7"
2017-02-19 15:09:22 +01:00
_initpath "$_main_domain" "$_isEcc"
2016-11-09 12:30:39 +01:00
if [ ! -d "$DOMAIN_PATH" ]; then
_err "The domain '$_main_domain' is not a cert name. You must use the cert name to specify the cert to install."
_err "Can not find path:'$DOMAIN_PATH'"
return 1
fi
2017-02-19 15:09:22 +01:00
_savedomainconf "Le_RealCertPath" "$_real_cert"
_savedomainconf "Le_RealCACertPath" "$_real_ca"
_savedomainconf "Le_RealKeyPath" "$_real_key"
_savedomainconf "Le_ReloadCmd" "$_reload_cmd" "base64"
2017-02-19 15:09:22 +01:00
_savedomainconf "Le_RealFullChainPath" "$_real_fullchain"
2017-02-21 14:34:43 +01:00
_installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"
}
2016-03-08 13:44:12 +01:00
2017-02-21 14:34:43 +01:00
#domain cert key ca fullchain reloadcmd backup-prefix
_installcert() {
2017-02-19 15:09:22 +01:00
_main_domain="$1"
_real_cert="$2"
_real_key="$3"
_real_ca="$4"
2017-02-21 14:34:43 +01:00
_real_fullchain="$5"
_reload_cmd="$6"
_backup_prefix="$7"
2016-03-08 13:44:12 +01:00
2017-02-19 15:09:22 +01:00
if [ "$_real_cert" = "$NO_VALUE" ]; then
_real_cert=""
2016-04-27 16:14:15 +02:00
fi
2017-02-19 15:09:22 +01:00
if [ "$_real_key" = "$NO_VALUE" ]; then
_real_key=""
2016-04-27 16:14:15 +02:00
fi
2017-02-19 15:09:22 +01:00
if [ "$_real_ca" = "$NO_VALUE" ]; then
_real_ca=""
2016-04-27 16:14:15 +02:00
fi
2017-02-19 15:09:22 +01:00
if [ "$_reload_cmd" = "$NO_VALUE" ]; then
_reload_cmd=""
2016-04-27 16:14:15 +02:00
fi
2017-02-19 15:09:22 +01:00
if [ "$_real_fullchain" = "$NO_VALUE" ]; then
_real_fullchain=""
2016-04-27 16:14:15 +02:00
fi
2016-11-09 12:30:39 +01:00
2017-02-21 14:34:43 +01:00
_backup_path="$DOMAIN_BACKUP_PATH/$_backup_prefix"
mkdir -p "$_backup_path"
2017-02-19 15:09:22 +01:00
if [ "$_real_cert" ]; then
_info "Installing cert to:$_real_cert"
2020-08-16 11:36:24 +02:00
if [ -f "$_real_cert" ] && [ ! "$_ACME_IS_RENEW" ]; then
2017-02-21 14:34:43 +01:00
cp "$_real_cert" "$_backup_path/cert.bak"
2016-03-08 13:44:12 +01:00
fi
cat "$CERT_PATH" >"$_real_cert" || return 1
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
2017-02-19 15:09:22 +01:00
if [ "$_real_ca" ]; then
_info "Installing CA to:$_real_ca"
if [ "$_real_ca" = "$_real_cert" ]; then
echo "" >>"$_real_ca"
cat "$CA_CERT_PATH" >>"$_real_ca" || return 1
2016-03-08 13:44:12 +01:00
else
2020-08-16 11:36:24 +02:00
if [ -f "$_real_ca" ] && [ ! "$_ACME_IS_RENEW" ]; then
2017-02-21 14:34:43 +01:00
cp "$_real_ca" "$_backup_path/ca.bak"
fi
cat "$CA_CERT_PATH" >"$_real_ca" || return 1
2016-03-08 13:44:12 +01:00
fi
fi
2017-02-19 15:09:22 +01:00
if [ "$_real_key" ]; then
_info "Installing key to:$_real_key"
2020-08-16 11:36:24 +02:00
if [ -f "$_real_key" ] && [ ! "$_ACME_IS_RENEW" ]; then
2017-02-21 14:34:43 +01:00
cp "$_real_key" "$_backup_path/key.bak"
2016-03-08 13:44:12 +01:00
fi
if [ -f "$_real_key" ]; then
cat "$CERT_KEY_PATH" >"$_real_key" || return 1
else
cat "$CERT_KEY_PATH" >"$_real_key" || return 1
chmod 600 "$_real_key"
fi
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
2017-02-19 15:09:22 +01:00
if [ "$_real_fullchain" ]; then
_info "Installing full chain to:$_real_fullchain"
2020-08-16 11:36:24 +02:00
if [ -f "$_real_fullchain" ] && [ ! "$_ACME_IS_RENEW" ]; then
2017-02-21 14:34:43 +01:00
cp "$_real_fullchain" "$_backup_path/fullchain.bak"
fi
cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" || return 1
2016-11-09 12:30:39 +01:00
fi
2016-03-08 13:44:12 +01:00
2017-02-19 15:09:22 +01:00
if [ "$_reload_cmd" ]; then
_info "Run reload cmd: $_reload_cmd"
2017-01-22 11:11:32 +01:00
if (
2017-01-22 11:48:21 +01:00
export CERT_PATH
export CERT_KEY_PATH
export CA_CERT_PATH
export CERT_FULLCHAIN_PATH
export Le_Domain="$_main_domain"
2017-02-19 15:09:22 +01:00
cd "$DOMAIN_PATH" && eval "$_reload_cmd"
2017-01-22 11:48:21 +01:00
); then
_info "$(__green "Reload success")"
2016-04-27 16:14:15 +02:00
else
_err "Reload error for :$Le_Domain"
fi
fi
2016-03-08 13:44:12 +01:00
}
__read_password() {
unset _pp
prompt="Enter Password:"
2019-03-13 13:49:26 +01:00
while IFS= read -p "$prompt" -r -s -n 1 char; do
if [ "$char" = $'\0' ]; then
2019-03-13 14:11:59 +01:00
break
2019-03-13 13:49:26 +01:00
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"
2019-03-13 13:49:26 +01:00
echo SCHTASKS /delete /f /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null
fi
}
2017-01-16 15:31:24 +01:00
#confighome
2016-03-08 13:44:12 +01:00
installcronjob() {
2017-01-16 15:31:24 +01:00
_c_home="$1"
2016-03-08 13:44:12 +01:00
_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."
2016-03-29 15:49:18 +02:00
_err "All your certs will not be renewed automatically."
2016-04-13 14:37:18 +02:00
_err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday."
2016-03-29 15:49:18 +02:00
return 1
fi
2016-03-08 13:44:12 +01:00
_info "Installing cron job"
if ! $_CRONTAB -l | grep "$PROJECT_ENTRY --cron"; then
if _exists uname && uname -a | grep SunOS >/dev/null; then
$_CRONTAB -l | {
2016-11-09 12:30:39 +01:00
cat
echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null"
} | $_CRONTAB --
else
$_CRONTAB -l | {
2016-11-09 12:30:39 +01:00
cat
echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null"
} | $_CRONTAB -
fi
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ "$?" != "0" ]; then
2016-03-08 13:44:12 +01:00
_err "Install cron job failed. You need to manually renew your certs."
_err "Or you can add cronjob by yourself:"
2016-04-13 14:37:18 +02:00
_err "$lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"
2016-03-08 13:44:12 +01:00
return 1
fi
}
uninstallcronjob() {
_CRONTAB="crontab"
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 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
2016-03-29 15:57:56 +02:00
return
fi
2016-03-08 13:44:12 +01:00
_info "Removing cron job"
cr="$($_CRONTAB -l | grep "$PROJECT_ENTRY --cron")"
2016-11-09 12:30:39 +01:00
if [ "$cr" ]; then
if _exists uname && uname -a | grep solaris >/dev/null; then
$_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB --
else
$_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB -
fi
2016-04-13 14:37:18 +02:00
LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')"
2016-03-08 13:44:12 +01:00
_info LE_WORKING_DIR "$LE_WORKING_DIR"
2017-01-16 15:31:24 +01:00
if _contains "$cr" "--config-home"; then
2017-01-21 04:28:10 +01:00
LE_CONFIG_HOME="$(echo "$cr" | cut -d ' ' -f 11 | tr -d '"')"
_debug LE_CONFIG_HOME "$LE_CONFIG_HOME"
2017-01-16 15:31:24 +01:00
fi
2016-11-09 12:30:39 +01:00
fi
2016-03-08 13:44:12 +01:00
_initpath
2016-04-13 14:37:18 +02:00
2016-03-08 13:44:12 +01:00
}
#domain isECC revokeReason
2016-04-06 16:16:09 +02:00
revoke() {
Le_Domain="$1"
2016-11-09 12:30:39 +01:00
if [ -z "$Le_Domain" ]; then
2017-01-21 06:32:12 +01:00
_usage "Usage: $PROJECT_ENTRY --revoke -d domain.com [--ecc]"
2016-04-06 16:16:09 +02:00
return 1
fi
2016-11-09 12:30:39 +01:00
_isEcc="$2"
_reason="$3"
if [ -z "$_reason" ]; then
_reason="0"
fi
2016-11-11 14:22:48 +01:00
_initpath "$Le_Domain" "$_isEcc"
2016-11-09 12:30:39 +01:00
if [ ! -f "$DOMAIN_CONF" ]; then
2016-04-06 16:16:09 +02:00
_err "$Le_Domain is not a issued domain, skip."
2016-11-09 12:30:39 +01:00
return 1
2016-04-06 16:16:09 +02:00
fi
2016-11-09 12:30:39 +01:00
if [ ! -f "$CERT_PATH" ]; then
2016-04-06 16:16:09 +02:00
_err "Cert for $Le_Domain $CERT_PATH is not found, skip."
return 1
fi
2017-01-29 04:47:04 +01:00
cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _url_replace)"
2016-11-09 12:30:39 +01:00
if [ -z "$cert" ]; then
2016-04-06 16:16:09 +02:00
_err "Cert for $Le_Domain is empty found, skip."
return 1
fi
2016-11-09 12:30:39 +01:00
2017-06-17 09:49:45 +02:00
_initAPI
if [ "$ACME_VERSION" = "2" ]; then
data="{\"certificate\": \"$cert\",\"reason\":$_reason}"
else
data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}"
fi
2017-06-17 09:49:45 +02:00
uri="${ACME_REVOKE_CERT}"
2016-04-06 16:16:09 +02:00
2016-11-09 12:30:39 +01:00
if [ -f "$CERT_KEY_PATH" ]; then
2016-10-28 14:56:18 +02:00
_info "Try domain key first."
2016-11-11 14:22:48 +01:00
if _send_signed_request "$uri" "$data" "" "$CERT_KEY_PATH"; then
2016-11-09 12:30:39 +01:00
if [ -z "$response" ]; then
2016-10-28 14:56:18 +02:00
_info "Revoke success."
2016-11-11 14:22:48 +01:00
rm -f "$CERT_PATH"
2016-10-28 14:56:18 +02:00
return 0
2016-11-09 12:30:39 +01:00
else
2016-10-28 14:56:18 +02:00
_err "Revoke error by domain key."
_err "$response"
fi
2016-04-06 16:16:09 +02:00
fi
2016-11-09 12:30:39 +01:00
else
_info "Domain key file doesn't exist."
2016-04-06 16:16:09 +02:00
fi
2016-10-28 14:56:18 +02:00
_info "Try account key."
2016-04-06 16:16:09 +02:00
2016-11-11 14:22:48 +01:00
if _send_signed_request "$uri" "$data" "" "$ACCOUNT_KEY_PATH"; then
2016-11-09 12:30:39 +01:00
if [ -z "$response" ]; then
2016-04-06 16:16:09 +02:00
_info "Revoke success."
2016-11-11 14:22:48 +01:00
rm -f "$CERT_PATH"
2016-04-06 16:16:09 +02:00
return 0
2016-11-09 12:30:39 +01:00
else
2016-04-06 16:16:09 +02:00
_err "Revoke error."
2016-07-21 04:48:37 +02:00
_debug "$response"
2016-04-06 16:16:09 +02:00
fi
fi
return 1
}
2016-03-08 13:44:12 +01:00
2017-01-21 06:32:12 +01:00
#domain ecc
remove() {
Le_Domain="$1"
if [ -z "$Le_Domain" ]; then
_usage "Usage: $PROJECT_ENTRY --remove -d domain.com [--ecc]"
return 1
fi
_isEcc="$2"
_initpath "$Le_Domain" "$_isEcc"
_removed_conf="$DOMAIN_CONF.removed"
if [ ! -f "$DOMAIN_CONF" ]; then
if [ -f "$_removed_conf" ]; then
_err "$Le_Domain is already removed, You can remove the folder by yourself: $DOMAIN_PATH"
else
_err "$Le_Domain is not a issued domain, skip."
fi
return 1
fi
if mv "$DOMAIN_CONF" "$_removed_conf"; then
2017-01-21 07:19:01 +01:00
_info "$Le_Domain is removed, the key and cert files are in $(__green $DOMAIN_PATH)"
2017-01-21 06:32:12 +01:00
_info "You can remove them by yourself."
return 0
else
_err "Remove $Le_Domain failed."
return 1
fi
}
#domain vtype
_deactivate() {
_d_domain="$1"
_d_type="$2"
_initpath
2016-11-09 12:30:39 +01:00
if [ "$ACME_VERSION" = "2" ]; then
_identifiers="{\"type\":\"dns\",\"value\":\"$_d_domain\"}"
if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then
_err "Can not get domain new order."
return 1
fi
2019-03-16 07:00:15 +01:00
_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."
_clearup
_on_issue_err "$_post_hook"
return 1
fi
2016-11-09 12:30:39 +01:00
authzUri="$_authorizations_seg"
_debug2 "authzUri" "$authzUri"
if ! _send_signed_request "$authzUri"; then
_err "get to authz error."
2018-03-14 14:27:29 +01:00
_err "_authorizations_seg" "$_authorizations_seg"
_err "authzUri" "$authzUri"
_clearup
_on_issue_err "$_post_hook"
return 1
fi
2016-11-09 12:30:39 +01:00
response="$(echo "$response" | _normalizeJson)"
_debug2 response "$response"
_URL_NAME="url"
else
if ! __get_domain_new_authz "$_d_domain"; then
_err "Can not get domain new authz token."
return 1
fi
authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ':' -f 2- | tr -d "\r\n")"
_debug "authzUri" "$authzUri"
if [ "$code" ] && [ ! "$code" = '201' ]; then
_err "new-authz error: $response"
return 1
fi
_URL_NAME="uri"
2017-07-01 15:47:30 +02:00
fi
entries="$(echo "$response" | _egrep_o "[^{]*\"type\":\"[^\"]*\", *\"status\": *\"valid\", *\"$_URL_NAME\"[^}]*")"
2017-07-01 15:47:30 +02:00
if [ -z "$entries" ]; then
_info "No valid entries found."
if [ -z "$thumbprint" ]; then
thumbprint="$(__calc_account_thumbprint)"
fi
_debug "Trigger validation."
vtype="$VTYPE_DNS"
2019-03-16 07:00:15 +01:00
entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
2017-07-01 15:47:30 +02:00
_debug entry "$entry"
if [ -z "$entry" ]; then
_err "Error, can not get domain token $d"
return 1
fi
2019-03-16 07:00:15 +01:00
token="$(echo "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
2017-07-01 15:47:30 +02:00
_debug token "$token"
2016-11-09 12:30:39 +01:00
2019-03-16 07:00:15 +01:00
uri="$(echo "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')"
2017-07-01 15:47:30 +02:00
_debug uri "$uri"
keyauthorization="$token.$thumbprint"
_debug keyauthorization "$keyauthorization"
__trigger_validation "$uri" "$keyauthorization"
fi
_d_i=0
_d_max_retry=$(echo "$entries" | wc -l)
while [ "$_d_i" -lt "$_d_max_retry" ]; do
_info "Deactivate: $_d_domain"
_d_i="$(_math $_d_i + 1)"
entry="$(echo "$entries" | sed -n "${_d_i}p")"
_debug entry "$entry"
2016-11-09 12:30:39 +01:00
if [ -z "$entry" ]; then
2016-09-22 17:25:32 +02:00
_info "No more valid entry found."
break
fi
2016-11-09 12:30:39 +01:00
2019-03-16 07:00:15 +01:00
_vtype="$(echo "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')"
2016-11-11 14:22:48 +01:00
_debug _vtype "$_vtype"
_info "Found $_vtype"
2019-03-16 07:00:15 +01:00
uri="$(echo "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')"
2016-11-11 14:22:48 +01:00
_debug uri "$uri"
2016-11-09 12:30:39 +01:00
if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then
_info "Skip $_vtype"
continue
fi
2016-11-09 12:30:39 +01:00
_info "Deactivate: $_vtype"
2016-11-09 12:30:39 +01:00
if [ "$ACME_VERSION" = "2" ]; then
_djson="{\"status\":\"deactivated\"}"
else
_djson="{\"resource\": \"authz\", \"status\":\"deactivated\"}"
fi
if _send_signed_request "$authzUri" "$_djson" && _contains "$response" '"deactivated"'; then
2017-07-01 15:47:30 +02:00
_info "Deactivate: $_vtype success."
else
_err "Can not deactivate $_vtype."
2017-07-01 15:47:30 +02:00
break
fi
2016-11-09 12:30:39 +01:00
done
_debug "$_d_i"
2017-07-01 15:47:30 +02:00
if [ "$_d_i" -eq "$_d_max_retry" ]; then
_info "Deactivated success!"
else
_err "Deactivate failed."
fi
}
deactivate() {
2016-09-23 16:35:13 +02:00
_d_domain_list="$1"
_d_type="$2"
_initpath
2017-06-17 10:30:04 +02:00
_initAPI
2016-09-23 16:35:13 +02:00
_debug _d_domain_list "$_d_domain_list"
2016-11-09 12:30:39 +01:00
if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then
2016-09-23 16:35:13 +02:00
_usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]"
return 1
fi
2016-11-09 12:30:39 +01:00
for _d_dm in $(echo "$_d_domain_list" | tr ',' ' '); do
if [ -z "$_d_dm" ] || [ "$_d_dm" = "$NO_VALUE" ]; then
2016-09-23 16:35:13 +02:00
continue
fi
2016-11-11 14:22:48 +01:00
if ! _deactivate "$_d_dm" "$_d_type"; then
2016-09-24 08:17:04 +02:00
return 1
fi
2016-09-23 16:35:13 +02:00
done
}
2016-03-08 13:44:12 +01:00
# Detect profile file if not specified as environment variable
_detect_profile() {
2016-11-09 12:30:39 +01:00
if [ -n "$PROFILE" -a -f "$PROFILE" ]; then
2016-03-08 13:44:12 +01:00
echo "$PROFILE"
return
fi
DETECTED_PROFILE=''
SHELLTYPE="$(basename "/$SHELL")"
2016-11-09 12:30:39 +01:00
if [ "$SHELLTYPE" = "bash" ]; then
if [ -f "$HOME/.bashrc" ]; then
2016-03-08 13:44:12 +01:00
DETECTED_PROFILE="$HOME/.bashrc"
2016-11-09 12:30:39 +01:00
elif [ -f "$HOME/.bash_profile" ]; then
2016-03-08 13:44:12 +01:00
DETECTED_PROFILE="$HOME/.bash_profile"
fi
2016-11-09 12:30:39 +01:00
elif [ "$SHELLTYPE" = "zsh" ]; then
2016-03-08 13:44:12 +01:00
DETECTED_PROFILE="$HOME/.zshrc"
fi
2016-11-09 12:30:39 +01:00
if [ -z "$DETECTED_PROFILE" ]; then
if [ -f "$HOME/.profile" ]; then
2016-03-08 13:44:12 +01:00
DETECTED_PROFILE="$HOME/.profile"
2016-11-09 12:30:39 +01:00
elif [ -f "$HOME/.bashrc" ]; then
2016-03-08 13:44:12 +01:00
DETECTED_PROFILE="$HOME/.bashrc"
2016-11-09 12:30:39 +01:00
elif [ -f "$HOME/.bash_profile" ]; then
2016-03-08 13:44:12 +01:00
DETECTED_PROFILE="$HOME/.bash_profile"
2016-11-09 12:30:39 +01:00
elif [ -f "$HOME/.zshrc" ]; then
2016-03-08 13:44:12 +01:00
DETECTED_PROFILE="$HOME/.zshrc"
fi
fi
2017-07-02 07:38:44 +02:00
echo "$DETECTED_PROFILE"
2016-03-08 13:44:12 +01:00
}
_initconf() {
_initpath
2016-11-09 12:30:39 +01:00
if [ ! -f "$ACCOUNT_CONF_PATH" ]; then
2017-02-06 02:28:30 +01:00
echo "
#LOG_FILE=\"$DEFAULT_LOG_FILE\"
2016-09-25 16:26:41 +02:00
#LOG_LEVEL=1
2016-09-19 17:07:43 +02:00
2016-09-20 16:23:49 +02:00
#AUTO_UPGRADE=\"1\"
#NO_TIMESTAMP=1
2016-11-20 16:21:07 +01:00
2016-11-09 14:44:46 +01:00
" >"$ACCOUNT_CONF_PATH"
2016-03-08 13:44:12 +01:00
fi
}
# nocron
_precheck() {
_nocron="$1"
2016-11-09 12:30:39 +01:00
if ! _exists "curl" && ! _exists "wget"; then
_err "Please install curl or wget first, we need to access http resources."
2016-03-08 13:44:12 +01:00
return 1
fi
2016-11-09 12:30:39 +01:00
if [ -z "$_nocron" ]; then
if ! _exists "crontab" && ! _exists "fcrontab"; then
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
2016-03-29 15:49:18 +02:00
fi
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
2017-03-30 15:16:25 +02:00
if ! _exists "${ACME_OPENSSL_BIN:-openssl}"; then
2017-02-25 12:08:00 +01:00
_err "Please install openssl first. ACME_OPENSSL_BIN=$ACME_OPENSSL_BIN"
_err "We need openssl to generate keys."
2016-03-08 13:44:12 +01:00
return 1
fi
2016-11-09 12:30:39 +01:00
if ! _exists "socat"; then
_err "It is recommended to install socat first."
_err "We use socat for standalone server if you use standalone mode."
_err "If you don't use standalone mode, just ignore this warning."
fi
2016-11-09 12:30:39 +01:00
return 0
}
_setShebang() {
_file="$1"
_shebang="$2"
2016-11-09 12:30:39 +01:00
if [ -z "$_shebang" ]; then
_usage "Usage: file shebang"
return 1
fi
cp "$_file" "$_file.tmp"
2016-11-09 12:30:39 +01:00
echo "$_shebang" >"$_file"
sed -n 2,99999p "$_file.tmp" >>"$_file"
rm -f "$_file.tmp"
}
2017-01-16 15:31:24 +01:00
#confighome
2016-05-07 11:11:01 +02:00
_installalias() {
2017-01-16 15:31:24 +01:00
_c_home="$1"
2016-05-07 11:11:01 +02:00
_initpath
_envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env"
2016-11-09 12:30:39 +01:00
if [ "$_upgrading" ] && [ "$_upgrading" = "1" ]; then
2016-11-09 15:35:30 +01:00
echo "$(cat "$_envfile")" | sed "s|^LE_WORKING_DIR.*$||" >"$_envfile"
echo "$(cat "$_envfile")" | sed "s|^alias le.*$||" >"$_envfile"
echo "$(cat "$_envfile")" | sed "s|^alias le.sh.*$||" >"$_envfile"
2016-05-07 11:11:01 +02:00
fi
2017-01-16 15:31:24 +01:00
if [ "$_c_home" ]; then
2017-01-21 05:40:43 +01:00
_c_entry=" --config-home '$_c_home'"
2017-01-16 15:31:24 +01:00
fi
2016-05-08 15:21:07 +02:00
_setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\""
2017-01-21 04:28:10 +01:00
if [ "$_c_home" ]; then
_setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\""
2017-07-01 04:54:14 +02:00
else
_sed_i "/^export LE_CONFIG_HOME/d" "$_envfile"
2017-01-21 04:28:10 +01:00
fi
2017-01-21 05:40:43 +01:00
_setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\""
2016-05-07 11:11:01 +02:00
_profile="$(_detect_profile)"
2016-11-09 12:30:39 +01:00
if [ "$_profile" ]; then
2016-05-07 11:11:01 +02:00
_debug "Found profile: $_profile"
_info "Installing alias to '$_profile'"
2016-05-07 11:11:01 +02:00
_setopt "$_profile" ". \"$_envfile\""
_info "OK, Close and reopen your terminal to start using $PROJECT_NAME"
else
_info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME"
fi
#for csh
_cshfile="$LE_WORKING_DIR/$PROJECT_ENTRY.csh"
_csh_profile="$HOME/.cshrc"
2016-11-09 12:30:39 +01:00
if [ -f "$_csh_profile" ]; then
_info "Installing alias to '$_csh_profile'"
_setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
2017-01-21 04:28:10 +01:00
if [ "$_c_home" ]; then
_setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\""
2017-07-01 04:54:14 +02:00
else
_sed_i "/^setenv LE_CONFIG_HOME/d" "$_cshfile"
2017-01-21 04:28:10 +01:00
fi
2017-01-21 05:40:43 +01:00
_setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\""
2016-11-09 12:30:39 +01:00
_setopt "$_csh_profile" "source \"$_cshfile\""
2016-05-07 11:11:01 +02:00
fi
2016-11-09 12:30:39 +01:00
2016-05-09 16:28:45 +02:00
#for tcsh
_tcsh_profile="$HOME/.tcshrc"
2016-11-09 12:30:39 +01:00
if [ -f "$_tcsh_profile" ]; then
_info "Installing alias to '$_tcsh_profile'"
2016-05-09 16:28:45 +02:00
_setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
2017-01-21 04:28:10 +01:00
if [ "$_c_home" ]; then
_setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\""
fi
2017-01-21 05:40:43 +01:00
_setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\""
2016-11-09 12:30:39 +01:00
_setopt "$_tcsh_profile" "source \"$_cshfile\""
2016-05-09 16:28:45 +02:00
fi
2016-05-07 11:11:01 +02:00
}
# nocron confighome noprofile
install() {
2016-11-09 12:30:39 +01:00
if [ -z "$LE_WORKING_DIR" ]; then
LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
fi
2016-11-09 12:30:39 +01:00
_nocron="$1"
2017-01-16 15:31:24 +01:00
_c_home="$2"
_noprofile="$3"
2016-11-09 12:30:39 +01:00
if ! _initpath; then
_err "Install failed."
2016-03-08 13:44:12 +01:00
return 1
fi
2016-11-09 12:30:39 +01:00
if [ "$_nocron" ]; then
2016-06-26 07:30:47 +02:00
_debug "Skip install cron job"
fi
2016-11-09 12:30:39 +01:00
2020-08-16 11:36:24 +02:00
if [ "$_ACME_IN_CRON" != "1" ]; then
if ! _precheck "$_nocron"; then
_err "Pre-check failed, can not install."
return 1
fi
2016-03-08 13:44:12 +01:00
fi
2016-11-09 12:30:39 +01:00
if [ -z "$_c_home" ] && [ "$LE_CONFIG_HOME" != "$LE_WORKING_DIR" ]; then
_info "Using config home: $LE_CONFIG_HOME"
_c_home="$LE_CONFIG_HOME"
fi
2016-04-14 15:44:26 +02:00
#convert from le
2016-11-09 12:30:39 +01:00
if [ -d "$HOME/.le" ]; then
for envfile in "le.env" "le.sh.env"; do
if [ -f "$HOME/.le/$envfile" ]; then
if grep "le.sh" "$HOME/.le/$envfile" >/dev/null; then
_upgrading="1"
_info "You are upgrading from le.sh"
_info "Renaming \"$HOME/.le\" to $LE_WORKING_DIR"
mv "$HOME/.le" "$LE_WORKING_DIR"
mv "$LE_WORKING_DIR/$envfile" "$LE_WORKING_DIR/$PROJECT_ENTRY.env"
break
2016-04-14 15:44:26 +02:00
fi
fi
done
fi
2016-03-08 13:44:12 +01:00
_info "Installing to $LE_WORKING_DIR"
2017-07-01 04:54:14 +02:00
if [ ! -d "$LE_WORKING_DIR" ]; then
if ! mkdir -p "$LE_WORKING_DIR"; then
_err "Can not create working dir: $LE_WORKING_DIR"
return 1
fi
chmod 700 "$LE_WORKING_DIR"
2016-03-27 14:31:22 +02:00
fi
2016-11-09 12:30:39 +01:00
2017-07-01 04:54:14 +02:00
if [ ! -d "$LE_CONFIG_HOME" ]; then
if ! mkdir -p "$LE_CONFIG_HOME"; then
_err "Can not create config dir: $LE_CONFIG_HOME"
return 1
fi
2017-07-01 04:54:14 +02:00
chmod 700 "$LE_CONFIG_HOME"
2017-01-16 15:31:24 +01:00
fi
2016-11-09 14:44:46 +01:00
cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY"
2016-03-08 13:44:12 +01:00
2016-11-09 12:30:39 +01:00
if [ "$?" != "0" ]; then
2016-04-13 14:37:18 +02:00
_err "Install failed, can not copy $PROJECT_ENTRY"
2016-03-08 13:44:12 +01:00
return 1
fi
2016-04-13 14:37:18 +02:00
_info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY"
2016-03-08 13:44:12 +01:00
2020-08-16 11:36:24 +02:00
if [ "$_ACME_IN_CRON" != "1" ] && [ -z "$_noprofile" ]; then
_installalias "$_c_home"
fi
2016-03-08 13:44:12 +01:00
2016-11-09 12:30:39 +01:00
for subf in $_SUB_FOLDERS; do
if [ -d "$subf" ]; then
2016-11-09 14:44:46 +01:00
mkdir -p "$LE_WORKING_DIR/$subf"
cp "$subf"/* "$LE_WORKING_DIR"/"$subf"/
2016-10-11 14:56:59 +02:00
fi
done
2016-11-09 12:30:39 +01:00
if [ ! -f "$ACCOUNT_CONF_PATH" ]; then
2016-03-08 13:44:12 +01:00
_initconf
fi
2016-04-14 15:44:26 +02:00
2016-11-09 12:30:39 +01:00
if [ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ]; then
_setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\""
2016-04-14 15:44:26 +02:00
fi
2016-11-09 12:30:39 +01:00
if [ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ]; then
_saveaccountconf "CERT_HOME" "$CERT_HOME"
fi
2016-11-09 12:30:39 +01:00
if [ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ]; then
_saveaccountconf "ACCOUNT_KEY_PATH" "$ACCOUNT_KEY_PATH"
fi
2016-11-09 12:30:39 +01:00
if [ -z "$_nocron" ]; then
2017-01-16 15:31:24 +01:00
installcronjob "$_c_home"
fi
2016-11-09 12:30:39 +01:00
if [ -z "$NO_DETECT_SH" ]; then
2016-04-18 16:43:33 +02:00
#Modify shebang
2016-11-09 12:30:39 +01:00
if _exists bash; then
_bash_path="$(bash -c "command -v bash 2>/dev/null")"
if [ -z "$_bash_path" ]; then
_bash_path="$(bash -c 'echo $SHELL')"
fi
fi
if [ "$_bash_path" ]; then
2016-12-14 21:32:24 +01:00
_info "Good, bash is found, so change the shebang to use bash as preferred."
_shebang='#!'"$_bash_path"
2016-04-18 16:43:33 +02:00
_setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang"
2016-11-09 12:30:39 +01:00
for subf in $_SUB_FOLDERS; do
if [ -d "$LE_WORKING_DIR/$subf" ]; then
for _apifile in "$LE_WORKING_DIR/$subf/"*.sh; do
2016-10-11 14:56:59 +02:00
_setShebang "$_apifile" "$_shebang"
done
fi
done
fi
fi
2016-03-08 13:44:12 +01:00
_info OK
}
2016-06-26 07:30:47 +02:00
# nocron
2016-03-08 13:44:12 +01:00
uninstall() {
2016-06-26 07:30:47 +02:00
_nocron="$1"
2016-11-09 12:30:39 +01:00
if [ -z "$_nocron" ]; then
2016-06-26 07:30:47 +02:00
uninstallcronjob
fi
2016-03-08 13:44:12 +01:00
_initpath
2016-10-23 09:10:09 +02:00
_uninstallalias
2016-11-09 12:30:39 +01:00
2016-11-09 14:44:46 +01:00
rm -f "$LE_WORKING_DIR/$PROJECT_ENTRY"
2017-01-21 04:28:10 +01:00
_info "The keys and certs are in \"$(__green "$LE_CONFIG_HOME")\", you can remove them by yourself."
2016-10-23 09:10:09 +02:00
}
_uninstallalias() {
_initpath
2016-03-08 13:44:12 +01:00
_profile="$(_detect_profile)"
2016-11-09 12:30:39 +01:00
if [ "$_profile" ]; then
2016-10-23 09:10:09 +02:00
_info "Uninstalling alias from: '$_profile'"
2016-11-09 14:44:46 +01:00
text="$(cat "$_profile")"
2016-11-09 12:30:39 +01:00
echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" >"$_profile"
2016-03-08 13:44:12 +01:00
fi
2016-05-07 11:11:01 +02:00
_csh_profile="$HOME/.cshrc"
2016-11-09 12:30:39 +01:00
if [ -f "$_csh_profile" ]; then
2016-10-23 09:10:09 +02:00
_info "Uninstalling alias from: '$_csh_profile'"
2016-11-09 14:44:46 +01:00
text="$(cat "$_csh_profile")"
2016-11-09 12:30:39 +01:00
echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_csh_profile"
2016-05-07 11:11:01 +02:00
fi
2016-11-09 12:30:39 +01:00
2016-05-09 16:28:45 +02:00
_tcsh_profile="$HOME/.tcshrc"
2016-11-09 12:30:39 +01:00
if [ -f "$_tcsh_profile" ]; then
2016-10-23 09:10:09 +02:00
_info "Uninstalling alias from: '$_csh_profile'"
2016-11-09 14:44:46 +01:00
text="$(cat "$_tcsh_profile")"
2016-11-09 12:30:39 +01:00
echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_tcsh_profile"
2016-05-09 16:28:45 +02:00
fi
2016-03-08 13:44:12 +01:00
}
cron() {
2020-08-16 11:36:24 +02:00
export _ACME_IN_CRON=1
_initpath
2017-03-30 15:16:25 +02:00
_info "$(__green "===Starting cron===")"
2016-11-09 12:30:39 +01:00
if [ "$AUTO_UPGRADE" = "1" ]; then
export LE_WORKING_DIR
(
2016-11-09 12:30:39 +01:00
if ! upgrade; then
_err "Cron:Upgrade failed!"
return 1
fi
)
2016-11-09 14:44:46 +01:00
. "$LE_WORKING_DIR/$PROJECT_ENTRY" >/dev/null
2016-09-20 14:34:33 +02:00
2016-11-09 12:30:39 +01:00
if [ -t 1 ]; then
2016-09-20 14:34:33 +02:00
__INTERACTIVE="1"
fi
2016-11-09 12:30:39 +01:00
_info "Auto upgraded to: $VER"
fi
2016-03-08 13:44:12 +01:00
renewAll
2016-06-18 05:29:28 +02:00
_ret="$?"
2020-08-16 11:36:24 +02:00
_ACME_IN_CRON=""
2017-03-30 15:16:25 +02:00
_info "$(__green "===End cron===")"
2016-09-24 07:43:08 +02:00
exit $_ret
2016-03-08 13:44:12 +01:00
}
version() {
echo "$PROJECT"
echo "v$VER"
2016-03-08 13:44:12 +01:00
}
# subject content hooks code
_send_notify() {
_nsubject="$1"
_ncontent="$2"
_nhooks="$3"
_nerror="$4"
if [ "$NOTIFY_LEVEL" = "$NOTIFY_LEVEL_DISABLE" ]; then
_debug "The NOTIFY_LEVEL is $NOTIFY_LEVEL, disabled, just return."
return 0
fi
if [ -z "$_nhooks" ]; then
_debug "The NOTIFY_HOOK is empty, just return."
return 0
fi
_send_err=0
for _n_hook in $(echo "$_nhooks" | tr ',' " "); do
_n_hook_file="$(_findHook "" $_SUB_FOLDER_NOTIFY "$_n_hook")"
2019-08-05 16:03:56 +02:00
_info "Sending via: $_n_hook"
_debug "Found $_n_hook_file for $_n_hook"
if [ -z "$_n_hook_file" ]; then
_err "Can not find the hook file for $_n_hook"
continue
fi
if ! (
if ! . "$_n_hook_file"; then
_err "Load file $_n_hook_file error. Please check your api file and try again."
return 1
fi
d_command="${_n_hook}_send"
if ! _exists "$d_command"; then
_err "It seems that your api file is not correct, it must have a function named: $d_command"
return 1
fi
if ! $d_command "$_nsubject" "$_ncontent" "$_nerror"; then
_err "Error send message by $d_command"
return 1
fi
return 0
); then
_err "Set $_n_hook_file error."
_send_err=1
else
_info "$_n_hook $(__green Success)"
fi
done
return $_send_err
}
# hook
_set_notify_hook() {
_nhooks="$1"
_test_subject="Hello, this is a notification from $PROJECT_NAME"
2019-08-05 16:03:56 +02:00
_test_content="If you receive this message, your notification works."
_send_notify "$_test_subject" "$_test_content" "$_nhooks" 0
}
#[hook] [level] [mode]
setnotify() {
_nhook="$1"
_nlevel="$2"
_nmode="$3"
_initpath
if [ -z "$_nhook$_nlevel$_nmode" ]; then
_usage "Usage: $PROJECT_ENTRY --set-notify [--notify-hook mailgun] [--notify-level $NOTIFY_LEVEL_DEFAULT] [--notify-mode $NOTIFY_MODE_DEFAULT]"
_usage "$_NOTIFY_WIKI"
return 1
fi
if [ "$_nlevel" ]; then
_info "Set notify level to: $_nlevel"
export "NOTIFY_LEVEL=$_nlevel"
_saveaccountconf "NOTIFY_LEVEL" "$NOTIFY_LEVEL"
fi
if [ "$_nmode" ]; then
_info "Set notify mode to: $_nmode"
export "NOTIFY_MODE=$_nmode"
_saveaccountconf "NOTIFY_MODE" "$NOTIFY_MODE"
fi
if [ "$_nhook" ]; then
_info "Set notify hook to: $_nhook"
if [ "$_nhook" = "$NO_VALUE" ]; then
_info "Clear notify hook"
_clearaccountconf "NOTIFY_HOOK"
else
if _set_notify_hook "$_nhook"; then
export NOTIFY_HOOK="$_nhook"
_saveaccountconf "NOTIFY_HOOK" "$NOTIFY_HOOK"
return 0
else
_err "Can not set notify hook to: $_nhook"
return 1
fi
fi
fi
}
2016-03-08 13:44:12 +01:00
showhelp() {
_initpath
2016-03-08 13:44:12 +01:00
version
2016-04-13 14:37:18 +02:00
echo "Usage: $PROJECT_ENTRY command ...[parameters]....
Commands:
--help, -h Show this help message.
--version, -v Show version info.
2016-04-13 14:37:18 +02:00
--install Install $PROJECT_NAME to your system.
--uninstall Uninstall $PROJECT_NAME, and uninstall the cron job.
--upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT.
--issue Issue a cert.
--signcsr Issue a cert from an existing csr.
2016-10-11 14:56:59 +02:00
--deploy Deploy the cert to your server.
2017-01-16 15:31:24 +01:00
--install-cert Install the issued cert to apache/nginx or any other server.
--renew, -r Renew a cert.
2017-01-16 15:31:24 +01:00
--renew-all Renew all the certs.
--revoke Revoke a cert.
--remove Remove the cert from list of certs known to $PROJECT_NAME.
--list List all the certs.
--showcsr Show the content of a csr.
2017-01-16 15:31:24 +01:00
--install-cronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
--uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically.
--cron Run cron job to renew all the certs.
--toPkcs Export the certificate and key to a pfx file.
--toPkcs8 Convert to pkcs8 format.
2017-01-16 15:31:24 +01:00
--update-account Update account info.
--register-account Register account key.
--deactivate-account Deactivate the account.
2017-02-11 06:36:52 +01:00
--create-account-key Create an account private key, professional use.
--create-domain-key Create an domain private key, professional use.
--createCSR, -ccsr Create CSR , professional use.
--deactivate Deactivate the domain authz, professional use.
--set-notify Set the cron notification hook, level or mode.
2017-04-17 13:08:34 +02:00
Parameters:
--domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc.
--challenge-alias domain.tld The challenge domain alias for DNS alias mode.
See: $_DNS_ALIAS_WIKI
--domain-alias domain.tld The domain alias for DNS alias mode.
See: $_DNS_ALIAS_WIKI
--preferred-chain CHAIN If the CA offers multiple certificate chains, prefer the chain with an issuer matching this Subject Common Name.
If no match, the default offered chain will be used. (default: empty)
See: $_PREFERRED_CHAIN_WIKI
--force, -f Used to force to install or force to renew a cert immediately.
--staging, --test Use staging server, just for test.
--debug Output debug info.
--output-insecure Output all the sensitive messages.
By default all the credentials/sensitive messages are hidden from the output/debug/log for security.
--webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
--standalone Use standalone mode.
--alpn Use standalone alpn mode.
--stateless Use stateless mode.
See: $_STATELESS_WIKI
--apache Use apache mode.
--dns [dns_hook] Use dns mode or dns api.
See: $_DNS_API_WIKI
--dnssleep 300 The time in seconds to wait for all the txt records to propagate in dns api mode.
It's not necessary to use this by default, $PROJECT_NAME polls dns status by DOH automatically.
2017-04-17 13:08:34 +02:00
--keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384, ec-521.
--accountkeylength, -ak [2048] Specifies the account key length: 2048, 3072, 4096
--log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here.
2016-09-25 15:58:59 +02:00
--log-level 1|2 Specifies the log level, default is 1.
2017-02-19 05:55:05 +01:00
--syslog [0|3|6|7] Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug.
2017-04-17 13:08:34 +02:00
2020-08-09 03:34:43 +02:00
--eab-kid EAB_KID Key Identifier for External Account Binding.
--eab-hmac-key EAB_HMAC_KEY HMAC key for External Account Binding.
2018-10-30 15:50:44 +01:00
These parameters are to install the cert to nginx/apache or any other server after issue/renew a cert:
2017-04-17 13:08:34 +02:00
2017-03-22 15:58:03 +01:00
--cert-file After issue/renew, the cert will be copied to this path.
--key-file After issue/renew, the key will be copied to this path.
--ca-file After issue/renew, the intermediate cert will be copied to this path.
--fullchain-file After issue/renew, the fullchain cert will be copied to this path.
2017-04-17 13:08:34 +02:00
--reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server.
--server SERVER ACME Directory Resource URI. (default: $DEFAULT_CA)
See: $_SERVER_WIKI
--accountconf Specifies a customized account config file.
--home Specifies the home dir for $PROJECT_NAME.
2017-01-16 15:31:24 +01:00
--cert-home Specifies the home dir to save all the certs, only valid for '--install' command.
--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.
--accountemail, -m Specifies the account email, only valid for the '--install' and '--update-account' command.
--accountkey Specifies the account key path, only valid for the '--install' command.
--days Specifies the days to renew the cert when using '--issue' command. The default value is $DEFAULT_RENEW days.
--httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
2018-12-18 13:18:18 +01:00
--tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer.
--local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses.
2016-06-14 07:07:33 +02:00
--listraw Only used for '--list' command, list the certs in raw format.
2017-01-16 15:31:24 +01:00
--stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal.
--insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted.
2017-03-26 07:31:12 +02:00
--ca-bundle Specifies the path to the CA certificate bundle to verify api server's certificate.
2017-03-22 15:58:03 +01:00
--ca-path Specifies directory containing CA certificates in PEM format, used by wget or curl.
--nocron Only valid for '--install' command, which means: do not install the default cron job.
In this case, the certs will not be renewed automatically.
--noprofile Only valid for '--install' command, which means: do not install aliases to user profile.
--no-color Do not output color text.
--force-color Force output of color text. Useful for non-interactive use with the aha tool for HTML E-Mails.
2017-01-16 15:31:24 +01:00
--ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR'
--csr Specifies the input csr.
--pre-hook Command to be run before obtaining any certificates.
2017-03-26 07:28:37 +02:00
--post-hook Command to be run after attempting to obtain/renew certificates. No matter the obtain/renew is success or failed.
--renew-hook Command to be run once for each successfully renewed certificate.
2016-10-11 14:56:59 +02:00
--deploy-hook The hook file to deploy cert
--ocsp-must-staple, --ocsp Generate ocsp must Staple extension.
--always-force-new-domain-key Generate new domain key when renewal. Otherwise, the domain key is not changed by default.
2016-09-28 16:05:43 +02:00
--auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future.
--listen-v4 Force standalone/tls server to listen at ipv4.
--listen-v6 Force standalone/tls server to listen at ipv6.
--openssl-bin Specifies a custom openssl bin location.
--use-wget Force to use wget, if you have both curl and wget installed.
--yes-I-know-dns-manual-mode-enough-go-ahead-please Force to use dns manual mode.
See: $_DNS_MANUAL_WIKI
2018-04-21 07:21:56 +02:00
--branch, -b Only valid for '--upgrade' command, specifies the branch name to upgrade to.
--notify-level 0|1|2|3 Set the notification level: Default value is $NOTIFY_LEVEL_DEFAULT.
0: disabled, no notification will be sent.
1: send notifications only when there is an error.
2: send notifications when a cert is successfully renewed, or there is an error.
3: send notifications when a cert is skipped, renewed, or error.
--notify-mode 0|1 Set notification mode. Default value is $NOTIFY_MODE_DEFAULT.
0: Bulk mode. Send all the domain's notifications in one message(mail).
1: Cert mode. Send a message for every single cert.
--notify-hook [hookname] Set the notify hook
--revoke-reason [0-10] The reason for '--revoke' command.
See: $_REVOKE_WIKI
"
2016-03-08 13:44:12 +01:00
}
# nocron noprofile
2016-03-27 14:31:22 +02:00
_installOnline() {
_info "Installing from online archive."
2016-06-26 07:30:47 +02:00
_nocron="$1"
_noprofile="$2"
2016-11-09 12:30:39 +01:00
if [ ! "$BRANCH" ]; then
2016-03-27 14:31:22 +02:00
BRANCH="master"
fi
2016-03-27 14:31:22 +02:00
target="$PROJECT/archive/$BRANCH.tar.gz"
_info "Downloading $target"
localname="$BRANCH.tar.gz"
2016-11-09 12:30:39 +01:00
if ! _get "$target" >$localname; then
2016-08-15 13:15:19 +02:00
_err "Download error."
2016-03-27 14:31:22 +02:00
return 1
fi
2016-07-03 06:46:18 +02:00
(
2016-11-09 12:30:39 +01:00
_info "Extracting $localname"
if ! (tar xzf $localname || gtar xzf $localname); then
_err "Extraction error."
exit 1
fi
2016-11-09 12:30:39 +01:00
cd "$PROJECT_NAME-$BRANCH"
chmod +x $PROJECT_ENTRY
if ./$PROJECT_ENTRY install "$_nocron" "" "$_noprofile"; then
2016-11-09 12:30:39 +01:00
_info "Install success!"
_initpath
2020-03-24 14:44:35 +01:00
_saveaccountconf "UPGRADE_HASH" "$(_getUpgradeHash)"
2016-11-09 12:30:39 +01:00
fi
cd ..
rm -rf "$PROJECT_NAME-$BRANCH"
rm -f "$localname"
2016-07-03 06:46:18 +02:00
)
2016-03-27 14:31:22 +02:00
}
2020-03-24 14:44:35 +01:00
_getRepoHash() {
_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
}
_getUpgradeHash() {
_b="$BRANCH"
if [ -z "$_b" ]; then
_b="master"
fi
2020-03-24 14:44:35 +01:00
_hash=$(_getRepoHash "heads/$_b")
if [ -z "$_hash" ]; then _hash=$(_getRepoHash "tags/$_b"); fi
echo $_hash
}
2016-06-26 07:30:47 +02:00
upgrade() {
if (
_initpath
2020-03-24 14:44:35 +01:00
[ -z "$FORCE" ] && [ "$(_getUpgradeHash)" = "$(_readaccountconf "UPGRADE_HASH")" ] && _info "Already uptodate!" && exit 0
export LE_WORKING_DIR
2016-07-02 07:46:35 +02:00
cd "$LE_WORKING_DIR"
_installOnline "nocron" "noprofile"
2016-11-09 12:30:39 +01:00
); then
2016-06-26 07:30:47 +02:00
_info "Upgrade success!"
2016-07-04 14:40:29 +02:00
exit 0
2016-06-26 07:30:47 +02:00
else
_err "Upgrade failed!"
2016-07-04 14:40:29 +02:00
exit 1
2016-06-26 07:30:47 +02:00
fi
}
2016-09-19 17:07:43 +02:00
_processAccountConf() {
2016-11-09 12:30:39 +01:00
if [ "$_useragent" ]; then
2016-09-19 17:07:43 +02:00
_saveaccountconf "USER_AGENT" "$_useragent"
2016-11-09 12:30:39 +01:00
elif [ "$USER_AGENT" ] && [ "$USER_AGENT" != "$DEFAULT_USER_AGENT" ]; then
_saveaccountconf "USER_AGENT" "$USER_AGENT"
2016-09-19 17:07:43 +02:00
fi
2016-11-09 12:30:39 +01:00
if [ "$_openssl_bin" ]; then
2017-02-25 12:08:00 +01:00
_saveaccountconf "ACME_OPENSSL_BIN" "$_openssl_bin"
elif [ "$ACME_OPENSSL_BIN" ] && [ "$ACME_OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then
_saveaccountconf "ACME_OPENSSL_BIN" "$ACME_OPENSSL_BIN"
fi
2016-11-09 12:30:39 +01:00
if [ "$_auto_upgrade" ]; then
2016-09-28 16:05:43 +02:00
_saveaccountconf "AUTO_UPGRADE" "$_auto_upgrade"
2016-11-09 12:30:39 +01:00
elif [ "$AUTO_UPGRADE" ]; then
2016-09-28 16:05:43 +02:00
_saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE"
fi
2016-11-09 12:30:39 +01:00
if [ "$_use_wget" ]; then
_saveaccountconf "ACME_USE_WGET" "$_use_wget"
elif [ "$ACME_USE_WGET" ]; then
_saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET"
fi
2016-09-19 17:07:43 +02:00
}
2019-08-11 08:07:36 +02:00
_checkSudo() {
if [ "$SUDO_GID" ] && [ "$SUDO_COMMAND" ] && [ "$SUDO_USER" ] && [ "$SUDO_UID" ]; then
if [ "$SUDO_USER" = "root" ] && [ "$SUDO_UID" = "0" ]; then
#it's root using sudo, no matter it's using sudo or not, just fine
return 0
fi
2020-01-15 15:11:34 +01:00
if [ -n "$SUDO_COMMAND" ]; then
#it's a normal user doing "sudo su", or `sudo -i` or `sudo -s`
2020-01-15 15:11:34 +01:00
_endswith "$SUDO_COMMAND" /bin/su || grep "^$SUDO_COMMAND\$" /etc/shells >/dev/null 2>&1
return $?
2019-08-11 08:07:36 +02:00
fi
#otherwise
return 1
fi
return 0
}
#server
_selectServer() {
_server="$1"
_server_lower="$(echo "$_server" | _lower_case)"
_sindex=0
for snames in $CA_NAMES; do
snames="$(echo "$snames" | _lower_case)"
_sindex="$(_math $_sindex + 1)"
_debug2 "_selectServer try snames" "$snames"
for sname in $(echo "$snames" | tr ',' ' '); do
if [ "$_server_lower" = "$sname" ]; then
_debug2 "_selectServer match $sname"
_serverdir="$(_getfield "$CA_SERVERS" $_sindex)"
_debug "Selected server: $_serverdir"
ACME_DIRECTORY="$_serverdir"
export ACME_DIRECTORY
return
fi
done
done
ACME_DIRECTORY="$_server"
export ACME_DIRECTORY
}
#url
_getCAShortName() {
caurl="$1"
if [ -z "$caurl" ]; then
caurl="$DEFAULT_CA"
fi
caurl_lower="$(echo $caurl | _lower_case)"
_sindex=0
for surl in $(echo "$CA_SERVERS" | _lower_case | tr , ' '); do
_sindex="$(_math $_sindex + 1)"
if [ "$caurl_lower" = "$surl" ]; then
_nindex=0
for snames in $CA_NAMES; do
_nindex="$(_math $_nindex + 1)"
if [ $_nindex -ge $_sindex ]; then
_getfield "$snames" 1
return
fi
done
fi
done
echo "$caurl"
}
#set default ca to $ACME_DIRECTORY
setdefaultca() {
if [ -z "$ACME_DIRECTORY" ]; then
_err "Please give a --server parameter."
return 1
fi
_saveaccountconf "DEFAULT_ACME_SERVER" "$ACME_DIRECTORY"
2020-08-12 15:25:35 +02:00
_info "Changed default CA to: $(__green "$ACME_DIRECTORY")"
}
_process() {
_CMD=""
_domain=""
2016-09-23 16:35:13 +02:00
_altdomains="$NO_VALUE"
_webroot=""
2018-02-10 03:45:29 +01:00
_challenge_alias=""
2016-07-09 11:25:27 +02:00
_keylength=""
_accountkeylength=""
2017-03-22 14:20:35 +01:00
_cert_file=""
_key_file=""
_ca_file=""
_fullchain_file=""
2016-04-27 16:14:15 +02:00
_reloadcmd=""
_password=""
_accountconf=""
_useragent=""
_accountemail=""
_accountkey=""
_certhome=""
2017-01-16 15:31:24 +01:00
_confighome=""
_httpport=""
_tlsport=""
_dnssleep=""
2016-06-14 07:07:33 +02:00
_listraw=""
2016-06-18 05:29:28 +02:00
_stopRenewOnError=""
2016-11-11 14:15:48 +01:00
#_insecure=""
_ca_bundle=""
_ca_path=""
_nocron=""
_noprofile=""
_ecc=""
_csr=""
_pre_hook=""
_post_hook=""
_renew_hook=""
2016-10-11 14:56:59 +02:00
_deploy_hook=""
2016-09-19 17:07:43 +02:00
_logfile=""
_log=""
_local_address=""
2016-09-25 15:58:59 +02:00
_log_level=""
2016-09-28 16:05:43 +02:00
_auto_upgrade=""
_listen_v4=""
_listen_v6=""
_openssl_bin=""
2017-02-11 14:15:36 +01:00
_syslog=""
_use_wget=""
2017-06-19 14:19:30 +02:00
_server=""
_notify_hook=""
_notify_level=""
_notify_mode=""
_revoke_reason=""
2020-08-09 03:34:43 +02:00
_eab_kid=""
_eab_hmac_key=""
_preferred_chain=""
2016-11-09 12:30:39 +01:00
while [ ${#} -gt 0 ]; do
case "${1}" in
2016-11-09 12:30:39 +01:00
2020-08-17 16:18:20 +02:00
--help | -h)
showhelp
return
;;
--version | -v)
version
return
;;
--install)
_CMD="install"
;;
--uninstall)
_CMD="uninstall"
;;
--upgrade)
_CMD="upgrade"
;;
--issue)
_CMD="issue"
;;
--deploy)
_CMD="deploy"
;;
--signcsr)
_CMD="signcsr"
;;
--showcsr)
_CMD="showcsr"
;;
--installcert | -i | --install-cert)
_CMD="installcert"
;;
--renew | -r)
_CMD="renew"
;;
--renewAll | --renewall | --renew-all)
_CMD="renewAll"
;;
--revoke)
_CMD="revoke"
;;
--remove)
_CMD="remove"
;;
--list)
_CMD="list"
;;
--installcronjob | --install-cronjob)
_CMD="installcronjob"
;;
--uninstallcronjob | --uninstall-cronjob)
_CMD="uninstallcronjob"
;;
--cron)
_CMD="cron"
;;
--toPkcs)
_CMD="toPkcs"
;;
--toPkcs8)
_CMD="toPkcs8"
;;
--createAccountKey | --createaccountkey | -cak | --create-account-key)
_CMD="createAccountKey"
;;
--createDomainKey | --createdomainkey | -cdk | --create-domain-key)
_CMD="createDomainKey"
;;
--createCSR | --createcsr | -ccr)
_CMD="createCSR"
;;
--deactivate)
_CMD="deactivate"
;;
--updateaccount | --update-account)
_CMD="updateaccount"
;;
--registeraccount | --register-account)
_CMD="registeraccount"
;;
--deactivate-account)
_CMD="deactivateaccount"
;;
--set-notify)
_CMD="setnotify"
;;
--set-default-ca)
_CMD="setdefaultca"
;;
--domain | -d)
_dvalue="$2"
2016-11-09 12:30:39 +01:00
2020-08-17 16:18:20 +02:00
if [ "$_dvalue" ]; then
if _startswith "$_dvalue" "-"; then
_err "'$_dvalue' is not a valid domain for parameter '$1'"
return 1
fi
if _is_idn "$_dvalue" && ! _exists idn; then
_err "It seems that $_dvalue is an IDN( Internationalized Domain Names), please install 'idn' command first."
return 1
fi
2016-11-09 12:30:39 +01:00
2020-08-17 16:18:20 +02:00
if _startswith "$_dvalue" "*."; then
_debug "Wildcard domain"
export ACME_VERSION=2
fi
if [ -z "$_domain" ]; then
_domain="$_dvalue"
else
if [ "$_altdomains" = "$NO_VALUE" ]; then
_altdomains="$_dvalue"
else
2020-08-17 16:18:20 +02:00
_altdomains="$_altdomains,$_dvalue"
fi
fi
2020-08-17 16:18:20 +02:00
fi
2016-11-09 12:30:39 +01:00
2020-08-17 16:18:20 +02:00
shift
;;
2020-08-17 16:18:20 +02:00
--force | -f)
FORCE="1"
;;
--staging | --test)
STAGE="1"
;;
--server)
_server="$2"
_selectServer "$_server"
shift
;;
--debug)
if [ -z "$2" ] || _startswith "$2" "-"; then
DEBUG="$DEBUG_LEVEL_DEFAULT"
else
DEBUG="$2"
2018-02-12 14:49:22 +01:00
shift
2020-08-17 16:18:20 +02:00
fi
;;
--output-insecure)
export OUTPUT_INSECURE=1
;;
--webroot | -w)
wvalue="$2"
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
shift
;;
--challenge-alias)
cvalue="$2"
_challenge_alias="$_challenge_alias$cvalue,"
shift
;;
--domain-alias)
cvalue="$DNS_ALIAS_PREFIX$2"
_challenge_alias="$_challenge_alias$cvalue,"
shift
;;
--standalone)
wvalue="$NO_VALUE"
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
;;
--alpn)
wvalue="$W_ALPN"
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
;;
--stateless)
wvalue="$MODE_STATELESS"
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
;;
--local-address)
lvalue="$2"
_local_address="$_local_address$lvalue,"
shift
;;
--apache)
wvalue="apache"
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
;;
--nginx)
wvalue="$NGINX"
if [ "$2" ] && ! _startswith "$2" "-"; then
wvalue="$NGINX$2"
shift
2020-08-17 16:18:20 +02:00
fi
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
;;
--dns)
wvalue="$W_DNS"
if [ "$2" ] && ! _startswith "$2" "-"; then
wvalue="$2"
shift
2020-08-17 16:18:20 +02:00
fi
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
;;
--dnssleep)
_dnssleep="$2"
Le_DNSSleep="$_dnssleep"
shift
;;
2016-11-09 12:30:39 +01:00
2020-08-17 16:18:20 +02:00
--keylength | -k)
_keylength="$2"
shift
;;
--accountkeylength | -ak)
_accountkeylength="$2"
shift
;;
2020-08-17 16:18:20 +02:00
--cert-file | --certpath)
_cert_file="$2"
shift
;;
--key-file | --keypath)
_key_file="$2"
shift
;;
--ca-file | --capath)
_ca_file="$2"
shift
;;
--fullchain-file | --fullchainpath)
_fullchain_file="$2"
shift
;;
--reloadcmd | --reloadCmd)
_reloadcmd="$2"
shift
;;
--password)
_password="$2"
shift
;;
--accountconf)
_accountconf="$2"
ACCOUNT_CONF_PATH="$_accountconf"
shift
;;
--home)
LE_WORKING_DIR="$2"
shift
;;
--certhome | --cert-home)
_certhome="$2"
CERT_HOME="$_certhome"
shift
;;
--config-home)
_confighome="$2"
LE_CONFIG_HOME="$_confighome"
shift
;;
--useragent)
_useragent="$2"
USER_AGENT="$_useragent"
shift
;;
--accountemail | -m)
_accountemail="$2"
ACCOUNT_EMAIL="$_accountemail"
shift
;;
--accountkey)
_accountkey="$2"
ACCOUNT_KEY_PATH="$_accountkey"
shift
;;
--days)
_days="$2"
Le_RenewalDays="$_days"
shift
;;
--httpport)
_httpport="$2"
Le_HTTPPort="$_httpport"
shift
;;
--tlsport)
_tlsport="$2"
Le_TLSPort="$_tlsport"
shift
;;
--listraw)
_listraw="raw"
;;
--stopRenewOnError | --stoprenewonerror | -se)
_stopRenewOnError="1"
;;
--insecure)
#_insecure="1"
HTTPS_INSECURE="1"
;;
--ca-bundle)
_ca_bundle="$(_readlink "$2")"
CA_BUNDLE="$_ca_bundle"
shift
;;
--ca-path)
_ca_path="$2"
CA_PATH="$_ca_path"
shift
;;
--nocron)
_nocron="1"
;;
--noprofile)
_noprofile="1"
;;
--no-color)
export ACME_NO_COLOR=1
;;
--force-color)
export ACME_FORCE_COLOR=1
;;
--ecc)
_ecc="isEcc"
;;
--csr)
_csr="$2"
shift
;;
--pre-hook)
_pre_hook="$2"
shift
;;
--post-hook)
_post_hook="$2"
shift
;;
--renew-hook)
_renew_hook="$2"
shift
;;
--deploy-hook)
if [ -z "$2" ] || _startswith "$2" "-"; then
_usage "Please specify a value for '--deploy-hook'"
return 1
fi
_deploy_hook="$_deploy_hook$2,"
shift
;;
--ocsp-must-staple | --ocsp)
Le_OCSP_Staple="1"
;;
--always-force-new-domain-key)
if [ -z "$2" ] || _startswith "$2" "-"; then
Le_ForceNewDomainKey=1
else
Le_ForceNewDomainKey="$2"
shift
2020-08-17 16:18:20 +02:00
fi
;;
--yes-I-know-dns-manual-mode-enough-go-ahead-please)
export FORCE_DNS_MANUAL=1
;;
--log | --logfile)
_log="1"
_logfile="$2"
if _startswith "$_logfile" '-'; then
_logfile=""
else
2020-08-09 03:34:43 +02:00
shift
2020-08-17 16:18:20 +02:00
fi
LOG_FILE="$_logfile"
if [ -z "$LOG_LEVEL" ]; then
LOG_LEVEL="$DEFAULT_LOG_LEVEL"
fi
;;
--log-level)
_log_level="$2"
LOG_LEVEL="$_log_level"
shift
;;
--syslog)
if ! _startswith "$2" '-'; then
_syslog="$2"
2020-08-09 03:34:43 +02:00
shift
2020-08-17 16:18:20 +02:00
fi
if [ -z "$_syslog" ]; then
_syslog="$SYSLOG_LEVEL_DEFAULT"
fi
;;
--auto-upgrade)
_auto_upgrade="$2"
if [ -z "$_auto_upgrade" ] || _startswith "$_auto_upgrade" '-'; then
_auto_upgrade="1"
else
shift
2020-08-17 16:18:20 +02:00
fi
AUTO_UPGRADE="$_auto_upgrade"
;;
--listen-v4)
_listen_v4="1"
Le_Listen_V4="$_listen_v4"
;;
--listen-v6)
_listen_v6="1"
Le_Listen_V6="$_listen_v6"
;;
--openssl-bin)
_openssl_bin="$2"
ACME_OPENSSL_BIN="$_openssl_bin"
shift
;;
--use-wget)
_use_wget="1"
ACME_USE_WGET="1"
;;
--branch | -b)
export BRANCH="$2"
shift
;;
--notify-hook)
_nhook="$2"
if _startswith "$_nhook" "-"; then
_err "'$_nhook' is not a hook name for '$1'"
return 1
2020-08-17 16:18:20 +02:00
fi
if [ "$_notify_hook" ]; then
_notify_hook="$_notify_hook,$_nhook"
else
_notify_hook="$_nhook"
fi
shift
;;
--notify-level)
_nlevel="$2"
if _startswith "$_nlevel" "-"; then
_err "'$_nlevel' is not a integer for '$1'"
return 1
fi
_notify_level="$_nlevel"
shift
;;
--notify-mode)
_nmode="$2"
if _startswith "$_nmode" "-"; then
_err "'$_nmode' is not a integer for '$1'"
return 1
fi
_notify_mode="$_nmode"
shift
;;
--revoke-reason)
_revoke_reason="$2"
if _startswith "$_revoke_reason" "-"; then
_err "'$_revoke_reason' is not a integer for '$1'"
return 1
fi
shift
;;
--eab-kid)
_eab_kid="$2"
shift
;;
--eab-hmac-key)
_eab_hmac_key="$2"
shift
;;
--preferred-chain)
_preferred_chain="$2"
shift
;;
*)
_err "Unknown parameter : $1"
return 1
;;
esac
shift 1
done
2016-11-09 12:30:39 +01:00
if [ "${_CMD}" != "install" ]; then
2019-08-11 08:07:36 +02:00
if [ "$__INTERACTIVE" ] && ! _checkSudo; then
if [ -z "$FORCE" ]; then
#Use "echo" here, instead of _info. it's too early
echo "It seems that you are using sudo, please read this link first:"
echo "$_SUDO_WIKI"
return 1
fi
fi
2016-09-19 17:07:43 +02:00
__initHome
2016-10-12 15:48:18 +02:00
if [ "$_log" ]; then
2016-11-09 12:30:39 +01:00
if [ -z "$_logfile" ]; then
2016-10-12 15:48:18 +02:00
_logfile="$DEFAULT_LOG_FILE"
fi
fi
2016-11-09 12:30:39 +01:00
if [ "$_logfile" ]; then
2016-09-19 17:07:43 +02:00
_saveaccountconf "LOG_FILE" "$_logfile"
2016-10-12 15:48:18 +02:00
LOG_FILE="$_logfile"
2016-09-19 17:07:43 +02:00
fi
2016-09-25 15:58:59 +02:00
2016-11-09 12:30:39 +01:00
if [ "$_log_level" ]; then
2016-09-25 15:58:59 +02:00
_saveaccountconf "LOG_LEVEL" "$_log_level"
LOG_LEVEL="$_log_level"
fi
2016-11-09 12:30:39 +01:00
2017-02-11 14:15:36 +01:00
if [ "$_syslog" ]; then
if _exists logger; then
if [ "$_syslog" = "0" ]; then
_clearaccountconf "SYS_LOG"
else
_saveaccountconf "SYS_LOG" "$_syslog"
fi
SYS_LOG="$_syslog"
else
_err "The 'logger' command is not found, can not enable syslog."
_clearaccountconf "SYS_LOG"
SYS_LOG=""
fi
fi
2016-09-19 17:07:43 +02:00
_processAccountConf
fi
2016-11-09 12:30:39 +01:00
2016-11-04 15:03:41 +01:00
_debug2 LE_WORKING_DIR "$LE_WORKING_DIR"
2016-11-09 12:30:39 +01:00
if [ "$DEBUG" ]; then
2016-07-15 10:40:03 +02:00
version
2017-06-19 14:19:30 +02:00
if [ "$_server" ]; then
_debug "Using server: $_server"
fi
2016-07-15 10:40:03 +02:00
fi
_debug "Running cmd: ${_CMD}"
case "${_CMD}" in
2020-08-17 16:18:20 +02:00
install) install "$_nocron" "$_confighome" "$_noprofile" ;;
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"
;;
deploy)
deploy "$_domain" "$_deploy_hook" "$_ecc"
;;
signcsr)
signcsr "$_csr" "$_webroot" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias"
;;
showcsr)
showcsr "$_csr" "$_domain"
;;
installcert)
installcert "$_domain" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_ecc"
;;
renew)
renew "$_domain" "$_ecc"
;;
renewAll)
renewAll "$_stopRenewOnError"
;;
revoke)
revoke "$_domain" "$_ecc" "$_revoke_reason"
;;
remove)
remove "$_domain" "$_ecc"
;;
deactivate)
deactivate "$_domain,$_altdomains"
;;
registeraccount)
registeraccount "$_accountkeylength" "$_eab_kid" "$_eab_hmac_key"
;;
updateaccount)
updateaccount
;;
deactivateaccount)
deactivateaccount
;;
list)
list "$_listraw" "$_domain"
;;
installcronjob) installcronjob "$_confighome" ;;
uninstallcronjob) uninstallcronjob ;;
cron) cron ;;
toPkcs)
toPkcs "$_domain" "$_password" "$_ecc"
;;
toPkcs8)
toPkcs8 "$_domain" "$_ecc"
;;
createAccountKey)
createAccountKey "$_accountkeylength"
;;
createDomainKey)
createDomainKey "$_domain" "$_keylength"
;;
createCSR)
createCSR "$_domain" "$_altdomains" "$_ecc"
;;
setnotify)
setnotify "$_notify_hook" "$_notify_level" "$_notify_mode"
;;
setdefaultca)
setdefaultca
;;
*)
if [ "$_CMD" ]; then
_err "Invalid command: $_CMD"
fi
showhelp
return 1
;;
esac
2016-05-09 16:56:19 +02:00
_ret="$?"
2016-11-09 12:30:39 +01:00
if [ "$_ret" != "0" ]; then
2016-05-09 16:56:19 +02:00
return $_ret
fi
2016-11-09 12:30:39 +01:00
if [ "${_CMD}" = "install" ]; then
if [ "$_log" ]; then
if [ -z "$LOG_FILE" ]; then
LOG_FILE="$DEFAULT_LOG_FILE"
fi
_saveaccountconf "LOG_FILE" "$LOG_FILE"
2016-09-19 17:07:43 +02:00
fi
2016-11-09 12:30:39 +01:00
if [ "$_log_level" ]; then
2016-09-25 15:58:59 +02:00
_saveaccountconf "LOG_LEVEL" "$_log_level"
fi
2017-02-11 14:15:36 +01:00
if [ "$_syslog" ]; then
if _exists logger; then
if [ "$_syslog" = "0" ]; then
_clearaccountconf "SYS_LOG"
else
_saveaccountconf "SYS_LOG" "$_syslog"
fi
else
_err "The 'logger' command is not found, can not enable syslog."
_clearaccountconf "SYS_LOG"
SYS_LOG=""
fi
fi
2016-09-19 17:07:43 +02:00
_processAccountConf
fi
}
2016-11-09 12:30:39 +01:00
if [ "$INSTALLONLINE" ]; then
2016-03-27 14:37:26 +02:00
INSTALLONLINE=""
2017-01-13 13:49:58 +01:00
_installOnline
2016-03-27 14:31:22 +02:00
exit
fi
2016-03-08 13:44:12 +01:00
2016-09-21 07:39:39 +02:00
main() {
[ -z "$1" ] && showhelp && return
2016-11-09 12:30:39 +01:00
if _startswith "$1" '-'; then _process "$@"; else "$@"; fi
2016-09-21 07:39:39 +02:00
}
2016-09-21 07:27:05 +02:00
2016-10-05 06:15:06 +02:00
main "$@"