| 1630 | 1 #!/usr/bin/env sh | 
|  | 2 | 
|  | 3 VER=2.8.8 | 
|  | 4 | 
|  | 5 PROJECT_NAME="acme.sh" | 
|  | 6 | 
|  | 7 PROJECT_ENTRY="acme.sh" | 
|  | 8 | 
|  | 9 PROJECT="https://github.com/acmesh-official/$PROJECT_NAME" | 
|  | 10 | 
|  | 11 DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME" | 
|  | 12 | 
|  | 13 _WINDOWS_SCHEDULER_NAME="$PROJECT_NAME.cron" | 
|  | 14 | 
|  | 15 _SCRIPT_="$0" | 
|  | 16 | 
|  | 17 _SUB_FOLDER_NOTIFY="notify" | 
|  | 18 _SUB_FOLDER_DNSAPI="dnsapi" | 
|  | 19 _SUB_FOLDER_DEPLOY="deploy" | 
|  | 20 | 
|  | 21 _SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY" | 
|  | 22 | 
|  | 23 LETSENCRYPT_CA_V1="https://acme-v01.api.letsencrypt.org/directory" | 
|  | 24 LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory" | 
|  | 25 | 
|  | 26 CA_LETSENCRYPT_V2="https://acme-v02.api.letsencrypt.org/directory" | 
|  | 27 CA_LETSENCRYPT_V2_TEST="https://acme-staging-v02.api.letsencrypt.org/directory" | 
|  | 28 | 
|  | 29 CA_BUYPASS="https://api.buypass.com/acme/directory" | 
|  | 30 CA_BUYPASS_TEST="https://api.test4.buypass.no/acme/directory" | 
|  | 31 | 
|  | 32 CA_ZEROSSL="https://acme.zerossl.com/v2/DV90" | 
|  | 33 _ZERO_EAB_ENDPOINT="http://api.zerossl.com/acme/eab-credentials-email" | 
|  | 34 | 
|  | 35 DEFAULT_CA=$CA_LETSENCRYPT_V2 | 
|  | 36 DEFAULT_STAGING_CA=$CA_LETSENCRYPT_V2_TEST | 
|  | 37 | 
|  | 38 CA_NAMES=" | 
|  | 39 LetsEncrypt.org,letsencrypt | 
|  | 40 LetsEncrypt.org_test,letsencrypt_test,letsencrypttest | 
|  | 41 BuyPass.com,buypass | 
|  | 42 BuyPass.com_test,buypass_test,buypasstest | 
|  | 43 ZeroSSL.com,zerossl | 
|  | 44 " | 
|  | 45 | 
|  | 46 CA_SERVERS="$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_BUYPASS,$CA_BUYPASS_TEST,$CA_ZEROSSL" | 
|  | 47 | 
|  | 48 DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" | 
|  | 49 | 
|  | 50 DEFAULT_ACCOUNT_KEY_LENGTH=2048 | 
|  | 51 DEFAULT_DOMAIN_KEY_LENGTH=2048 | 
|  | 52 | 
|  | 53 DEFAULT_OPENSSL_BIN="openssl" | 
|  | 54 | 
|  | 55 VTYPE_HTTP="http-01" | 
|  | 56 VTYPE_DNS="dns-01" | 
|  | 57 VTYPE_ALPN="tls-alpn-01" | 
|  | 58 | 
|  | 59 LOCAL_ANY_ADDRESS="0.0.0.0" | 
|  | 60 | 
|  | 61 DEFAULT_RENEW=60 | 
|  | 62 | 
|  | 63 NO_VALUE="no" | 
|  | 64 | 
|  | 65 W_DNS="dns" | 
|  | 66 W_ALPN="alpn" | 
|  | 67 DNS_ALIAS_PREFIX="=" | 
|  | 68 | 
|  | 69 MODE_STATELESS="stateless" | 
|  | 70 | 
|  | 71 STATE_VERIFIED="verified_ok" | 
|  | 72 | 
|  | 73 NGINX="nginx:" | 
|  | 74 NGINX_START="#ACME_NGINX_START" | 
|  | 75 NGINX_END="#ACME_NGINX_END" | 
|  | 76 | 
|  | 77 BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" | 
|  | 78 END_CSR="-----END CERTIFICATE REQUEST-----" | 
|  | 79 | 
|  | 80 BEGIN_CERT="-----BEGIN CERTIFICATE-----" | 
|  | 81 END_CERT="-----END CERTIFICATE-----" | 
|  | 82 | 
|  | 83 CONTENT_TYPE_JSON="application/jose+json" | 
|  | 84 RENEW_SKIP=2 | 
|  | 85 | 
|  | 86 B64CONF_START="__ACME_BASE64__START_" | 
|  | 87 B64CONF_END="__ACME_BASE64__END_" | 
|  | 88 | 
|  | 89 ECC_SEP="_" | 
|  | 90 ECC_SUFFIX="${ECC_SEP}ecc" | 
|  | 91 | 
|  | 92 LOG_LEVEL_1=1 | 
|  | 93 LOG_LEVEL_2=2 | 
|  | 94 LOG_LEVEL_3=3 | 
|  | 95 DEFAULT_LOG_LEVEL="$LOG_LEVEL_1" | 
|  | 96 | 
|  | 97 DEBUG_LEVEL_1=1 | 
|  | 98 DEBUG_LEVEL_2=2 | 
|  | 99 DEBUG_LEVEL_3=3 | 
|  | 100 DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1 | 
|  | 101 DEBUG_LEVEL_NONE=0 | 
|  | 102 | 
|  | 103 DOH_CLOUDFLARE=1 | 
|  | 104 DOH_GOOGLE=2 | 
|  | 105 | 
|  | 106 HIDDEN_VALUE="[hidden](please add '--output-insecure' to see this value)" | 
|  | 107 | 
|  | 108 SYSLOG_ERROR="user.error" | 
|  | 109 SYSLOG_INFO="user.info" | 
|  | 110 SYSLOG_DEBUG="user.debug" | 
|  | 111 | 
|  | 112 #error | 
|  | 113 SYSLOG_LEVEL_ERROR=3 | 
|  | 114 #info | 
|  | 115 SYSLOG_LEVEL_INFO=6 | 
|  | 116 #debug | 
|  | 117 SYSLOG_LEVEL_DEBUG=7 | 
|  | 118 #debug2 | 
|  | 119 SYSLOG_LEVEL_DEBUG_2=8 | 
|  | 120 #debug3 | 
|  | 121 SYSLOG_LEVEL_DEBUG_3=9 | 
|  | 122 | 
|  | 123 SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_ERROR | 
|  | 124 #none | 
|  | 125 SYSLOG_LEVEL_NONE=0 | 
|  | 126 | 
|  | 127 NOTIFY_LEVEL_DISABLE=0 | 
|  | 128 NOTIFY_LEVEL_ERROR=1 | 
|  | 129 NOTIFY_LEVEL_RENEW=2 | 
|  | 130 NOTIFY_LEVEL_SKIP=3 | 
|  | 131 | 
|  | 132 NOTIFY_LEVEL_DEFAULT=$NOTIFY_LEVEL_RENEW | 
|  | 133 | 
|  | 134 NOTIFY_MODE_BULK=0 | 
|  | 135 NOTIFY_MODE_CERT=1 | 
|  | 136 | 
|  | 137 NOTIFY_MODE_DEFAULT=$NOTIFY_MODE_BULK | 
|  | 138 | 
|  | 139 _DEBUG_WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh" | 
|  | 140 | 
|  | 141 _PREPARE_LINK="https://github.com/acmesh-official/acme.sh/wiki/Install-preparations" | 
|  | 142 | 
|  | 143 _STATELESS_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Stateless-Mode" | 
|  | 144 | 
|  | 145 _DNS_ALIAS_WIKI="https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode" | 
|  | 146 | 
|  | 147 _DNS_MANUAL_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dns-manual-mode" | 
|  | 148 | 
|  | 149 _DNS_API_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dnsapi" | 
|  | 150 | 
|  | 151 _NOTIFY_WIKI="https://github.com/acmesh-official/acme.sh/wiki/notify" | 
|  | 152 | 
|  | 153 _SUDO_WIKI="https://github.com/acmesh-official/acme.sh/wiki/sudo" | 
|  | 154 | 
|  | 155 _REVOKE_WIKI="https://github.com/acmesh-official/acme.sh/wiki/revokecert" | 
|  | 156 | 
|  | 157 _ZEROSSL_WIKI="https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA" | 
|  | 158 | 
|  | 159 _SERVER_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Server" | 
|  | 160 | 
|  | 161 _PREFERRED_CHAIN_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Preferred-Chain" | 
|  | 162 | 
|  | 163 _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." | 
|  | 164 | 
|  | 165 _DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR" | 
|  | 166 | 
|  | 167 _DNS_MANUAL_ERROR="It seems that you are using dns manual mode. Read this link first: $_DNS_MANUAL_WIKI" | 
|  | 168 | 
|  | 169 __INTERACTIVE="" | 
|  | 170 if [ -t 1 ]; then | 
|  | 171   __INTERACTIVE="1" | 
|  | 172 fi | 
|  | 173 | 
|  | 174 __green() { | 
|  | 175   if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then | 
|  | 176     printf '\33[1;32m%b\33[0m' "$1" | 
|  | 177     return | 
|  | 178   fi | 
|  | 179   printf -- "%b" "$1" | 
|  | 180 } | 
|  | 181 | 
|  | 182 __red() { | 
|  | 183   if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then | 
|  | 184     printf '\33[1;31m%b\33[0m' "$1" | 
|  | 185     return | 
|  | 186   fi | 
|  | 187   printf -- "%b" "$1" | 
|  | 188 } | 
|  | 189 | 
|  | 190 _printargs() { | 
|  | 191   _exitstatus="$?" | 
|  | 192   if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then | 
|  | 193     printf -- "%s" "[$(date)] " | 
|  | 194   fi | 
|  | 195   if [ -z "$2" ]; then | 
|  | 196     printf -- "%s" "$1" | 
|  | 197   else | 
|  | 198     printf -- "%s" "$1='$2'" | 
|  | 199   fi | 
|  | 200   printf "\n" | 
|  | 201   # return the saved exit status | 
|  | 202   return "$_exitstatus" | 
|  | 203 } | 
|  | 204 | 
|  | 205 _dlg_versions() { | 
|  | 206   echo "Diagnosis versions: " | 
|  | 207   echo "openssl:$ACME_OPENSSL_BIN" | 
|  | 208   if _exists "${ACME_OPENSSL_BIN:-openssl}"; then | 
|  | 209     ${ACME_OPENSSL_BIN:-openssl} version 2>&1 | 
|  | 210   else | 
|  | 211     echo "$ACME_OPENSSL_BIN doesn't exist." | 
|  | 212   fi | 
|  | 213 | 
|  | 214   echo "apache:" | 
|  | 215   if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then | 
|  | 216     $_APACHECTL -V 2>&1 | 
|  | 217   else | 
|  | 218     echo "apache doesn't exist." | 
|  | 219   fi | 
|  | 220 | 
|  | 221   echo "nginx:" | 
|  | 222   if _exists "nginx"; then | 
|  | 223     nginx -V 2>&1 | 
|  | 224   else | 
|  | 225     echo "nginx doesn't exist." | 
|  | 226   fi | 
|  | 227 | 
|  | 228   echo "socat:" | 
|  | 229   if _exists "socat"; then | 
|  | 230     socat -V 2>&1 | 
|  | 231   else | 
|  | 232     _debug "socat doesn't exist." | 
|  | 233   fi | 
|  | 234 } | 
|  | 235 | 
|  | 236 #class | 
|  | 237 _syslog() { | 
|  | 238   _exitstatus="$?" | 
|  | 239   if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" = "$SYSLOG_LEVEL_NONE" ]; then | 
|  | 240     return | 
|  | 241   fi | 
|  | 242   _logclass="$1" | 
|  | 243   shift | 
|  | 244   if [ -z "$__logger_i" ]; then | 
|  | 245     if _contains "$(logger --help 2>&1)" "-i"; then | 
|  | 246       __logger_i="logger -i" | 
|  | 247     else | 
|  | 248       __logger_i="logger" | 
|  | 249     fi | 
|  | 250   fi | 
|  | 251   $__logger_i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1 | 
|  | 252   return "$_exitstatus" | 
|  | 253 } | 
|  | 254 | 
|  | 255 _log() { | 
|  | 256   [ -z "$LOG_FILE" ] && return | 
|  | 257   _printargs "$@" >>"$LOG_FILE" | 
|  | 258 } | 
|  | 259 | 
|  | 260 _info() { | 
|  | 261   _log "$@" | 
|  | 262   if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_INFO" ]; then | 
|  | 263     _syslog "$SYSLOG_INFO" "$@" | 
|  | 264   fi | 
|  | 265   _printargs "$@" | 
|  | 266 } | 
|  | 267 | 
|  | 268 _err() { | 
|  | 269   _syslog "$SYSLOG_ERROR" "$@" | 
|  | 270   _log "$@" | 
|  | 271   if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then | 
|  | 272     printf -- "%s" "[$(date)] " >&2 | 
|  | 273   fi | 
|  | 274   if [ -z "$2" ]; then | 
|  | 275     __red "$1" >&2 | 
|  | 276   else | 
|  | 277     __red "$1='$2'" >&2 | 
|  | 278   fi | 
|  | 279   printf "\n" >&2 | 
|  | 280   return 1 | 
|  | 281 } | 
|  | 282 | 
|  | 283 _usage() { | 
|  | 284   __red "$@" >&2 | 
|  | 285   printf "\n" >&2 | 
|  | 286 } | 
|  | 287 | 
|  | 288 __debug_bash_helper() { | 
|  | 289   # At this point only do for --debug 3 | 
|  | 290   if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -lt "$DEBUG_LEVEL_3" ]; then | 
|  | 291     return | 
|  | 292   fi | 
|  | 293   # Return extra debug info when running with bash, otherwise return empty | 
|  | 294   # string. | 
|  | 295   if [ -z "${BASH_VERSION}" ]; then | 
|  | 296     return | 
|  | 297   fi | 
|  | 298   # We are a bash shell at this point, return the filename, function name, and | 
|  | 299   # line number as a string | 
|  | 300   _dbh_saveIFS=$IFS | 
|  | 301   IFS=" " | 
|  | 302   # Must use eval or syntax error happens under dash. The eval should use | 
|  | 303   # single quotes as older versions of busybox had a bug with double quotes and | 
|  | 304   # eval. | 
|  | 305   # Use 'caller 1' as we want one level up the stack as we should be called | 
|  | 306   # by one of the _debug* functions | 
|  | 307   eval '_dbh_called=($(caller 1))' | 
|  | 308   IFS=$_dbh_saveIFS | 
|  | 309   eval '_dbh_file=${_dbh_called[2]}' | 
|  | 310   if [ -n "${_script_home}" ]; then | 
|  | 311     # Trim off the _script_home directory name | 
|  | 312     eval '_dbh_file=${_dbh_file#$_script_home/}' | 
|  | 313   fi | 
|  | 314   eval '_dbh_function=${_dbh_called[1]}' | 
|  | 315   eval '_dbh_lineno=${_dbh_called[0]}' | 
|  | 316   printf "%-40s " "$_dbh_file:${_dbh_function}:${_dbh_lineno}" | 
|  | 317 } | 
|  | 318 | 
|  | 319 _debug() { | 
|  | 320   if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then | 
|  | 321     _log "$@" | 
|  | 322   fi | 
|  | 323   if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then | 
|  | 324     _syslog "$SYSLOG_DEBUG" "$@" | 
|  | 325   fi | 
|  | 326   if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then | 
|  | 327     _bash_debug=$(__debug_bash_helper) | 
|  | 328     _printargs "${_bash_debug}$@" >&2 | 
|  | 329   fi | 
|  | 330 } | 
|  | 331 | 
|  | 332 #output the sensitive messages | 
|  | 333 _secure_debug() { | 
|  | 334   if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then | 
|  | 335     if [ "$OUTPUT_INSECURE" = "1" ]; then | 
|  | 336       _log "$@" | 
|  | 337     else | 
|  | 338       _log "$1" "$HIDDEN_VALUE" | 
|  | 339     fi | 
|  | 340   fi | 
|  | 341   if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then | 
|  | 342     _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" | 
|  | 343   fi | 
|  | 344   if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then | 
|  | 345     if [ "$OUTPUT_INSECURE" = "1" ]; then | 
|  | 346       _printargs "$@" >&2 | 
|  | 347     else | 
|  | 348       _printargs "$1" "$HIDDEN_VALUE" >&2 | 
|  | 349     fi | 
|  | 350   fi | 
|  | 351 } | 
|  | 352 | 
|  | 353 _debug2() { | 
|  | 354   if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then | 
|  | 355     _log "$@" | 
|  | 356   fi | 
|  | 357   if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then | 
|  | 358     _syslog "$SYSLOG_DEBUG" "$@" | 
|  | 359   fi | 
|  | 360   if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then | 
|  | 361     _bash_debug=$(__debug_bash_helper) | 
|  | 362     _printargs "${_bash_debug}$@" >&2 | 
|  | 363   fi | 
|  | 364 } | 
|  | 365 | 
|  | 366 _secure_debug2() { | 
|  | 367   if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then | 
|  | 368     if [ "$OUTPUT_INSECURE" = "1" ]; then | 
|  | 369       _log "$@" | 
|  | 370     else | 
|  | 371       _log "$1" "$HIDDEN_VALUE" | 
|  | 372     fi | 
|  | 373   fi | 
|  | 374   if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then | 
|  | 375     _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" | 
|  | 376   fi | 
|  | 377   if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then | 
|  | 378     if [ "$OUTPUT_INSECURE" = "1" ]; then | 
|  | 379       _printargs "$@" >&2 | 
|  | 380     else | 
|  | 381       _printargs "$1" "$HIDDEN_VALUE" >&2 | 
|  | 382     fi | 
|  | 383   fi | 
|  | 384 } | 
|  | 385 | 
|  | 386 _debug3() { | 
|  | 387   if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then | 
|  | 388     _log "$@" | 
|  | 389   fi | 
|  | 390   if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then | 
|  | 391     _syslog "$SYSLOG_DEBUG" "$@" | 
|  | 392   fi | 
|  | 393   if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then | 
|  | 394     _bash_debug=$(__debug_bash_helper) | 
|  | 395     _printargs "${_bash_debug}$@" >&2 | 
|  | 396   fi | 
|  | 397 } | 
|  | 398 | 
|  | 399 _secure_debug3() { | 
|  | 400   if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then | 
|  | 401     if [ "$OUTPUT_INSECURE" = "1" ]; then | 
|  | 402       _log "$@" | 
|  | 403     else | 
|  | 404       _log "$1" "$HIDDEN_VALUE" | 
|  | 405     fi | 
|  | 406   fi | 
|  | 407   if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then | 
|  | 408     _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" | 
|  | 409   fi | 
|  | 410   if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then | 
|  | 411     if [ "$OUTPUT_INSECURE" = "1" ]; then | 
|  | 412       _printargs "$@" >&2 | 
|  | 413     else | 
|  | 414       _printargs "$1" "$HIDDEN_VALUE" >&2 | 
|  | 415     fi | 
|  | 416   fi | 
|  | 417 } | 
|  | 418 | 
|  | 419 _upper_case() { | 
|  | 420   # shellcheck disable=SC2018,SC2019 | 
|  | 421   tr 'a-z' 'A-Z' | 
|  | 422 } | 
|  | 423 | 
|  | 424 _lower_case() { | 
|  | 425   # shellcheck disable=SC2018,SC2019 | 
|  | 426   tr 'A-Z' 'a-z' | 
|  | 427 } | 
|  | 428 | 
|  | 429 _startswith() { | 
|  | 430   _str="$1" | 
|  | 431   _sub="$2" | 
|  | 432   echo "$_str" | grep "^$_sub" >/dev/null 2>&1 | 
|  | 433 } | 
|  | 434 | 
|  | 435 _endswith() { | 
|  | 436   _str="$1" | 
|  | 437   _sub="$2" | 
|  | 438   echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1 | 
|  | 439 } | 
|  | 440 | 
|  | 441 _contains() { | 
|  | 442   _str="$1" | 
|  | 443   _sub="$2" | 
|  | 444   echo "$_str" | grep -- "$_sub" >/dev/null 2>&1 | 
|  | 445 } | 
|  | 446 | 
|  | 447 _hasfield() { | 
|  | 448   _str="$1" | 
|  | 449   _field="$2" | 
|  | 450   _sep="$3" | 
|  | 451   if [ -z "$_field" ]; then | 
|  | 452     _usage "Usage: str field  [sep]" | 
|  | 453     return 1 | 
|  | 454   fi | 
|  | 455 | 
|  | 456   if [ -z "$_sep" ]; then | 
|  | 457     _sep="," | 
|  | 458   fi | 
|  | 459 | 
|  | 460   for f in $(echo "$_str" | tr "$_sep" ' '); do | 
|  | 461     if [ "$f" = "$_field" ]; then | 
|  | 462       _debug2 "'$_str' contains '$_field'" | 
|  | 463       return 0 #contains ok | 
|  | 464     fi | 
|  | 465   done | 
|  | 466   _debug2 "'$_str' does not contain '$_field'" | 
|  | 467   return 1 #not contains | 
|  | 468 } | 
|  | 469 | 
|  | 470 # str index [sep] | 
|  | 471 _getfield() { | 
|  | 472   _str="$1" | 
|  | 473   _findex="$2" | 
|  | 474   _sep="$3" | 
|  | 475 | 
|  | 476   if [ -z "$_findex" ]; then | 
|  | 477     _usage "Usage: str field  [sep]" | 
|  | 478     return 1 | 
|  | 479   fi | 
|  | 480 | 
|  | 481   if [ -z "$_sep" ]; then | 
|  | 482     _sep="," | 
|  | 483   fi | 
|  | 484 | 
|  | 485   _ffi="$_findex" | 
|  | 486   while [ "$_ffi" -gt "0" ]; do | 
|  | 487     _fv="$(echo "$_str" | cut -d "$_sep" -f "$_ffi")" | 
|  | 488     if [ "$_fv" ]; then | 
|  | 489       printf -- "%s" "$_fv" | 
|  | 490       return 0 | 
|  | 491     fi | 
|  | 492     _ffi="$(_math "$_ffi" - 1)" | 
|  | 493   done | 
|  | 494 | 
|  | 495   printf -- "%s" "$_str" | 
|  | 496 | 
|  | 497 } | 
|  | 498 | 
|  | 499 _exists() { | 
|  | 500   cmd="$1" | 
|  | 501   if [ -z "$cmd" ]; then | 
|  | 502     _usage "Usage: _exists cmd" | 
|  | 503     return 1 | 
|  | 504   fi | 
|  | 505 | 
|  | 506   if eval type type >/dev/null 2>&1; then | 
|  | 507     eval type "$cmd" >/dev/null 2>&1 | 
|  | 508   elif command >/dev/null 2>&1; then | 
|  | 509     command -v "$cmd" >/dev/null 2>&1 | 
|  | 510   else | 
|  | 511     which "$cmd" >/dev/null 2>&1 | 
|  | 512   fi | 
|  | 513   ret="$?" | 
|  | 514   _debug3 "$cmd exists=$ret" | 
|  | 515   return $ret | 
|  | 516 } | 
|  | 517 | 
|  | 518 #a + b | 
|  | 519 _math() { | 
|  | 520   _m_opts="$@" | 
|  | 521   printf "%s" "$(($_m_opts))" | 
|  | 522 } | 
|  | 523 | 
|  | 524 _h_char_2_dec() { | 
|  | 525   _ch=$1 | 
|  | 526   case "${_ch}" in | 
|  | 527   a | A) | 
|  | 528     printf "10" | 
|  | 529     ;; | 
|  | 530   b | B) | 
|  | 531     printf "11" | 
|  | 532     ;; | 
|  | 533   c | C) | 
|  | 534     printf "12" | 
|  | 535     ;; | 
|  | 536   d | D) | 
|  | 537     printf "13" | 
|  | 538     ;; | 
|  | 539   e | E) | 
|  | 540     printf "14" | 
|  | 541     ;; | 
|  | 542   f | F) | 
|  | 543     printf "15" | 
|  | 544     ;; | 
|  | 545   *) | 
|  | 546     printf "%s" "$_ch" | 
|  | 547     ;; | 
|  | 548   esac | 
|  | 549 | 
|  | 550 } | 
|  | 551 | 
|  | 552 _URGLY_PRINTF="" | 
|  | 553 if [ "$(printf '\x41')" != 'A' ]; then | 
|  | 554   _URGLY_PRINTF=1 | 
|  | 555 fi | 
|  | 556 | 
|  | 557 _ESCAPE_XARGS="" | 
|  | 558 if _exists xargs && [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then | 
|  | 559   _ESCAPE_XARGS=1 | 
|  | 560 fi | 
|  | 561 | 
|  | 562 _h2b() { | 
|  | 563   if _exists xxd && xxd -r -p 2>/dev/null; then | 
|  | 564     return | 
|  | 565   fi | 
|  | 566 | 
|  | 567   hex=$(cat) | 
|  | 568   ic="" | 
|  | 569   jc="" | 
|  | 570   _debug2 _URGLY_PRINTF "$_URGLY_PRINTF" | 
|  | 571   if [ -z "$_URGLY_PRINTF" ]; then | 
|  | 572     if [ "$_ESCAPE_XARGS" ] && _exists xargs; then | 
|  | 573       _debug2 "xargs" | 
|  | 574       echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf | 
|  | 575     else | 
|  | 576       for h in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/ \1/g'); do | 
|  | 577         if [ -z "$h" ]; then | 
|  | 578           break | 
|  | 579         fi | 
|  | 580         printf "\x$h%s" | 
|  | 581       done | 
|  | 582     fi | 
|  | 583   else | 
|  | 584     for c in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\)/ \1/g'); do | 
|  | 585       if [ -z "$ic" ]; then | 
|  | 586         ic=$c | 
|  | 587         continue | 
|  | 588       fi | 
|  | 589       jc=$c | 
|  | 590       ic="$(_h_char_2_dec "$ic")" | 
|  | 591       jc="$(_h_char_2_dec "$jc")" | 
|  | 592       printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s" | 
|  | 593       ic="" | 
|  | 594       jc="" | 
|  | 595     done | 
|  | 596   fi | 
|  | 597 | 
|  | 598 } | 
|  | 599 | 
|  | 600 _is_solaris() { | 
|  | 601   _contains "${__OS__:=$(uname -a)}" "solaris" || _contains "${__OS__:=$(uname -a)}" "SunOS" | 
|  | 602 } | 
|  | 603 | 
|  | 604 #_ascii_hex str | 
|  | 605 #this can only process ascii chars, should only be used when od command is missing as a backup way. | 
|  | 606 _ascii_hex() { | 
|  | 607   _debug2 "Using _ascii_hex" | 
|  | 608   _str="$1" | 
|  | 609   _str_len=${#_str} | 
|  | 610   _h_i=1 | 
|  | 611   while [ "$_h_i" -le "$_str_len" ]; do | 
|  | 612     _str_c="$(printf "%s" "$_str" | cut -c "$_h_i")" | 
|  | 613     printf " %02x" "'$_str_c" | 
|  | 614     _h_i="$(_math "$_h_i" + 1)" | 
|  | 615   done | 
|  | 616 } | 
|  | 617 | 
|  | 618 #stdin  output hexstr splited by one space | 
|  | 619 #input:"abc" | 
|  | 620 #output: " 61 62 63" | 
|  | 621 _hex_dump() { | 
|  | 622   if _exists od; then | 
|  | 623     od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n" | 
|  | 624   elif _exists hexdump; then | 
|  | 625     _debug3 "using hexdump" | 
|  | 626     hexdump -v -e '/1 ""' -e '/1 " %02x" ""' | 
|  | 627   elif _exists xxd; then | 
|  | 628     _debug3 "using xxd" | 
|  | 629     xxd -ps -c 20 -i | sed "s/ 0x/ /g" | tr -d ",\n" | tr -s " " | 
|  | 630   else | 
|  | 631     _debug3 "using _ascii_hex" | 
|  | 632     str=$(cat) | 
|  | 633     _ascii_hex "$str" | 
|  | 634   fi | 
|  | 635 } | 
|  | 636 | 
|  | 637 #url encode, no-preserved chars | 
|  | 638 #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 | 
|  | 639 #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 | 
|  | 640 | 
|  | 641 #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 | 
|  | 642 #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 | 
|  | 643 | 
|  | 644 #0  1  2  3  4  5  6  7  8  9  -  _  .  ~ | 
|  | 645 #30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e | 
|  | 646 | 
|  | 647 #stdin stdout | 
|  | 648 _url_encode() { | 
|  | 649   _hex_str=$(_hex_dump) | 
|  | 650   _debug3 "_url_encode" | 
|  | 651   _debug3 "_hex_str" "$_hex_str" | 
|  | 652   for _hex_code in $_hex_str; do | 
|  | 653     #upper case | 
|  | 654     case "${_hex_code}" in | 
|  | 655     "41") | 
|  | 656       printf "%s" "A" | 
|  | 657       ;; | 
|  | 658     "42") | 
|  | 659       printf "%s" "B" | 
|  | 660       ;; | 
|  | 661     "43") | 
|  | 662       printf "%s" "C" | 
|  | 663       ;; | 
|  | 664     "44") | 
|  | 665       printf "%s" "D" | 
|  | 666       ;; | 
|  | 667     "45") | 
|  | 668       printf "%s" "E" | 
|  | 669       ;; | 
|  | 670     "46") | 
|  | 671       printf "%s" "F" | 
|  | 672       ;; | 
|  | 673     "47") | 
|  | 674       printf "%s" "G" | 
|  | 675       ;; | 
|  | 676     "48") | 
|  | 677       printf "%s" "H" | 
|  | 678       ;; | 
|  | 679     "49") | 
|  | 680       printf "%s" "I" | 
|  | 681       ;; | 
|  | 682     "4a") | 
|  | 683       printf "%s" "J" | 
|  | 684       ;; | 
|  | 685     "4b") | 
|  | 686       printf "%s" "K" | 
|  | 687       ;; | 
|  | 688     "4c") | 
|  | 689       printf "%s" "L" | 
|  | 690       ;; | 
|  | 691     "4d") | 
|  | 692       printf "%s" "M" | 
|  | 693       ;; | 
|  | 694     "4e") | 
|  | 695       printf "%s" "N" | 
|  | 696       ;; | 
|  | 697     "4f") | 
|  | 698       printf "%s" "O" | 
|  | 699       ;; | 
|  | 700     "50") | 
|  | 701       printf "%s" "P" | 
|  | 702       ;; | 
|  | 703     "51") | 
|  | 704       printf "%s" "Q" | 
|  | 705       ;; | 
|  | 706     "52") | 
|  | 707       printf "%s" "R" | 
|  | 708       ;; | 
|  | 709     "53") | 
|  | 710       printf "%s" "S" | 
|  | 711       ;; | 
|  | 712     "54") | 
|  | 713       printf "%s" "T" | 
|  | 714       ;; | 
|  | 715     "55") | 
|  | 716       printf "%s" "U" | 
|  | 717       ;; | 
|  | 718     "56") | 
|  | 719       printf "%s" "V" | 
|  | 720       ;; | 
|  | 721     "57") | 
|  | 722       printf "%s" "W" | 
|  | 723       ;; | 
|  | 724     "58") | 
|  | 725       printf "%s" "X" | 
|  | 726       ;; | 
|  | 727     "59") | 
|  | 728       printf "%s" "Y" | 
|  | 729       ;; | 
|  | 730     "5a") | 
|  | 731       printf "%s" "Z" | 
|  | 732       ;; | 
|  | 733 | 
|  | 734       #lower case | 
|  | 735     "61") | 
|  | 736       printf "%s" "a" | 
|  | 737       ;; | 
|  | 738     "62") | 
|  | 739       printf "%s" "b" | 
|  | 740       ;; | 
|  | 741     "63") | 
|  | 742       printf "%s" "c" | 
|  | 743       ;; | 
|  | 744     "64") | 
|  | 745       printf "%s" "d" | 
|  | 746       ;; | 
|  | 747     "65") | 
|  | 748       printf "%s" "e" | 
|  | 749       ;; | 
|  | 750     "66") | 
|  | 751       printf "%s" "f" | 
|  | 752       ;; | 
|  | 753     "67") | 
|  | 754       printf "%s" "g" | 
|  | 755       ;; | 
|  | 756     "68") | 
|  | 757       printf "%s" "h" | 
|  | 758       ;; | 
|  | 759     "69") | 
|  | 760       printf "%s" "i" | 
|  | 761       ;; | 
|  | 762     "6a") | 
|  | 763       printf "%s" "j" | 
|  | 764       ;; | 
|  | 765     "6b") | 
|  | 766       printf "%s" "k" | 
|  | 767       ;; | 
|  | 768     "6c") | 
|  | 769       printf "%s" "l" | 
|  | 770       ;; | 
|  | 771     "6d") | 
|  | 772       printf "%s" "m" | 
|  | 773       ;; | 
|  | 774     "6e") | 
|  | 775       printf "%s" "n" | 
|  | 776       ;; | 
|  | 777     "6f") | 
|  | 778       printf "%s" "o" | 
|  | 779       ;; | 
|  | 780     "70") | 
|  | 781       printf "%s" "p" | 
|  | 782       ;; | 
|  | 783     "71") | 
|  | 784       printf "%s" "q" | 
|  | 785       ;; | 
|  | 786     "72") | 
|  | 787       printf "%s" "r" | 
|  | 788       ;; | 
|  | 789     "73") | 
|  | 790       printf "%s" "s" | 
|  | 791       ;; | 
|  | 792     "74") | 
|  | 793       printf "%s" "t" | 
|  | 794       ;; | 
|  | 795     "75") | 
|  | 796       printf "%s" "u" | 
|  | 797       ;; | 
|  | 798     "76") | 
|  | 799       printf "%s" "v" | 
|  | 800       ;; | 
|  | 801     "77") | 
|  | 802       printf "%s" "w" | 
|  | 803       ;; | 
|  | 804     "78") | 
|  | 805       printf "%s" "x" | 
|  | 806       ;; | 
|  | 807     "79") | 
|  | 808       printf "%s" "y" | 
|  | 809       ;; | 
|  | 810     "7a") | 
|  | 811       printf "%s" "z" | 
|  | 812       ;; | 
|  | 813       #numbers | 
|  | 814     "30") | 
|  | 815       printf "%s" "0" | 
|  | 816       ;; | 
|  | 817     "31") | 
|  | 818       printf "%s" "1" | 
|  | 819       ;; | 
|  | 820     "32") | 
|  | 821       printf "%s" "2" | 
|  | 822       ;; | 
|  | 823     "33") | 
|  | 824       printf "%s" "3" | 
|  | 825       ;; | 
|  | 826     "34") | 
|  | 827       printf "%s" "4" | 
|  | 828       ;; | 
|  | 829     "35") | 
|  | 830       printf "%s" "5" | 
|  | 831       ;; | 
|  | 832     "36") | 
|  | 833       printf "%s" "6" | 
|  | 834       ;; | 
|  | 835     "37") | 
|  | 836       printf "%s" "7" | 
|  | 837       ;; | 
|  | 838     "38") | 
|  | 839       printf "%s" "8" | 
|  | 840       ;; | 
|  | 841     "39") | 
|  | 842       printf "%s" "9" | 
|  | 843       ;; | 
|  | 844     "2d") | 
|  | 845       printf "%s" "-" | 
|  | 846       ;; | 
|  | 847     "5f") | 
|  | 848       printf "%s" "_" | 
|  | 849       ;; | 
|  | 850     "2e") | 
|  | 851       printf "%s" "." | 
|  | 852       ;; | 
|  | 853     "7e") | 
|  | 854       printf "%s" "~" | 
|  | 855       ;; | 
|  | 856     #other hex | 
|  | 857     *) | 
|  | 858       printf '%%%s' "$_hex_code" | 
|  | 859       ;; | 
|  | 860     esac | 
|  | 861   done | 
|  | 862 } | 
|  | 863 | 
|  | 864 _json_encode() { | 
|  | 865   _j_str="$(sed 's/"/\\"/g' | sed "s/\r/\\r/g")" | 
|  | 866   _debug3 "_json_encode" | 
|  | 867   _debug3 "_j_str" "$_j_str" | 
|  | 868   echo "$_j_str" | _hex_dump | _lower_case | sed 's/0a/5c 6e/g' | tr -d ' ' | _h2b | tr -d "\r\n" | 
|  | 869 } | 
|  | 870 | 
|  | 871 #from: http:\/\/  to http:// | 
|  | 872 _json_decode() { | 
|  | 873   _j_str="$(sed 's#\\/#/#g')" | 
|  | 874   _debug3 "_json_decode" | 
|  | 875   _debug3 "_j_str" "$_j_str" | 
|  | 876   echo "$_j_str" | 
|  | 877 } | 
|  | 878 | 
|  | 879 #options file | 
|  | 880 _sed_i() { | 
|  | 881   options="$1" | 
|  | 882   filename="$2" | 
|  | 883   if [ -z "$filename" ]; then | 
|  | 884     _usage "Usage:_sed_i options filename" | 
|  | 885     return 1 | 
|  | 886   fi | 
|  | 887   _debug2 options "$options" | 
|  | 888   if sed -h 2>&1 | grep "\-i\[SUFFIX]" >/dev/null 2>&1; then | 
|  | 889     _debug "Using sed  -i" | 
|  | 890     sed -i "$options" "$filename" | 
|  | 891   else | 
|  | 892     _debug "No -i support in sed" | 
|  | 893     text="$(cat "$filename")" | 
|  | 894     echo "$text" | sed "$options" >"$filename" | 
|  | 895   fi | 
|  | 896 } | 
|  | 897 | 
|  | 898 _egrep_o() { | 
|  | 899   if ! egrep -o "$1" 2>/dev/null; then | 
|  | 900     sed -n 's/.*\('"$1"'\).*/\1/p' | 
|  | 901   fi | 
|  | 902 } | 
|  | 903 | 
|  | 904 #Usage: file startline endline | 
|  | 905 _getfile() { | 
|  | 906   filename="$1" | 
|  | 907   startline="$2" | 
|  | 908   endline="$3" | 
|  | 909   if [ -z "$endline" ]; then | 
|  | 910     _usage "Usage: file startline endline" | 
|  | 911     return 1 | 
|  | 912   fi | 
|  | 913 | 
|  | 914   i="$(grep -n -- "$startline" "$filename" | cut -d : -f 1)" | 
|  | 915   if [ -z "$i" ]; then | 
|  | 916     _err "Can not find start line: $startline" | 
|  | 917     return 1 | 
|  | 918   fi | 
|  | 919   i="$(_math "$i" + 1)" | 
|  | 920   _debug i "$i" | 
|  | 921 | 
|  | 922   j="$(grep -n -- "$endline" "$filename" | cut -d : -f 1)" | 
|  | 923   if [ -z "$j" ]; then | 
|  | 924     _err "Can not find end line: $endline" | 
|  | 925     return 1 | 
|  | 926   fi | 
|  | 927   j="$(_math "$j" - 1)" | 
|  | 928   _debug j "$j" | 
|  | 929 | 
|  | 930   sed -n "$i,${j}p" "$filename" | 
|  | 931 | 
|  | 932 } | 
|  | 933 | 
|  | 934 #Usage: multiline | 
|  | 935 _base64() { | 
|  | 936   [ "" ] #urgly | 
|  | 937   if [ "$1" ]; then | 
|  | 938     _debug3 "base64 multiline:'$1'" | 
|  | 939     ${ACME_OPENSSL_BIN:-openssl} base64 -e | 
|  | 940   else | 
|  | 941     _debug3 "base64 single line." | 
|  | 942     ${ACME_OPENSSL_BIN:-openssl} base64 -e | tr -d '\r\n' | 
|  | 943   fi | 
|  | 944 } | 
|  | 945 | 
|  | 946 #Usage: multiline | 
|  | 947 _dbase64() { | 
|  | 948   if [ "$1" ]; then | 
|  | 949     ${ACME_OPENSSL_BIN:-openssl} base64 -d -A | 
|  | 950   else | 
|  | 951     ${ACME_OPENSSL_BIN:-openssl} base64 -d | 
|  | 952   fi | 
|  | 953 } | 
|  | 954 | 
|  | 955 #file | 
|  | 956 _checkcert() { | 
|  | 957   _cf="$1" | 
|  | 958   if [ "$DEBUG" ]; then | 
|  | 959     ${ACME_OPENSSL_BIN:-openssl} x509 -noout -text -in "$_cf" | 
|  | 960   else | 
|  | 961     ${ACME_OPENSSL_BIN:-openssl} x509 -noout -text -in "$_cf" >/dev/null 2>&1 | 
|  | 962   fi | 
|  | 963 } | 
|  | 964 | 
|  | 965 #Usage: hashalg  [outputhex] | 
|  | 966 #Output Base64-encoded digest | 
|  | 967 _digest() { | 
|  | 968   alg="$1" | 
|  | 969   if [ -z "$alg" ]; then | 
|  | 970     _usage "Usage: _digest hashalg" | 
|  | 971     return 1 | 
|  | 972   fi | 
|  | 973 | 
|  | 974   outputhex="$2" | 
|  | 975 | 
|  | 976   if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then | 
|  | 977     if [ "$outputhex" ]; then | 
|  | 978       ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' | 
|  | 979     else | 
|  | 980       ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -binary | _base64 | 
|  | 981     fi | 
|  | 982   else | 
|  | 983     _err "$alg is not supported yet" | 
|  | 984     return 1 | 
|  | 985   fi | 
|  | 986 | 
|  | 987 } | 
|  | 988 | 
|  | 989 #Usage: hashalg  secret_hex  [outputhex] | 
|  | 990 #Output binary hmac | 
|  | 991 _hmac() { | 
|  | 992   alg="$1" | 
|  | 993   secret_hex="$2" | 
|  | 994   outputhex="$3" | 
|  | 995 | 
|  | 996   if [ -z "$secret_hex" ]; then | 
|  | 997     _usage "Usage: _hmac hashalg secret [outputhex]" | 
|  | 998     return 1 | 
|  | 999   fi | 
|  | 1000 | 
|  | 1001   if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then | 
|  | 1002     if [ "$outputhex" ]; then | 
|  | 1003       (${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 ' ' | 
|  | 1004     else | 
|  | 1005       ${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 | 
|  | 1006     fi | 
|  | 1007   else | 
|  | 1008     _err "$alg is not supported yet" | 
|  | 1009     return 1 | 
|  | 1010   fi | 
|  | 1011 | 
|  | 1012 } | 
|  | 1013 | 
|  | 1014 #Usage: keyfile hashalg | 
|  | 1015 #Output: Base64-encoded signature value | 
|  | 1016 _sign() { | 
|  | 1017   keyfile="$1" | 
|  | 1018   alg="$2" | 
|  | 1019   if [ -z "$alg" ]; then | 
|  | 1020     _usage "Usage: _sign keyfile hashalg" | 
|  | 1021     return 1 | 
|  | 1022   fi | 
|  | 1023 | 
|  | 1024   _sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile " | 
|  | 1025 | 
|  | 1026   if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || grep "BEGIN PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then | 
|  | 1027     $_sign_openssl -$alg | _base64 | 
|  | 1028   elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then | 
|  | 1029     if ! _signedECText="$($_sign_openssl -sha$__ECC_KEY_LEN | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then | 
|  | 1030       _err "Sign failed: $_sign_openssl" | 
|  | 1031       _err "Key file: $keyfile" | 
|  | 1032       _err "Key content:$(wc -l <"$keyfile") lines" | 
|  | 1033       return 1 | 
|  | 1034     fi | 
|  | 1035     _debug3 "_signedECText" "$_signedECText" | 
|  | 1036     _ec_r="$(echo "$_signedECText" | _head_n 2 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")" | 
|  | 1037     _ec_s="$(echo "$_signedECText" | _head_n 3 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")" | 
|  | 1038     if [ "$__ECC_KEY_LEN" -eq "256" ]; then | 
|  | 1039       while [ "${#_ec_r}" -lt "64" ]; do | 
|  | 1040         _ec_r="0${_ec_r}" | 
|  | 1041       done | 
|  | 1042       while [ "${#_ec_s}" -lt "64" ]; do | 
|  | 1043         _ec_s="0${_ec_s}" | 
|  | 1044       done | 
|  | 1045     fi | 
|  | 1046     if [ "$__ECC_KEY_LEN" -eq "384" ]; then | 
|  | 1047       while [ "${#_ec_r}" -lt "96" ]; do | 
|  | 1048         _ec_r="0${_ec_r}" | 
|  | 1049       done | 
|  | 1050       while [ "${#_ec_s}" -lt "96" ]; do | 
|  | 1051         _ec_s="0${_ec_s}" | 
|  | 1052       done | 
|  | 1053     fi | 
|  | 1054     if [ "$__ECC_KEY_LEN" -eq "512" ]; then | 
|  | 1055       while [ "${#_ec_r}" -lt "132" ]; do | 
|  | 1056         _ec_r="0${_ec_r}" | 
|  | 1057       done | 
|  | 1058       while [ "${#_ec_s}" -lt "132" ]; do | 
|  | 1059         _ec_s="0${_ec_s}" | 
|  | 1060       done | 
|  | 1061     fi | 
|  | 1062     _debug3 "_ec_r" "$_ec_r" | 
|  | 1063     _debug3 "_ec_s" "$_ec_s" | 
|  | 1064     printf "%s" "$_ec_r$_ec_s" | _h2b | _base64 | 
|  | 1065   else | 
|  | 1066     _err "Unknown key file format." | 
|  | 1067     return 1 | 
|  | 1068   fi | 
|  | 1069 | 
|  | 1070 } | 
|  | 1071 | 
|  | 1072 #keylength or isEcc flag (empty str => not ecc) | 
|  | 1073 _isEccKey() { | 
|  | 1074   _length="$1" | 
|  | 1075 | 
|  | 1076   if [ -z "$_length" ]; then | 
|  | 1077     return 1 | 
|  | 1078   fi | 
|  | 1079 | 
|  | 1080   [ "$_length" != "1024" ] && | 
|  | 1081     [ "$_length" != "2048" ] && | 
|  | 1082     [ "$_length" != "3072" ] && | 
|  | 1083     [ "$_length" != "4096" ] && | 
|  | 1084     [ "$_length" != "8192" ] | 
|  | 1085 } | 
|  | 1086 | 
|  | 1087 # _createkey  2048|ec-256   file | 
|  | 1088 _createkey() { | 
|  | 1089   length="$1" | 
|  | 1090   f="$2" | 
|  | 1091   _debug2 "_createkey for file:$f" | 
|  | 1092   eccname="$length" | 
|  | 1093   if _startswith "$length" "ec-"; then | 
|  | 1094     length=$(printf "%s" "$length" | cut -d '-' -f 2-100) | 
|  | 1095 | 
|  | 1096     if [ "$length" = "256" ]; then | 
|  | 1097       eccname="prime256v1" | 
|  | 1098     fi | 
|  | 1099     if [ "$length" = "384" ]; then | 
|  | 1100       eccname="secp384r1" | 
|  | 1101     fi | 
|  | 1102     if [ "$length" = "521" ]; then | 
|  | 1103       eccname="secp521r1" | 
|  | 1104     fi | 
|  | 1105 | 
|  | 1106   fi | 
|  | 1107 | 
|  | 1108   if [ -z "$length" ]; then | 
|  | 1109     length=2048 | 
|  | 1110   fi | 
|  | 1111 | 
|  | 1112   _debug "Use length $length" | 
|  | 1113 | 
|  | 1114   if ! touch "$f" >/dev/null 2>&1; then | 
|  | 1115     _f_path="$(dirname "$f")" | 
|  | 1116     _debug _f_path "$_f_path" | 
|  | 1117     if ! mkdir -p "$_f_path"; then | 
|  | 1118       _err "Can not create path: $_f_path" | 
|  | 1119       return 1 | 
|  | 1120     fi | 
|  | 1121   fi | 
|  | 1122 | 
|  | 1123   if _isEccKey "$length"; then | 
|  | 1124     _debug "Using ec name: $eccname" | 
|  | 1125     if _opkey="$(${ACME_OPENSSL_BIN:-openssl} ecparam -name "$eccname" -genkey 2>/dev/null)"; then | 
|  | 1126       echo "$_opkey" >"$f" | 
|  | 1127     else | 
|  | 1128       _err "error ecc key name: $eccname" | 
|  | 1129       return 1 | 
|  | 1130     fi | 
|  | 1131   else | 
|  | 1132     _debug "Using RSA: $length" | 
|  | 1133     if _opkey="$(${ACME_OPENSSL_BIN:-openssl} genrsa "$length" 2>/dev/null)"; then | 
|  | 1134       echo "$_opkey" >"$f" | 
|  | 1135     else | 
|  | 1136       _err "error rsa key: $length" | 
|  | 1137       return 1 | 
|  | 1138     fi | 
|  | 1139   fi | 
|  | 1140 | 
|  | 1141   if [ "$?" != "0" ]; then | 
|  | 1142     _err "Create key error." | 
|  | 1143     return 1 | 
|  | 1144   fi | 
|  | 1145 } | 
|  | 1146 | 
|  | 1147 #domain | 
|  | 1148 _is_idn() { | 
|  | 1149   _is_idn_d="$1" | 
|  | 1150   _debug2 _is_idn_d "$_is_idn_d" | 
|  | 1151   _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '*.,-_') | 
|  | 1152   _debug2 _idn_temp "$_idn_temp" | 
|  | 1153   [ "$_idn_temp" ] | 
|  | 1154 } | 
|  | 1155 | 
|  | 1156 #aa.com | 
|  | 1157 #aa.com,bb.com,cc.com | 
|  | 1158 _idn() { | 
|  | 1159   __idn_d="$1" | 
|  | 1160   if ! _is_idn "$__idn_d"; then | 
|  | 1161     printf "%s" "$__idn_d" | 
|  | 1162     return 0 | 
|  | 1163   fi | 
|  | 1164 | 
|  | 1165   if _exists idn; then | 
|  | 1166     if _contains "$__idn_d" ','; then | 
|  | 1167       _i_first="1" | 
|  | 1168       for f in $(echo "$__idn_d" | tr ',' ' '); do | 
|  | 1169         [ -z "$f" ] && continue | 
|  | 1170         if [ -z "$_i_first" ]; then | 
|  | 1171           printf "%s" "," | 
|  | 1172         else | 
|  | 1173           _i_first="" | 
|  | 1174         fi | 
|  | 1175         idn --quiet "$f" | tr -d "\r\n" | 
|  | 1176       done | 
|  | 1177     else | 
|  | 1178       idn "$__idn_d" | tr -d "\r\n" | 
|  | 1179     fi | 
|  | 1180   else | 
|  | 1181     _err "Please install idn to process IDN names." | 
|  | 1182   fi | 
|  | 1183 } | 
|  | 1184 | 
|  | 1185 #_createcsr  cn  san_list  keyfile csrfile conf acmeValidationv1 | 
|  | 1186 _createcsr() { | 
|  | 1187   _debug _createcsr | 
|  | 1188   domain="$1" | 
|  | 1189   domainlist="$2" | 
|  | 1190   csrkey="$3" | 
|  | 1191   csr="$4" | 
|  | 1192   csrconf="$5" | 
|  | 1193   acmeValidationv1="$6" | 
|  | 1194   _debug2 domain "$domain" | 
|  | 1195   _debug2 domainlist "$domainlist" | 
|  | 1196   _debug2 csrkey "$csrkey" | 
|  | 1197   _debug2 csr "$csr" | 
|  | 1198   _debug2 csrconf "$csrconf" | 
|  | 1199 | 
|  | 1200   printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf" | 
|  | 1201 | 
|  | 1202   if [ "$acmeValidationv1" ]; then | 
|  | 1203     domainlist="$(_idn "$domainlist")" | 
|  | 1204     printf -- "\nsubjectAltName=DNS:$domainlist" >>"$csrconf" | 
|  | 1205   elif [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then | 
|  | 1206     #single domain | 
|  | 1207     _info "Single domain" "$domain" | 
|  | 1208     printf -- "\nsubjectAltName=DNS:$(_idn "$domain")" >>"$csrconf" | 
|  | 1209   else | 
|  | 1210     domainlist="$(_idn "$domainlist")" | 
|  | 1211     _debug2 domainlist "$domainlist" | 
|  | 1212     if _contains "$domainlist" ","; then | 
|  | 1213       alt="DNS:$(_idn "$domain"),DNS:$(echo "$domainlist" | sed "s/,,/,/g" | sed "s/,/,DNS:/g")" | 
|  | 1214     else | 
|  | 1215       alt="DNS:$(_idn "$domain"),DNS:$domainlist" | 
|  | 1216     fi | 
|  | 1217     #multi | 
|  | 1218     _info "Multi domain" "$alt" | 
|  | 1219     printf -- "\nsubjectAltName=$alt" >>"$csrconf" | 
|  | 1220   fi | 
|  | 1221   if [ "$Le_OCSP_Staple" = "1" ]; then | 
|  | 1222     _savedomainconf Le_OCSP_Staple "$Le_OCSP_Staple" | 
|  | 1223     printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf" | 
|  | 1224   fi | 
|  | 1225 | 
|  | 1226   if [ "$acmeValidationv1" ]; then | 
|  | 1227     printf "\n1.3.6.1.5.5.7.1.31=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}" | 
|  | 1228   fi | 
|  | 1229 | 
|  | 1230   _csr_cn="$(_idn "$domain")" | 
|  | 1231   _debug2 _csr_cn "$_csr_cn" | 
|  | 1232   if _contains "$(uname -a)" "MINGW"; then | 
|  | 1233     ${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" | 
|  | 1234   else | 
|  | 1235     ${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" | 
|  | 1236   fi | 
|  | 1237 } | 
|  | 1238 | 
|  | 1239 #_signcsr key  csr  conf cert | 
|  | 1240 _signcsr() { | 
|  | 1241   key="$1" | 
|  | 1242   csr="$2" | 
|  | 1243   conf="$3" | 
|  | 1244   cert="$4" | 
|  | 1245   _debug "_signcsr" | 
|  | 1246 | 
|  | 1247   _msg="$(${ACME_OPENSSL_BIN:-openssl} x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" | 
|  | 1248   _ret="$?" | 
|  | 1249   _debug "$_msg" | 
|  | 1250   return $_ret | 
|  | 1251 } | 
|  | 1252 | 
|  | 1253 #_csrfile | 
|  | 1254 _readSubjectFromCSR() { | 
|  | 1255   _csrfile="$1" | 
|  | 1256   if [ -z "$_csrfile" ]; then | 
|  | 1257     _usage "_readSubjectFromCSR mycsr.csr" | 
|  | 1258     return 1 | 
|  | 1259   fi | 
|  | 1260   ${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' | 
|  | 1261 } | 
|  | 1262 | 
|  | 1263 #_csrfile | 
|  | 1264 #echo comma separated domain list | 
|  | 1265 _readSubjectAltNamesFromCSR() { | 
|  | 1266   _csrfile="$1" | 
|  | 1267   if [ -z "$_csrfile" ]; then | 
|  | 1268     _usage "_readSubjectAltNamesFromCSR mycsr.csr" | 
|  | 1269     return 1 | 
|  | 1270   fi | 
|  | 1271 | 
|  | 1272   _csrsubj="$(_readSubjectFromCSR "$_csrfile")" | 
|  | 1273   _debug _csrsubj "$_csrsubj" | 
|  | 1274 | 
|  | 1275   _dnsAltnames="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" | 
|  | 1276   _debug _dnsAltnames "$_dnsAltnames" | 
|  | 1277 | 
|  | 1278   if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then | 
|  | 1279     _debug "AltNames contains subject" | 
|  | 1280     _excapedAlgnames="$(echo "$_dnsAltnames" | tr '*' '#')" | 
|  | 1281     _debug _excapedAlgnames "$_excapedAlgnames" | 
|  | 1282     _escapedSubject="$(echo "$_csrsubj" | tr '*' '#')" | 
|  | 1283     _debug _escapedSubject "$_escapedSubject" | 
|  | 1284     _dnsAltnames="$(echo "$_excapedAlgnames," | sed "s/DNS:$_escapedSubject,//g" | tr '#' '*' | sed "s/,\$//g")" | 
|  | 1285     _debug _dnsAltnames "$_dnsAltnames" | 
|  | 1286   else | 
|  | 1287     _debug "AltNames doesn't contain subject" | 
|  | 1288   fi | 
|  | 1289 | 
|  | 1290   echo "$_dnsAltnames" | sed "s/DNS://g" | 
|  | 1291 } | 
|  | 1292 | 
|  | 1293 #_csrfile | 
|  | 1294 _readKeyLengthFromCSR() { | 
|  | 1295   _csrfile="$1" | 
|  | 1296   if [ -z "$_csrfile" ]; then | 
|  | 1297     _usage "_readKeyLengthFromCSR mycsr.csr" | 
|  | 1298     return 1 | 
|  | 1299   fi | 
|  | 1300 | 
|  | 1301   _outcsr="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile")" | 
|  | 1302   _debug2 _outcsr "$_outcsr" | 
|  | 1303   if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then | 
|  | 1304     _debug "ECC CSR" | 
|  | 1305     echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' | 
|  | 1306   else | 
|  | 1307     _debug "RSA CSR" | 
|  | 1308     _rkl="$(echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1)" | 
|  | 1309     if [ "$_rkl" ]; then | 
|  | 1310       echo "$_rkl" | 
|  | 1311     else | 
|  | 1312       echo "$_outcsr" | tr "\t" " " | _egrep_o "RSA Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 | 
|  | 1313     fi | 
|  | 1314   fi | 
|  | 1315 } | 
|  | 1316 | 
|  | 1317 _ss() { | 
|  | 1318   _port="$1" | 
|  | 1319 | 
|  | 1320   if _exists "ss"; then | 
|  | 1321     _debug "Using: ss" | 
|  | 1322     ss -ntpl 2>/dev/null | grep ":$_port " | 
|  | 1323     return 0 | 
|  | 1324   fi | 
|  | 1325 | 
|  | 1326   if _exists "netstat"; then | 
|  | 1327     _debug "Using: netstat" | 
|  | 1328     if netstat -help 2>&1 | grep "\-p proto" >/dev/null; then | 
|  | 1329       #for windows version netstat tool | 
|  | 1330       netstat -an -p tcp | grep "LISTENING" | grep ":$_port " | 
|  | 1331     else | 
|  | 1332       if netstat -help 2>&1 | grep "\-p protocol" >/dev/null; then | 
|  | 1333         netstat -an -p tcp | grep LISTEN | grep ":$_port " | 
|  | 1334       elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then | 
|  | 1335         #for solaris | 
|  | 1336         netstat -an -P tcp | grep "\.$_port " | grep "LISTEN" | 
|  | 1337       elif netstat -help 2>&1 | grep "\-p" >/dev/null; then | 
|  | 1338         #for full linux | 
|  | 1339         netstat -ntpl | grep ":$_port " | 
|  | 1340       else | 
|  | 1341         #for busybox (embedded linux; no pid support) | 
|  | 1342         netstat -ntl 2>/dev/null | grep ":$_port " | 
|  | 1343       fi | 
|  | 1344     fi | 
|  | 1345     return 0 | 
|  | 1346   fi | 
|  | 1347 | 
|  | 1348   return 1 | 
|  | 1349 } | 
|  | 1350 | 
|  | 1351 #outfile key cert cacert [password [name [caname]]] | 
|  | 1352 _toPkcs() { | 
|  | 1353   _cpfx="$1" | 
|  | 1354   _ckey="$2" | 
|  | 1355   _ccert="$3" | 
|  | 1356   _cca="$4" | 
|  | 1357   pfxPassword="$5" | 
|  | 1358   pfxName="$6" | 
|  | 1359   pfxCaname="$7" | 
|  | 1360 | 
|  | 1361   if [ "$pfxCaname" ]; then | 
|  | 1362     ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName" -caname "$pfxCaname" | 
|  | 1363   elif [ "$pfxName" ]; then | 
|  | 1364     ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName" | 
|  | 1365   elif [ "$pfxPassword" ]; then | 
|  | 1366     ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" | 
|  | 1367   else | 
|  | 1368     ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" | 
|  | 1369   fi | 
|  | 1370 | 
|  | 1371 } | 
|  | 1372 | 
|  | 1373 #domain [password] [isEcc] | 
|  | 1374 toPkcs() { | 
|  | 1375   domain="$1" | 
|  | 1376   pfxPassword="$2" | 
|  | 1377   if [ -z "$domain" ]; then | 
|  | 1378     _usage "Usage: $PROJECT_ENTRY --to-pkcs12 --domain <domain.tld> [--password <password>] [--ecc]" | 
|  | 1379     return 1 | 
|  | 1380   fi | 
|  | 1381 | 
|  | 1382   _isEcc="$3" | 
|  | 1383 | 
|  | 1384   _initpath "$domain" "$_isEcc" | 
|  | 1385 | 
|  | 1386   _toPkcs "$CERT_PFX_PATH" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$pfxPassword" | 
|  | 1387 | 
|  | 1388   if [ "$?" = "0" ]; then | 
|  | 1389     _info "Success, Pfx is exported to: $CERT_PFX_PATH" | 
|  | 1390   fi | 
|  | 1391 | 
|  | 1392 } | 
|  | 1393 | 
|  | 1394 #domain [isEcc] | 
|  | 1395 toPkcs8() { | 
|  | 1396   domain="$1" | 
|  | 1397 | 
|  | 1398   if [ -z "$domain" ]; then | 
|  | 1399     _usage "Usage: $PROJECT_ENTRY --to-pkcs8 --domain <domain.tld> [--ecc]" | 
|  | 1400     return 1 | 
|  | 1401   fi | 
|  | 1402 | 
|  | 1403   _isEcc="$2" | 
|  | 1404 | 
|  | 1405   _initpath "$domain" "$_isEcc" | 
|  | 1406 | 
|  | 1407   ${ACME_OPENSSL_BIN:-openssl} pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH" | 
|  | 1408 | 
|  | 1409   if [ "$?" = "0" ]; then | 
|  | 1410     _info "Success, $CERT_PKCS8_PATH" | 
|  | 1411   fi | 
|  | 1412 | 
|  | 1413 } | 
|  | 1414 | 
|  | 1415 #[2048] | 
|  | 1416 createAccountKey() { | 
|  | 1417   _info "Creating account key" | 
|  | 1418   if [ -z "$1" ]; then | 
|  | 1419     _usage "Usage: $PROJECT_ENTRY --create-account-key [--accountkeylength <bits>]" | 
|  | 1420     return | 
|  | 1421   fi | 
|  | 1422 | 
|  | 1423   length=$1 | 
|  | 1424   _create_account_key "$length" | 
|  | 1425 | 
|  | 1426 } | 
|  | 1427 | 
|  | 1428 _create_account_key() { | 
|  | 1429 | 
|  | 1430   length=$1 | 
|  | 1431 | 
|  | 1432   if [ -z "$length" ] || [ "$length" = "$NO_VALUE" ]; then | 
|  | 1433     _debug "Use default length $DEFAULT_ACCOUNT_KEY_LENGTH" | 
|  | 1434     length="$DEFAULT_ACCOUNT_KEY_LENGTH" | 
|  | 1435   fi | 
|  | 1436 | 
|  | 1437   _debug length "$length" | 
|  | 1438   _initpath | 
|  | 1439 | 
|  | 1440   mkdir -p "$CA_DIR" | 
|  | 1441   if [ -s "$ACCOUNT_KEY_PATH" ]; then | 
|  | 1442     _info "Account key exists, skip" | 
|  | 1443     return 0 | 
|  | 1444   else | 
|  | 1445     #generate account key | 
|  | 1446     if _createkey "$length" "$ACCOUNT_KEY_PATH"; then | 
|  | 1447       chmod 600 "$ACCOUNT_KEY_PATH" | 
|  | 1448       _info "Create account key ok." | 
|  | 1449       return 0 | 
|  | 1450     else | 
|  | 1451       _err "Create account key error." | 
|  | 1452       return 1 | 
|  | 1453     fi | 
|  | 1454   fi | 
|  | 1455 | 
|  | 1456 } | 
|  | 1457 | 
|  | 1458 #domain [length] | 
|  | 1459 createDomainKey() { | 
|  | 1460   _info "Creating domain key" | 
|  | 1461   if [ -z "$1" ]; then | 
|  | 1462     _usage "Usage: $PROJECT_ENTRY --create-domain-key --domain <domain.tld> [--keylength <bits>]" | 
|  | 1463     return | 
|  | 1464   fi | 
|  | 1465 | 
|  | 1466   domain=$1 | 
|  | 1467   _cdl=$2 | 
|  | 1468 | 
|  | 1469   if [ -z "$_cdl" ]; then | 
|  | 1470     _debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH" | 
|  | 1471     _cdl="$DEFAULT_DOMAIN_KEY_LENGTH" | 
|  | 1472   fi | 
|  | 1473 | 
|  | 1474   _initpath "$domain" "$_cdl" | 
|  | 1475 | 
|  | 1476   if [ ! -f "$CERT_KEY_PATH" ] || [ ! -s "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$_ACME_IS_RENEW" ]) || [ "$Le_ForceNewDomainKey" = "1" ]; then | 
|  | 1477     if _createkey "$_cdl" "$CERT_KEY_PATH"; then | 
|  | 1478       _savedomainconf Le_Keylength "$_cdl" | 
|  | 1479       _info "The domain key is here: $(__green $CERT_KEY_PATH)" | 
|  | 1480       return 0 | 
|  | 1481     else | 
|  | 1482       _err "Can not create domain key" | 
|  | 1483       return 1 | 
|  | 1484     fi | 
|  | 1485   else | 
|  | 1486     if [ "$_ACME_IS_RENEW" ]; then | 
|  | 1487       _info "Domain key exists, skip" | 
|  | 1488       return 0 | 
|  | 1489     else | 
|  | 1490       _err "Domain key exists, do you want to overwrite the key?" | 
|  | 1491       _err "Add '--force', and try again." | 
|  | 1492       return 1 | 
|  | 1493     fi | 
|  | 1494   fi | 
|  | 1495 | 
|  | 1496 } | 
|  | 1497 | 
|  | 1498 # domain  domainlist isEcc | 
|  | 1499 createCSR() { | 
|  | 1500   _info "Creating csr" | 
|  | 1501   if [ -z "$1" ]; then | 
|  | 1502     _usage "Usage: $PROJECT_ENTRY --create-csr --domain <domain.tld> [--domain <domain2.tld> ...]" | 
|  | 1503     return | 
|  | 1504   fi | 
|  | 1505 | 
|  | 1506   domain="$1" | 
|  | 1507   domainlist="$2" | 
|  | 1508   _isEcc="$3" | 
|  | 1509 | 
|  | 1510   _initpath "$domain" "$_isEcc" | 
|  | 1511 | 
|  | 1512   if [ -f "$CSR_PATH" ] && [ "$_ACME_IS_RENEW" ] && [ -z "$FORCE" ]; then | 
|  | 1513     _info "CSR exists, skip" | 
|  | 1514     return | 
|  | 1515   fi | 
|  | 1516 | 
|  | 1517   if [ ! -f "$CERT_KEY_PATH" ]; then | 
|  | 1518     _err "The key file is not found: $CERT_KEY_PATH" | 
|  | 1519     _err "Please create the key file first." | 
|  | 1520     return 1 | 
|  | 1521   fi | 
|  | 1522   _createcsr "$domain" "$domainlist" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" | 
|  | 1523 | 
|  | 1524 } | 
|  | 1525 | 
|  | 1526 _url_replace() { | 
|  | 1527   tr '/+' '_-' | tr -d '= ' | 
|  | 1528 } | 
|  | 1529 | 
|  | 1530 #base64 string | 
|  | 1531 _durl_replace_base64() { | 
|  | 1532   _l=$((${#1} % 4)) | 
|  | 1533   if [ $_l -eq 2 ]; then | 
|  | 1534     _s="$1"'==' | 
|  | 1535   elif [ $_l -eq 3 ]; then | 
|  | 1536     _s="$1"'=' | 
|  | 1537   else | 
|  | 1538     _s="$1" | 
|  | 1539   fi | 
|  | 1540   echo "$_s" | tr '_-' '/+' | 
|  | 1541 } | 
|  | 1542 | 
|  | 1543 _time2str() { | 
|  | 1544   #BSD | 
|  | 1545   if date -u -r "$1" 2>/dev/null; then | 
|  | 1546     return | 
|  | 1547   fi | 
|  | 1548 | 
|  | 1549   #Linux | 
|  | 1550   if date -u -d@"$1" 2>/dev/null; then | 
|  | 1551     return | 
|  | 1552   fi | 
|  | 1553 | 
|  | 1554   #Solaris | 
|  | 1555   if _exists adb; then | 
|  | 1556     _t_s_a=$(echo "0t${1}=Y" | adb) | 
|  | 1557     echo "$_t_s_a" | 
|  | 1558   fi | 
|  | 1559 | 
|  | 1560   #Busybox | 
|  | 1561   if echo "$1" | awk '{ print strftime("%c", $0); }' 2>/dev/null; then | 
|  | 1562     return | 
|  | 1563   fi | 
|  | 1564 } | 
|  | 1565 | 
|  | 1566 _normalizeJson() { | 
|  | 1567   sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n" | 
|  | 1568 } | 
|  | 1569 | 
|  | 1570 _stat() { | 
|  | 1571   #Linux | 
|  | 1572   if stat -c '%U:%G' "$1" 2>/dev/null; then | 
|  | 1573     return | 
|  | 1574   fi | 
|  | 1575 | 
|  | 1576   #BSD | 
|  | 1577   if stat -f '%Su:%Sg' "$1" 2>/dev/null; then | 
|  | 1578     return | 
|  | 1579   fi | 
|  | 1580 | 
|  | 1581   return 1 #error, 'stat' not found | 
|  | 1582 } | 
|  | 1583 | 
|  | 1584 #keyfile | 
|  | 1585 _calcjwk() { | 
|  | 1586   keyfile="$1" | 
|  | 1587   if [ -z "$keyfile" ]; then | 
|  | 1588     _usage "Usage: _calcjwk keyfile" | 
|  | 1589     return 1 | 
|  | 1590   fi | 
|  | 1591 | 
|  | 1592   if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ]; then | 
|  | 1593     _debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE" | 
|  | 1594     return 0 | 
|  | 1595   fi | 
|  | 1596 | 
|  | 1597   if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then | 
|  | 1598     _debug "RSA key" | 
|  | 1599     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) | 
|  | 1600     if [ "${#pub_exp}" = "5" ]; then | 
|  | 1601       pub_exp=0$pub_exp | 
|  | 1602     fi | 
|  | 1603     _debug3 pub_exp "$pub_exp" | 
|  | 1604 | 
|  | 1605     e=$(echo "$pub_exp" | _h2b | _base64) | 
|  | 1606     _debug3 e "$e" | 
|  | 1607 | 
|  | 1608     modulus=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) | 
|  | 1609     _debug3 modulus "$modulus" | 
|  | 1610     n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" | 
|  | 1611     _debug3 n "$n" | 
|  | 1612 | 
|  | 1613     jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' | 
|  | 1614     _debug3 jwk "$jwk" | 
|  | 1615 | 
|  | 1616     JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}' | 
|  | 1617     JWK_HEADERPLACE_PART1='{"nonce": "' | 
|  | 1618     JWK_HEADERPLACE_PART2='", "alg": "RS256"' | 
|  | 1619   elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then | 
|  | 1620     _debug "EC key" | 
|  | 1621     crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" | 
|  | 1622     _debug3 crv "$crv" | 
|  | 1623     __ECC_KEY_LEN=$(echo "$crv" | cut -d "-" -f 2) | 
|  | 1624     if [ "$__ECC_KEY_LEN" = "521" ]; then | 
|  | 1625       __ECC_KEY_LEN=512 | 
|  | 1626     fi | 
|  | 1627     _debug3 __ECC_KEY_LEN "$__ECC_KEY_LEN" | 
|  | 1628     if [ -z "$crv" ]; then | 
|  | 1629       _debug "Let's try ASN1 OID" | 
|  | 1630       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")" | 
|  | 1631       _debug3 crv_oid "$crv_oid" | 
|  | 1632       case "${crv_oid}" in | 
|  | 1633       "prime256v1") | 
|  | 1634         crv="P-256" | 
|  | 1635         __ECC_KEY_LEN=256 | 
|  | 1636         ;; | 
|  | 1637       "secp384r1") | 
|  | 1638         crv="P-384" | 
|  | 1639         __ECC_KEY_LEN=384 | 
|  | 1640         ;; | 
|  | 1641       "secp521r1") | 
|  | 1642         crv="P-521" | 
|  | 1643         __ECC_KEY_LEN=512 | 
|  | 1644         ;; | 
|  | 1645       *) | 
|  | 1646         _err "ECC oid : $crv_oid" | 
|  | 1647         return 1 | 
|  | 1648         ;; | 
|  | 1649       esac | 
|  | 1650       _debug3 crv "$crv" | 
|  | 1651     fi | 
|  | 1652 | 
|  | 1653     pubi="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" | 
|  | 1654     pubi=$(_math "$pubi" + 1) | 
|  | 1655     _debug3 pubi "$pubi" | 
|  | 1656 | 
|  | 1657     pubj="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" | 
|  | 1658     pubj=$(_math "$pubj" - 1) | 
|  | 1659     _debug3 pubj "$pubj" | 
|  | 1660 | 
|  | 1661     pubtext="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" | 
|  | 1662     _debug3 pubtext "$pubtext" | 
|  | 1663 | 
|  | 1664     xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" | 
|  | 1665     xlen=$(_math "$xlen" / 4) | 
|  | 1666     _debug3 xlen "$xlen" | 
|  | 1667 | 
|  | 1668     xend=$(_math "$xlen" + 1) | 
|  | 1669     x="$(printf "%s" "$pubtext" | cut -d : -f 2-"$xend")" | 
|  | 1670     _debug3 x "$x" | 
|  | 1671 | 
|  | 1672     x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _url_replace)" | 
|  | 1673     _debug3 x64 "$x64" | 
|  | 1674 | 
|  | 1675     xend=$(_math "$xend" + 1) | 
|  | 1676     y="$(printf "%s" "$pubtext" | cut -d : -f "$xend"-10000)" | 
|  | 1677     _debug3 y "$y" | 
|  | 1678 | 
|  | 1679     y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _url_replace)" | 
|  | 1680     _debug3 y64 "$y64" | 
|  | 1681 | 
|  | 1682     jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}' | 
|  | 1683     _debug3 jwk "$jwk" | 
|  | 1684 | 
|  | 1685     JWK_HEADER='{"alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' | 
|  | 1686     JWK_HEADERPLACE_PART1='{"nonce": "' | 
|  | 1687     JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"' | 
|  | 1688   else | 
|  | 1689     _err "Only RSA or EC key is supported. keyfile=$keyfile" | 
|  | 1690     _debug2 "$(cat "$keyfile")" | 
|  | 1691     return 1 | 
|  | 1692   fi | 
|  | 1693 | 
|  | 1694   _debug3 JWK_HEADER "$JWK_HEADER" | 
|  | 1695   __CACHED_JWK_KEY_FILE="$keyfile" | 
|  | 1696 } | 
|  | 1697 | 
|  | 1698 _time() { | 
|  | 1699   date -u "+%s" | 
|  | 1700 } | 
|  | 1701 | 
|  | 1702 _utc_date() { | 
|  | 1703   date -u "+%Y-%m-%d %H:%M:%S" | 
|  | 1704 } | 
|  | 1705 | 
|  | 1706 _mktemp() { | 
|  | 1707   if _exists mktemp; then | 
|  | 1708     if mktemp 2>/dev/null; then | 
|  | 1709       return 0 | 
|  | 1710     elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null; then | 
|  | 1711       #for Mac osx | 
|  | 1712       return 0 | 
|  | 1713     fi | 
|  | 1714   fi | 
|  | 1715   if [ -d "/tmp" ]; then | 
|  | 1716     echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp" | 
|  | 1717     return 0 | 
|  | 1718   elif [ "$LE_TEMP_DIR" ] && mkdir -p "$LE_TEMP_DIR"; then | 
|  | 1719     echo "/$LE_TEMP_DIR/wefADf24sf.$(_time).tmp" | 
|  | 1720     return 0 | 
|  | 1721   fi | 
|  | 1722   _err "Can not create temp file." | 
|  | 1723 } | 
|  | 1724 | 
|  | 1725 _inithttp() { | 
|  | 1726 | 
|  | 1727   if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER"; then | 
|  | 1728     HTTP_HEADER="$(_mktemp)" | 
|  | 1729     _debug2 HTTP_HEADER "$HTTP_HEADER" | 
|  | 1730   fi | 
|  | 1731 | 
|  | 1732   if [ "$__HTTP_INITIALIZED" ]; then | 
|  | 1733     if [ "$_ACME_CURL$_ACME_WGET" ]; then | 
|  | 1734       _debug2 "Http already initialized." | 
|  | 1735       return 0 | 
|  | 1736     fi | 
|  | 1737   fi | 
|  | 1738 | 
|  | 1739   if [ -z "$_ACME_CURL" ] && _exists "curl"; then | 
|  | 1740     _ACME_CURL="curl -L --silent --dump-header $HTTP_HEADER " | 
|  | 1741     if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then | 
|  | 1742       _CURL_DUMP="$(_mktemp)" | 
|  | 1743       _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " | 
|  | 1744     fi | 
|  | 1745 | 
|  | 1746     if [ "$CA_PATH" ]; then | 
|  | 1747       _ACME_CURL="$_ACME_CURL --capath $CA_PATH " | 
|  | 1748     elif [ "$CA_BUNDLE" ]; then | 
|  | 1749       _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE " | 
|  | 1750     fi | 
|  | 1751 | 
|  | 1752     if _contains "$(curl --help 2>&1)" "--globoff"; then | 
|  | 1753       _ACME_CURL="$_ACME_CURL -g " | 
|  | 1754     fi | 
|  | 1755   fi | 
|  | 1756 | 
|  | 1757   if [ -z "$_ACME_WGET" ] && _exists "wget"; then | 
|  | 1758     _ACME_WGET="wget -q" | 
|  | 1759     if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then | 
|  | 1760       _ACME_WGET="$_ACME_WGET -d " | 
|  | 1761     fi | 
|  | 1762     if [ "$CA_PATH" ]; then | 
|  | 1763       _ACME_WGET="$_ACME_WGET --ca-directory=$CA_PATH " | 
|  | 1764     elif [ "$CA_BUNDLE" ]; then | 
|  | 1765       _ACME_WGET="$_ACME_WGET --ca-certificate=$CA_BUNDLE " | 
|  | 1766     fi | 
|  | 1767   fi | 
|  | 1768 | 
|  | 1769   #from wget 1.14: do not skip body on 404 error | 
|  | 1770   if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help 2>&1)" "--content-on-error"; then | 
|  | 1771     _ACME_WGET="$_ACME_WGET --content-on-error " | 
|  | 1772   fi | 
|  | 1773 | 
|  | 1774   __HTTP_INITIALIZED=1 | 
|  | 1775 | 
|  | 1776 } | 
|  | 1777 | 
|  | 1778 # body  url [needbase64] [POST|PUT|DELETE] [ContentType] | 
|  | 1779 _post() { | 
|  | 1780   body="$1" | 
|  | 1781   _post_url="$2" | 
|  | 1782   needbase64="$3" | 
|  | 1783   httpmethod="$4" | 
|  | 1784   _postContentType="$5" | 
|  | 1785 | 
|  | 1786   if [ -z "$httpmethod" ]; then | 
|  | 1787     httpmethod="POST" | 
|  | 1788   fi | 
|  | 1789   _debug $httpmethod | 
|  | 1790   _debug "_post_url" "$_post_url" | 
|  | 1791   _debug2 "body" "$body" | 
|  | 1792   _debug2 "_postContentType" "$_postContentType" | 
|  | 1793 | 
|  | 1794   _inithttp | 
|  | 1795 | 
|  | 1796   if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then | 
|  | 1797     _CURL="$_ACME_CURL" | 
|  | 1798     if [ "$HTTPS_INSECURE" ]; then | 
|  | 1799       _CURL="$_CURL --insecure  " | 
|  | 1800     fi | 
|  | 1801     if [ "$httpmethod" = "HEAD" ]; then | 
|  | 1802       _CURL="$_CURL -I  " | 
|  | 1803     fi | 
|  | 1804     _debug "_CURL" "$_CURL" | 
|  | 1805     if [ "$needbase64" ]; then | 
|  | 1806       if [ "$body" ]; then | 
|  | 1807         if [ "$_postContentType" ]; then | 
|  | 1808           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)" | 
|  | 1809         else | 
|  | 1810           response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" | 
|  | 1811         fi | 
|  | 1812       else | 
|  | 1813         if [ "$_postContentType" ]; then | 
|  | 1814           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)" | 
|  | 1815         else | 
|  | 1816           response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)" | 
|  | 1817         fi | 
|  | 1818       fi | 
|  | 1819     else | 
|  | 1820       if [ "$body" ]; then | 
|  | 1821         if [ "$_postContentType" ]; then | 
|  | 1822           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")" | 
|  | 1823         else | 
|  | 1824           response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" | 
|  | 1825         fi | 
|  | 1826       else | 
|  | 1827         if [ "$_postContentType" ]; then | 
|  | 1828           response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")" | 
|  | 1829         else | 
|  | 1830           response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")" | 
|  | 1831         fi | 
|  | 1832       fi | 
|  | 1833     fi | 
|  | 1834     _ret="$?" | 
|  | 1835     if [ "$_ret" != "0" ]; then | 
|  | 1836       _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" | 
|  | 1837       if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then | 
|  | 1838         _err "Here is the curl dump log:" | 
|  | 1839         _err "$(cat "$_CURL_DUMP")" | 
|  | 1840       fi | 
|  | 1841     fi | 
|  | 1842   elif [ "$_ACME_WGET" ]; then | 
|  | 1843     _WGET="$_ACME_WGET" | 
|  | 1844     if [ "$HTTPS_INSECURE" ]; then | 
|  | 1845       _WGET="$_WGET --no-check-certificate " | 
|  | 1846     fi | 
|  | 1847     if [ "$httpmethod" = "HEAD" ]; then | 
|  | 1848       _WGET="$_WGET --read-timeout=3.0  --tries=2  " | 
|  | 1849     fi | 
|  | 1850     _debug "_WGET" "$_WGET" | 
|  | 1851     if [ "$needbase64" ]; then | 
|  | 1852       if [ "$httpmethod" = "POST" ]; then | 
|  | 1853         if [ "$_postContentType" ]; then | 
|  | 1854           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)" | 
|  | 1855         else | 
|  | 1856           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)" | 
|  | 1857         fi | 
|  | 1858       else | 
|  | 1859         if [ "$_postContentType" ]; then | 
|  | 1860           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)" | 
|  | 1861         else | 
|  | 1862           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)" | 
|  | 1863         fi | 
|  | 1864       fi | 
|  | 1865     else | 
|  | 1866       if [ "$httpmethod" = "POST" ]; then | 
|  | 1867         if [ "$_postContentType" ]; then | 
|  | 1868           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")" | 
|  | 1869         else | 
|  | 1870           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")" | 
|  | 1871         fi | 
|  | 1872       elif [ "$httpmethod" = "HEAD" ]; then | 
|  | 1873         if [ "$_postContentType" ]; then | 
|  | 1874           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")" | 
|  | 1875         else | 
|  | 1876           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")" | 
|  | 1877         fi | 
|  | 1878       else | 
|  | 1879         if [ "$_postContentType" ]; then | 
|  | 1880           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")" | 
|  | 1881         else | 
|  | 1882           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")" | 
|  | 1883         fi | 
|  | 1884       fi | 
|  | 1885     fi | 
|  | 1886     _ret="$?" | 
|  | 1887     if [ "$_ret" = "8" ]; then | 
|  | 1888       _ret=0 | 
|  | 1889       _debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later." | 
|  | 1890     fi | 
|  | 1891     if [ "$_ret" != "0" ]; then | 
|  | 1892       _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" | 
|  | 1893     fi | 
|  | 1894     _sed_i "s/^ *//g" "$HTTP_HEADER" | 
|  | 1895   else | 
|  | 1896     _ret="$?" | 
|  | 1897     _err "Neither curl nor wget is found, can not do $httpmethod." | 
|  | 1898   fi | 
|  | 1899   _debug "_ret" "$_ret" | 
|  | 1900   printf "%s" "$response" | 
|  | 1901   return $_ret | 
|  | 1902 } | 
|  | 1903 | 
|  | 1904 # url getheader timeout | 
|  | 1905 _get() { | 
|  | 1906   _debug GET | 
|  | 1907   url="$1" | 
|  | 1908   onlyheader="$2" | 
|  | 1909   t="$3" | 
|  | 1910   _debug url "$url" | 
|  | 1911   _debug "timeout=$t" | 
|  | 1912 | 
|  | 1913   _inithttp | 
|  | 1914 | 
|  | 1915   if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then | 
|  | 1916     _CURL="$_ACME_CURL" | 
|  | 1917     if [ "$HTTPS_INSECURE" ]; then | 
|  | 1918       _CURL="$_CURL --insecure  " | 
|  | 1919     fi | 
|  | 1920     if [ "$t" ]; then | 
|  | 1921       _CURL="$_CURL --connect-timeout $t" | 
|  | 1922     fi | 
|  | 1923     _debug "_CURL" "$_CURL" | 
|  | 1924     if [ "$onlyheader" ]; then | 
|  | 1925       $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" | 
|  | 1926     else | 
|  | 1927       $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" | 
|  | 1928     fi | 
|  | 1929     ret=$? | 
|  | 1930     if [ "$ret" != "0" ]; then | 
|  | 1931       _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret" | 
|  | 1932       if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then | 
|  | 1933         _err "Here is the curl dump log:" | 
|  | 1934         _err "$(cat "$_CURL_DUMP")" | 
|  | 1935       fi | 
|  | 1936     fi | 
|  | 1937   elif [ "$_ACME_WGET" ]; then | 
|  | 1938     _WGET="$_ACME_WGET" | 
|  | 1939     if [ "$HTTPS_INSECURE" ]; then | 
|  | 1940       _WGET="$_WGET --no-check-certificate " | 
|  | 1941     fi | 
|  | 1942     if [ "$t" ]; then | 
|  | 1943       _WGET="$_WGET --timeout=$t" | 
|  | 1944     fi | 
|  | 1945     _debug "_WGET" "$_WGET" | 
|  | 1946     if [ "$onlyheader" ]; then | 
|  | 1947       $_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' | 
|  | 1948     else | 
|  | 1949       $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - "$url" | 
|  | 1950     fi | 
|  | 1951     ret=$? | 
|  | 1952     if [ "$ret" = "8" ]; then | 
|  | 1953       ret=0 | 
|  | 1954       _debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later." | 
|  | 1955     fi | 
|  | 1956     if [ "$ret" != "0" ]; then | 
|  | 1957       _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret" | 
|  | 1958     fi | 
|  | 1959   else | 
|  | 1960     ret=$? | 
|  | 1961     _err "Neither curl nor wget is found, can not do GET." | 
|  | 1962   fi | 
|  | 1963   _debug "ret" "$ret" | 
|  | 1964   return $ret | 
|  | 1965 } | 
|  | 1966 | 
|  | 1967 _head_n() { | 
|  | 1968   head -n "$1" | 
|  | 1969 } | 
|  | 1970 | 
|  | 1971 _tail_n() { | 
|  | 1972   if ! tail -n "$1" 2>/dev/null; then | 
|  | 1973     #fix for solaris | 
|  | 1974     tail -"$1" | 
|  | 1975   fi | 
|  | 1976 } | 
|  | 1977 | 
|  | 1978 # url  payload needbase64  keyfile | 
|  | 1979 _send_signed_request() { | 
|  | 1980   url=$1 | 
|  | 1981   payload=$2 | 
|  | 1982   needbase64=$3 | 
|  | 1983   keyfile=$4 | 
|  | 1984   if [ -z "$keyfile" ]; then | 
|  | 1985     keyfile="$ACCOUNT_KEY_PATH" | 
|  | 1986   fi | 
|  | 1987   _debug url "$url" | 
|  | 1988   _debug payload "$payload" | 
|  | 1989 | 
|  | 1990   if ! _calcjwk "$keyfile"; then | 
|  | 1991     return 1 | 
|  | 1992   fi | 
|  | 1993 | 
|  | 1994   __request_conent_type="$CONTENT_TYPE_JSON" | 
|  | 1995 | 
|  | 1996   payload64=$(printf "%s" "$payload" | _base64 | _url_replace) | 
|  | 1997   _debug3 payload64 "$payload64" | 
|  | 1998 | 
|  | 1999   MAX_REQUEST_RETRY_TIMES=20 | 
|  | 2000   _sleep_retry_sec=1 | 
|  | 2001   _request_retry_times=0 | 
|  | 2002   while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do | 
|  | 2003     _request_retry_times=$(_math "$_request_retry_times" + 1) | 
|  | 2004     _debug3 _request_retry_times "$_request_retry_times" | 
|  | 2005     if [ -z "$_CACHED_NONCE" ]; then | 
|  | 2006       _headers="" | 
|  | 2007       if [ "$ACME_NEW_NONCE" ]; then | 
|  | 2008         _debug2 "Get nonce with HEAD. ACME_NEW_NONCE" "$ACME_NEW_NONCE" | 
|  | 2009         nonceurl="$ACME_NEW_NONCE" | 
|  | 2010         if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type" >/dev/null; then | 
|  | 2011           _headers="$(cat "$HTTP_HEADER")" | 
|  | 2012           _debug2 _headers "$_headers" | 
|  | 2013           _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" | 
|  | 2014         fi | 
|  | 2015       fi | 
|  | 2016       if [ -z "$_CACHED_NONCE" ]; then | 
|  | 2017         _debug2 "Get nonce with GET. ACME_DIRECTORY" "$ACME_DIRECTORY" | 
|  | 2018         nonceurl="$ACME_DIRECTORY" | 
|  | 2019         _headers="$(_get "$nonceurl" "onlyheader")" | 
|  | 2020         _debug2 _headers "$_headers" | 
|  | 2021         _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" | 
|  | 2022       fi | 
|  | 2023       if [ -z "$_CACHED_NONCE" ] && [ "$ACME_NEW_NONCE" ]; then | 
|  | 2024         _debug2 "Get nonce with GET. ACME_NEW_NONCE" "$ACME_NEW_NONCE" | 
|  | 2025         nonceurl="$ACME_NEW_NONCE" | 
|  | 2026         _headers="$(_get "$nonceurl" "onlyheader")" | 
|  | 2027         _debug2 _headers "$_headers" | 
|  | 2028         _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" | 
|  | 2029       fi | 
|  | 2030       _debug2 _CACHED_NONCE "$_CACHED_NONCE" | 
|  | 2031       if [ "$?" != "0" ]; then | 
|  | 2032         _err "Can not connect to $nonceurl to get nonce." | 
|  | 2033         return 1 | 
|  | 2034       fi | 
|  | 2035     else | 
|  | 2036       _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE" | 
|  | 2037     fi | 
|  | 2038     nonce="$_CACHED_NONCE" | 
|  | 2039     _debug2 nonce "$nonce" | 
|  | 2040     if [ -z "$nonce" ]; then | 
|  | 2041       _info "Could not get nonce, let's try again." | 
|  | 2042       _sleep 2 | 
|  | 2043       continue | 
|  | 2044     fi | 
|  | 2045     if [ "$ACME_VERSION" = "2" ]; then | 
|  | 2046       if [ "$url" = "$ACME_NEW_ACCOUNT" ]; then | 
|  | 2047         protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' | 
|  | 2048       elif [ "$url" = "$ACME_REVOKE_CERT" ] && [ "$keyfile" != "$ACCOUNT_KEY_PATH" ]; then | 
|  | 2049         protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' | 
|  | 2050       else | 
|  | 2051         protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"kid\": \"${ACCOUNT_URL}\""'}' | 
|  | 2052       fi | 
|  | 2053     else | 
|  | 2054       protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' | 
|  | 2055     fi | 
|  | 2056     _debug3 protected "$protected" | 
|  | 2057 | 
|  | 2058     protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" | 
|  | 2059     _debug3 protected64 "$protected64" | 
|  | 2060 | 
|  | 2061     if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then | 
|  | 2062       _err "Sign request failed." | 
|  | 2063       return 1 | 
|  | 2064     fi | 
|  | 2065     _debug3 _sig_t "$_sig_t" | 
|  | 2066 | 
|  | 2067     sig="$(printf "%s" "$_sig_t" | _url_replace)" | 
|  | 2068     _debug3 sig "$sig" | 
|  | 2069 | 
|  | 2070     body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" | 
|  | 2071     _debug3 body "$body" | 
|  | 2072 | 
|  | 2073     response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")" | 
|  | 2074     _CACHED_NONCE="" | 
|  | 2075 | 
|  | 2076     if [ "$?" != "0" ]; then | 
|  | 2077       _err "Can not post to $url" | 
|  | 2078       return 1 | 
|  | 2079     fi | 
|  | 2080 | 
|  | 2081     responseHeaders="$(cat "$HTTP_HEADER")" | 
|  | 2082     _debug2 responseHeaders "$responseHeaders" | 
|  | 2083 | 
|  | 2084     code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" | 
|  | 2085     _debug code "$code" | 
|  | 2086 | 
|  | 2087     _debug2 original "$response" | 
|  | 2088     if echo "$responseHeaders" | grep -i "Content-Type: *application/json" >/dev/null 2>&1; then | 
|  | 2089       response="$(echo "$response" | _normalizeJson | _json_decode)" | 
|  | 2090     fi | 
|  | 2091     _debug2 response "$response" | 
|  | 2092 | 
|  | 2093     _CACHED_NONCE="$(echo "$responseHeaders" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" | 
|  | 2094 | 
|  | 2095     if ! _startswith "$code" "2"; then | 
|  | 2096       _body="$response" | 
|  | 2097       if [ "$needbase64" ]; then | 
|  | 2098         _body="$(echo "$_body" | _dbase64 multiline)" | 
|  | 2099         _debug3 _body "$_body" | 
|  | 2100       fi | 
|  | 2101 | 
|  | 2102       if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then | 
|  | 2103         _info "It seems the CA server is busy now, let's wait and retry. Sleeping $_sleep_retry_sec seconds." | 
|  | 2104         _CACHED_NONCE="" | 
|  | 2105         _sleep $_sleep_retry_sec | 
|  | 2106         continue | 
|  | 2107       fi | 
|  | 2108     fi | 
|  | 2109     return 0 | 
|  | 2110   done | 
|  | 2111   _info "Giving up sending to CA server after $MAX_REQUEST_RETRY_TIMES retries." | 
|  | 2112   return 1 | 
|  | 2113 | 
|  | 2114 } | 
|  | 2115 | 
|  | 2116 #setopt "file"  "opt"  "="  "value" [";"] | 
|  | 2117 _setopt() { | 
|  | 2118   __conf="$1" | 
|  | 2119   __opt="$2" | 
|  | 2120   __sep="$3" | 
|  | 2121   __val="$4" | 
|  | 2122   __end="$5" | 
|  | 2123   if [ -z "$__opt" ]; then | 
|  | 2124     _usage usage: _setopt '"file"  "opt"  "="  "value" [";"]' | 
|  | 2125     return | 
|  | 2126   fi | 
|  | 2127   if [ ! -f "$__conf" ]; then | 
|  | 2128     touch "$__conf" | 
|  | 2129   fi | 
|  | 2130 | 
|  | 2131   if grep -n "^$__opt$__sep" "$__conf" >/dev/null; then | 
|  | 2132     _debug3 OK | 
|  | 2133     if _contains "$__val" "&"; then | 
|  | 2134       __val="$(echo "$__val" | sed 's/&/\\&/g')" | 
|  | 2135     fi | 
|  | 2136     text="$(cat "$__conf")" | 
|  | 2137     printf -- "%s\n" "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" | 
|  | 2138 | 
|  | 2139   elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then | 
|  | 2140     if _contains "$__val" "&"; then | 
|  | 2141       __val="$(echo "$__val" | sed 's/&/\\&/g')" | 
|  | 2142     fi | 
|  | 2143     text="$(cat "$__conf")" | 
|  | 2144     printf -- "%s\n" "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" | 
|  | 2145 | 
|  | 2146   else | 
|  | 2147     _debug3 APP | 
|  | 2148     echo "$__opt$__sep$__val$__end" >>"$__conf" | 
|  | 2149   fi | 
|  | 2150   _debug3 "$(grep -n "^$__opt$__sep" "$__conf")" | 
|  | 2151 } | 
|  | 2152 | 
|  | 2153 #_save_conf  file key  value base64encode | 
|  | 2154 #save to conf | 
|  | 2155 _save_conf() { | 
|  | 2156   _s_c_f="$1" | 
|  | 2157   _sdkey="$2" | 
|  | 2158   _sdvalue="$3" | 
|  | 2159   _b64encode="$4" | 
|  | 2160   if [ "$_sdvalue" ] && [ "$_b64encode" ]; then | 
|  | 2161     _sdvalue="${B64CONF_START}$(printf "%s" "${_sdvalue}" | _base64)${B64CONF_END}" | 
|  | 2162   fi | 
|  | 2163   if [ "$_s_c_f" ]; then | 
|  | 2164     _setopt "$_s_c_f" "$_sdkey" "=" "'$_sdvalue'" | 
|  | 2165   else | 
|  | 2166     _err "config file is empty, can not save $_sdkey=$_sdvalue" | 
|  | 2167   fi | 
|  | 2168 } | 
|  | 2169 | 
|  | 2170 #_clear_conf file  key | 
|  | 2171 _clear_conf() { | 
|  | 2172   _c_c_f="$1" | 
|  | 2173   _sdkey="$2" | 
|  | 2174   if [ "$_c_c_f" ]; then | 
|  | 2175     _conf_data="$(cat "$_c_c_f")" | 
|  | 2176     echo "$_conf_data" | sed "s/^$_sdkey *=.*$//" >"$_c_c_f" | 
|  | 2177   else | 
|  | 2178     _err "config file is empty, can not clear" | 
|  | 2179   fi | 
|  | 2180 } | 
|  | 2181 | 
|  | 2182 #_read_conf file  key | 
|  | 2183 _read_conf() { | 
|  | 2184   _r_c_f="$1" | 
|  | 2185   _sdkey="$2" | 
|  | 2186   if [ -f "$_r_c_f" ]; then | 
|  | 2187     _sdv="$( | 
|  | 2188       eval "$(grep "^$_sdkey *=" "$_r_c_f")" | 
|  | 2189       eval "printf \"%s\" \"\$$_sdkey\"" | 
|  | 2190     )" | 
|  | 2191     if _startswith "$_sdv" "${B64CONF_START}" && _endswith "$_sdv" "${B64CONF_END}"; then | 
|  | 2192       _sdv="$(echo "$_sdv" | sed "s/${B64CONF_START}//" | sed "s/${B64CONF_END}//" | _dbase64)" | 
|  | 2193     fi | 
|  | 2194     printf "%s" "$_sdv" | 
|  | 2195   else | 
|  | 2196     _debug "config file is empty, can not read $_sdkey" | 
|  | 2197   fi | 
|  | 2198 } | 
|  | 2199 | 
|  | 2200 #_savedomainconf   key  value  base64encode | 
|  | 2201 #save to domain.conf | 
|  | 2202 _savedomainconf() { | 
|  | 2203   _save_conf "$DOMAIN_CONF" "$@" | 
|  | 2204 } | 
|  | 2205 | 
|  | 2206 #_cleardomainconf   key | 
|  | 2207 _cleardomainconf() { | 
|  | 2208   _clear_conf "$DOMAIN_CONF" "$1" | 
|  | 2209 } | 
|  | 2210 | 
|  | 2211 #_readdomainconf   key | 
|  | 2212 _readdomainconf() { | 
|  | 2213   _read_conf "$DOMAIN_CONF" "$1" | 
|  | 2214 } | 
|  | 2215 | 
|  | 2216 #key  value  base64encode | 
|  | 2217 _savedeployconf() { | 
|  | 2218   _savedomainconf "SAVED_$1" "$2" "$3" | 
|  | 2219   #remove later | 
|  | 2220   _cleardomainconf "$1" | 
|  | 2221 } | 
|  | 2222 | 
|  | 2223 #key | 
|  | 2224 _getdeployconf() { | 
|  | 2225   _rac_key="$1" | 
|  | 2226   _rac_value="$(eval echo \$"$_rac_key")" | 
|  | 2227   if [ "$_rac_value" ]; then | 
|  | 2228     if _startswith "$_rac_value" '"' && _endswith "$_rac_value" '"'; then | 
|  | 2229       _debug2 "trim quotation marks" | 
|  | 2230       eval "export $_rac_key=$_rac_value" | 
|  | 2231     fi | 
|  | 2232     return 0 # do nothing | 
|  | 2233   fi | 
|  | 2234   _saved=$(_readdomainconf "SAVED_$_rac_key") | 
|  | 2235   eval "export $_rac_key=\"$_saved\"" | 
|  | 2236 } | 
|  | 2237 | 
|  | 2238 #_saveaccountconf  key  value  base64encode | 
|  | 2239 _saveaccountconf() { | 
|  | 2240   _save_conf "$ACCOUNT_CONF_PATH" "$@" | 
|  | 2241 } | 
|  | 2242 | 
|  | 2243 #key  value base64encode | 
|  | 2244 _saveaccountconf_mutable() { | 
|  | 2245   _save_conf "$ACCOUNT_CONF_PATH" "SAVED_$1" "$2" "$3" | 
|  | 2246   #remove later | 
|  | 2247   _clearaccountconf "$1" | 
|  | 2248 } | 
|  | 2249 | 
|  | 2250 #key | 
|  | 2251 _readaccountconf() { | 
|  | 2252   _read_conf "$ACCOUNT_CONF_PATH" "$1" | 
|  | 2253 } | 
|  | 2254 | 
|  | 2255 #key | 
|  | 2256 _readaccountconf_mutable() { | 
|  | 2257   _rac_key="$1" | 
|  | 2258   _readaccountconf "SAVED_$_rac_key" | 
|  | 2259 } | 
|  | 2260 | 
|  | 2261 #_clearaccountconf   key | 
|  | 2262 _clearaccountconf() { | 
|  | 2263   _clear_conf "$ACCOUNT_CONF_PATH" "$1" | 
|  | 2264 } | 
|  | 2265 | 
|  | 2266 #_savecaconf  key  value | 
|  | 2267 _savecaconf() { | 
|  | 2268   _save_conf "$CA_CONF" "$1" "$2" | 
|  | 2269 } | 
|  | 2270 | 
|  | 2271 #_readcaconf   key | 
|  | 2272 _readcaconf() { | 
|  | 2273   _read_conf "$CA_CONF" "$1" | 
|  | 2274 } | 
|  | 2275 | 
|  | 2276 #_clearaccountconf   key | 
|  | 2277 _clearcaconf() { | 
|  | 2278   _clear_conf "$CA_CONF" "$1" | 
|  | 2279 } | 
|  | 2280 | 
|  | 2281 # content localaddress | 
|  | 2282 _startserver() { | 
|  | 2283   content="$1" | 
|  | 2284   ncaddr="$2" | 
|  | 2285   _debug "content" "$content" | 
|  | 2286   _debug "ncaddr" "$ncaddr" | 
|  | 2287 | 
|  | 2288   _debug "startserver: $$" | 
|  | 2289 | 
|  | 2290   _debug Le_HTTPPort "$Le_HTTPPort" | 
|  | 2291   _debug Le_Listen_V4 "$Le_Listen_V4" | 
|  | 2292   _debug Le_Listen_V6 "$Le_Listen_V6" | 
|  | 2293 | 
|  | 2294   _NC="socat" | 
|  | 2295   if [ "$Le_Listen_V4" ]; then | 
|  | 2296     _NC="$_NC -4" | 
|  | 2297   elif [ "$Le_Listen_V6" ]; then | 
|  | 2298     _NC="$_NC -6" | 
|  | 2299   fi | 
|  | 2300 | 
|  | 2301   if [ "$DEBUG" ] && [ "$DEBUG" -gt "1" ]; then | 
|  | 2302     _NC="$_NC -d -d -v" | 
|  | 2303   fi | 
|  | 2304 | 
|  | 2305   SOCAT_OPTIONS=TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork | 
|  | 2306 | 
|  | 2307   #Adding bind to local-address | 
|  | 2308   if [ "$ncaddr" ]; then | 
|  | 2309     SOCAT_OPTIONS="$SOCAT_OPTIONS,bind=${ncaddr}" | 
|  | 2310   fi | 
|  | 2311 | 
|  | 2312   _content_len="$(printf "%s" "$content" | wc -c)" | 
|  | 2313   _debug _content_len "$_content_len" | 
|  | 2314   _debug "_NC" "$_NC $SOCAT_OPTIONS" | 
|  | 2315   $_NC $SOCAT_OPTIONS SYSTEM:"sleep 1; \ | 
|  | 2316 echo 'HTTP/1.0 200 OK'; \ | 
|  | 2317 echo 'Content-Length\: $_content_len'; \ | 
|  | 2318 echo ''; \ | 
|  | 2319 printf -- '$content';" & | 
|  | 2320   serverproc="$!" | 
|  | 2321 } | 
|  | 2322 | 
|  | 2323 _stopserver() { | 
|  | 2324   pid="$1" | 
|  | 2325   _debug "pid" "$pid" | 
|  | 2326   if [ -z "$pid" ]; then | 
|  | 2327     return | 
|  | 2328   fi | 
|  | 2329 | 
|  | 2330   kill $pid | 
|  | 2331 | 
|  | 2332 } | 
|  | 2333 | 
|  | 2334 # sleep sec | 
|  | 2335 _sleep() { | 
|  | 2336   _sleep_sec="$1" | 
|  | 2337   if [ "$__INTERACTIVE" ]; then | 
|  | 2338     _sleep_c="$_sleep_sec" | 
|  | 2339     while [ "$_sleep_c" -ge "0" ]; do | 
|  | 2340       printf "\r      \r" | 
|  | 2341       __green "$_sleep_c" | 
|  | 2342       _sleep_c="$(_math "$_sleep_c" - 1)" | 
|  | 2343       sleep 1 | 
|  | 2344     done | 
|  | 2345     printf "\r" | 
|  | 2346   else | 
|  | 2347     sleep "$_sleep_sec" | 
|  | 2348   fi | 
|  | 2349 } | 
|  | 2350 | 
|  | 2351 # _starttlsserver  san_a  san_b port content _ncaddr acmeValidationv1 | 
|  | 2352 _starttlsserver() { | 
|  | 2353   _info "Starting tls server." | 
|  | 2354   san_a="$1" | 
|  | 2355   san_b="$2" | 
|  | 2356   port="$3" | 
|  | 2357   content="$4" | 
|  | 2358   opaddr="$5" | 
|  | 2359   acmeValidationv1="$6" | 
|  | 2360 | 
|  | 2361   _debug san_a "$san_a" | 
|  | 2362   _debug san_b "$san_b" | 
|  | 2363   _debug port "$port" | 
|  | 2364   _debug acmeValidationv1 "$acmeValidationv1" | 
|  | 2365 | 
|  | 2366   #create key TLS_KEY | 
|  | 2367   if ! _createkey "2048" "$TLS_KEY"; then | 
|  | 2368     _err "Create tls validation key error." | 
|  | 2369     return 1 | 
|  | 2370   fi | 
|  | 2371 | 
|  | 2372   #create csr | 
|  | 2373   alt="$san_a" | 
|  | 2374   if [ "$san_b" ]; then | 
|  | 2375     alt="$alt,$san_b" | 
|  | 2376   fi | 
|  | 2377   if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$acmeValidationv1"; then | 
|  | 2378     _err "Create tls validation csr error." | 
|  | 2379     return 1 | 
|  | 2380   fi | 
|  | 2381 | 
|  | 2382   #self signed | 
|  | 2383   if ! _signcsr "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$TLS_CERT"; then | 
|  | 2384     _err "Create tls validation cert error." | 
|  | 2385     return 1 | 
|  | 2386   fi | 
|  | 2387 | 
|  | 2388   __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -www -cert $TLS_CERT  -key $TLS_KEY " | 
|  | 2389   if [ "$opaddr" ]; then | 
|  | 2390     __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" | 
|  | 2391   else | 
|  | 2392     __S_OPENSSL="$__S_OPENSSL -accept $port" | 
|  | 2393   fi | 
|  | 2394 | 
|  | 2395   _debug Le_Listen_V4 "$Le_Listen_V4" | 
|  | 2396   _debug Le_Listen_V6 "$Le_Listen_V6" | 
|  | 2397   if [ "$Le_Listen_V4" ]; then | 
|  | 2398     __S_OPENSSL="$__S_OPENSSL -4" | 
|  | 2399   elif [ "$Le_Listen_V6" ]; then | 
|  | 2400     __S_OPENSSL="$__S_OPENSSL -6" | 
|  | 2401   fi | 
|  | 2402 | 
|  | 2403   if [ "$acmeValidationv1" ]; then | 
|  | 2404     __S_OPENSSL="$__S_OPENSSL -alpn acme-tls/1" | 
|  | 2405   fi | 
|  | 2406 | 
|  | 2407   _debug "$__S_OPENSSL" | 
|  | 2408   if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then | 
|  | 2409     $__S_OPENSSL -tlsextdebug & | 
|  | 2410   else | 
|  | 2411     $__S_OPENSSL >/dev/null 2>&1 & | 
|  | 2412   fi | 
|  | 2413 | 
|  | 2414   serverproc="$!" | 
|  | 2415   sleep 1 | 
|  | 2416   _debug serverproc "$serverproc" | 
|  | 2417 } | 
|  | 2418 | 
|  | 2419 #file | 
|  | 2420 _readlink() { | 
|  | 2421   _rf="$1" | 
|  | 2422   if ! readlink -f "$_rf" 2>/dev/null; then | 
|  | 2423     if _startswith "$_rf" "/"; then | 
|  | 2424       echo "$_rf" | 
|  | 2425       return 0 | 
|  | 2426     fi | 
|  | 2427     echo "$(pwd)/$_rf" | _conapath | 
|  | 2428   fi | 
|  | 2429 } | 
|  | 2430 | 
|  | 2431 _conapath() { | 
|  | 2432   sed "s#/\./#/#g" | 
|  | 2433 } | 
|  | 2434 | 
|  | 2435 __initHome() { | 
|  | 2436   if [ -z "$_SCRIPT_HOME" ]; then | 
|  | 2437     if _exists readlink && _exists dirname; then | 
|  | 2438       _debug "Lets find script dir." | 
|  | 2439       _debug "_SCRIPT_" "$_SCRIPT_" | 
|  | 2440       _script="$(_readlink "$_SCRIPT_")" | 
|  | 2441       _debug "_script" "$_script" | 
|  | 2442       _script_home="$(dirname "$_script")" | 
|  | 2443       _debug "_script_home" "$_script_home" | 
|  | 2444       if [ -d "$_script_home" ]; then | 
|  | 2445         _SCRIPT_HOME="$_script_home" | 
|  | 2446       else | 
|  | 2447         _err "It seems the script home is not correct:$_script_home" | 
|  | 2448       fi | 
|  | 2449     fi | 
|  | 2450   fi | 
|  | 2451 | 
|  | 2452   #  if [ -z "$LE_WORKING_DIR" ]; then | 
|  | 2453   #    if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then | 
|  | 2454   #      _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" | 
|  | 2455   #      LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" | 
|  | 2456   #    else | 
|  | 2457   #      LE_WORKING_DIR="$_SCRIPT_HOME" | 
|  | 2458   #    fi | 
|  | 2459   #  fi | 
|  | 2460 | 
|  | 2461   if [ -z "$LE_WORKING_DIR" ]; then | 
|  | 2462     _debug "Using default home:$DEFAULT_INSTALL_HOME" | 
|  | 2463     LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" | 
|  | 2464   fi | 
|  | 2465   export LE_WORKING_DIR | 
|  | 2466 | 
|  | 2467   if [ -z "$LE_CONFIG_HOME" ]; then | 
|  | 2468     LE_CONFIG_HOME="$LE_WORKING_DIR" | 
|  | 2469   fi | 
|  | 2470   _debug "Using config home:$LE_CONFIG_HOME" | 
|  | 2471   export LE_CONFIG_HOME | 
|  | 2472 | 
|  | 2473   _DEFAULT_ACCOUNT_CONF_PATH="$LE_CONFIG_HOME/account.conf" | 
|  | 2474 | 
|  | 2475   if [ -z "$ACCOUNT_CONF_PATH" ]; then | 
|  | 2476     if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]; then | 
|  | 2477       . "$_DEFAULT_ACCOUNT_CONF_PATH" | 
|  | 2478     fi | 
|  | 2479   fi | 
|  | 2480 | 
|  | 2481   if [ -z "$ACCOUNT_CONF_PATH" ]; then | 
|  | 2482     ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH" | 
|  | 2483   fi | 
|  | 2484   _debug3 ACCOUNT_CONF_PATH "$ACCOUNT_CONF_PATH" | 
|  | 2485   DEFAULT_LOG_FILE="$LE_CONFIG_HOME/$PROJECT_NAME.log" | 
|  | 2486 | 
|  | 2487   DEFAULT_CA_HOME="$LE_CONFIG_HOME/ca" | 
|  | 2488 | 
|  | 2489   if [ -z "$LE_TEMP_DIR" ]; then | 
|  | 2490     LE_TEMP_DIR="$LE_CONFIG_HOME/tmp" | 
|  | 2491   fi | 
|  | 2492 } | 
|  | 2493 | 
|  | 2494 #server | 
|  | 2495 _initAPI() { | 
|  | 2496   _api_server="${1:-$ACME_DIRECTORY}" | 
|  | 2497   _debug "_init api for server: $_api_server" | 
|  | 2498 | 
|  | 2499   if [ -z "$ACME_NEW_ACCOUNT" ]; then | 
|  | 2500     response=$(_get "$_api_server") | 
|  | 2501     if [ "$?" != "0" ]; then | 
|  | 2502       _debug2 "response" "$response" | 
|  | 2503       _err "Can not init api." | 
|  | 2504       return 1 | 
|  | 2505     fi | 
|  | 2506     response=$(echo "$response" | _json_decode) | 
|  | 2507     _debug2 "response" "$response" | 
|  | 2508 | 
|  | 2509     ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2510     if [ -z "$ACME_KEY_CHANGE" ]; then | 
|  | 2511       ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'keyChange" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2512     fi | 
|  | 2513     export ACME_KEY_CHANGE | 
|  | 2514 | 
|  | 2515     ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2516     if [ -z "$ACME_NEW_AUTHZ" ]; then | 
|  | 2517       ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'newAuthz" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2518     fi | 
|  | 2519     export ACME_NEW_AUTHZ | 
|  | 2520 | 
|  | 2521     ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2522     ACME_NEW_ORDER_RES="new-cert" | 
|  | 2523     if [ -z "$ACME_NEW_ORDER" ]; then | 
|  | 2524       ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2525       ACME_NEW_ORDER_RES="new-order" | 
|  | 2526       if [ -z "$ACME_NEW_ORDER" ]; then | 
|  | 2527         ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'newOrder" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2528       fi | 
|  | 2529     fi | 
|  | 2530     export ACME_NEW_ORDER | 
|  | 2531     export ACME_NEW_ORDER_RES | 
|  | 2532 | 
|  | 2533     ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2534     ACME_NEW_ACCOUNT_RES="new-reg" | 
|  | 2535     if [ -z "$ACME_NEW_ACCOUNT" ]; then | 
|  | 2536       ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2537       ACME_NEW_ACCOUNT_RES="new-account" | 
|  | 2538       if [ -z "$ACME_NEW_ACCOUNT" ]; then | 
|  | 2539         ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'newAccount" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2540         if [ "$ACME_NEW_ACCOUNT" ]; then | 
|  | 2541           export ACME_VERSION=2 | 
|  | 2542         fi | 
|  | 2543       fi | 
|  | 2544     fi | 
|  | 2545     export ACME_NEW_ACCOUNT | 
|  | 2546     export ACME_NEW_ACCOUNT_RES | 
|  | 2547 | 
|  | 2548     ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2549     if [ -z "$ACME_REVOKE_CERT" ]; then | 
|  | 2550       ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revokeCert" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2551     fi | 
|  | 2552     export ACME_REVOKE_CERT | 
|  | 2553 | 
|  | 2554     ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2555     if [ -z "$ACME_NEW_NONCE" ]; then | 
|  | 2556       ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'newNonce" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2557     fi | 
|  | 2558     export ACME_NEW_NONCE | 
|  | 2559 | 
|  | 2560     ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2561     if [ -z "$ACME_AGREEMENT" ]; then | 
|  | 2562       ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3) | 
|  | 2563     fi | 
|  | 2564     export ACME_AGREEMENT | 
|  | 2565 | 
|  | 2566     _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" | 
|  | 2567     _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" | 
|  | 2568     _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" | 
|  | 2569     _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" | 
|  | 2570     _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" | 
|  | 2571     _debug "ACME_AGREEMENT" "$ACME_AGREEMENT" | 
|  | 2572     _debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE" | 
|  | 2573     _debug "ACME_VERSION" "$ACME_VERSION" | 
|  | 2574 | 
|  | 2575   fi | 
|  | 2576 } | 
|  | 2577 | 
|  | 2578 #[domain]  [keylength or isEcc flag] | 
|  | 2579 _initpath() { | 
|  | 2580   domain="$1" | 
|  | 2581   _ilength="$2" | 
|  | 2582 | 
|  | 2583   __initHome | 
|  | 2584 | 
|  | 2585   if [ -f "$ACCOUNT_CONF_PATH" ]; then | 
|  | 2586     . "$ACCOUNT_CONF_PATH" | 
|  | 2587   fi | 
|  | 2588 | 
|  | 2589   if [ "$_ACME_IN_CRON" ]; then | 
|  | 2590     if [ ! "$_USER_PATH_EXPORTED" ]; then | 
|  | 2591       _USER_PATH_EXPORTED=1 | 
|  | 2592       export PATH="$USER_PATH:$PATH" | 
|  | 2593     fi | 
|  | 2594   fi | 
|  | 2595 | 
|  | 2596   if [ -z "$CA_HOME" ]; then | 
|  | 2597     CA_HOME="$DEFAULT_CA_HOME" | 
|  | 2598   fi | 
|  | 2599 | 
|  | 2600   if [ -z "$ACME_DIRECTORY" ]; then | 
|  | 2601     if [ "$STAGE" ]; then | 
|  | 2602       ACME_DIRECTORY="$DEFAULT_STAGING_CA" | 
|  | 2603       _info "Using ACME_DIRECTORY: $ACME_DIRECTORY" | 
|  | 2604     else | 
|  | 2605       default_acme_server=$(_readaccountconf "DEFAULT_ACME_SERVER") | 
|  | 2606       _debug default_acme_server "$default_acme_server" | 
|  | 2607       if [ "$default_acme_server" ]; then | 
|  | 2608         ACME_DIRECTORY="$default_acme_server" | 
|  | 2609       else | 
|  | 2610         ACME_DIRECTORY="$DEFAULT_CA" | 
|  | 2611       fi | 
|  | 2612     fi | 
|  | 2613   fi | 
|  | 2614 | 
|  | 2615   _debug ACME_DIRECTORY "$ACME_DIRECTORY" | 
|  | 2616   _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)" | 
|  | 2617   _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" | 
|  | 2618 | 
|  | 2619   CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" | 
|  | 2620 | 
|  | 2621   _DEFAULT_CA_CONF="$CA_DIR/ca.conf" | 
|  | 2622 | 
|  | 2623   if [ -z "$CA_CONF" ]; then | 
|  | 2624     CA_CONF="$_DEFAULT_CA_CONF" | 
|  | 2625   fi | 
|  | 2626   _debug3 CA_CONF "$CA_CONF" | 
|  | 2627 | 
|  | 2628   if [ -f "$CA_CONF" ]; then | 
|  | 2629     . "$CA_CONF" | 
|  | 2630   fi | 
|  | 2631 | 
|  | 2632   if [ -z "$ACME_DIR" ]; then | 
|  | 2633     ACME_DIR="/home/.acme" | 
|  | 2634   fi | 
|  | 2635 | 
|  | 2636   if [ -z "$APACHE_CONF_BACKUP_DIR" ]; then | 
|  | 2637     APACHE_CONF_BACKUP_DIR="$LE_CONFIG_HOME" | 
|  | 2638   fi | 
|  | 2639 | 
|  | 2640   if [ -z "$USER_AGENT" ]; then | 
|  | 2641     USER_AGENT="$DEFAULT_USER_AGENT" | 
|  | 2642   fi | 
|  | 2643 | 
|  | 2644   if [ -z "$HTTP_HEADER" ]; then | 
|  | 2645     HTTP_HEADER="$LE_CONFIG_HOME/http.header" | 
|  | 2646   fi | 
|  | 2647 | 
|  | 2648   _OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key" | 
|  | 2649   _OLD_ACCOUNT_JSON="$LE_WORKING_DIR/account.json" | 
|  | 2650 | 
|  | 2651   _DEFAULT_ACCOUNT_KEY_PATH="$CA_DIR/account.key" | 
|  | 2652   _DEFAULT_ACCOUNT_JSON_PATH="$CA_DIR/account.json" | 
|  | 2653   if [ -z "$ACCOUNT_KEY_PATH" ]; then | 
|  | 2654     ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH" | 
|  | 2655   fi | 
|  | 2656 | 
|  | 2657   if [ -z "$ACCOUNT_JSON_PATH" ]; then | 
|  | 2658     ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH" | 
|  | 2659   fi | 
|  | 2660 | 
|  | 2661   _DEFAULT_CERT_HOME="$LE_CONFIG_HOME" | 
|  | 2662   if [ -z "$CERT_HOME" ]; then | 
|  | 2663     CERT_HOME="$_DEFAULT_CERT_HOME" | 
|  | 2664   fi | 
|  | 2665 | 
|  | 2666   if [ -z "$ACME_OPENSSL_BIN" ] || [ ! -f "$ACME_OPENSSL_BIN" ] || [ ! -x "$ACME_OPENSSL_BIN" ]; then | 
|  | 2667     ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" | 
|  | 2668   fi | 
|  | 2669 | 
|  | 2670   if [ -z "$domain" ]; then | 
|  | 2671     return 0 | 
|  | 2672   fi | 
|  | 2673 | 
|  | 2674   if [ -z "$DOMAIN_PATH" ]; then | 
|  | 2675     domainhome="$CERT_HOME/$domain" | 
|  | 2676     domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX" | 
|  | 2677 | 
|  | 2678     DOMAIN_PATH="$domainhome" | 
|  | 2679 | 
|  | 2680     if _isEccKey "$_ilength"; then | 
|  | 2681       DOMAIN_PATH="$domainhomeecc" | 
|  | 2682     else | 
|  | 2683       if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ]; then | 
|  | 2684         _info "The domain '$domain' seems to have a ECC cert already, please add '$(__red "--ecc")' parameter if you want to use that cert." | 
|  | 2685       fi | 
|  | 2686     fi | 
|  | 2687     _debug DOMAIN_PATH "$DOMAIN_PATH" | 
|  | 2688   fi | 
|  | 2689 | 
|  | 2690   if [ -z "$DOMAIN_BACKUP_PATH" ]; then | 
|  | 2691     DOMAIN_BACKUP_PATH="$DOMAIN_PATH/backup" | 
|  | 2692   fi | 
|  | 2693 | 
|  | 2694   if [ -z "$DOMAIN_CONF" ]; then | 
|  | 2695     DOMAIN_CONF="$DOMAIN_PATH/$domain.conf" | 
|  | 2696   fi | 
|  | 2697 | 
|  | 2698   if [ -z "$DOMAIN_SSL_CONF" ]; then | 
|  | 2699     DOMAIN_SSL_CONF="$DOMAIN_PATH/$domain.csr.conf" | 
|  | 2700   fi | 
|  | 2701 | 
|  | 2702   if [ -z "$CSR_PATH" ]; then | 
|  | 2703     CSR_PATH="$DOMAIN_PATH/$domain.csr" | 
|  | 2704   fi | 
|  | 2705   if [ -z "$CERT_KEY_PATH" ]; then | 
|  | 2706     CERT_KEY_PATH="$DOMAIN_PATH/$domain.key" | 
|  | 2707   fi | 
|  | 2708   if [ -z "$CERT_PATH" ]; then | 
|  | 2709     CERT_PATH="$DOMAIN_PATH/$domain.cer" | 
|  | 2710   fi | 
|  | 2711   if [ -z "$CA_CERT_PATH" ]; then | 
|  | 2712     CA_CERT_PATH="$DOMAIN_PATH/ca.cer" | 
|  | 2713   fi | 
|  | 2714   if [ -z "$CERT_FULLCHAIN_PATH" ]; then | 
|  | 2715     CERT_FULLCHAIN_PATH="$DOMAIN_PATH/fullchain.cer" | 
|  | 2716   fi | 
|  | 2717   if [ -z "$CERT_PFX_PATH" ]; then | 
|  | 2718     CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx" | 
|  | 2719   fi | 
|  | 2720   if [ -z "$CERT_PKCS8_PATH" ]; then | 
|  | 2721     CERT_PKCS8_PATH="$DOMAIN_PATH/$domain.pkcs8" | 
|  | 2722   fi | 
|  | 2723 | 
|  | 2724   if [ -z "$TLS_CONF" ]; then | 
|  | 2725     TLS_CONF="$DOMAIN_PATH/tls.validation.conf" | 
|  | 2726   fi | 
|  | 2727   if [ -z "$TLS_CERT" ]; then | 
|  | 2728     TLS_CERT="$DOMAIN_PATH/tls.validation.cert" | 
|  | 2729   fi | 
|  | 2730   if [ -z "$TLS_KEY" ]; then | 
|  | 2731     TLS_KEY="$DOMAIN_PATH/tls.validation.key" | 
|  | 2732   fi | 
|  | 2733   if [ -z "$TLS_CSR" ]; then | 
|  | 2734     TLS_CSR="$DOMAIN_PATH/tls.validation.csr" | 
|  | 2735   fi | 
|  | 2736 | 
|  | 2737 } | 
|  | 2738 | 
|  | 2739 _exec() { | 
|  | 2740   if [ -z "$_EXEC_TEMP_ERR" ]; then | 
|  | 2741     _EXEC_TEMP_ERR="$(_mktemp)" | 
|  | 2742   fi | 
|  | 2743 | 
|  | 2744   if [ "$_EXEC_TEMP_ERR" ]; then | 
|  | 2745     eval "$@ 2>>$_EXEC_TEMP_ERR" | 
|  | 2746   else | 
|  | 2747     eval "$@" | 
|  | 2748   fi | 
|  | 2749 } | 
|  | 2750 | 
|  | 2751 _exec_err() { | 
|  | 2752   [ "$_EXEC_TEMP_ERR" ] && _err "$(cat "$_EXEC_TEMP_ERR")" && echo "" >"$_EXEC_TEMP_ERR" | 
|  | 2753 } | 
|  | 2754 | 
|  | 2755 _apachePath() { | 
|  | 2756   _APACHECTL="apachectl" | 
|  | 2757   if ! _exists apachectl; then | 
|  | 2758     if _exists apache2ctl; then | 
|  | 2759       _APACHECTL="apache2ctl" | 
|  | 2760     else | 
|  | 2761       _err "'apachectl not found. It seems that apache is not installed, or you are not root user.'" | 
|  | 2762       _err "Please use webroot mode to try again." | 
|  | 2763       return 1 | 
|  | 2764     fi | 
|  | 2765   fi | 
|  | 2766 | 
|  | 2767   if ! _exec $_APACHECTL -V >/dev/null; then | 
|  | 2768     _exec_err | 
|  | 2769     return 1 | 
|  | 2770   fi | 
|  | 2771 | 
|  | 2772   if [ "$APACHE_HTTPD_CONF" ]; then | 
|  | 2773     _saveaccountconf APACHE_HTTPD_CONF "$APACHE_HTTPD_CONF" | 
|  | 2774     httpdconf="$APACHE_HTTPD_CONF" | 
|  | 2775     httpdconfname="$(basename "$httpdconfname")" | 
|  | 2776   else | 
|  | 2777     httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"')" | 
|  | 2778     _debug httpdconfname "$httpdconfname" | 
|  | 2779 | 
|  | 2780     if [ -z "$httpdconfname" ]; then | 
|  | 2781       _err "Can not read apache config file." | 
|  | 2782       return 1 | 
|  | 2783     fi | 
|  | 2784 | 
|  | 2785     if _startswith "$httpdconfname" '/'; then | 
|  | 2786       httpdconf="$httpdconfname" | 
|  | 2787       httpdconfname="$(basename "$httpdconfname")" | 
|  | 2788     else | 
|  | 2789       httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"')" | 
|  | 2790       _debug httpdroot "$httpdroot" | 
|  | 2791       httpdconf="$httpdroot/$httpdconfname" | 
|  | 2792       httpdconfname="$(basename "$httpdconfname")" | 
|  | 2793     fi | 
|  | 2794   fi | 
|  | 2795   _debug httpdconf "$httpdconf" | 
|  | 2796   _debug httpdconfname "$httpdconfname" | 
|  | 2797   if [ ! -f "$httpdconf" ]; then | 
|  | 2798     _err "Apache Config file not found" "$httpdconf" | 
|  | 2799     return 1 | 
|  | 2800   fi | 
|  | 2801   return 0 | 
|  | 2802 } | 
|  | 2803 | 
|  | 2804 _restoreApache() { | 
|  | 2805   if [ -z "$usingApache" ]; then | 
|  | 2806     return 0 | 
|  | 2807   fi | 
|  | 2808   _initpath | 
|  | 2809   if ! _apachePath; then | 
|  | 2810     return 1 | 
|  | 2811   fi | 
|  | 2812 | 
|  | 2813   if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ]; then | 
|  | 2814     _debug "No config file to restore." | 
|  | 2815     return 0 | 
|  | 2816   fi | 
|  | 2817 | 
|  | 2818   cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" >"$httpdconf" | 
|  | 2819   _debug "Restored: $httpdconf." | 
|  | 2820   if ! _exec $_APACHECTL -t; then | 
|  | 2821     _exec_err | 
|  | 2822     _err "Sorry, restore apache config error, please contact me." | 
|  | 2823     return 1 | 
|  | 2824   fi | 
|  | 2825   _debug "Restored successfully." | 
|  | 2826   rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" | 
|  | 2827   return 0 | 
|  | 2828 } | 
|  | 2829 | 
|  | 2830 _setApache() { | 
|  | 2831   _initpath | 
|  | 2832   if ! _apachePath; then | 
|  | 2833     return 1 | 
|  | 2834   fi | 
|  | 2835 | 
|  | 2836   #test the conf first | 
|  | 2837   _info "Checking if there is an error in the apache config file before starting." | 
|  | 2838 | 
|  | 2839   if ! _exec "$_APACHECTL" -t >/dev/null; then | 
|  | 2840     _exec_err | 
|  | 2841     _err "The apache config file has error, please fix it first, then try again." | 
|  | 2842     _err "Don't worry, there is nothing changed to your system." | 
|  | 2843     return 1 | 
|  | 2844   else | 
|  | 2845     _info "OK" | 
|  | 2846   fi | 
|  | 2847 | 
|  | 2848   #backup the conf | 
|  | 2849   _debug "Backup apache config file" "$httpdconf" | 
|  | 2850   if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/"; then | 
|  | 2851     _err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed." | 
|  | 2852     _err "This might be a bug of $PROJECT_NAME , please report issue: $PROJECT" | 
|  | 2853     return 1 | 
|  | 2854   fi | 
|  | 2855   _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" | 
|  | 2856   _info "In case there is an error that can not be restored automatically, you may try restore it yourself." | 
|  | 2857   _info "The backup file will be deleted on success, just forget it." | 
|  | 2858 | 
|  | 2859   #add alias | 
|  | 2860 | 
|  | 2861   apacheVer="$($_APACHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2)" | 
|  | 2862   _debug "apacheVer" "$apacheVer" | 
|  | 2863   apacheMajor="$(echo "$apacheVer" | cut -d . -f 1)" | 
|  | 2864   apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)" | 
|  | 2865 | 
|  | 2866   if [ "$apacheVer" ] && [ "$apacheMajor$apacheMinor" -ge "24" ]; then | 
|  | 2867     echo " | 
|  | 2868 Alias /.well-known/acme-challenge  $ACME_DIR | 
|  | 2869 <Directory $ACME_DIR > | 
|  | 2870 Require all granted | 
|  | 2871 </Directory> | 
|  | 2872   " >>"$httpdconf" | 
|  | 2873   else | 
|  | 2874     echo " | 
|  | 2875 Alias /.well-known/acme-challenge  $ACME_DIR | 
|  | 2876 <Directory $ACME_DIR > | 
|  | 2877 Order allow,deny | 
|  | 2878 Allow from all | 
|  | 2879 </Directory> | 
|  | 2880   " >>"$httpdconf" | 
|  | 2881   fi | 
|  | 2882 | 
|  | 2883   _msg="$($_APACHECTL -t 2>&1)" | 
|  | 2884   if [ "$?" != "0" ]; then | 
|  | 2885     _err "Sorry, apache config error" | 
|  | 2886     if _restoreApache; then | 
|  | 2887       _err "The apache config file is restored." | 
|  | 2888     else | 
|  | 2889       _err "Sorry, the apache config file can not be restored, please report bug." | 
|  | 2890     fi | 
|  | 2891     return 1 | 
|  | 2892   fi | 
|  | 2893 | 
|  | 2894   if [ ! -d "$ACME_DIR" ]; then | 
|  | 2895     mkdir -p "$ACME_DIR" | 
|  | 2896     chmod 755 "$ACME_DIR" | 
|  | 2897   fi | 
|  | 2898 | 
|  | 2899   if ! _exec "$_APACHECTL" graceful; then | 
|  | 2900     _exec_err | 
|  | 2901     _err "$_APACHECTL  graceful error, please contact me." | 
|  | 2902     _restoreApache | 
|  | 2903     return 1 | 
|  | 2904   fi | 
|  | 2905   usingApache="1" | 
|  | 2906   return 0 | 
|  | 2907 } | 
|  | 2908 | 
|  | 2909 #find the real nginx conf file | 
|  | 2910 #backup | 
|  | 2911 #set the nginx conf | 
|  | 2912 #returns the real nginx conf file | 
|  | 2913 _setNginx() { | 
|  | 2914   _d="$1" | 
|  | 2915   _croot="$2" | 
|  | 2916   _thumbpt="$3" | 
|  | 2917 | 
|  | 2918   FOUND_REAL_NGINX_CONF="" | 
|  | 2919   FOUND_REAL_NGINX_CONF_LN="" | 
|  | 2920   BACKUP_NGINX_CONF="" | 
|  | 2921   _debug _croot "$_croot" | 
|  | 2922   _start_f="$(echo "$_croot" | cut -d : -f 2)" | 
|  | 2923   _debug _start_f "$_start_f" | 
|  | 2924   if [ -z "$_start_f" ]; then | 
|  | 2925     _debug "find start conf from nginx command" | 
|  | 2926     if [ -z "$NGINX_CONF" ]; then | 
|  | 2927       if ! _exists "nginx"; then | 
|  | 2928         _err "nginx command is not found." | 
|  | 2929         return 1 | 
|  | 2930       fi | 
|  | 2931       NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "--conf-path=[^ ]* " | tr -d " ")" | 
|  | 2932       _debug NGINX_CONF "$NGINX_CONF" | 
|  | 2933       NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)" | 
|  | 2934       _debug NGINX_CONF "$NGINX_CONF" | 
|  | 2935       if [ -z "$NGINX_CONF" ]; then | 
|  | 2936         _err "Can not find nginx conf." | 
|  | 2937         NGINX_CONF="" | 
|  | 2938         return 1 | 
|  | 2939       fi | 
|  | 2940       if [ ! -f "$NGINX_CONF" ]; then | 
|  | 2941         _err "'$NGINX_CONF' doesn't exist." | 
|  | 2942         NGINX_CONF="" | 
|  | 2943         return 1 | 
|  | 2944       fi | 
|  | 2945       _debug "Found nginx conf file:$NGINX_CONF" | 
|  | 2946     fi | 
|  | 2947     _start_f="$NGINX_CONF" | 
|  | 2948   fi | 
|  | 2949   _debug "Start detect nginx conf for $_d from:$_start_f" | 
|  | 2950   if ! _checkConf "$_d" "$_start_f"; then | 
|  | 2951     _err "Can not find conf file for domain $d" | 
|  | 2952     return 1 | 
|  | 2953   fi | 
|  | 2954   _info "Found conf file: $FOUND_REAL_NGINX_CONF" | 
|  | 2955 | 
|  | 2956   _ln=$FOUND_REAL_NGINX_CONF_LN | 
|  | 2957   _debug "_ln" "$_ln" | 
|  | 2958 | 
|  | 2959   _lnn=$(_math $_ln + 1) | 
|  | 2960   _debug _lnn "$_lnn" | 
|  | 2961   _start_tag="$(sed -n "$_lnn,${_lnn}p" "$FOUND_REAL_NGINX_CONF")" | 
|  | 2962   _debug "_start_tag" "$_start_tag" | 
|  | 2963   if [ "$_start_tag" = "$NGINX_START" ]; then | 
|  | 2964     _info "The domain $_d is already configured, skip" | 
|  | 2965     FOUND_REAL_NGINX_CONF="" | 
|  | 2966     return 0 | 
|  | 2967   fi | 
|  | 2968 | 
|  | 2969   mkdir -p "$DOMAIN_BACKUP_PATH" | 
|  | 2970   _backup_conf="$DOMAIN_BACKUP_PATH/$_d.nginx.conf" | 
|  | 2971   _debug _backup_conf "$_backup_conf" | 
|  | 2972   BACKUP_NGINX_CONF="$_backup_conf" | 
|  | 2973   _info "Backup $FOUND_REAL_NGINX_CONF to $_backup_conf" | 
|  | 2974   if ! cp "$FOUND_REAL_NGINX_CONF" "$_backup_conf"; then | 
|  | 2975     _err "backup error." | 
|  | 2976     FOUND_REAL_NGINX_CONF="" | 
|  | 2977     return 1 | 
|  | 2978   fi | 
|  | 2979 | 
|  | 2980   if ! _exists "nginx"; then | 
|  | 2981     _err "nginx command is not found." | 
|  | 2982     return 1 | 
|  | 2983   fi | 
|  | 2984   _info "Check the nginx conf before setting up." | 
|  | 2985   if ! _exec "nginx -t" >/dev/null; then | 
|  | 2986     _exec_err | 
|  | 2987     return 1 | 
|  | 2988   fi | 
|  | 2989 | 
|  | 2990   _info "OK, Set up nginx config file" | 
|  | 2991 | 
|  | 2992   if ! sed -n "1,${_ln}p" "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"; then | 
|  | 2993     cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" | 
|  | 2994     _err "write nginx conf error, but don't worry, the file is restored to the original version." | 
|  | 2995     return 1 | 
|  | 2996   fi | 
|  | 2997 | 
|  | 2998   echo "$NGINX_START | 
|  | 2999 location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { | 
|  | 3000   default_type text/plain; | 
|  | 3001   return 200 \"\$1.$_thumbpt\"; | 
|  | 3002 } | 
|  | 3003 #NGINX_START | 
|  | 3004 " >>"$FOUND_REAL_NGINX_CONF" | 
|  | 3005 | 
|  | 3006   if ! sed -n "${_lnn},99999p" "$_backup_conf" >>"$FOUND_REAL_NGINX_CONF"; then | 
|  | 3007     cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" | 
|  | 3008     _err "write nginx conf error, but don't worry, the file is restored." | 
|  | 3009     return 1 | 
|  | 3010   fi | 
|  | 3011   _debug3 "Modified config:$(cat $FOUND_REAL_NGINX_CONF)" | 
|  | 3012   _info "nginx conf is done, let's check it again." | 
|  | 3013   if ! _exec "nginx -t" >/dev/null; then | 
|  | 3014     _exec_err | 
|  | 3015     _err "It seems that nginx conf was broken, let's restore." | 
|  | 3016     cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" | 
|  | 3017     return 1 | 
|  | 3018   fi | 
|  | 3019 | 
|  | 3020   _info "Reload nginx" | 
|  | 3021   if ! _exec "nginx -s reload" >/dev/null; then | 
|  | 3022     _exec_err | 
|  | 3023     _err "It seems that nginx reload error, let's restore." | 
|  | 3024     cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" | 
|  | 3025     return 1 | 
|  | 3026   fi | 
|  | 3027 | 
|  | 3028   return 0 | 
|  | 3029 } | 
|  | 3030 | 
|  | 3031 #d , conf | 
|  | 3032 _checkConf() { | 
|  | 3033   _d="$1" | 
|  | 3034   _c_file="$2" | 
|  | 3035   _debug "Start _checkConf from:$_c_file" | 
|  | 3036   if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then | 
|  | 3037     _debug "wildcard" | 
|  | 3038     for _w_f in $2; do | 
|  | 3039       if [ -f "$_w_f" ] && _checkConf "$1" "$_w_f"; then | 
|  | 3040         return 0 | 
|  | 3041       fi | 
|  | 3042     done | 
|  | 3043     #not found | 
|  | 3044     return 1 | 
|  | 3045   elif [ -f "$2" ]; then | 
|  | 3046     _debug "single" | 
|  | 3047     if _isRealNginxConf "$1" "$2"; then | 
|  | 3048       _debug "$2 is found." | 
|  | 3049       FOUND_REAL_NGINX_CONF="$2" | 
|  | 3050       return 0 | 
|  | 3051     fi | 
|  | 3052     if cat "$2" | tr "\t" " " | grep "^ *include *.*;" >/dev/null; then | 
|  | 3053       _debug "Try include files" | 
|  | 3054       for included in $(cat "$2" | tr "\t" " " | grep "^ *include *.*;" | sed "s/include //" | tr -d " ;"); do | 
|  | 3055         _debug "check included $included" | 
|  | 3056         if _checkConf "$1" "$included"; then | 
|  | 3057           return 0 | 
|  | 3058         fi | 
|  | 3059       done | 
|  | 3060     fi | 
|  | 3061     return 1 | 
|  | 3062   else | 
|  | 3063     _debug "$2 not found." | 
|  | 3064     return 1 | 
|  | 3065   fi | 
|  | 3066   return 1 | 
|  | 3067 } | 
|  | 3068 | 
|  | 3069 #d , conf | 
|  | 3070 _isRealNginxConf() { | 
|  | 3071   _debug "_isRealNginxConf $1 $2" | 
|  | 3072   if [ -f "$2" ]; then | 
|  | 3073     for _fln in $(tr "\t" ' ' <"$2" | grep -n "^ *server_name.* $1" | cut -d : -f 1); do | 
|  | 3074       _debug _fln "$_fln" | 
|  | 3075       if [ "$_fln" ]; then | 
|  | 3076         _start=$(tr "\t" ' ' <"$2" | _head_n "$_fln" | grep -n "^ *server *" | grep -v server_name | _tail_n 1) | 
|  | 3077         _debug "_start" "$_start" | 
|  | 3078         _start_n=$(echo "$_start" | cut -d : -f 1) | 
|  | 3079         _start_nn=$(_math $_start_n + 1) | 
|  | 3080         _debug "_start_n" "$_start_n" | 
|  | 3081         _debug "_start_nn" "$_start_nn" | 
|  | 3082 | 
|  | 3083         _left="$(sed -n "${_start_nn},99999p" "$2")" | 
|  | 3084         _debug2 _left "$_left" | 
|  | 3085         _end="$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *" | grep -v server_name | _head_n 1)" | 
|  | 3086         _debug "_end" "$_end" | 
|  | 3087         if [ "$_end" ]; then | 
|  | 3088           _end_n=$(echo "$_end" | cut -d : -f 1) | 
|  | 3089           _debug "_end_n" "$_end_n" | 
|  | 3090           _seg_n=$(echo "$_left" | sed -n "1,${_end_n}p") | 
|  | 3091         else | 
|  | 3092           _seg_n="$_left" | 
|  | 3093         fi | 
|  | 3094 | 
|  | 3095         _debug "_seg_n" "$_seg_n" | 
|  | 3096 | 
|  | 3097         _skip_ssl=1 | 
|  | 3098         for _listen_i in $(echo "$_seg_n" | tr "\t" ' ' | grep "^ *listen" | tr -d " "); do | 
|  | 3099           if [ "$_listen_i" ]; then | 
|  | 3100             if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl")" ]; then | 
|  | 3101               _debug2 "$_listen_i is ssl" | 
|  | 3102             else | 
|  | 3103               _debug2 "$_listen_i is plain text" | 
|  | 3104               _skip_ssl="" | 
|  | 3105               break | 
|  | 3106             fi | 
|  | 3107           fi | 
|  | 3108         done | 
|  | 3109 | 
|  | 3110         if [ "$_skip_ssl" = "1" ]; then | 
|  | 3111           _debug "ssl on, skip" | 
|  | 3112         else | 
|  | 3113           FOUND_REAL_NGINX_CONF_LN=$_fln | 
|  | 3114           _debug3 "found FOUND_REAL_NGINX_CONF_LN" "$FOUND_REAL_NGINX_CONF_LN" | 
|  | 3115           return 0 | 
|  | 3116         fi | 
|  | 3117       fi | 
|  | 3118     done | 
|  | 3119   fi | 
|  | 3120   return 1 | 
|  | 3121 } | 
|  | 3122 | 
|  | 3123 #restore all the nginx conf | 
|  | 3124 _restoreNginx() { | 
|  | 3125   if [ -z "$NGINX_RESTORE_VLIST" ]; then | 
|  | 3126     _debug "No need to restore nginx, skip." | 
|  | 3127     return | 
|  | 3128   fi | 
|  | 3129   _debug "_restoreNginx" | 
|  | 3130   _debug "NGINX_RESTORE_VLIST" "$NGINX_RESTORE_VLIST" | 
|  | 3131 | 
|  | 3132   for ng_entry in $(echo "$NGINX_RESTORE_VLIST" | tr "$dvsep" ' '); do | 
|  | 3133     _debug "ng_entry" "$ng_entry" | 
|  | 3134     _nd=$(echo "$ng_entry" | cut -d "$sep" -f 1) | 
|  | 3135     _ngconf=$(echo "$ng_entry" | cut -d "$sep" -f 2) | 
|  | 3136     _ngbackupconf=$(echo "$ng_entry" | cut -d "$sep" -f 3) | 
|  | 3137     _info "Restoring from $_ngbackupconf to $_ngconf" | 
|  | 3138     cat "$_ngbackupconf" >"$_ngconf" | 
|  | 3139   done | 
|  | 3140 | 
|  | 3141   _info "Reload nginx" | 
|  | 3142   if ! _exec "nginx -s reload" >/dev/null; then | 
|  | 3143     _exec_err | 
|  | 3144     _err "It seems that nginx reload error, please report bug." | 
|  | 3145     return 1 | 
|  | 3146   fi | 
|  | 3147   return 0 | 
|  | 3148 } | 
|  | 3149 | 
|  | 3150 _clearup() { | 
|  | 3151   _stopserver "$serverproc" | 
|  | 3152   serverproc="" | 
|  | 3153   _restoreApache | 
|  | 3154   _restoreNginx | 
|  | 3155   _clearupdns | 
|  | 3156   if [ -z "$DEBUG" ]; then | 
|  | 3157     rm -f "$TLS_CONF" | 
|  | 3158     rm -f "$TLS_CERT" | 
|  | 3159     rm -f "$TLS_KEY" | 
|  | 3160     rm -f "$TLS_CSR" | 
|  | 3161   fi | 
|  | 3162 } | 
|  | 3163 | 
|  | 3164 _clearupdns() { | 
|  | 3165   _debug "_clearupdns" | 
|  | 3166   _debug "dns_entries" "$dns_entries" | 
|  | 3167 | 
|  | 3168   if [ -z "$dns_entries" ]; then | 
|  | 3169     _debug "skip dns." | 
|  | 3170     return | 
|  | 3171   fi | 
|  | 3172   _info "Removing DNS records." | 
|  | 3173 | 
|  | 3174   for entry in $dns_entries; do | 
|  | 3175     d=$(_getfield "$entry" 1) | 
|  | 3176     txtdomain=$(_getfield "$entry" 2) | 
|  | 3177     aliasDomain=$(_getfield "$entry" 3) | 
|  | 3178     _currentRoot=$(_getfield "$entry" 4) | 
|  | 3179     txt=$(_getfield "$entry" 5) | 
|  | 3180     d_api=$(_getfield "$entry" 6) | 
|  | 3181     _debug "d" "$d" | 
|  | 3182     _debug "txtdomain" "$txtdomain" | 
|  | 3183     _debug "aliasDomain" "$aliasDomain" | 
|  | 3184     _debug "_currentRoot" "$_currentRoot" | 
|  | 3185     _debug "txt" "$txt" | 
|  | 3186     _debug "d_api" "$d_api" | 
|  | 3187     if [ "$d_api" = "$txt" ]; then | 
|  | 3188       d_api="" | 
|  | 3189     fi | 
|  | 3190 | 
|  | 3191     if [ -z "$d_api" ]; then | 
|  | 3192       _info "Not Found domain api file: $d_api" | 
|  | 3193       continue | 
|  | 3194     fi | 
|  | 3195 | 
|  | 3196     if [ "$aliasDomain" ]; then | 
|  | 3197       txtdomain="$aliasDomain" | 
|  | 3198     fi | 
|  | 3199 | 
|  | 3200     ( | 
|  | 3201       if ! . "$d_api"; then | 
|  | 3202         _err "Load file $d_api error. Please check your api file and try again." | 
|  | 3203         return 1 | 
|  | 3204       fi | 
|  | 3205 | 
|  | 3206       rmcommand="${_currentRoot}_rm" | 
|  | 3207       if ! _exists "$rmcommand"; then | 
|  | 3208         _err "It seems that your api file doesn't define $rmcommand" | 
|  | 3209         return 1 | 
|  | 3210       fi | 
|  | 3211       _info "Removing txt: $txt for domain: $txtdomain" | 
|  | 3212       if ! $rmcommand "$txtdomain" "$txt"; then | 
|  | 3213         _err "Error removing txt for domain:$txtdomain" | 
|  | 3214         return 1 | 
|  | 3215       fi | 
|  | 3216       _info "Removed: Success" | 
|  | 3217     ) | 
|  | 3218 | 
|  | 3219   done | 
|  | 3220 } | 
|  | 3221 | 
|  | 3222 # webroot  removelevel tokenfile | 
|  | 3223 _clearupwebbroot() { | 
|  | 3224   __webroot="$1" | 
|  | 3225   if [ -z "$__webroot" ]; then | 
|  | 3226     _debug "no webroot specified, skip" | 
|  | 3227     return 0 | 
|  | 3228   fi | 
|  | 3229 | 
|  | 3230   _rmpath="" | 
|  | 3231   if [ "$2" = '1' ]; then | 
|  | 3232     _rmpath="$__webroot/.well-known" | 
|  | 3233   elif [ "$2" = '2' ]; then | 
|  | 3234     _rmpath="$__webroot/.well-known/acme-challenge" | 
|  | 3235   elif [ "$2" = '3' ]; then | 
|  | 3236     _rmpath="$__webroot/.well-known/acme-challenge/$3" | 
|  | 3237   else | 
|  | 3238     _debug "Skip for removelevel:$2" | 
|  | 3239   fi | 
|  | 3240 | 
|  | 3241   if [ "$_rmpath" ]; then | 
|  | 3242     if [ "$DEBUG" ]; then | 
|  | 3243       _debug "Debugging, skip removing: $_rmpath" | 
|  | 3244     else | 
|  | 3245       rm -rf "$_rmpath" | 
|  | 3246     fi | 
|  | 3247   fi | 
|  | 3248 | 
|  | 3249   return 0 | 
|  | 3250 | 
|  | 3251 } | 
|  | 3252 | 
|  | 3253 _on_before_issue() { | 
|  | 3254   _chk_web_roots="$1" | 
|  | 3255   _chk_main_domain="$2" | 
|  | 3256   _chk_alt_domains="$3" | 
|  | 3257   _chk_pre_hook="$4" | 
|  | 3258   _chk_local_addr="$5" | 
|  | 3259   _debug _on_before_issue | 
|  | 3260   _debug _chk_main_domain "$_chk_main_domain" | 
|  | 3261   _debug _chk_alt_domains "$_chk_alt_domains" | 
|  | 3262   #run pre hook | 
|  | 3263   if [ "$_chk_pre_hook" ]; then | 
|  | 3264     _info "Run pre hook:'$_chk_pre_hook'" | 
|  | 3265     if ! ( | 
|  | 3266       cd "$DOMAIN_PATH" && eval "$_chk_pre_hook" | 
|  | 3267     ); then | 
|  | 3268       _err "Error when run pre hook." | 
|  | 3269       return 1 | 
|  | 3270     fi | 
|  | 3271   fi | 
|  | 3272 | 
|  | 3273   if _hasfield "$_chk_web_roots" "$NO_VALUE"; then | 
|  | 3274     if ! _exists "socat"; then | 
|  | 3275       _err "Please install socat tools first." | 
|  | 3276       return 1 | 
|  | 3277     fi | 
|  | 3278   fi | 
|  | 3279 | 
|  | 3280   _debug Le_LocalAddress "$_chk_local_addr" | 
|  | 3281 | 
|  | 3282   _index=1 | 
|  | 3283   _currentRoot="" | 
|  | 3284   _addrIndex=1 | 
|  | 3285   _w_index=1 | 
|  | 3286   while true; do | 
|  | 3287     d="$(echo "$_chk_main_domain,$_chk_alt_domains," | cut -d , -f "$_w_index")" | 
|  | 3288     _w_index="$(_math "$_w_index" + 1)" | 
|  | 3289     _debug d "$d" | 
|  | 3290     if [ -z "$d" ]; then | 
|  | 3291       break | 
|  | 3292     fi | 
|  | 3293     _debug "Check for domain" "$d" | 
|  | 3294     _currentRoot="$(_getfield "$_chk_web_roots" $_index)" | 
|  | 3295     _debug "_currentRoot" "$_currentRoot" | 
|  | 3296     _index=$(_math $_index + 1) | 
|  | 3297     _checkport="" | 
|  | 3298     if [ "$_currentRoot" = "$NO_VALUE" ]; then | 
|  | 3299       _info "Standalone mode." | 
|  | 3300       if [ -z "$Le_HTTPPort" ]; then | 
|  | 3301         Le_HTTPPort=80 | 
|  | 3302         _cleardomainconf "Le_HTTPPort" | 
|  | 3303       else | 
|  | 3304         _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" | 
|  | 3305       fi | 
|  | 3306       _checkport="$Le_HTTPPort" | 
|  | 3307     elif [ "$_currentRoot" = "$W_ALPN" ]; then | 
|  | 3308       _info "Standalone alpn mode." | 
|  | 3309       if [ -z "$Le_TLSPort" ]; then | 
|  | 3310         Le_TLSPort=443 | 
|  | 3311       else | 
|  | 3312         _savedomainconf "Le_TLSPort" "$Le_TLSPort" | 
|  | 3313       fi | 
|  | 3314       _checkport="$Le_TLSPort" | 
|  | 3315     fi | 
|  | 3316 | 
|  | 3317     if [ "$_checkport" ]; then | 
|  | 3318       _debug _checkport "$_checkport" | 
|  | 3319       _checkaddr="$(_getfield "$_chk_local_addr" $_addrIndex)" | 
|  | 3320       _debug _checkaddr "$_checkaddr" | 
|  | 3321 | 
|  | 3322       _addrIndex="$(_math $_addrIndex + 1)" | 
|  | 3323 | 
|  | 3324       _netprc="$(_ss "$_checkport" | grep "$_checkport")" | 
|  | 3325       netprc="$(echo "$_netprc" | grep "$_checkaddr")" | 
|  | 3326       if [ -z "$netprc" ]; then | 
|  | 3327         netprc="$(echo "$_netprc" | grep "$LOCAL_ANY_ADDRESS")" | 
|  | 3328       fi | 
|  | 3329       if [ "$netprc" ]; then | 
|  | 3330         _err "$netprc" | 
|  | 3331         _err "tcp port $_checkport is already used by $(echo "$netprc" | cut -d : -f 4)" | 
|  | 3332         _err "Please stop it first" | 
|  | 3333         return 1 | 
|  | 3334       fi | 
|  | 3335     fi | 
|  | 3336   done | 
|  | 3337 | 
|  | 3338   if _hasfield "$_chk_web_roots" "apache"; then | 
|  | 3339     if ! _setApache; then | 
|  | 3340       _err "set up apache error. Report error to me." | 
|  | 3341       return 1 | 
|  | 3342     fi | 
|  | 3343   else | 
|  | 3344     usingApache="" | 
|  | 3345   fi | 
|  | 3346 | 
|  | 3347 } | 
|  | 3348 | 
|  | 3349 _on_issue_err() { | 
|  | 3350   _chk_post_hook="$1" | 
|  | 3351   _chk_vlist="$2" | 
|  | 3352   _debug _on_issue_err | 
|  | 3353 | 
|  | 3354   if [ "$LOG_FILE" ]; then | 
|  | 3355     _err "Please check log file for more details: $LOG_FILE" | 
|  | 3356   else | 
|  | 3357     _err "Please add '--debug' or '--log' to check more details." | 
|  | 3358     _err "See: $_DEBUG_WIKI" | 
|  | 3359   fi | 
|  | 3360 | 
|  | 3361   #run the post hook | 
|  | 3362   if [ "$_chk_post_hook" ]; then | 
|  | 3363     _info "Run post hook:'$_chk_post_hook'" | 
|  | 3364     if ! ( | 
|  | 3365       cd "$DOMAIN_PATH" && eval "$_chk_post_hook" | 
|  | 3366     ); then | 
|  | 3367       _err "Error when run post hook." | 
|  | 3368       return 1 | 
|  | 3369     fi | 
|  | 3370   fi | 
|  | 3371 | 
|  | 3372   #trigger the validation to flush the pending authz | 
|  | 3373   _debug2 "_chk_vlist" "$_chk_vlist" | 
|  | 3374   if [ "$_chk_vlist" ]; then | 
|  | 3375     ( | 
|  | 3376       _debug2 "start to deactivate authz" | 
|  | 3377       ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ') | 
|  | 3378       for ventry in $ventries; do | 
|  | 3379         d=$(echo "$ventry" | cut -d "$sep" -f 1) | 
|  | 3380         keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) | 
|  | 3381         uri=$(echo "$ventry" | cut -d "$sep" -f 3) | 
|  | 3382         vtype=$(echo "$ventry" | cut -d "$sep" -f 4) | 
|  | 3383         _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) | 
|  | 3384         __trigger_validation "$uri" "$keyauthorization" | 
|  | 3385       done | 
|  | 3386     ) | 
|  | 3387   fi | 
|  | 3388 | 
|  | 3389   if [ "$_ACME_IS_RENEW" = "1" ] && _hasfield "$Le_Webroot" "$W_DNS"; then | 
|  | 3390     _err "$_DNS_MANUAL_ERR" | 
|  | 3391   fi | 
|  | 3392 | 
|  | 3393   if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then | 
|  | 3394     _debug "$(_dlg_versions)" | 
|  | 3395   fi | 
|  | 3396 | 
|  | 3397 } | 
|  | 3398 | 
|  | 3399 _on_issue_success() { | 
|  | 3400   _chk_post_hook="$1" | 
|  | 3401   _chk_renew_hook="$2" | 
|  | 3402   _debug _on_issue_success | 
|  | 3403 | 
|  | 3404   #run the post hook | 
|  | 3405   if [ "$_chk_post_hook" ]; then | 
|  | 3406     _info "Run post hook:'$_chk_post_hook'" | 
|  | 3407     if ! ( | 
|  | 3408       export CERT_PATH | 
|  | 3409       export CERT_KEY_PATH | 
|  | 3410       export CA_CERT_PATH | 
|  | 3411       export CERT_FULLCHAIN_PATH | 
|  | 3412       export Le_Domain="$_main_domain" | 
|  | 3413       cd "$DOMAIN_PATH" && eval "$_chk_post_hook" | 
|  | 3414     ); then | 
|  | 3415       _err "Error when run post hook." | 
|  | 3416       return 1 | 
|  | 3417     fi | 
|  | 3418   fi | 
|  | 3419 | 
|  | 3420   #run renew hook | 
|  | 3421   if [ "$_ACME_IS_RENEW" ] && [ "$_chk_renew_hook" ]; then | 
|  | 3422     _info "Run renew hook:'$_chk_renew_hook'" | 
|  | 3423     if ! ( | 
|  | 3424       export CERT_PATH | 
|  | 3425       export CERT_KEY_PATH | 
|  | 3426       export CA_CERT_PATH | 
|  | 3427       export CERT_FULLCHAIN_PATH | 
|  | 3428       export Le_Domain="$_main_domain" | 
|  | 3429       cd "$DOMAIN_PATH" && eval "$_chk_renew_hook" | 
|  | 3430     ); then | 
|  | 3431       _err "Error when run renew hook." | 
|  | 3432       return 1 | 
|  | 3433     fi | 
|  | 3434   fi | 
|  | 3435 | 
|  | 3436   if _hasfield "$Le_Webroot" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then | 
|  | 3437     _err "$_DNS_MANUAL_WARN" | 
|  | 3438   fi | 
|  | 3439 | 
|  | 3440 } | 
|  | 3441 | 
|  | 3442 #account_key_length   eab-kid  eab-hmac-key | 
|  | 3443 registeraccount() { | 
|  | 3444   _account_key_length="$1" | 
|  | 3445   _eab_id="$2" | 
|  | 3446   _eab_hmac_key="$3" | 
|  | 3447   _initpath | 
|  | 3448   _regAccount "$_account_key_length" "$_eab_id" "$_eab_hmac_key" | 
|  | 3449 } | 
|  | 3450 | 
|  | 3451 __calcAccountKeyHash() { | 
|  | 3452   [ -f "$ACCOUNT_KEY_PATH" ] && _digest sha256 <"$ACCOUNT_KEY_PATH" | 
|  | 3453 } | 
|  | 3454 | 
|  | 3455 __calc_account_thumbprint() { | 
|  | 3456   printf "%s" "$jwk" | tr -d ' ' | _digest "sha256" | _url_replace | 
|  | 3457 } | 
|  | 3458 | 
|  | 3459 _getAccountEmail() { | 
|  | 3460   if [ "$ACCOUNT_EMAIL" ]; then | 
|  | 3461     echo "$ACCOUNT_EMAIL" | 
|  | 3462     return 0 | 
|  | 3463   fi | 
|  | 3464   if [ -z "$CA_EMAIL" ]; then | 
|  | 3465     CA_EMAIL="$(_readcaconf CA_EMAIL)" | 
|  | 3466   fi | 
|  | 3467   if [ "$CA_EMAIL" ]; then | 
|  | 3468     echo "$CA_EMAIL" | 
|  | 3469     return 0 | 
|  | 3470   fi | 
|  | 3471   _readaccountconf "ACCOUNT_EMAIL" | 
|  | 3472 } | 
|  | 3473 | 
|  | 3474 #keylength | 
|  | 3475 _regAccount() { | 
|  | 3476   _initpath | 
|  | 3477   _reg_length="$1" | 
|  | 3478   _eab_id="$2" | 
|  | 3479   _eab_hmac_key="$3" | 
|  | 3480   _debug3 _regAccount "$_regAccount" | 
|  | 3481   _initAPI | 
|  | 3482 | 
|  | 3483   mkdir -p "$CA_DIR" | 
|  | 3484   if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then | 
|  | 3485     _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" | 
|  | 3486     mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" | 
|  | 3487   fi | 
|  | 3488 | 
|  | 3489   if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then | 
|  | 3490     _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" | 
|  | 3491     mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" | 
|  | 3492   fi | 
|  | 3493 | 
|  | 3494   if [ ! -f "$ACCOUNT_KEY_PATH" ]; then | 
|  | 3495     if ! _create_account_key "$_reg_length"; then | 
|  | 3496       _err "Create account key error." | 
|  | 3497       return 1 | 
|  | 3498     fi | 
|  | 3499   fi | 
|  | 3500 | 
|  | 3501   if ! _calcjwk "$ACCOUNT_KEY_PATH"; then | 
|  | 3502     return 1 | 
|  | 3503   fi | 
|  | 3504   if [ "$_eab_id" ] && [ "$_eab_hmac_key" ]; then | 
|  | 3505     _savecaconf CA_EAB_KEY_ID "$_eab_id" | 
|  | 3506     _savecaconf CA_EAB_HMAC_KEY "$_eab_hmac_key" | 
|  | 3507   fi | 
|  | 3508   _eab_id=$(_readcaconf "CA_EAB_KEY_ID") | 
|  | 3509   _eab_hmac_key=$(_readcaconf "CA_EAB_HMAC_KEY") | 
|  | 3510   _secure_debug3 _eab_id "$_eab_id" | 
|  | 3511   _secure_debug3 _eab_hmac_key "$_eab_hmac_key" | 
|  | 3512   _email="$(_getAccountEmail)" | 
|  | 3513   if [ "$_email" ]; then | 
|  | 3514     _savecaconf "CA_EMAIL" "$_email" | 
|  | 3515   fi | 
|  | 3516   if [ "$ACME_VERSION" = "2" ]; then | 
|  | 3517     if [ "$ACME_DIRECTORY" = "$CA_ZEROSSL" ]; then | 
|  | 3518       if [ -z "$_eab_id" ] || [ -z "$_eab_hmac_key" ]; then | 
|  | 3519         _info "No EAB credentials found for ZeroSSL, let's get one" | 
|  | 3520         if [ -z "$_email" ]; then | 
|  | 3521           _err "Please provide a email address for ZeroSSL account." | 
|  | 3522           _err "See ZeroSSL usage: $_ZEROSSL_WIKI" | 
|  | 3523           return 1 | 
|  | 3524         fi | 
|  | 3525         _eabresp=$(_post "email=$_email" $_ZERO_EAB_ENDPOINT) | 
|  | 3526         if [ "$?" != "0" ]; then | 
|  | 3527           _debug2 "$_eabresp" | 
|  | 3528           _err "Can not get EAB credentials from ZeroSSL." | 
|  | 3529           return 1 | 
|  | 3530         fi | 
|  | 3531         _eab_id="$(echo "$_eabresp" | tr ',}' '\n' | grep '"eab_kid"' | cut -d : -f 2 | tr -d '"')" | 
|  | 3532         if [ -z "$_eab_id" ]; then | 
|  | 3533           _err "Can not resolve _eab_id" | 
|  | 3534           return 1 | 
|  | 3535         fi | 
|  | 3536         _eab_hmac_key="$(echo "$_eabresp" | tr ',}' '\n' | grep '"eab_hmac_key"' | cut -d : -f 2 | tr -d '"')" | 
|  | 3537         if [ -z "$_eab_hmac_key" ]; then | 
|  | 3538           _err "Can not resolve _eab_hmac_key" | 
|  | 3539           return 1 | 
|  | 3540         fi | 
|  | 3541         _savecaconf CA_EAB_KEY_ID "$_eab_id" | 
|  | 3542         _savecaconf CA_EAB_HMAC_KEY "$_eab_hmac_key" | 
|  | 3543       fi | 
|  | 3544     fi | 
|  | 3545     if [ "$_eab_id" ] && [ "$_eab_hmac_key" ]; then | 
|  | 3546       eab_protected="{\"alg\":\"HS256\",\"kid\":\"$_eab_id\",\"url\":\"${ACME_NEW_ACCOUNT}\"}" | 
|  | 3547       _debug3 eab_protected "$eab_protected" | 
|  | 3548 | 
|  | 3549       eab_protected64=$(printf "%s" "$eab_protected" | _base64 | _url_replace) | 
|  | 3550       _debug3 eab_protected64 "$eab_protected64" | 
|  | 3551 | 
|  | 3552       eab_payload64=$(printf "%s" "$jwk" | _base64 | _url_replace) | 
|  | 3553       _debug3 eab_payload64 "$eab_payload64" | 
|  | 3554 | 
|  | 3555       eab_sign_t="$eab_protected64.$eab_payload64" | 
|  | 3556       _debug3 eab_sign_t "$eab_sign_t" | 
|  | 3557 | 
|  | 3558       key_hex="$(_durl_replace_base64 "$_eab_hmac_key" | _dbase64 | _hex_dump | tr -d ' ')" | 
|  | 3559       _debug3 key_hex "$key_hex" | 
|  | 3560 | 
|  | 3561       eab_signature=$(printf "%s" "$eab_sign_t" | _hmac sha256 $key_hex | _base64 | _url_replace) | 
|  | 3562       _debug3 eab_signature "$eab_signature" | 
|  | 3563 | 
|  | 3564       externalBinding=",\"externalAccountBinding\":{\"protected\":\"$eab_protected64\", \"payload\":\"$eab_payload64\", \"signature\":\"$eab_signature\"}" | 
|  | 3565       _debug3 externalBinding "$externalBinding" | 
|  | 3566     fi | 
|  | 3567     if [ "$_email" ]; then | 
|  | 3568       email_sg="\"contact\": [\"mailto:$_email\"], " | 
|  | 3569     fi | 
|  | 3570     regjson="{$email_sg\"termsOfServiceAgreed\": true$externalBinding}" | 
|  | 3571   else | 
|  | 3572     _reg_res="$ACME_NEW_ACCOUNT_RES" | 
|  | 3573     regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' | 
|  | 3574     if [ "$_email" ]; then | 
|  | 3575       regjson='{"resource": "'$_reg_res'", "contact": ["mailto:'$_email'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' | 
|  | 3576     fi | 
|  | 3577   fi | 
|  | 3578 | 
|  | 3579   _info "Registering account: $ACME_DIRECTORY" | 
|  | 3580 | 
|  | 3581   if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then | 
|  | 3582     _err "Register account Error: $response" | 
|  | 3583     return 1 | 
|  | 3584   fi | 
|  | 3585 | 
|  | 3586   _eabAlreadyBound="" | 
|  | 3587   if [ "$code" = "" ] || [ "$code" = '201' ]; then | 
|  | 3588     echo "$response" >"$ACCOUNT_JSON_PATH" | 
|  | 3589     _info "Registered" | 
|  | 3590   elif [ "$code" = '409' ] || [ "$code" = '200' ]; then | 
|  | 3591     _info "Already registered" | 
|  | 3592   elif [ "$code" = '400' ] && _contains "$response" 'The account is not awaiting external account binding'; then | 
|  | 3593     _info "Already register EAB." | 
|  | 3594     _eabAlreadyBound=1 | 
|  | 3595   else | 
|  | 3596     _err "Register account Error: $response" | 
|  | 3597     return 1 | 
|  | 3598   fi | 
|  | 3599 | 
|  | 3600   if [ -z "$_eabAlreadyBound" ]; then | 
|  | 3601     _debug2 responseHeaders "$responseHeaders" | 
|  | 3602     _accUri="$(echo "$responseHeaders" | grep -i "^Location:" | _head_n 1 | cut -d ':' -f 2- | tr -d "\r\n ")" | 
|  | 3603     _debug "_accUri" "$_accUri" | 
|  | 3604     if [ -z "$_accUri" ]; then | 
|  | 3605       _err "Can not find account id url." | 
|  | 3606       _err "$responseHeaders" | 
|  | 3607       return 1 | 
|  | 3608     fi | 
|  | 3609     _savecaconf "ACCOUNT_URL" "$_accUri" | 
|  | 3610   else | 
|  | 3611     ACCOUNT_URL="$(_readcaconf ACCOUNT_URL)" | 
|  | 3612   fi | 
|  | 3613   export ACCOUNT_URL="$_accUri" | 
|  | 3614 | 
|  | 3615   CA_KEY_HASH="$(__calcAccountKeyHash)" | 
|  | 3616   _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" | 
|  | 3617   _savecaconf CA_KEY_HASH "$CA_KEY_HASH" | 
|  | 3618 | 
|  | 3619   if [ "$code" = '403' ]; then | 
|  | 3620     _err "It seems that the account key is already deactivated, please use a new account key." | 
|  | 3621     return 1 | 
|  | 3622   fi | 
|  | 3623 | 
|  | 3624   ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" | 
|  | 3625   _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" | 
|  | 3626 } | 
|  | 3627 | 
|  | 3628 #implement updateaccount | 
|  | 3629 updateaccount() { | 
|  | 3630   _initpath | 
|  | 3631 | 
|  | 3632   if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then | 
|  | 3633     _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" | 
|  | 3634     mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" | 
|  | 3635   fi | 
|  | 3636 | 
|  | 3637   if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then | 
|  | 3638     _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" | 
|  | 3639     mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" | 
|  | 3640   fi | 
|  | 3641 | 
|  | 3642   if [ ! -f "$ACCOUNT_KEY_PATH" ]; then | 
|  | 3643     _err "Account key is not found at: $ACCOUNT_KEY_PATH" | 
|  | 3644     return 1 | 
|  | 3645   fi | 
|  | 3646 | 
|  | 3647   _accUri=$(_readcaconf "ACCOUNT_URL") | 
|  | 3648   _debug _accUri "$_accUri" | 
|  | 3649 | 
|  | 3650   if [ -z "$_accUri" ]; then | 
|  | 3651     _err "The account url is empty, please run '--update-account' first to update the account info first," | 
|  | 3652     _err "Then try again." | 
|  | 3653     return 1 | 
|  | 3654   fi | 
|  | 3655 | 
|  | 3656   if ! _calcjwk "$ACCOUNT_KEY_PATH"; then | 
|  | 3657     return 1 | 
|  | 3658   fi | 
|  | 3659   _initAPI | 
|  | 3660 | 
|  | 3661   _email="$(_getAccountEmail)" | 
|  | 3662   if [ "$ACME_VERSION" = "2" ]; then | 
|  | 3663     if [ "$ACCOUNT_EMAIL" ]; then | 
|  | 3664       updjson='{"contact": ["mailto:'$_email'"]}' | 
|  | 3665     else | 
|  | 3666       updjson='{"contact": []}' | 
|  | 3667     fi | 
|  | 3668   else | 
|  | 3669     # ACMEv1: Updates happen the same way a registration is done. | 
|  | 3670     # https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-6.3 | 
|  | 3671     _regAccount | 
|  | 3672     return | 
|  | 3673   fi | 
|  | 3674 | 
|  | 3675   # this part handles ACMEv2 account updates. | 
|  | 3676   _send_signed_request "$_accUri" "$updjson" | 
|  | 3677 | 
|  | 3678   if [ "$code" = '200' ]; then | 
|  | 3679     echo "$response" >"$ACCOUNT_JSON_PATH" | 
|  | 3680     _info "account update success for $_accUri." | 
|  | 3681   else | 
|  | 3682     _info "Error. The account was not updated." | 
|  | 3683     return 1 | 
|  | 3684   fi | 
|  | 3685 } | 
|  | 3686 | 
|  | 3687 #Implement deactivate account | 
|  | 3688 deactivateaccount() { | 
|  | 3689   _initpath | 
|  | 3690 | 
|  | 3691   if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then | 
|  | 3692     _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" | 
|  | 3693     mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" | 
|  | 3694   fi | 
|  | 3695 | 
|  | 3696   if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then | 
|  | 3697     _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" | 
|  | 3698     mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" | 
|  | 3699   fi | 
|  | 3700 | 
|  | 3701   if [ ! -f "$ACCOUNT_KEY_PATH" ]; then | 
|  | 3702     _err "Account key is not found at: $ACCOUNT_KEY_PATH" | 
|  | 3703     return 1 | 
|  | 3704   fi | 
|  | 3705 | 
|  | 3706   _accUri=$(_readcaconf "ACCOUNT_URL") | 
|  | 3707   _debug _accUri "$_accUri" | 
|  | 3708 | 
|  | 3709   if [ -z "$_accUri" ]; then | 
|  | 3710     _err "The account url is empty, please run '--update-account' first to update the account info first," | 
|  | 3711     _err "Then try again." | 
|  | 3712     return 1 | 
|  | 3713   fi | 
|  | 3714 | 
|  | 3715   if ! _calcjwk "$ACCOUNT_KEY_PATH"; then | 
|  | 3716     return 1 | 
|  | 3717   fi | 
|  | 3718   _initAPI | 
|  | 3719 | 
|  | 3720   if [ "$ACME_VERSION" = "2" ]; then | 
|  | 3721     _djson="{\"status\":\"deactivated\"}" | 
|  | 3722   else | 
|  | 3723     _djson="{\"resource\": \"reg\", \"status\":\"deactivated\"}" | 
|  | 3724   fi | 
|  | 3725   if _send_signed_request "$_accUri" "$_djson" && _contains "$response" '"deactivated"'; then | 
|  | 3726     _info "Deactivate account success for $_accUri." | 
|  | 3727     _accid=$(echo "$response" | _egrep_o "\"id\" *: *[^,]*," | cut -d : -f 2 | tr -d ' ,') | 
|  | 3728   elif [ "$code" = "403" ]; then | 
|  | 3729     _info "The account is already deactivated." | 
|  | 3730     _accid=$(_getfield "$_accUri" "999" "/") | 
|  | 3731   else | 
|  | 3732     _err "Deactivate: account failed for $_accUri." | 
|  | 3733     return 1 | 
|  | 3734   fi | 
|  | 3735 | 
|  | 3736   _debug "Account id: $_accid" | 
|  | 3737   if [ "$_accid" ]; then | 
|  | 3738     _deactivated_account_path="$CA_DIR/deactivated/$_accid" | 
|  | 3739     _debug _deactivated_account_path "$_deactivated_account_path" | 
|  | 3740     if mkdir -p "$_deactivated_account_path"; then | 
|  | 3741       _info "Moving deactivated account info to $_deactivated_account_path/" | 
|  | 3742       mv "$CA_CONF" "$_deactivated_account_path/" | 
|  | 3743       mv "$ACCOUNT_JSON_PATH" "$_deactivated_account_path/" | 
|  | 3744       mv "$ACCOUNT_KEY_PATH" "$_deactivated_account_path/" | 
|  | 3745     else | 
|  | 3746       _err "Can not create dir: $_deactivated_account_path, try to remove the deactivated account key." | 
|  | 3747       rm -f "$CA_CONF" | 
|  | 3748       rm -f "$ACCOUNT_JSON_PATH" | 
|  | 3749       rm -f "$ACCOUNT_KEY_PATH" | 
|  | 3750     fi | 
|  | 3751   fi | 
|  | 3752 } | 
|  | 3753 | 
|  | 3754 # domain folder  file | 
|  | 3755 _findHook() { | 
|  | 3756   _hookdomain="$1" | 
|  | 3757   _hookcat="$2" | 
|  | 3758   _hookname="$3" | 
|  | 3759 | 
|  | 3760   if [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname" ]; then | 
|  | 3761     d_api="$_SCRIPT_HOME/$_hookcat/$_hookname" | 
|  | 3762   elif [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname.sh" ]; then | 
|  | 3763     d_api="$_SCRIPT_HOME/$_hookcat/$_hookname.sh" | 
|  | 3764   elif [ "$_hookdomain" ] && [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ]; then | 
|  | 3765     d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname" | 
|  | 3766   elif [ "$_hookdomain" ] && [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ]; then | 
|  | 3767     d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" | 
|  | 3768   elif [ -f "$LE_WORKING_DIR/$_hookname" ]; then | 
|  | 3769     d_api="$LE_WORKING_DIR/$_hookname" | 
|  | 3770   elif [ -f "$LE_WORKING_DIR/$_hookname.sh" ]; then | 
|  | 3771     d_api="$LE_WORKING_DIR/$_hookname.sh" | 
|  | 3772   elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname" ]; then | 
|  | 3773     d_api="$LE_WORKING_DIR/$_hookcat/$_hookname" | 
|  | 3774   elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname.sh" ]; then | 
|  | 3775     d_api="$LE_WORKING_DIR/$_hookcat/$_hookname.sh" | 
|  | 3776   fi | 
|  | 3777 | 
|  | 3778   printf "%s" "$d_api" | 
|  | 3779 } | 
|  | 3780 | 
|  | 3781 #domain | 
|  | 3782 __get_domain_new_authz() { | 
|  | 3783   _gdnd="$1" | 
|  | 3784   _info "Getting new-authz for domain" "$_gdnd" | 
|  | 3785   _initAPI | 
|  | 3786   _Max_new_authz_retry_times=5 | 
|  | 3787   _authz_i=0 | 
|  | 3788   while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do | 
|  | 3789     _debug "Try new-authz for the $_authz_i time." | 
|  | 3790     if ! _send_signed_request "${ACME_NEW_AUTHZ}" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then | 
|  | 3791       _err "Can not get domain new authz." | 
|  | 3792       return 1 | 
|  | 3793     fi | 
|  | 3794     if _contains "$response" "No registration exists matching provided key"; then | 
|  | 3795       _err "It seems there is an error, but it's recovered now, please try again." | 
|  | 3796       _err "If you see this message for a second time, please report bug: $(__green "$PROJECT")" | 
|  | 3797       _clearcaconf "CA_KEY_HASH" | 
|  | 3798       break | 
|  | 3799     fi | 
|  | 3800     if ! _contains "$response" "An error occurred while processing your request"; then | 
|  | 3801       _info "The new-authz request is ok." | 
|  | 3802       break | 
|  | 3803     fi | 
|  | 3804     _authz_i="$(_math "$_authz_i" + 1)" | 
|  | 3805     _info "The server is busy, Sleep $_authz_i to retry." | 
|  | 3806     _sleep "$_authz_i" | 
|  | 3807   done | 
|  | 3808 | 
|  | 3809   if [ "$_authz_i" = "$_Max_new_authz_retry_times" ]; then | 
|  | 3810     _err "new-authz retry reach the max $_Max_new_authz_retry_times times." | 
|  | 3811   fi | 
|  | 3812 | 
|  | 3813   if [ "$code" ] && [ "$code" != '201' ]; then | 
|  | 3814     _err "new-authz error: $response" | 
|  | 3815     return 1 | 
|  | 3816   fi | 
|  | 3817 | 
|  | 3818 } | 
|  | 3819 | 
|  | 3820 #uri keyAuthorization | 
|  | 3821 __trigger_validation() { | 
|  | 3822   _debug2 "Trigger domain validation." | 
|  | 3823   _t_url="$1" | 
|  | 3824   _debug2 _t_url "$_t_url" | 
|  | 3825   _t_key_authz="$2" | 
|  | 3826   _debug2 _t_key_authz "$_t_key_authz" | 
|  | 3827   _t_vtype="$3" | 
|  | 3828   _debug2 _t_vtype "$_t_vtype" | 
|  | 3829   if [ "$ACME_VERSION" = "2" ]; then | 
|  | 3830     _send_signed_request "$_t_url" "{}" | 
|  | 3831   else | 
|  | 3832     _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"type\": \"$_t_vtype\", \"keyAuthorization\": \"$_t_key_authz\"}" | 
|  | 3833   fi | 
|  | 3834 } | 
|  | 3835 | 
|  | 3836 #endpoint  domain type | 
|  | 3837 _ns_lookup_impl() { | 
|  | 3838   _ns_ep="$1" | 
|  | 3839   _ns_domain="$2" | 
|  | 3840   _ns_type="$3" | 
|  | 3841   _debug2 "_ns_ep" "$_ns_ep" | 
|  | 3842   _debug2 "_ns_domain" "$_ns_domain" | 
|  | 3843   _debug2 "_ns_type" "$_ns_type" | 
|  | 3844 | 
|  | 3845   response="$(_H1="accept: application/dns-json" _get "$_ns_ep?name=$_ns_domain&type=$_ns_type")" | 
|  | 3846   _ret=$? | 
|  | 3847   _debug2 "response" "$response" | 
|  | 3848   if [ "$_ret" != "0" ]; then | 
|  | 3849     return $_ret | 
|  | 3850   fi | 
|  | 3851   _answers="$(echo "$response" | tr '{}' '<>' | _egrep_o '"Answer":\[[^]]*]' | tr '<>' '\n\n')" | 
|  | 3852   _debug2 "_answers" "$_answers" | 
|  | 3853   echo "$_answers" | 
|  | 3854 } | 
|  | 3855 | 
|  | 3856 #domain, type | 
|  | 3857 _ns_lookup_cf() { | 
|  | 3858   _cf_ld="$1" | 
|  | 3859   _cf_ld_type="$2" | 
|  | 3860   _cf_ep="https://cloudflare-dns.com/dns-query" | 
|  | 3861   _ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type" | 
|  | 3862 } | 
|  | 3863 | 
|  | 3864 #domain, type | 
|  | 3865 _ns_purge_cf() { | 
|  | 3866   _cf_d="$1" | 
|  | 3867   _cf_d_type="$2" | 
|  | 3868   _debug "Cloudflare purge $_cf_d_type record for domain $_cf_d" | 
|  | 3869   _cf_purl="https://cloudflare-dns.com/api/v1/purge?domain=$_cf_d&type=$_cf_d_type" | 
|  | 3870   response="$(_post "" "$_cf_purl")" | 
|  | 3871   _debug2 response "$response" | 
|  | 3872 } | 
|  | 3873 | 
|  | 3874 #checks if cf server is available | 
|  | 3875 _ns_is_available_cf() { | 
|  | 3876   if _get "https://cloudflare-dns.com" >/dev/null 2>&1; then | 
|  | 3877     return 0 | 
|  | 3878   else | 
|  | 3879     return 1 | 
|  | 3880   fi | 
|  | 3881 } | 
|  | 3882 | 
|  | 3883 #domain, type | 
|  | 3884 _ns_lookup_google() { | 
|  | 3885   _cf_ld="$1" | 
|  | 3886   _cf_ld_type="$2" | 
|  | 3887   _cf_ep="https://dns.google/resolve" | 
|  | 3888   _ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type" | 
|  | 3889 } | 
|  | 3890 | 
|  | 3891 #domain, type | 
|  | 3892 _ns_lookup() { | 
|  | 3893   if [ -z "$DOH_USE" ]; then | 
|  | 3894     _debug "Detect dns server first." | 
|  | 3895     if _ns_is_available_cf; then | 
|  | 3896       _debug "Use cloudflare doh server" | 
|  | 3897       export DOH_USE=$DOH_CLOUDFLARE | 
|  | 3898     else | 
|  | 3899       _debug "Use google doh server" | 
|  | 3900       export DOH_USE=$DOH_GOOGLE | 
|  | 3901     fi | 
|  | 3902   fi | 
|  | 3903 | 
|  | 3904   if [ "$DOH_USE" = "$DOH_CLOUDFLARE" ] || [ -z "$DOH_USE" ]; then | 
|  | 3905     _ns_lookup_cf "$@" | 
|  | 3906   else | 
|  | 3907     _ns_lookup_google "$@" | 
|  | 3908   fi | 
|  | 3909 | 
|  | 3910 } | 
|  | 3911 | 
|  | 3912 #txtdomain, alias, txt | 
|  | 3913 __check_txt() { | 
|  | 3914   _c_txtdomain="$1" | 
|  | 3915   _c_aliasdomain="$2" | 
|  | 3916   _c_txt="$3" | 
|  | 3917   _debug "_c_txtdomain" "$_c_txtdomain" | 
|  | 3918   _debug "_c_aliasdomain" "$_c_aliasdomain" | 
|  | 3919   _debug "_c_txt" "$_c_txt" | 
|  | 3920   _answers="$(_ns_lookup "$_c_aliasdomain" TXT)" | 
|  | 3921   _contains "$_answers" "$_c_txt" | 
|  | 3922 | 
|  | 3923 } | 
|  | 3924 | 
|  | 3925 #txtdomain | 
|  | 3926 __purge_txt() { | 
|  | 3927   _p_txtdomain="$1" | 
|  | 3928   _debug _p_txtdomain "$_p_txtdomain" | 
|  | 3929   if [ "$DOH_USE" = "$DOH_CLOUDFLARE" ] || [ -z "$DOH_USE" ]; then | 
|  | 3930     _ns_purge_cf "$_p_txtdomain" "TXT" | 
|  | 3931   else | 
|  | 3932     _debug "no purge api for google dns api, just sleep 5 secs" | 
|  | 3933     _sleep 5 | 
|  | 3934   fi | 
|  | 3935 | 
|  | 3936 } | 
|  | 3937 | 
|  | 3938 #wait and check each dns entries | 
|  | 3939 _check_dns_entries() { | 
|  | 3940   _success_txt="," | 
|  | 3941   _end_time="$(_time)" | 
|  | 3942   _end_time="$(_math "$_end_time" + 1200)" #let's check no more than 20 minutes. | 
|  | 3943 | 
|  | 3944   while [ "$(_time)" -le "$_end_time" ]; do | 
|  | 3945     _left="" | 
|  | 3946     for entry in $dns_entries; do | 
|  | 3947       d=$(_getfield "$entry" 1) | 
|  | 3948       txtdomain=$(_getfield "$entry" 2) | 
|  | 3949       txtdomain=$(_idn "$txtdomain") | 
|  | 3950       aliasDomain=$(_getfield "$entry" 3) | 
|  | 3951       aliasDomain=$(_idn "$aliasDomain") | 
|  | 3952       txt=$(_getfield "$entry" 5) | 
|  | 3953       d_api=$(_getfield "$entry" 6) | 
|  | 3954       _debug "d" "$d" | 
|  | 3955       _debug "txtdomain" "$txtdomain" | 
|  | 3956       _debug "aliasDomain" "$aliasDomain" | 
|  | 3957       _debug "txt" "$txt" | 
|  | 3958       _debug "d_api" "$d_api" | 
|  | 3959       _info "Checking $d for $aliasDomain" | 
|  | 3960       if _contains "$_success_txt" ",$txt,"; then | 
|  | 3961         _info "Already success, continue next one." | 
|  | 3962         continue | 
|  | 3963       fi | 
|  | 3964 | 
|  | 3965       if __check_txt "$txtdomain" "$aliasDomain" "$txt"; then | 
|  | 3966         _info "Domain $d '$aliasDomain' success." | 
|  | 3967         _success_txt="$_success_txt,$txt," | 
|  | 3968         continue | 
|  | 3969       fi | 
|  | 3970       _left=1 | 
|  | 3971       _info "Not valid yet, let's wait 10 seconds and check next one." | 
|  | 3972       __purge_txt "$txtdomain" | 
|  | 3973       if [ "$txtdomain" != "$aliasDomain" ]; then | 
|  | 3974         __purge_txt "$aliasDomain" | 
|  | 3975       fi | 
|  | 3976       _sleep 10 | 
|  | 3977     done | 
|  | 3978     if [ "$_left" ]; then | 
|  | 3979       _info "Let's wait 10 seconds and check again". | 
|  | 3980       _sleep 10 | 
|  | 3981     else | 
|  | 3982       _info "All success, let's return" | 
|  | 3983       return 0 | 
|  | 3984     fi | 
|  | 3985   done | 
|  | 3986   _info "Timed out waiting for DNS." | 
|  | 3987   return 1 | 
|  | 3988 | 
|  | 3989 } | 
|  | 3990 | 
|  | 3991 #file | 
|  | 3992 _get_cert_issuers() { | 
|  | 3993   _cfile="$1" | 
|  | 3994   if _contains "$(${ACME_OPENSSL_BIN:-openssl} help crl2pkcs7 2>&1)" "Usage: crl2pkcs7"; then | 
|  | 3995     ${ACME_OPENSSL_BIN:-openssl} crl2pkcs7 -nocrl -certfile $_cfile | ${ACME_OPENSSL_BIN:-openssl} pkcs7 -print_certs -text -noout | grep 'Issuer:' | _egrep_o "CN *=[^,]*" | cut -d = -f 2 | 
|  | 3996   else | 
|  | 3997     ${ACME_OPENSSL_BIN:-openssl} x509 -in $_cfile -text -noout | grep 'Issuer:' | _egrep_o "CN *=[^,]*" | cut -d = -f 2 | 
|  | 3998   fi | 
|  | 3999 } | 
|  | 4000 | 
|  | 4001 #cert  issuer | 
|  | 4002 _match_issuer() { | 
|  | 4003   _cfile="$1" | 
|  | 4004   _missuer="$2" | 
|  | 4005   _fissuers="$(_get_cert_issuers $_cfile)" | 
|  | 4006   _debug2 _fissuers "$_fissuers" | 
|  | 4007   if _contains "$_fissuers" "$_missuer"; then | 
|  | 4008     return 0 | 
|  | 4009   fi | 
|  | 4010   _fissuers="$(echo "$_fissuers" | _lower_case)" | 
|  | 4011   _missuer="$(echo "$_missuer" | _lower_case)" | 
|  | 4012   _contains "$_fissuers" "$_missuer" | 
|  | 4013 } | 
|  | 4014 | 
|  | 4015 #webroot, domain domainlist  keylength | 
|  | 4016 issue() { | 
|  | 4017   if [ -z "$2" ]; then | 
|  | 4018     _usage "Usage: $PROJECT_ENTRY --issue --domain <domain.tld> --webroot <directory>" | 
|  | 4019     return 1 | 
|  | 4020   fi | 
|  | 4021   if [ -z "$1" ]; then | 
|  | 4022     _usage "Please specify at least one validation method: '--webroot', '--standalone', '--apache', '--nginx' or '--dns' etc." | 
|  | 4023     return 1 | 
|  | 4024   fi | 
|  | 4025   _web_roots="$1" | 
|  | 4026   _main_domain="$2" | 
|  | 4027   _alt_domains="$3" | 
|  | 4028 | 
|  | 4029   if _contains "$_main_domain" ","; then | 
|  | 4030     _main_domain=$(echo "$2,$3" | cut -d , -f 1) | 
|  | 4031     _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") | 
|  | 4032   fi | 
|  | 4033   _debug _main_domain "$_main_domain" | 
|  | 4034   _debug _alt_domains "$_alt_domains" | 
|  | 4035 | 
|  | 4036   _key_length="$4" | 
|  | 4037   _real_cert="$5" | 
|  | 4038   _real_key="$6" | 
|  | 4039   _real_ca="$7" | 
|  | 4040   _reload_cmd="$8" | 
|  | 4041   _real_fullchain="$9" | 
|  | 4042   _pre_hook="${10}" | 
|  | 4043   _post_hook="${11}" | 
|  | 4044   _renew_hook="${12}" | 
|  | 4045   _local_addr="${13}" | 
|  | 4046   _challenge_alias="${14}" | 
|  | 4047   _preferred_chain="${15}" | 
|  | 4048 | 
|  | 4049   if [ -z "$_ACME_IS_RENEW" ]; then | 
|  | 4050     _initpath "$_main_domain" "$_key_length" | 
|  | 4051     mkdir -p "$DOMAIN_PATH" | 
|  | 4052   fi | 
|  | 4053 | 
|  | 4054   if _hasfield "$_web_roots" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then | 
|  | 4055     _err "$_DNS_MANUAL_ERROR" | 
|  | 4056     return 1 | 
|  | 4057   fi | 
|  | 4058 | 
|  | 4059   _debug "Using ACME_DIRECTORY: $ACME_DIRECTORY" | 
|  | 4060 | 
|  | 4061   _initAPI | 
|  | 4062 | 
|  | 4063   if [ -f "$DOMAIN_CONF" ]; then | 
|  | 4064     Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) | 
|  | 4065     _debug Le_NextRenewTime "$Le_NextRenewTime" | 
|  | 4066     if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then | 
|  | 4067       _saved_domain=$(_readdomainconf Le_Domain) | 
|  | 4068       _debug _saved_domain "$_saved_domain" | 
|  | 4069       _saved_alt=$(_readdomainconf Le_Alt) | 
|  | 4070       _debug _saved_alt "$_saved_alt" | 
|  | 4071       if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$_alt_domains" ]; then | 
|  | 4072         _info "Domains not changed." | 
|  | 4073         _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" | 
|  | 4074         _info "Add '$(__red '--force')' to force to renew." | 
|  | 4075         return $RENEW_SKIP | 
|  | 4076       else | 
|  | 4077         _info "Domains have changed." | 
|  | 4078       fi | 
|  | 4079     fi | 
|  | 4080   fi | 
|  | 4081 | 
|  | 4082   _savedomainconf "Le_Domain" "$_main_domain" | 
|  | 4083   _savedomainconf "Le_Alt" "$_alt_domains" | 
|  | 4084   _savedomainconf "Le_Webroot" "$_web_roots" | 
|  | 4085 | 
|  | 4086   _savedomainconf "Le_PreHook" "$_pre_hook" "base64" | 
|  | 4087   _savedomainconf "Le_PostHook" "$_post_hook" "base64" | 
|  | 4088   _savedomainconf "Le_RenewHook" "$_renew_hook" "base64" | 
|  | 4089 | 
|  | 4090   if [ "$_local_addr" ]; then | 
|  | 4091     _savedomainconf "Le_LocalAddress" "$_local_addr" | 
|  | 4092   else | 
|  | 4093     _cleardomainconf "Le_LocalAddress" | 
|  | 4094   fi | 
|  | 4095   if [ "$_challenge_alias" ]; then | 
|  | 4096     _savedomainconf "Le_ChallengeAlias" "$_challenge_alias" | 
|  | 4097   else | 
|  | 4098     _cleardomainconf "Le_ChallengeAlias" | 
|  | 4099   fi | 
|  | 4100   if [ "$_preferred_chain" ]; then | 
|  | 4101     _savedomainconf "Le_Preferred_Chain" "$_preferred_chain" "base64" | 
|  | 4102   else | 
|  | 4103     _cleardomainconf "Le_Preferred_Chain" | 
|  | 4104   fi | 
|  | 4105 | 
|  | 4106   Le_API="$ACME_DIRECTORY" | 
|  | 4107   _savedomainconf "Le_API" "$Le_API" | 
|  | 4108 | 
|  | 4109   _info "Using CA: $ACME_DIRECTORY" | 
|  | 4110   if [ "$_alt_domains" = "$NO_VALUE" ]; then | 
|  | 4111     _alt_domains="" | 
|  | 4112   fi | 
|  | 4113 | 
|  | 4114   if [ "$_key_length" = "$NO_VALUE" ]; then | 
|  | 4115     _key_length="" | 
|  | 4116   fi | 
|  | 4117 | 
|  | 4118   if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then | 
|  | 4119     _err "_on_before_issue." | 
|  | 4120     return 1 | 
|  | 4121   fi | 
|  | 4122 | 
|  | 4123   _saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")" | 
|  | 4124   _debug2 _saved_account_key_hash "$_saved_account_key_hash" | 
|  | 4125 | 
|  | 4126   if [ -z "$ACCOUNT_URL" ] || [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then | 
|  | 4127     if ! _regAccount "$_accountkeylength"; then | 
|  | 4128       _on_issue_err "$_post_hook" | 
|  | 4129       return 1 | 
|  | 4130     fi | 
|  | 4131   else | 
|  | 4132     _debug "_saved_account_key_hash is not changed, skip register account." | 
|  | 4133   fi | 
|  | 4134 | 
|  | 4135   if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ]; then | 
|  | 4136     _info "Signing from existing CSR." | 
|  | 4137   else | 
|  | 4138     _key=$(_readdomainconf Le_Keylength) | 
|  | 4139     _debug "Read key length:$_key" | 
|  | 4140     if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ] || [ "$Le_ForceNewDomainKey" = "1" ]; then | 
|  | 4141       if ! createDomainKey "$_main_domain" "$_key_length"; then | 
|  | 4142         _err "Create domain key error." | 
|  | 4143         _clearup | 
|  | 4144         _on_issue_err "$_post_hook" | 
|  | 4145         return 1 | 
|  | 4146       fi | 
|  | 4147     fi | 
|  | 4148 | 
|  | 4149     if ! _createcsr "$_main_domain" "$_alt_domains" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then | 
|  | 4150       _err "Create CSR error." | 
|  | 4151       _clearup | 
|  | 4152       _on_issue_err "$_post_hook" | 
|  | 4153       return 1 | 
|  | 4154     fi | 
|  | 4155   fi | 
|  | 4156 | 
|  | 4157   _savedomainconf "Le_Keylength" "$_key_length" | 
|  | 4158 | 
|  | 4159   vlist="$Le_Vlist" | 
|  | 4160   _cleardomainconf "Le_Vlist" | 
|  | 4161   _info "Getting domain auth token for each domain" | 
|  | 4162   sep='#' | 
|  | 4163   dvsep=',' | 
|  | 4164   if [ -z "$vlist" ]; then | 
|  | 4165     if [ "$ACME_VERSION" = "2" ]; then | 
|  | 4166       #make new order request | 
|  | 4167       _identifiers="{\"type\":\"dns\",\"value\":\"$(_idn "$_main_domain")\"}" | 
|  | 4168       _w_index=1 | 
|  | 4169       while true; do | 
|  | 4170         d="$(echo "$_alt_domains," | cut -d , -f "$_w_index")" | 
|  | 4171         _w_index="$(_math "$_w_index" + 1)" | 
|  | 4172         _debug d "$d" | 
|  | 4173         if [ -z "$d" ]; then | 
|  | 4174           break | 
|  | 4175         fi | 
|  | 4176         _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$(_idn "$d")\"}" | 
|  | 4177       done | 
|  | 4178       _debug2 _identifiers "$_identifiers" | 
|  | 4179       if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then | 
|  | 4180         _err "Create new order error." | 
|  | 4181         _clearup | 
|  | 4182         _on_issue_err "$_post_hook" | 
|  | 4183         return 1 | 
|  | 4184       fi | 
|  | 4185       Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n " | cut -d ":" -f 2-)" | 
|  | 4186       _debug Le_LinkOrder "$Le_LinkOrder" | 
|  | 4187       Le_OrderFinalize="$(echo "$response" | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" | 
|  | 4188       _debug Le_OrderFinalize "$Le_OrderFinalize" | 
|  | 4189       if [ -z "$Le_OrderFinalize" ]; then | 
|  | 4190         _err "Create new order error. Le_OrderFinalize not found. $response" | 
|  | 4191         _clearup | 
|  | 4192         _on_issue_err "$_post_hook" | 
|  | 4193         return 1 | 
|  | 4194       fi | 
|  | 4195 | 
|  | 4196       #for dns manual mode | 
|  | 4197       _savedomainconf "Le_OrderFinalize" "$Le_OrderFinalize" | 
|  | 4198 | 
|  | 4199       _authorizations_seg="$(echo "$response" | _json_decode | _egrep_o '"authorizations" *: *\[[^\[]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" | 
|  | 4200       _debug2 _authorizations_seg "$_authorizations_seg" | 
|  | 4201       if [ -z "$_authorizations_seg" ]; then | 
|  | 4202         _err "_authorizations_seg not found." | 
|  | 4203         _clearup | 
|  | 4204         _on_issue_err "$_post_hook" | 
|  | 4205         return 1 | 
|  | 4206       fi | 
|  | 4207 | 
|  | 4208       #domain and authz map | 
|  | 4209       _authorizations_map="" | 
|  | 4210       for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' '); do | 
|  | 4211         _debug2 "_authz_url" "$_authz_url" | 
|  | 4212         if ! _send_signed_request "$_authz_url"; then | 
|  | 4213           _err "get to authz error." | 
|  | 4214           _err "_authorizations_seg" "$_authorizations_seg" | 
|  | 4215           _err "_authz_url" "$_authz_url" | 
|  | 4216           _clearup | 
|  | 4217           _on_issue_err "$_post_hook" | 
|  | 4218           return 1 | 
|  | 4219         fi | 
|  | 4220 | 
|  | 4221         response="$(echo "$response" | _normalizeJson)" | 
|  | 4222         _debug2 response "$response" | 
|  | 4223         _d="$(echo "$response" | _egrep_o '"value" *: *"[^"]*"' | cut -d : -f 2 | tr -d ' "')" | 
|  | 4224         if _contains "$response" "\"wildcard\" *: *true"; then | 
|  | 4225           _d="*.$_d" | 
|  | 4226         fi | 
|  | 4227         _debug2 _d "$_d" | 
|  | 4228         _authorizations_map="$_d,$response | 
|  | 4229 $_authorizations_map" | 
|  | 4230       done | 
|  | 4231       _debug2 _authorizations_map "$_authorizations_map" | 
|  | 4232     fi | 
|  | 4233 | 
|  | 4234     _index=0 | 
|  | 4235     _currentRoot="" | 
|  | 4236     _w_index=1 | 
|  | 4237     while true; do | 
|  | 4238       d="$(echo "$_main_domain,$_alt_domains," | cut -d , -f "$_w_index")" | 
|  | 4239       _w_index="$(_math "$_w_index" + 1)" | 
|  | 4240       _debug d "$d" | 
|  | 4241       if [ -z "$d" ]; then | 
|  | 4242         break | 
|  | 4243       fi | 
|  | 4244       _info "Getting webroot for domain" "$d" | 
|  | 4245       _index=$(_math $_index + 1) | 
|  | 4246       _w="$(echo $_web_roots | cut -d , -f $_index)" | 
|  | 4247       _debug _w "$_w" | 
|  | 4248       if [ "$_w" ]; then | 
|  | 4249         _currentRoot="$_w" | 
|  | 4250       fi | 
|  | 4251       _debug "_currentRoot" "$_currentRoot" | 
|  | 4252 | 
|  | 4253       vtype="$VTYPE_HTTP" | 
|  | 4254       #todo, v2 wildcard force to use dns | 
|  | 4255       if _startswith "$_currentRoot" "$W_DNS"; then | 
|  | 4256         vtype="$VTYPE_DNS" | 
|  | 4257       fi | 
|  | 4258 | 
|  | 4259       if [ "$_currentRoot" = "$W_ALPN" ]; then | 
|  | 4260         vtype="$VTYPE_ALPN" | 
|  | 4261       fi | 
|  | 4262 | 
|  | 4263       if [ "$ACME_VERSION" = "2" ]; then | 
|  | 4264         _idn_d="$(_idn "$d")" | 
|  | 4265         _candidates="$(echo "$_authorizations_map" | grep -i "^$_idn_d,")" | 
|  | 4266         _debug2 _candidates "$_candidates" | 
|  | 4267         if [ "$(echo "$_candidates" | wc -l)" -gt 1 ]; then | 
|  | 4268           for _can in $_candidates; do | 
|  | 4269             if _startswith "$(echo "$_can" | tr '.' '|')" "$(echo "$_idn_d" | tr '.' '|'),"; then | 
|  | 4270               _candidates="$_can" | 
|  | 4271               break | 
|  | 4272             fi | 
|  | 4273           done | 
|  | 4274         fi | 
|  | 4275         response="$(echo "$_candidates" | sed "s/$_idn_d,//")" | 
|  | 4276         _debug2 "response" "$response" | 
|  | 4277         if [ -z "$response" ]; then | 
|  | 4278           _err "get to authz error." | 
|  | 4279           _err "_authorizations_map" "$_authorizations_map" | 
|  | 4280           _clearup | 
|  | 4281           _on_issue_err "$_post_hook" | 
|  | 4282           return 1 | 
|  | 4283         fi | 
|  | 4284       else | 
|  | 4285         if ! __get_domain_new_authz "$d"; then | 
|  | 4286           _clearup | 
|  | 4287           _on_issue_err "$_post_hook" | 
|  | 4288           return 1 | 
|  | 4289         fi | 
|  | 4290       fi | 
|  | 4291 | 
|  | 4292       if [ -z "$thumbprint" ]; then | 
|  | 4293         thumbprint="$(__calc_account_thumbprint)" | 
|  | 4294       fi | 
|  | 4295 | 
|  | 4296       entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" | 
|  | 4297       _debug entry "$entry" | 
|  | 4298       keyauthorization="" | 
|  | 4299       if [ -z "$entry" ]; then | 
|  | 4300         if ! _startswith "$d" '*.'; then | 
|  | 4301           _debug "Not a wildcard domain, lets check whether the validation is already valid." | 
|  | 4302           if echo "$response" | grep '"status":"valid"' >/dev/null 2>&1; then | 
|  | 4303             _debug "$d is already valid." | 
|  | 4304             keyauthorization="$STATE_VERIFIED" | 
|  | 4305             _debug keyauthorization "$keyauthorization" | 
|  | 4306           fi | 
|  | 4307         fi | 
|  | 4308         if [ -z "$keyauthorization" ]; then | 
|  | 4309           _err "Error, can not get domain token entry $d for $vtype" | 
|  | 4310           _supported_vtypes="$(echo "$response" | _egrep_o "\"challenges\":\[[^]]*]" | tr '{' "\n" | grep type | cut -d '"' -f 4 | tr "\n" ' ')" | 
|  | 4311           if [ "$_supported_vtypes" ]; then | 
|  | 4312             _err "The supported validation types are: $_supported_vtypes, but you specified: $vtype" | 
|  | 4313           fi | 
|  | 4314           _clearup | 
|  | 4315           _on_issue_err "$_post_hook" | 
|  | 4316           return 1 | 
|  | 4317         fi | 
|  | 4318       fi | 
|  | 4319 | 
|  | 4320       if [ -z "$keyauthorization" ]; then | 
|  | 4321         token="$(echo "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" | 
|  | 4322         _debug token "$token" | 
|  | 4323 | 
|  | 4324         if [ -z "$token" ]; then | 
|  | 4325           _err "Error, can not get domain token $entry" | 
|  | 4326           _clearup | 
|  | 4327           _on_issue_err "$_post_hook" | 
|  | 4328           return 1 | 
|  | 4329         fi | 
|  | 4330         if [ "$ACME_VERSION" = "2" ]; then | 
|  | 4331           uri="$(echo "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)" | 
|  | 4332         else | 
|  | 4333           uri="$(echo "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)" | 
|  | 4334         fi | 
|  | 4335         _debug uri "$uri" | 
|  | 4336 | 
|  | 4337         if [ -z "$uri" ]; then | 
|  | 4338           _err "Error, can not get domain uri. $entry" | 
|  | 4339           _clearup | 
|  | 4340           _on_issue_err "$_post_hook" | 
|  | 4341           return 1 | 
|  | 4342         fi | 
|  | 4343         keyauthorization="$token.$thumbprint" | 
|  | 4344         _debug keyauthorization "$keyauthorization" | 
|  | 4345 | 
|  | 4346         if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then | 
|  | 4347           _debug "$d is already verified." | 
|  | 4348           keyauthorization="$STATE_VERIFIED" | 
|  | 4349           _debug keyauthorization "$keyauthorization" | 
|  | 4350         fi | 
|  | 4351       fi | 
|  | 4352 | 
|  | 4353       dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot" | 
|  | 4354       _debug dvlist "$dvlist" | 
|  | 4355 | 
|  | 4356       vlist="$vlist$dvlist$dvsep" | 
|  | 4357 | 
|  | 4358     done | 
|  | 4359     _debug vlist "$vlist" | 
|  | 4360     #add entry | 
|  | 4361     dns_entries="" | 
|  | 4362     dnsadded="" | 
|  | 4363     ventries=$(echo "$vlist" | tr "$dvsep" ' ') | 
|  | 4364     _alias_index=1 | 
|  | 4365     for ventry in $ventries; do | 
|  | 4366       d=$(echo "$ventry" | cut -d "$sep" -f 1) | 
|  | 4367       keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) | 
|  | 4368       vtype=$(echo "$ventry" | cut -d "$sep" -f 4) | 
|  | 4369       _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) | 
|  | 4370       _debug d "$d" | 
|  | 4371       if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then | 
|  | 4372         _debug "$d is already verified, skip $vtype." | 
|  | 4373         _alias_index="$(_math "$_alias_index" + 1)" | 
|  | 4374         continue | 
|  | 4375       fi | 
|  | 4376 | 
|  | 4377       if [ "$vtype" = "$VTYPE_DNS" ]; then | 
|  | 4378         dnsadded='0' | 
|  | 4379         _dns_root_d="$d" | 
|  | 4380         if _startswith "$_dns_root_d" "*."; then | 
|  | 4381           _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')" | 
|  | 4382         fi | 
|  | 4383         _d_alias="$(_getfield "$_challenge_alias" "$_alias_index")" | 
|  | 4384         _alias_index="$(_math "$_alias_index" + 1)" | 
|  | 4385         _debug "_d_alias" "$_d_alias" | 
|  | 4386         if [ "$_d_alias" ]; then | 
|  | 4387           if _startswith "$_d_alias" "$DNS_ALIAS_PREFIX"; then | 
|  | 4388             txtdomain="$(echo "$_d_alias" | sed "s/$DNS_ALIAS_PREFIX//")" | 
|  | 4389           else | 
|  | 4390             txtdomain="_acme-challenge.$_d_alias" | 
|  | 4391           fi | 
|  | 4392           dns_entry="${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$txtdomain$dvsep$_currentRoot" | 
|  | 4393         else | 
|  | 4394           txtdomain="_acme-challenge.$_dns_root_d" | 
|  | 4395           dns_entry="${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$dvsep$_currentRoot" | 
|  | 4396         fi | 
|  | 4397 | 
|  | 4398         _debug txtdomain "$txtdomain" | 
|  | 4399         txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" | 
|  | 4400         _debug txt "$txt" | 
|  | 4401 | 
|  | 4402         d_api="$(_findHook "$_dns_root_d" $_SUB_FOLDER_DNSAPI "$_currentRoot")" | 
|  | 4403         _debug d_api "$d_api" | 
|  | 4404 | 
|  | 4405         dns_entry="$dns_entry$dvsep$txt${dvsep}$d_api" | 
|  | 4406         _debug2 dns_entry "$dns_entry" | 
|  | 4407         if [ "$d_api" ]; then | 
|  | 4408           _debug "Found domain api file: $d_api" | 
|  | 4409         else | 
|  | 4410           if [ "$_currentRoot" != "$W_DNS" ]; then | 
|  | 4411             _err "Can not find dns api hook for: $_currentRoot" | 
|  | 4412             _info "You need to add the txt record manually." | 
|  | 4413           fi | 
|  | 4414           _info "$(__red "Add the following TXT record:")" | 
|  | 4415           _info "$(__red "Domain: '$(__green "$txtdomain")'")" | 
|  | 4416           _info "$(__red "TXT value: '$(__green "$txt")'")" | 
|  | 4417           _info "$(__red "Please be aware that you prepend _acme-challenge. before your domain")" | 
|  | 4418           _info "$(__red "so the resulting subdomain will be: $txtdomain")" | 
|  | 4419           continue | 
|  | 4420         fi | 
|  | 4421 | 
|  | 4422         ( | 
|  | 4423           if ! . "$d_api"; then | 
|  | 4424             _err "Load file $d_api error. Please check your api file and try again." | 
|  | 4425             return 1 | 
|  | 4426           fi | 
|  | 4427 | 
|  | 4428           addcommand="${_currentRoot}_add" | 
|  | 4429           if ! _exists "$addcommand"; then | 
|  | 4430             _err "It seems that your api file is not correct, it must have a function named: $addcommand" | 
|  | 4431             return 1 | 
|  | 4432           fi | 
|  | 4433           _info "Adding txt value: $txt for domain:  $txtdomain" | 
|  | 4434           if ! $addcommand "$txtdomain" "$txt"; then | 
|  | 4435             _err "Error add txt for domain:$txtdomain" | 
|  | 4436             return 1 | 
|  | 4437           fi | 
|  | 4438           _info "The txt record is added: Success." | 
|  | 4439         ) | 
|  | 4440 | 
|  | 4441         if [ "$?" != "0" ]; then | 
|  | 4442           _on_issue_err "$_post_hook" "$vlist" | 
|  | 4443           _clearup | 
|  | 4444           return 1 | 
|  | 4445         fi | 
|  | 4446         dns_entries="$dns_entries$dns_entry | 
|  | 4447 " | 
|  | 4448         _debug2 "$dns_entries" | 
|  | 4449         dnsadded='1' | 
|  | 4450       fi | 
|  | 4451     done | 
|  | 4452 | 
|  | 4453     if [ "$dnsadded" = '0' ]; then | 
|  | 4454       _savedomainconf "Le_Vlist" "$vlist" | 
|  | 4455       _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." | 
|  | 4456       _err "Please add the TXT records to the domains, and re-run with --renew." | 
|  | 4457       _on_issue_err "$_post_hook" | 
|  | 4458       _clearup | 
|  | 4459       return 1 | 
|  | 4460     fi | 
|  | 4461 | 
|  | 4462   fi | 
|  | 4463 | 
|  | 4464   if [ "$dns_entries" ]; then | 
|  | 4465     if [ -z "$Le_DNSSleep" ]; then | 
|  | 4466       _info "Let's check each DNS record now. Sleep 20 seconds first." | 
|  | 4467       _sleep 20 | 
|  | 4468       if ! _check_dns_entries; then | 
|  | 4469         _err "check dns error." | 
|  | 4470         _on_issue_err "$_post_hook" | 
|  | 4471         _clearup | 
|  | 4472         return 1 | 
|  | 4473       fi | 
|  | 4474     else | 
|  | 4475       _savedomainconf "Le_DNSSleep" "$Le_DNSSleep" | 
|  | 4476       _info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect" | 
|  | 4477       _sleep "$Le_DNSSleep" | 
|  | 4478     fi | 
|  | 4479   fi | 
|  | 4480 | 
|  | 4481   NGINX_RESTORE_VLIST="" | 
|  | 4482   _debug "ok, let's start to verify" | 
|  | 4483 | 
|  | 4484   _ncIndex=1 | 
|  | 4485   ventries=$(echo "$vlist" | tr "$dvsep" ' ') | 
|  | 4486   for ventry in $ventries; do | 
|  | 4487     d=$(echo "$ventry" | cut -d "$sep" -f 1) | 
|  | 4488     keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) | 
|  | 4489     uri=$(echo "$ventry" | cut -d "$sep" -f 3) | 
|  | 4490     vtype=$(echo "$ventry" | cut -d "$sep" -f 4) | 
|  | 4491     _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) | 
|  | 4492 | 
|  | 4493     if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then | 
|  | 4494       _info "$d is already verified, skip $vtype." | 
|  | 4495       continue | 
|  | 4496     fi | 
|  | 4497 | 
|  | 4498     _info "Verifying: $d" | 
|  | 4499     _debug "d" "$d" | 
|  | 4500     _debug "keyauthorization" "$keyauthorization" | 
|  | 4501     _debug "uri" "$uri" | 
|  | 4502     removelevel="" | 
|  | 4503     token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)" | 
|  | 4504 | 
|  | 4505     _debug "_currentRoot" "$_currentRoot" | 
|  | 4506 | 
|  | 4507     if [ "$vtype" = "$VTYPE_HTTP" ]; then | 
|  | 4508       if [ "$_currentRoot" = "$NO_VALUE" ]; then | 
|  | 4509         _info "Standalone mode server" | 
|  | 4510         _ncaddr="$(_getfield "$_local_addr" "$_ncIndex")" | 
|  | 4511         _ncIndex="$(_math $_ncIndex + 1)" | 
|  | 4512         _startserver "$keyauthorization" "$_ncaddr" | 
|  | 4513         if [ "$?" != "0" ]; then | 
|  | 4514           _clearup | 
|  | 4515           _on_issue_err "$_post_hook" "$vlist" | 
|  | 4516           return 1 | 
|  | 4517         fi | 
|  | 4518         sleep 1 | 
|  | 4519         _debug serverproc "$serverproc" | 
|  | 4520       elif [ "$_currentRoot" = "$MODE_STATELESS" ]; then | 
|  | 4521         _info "Stateless mode for domain:$d" | 
|  | 4522         _sleep 1 | 
|  | 4523       elif _startswith "$_currentRoot" "$NGINX"; then | 
|  | 4524         _info "Nginx mode for domain:$d" | 
|  | 4525         #set up nginx server | 
|  | 4526         FOUND_REAL_NGINX_CONF="" | 
|  | 4527         BACKUP_NGINX_CONF="" | 
|  | 4528         if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then | 
|  | 4529           _clearup | 
|  | 4530           _on_issue_err "$_post_hook" "$vlist" | 
|  | 4531           return 1 | 
|  | 4532         fi | 
|  | 4533 | 
|  | 4534         if [ "$FOUND_REAL_NGINX_CONF" ]; then | 
|  | 4535           _realConf="$FOUND_REAL_NGINX_CONF" | 
|  | 4536           _backup="$BACKUP_NGINX_CONF" | 
|  | 4537           _debug _realConf "$_realConf" | 
|  | 4538           NGINX_RESTORE_VLIST="$d$sep$_realConf$sep$_backup$dvsep$NGINX_RESTORE_VLIST" | 
|  | 4539         fi | 
|  | 4540         _sleep 1 | 
|  | 4541       else | 
|  | 4542         if [ "$_currentRoot" = "apache" ]; then | 
|  | 4543           wellknown_path="$ACME_DIR" | 
|  | 4544         else | 
|  | 4545           wellknown_path="$_currentRoot/.well-known/acme-challenge" | 
|  | 4546           if [ ! -d "$_currentRoot/.well-known" ]; then | 
|  | 4547             removelevel='1' | 
|  | 4548           elif [ ! -d "$_currentRoot/.well-known/acme-challenge" ]; then | 
|  | 4549             removelevel='2' | 
|  | 4550           else | 
|  | 4551             removelevel='3' | 
|  | 4552           fi | 
|  | 4553         fi | 
|  | 4554 | 
|  | 4555         _debug wellknown_path "$wellknown_path" | 
|  | 4556 | 
|  | 4557         _debug "writing token:$token to $wellknown_path/$token" | 
|  | 4558 | 
|  | 4559         mkdir -p "$wellknown_path" | 
|  | 4560 | 
|  | 4561         if ! printf "%s" "$keyauthorization" >"$wellknown_path/$token"; then | 
|  | 4562           _err "$d:Can not write token to file : $wellknown_path/$token" | 
|  | 4563           _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | 
|  | 4564           _clearup | 
|  | 4565           _on_issue_err "$_post_hook" "$vlist" | 
|  | 4566           return 1 | 
|  | 4567         fi | 
|  | 4568 | 
|  | 4569         if [ ! "$usingApache" ]; then | 
|  | 4570           if webroot_owner=$(_stat "$_currentRoot"); then | 
|  | 4571             _debug "Changing owner/group of .well-known to $webroot_owner" | 
|  | 4572             if ! _exec "chown -R \"$webroot_owner\" \"$_currentRoot/.well-known\""; then | 
|  | 4573               _debug "$(cat "$_EXEC_TEMP_ERR")" | 
|  | 4574               _exec_err >/dev/null 2>&1 | 
|  | 4575             fi | 
|  | 4576           else | 
|  | 4577             _debug "not changing owner/group of webroot" | 
|  | 4578           fi | 
|  | 4579         fi | 
|  | 4580 | 
|  | 4581       fi | 
|  | 4582     elif [ "$vtype" = "$VTYPE_ALPN" ]; then | 
|  | 4583       acmevalidationv1="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")" | 
|  | 4584       _debug acmevalidationv1 "$acmevalidationv1" | 
|  | 4585       if ! _starttlsserver "$d" "" "$Le_TLSPort" "$keyauthorization" "$_ncaddr" "$acmevalidationv1"; then | 
|  | 4586         _err "Start tls server error." | 
|  | 4587         _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | 
|  | 4588         _clearup | 
|  | 4589         _on_issue_err "$_post_hook" "$vlist" | 
|  | 4590         return 1 | 
|  | 4591       fi | 
|  | 4592     fi | 
|  | 4593 | 
|  | 4594     if ! __trigger_validation "$uri" "$keyauthorization" "$vtype"; then | 
|  | 4595       _err "$d:Can not get challenge: $response" | 
|  | 4596       _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | 
|  | 4597       _clearup | 
|  | 4598       _on_issue_err "$_post_hook" "$vlist" | 
|  | 4599       return 1 | 
|  | 4600     fi | 
|  | 4601 | 
|  | 4602     if [ "$code" ] && [ "$code" != '202' ]; then | 
|  | 4603       if [ "$code" = '200' ]; then | 
|  | 4604         _debug "trigger validation code: $code" | 
|  | 4605       else | 
|  | 4606         _err "$d:Challenge error: $response" | 
|  | 4607         _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | 
|  | 4608         _clearup | 
|  | 4609         _on_issue_err "$_post_hook" "$vlist" | 
|  | 4610         return 1 | 
|  | 4611       fi | 
|  | 4612     fi | 
|  | 4613 | 
|  | 4614     waittimes=0 | 
|  | 4615     if [ -z "$MAX_RETRY_TIMES" ]; then | 
|  | 4616       MAX_RETRY_TIMES=30 | 
|  | 4617     fi | 
|  | 4618 | 
|  | 4619     while true; do | 
|  | 4620       waittimes=$(_math "$waittimes" + 1) | 
|  | 4621       if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ]; then | 
|  | 4622         _err "$d:Timeout" | 
|  | 4623         _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | 
|  | 4624         _clearup | 
|  | 4625         _on_issue_err "$_post_hook" "$vlist" | 
|  | 4626         return 1 | 
|  | 4627       fi | 
|  | 4628 | 
|  | 4629       _debug "sleep 2 secs to verify" | 
|  | 4630       sleep 2 | 
|  | 4631       _debug "checking" | 
|  | 4632       if [ "$ACME_VERSION" = "2" ]; then | 
|  | 4633         _send_signed_request "$uri" | 
|  | 4634       else | 
|  | 4635         response="$(_get "$uri")" | 
|  | 4636       fi | 
|  | 4637       if [ "$?" != "0" ]; then | 
|  | 4638         _err "$d:Verify error:$response" | 
|  | 4639         _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | 
|  | 4640         _clearup | 
|  | 4641         _on_issue_err "$_post_hook" "$vlist" | 
|  | 4642         return 1 | 
|  | 4643       fi | 
|  | 4644       _debug2 original "$response" | 
|  | 4645 | 
|  | 4646       response="$(echo "$response" | _normalizeJson)" | 
|  | 4647       _debug2 response "$response" | 
|  | 4648 | 
|  | 4649       status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') | 
|  | 4650       if [ "$status" = "valid" ]; then | 
|  | 4651         _info "$(__green Success)" | 
|  | 4652         _stopserver "$serverproc" | 
|  | 4653         serverproc="" | 
|  | 4654         _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | 
|  | 4655         break | 
|  | 4656       fi | 
|  | 4657 | 
|  | 4658       if [ "$status" = "invalid" ]; then | 
|  | 4659         error="$(echo "$response" | _egrep_o '"error":\{[^\}]*')" | 
|  | 4660         _debug2 error "$error" | 
|  | 4661         errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)" | 
|  | 4662         _debug2 errordetail "$errordetail" | 
|  | 4663         if [ "$errordetail" ]; then | 
|  | 4664           _err "$d:Verify error:$errordetail" | 
|  | 4665         else | 
|  | 4666           _err "$d:Verify error:$error" | 
|  | 4667         fi | 
|  | 4668         if [ "$DEBUG" ]; then | 
|  | 4669           if [ "$vtype" = "$VTYPE_HTTP" ]; then | 
|  | 4670             _debug "Debug: get token url." | 
|  | 4671             _get "http://$d/.well-known/acme-challenge/$token" "" 1 | 
|  | 4672           fi | 
|  | 4673         fi | 
|  | 4674         _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | 
|  | 4675         _clearup | 
|  | 4676         _on_issue_err "$_post_hook" "$vlist" | 
|  | 4677         return 1 | 
|  | 4678       fi | 
|  | 4679 | 
|  | 4680       if [ "$status" = "pending" ]; then | 
|  | 4681         _info "Pending" | 
|  | 4682       elif [ "$status" = "processing" ]; then | 
|  | 4683         _info "Processing" | 
|  | 4684       else | 
|  | 4685         _err "$d:Verify error:$response" | 
|  | 4686         _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | 
|  | 4687         _clearup | 
|  | 4688         _on_issue_err "$_post_hook" "$vlist" | 
|  | 4689         return 1 | 
|  | 4690       fi | 
|  | 4691 | 
|  | 4692     done | 
|  | 4693 | 
|  | 4694   done | 
|  | 4695 | 
|  | 4696   _clearup | 
|  | 4697   _info "Verify finished, start to sign." | 
|  | 4698   der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" | 
|  | 4699 | 
|  | 4700   if [ "$ACME_VERSION" = "2" ]; then | 
|  | 4701     _info "Lets finalize the order." | 
|  | 4702     _info "Le_OrderFinalize" "$Le_OrderFinalize" | 
|  | 4703     if ! _send_signed_request "${Le_OrderFinalize}" "{\"csr\": \"$der\"}"; then | 
|  | 4704       _err "Sign failed." | 
|  | 4705       _on_issue_err "$_post_hook" | 
|  | 4706       return 1 | 
|  | 4707     fi | 
|  | 4708     if [ "$code" != "200" ]; then | 
|  | 4709       _err "Sign failed, finalize code is not 200." | 
|  | 4710       _err "$response" | 
|  | 4711       _on_issue_err "$_post_hook" | 
|  | 4712       return 1 | 
|  | 4713     fi | 
|  | 4714     if [ -z "$Le_LinkOrder" ]; then | 
|  | 4715       Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n \t" | cut -d ":" -f 2-)" | 
|  | 4716     fi | 
|  | 4717 | 
|  | 4718     _savedomainconf "Le_LinkOrder" "$Le_LinkOrder" | 
|  | 4719 | 
|  | 4720     _link_cert_retry=0 | 
|  | 4721     _MAX_CERT_RETRY=30 | 
|  | 4722     while [ "$_link_cert_retry" -lt "$_MAX_CERT_RETRY" ]; do | 
|  | 4723       if _contains "$response" "\"status\":\"valid\""; then | 
|  | 4724         _debug "Order status is valid." | 
|  | 4725         Le_LinkCert="$(echo "$response" | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" | 
|  | 4726         _debug Le_LinkCert "$Le_LinkCert" | 
|  | 4727         if [ -z "$Le_LinkCert" ]; then | 
|  | 4728           _err "Sign error, can not find Le_LinkCert" | 
|  | 4729           _err "$response" | 
|  | 4730           _on_issue_err "$_post_hook" | 
|  | 4731           return 1 | 
|  | 4732         fi | 
|  | 4733         break | 
|  | 4734       elif _contains "$response" "\"processing\""; then | 
|  | 4735         _info "Order status is processing, lets sleep and retry." | 
|  | 4736         _retryafter=$(echo "$responseHeaders" | grep -i "^Retry-After *:" | cut -d : -f 2 | tr -d ' ' | tr -d '\r') | 
|  | 4737         _debug "_retryafter" "$_retryafter" | 
|  | 4738         if [ "$_retryafter" ]; then | 
|  | 4739           _info "Retry after: $_retryafter" | 
|  | 4740           _sleep $_retryafter | 
|  | 4741         else | 
|  | 4742           _sleep 2 | 
|  | 4743         fi | 
|  | 4744       else | 
|  | 4745         _err "Sign error, wrong status" | 
|  | 4746         _err "$response" | 
|  | 4747         _on_issue_err "$_post_hook" | 
|  | 4748         return 1 | 
|  | 4749       fi | 
|  | 4750       #the order is processing, so we are going to poll order status | 
|  | 4751       if [ -z "$Le_LinkOrder" ]; then | 
|  | 4752         _err "Sign error, can not get order link location header" | 
|  | 4753         _err "responseHeaders" "$responseHeaders" | 
|  | 4754         _on_issue_err "$_post_hook" | 
|  | 4755         return 1 | 
|  | 4756       fi | 
|  | 4757       _info "Polling order status: $Le_LinkOrder" | 
|  | 4758       if ! _send_signed_request "$Le_LinkOrder"; then | 
|  | 4759         _err "Sign failed, can not post to Le_LinkOrder cert:$Le_LinkOrder." | 
|  | 4760         _err "$response" | 
|  | 4761         _on_issue_err "$_post_hook" | 
|  | 4762         return 1 | 
|  | 4763       fi | 
|  | 4764       _link_cert_retry="$(_math $_link_cert_retry + 1)" | 
|  | 4765     done | 
|  | 4766 | 
|  | 4767     if [ -z "$Le_LinkCert" ]; then | 
|  | 4768       _err "Sign failed, can not get Le_LinkCert, retry time limit." | 
|  | 4769       _err "$response" | 
|  | 4770       _on_issue_err "$_post_hook" | 
|  | 4771       return 1 | 
|  | 4772     fi | 
|  | 4773     _info "Downloading cert." | 
|  | 4774     _info "Le_LinkCert" "$Le_LinkCert" | 
|  | 4775     if ! _send_signed_request "$Le_LinkCert"; then | 
|  | 4776       _err "Sign failed, can not download cert:$Le_LinkCert." | 
|  | 4777       _err "$response" | 
|  | 4778       _on_issue_err "$_post_hook" | 
|  | 4779       return 1 | 
|  | 4780     fi | 
|  | 4781 | 
|  | 4782     echo "$response" >"$CERT_PATH" | 
|  | 4783     _split_cert_chain "$CERT_PATH" "$CERT_FULLCHAIN_PATH" "$CA_CERT_PATH" | 
|  | 4784 | 
|  | 4785     if [ "$_preferred_chain" ] && [ -f "$CERT_FULLCHAIN_PATH" ]; then | 
|  | 4786       if ! _match_issuer "$CERT_FULLCHAIN_PATH" "$_preferred_chain"; then | 
|  | 4787         rels="$(echo "$responseHeaders" | tr -d ' <>' | grep -i "^link:" | grep -i 'rel="alternate"' | cut -d : -f 2- | cut -d ';' -f 1)" | 
|  | 4788         _debug2 "rels" "$rels" | 
|  | 4789         for rel in $rels; do | 
|  | 4790           _info "Try rel: $rel" | 
|  | 4791           if ! _send_signed_request "$rel"; then | 
|  | 4792             _err "Sign failed, can not download cert:$rel" | 
|  | 4793             _err "$response" | 
|  | 4794             continue | 
|  | 4795           fi | 
|  | 4796           _relcert="$CERT_PATH.alt" | 
|  | 4797           _relfullchain="$CERT_FULLCHAIN_PATH.alt" | 
|  | 4798           _relca="$CA_CERT_PATH.alt" | 
|  | 4799           echo "$response" >"$_relcert" | 
|  | 4800           _split_cert_chain "$_relcert" "$_relfullchain" "$_relca" | 
|  | 4801           if _match_issuer "$_relfullchain" "$_preferred_chain"; then | 
|  | 4802             _info "Matched issuer in: $rel" | 
|  | 4803             cat $_relcert >"$CERT_PATH" | 
|  | 4804             cat $_relfullchain >"$CERT_FULLCHAIN_PATH" | 
|  | 4805             cat $_relca >"$CA_CERT_PATH" | 
|  | 4806             break | 
|  | 4807           fi | 
|  | 4808         done | 
|  | 4809       fi | 
|  | 4810     fi | 
|  | 4811   else | 
|  | 4812     if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then | 
|  | 4813       _err "Sign failed. $response" | 
|  | 4814       _on_issue_err "$_post_hook" | 
|  | 4815       return 1 | 
|  | 4816     fi | 
|  | 4817     _rcert="$response" | 
|  | 4818     Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)" | 
|  | 4819     echo "$BEGIN_CERT" >"$CERT_PATH" | 
|  | 4820 | 
|  | 4821     #if ! _get "$Le_LinkCert" | _base64 "multiline"  >> "$CERT_PATH" ; then | 
|  | 4822     #  _debug "Get cert failed. Let's try last response." | 
|  | 4823     #  printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" | 
|  | 4824     #fi | 
|  | 4825 | 
|  | 4826     if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >>"$CERT_PATH"; then | 
|  | 4827       _debug "Try cert link." | 
|  | 4828       _get "$Le_LinkCert" | _base64 "multiline" >>"$CERT_PATH" | 
|  | 4829     fi | 
|  | 4830 | 
|  | 4831     echo "$END_CERT" >>"$CERT_PATH" | 
|  | 4832   fi | 
|  | 4833 | 
|  | 4834   _debug "Le_LinkCert" "$Le_LinkCert" | 
|  | 4835   _savedomainconf "Le_LinkCert" "$Le_LinkCert" | 
|  | 4836 | 
|  | 4837   if [ -z "$Le_LinkCert" ] || ! _checkcert "$CERT_PATH"; then | 
|  | 4838     response="$(echo "$response" | _dbase64 "multiline" | tr -d '\0' | _normalizeJson)" | 
|  | 4839     _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" | 
|  | 4840     _on_issue_err "$_post_hook" | 
|  | 4841     return 1 | 
|  | 4842   fi | 
|  | 4843 | 
|  | 4844   if [ "$Le_LinkCert" ]; then | 
|  | 4845     _info "$(__green "Cert success.")" | 
|  | 4846     cat "$CERT_PATH" | 
|  | 4847 | 
|  | 4848     _info "Your cert is in $(__green " $CERT_PATH ")" | 
|  | 4849 | 
|  | 4850     if [ -f "$CERT_KEY_PATH" ]; then | 
|  | 4851       _info "Your cert key is in $(__green " $CERT_KEY_PATH ")" | 
|  | 4852     fi | 
|  | 4853 | 
|  | 4854     if [ ! "$USER_PATH" ] || [ ! "$_ACME_IN_CRON" ]; then | 
|  | 4855       USER_PATH="$PATH" | 
|  | 4856       _saveaccountconf "USER_PATH" "$USER_PATH" | 
|  | 4857     fi | 
|  | 4858   fi | 
|  | 4859 | 
|  | 4860   if [ "$ACME_VERSION" = "2" ]; then | 
|  | 4861     _debug "v2 chain." | 
|  | 4862   else | 
|  | 4863     cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" | 
|  | 4864     Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') | 
|  | 4865 | 
|  | 4866     if [ "$Le_LinkIssuer" ]; then | 
|  | 4867       if ! _contains "$Le_LinkIssuer" ":"; then | 
|  | 4868         _info "$(__red "Relative issuer link found.")" | 
|  | 4869         Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" | 
|  | 4870       fi | 
|  | 4871       _debug Le_LinkIssuer "$Le_LinkIssuer" | 
|  | 4872       _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" | 
|  | 4873 | 
|  | 4874       _link_issuer_retry=0 | 
|  | 4875       _MAX_ISSUER_RETRY=5 | 
|  | 4876       while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do | 
|  | 4877         _debug _link_issuer_retry "$_link_issuer_retry" | 
|  | 4878         if [ "$ACME_VERSION" = "2" ]; then | 
|  | 4879           if _send_signed_request "$Le_LinkIssuer"; then | 
|  | 4880             echo "$response" >"$CA_CERT_PATH" | 
|  | 4881             break | 
|  | 4882           fi | 
|  | 4883         else | 
|  | 4884           if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then | 
|  | 4885             echo "$BEGIN_CERT" >"$CA_CERT_PATH" | 
|  | 4886             _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" | 
|  | 4887             echo "$END_CERT" >>"$CA_CERT_PATH" | 
|  | 4888             if ! _checkcert "$CA_CERT_PATH"; then | 
|  | 4889               _err "Can not get the ca cert." | 
|  | 4890               break | 
|  | 4891             fi | 
|  | 4892             cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" | 
|  | 4893             rm -f "$CA_CERT_PATH.der" | 
|  | 4894             break | 
|  | 4895           fi | 
|  | 4896         fi | 
|  | 4897         _link_issuer_retry=$(_math $_link_issuer_retry + 1) | 
|  | 4898         _sleep "$_link_issuer_retry" | 
|  | 4899       done | 
|  | 4900       if [ "$_link_issuer_retry" = "$_MAX_ISSUER_RETRY" ]; then | 
|  | 4901         _err "Max retry for issuer ca cert is reached." | 
|  | 4902       fi | 
|  | 4903     else | 
|  | 4904       _debug "No Le_LinkIssuer header found." | 
|  | 4905     fi | 
|  | 4906   fi | 
|  | 4907   [ -f "$CA_CERT_PATH" ] && _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")" | 
|  | 4908   [ -f "$CERT_FULLCHAIN_PATH" ] && _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")" | 
|  | 4909 | 
|  | 4910   Le_CertCreateTime=$(_time) | 
|  | 4911   _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime" | 
|  | 4912 | 
|  | 4913   Le_CertCreateTimeStr=$(date -u) | 
|  | 4914   _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr" | 
|  | 4915 | 
|  | 4916   if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ]; then | 
|  | 4917     Le_RenewalDays="$DEFAULT_RENEW" | 
|  | 4918   else | 
|  | 4919     _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" | 
|  | 4920   fi | 
|  | 4921 | 
|  | 4922   if [ "$CA_BUNDLE" ]; then | 
|  | 4923     _saveaccountconf CA_BUNDLE "$CA_BUNDLE" | 
|  | 4924   else | 
|  | 4925     _clearaccountconf "CA_BUNDLE" | 
|  | 4926   fi | 
|  | 4927 | 
|  | 4928   if [ "$CA_PATH" ]; then | 
|  | 4929     _saveaccountconf CA_PATH "$CA_PATH" | 
|  | 4930   else | 
|  | 4931     _clearaccountconf "CA_PATH" | 
|  | 4932   fi | 
|  | 4933 | 
|  | 4934   if [ "$HTTPS_INSECURE" ]; then | 
|  | 4935     _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE" | 
|  | 4936   else | 
|  | 4937     _clearaccountconf "HTTPS_INSECURE" | 
|  | 4938   fi | 
|  | 4939 | 
|  | 4940   if [ "$Le_Listen_V4" ]; then | 
|  | 4941     _savedomainconf "Le_Listen_V4" "$Le_Listen_V4" | 
|  | 4942     _cleardomainconf Le_Listen_V6 | 
|  | 4943   elif [ "$Le_Listen_V6" ]; then | 
|  | 4944     _savedomainconf "Le_Listen_V6" "$Le_Listen_V6" | 
|  | 4945     _cleardomainconf Le_Listen_V4 | 
|  | 4946   fi | 
|  | 4947 | 
|  | 4948   if [ "$Le_ForceNewDomainKey" = "1" ]; then | 
|  | 4949     _savedomainconf "Le_ForceNewDomainKey" "$Le_ForceNewDomainKey" | 
|  | 4950   else | 
|  | 4951     _cleardomainconf Le_ForceNewDomainKey | 
|  | 4952   fi | 
|  | 4953 | 
|  | 4954   Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60) | 
|  | 4955 | 
|  | 4956   Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime") | 
|  | 4957   _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr" | 
|  | 4958 | 
|  | 4959   Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400) | 
|  | 4960   _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" | 
|  | 4961 | 
|  | 4962   if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then | 
|  | 4963     _savedomainconf "Le_RealCertPath" "$_real_cert" | 
|  | 4964     _savedomainconf "Le_RealCACertPath" "$_real_ca" | 
|  | 4965     _savedomainconf "Le_RealKeyPath" "$_real_key" | 
|  | 4966     _savedomainconf "Le_ReloadCmd" "$_reload_cmd" "base64" | 
|  | 4967     _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" | 
|  | 4968     if ! _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"; then | 
|  | 4969       return 1 | 
|  | 4970     fi | 
|  | 4971   fi | 
|  | 4972 | 
|  | 4973   if ! _on_issue_success "$_post_hook" "$_renew_hook"; then | 
|  | 4974     _err "Call hook error." | 
|  | 4975     return 1 | 
|  | 4976   fi | 
|  | 4977 } | 
|  | 4978 | 
|  | 4979 #in_out_cert   out_fullchain   out_ca | 
|  | 4980 _split_cert_chain() { | 
|  | 4981   _certf="$1" | 
|  | 4982   _fullchainf="$2" | 
|  | 4983   _caf="$3" | 
|  | 4984   if [ "$(grep -- "$BEGIN_CERT" "$_certf" | wc -l)" -gt "1" ]; then | 
|  | 4985     _debug "Found cert chain" | 
|  | 4986     cat "$_certf" >"$_fullchainf" | 
|  | 4987     _end_n="$(grep -n -- "$END_CERT" "$_fullchainf" | _head_n 1 | cut -d : -f 1)" | 
|  | 4988     _debug _end_n "$_end_n" | 
|  | 4989     sed -n "1,${_end_n}p" "$_fullchainf" >"$_certf" | 
|  | 4990     _end_n="$(_math $_end_n + 1)" | 
|  | 4991     sed -n "${_end_n},9999p" "$_fullchainf" >"$_caf" | 
|  | 4992   fi | 
|  | 4993 } | 
|  | 4994 | 
|  | 4995 #domain  [isEcc] | 
|  | 4996 renew() { | 
|  | 4997   Le_Domain="$1" | 
|  | 4998   if [ -z "$Le_Domain" ]; then | 
|  | 4999     _usage "Usage: $PROJECT_ENTRY --renew --domain <domain.tld> [--ecc]" | 
|  | 5000     return 1 | 
|  | 5001   fi | 
|  | 5002 | 
|  | 5003   _isEcc="$2" | 
|  | 5004 | 
|  | 5005   _initpath "$Le_Domain" "$_isEcc" | 
|  | 5006 | 
|  | 5007   _info "$(__green "Renew: '$Le_Domain'")" | 
|  | 5008   if [ ! -f "$DOMAIN_CONF" ]; then | 
|  | 5009     _info "'$Le_Domain' is not an issued domain, skip." | 
|  | 5010     return $RENEW_SKIP | 
|  | 5011   fi | 
|  | 5012 | 
|  | 5013   if [ "$Le_RenewalDays" ]; then | 
|  | 5014     _savedomainconf Le_RenewalDays "$Le_RenewalDays" | 
|  | 5015   fi | 
|  | 5016 | 
|  | 5017   . "$DOMAIN_CONF" | 
|  | 5018   _debug Le_API "$Le_API" | 
|  | 5019 | 
|  | 5020   if [ "$Le_API" = "$LETSENCRYPT_CA_V1" ]; then | 
|  | 5021     _cleardomainconf Le_API | 
|  | 5022     Le_API="$DEFAULT_CA" | 
|  | 5023   fi | 
|  | 5024   if [ "$Le_API" = "$LETSENCRYPT_STAGING_CA_V1" ]; then | 
|  | 5025     _cleardomainconf Le_API | 
|  | 5026     Le_API="$DEFAULT_STAGING_CA" | 
|  | 5027   fi | 
|  | 5028 | 
|  | 5029   if [ "$Le_API" ]; then | 
|  | 5030     export ACME_DIRECTORY="$Le_API" | 
|  | 5031     #reload ca configs | 
|  | 5032     ACCOUNT_KEY_PATH="" | 
|  | 5033     ACCOUNT_JSON_PATH="" | 
|  | 5034     CA_CONF="" | 
|  | 5035     _debug3 "initpath again." | 
|  | 5036     _initpath "$Le_Domain" "$_isEcc" | 
|  | 5037   fi | 
|  | 5038 | 
|  | 5039   if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then | 
|  | 5040     _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")" | 
|  | 5041     _info "Add '$(__red '--force')' to force to renew." | 
|  | 5042     return "$RENEW_SKIP" | 
|  | 5043   fi | 
|  | 5044 | 
|  | 5045   if [ "$_ACME_IN_CRON" = "1" ] && [ -z "$Le_CertCreateTime" ]; then | 
|  | 5046     _info "Skip invalid cert for: $Le_Domain" | 
|  | 5047     return $RENEW_SKIP | 
|  | 5048   fi | 
|  | 5049 | 
|  | 5050   _ACME_IS_RENEW="1" | 
|  | 5051   Le_ReloadCmd="$(_readdomainconf Le_ReloadCmd)" | 
|  | 5052   Le_PreHook="$(_readdomainconf Le_PreHook)" | 
|  | 5053   Le_PostHook="$(_readdomainconf Le_PostHook)" | 
|  | 5054   Le_RenewHook="$(_readdomainconf Le_RenewHook)" | 
|  | 5055   Le_Preferred_Chain="$(_readdomainconf Le_Preferred_Chain)" | 
|  | 5056   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" | 
|  | 5057   res="$?" | 
|  | 5058   if [ "$res" != "0" ]; then | 
|  | 5059     return "$res" | 
|  | 5060   fi | 
|  | 5061 | 
|  | 5062   if [ "$Le_DeployHook" ]; then | 
|  | 5063     _deploy "$Le_Domain" "$Le_DeployHook" | 
|  | 5064     res="$?" | 
|  | 5065   fi | 
|  | 5066 | 
|  | 5067   _ACME_IS_RENEW="" | 
|  | 5068 | 
|  | 5069   return "$res" | 
|  | 5070 } | 
|  | 5071 | 
|  | 5072 #renewAll  [stopRenewOnError] | 
|  | 5073 renewAll() { | 
|  | 5074   _initpath | 
|  | 5075   _stopRenewOnError="$1" | 
|  | 5076   _debug "_stopRenewOnError" "$_stopRenewOnError" | 
|  | 5077   _ret="0" | 
|  | 5078   _success_msg="" | 
|  | 5079   _error_msg="" | 
|  | 5080   _skipped_msg="" | 
|  | 5081   _error_level=$NOTIFY_LEVEL_SKIP | 
|  | 5082   _notify_code=$RENEW_SKIP | 
|  | 5083   _set_level=${NOTIFY_LEVEL:-$NOTIFY_LEVEL_DEFAULT} | 
|  | 5084   _debug "_set_level" "$_set_level" | 
|  | 5085   for di in "${CERT_HOME}"/*.*/; do | 
|  | 5086     _debug di "$di" | 
|  | 5087     if ! [ -d "$di" ]; then | 
|  | 5088       _debug "Not a directory, skip: $di" | 
|  | 5089       continue | 
|  | 5090     fi | 
|  | 5091     d=$(basename "$di") | 
|  | 5092     _debug d "$d" | 
|  | 5093     ( | 
|  | 5094       if _endswith "$d" "$ECC_SUFFIX"; then | 
|  | 5095         _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2) | 
|  | 5096         d=$(echo "$d" | cut -d "$ECC_SEP" -f 1) | 
|  | 5097       fi | 
|  | 5098       renew "$d" "$_isEcc" | 
|  | 5099     ) | 
|  | 5100     rc="$?" | 
|  | 5101     _debug "Return code: $rc" | 
|  | 5102     if [ "$rc" = "0" ]; then | 
|  | 5103       if [ $_error_level -gt $NOTIFY_LEVEL_RENEW ]; then | 
|  | 5104         _error_level="$NOTIFY_LEVEL_RENEW" | 
|  | 5105         _notify_code=0 | 
|  | 5106       fi | 
|  | 5107       if [ "$_ACME_IN_CRON" ]; then | 
|  | 5108         if [ $_set_level -ge $NOTIFY_LEVEL_RENEW ]; then | 
|  | 5109           if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then | 
|  | 5110             _send_notify "Renew $d success" "Good, the cert is renewed." "$NOTIFY_HOOK" 0 | 
|  | 5111           fi | 
|  | 5112         fi | 
|  | 5113       fi | 
|  | 5114       _success_msg="${_success_msg}    $d | 
|  | 5115 " | 
|  | 5116     elif [ "$rc" = "$RENEW_SKIP" ]; then | 
|  | 5117       if [ $_error_level -gt $NOTIFY_LEVEL_SKIP ]; then | 
|  | 5118         _error_level="$NOTIFY_LEVEL_SKIP" | 
|  | 5119         _notify_code=$RENEW_SKIP | 
|  | 5120       fi | 
|  | 5121       if [ "$_ACME_IN_CRON" ]; then | 
|  | 5122         if [ $_set_level -ge $NOTIFY_LEVEL_SKIP ]; then | 
|  | 5123           if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then | 
|  | 5124             _send_notify "Renew $d skipped" "Good, the cert is skipped." "$NOTIFY_HOOK" "$RENEW_SKIP" | 
|  | 5125           fi | 
|  | 5126         fi | 
|  | 5127       fi | 
|  | 5128       _info "Skipped $d" | 
|  | 5129       _skipped_msg="${_skipped_msg}    $d | 
|  | 5130 " | 
|  | 5131     else | 
|  | 5132       if [ $_error_level -gt $NOTIFY_LEVEL_ERROR ]; then | 
|  | 5133         _error_level="$NOTIFY_LEVEL_ERROR" | 
|  | 5134         _notify_code=1 | 
|  | 5135       fi | 
|  | 5136       if [ "$_ACME_IN_CRON" ]; then | 
|  | 5137         if [ $_set_level -ge $NOTIFY_LEVEL_ERROR ]; then | 
|  | 5138           if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then | 
|  | 5139             _send_notify "Renew $d error" "There is an error." "$NOTIFY_HOOK" 1 | 
|  | 5140           fi | 
|  | 5141         fi | 
|  | 5142       fi | 
|  | 5143       _error_msg="${_error_msg}    $d | 
|  | 5144 " | 
|  | 5145       if [ "$_stopRenewOnError" ]; then | 
|  | 5146         _err "Error renew $d,  stop now." | 
|  | 5147         _ret="$rc" | 
|  | 5148         break | 
|  | 5149       else | 
|  | 5150         _ret="$rc" | 
|  | 5151         _err "Error renew $d." | 
|  | 5152       fi | 
|  | 5153     fi | 
|  | 5154   done | 
|  | 5155   _debug _error_level "$_error_level" | 
|  | 5156   _debug _set_level "$_set_level" | 
|  | 5157   if [ "$_ACME_IN_CRON" ] && [ $_error_level -le $_set_level ]; then | 
|  | 5158     if [ -z "$NOTIFY_MODE" ] || [ "$NOTIFY_MODE" = "$NOTIFY_MODE_BULK" ]; then | 
|  | 5159       _msg_subject="Renew" | 
|  | 5160       if [ "$_error_msg" ]; then | 
|  | 5161         _msg_subject="${_msg_subject} Error" | 
|  | 5162         _msg_data="Error certs: | 
|  | 5163 ${_error_msg} | 
|  | 5164 " | 
|  | 5165       fi | 
|  | 5166       if [ "$_success_msg" ]; then | 
|  | 5167         _msg_subject="${_msg_subject} Success" | 
|  | 5168         _msg_data="${_msg_data}Success certs: | 
|  | 5169 ${_success_msg} | 
|  | 5170 " | 
|  | 5171       fi | 
|  | 5172       if [ "$_skipped_msg" ]; then | 
|  | 5173         _msg_subject="${_msg_subject} Skipped" | 
|  | 5174         _msg_data="${_msg_data}Skipped certs: | 
|  | 5175 ${_skipped_msg} | 
|  | 5176 " | 
|  | 5177       fi | 
|  | 5178 | 
|  | 5179       _send_notify "$_msg_subject" "$_msg_data" "$NOTIFY_HOOK" "$_notify_code" | 
|  | 5180     fi | 
|  | 5181   fi | 
|  | 5182 | 
|  | 5183   return "$_ret" | 
|  | 5184 } | 
|  | 5185 | 
|  | 5186 #csr webroot | 
|  | 5187 signcsr() { | 
|  | 5188   _csrfile="$1" | 
|  | 5189   _csrW="$2" | 
|  | 5190   if [ -z "$_csrfile" ] || [ -z "$_csrW" ]; then | 
|  | 5191     _usage "Usage: $PROJECT_ENTRY --sign-csr --csr <csr-file> --webroot <directory>" | 
|  | 5192     return 1 | 
|  | 5193   fi | 
|  | 5194 | 
|  | 5195   _real_cert="$3" | 
|  | 5196   _real_key="$4" | 
|  | 5197   _real_ca="$5" | 
|  | 5198   _reload_cmd="$6" | 
|  | 5199   _real_fullchain="$7" | 
|  | 5200   _pre_hook="${8}" | 
|  | 5201   _post_hook="${9}" | 
|  | 5202   _renew_hook="${10}" | 
|  | 5203   _local_addr="${11}" | 
|  | 5204   _challenge_alias="${12}" | 
|  | 5205 | 
|  | 5206   _csrsubj=$(_readSubjectFromCSR "$_csrfile") | 
|  | 5207   if [ "$?" != "0" ]; then | 
|  | 5208     _err "Can not read subject from csr: $_csrfile" | 
|  | 5209     return 1 | 
|  | 5210   fi | 
|  | 5211   _debug _csrsubj "$_csrsubj" | 
|  | 5212   if _contains "$_csrsubj" ' ' || ! _contains "$_csrsubj" '.'; then | 
|  | 5213     _info "It seems that the subject: $_csrsubj is not a valid domain name. Drop it." | 
|  | 5214     _csrsubj="" | 
|  | 5215   fi | 
|  | 5216 | 
|  | 5217   _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") | 
|  | 5218   if [ "$?" != "0" ]; then | 
|  | 5219     _err "Can not read domain list from csr: $_csrfile" | 
|  | 5220     return 1 | 
|  | 5221   fi | 
|  | 5222   _debug "_csrdomainlist" "$_csrdomainlist" | 
|  | 5223 | 
|  | 5224   if [ -z "$_csrsubj" ]; then | 
|  | 5225     _csrsubj="$(_getfield "$_csrdomainlist" 1)" | 
|  | 5226     _debug _csrsubj "$_csrsubj" | 
|  | 5227     _csrdomainlist="$(echo "$_csrdomainlist" | cut -d , -f 2-)" | 
|  | 5228     _debug "_csrdomainlist" "$_csrdomainlist" | 
|  | 5229   fi | 
|  | 5230 | 
|  | 5231   if [ -z "$_csrsubj" ]; then | 
|  | 5232     _err "Can not read subject from csr: $_csrfile" | 
|  | 5233     return 1 | 
|  | 5234   fi | 
|  | 5235 | 
|  | 5236   _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile") | 
|  | 5237   if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then | 
|  | 5238     _err "Can not read key length from csr: $_csrfile" | 
|  | 5239     return 1 | 
|  | 5240   fi | 
|  | 5241 | 
|  | 5242   if [ -z "$ACME_VERSION" ] && _contains "$_csrsubj,$_csrdomainlist" "*."; then | 
|  | 5243     export ACME_VERSION=2 | 
|  | 5244   fi | 
|  | 5245   _initpath "$_csrsubj" "$_csrkeylength" | 
|  | 5246   mkdir -p "$DOMAIN_PATH" | 
|  | 5247 | 
|  | 5248   _info "Copy csr to: $CSR_PATH" | 
|  | 5249   cp "$_csrfile" "$CSR_PATH" | 
|  | 5250 | 
|  | 5251   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" | 
|  | 5252 | 
|  | 5253 } | 
|  | 5254 | 
|  | 5255 showcsr() { | 
|  | 5256   _csrfile="$1" | 
|  | 5257   _csrd="$2" | 
|  | 5258   if [ -z "$_csrfile" ] && [ -z "$_csrd" ]; then | 
|  | 5259     _usage "Usage: $PROJECT_ENTRY --show-csr --csr <csr-file>" | 
|  | 5260     return 1 | 
|  | 5261   fi | 
|  | 5262 | 
|  | 5263   _initpath | 
|  | 5264 | 
|  | 5265   _csrsubj=$(_readSubjectFromCSR "$_csrfile") | 
|  | 5266   if [ "$?" != "0" ] || [ -z "$_csrsubj" ]; then | 
|  | 5267     _err "Can not read subject from csr: $_csrfile" | 
|  | 5268     return 1 | 
|  | 5269   fi | 
|  | 5270 | 
|  | 5271   _info "Subject=$_csrsubj" | 
|  | 5272 | 
|  | 5273   _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") | 
|  | 5274   if [ "$?" != "0" ]; then | 
|  | 5275     _err "Can not read domain list from csr: $_csrfile" | 
|  | 5276     return 1 | 
|  | 5277   fi | 
|  | 5278   _debug "_csrdomainlist" "$_csrdomainlist" | 
|  | 5279 | 
|  | 5280   _info "SubjectAltNames=$_csrdomainlist" | 
|  | 5281 | 
|  | 5282   _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile") | 
|  | 5283   if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then | 
|  | 5284     _err "Can not read key length from csr: $_csrfile" | 
|  | 5285     return 1 | 
|  | 5286   fi | 
|  | 5287   _info "KeyLength=$_csrkeylength" | 
|  | 5288 } | 
|  | 5289 | 
|  | 5290 #listraw  domain | 
|  | 5291 list() { | 
|  | 5292   _raw="$1" | 
|  | 5293   _domain="$2" | 
|  | 5294   _initpath | 
|  | 5295 | 
|  | 5296   _sep="|" | 
|  | 5297   if [ "$_raw" ]; then | 
|  | 5298     if [ -z "$_domain" ]; then | 
|  | 5299       printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}CA${_sep}Created${_sep}Renew" | 
|  | 5300     fi | 
|  | 5301     for di in "${CERT_HOME}"/*.*/; do | 
|  | 5302       d=$(basename "$di") | 
|  | 5303       _debug d "$d" | 
|  | 5304       ( | 
|  | 5305         if _endswith "$d" "$ECC_SUFFIX"; then | 
|  | 5306           _isEcc="ecc" | 
|  | 5307           d=$(echo "$d" | cut -d "$ECC_SEP" -f 1) | 
|  | 5308         fi | 
|  | 5309         DOMAIN_CONF="$di/$d.conf" | 
|  | 5310         if [ -f "$DOMAIN_CONF" ]; then | 
|  | 5311           . "$DOMAIN_CONF" | 
|  | 5312           _ca="$(_getCAShortName "$Le_API")" | 
|  | 5313           if [ -z "$_domain" ]; then | 
|  | 5314             printf "%s\n" "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$_ca${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr" | 
|  | 5315           else | 
|  | 5316             if [ "$_domain" = "$d" ]; then | 
|  | 5317               cat "$DOMAIN_CONF" | 
|  | 5318             fi | 
|  | 5319           fi | 
|  | 5320         fi | 
|  | 5321       ) | 
|  | 5322     done | 
|  | 5323   else | 
|  | 5324     if _exists column; then | 
|  | 5325       list "raw" "$_domain" | column -t -s "$_sep" | 
|  | 5326     else | 
|  | 5327       list "raw" "$_domain" | tr "$_sep" '\t' | 
|  | 5328     fi | 
|  | 5329   fi | 
|  | 5330 | 
|  | 5331 } | 
|  | 5332 | 
|  | 5333 _deploy() { | 
|  | 5334   _d="$1" | 
|  | 5335   _hooks="$2" | 
|  | 5336 | 
|  | 5337   for _d_api in $(echo "$_hooks" | tr ',' " "); do | 
|  | 5338     _deployApi="$(_findHook "$_d" $_SUB_FOLDER_DEPLOY "$_d_api")" | 
|  | 5339     if [ -z "$_deployApi" ]; then | 
|  | 5340       _err "The deploy hook $_d_api is not found." | 
|  | 5341       return 1 | 
|  | 5342     fi | 
|  | 5343     _debug _deployApi "$_deployApi" | 
|  | 5344 | 
|  | 5345     if ! ( | 
|  | 5346       if ! . "$_deployApi"; then | 
|  | 5347         _err "Load file $_deployApi error. Please check your api file and try again." | 
|  | 5348         return 1 | 
|  | 5349       fi | 
|  | 5350 | 
|  | 5351       d_command="${_d_api}_deploy" | 
|  | 5352       if ! _exists "$d_command"; then | 
|  | 5353         _err "It seems that your api file is not correct, it must have a function named: $d_command" | 
|  | 5354         return 1 | 
|  | 5355       fi | 
|  | 5356 | 
|  | 5357       if ! $d_command "$_d" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then | 
|  | 5358         _err "Error deploy for domain:$_d" | 
|  | 5359         return 1 | 
|  | 5360       fi | 
|  | 5361     ); then | 
|  | 5362       _err "Deploy error." | 
|  | 5363       return 1 | 
|  | 5364     else | 
|  | 5365       _info "$(__green Success)" | 
|  | 5366     fi | 
|  | 5367   done | 
|  | 5368 } | 
|  | 5369 | 
|  | 5370 #domain hooks | 
|  | 5371 deploy() { | 
|  | 5372   _d="$1" | 
|  | 5373   _hooks="$2" | 
|  | 5374   _isEcc="$3" | 
|  | 5375   if [ -z "$_hooks" ]; then | 
|  | 5376     _usage "Usage: $PROJECT_ENTRY --deploy --domain <domain.tld> --deploy-hook <hookname> [--ecc] " | 
|  | 5377     return 1 | 
|  | 5378   fi | 
|  | 5379 | 
|  | 5380   _initpath "$_d" "$_isEcc" | 
|  | 5381   if [ ! -d "$DOMAIN_PATH" ]; then | 
|  | 5382     _err "The domain '$_d' is not a cert name. You must use the cert name to specify the cert to install." | 
|  | 5383     _err "Can not find path:'$DOMAIN_PATH'" | 
|  | 5384     return 1 | 
|  | 5385   fi | 
|  | 5386 | 
|  | 5387   . "$DOMAIN_CONF" | 
|  | 5388 | 
|  | 5389   _savedomainconf Le_DeployHook "$_hooks" | 
|  | 5390 | 
|  | 5391   _deploy "$_d" "$_hooks" | 
|  | 5392 } | 
|  | 5393 | 
|  | 5394 installcert() { | 
|  | 5395   _main_domain="$1" | 
|  | 5396   if [ -z "$_main_domain" ]; then | 
|  | 5397     _usage "Usage: $PROJECT_ENTRY --install-cert --domain <domain.tld> [--ecc] [--cert-file <file>] [--key-file <file>] [--ca-file <file>] [ --reloadcmd <command>] [--fullchain-file <file>]" | 
|  | 5398     return 1 | 
|  | 5399   fi | 
|  | 5400 | 
|  | 5401   _real_cert="$2" | 
|  | 5402   _real_key="$3" | 
|  | 5403   _real_ca="$4" | 
|  | 5404   _reload_cmd="$5" | 
|  | 5405   _real_fullchain="$6" | 
|  | 5406   _isEcc="$7" | 
|  | 5407 | 
|  | 5408   _initpath "$_main_domain" "$_isEcc" | 
|  | 5409   if [ ! -d "$DOMAIN_PATH" ]; then | 
|  | 5410     _err "The domain '$_main_domain' is not a cert name. You must use the cert name to specify the cert to install." | 
|  | 5411     _err "Can not find path:'$DOMAIN_PATH'" | 
|  | 5412     return 1 | 
|  | 5413   fi | 
|  | 5414 | 
|  | 5415   _savedomainconf "Le_RealCertPath" "$_real_cert" | 
|  | 5416   _savedomainconf "Le_RealCACertPath" "$_real_ca" | 
|  | 5417   _savedomainconf "Le_RealKeyPath" "$_real_key" | 
|  | 5418   _savedomainconf "Le_ReloadCmd" "$_reload_cmd" "base64" | 
|  | 5419   _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" | 
|  | 5420 | 
|  | 5421   _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd" | 
|  | 5422 } | 
|  | 5423 | 
|  | 5424 #domain  cert  key  ca  fullchain reloadcmd backup-prefix | 
|  | 5425 _installcert() { | 
|  | 5426   _main_domain="$1" | 
|  | 5427   _real_cert="$2" | 
|  | 5428   _real_key="$3" | 
|  | 5429   _real_ca="$4" | 
|  | 5430   _real_fullchain="$5" | 
|  | 5431   _reload_cmd="$6" | 
|  | 5432   _backup_prefix="$7" | 
|  | 5433 | 
|  | 5434   if [ "$_real_cert" = "$NO_VALUE" ]; then | 
|  | 5435     _real_cert="" | 
|  | 5436   fi | 
|  | 5437   if [ "$_real_key" = "$NO_VALUE" ]; then | 
|  | 5438     _real_key="" | 
|  | 5439   fi | 
|  | 5440   if [ "$_real_ca" = "$NO_VALUE" ]; then | 
|  | 5441     _real_ca="" | 
|  | 5442   fi | 
|  | 5443   if [ "$_reload_cmd" = "$NO_VALUE" ]; then | 
|  | 5444     _reload_cmd="" | 
|  | 5445   fi | 
|  | 5446   if [ "$_real_fullchain" = "$NO_VALUE" ]; then | 
|  | 5447     _real_fullchain="" | 
|  | 5448   fi | 
|  | 5449 | 
|  | 5450   _backup_path="$DOMAIN_BACKUP_PATH/$_backup_prefix" | 
|  | 5451   mkdir -p "$_backup_path" | 
|  | 5452 | 
|  | 5453   if [ "$_real_cert" ]; then | 
|  | 5454     _info "Installing cert to:$_real_cert" | 
|  | 5455     if [ -f "$_real_cert" ] && [ ! "$_ACME_IS_RENEW" ]; then | 
|  | 5456       cp "$_real_cert" "$_backup_path/cert.bak" | 
|  | 5457     fi | 
|  | 5458     cat "$CERT_PATH" >"$_real_cert" || return 1 | 
|  | 5459   fi | 
|  | 5460 | 
|  | 5461   if [ "$_real_ca" ]; then | 
|  | 5462     _info "Installing CA to:$_real_ca" | 
|  | 5463     if [ "$_real_ca" = "$_real_cert" ]; then | 
|  | 5464       echo "" >>"$_real_ca" | 
|  | 5465       cat "$CA_CERT_PATH" >>"$_real_ca" || return 1 | 
|  | 5466     else | 
|  | 5467       if [ -f "$_real_ca" ] && [ ! "$_ACME_IS_RENEW" ]; then | 
|  | 5468         cp "$_real_ca" "$_backup_path/ca.bak" | 
|  | 5469       fi | 
|  | 5470       cat "$CA_CERT_PATH" >"$_real_ca" || return 1 | 
|  | 5471     fi | 
|  | 5472   fi | 
|  | 5473 | 
|  | 5474   if [ "$_real_key" ]; then | 
|  | 5475     _info "Installing key to:$_real_key" | 
|  | 5476     if [ -f "$_real_key" ] && [ ! "$_ACME_IS_RENEW" ]; then | 
|  | 5477       cp "$_real_key" "$_backup_path/key.bak" | 
|  | 5478     fi | 
|  | 5479     if [ -f "$_real_key" ]; then | 
|  | 5480       cat "$CERT_KEY_PATH" >"$_real_key" || return 1 | 
|  | 5481     else | 
|  | 5482       cat "$CERT_KEY_PATH" >"$_real_key" || return 1 | 
|  | 5483       chmod 600 "$_real_key" | 
|  | 5484     fi | 
|  | 5485   fi | 
|  | 5486 | 
|  | 5487   if [ "$_real_fullchain" ]; then | 
|  | 5488     _info "Installing full chain to:$_real_fullchain" | 
|  | 5489     if [ -f "$_real_fullchain" ] && [ ! "$_ACME_IS_RENEW" ]; then | 
|  | 5490       cp "$_real_fullchain" "$_backup_path/fullchain.bak" | 
|  | 5491     fi | 
|  | 5492     cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" || return 1 | 
|  | 5493   fi | 
|  | 5494 | 
|  | 5495   if [ "$_reload_cmd" ]; then | 
|  | 5496     _info "Run reload cmd: $_reload_cmd" | 
|  | 5497     if ( | 
|  | 5498       export CERT_PATH | 
|  | 5499       export CERT_KEY_PATH | 
|  | 5500       export CA_CERT_PATH | 
|  | 5501       export CERT_FULLCHAIN_PATH | 
|  | 5502       export Le_Domain="$_main_domain" | 
|  | 5503       cd "$DOMAIN_PATH" && eval "$_reload_cmd" | 
|  | 5504     ); then | 
|  | 5505       _info "$(__green "Reload success")" | 
|  | 5506     else | 
|  | 5507       _err "Reload error for :$Le_Domain" | 
|  | 5508     fi | 
|  | 5509   fi | 
|  | 5510 | 
|  | 5511 } | 
|  | 5512 | 
|  | 5513 __read_password() { | 
|  | 5514   unset _pp | 
|  | 5515   prompt="Enter Password:" | 
|  | 5516   while IFS= read -p "$prompt" -r -s -n 1 char; do | 
|  | 5517     if [ "$char" = $'\0' ]; then | 
|  | 5518       break | 
|  | 5519     fi | 
|  | 5520     prompt='*' | 
|  | 5521     _pp="$_pp$char" | 
|  | 5522   done | 
|  | 5523   echo "$_pp" | 
|  | 5524 } | 
|  | 5525 | 
|  | 5526 _install_win_taskscheduler() { | 
|  | 5527   _lesh="$1" | 
|  | 5528   _centry="$2" | 
|  | 5529   _randomminute="$3" | 
|  | 5530   if ! _exists cygpath; then | 
|  | 5531     _err "cygpath not found" | 
|  | 5532     return 1 | 
|  | 5533   fi | 
|  | 5534   if ! _exists schtasks; then | 
|  | 5535     _err "schtasks.exe is not found, are you on Windows?" | 
|  | 5536     return 1 | 
|  | 5537   fi | 
|  | 5538   _winbash="$(cygpath -w $(which bash))" | 
|  | 5539   _debug _winbash "$_winbash" | 
|  | 5540   if [ -z "$_winbash" ]; then | 
|  | 5541     _err "can not find bash path" | 
|  | 5542     return 1 | 
|  | 5543   fi | 
|  | 5544   _myname="$(whoami)" | 
|  | 5545   _debug "_myname" "$_myname" | 
|  | 5546   if [ -z "$_myname" ]; then | 
|  | 5547     _err "can not find my user name" | 
|  | 5548     return 1 | 
|  | 5549   fi | 
|  | 5550   _debug "_lesh" "$_lesh" | 
|  | 5551 | 
|  | 5552   _info "To install scheduler task in your Windows account, you must input your windows password." | 
|  | 5553   _info "$PROJECT_NAME doesn't save your password." | 
|  | 5554   _info "Please input your Windows password for: $(__green "$_myname")" | 
|  | 5555   _password="$(__read_password)" | 
|  | 5556   #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 | 
|  | 5557   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 | 
|  | 5558   echo | 
|  | 5559 | 
|  | 5560 } | 
|  | 5561 | 
|  | 5562 _uninstall_win_taskscheduler() { | 
|  | 5563   if ! _exists schtasks; then | 
|  | 5564     _err "schtasks.exe is not found, are you on Windows?" | 
|  | 5565     return 1 | 
|  | 5566   fi | 
|  | 5567   if ! echo SCHTASKS /query /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null; then | 
|  | 5568     _debug "scheduler $_WINDOWS_SCHEDULER_NAME is not found." | 
|  | 5569   else | 
|  | 5570     _info "Removing $_WINDOWS_SCHEDULER_NAME" | 
|  | 5571     echo SCHTASKS /delete /f /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null | 
|  | 5572   fi | 
|  | 5573 } | 
|  | 5574 | 
|  | 5575 #confighome | 
|  | 5576 installcronjob() { | 
|  | 5577   _c_home="$1" | 
|  | 5578   _initpath | 
|  | 5579   _CRONTAB="crontab" | 
|  | 5580   if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then | 
|  | 5581     lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY" | 
|  | 5582   else | 
|  | 5583     _err "Can not install cronjob, $PROJECT_ENTRY not found." | 
|  | 5584     return 1 | 
|  | 5585   fi | 
|  | 5586   if [ "$_c_home" ]; then | 
|  | 5587     _c_entry="--config-home \"$_c_home\" " | 
|  | 5588   fi | 
|  | 5589   _t=$(_time) | 
|  | 5590   random_minute=$(_math $_t % 60) | 
|  | 5591 | 
|  | 5592   if ! _exists "$_CRONTAB" && _exists "fcrontab"; then | 
|  | 5593     _CRONTAB="fcrontab" | 
|  | 5594   fi | 
|  | 5595 | 
|  | 5596   if ! _exists "$_CRONTAB"; then | 
|  | 5597     if _exists cygpath && _exists schtasks.exe; then | 
|  | 5598       _info "It seems you are on Windows,  let's install Windows scheduler task." | 
|  | 5599       if _install_win_taskscheduler "$lesh" "$_c_entry" "$random_minute"; then | 
|  | 5600         _info "Install Windows scheduler task success." | 
|  | 5601         return 0 | 
|  | 5602       else | 
|  | 5603         _err "Install Windows scheduler task failed." | 
|  | 5604         return 1 | 
|  | 5605       fi | 
|  | 5606     fi | 
|  | 5607     _err "crontab/fcrontab doesn't exist, so, we can not install cron jobs." | 
|  | 5608     _err "All your certs will not be renewed automatically." | 
|  | 5609     _err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday." | 
|  | 5610     return 1 | 
|  | 5611   fi | 
|  | 5612   _info "Installing cron job" | 
|  | 5613   if ! $_CRONTAB -l | grep "$PROJECT_ENTRY --cron"; then | 
|  | 5614     if _exists uname && uname -a | grep SunOS >/dev/null; then | 
|  | 5615       $_CRONTAB -l | { | 
|  | 5616         cat | 
|  | 5617         echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" | 
|  | 5618       } | $_CRONTAB -- | 
|  | 5619     else | 
|  | 5620       $_CRONTAB -l | { | 
|  | 5621         cat | 
|  | 5622         echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" | 
|  | 5623       } | $_CRONTAB - | 
|  | 5624     fi | 
|  | 5625   fi | 
|  | 5626   if [ "$?" != "0" ]; then | 
|  | 5627     _err "Install cron job failed. You need to manually renew your certs." | 
|  | 5628     _err "Or you can add cronjob by yourself:" | 
|  | 5629     _err "$lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" | 
|  | 5630     return 1 | 
|  | 5631   fi | 
|  | 5632 } | 
|  | 5633 | 
|  | 5634 uninstallcronjob() { | 
|  | 5635   _CRONTAB="crontab" | 
|  | 5636   if ! _exists "$_CRONTAB" && _exists "fcrontab"; then | 
|  | 5637     _CRONTAB="fcrontab" | 
|  | 5638   fi | 
|  | 5639 | 
|  | 5640   if ! _exists "$_CRONTAB"; then | 
|  | 5641     if _exists cygpath && _exists schtasks.exe; then | 
|  | 5642       _info "It seems you are on Windows,  let's uninstall Windows scheduler task." | 
|  | 5643       if _uninstall_win_taskscheduler; then | 
|  | 5644         _info "Uninstall Windows scheduler task success." | 
|  | 5645         return 0 | 
|  | 5646       else | 
|  | 5647         _err "Uninstall Windows scheduler task failed." | 
|  | 5648         return 1 | 
|  | 5649       fi | 
|  | 5650     fi | 
|  | 5651     return | 
|  | 5652   fi | 
|  | 5653   _info "Removing cron job" | 
|  | 5654   cr="$($_CRONTAB -l | grep "$PROJECT_ENTRY --cron")" | 
|  | 5655   if [ "$cr" ]; then | 
|  | 5656     if _exists uname && uname -a | grep solaris >/dev/null; then | 
|  | 5657       $_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB -- | 
|  | 5658     else | 
|  | 5659       $_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB - | 
|  | 5660     fi | 
|  | 5661     LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" | 
|  | 5662     _info LE_WORKING_DIR "$LE_WORKING_DIR" | 
|  | 5663     if _contains "$cr" "--config-home"; then | 
|  | 5664       LE_CONFIG_HOME="$(echo "$cr" | cut -d ' ' -f 11 | tr -d '"')" | 
|  | 5665       _debug LE_CONFIG_HOME "$LE_CONFIG_HOME" | 
|  | 5666     fi | 
|  | 5667   fi | 
|  | 5668   _initpath | 
|  | 5669 | 
|  | 5670 } | 
|  | 5671 | 
|  | 5672 #domain  isECC  revokeReason | 
|  | 5673 revoke() { | 
|  | 5674   Le_Domain="$1" | 
|  | 5675   if [ -z "$Le_Domain" ]; then | 
|  | 5676     _usage "Usage: $PROJECT_ENTRY --revoke --domain <domain.tld> [--ecc]" | 
|  | 5677     return 1 | 
|  | 5678   fi | 
|  | 5679 | 
|  | 5680   _isEcc="$2" | 
|  | 5681   _reason="$3" | 
|  | 5682   if [ -z "$_reason" ]; then | 
|  | 5683     _reason="0" | 
|  | 5684   fi | 
|  | 5685   _initpath "$Le_Domain" "$_isEcc" | 
|  | 5686   if [ ! -f "$DOMAIN_CONF" ]; then | 
|  | 5687     _err "$Le_Domain is not a issued domain, skip." | 
|  | 5688     return 1 | 
|  | 5689   fi | 
|  | 5690 | 
|  | 5691   if [ ! -f "$CERT_PATH" ]; then | 
|  | 5692     _err "Cert for $Le_Domain $CERT_PATH is not found, skip." | 
|  | 5693     return 1 | 
|  | 5694   fi | 
|  | 5695 | 
|  | 5696   cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _url_replace)" | 
|  | 5697 | 
|  | 5698   if [ -z "$cert" ]; then | 
|  | 5699     _err "Cert for $Le_Domain is empty found, skip." | 
|  | 5700     return 1 | 
|  | 5701   fi | 
|  | 5702 | 
|  | 5703   _initAPI | 
|  | 5704 | 
|  | 5705   if [ "$ACME_VERSION" = "2" ]; then | 
|  | 5706     data="{\"certificate\": \"$cert\",\"reason\":$_reason}" | 
|  | 5707   else | 
|  | 5708     data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" | 
|  | 5709   fi | 
|  | 5710   uri="${ACME_REVOKE_CERT}" | 
|  | 5711 | 
|  | 5712   if [ -f "$CERT_KEY_PATH" ]; then | 
|  | 5713     _info "Try domain key first." | 
|  | 5714     if _send_signed_request "$uri" "$data" "" "$CERT_KEY_PATH"; then | 
|  | 5715       if [ -z "$response" ]; then | 
|  | 5716         _info "Revoke success." | 
|  | 5717         rm -f "$CERT_PATH" | 
|  | 5718         return 0 | 
|  | 5719       else | 
|  | 5720         _err "Revoke error by domain key." | 
|  | 5721         _err "$response" | 
|  | 5722       fi | 
|  | 5723     fi | 
|  | 5724   else | 
|  | 5725     _info "Domain key file doesn't exist." | 
|  | 5726   fi | 
|  | 5727 | 
|  | 5728   _info "Try account key." | 
|  | 5729 | 
|  | 5730   if _send_signed_request "$uri" "$data" "" "$ACCOUNT_KEY_PATH"; then | 
|  | 5731     if [ -z "$response" ]; then | 
|  | 5732       _info "Revoke success." | 
|  | 5733       rm -f "$CERT_PATH" | 
|  | 5734       return 0 | 
|  | 5735     else | 
|  | 5736       _err "Revoke error." | 
|  | 5737       _debug "$response" | 
|  | 5738     fi | 
|  | 5739   fi | 
|  | 5740   return 1 | 
|  | 5741 } | 
|  | 5742 | 
|  | 5743 #domain  ecc | 
|  | 5744 remove() { | 
|  | 5745   Le_Domain="$1" | 
|  | 5746   if [ -z "$Le_Domain" ]; then | 
|  | 5747     _usage "Usage: $PROJECT_ENTRY --remove --domain <domain.tld> [--ecc]" | 
|  | 5748     return 1 | 
|  | 5749   fi | 
|  | 5750 | 
|  | 5751   _isEcc="$2" | 
|  | 5752 | 
|  | 5753   _initpath "$Le_Domain" "$_isEcc" | 
|  | 5754   _removed_conf="$DOMAIN_CONF.removed" | 
|  | 5755   if [ ! -f "$DOMAIN_CONF" ]; then | 
|  | 5756     if [ -f "$_removed_conf" ]; then | 
|  | 5757       _err "$Le_Domain is already removed, You can remove the folder by yourself: $DOMAIN_PATH" | 
|  | 5758     else | 
|  | 5759       _err "$Le_Domain is not a issued domain, skip." | 
|  | 5760     fi | 
|  | 5761     return 1 | 
|  | 5762   fi | 
|  | 5763 | 
|  | 5764   if mv "$DOMAIN_CONF" "$_removed_conf"; then | 
|  | 5765     _info "$Le_Domain is removed, the key and cert files are in $(__green $DOMAIN_PATH)" | 
|  | 5766     _info "You can remove them by yourself." | 
|  | 5767     return 0 | 
|  | 5768   else | 
|  | 5769     _err "Remove $Le_Domain failed." | 
|  | 5770     return 1 | 
|  | 5771   fi | 
|  | 5772 } | 
|  | 5773 | 
|  | 5774 #domain vtype | 
|  | 5775 _deactivate() { | 
|  | 5776   _d_domain="$1" | 
|  | 5777   _d_type="$2" | 
|  | 5778   _initpath | 
|  | 5779 | 
|  | 5780   if [ "$ACME_VERSION" = "2" ]; then | 
|  | 5781     _identifiers="{\"type\":\"dns\",\"value\":\"$_d_domain\"}" | 
|  | 5782     if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then | 
|  | 5783       _err "Can not get domain new order." | 
|  | 5784       return 1 | 
|  | 5785     fi | 
|  | 5786     _authorizations_seg="$(echo "$response" | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" | 
|  | 5787     _debug2 _authorizations_seg "$_authorizations_seg" | 
|  | 5788     if [ -z "$_authorizations_seg" ]; then | 
|  | 5789       _err "_authorizations_seg not found." | 
|  | 5790       _clearup | 
|  | 5791       _on_issue_err "$_post_hook" | 
|  | 5792       return 1 | 
|  | 5793     fi | 
|  | 5794 | 
|  | 5795     authzUri="$_authorizations_seg" | 
|  | 5796     _debug2 "authzUri" "$authzUri" | 
|  | 5797     if ! _send_signed_request "$authzUri"; then | 
|  | 5798       _err "get to authz error." | 
|  | 5799       _err "_authorizations_seg" "$_authorizations_seg" | 
|  | 5800       _err "authzUri" "$authzUri" | 
|  | 5801       _clearup | 
|  | 5802       _on_issue_err "$_post_hook" | 
|  | 5803       return 1 | 
|  | 5804     fi | 
|  | 5805 | 
|  | 5806     response="$(echo "$response" | _normalizeJson)" | 
|  | 5807     _debug2 response "$response" | 
|  | 5808     _URL_NAME="url" | 
|  | 5809   else | 
|  | 5810     if ! __get_domain_new_authz "$_d_domain"; then | 
|  | 5811       _err "Can not get domain new authz token." | 
|  | 5812       return 1 | 
|  | 5813     fi | 
|  | 5814 | 
|  | 5815     authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ':' -f 2- | tr -d "\r\n")" | 
|  | 5816     _debug "authzUri" "$authzUri" | 
|  | 5817     if [ "$code" ] && [ ! "$code" = '201' ]; then | 
|  | 5818       _err "new-authz error: $response" | 
|  | 5819       return 1 | 
|  | 5820     fi | 
|  | 5821     _URL_NAME="uri" | 
|  | 5822   fi | 
|  | 5823 | 
|  | 5824   entries="$(echo "$response" | _egrep_o "[^{]*\"type\":\"[^\"]*\", *\"status\": *\"valid\", *\"$_URL_NAME\"[^}]*")" | 
|  | 5825   if [ -z "$entries" ]; then | 
|  | 5826     _info "No valid entries found." | 
|  | 5827     if [ -z "$thumbprint" ]; then | 
|  | 5828       thumbprint="$(__calc_account_thumbprint)" | 
|  | 5829     fi | 
|  | 5830     _debug "Trigger validation." | 
|  | 5831     vtype="$VTYPE_DNS" | 
|  | 5832     entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" | 
|  | 5833     _debug entry "$entry" | 
|  | 5834     if [ -z "$entry" ]; then | 
|  | 5835       _err "Error, can not get domain token $d" | 
|  | 5836       return 1 | 
|  | 5837     fi | 
|  | 5838     token="$(echo "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" | 
|  | 5839     _debug token "$token" | 
|  | 5840 | 
|  | 5841     uri="$(echo "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" | 
|  | 5842     _debug uri "$uri" | 
|  | 5843 | 
|  | 5844     keyauthorization="$token.$thumbprint" | 
|  | 5845     _debug keyauthorization "$keyauthorization" | 
|  | 5846     __trigger_validation "$uri" "$keyauthorization" | 
|  | 5847 | 
|  | 5848   fi | 
|  | 5849 | 
|  | 5850   _d_i=0 | 
|  | 5851   _d_max_retry=$(echo "$entries" | wc -l) | 
|  | 5852   while [ "$_d_i" -lt "$_d_max_retry" ]; do | 
|  | 5853     _info "Deactivate: $_d_domain" | 
|  | 5854     _d_i="$(_math $_d_i + 1)" | 
|  | 5855     entry="$(echo "$entries" | sed -n "${_d_i}p")" | 
|  | 5856     _debug entry "$entry" | 
|  | 5857 | 
|  | 5858     if [ -z "$entry" ]; then | 
|  | 5859       _info "No more valid entry found." | 
|  | 5860       break | 
|  | 5861     fi | 
|  | 5862 | 
|  | 5863     _vtype="$(echo "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')" | 
|  | 5864     _debug _vtype "$_vtype" | 
|  | 5865     _info "Found $_vtype" | 
|  | 5866 | 
|  | 5867     uri="$(echo "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" | 
|  | 5868     _debug uri "$uri" | 
|  | 5869 | 
|  | 5870     if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then | 
|  | 5871       _info "Skip $_vtype" | 
|  | 5872       continue | 
|  | 5873     fi | 
|  | 5874 | 
|  | 5875     _info "Deactivate: $_vtype" | 
|  | 5876 | 
|  | 5877     if [ "$ACME_VERSION" = "2" ]; then | 
|  | 5878       _djson="{\"status\":\"deactivated\"}" | 
|  | 5879     else | 
|  | 5880       _djson="{\"resource\": \"authz\", \"status\":\"deactivated\"}" | 
|  | 5881     fi | 
|  | 5882 | 
|  | 5883     if _send_signed_request "$authzUri" "$_djson" && _contains "$response" '"deactivated"'; then | 
|  | 5884       _info "Deactivate: $_vtype success." | 
|  | 5885     else | 
|  | 5886       _err "Can not deactivate $_vtype." | 
|  | 5887       break | 
|  | 5888     fi | 
|  | 5889 | 
|  | 5890   done | 
|  | 5891   _debug "$_d_i" | 
|  | 5892   if [ "$_d_i" -eq "$_d_max_retry" ]; then | 
|  | 5893     _info "Deactivated success!" | 
|  | 5894   else | 
|  | 5895     _err "Deactivate failed." | 
|  | 5896   fi | 
|  | 5897 | 
|  | 5898 } | 
|  | 5899 | 
|  | 5900 deactivate() { | 
|  | 5901   _d_domain_list="$1" | 
|  | 5902   _d_type="$2" | 
|  | 5903   _initpath | 
|  | 5904   _initAPI | 
|  | 5905   _debug _d_domain_list "$_d_domain_list" | 
|  | 5906   if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then | 
|  | 5907     _usage "Usage: $PROJECT_ENTRY --deactivate --domain <domain.tld> [--domain <domain2.tld> ...]" | 
|  | 5908     return 1 | 
|  | 5909   fi | 
|  | 5910   for _d_dm in $(echo "$_d_domain_list" | tr ',' ' '); do | 
|  | 5911     if [ -z "$_d_dm" ] || [ "$_d_dm" = "$NO_VALUE" ]; then | 
|  | 5912       continue | 
|  | 5913     fi | 
|  | 5914     if ! _deactivate "$_d_dm" "$_d_type"; then | 
|  | 5915       return 1 | 
|  | 5916     fi | 
|  | 5917   done | 
|  | 5918 } | 
|  | 5919 | 
|  | 5920 # Detect profile file if not specified as environment variable | 
|  | 5921 _detect_profile() { | 
|  | 5922   if [ -n "$PROFILE" -a -f "$PROFILE" ]; then | 
|  | 5923     echo "$PROFILE" | 
|  | 5924     return | 
|  | 5925   fi | 
|  | 5926 | 
|  | 5927   DETECTED_PROFILE='' | 
|  | 5928   SHELLTYPE="$(basename "/$SHELL")" | 
|  | 5929 | 
|  | 5930   if [ "$SHELLTYPE" = "bash" ]; then | 
|  | 5931     if [ -f "$HOME/.bashrc" ]; then | 
|  | 5932       DETECTED_PROFILE="$HOME/.bashrc" | 
|  | 5933     elif [ -f "$HOME/.bash_profile" ]; then | 
|  | 5934       DETECTED_PROFILE="$HOME/.bash_profile" | 
|  | 5935     fi | 
|  | 5936   elif [ "$SHELLTYPE" = "zsh" ]; then | 
|  | 5937     DETECTED_PROFILE="$HOME/.zshrc" | 
|  | 5938   fi | 
|  | 5939 | 
|  | 5940   if [ -z "$DETECTED_PROFILE" ]; then | 
|  | 5941     if [ -f "$HOME/.profile" ]; then | 
|  | 5942       DETECTED_PROFILE="$HOME/.profile" | 
|  | 5943     elif [ -f "$HOME/.bashrc" ]; then | 
|  | 5944       DETECTED_PROFILE="$HOME/.bashrc" | 
|  | 5945     elif [ -f "$HOME/.bash_profile" ]; then | 
|  | 5946       DETECTED_PROFILE="$HOME/.bash_profile" | 
|  | 5947     elif [ -f "$HOME/.zshrc" ]; then | 
|  | 5948       DETECTED_PROFILE="$HOME/.zshrc" | 
|  | 5949     fi | 
|  | 5950   fi | 
|  | 5951 | 
|  | 5952   echo "$DETECTED_PROFILE" | 
|  | 5953 } | 
|  | 5954 | 
|  | 5955 _initconf() { | 
|  | 5956   _initpath | 
|  | 5957   if [ ! -f "$ACCOUNT_CONF_PATH" ]; then | 
|  | 5958     echo " | 
|  | 5959 #LOG_FILE=\"$DEFAULT_LOG_FILE\" | 
|  | 5960 #LOG_LEVEL=1 | 
|  | 5961 #AUTO_UPGRADE=\"1\" | 
|  | 5962 #NO_TIMESTAMP=1 | 
|  | 5963     " >"$ACCOUNT_CONF_PATH" | 
|  | 5964   fi | 
|  | 5965 } | 
|  | 5966 | 
|  | 5967 # nocron | 
|  | 5968 _precheck() { | 
|  | 5969   _nocron="$1" | 
|  | 5970 | 
|  | 5971   if ! _exists "curl" && ! _exists "wget"; then | 
|  | 5972     _err "Please install curl or wget first, we need to access http resources." | 
|  | 5973     return 1 | 
|  | 5974   fi | 
|  | 5975 | 
|  | 5976   if [ -z "$_nocron" ]; then | 
|  | 5977     if ! _exists "crontab" && ! _exists "fcrontab"; then | 
|  | 5978       if _exists cygpath && _exists schtasks.exe; then | 
|  | 5979         _info "It seems you are on Windows,  we will install Windows scheduler task." | 
|  | 5980       else | 
|  | 5981         _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." | 
|  | 5982         _err "We need to set cron job to renew the certs automatically." | 
|  | 5983         _err "Otherwise, your certs will not be able to be renewed automatically." | 
|  | 5984         if [ -z "$FORCE" ]; then | 
|  | 5985           _err "Please add '--force' and try install again to go without crontab." | 
|  | 5986           _err "./$PROJECT_ENTRY --install --force" | 
|  | 5987           return 1 | 
|  | 5988         fi | 
|  | 5989       fi | 
|  | 5990     fi | 
|  | 5991   fi | 
|  | 5992 | 
|  | 5993   if ! _exists "${ACME_OPENSSL_BIN:-openssl}"; then | 
|  | 5994     _err "Please install openssl first. ACME_OPENSSL_BIN=$ACME_OPENSSL_BIN" | 
|  | 5995     _err "We need openssl to generate keys." | 
|  | 5996     return 1 | 
|  | 5997   fi | 
|  | 5998 | 
|  | 5999   if ! _exists "socat"; then | 
|  | 6000     _err "It is recommended to install socat first." | 
|  | 6001     _err "We use socat for standalone server if you use standalone mode." | 
|  | 6002     _err "If you don't use standalone mode, just ignore this warning." | 
|  | 6003   fi | 
|  | 6004 | 
|  | 6005   return 0 | 
|  | 6006 } | 
|  | 6007 | 
|  | 6008 _setShebang() { | 
|  | 6009   _file="$1" | 
|  | 6010   _shebang="$2" | 
|  | 6011   if [ -z "$_shebang" ]; then | 
|  | 6012     _usage "Usage: file shebang" | 
|  | 6013     return 1 | 
|  | 6014   fi | 
|  | 6015   cp "$_file" "$_file.tmp" | 
|  | 6016   echo "$_shebang" >"$_file" | 
|  | 6017   sed -n 2,99999p "$_file.tmp" >>"$_file" | 
|  | 6018   rm -f "$_file.tmp" | 
|  | 6019 } | 
|  | 6020 | 
|  | 6021 #confighome | 
|  | 6022 _installalias() { | 
|  | 6023   _c_home="$1" | 
|  | 6024   _initpath | 
|  | 6025 | 
|  | 6026   _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" | 
|  | 6027   if [ "$_upgrading" ] && [ "$_upgrading" = "1" ]; then | 
|  | 6028     echo "$(cat "$_envfile")" | sed "s|^LE_WORKING_DIR.*$||" >"$_envfile" | 
|  | 6029     echo "$(cat "$_envfile")" | sed "s|^alias le.*$||" >"$_envfile" | 
|  | 6030     echo "$(cat "$_envfile")" | sed "s|^alias le.sh.*$||" >"$_envfile" | 
|  | 6031   fi | 
|  | 6032 | 
|  | 6033   if [ "$_c_home" ]; then | 
|  | 6034     _c_entry=" --config-home '$_c_home'" | 
|  | 6035   fi | 
|  | 6036 | 
|  | 6037   _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" | 
|  | 6038   if [ "$_c_home" ]; then | 
|  | 6039     _setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\"" | 
|  | 6040   else | 
|  | 6041     _sed_i "/^export LE_CONFIG_HOME/d" "$_envfile" | 
|  | 6042   fi | 
|  | 6043   _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" | 
|  | 6044 | 
|  | 6045   _profile="$(_detect_profile)" | 
|  | 6046   if [ "$_profile" ]; then | 
|  | 6047     _debug "Found profile: $_profile" | 
|  | 6048     _info "Installing alias to '$_profile'" | 
|  | 6049     _setopt "$_profile" ". \"$_envfile\"" | 
|  | 6050     _info "OK, Close and reopen your terminal to start using $PROJECT_NAME" | 
|  | 6051   else | 
|  | 6052     _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME" | 
|  | 6053   fi | 
|  | 6054 | 
|  | 6055   #for csh | 
|  | 6056   _cshfile="$LE_WORKING_DIR/$PROJECT_ENTRY.csh" | 
|  | 6057   _csh_profile="$HOME/.cshrc" | 
|  | 6058   if [ -f "$_csh_profile" ]; then | 
|  | 6059     _info "Installing alias to '$_csh_profile'" | 
|  | 6060     _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" | 
|  | 6061     if [ "$_c_home" ]; then | 
|  | 6062       _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" | 
|  | 6063     else | 
|  | 6064       _sed_i "/^setenv LE_CONFIG_HOME/d" "$_cshfile" | 
|  | 6065     fi | 
|  | 6066     _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" | 
|  | 6067     _setopt "$_csh_profile" "source \"$_cshfile\"" | 
|  | 6068   fi | 
|  | 6069 | 
|  | 6070   #for tcsh | 
|  | 6071   _tcsh_profile="$HOME/.tcshrc" | 
|  | 6072   if [ -f "$_tcsh_profile" ]; then | 
|  | 6073     _info "Installing alias to '$_tcsh_profile'" | 
|  | 6074     _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" | 
|  | 6075     if [ "$_c_home" ]; then | 
|  | 6076       _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" | 
|  | 6077     fi | 
|  | 6078     _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" | 
|  | 6079     _setopt "$_tcsh_profile" "source \"$_cshfile\"" | 
|  | 6080   fi | 
|  | 6081 | 
|  | 6082 } | 
|  | 6083 | 
|  | 6084 # nocron confighome noprofile | 
|  | 6085 install() { | 
|  | 6086 | 
|  | 6087   if [ -z "$LE_WORKING_DIR" ]; then | 
|  | 6088     LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" | 
|  | 6089   fi | 
|  | 6090 | 
|  | 6091   _nocron="$1" | 
|  | 6092   _c_home="$2" | 
|  | 6093   _noprofile="$3" | 
|  | 6094   if ! _initpath; then | 
|  | 6095     _err "Install failed." | 
|  | 6096     return 1 | 
|  | 6097   fi | 
|  | 6098   if [ "$_nocron" ]; then | 
|  | 6099     _debug "Skip install cron job" | 
|  | 6100   fi | 
|  | 6101 | 
|  | 6102   if [ "$_ACME_IN_CRON" != "1" ]; then | 
|  | 6103     if ! _precheck "$_nocron"; then | 
|  | 6104       _err "Pre-check failed, can not install." | 
|  | 6105       return 1 | 
|  | 6106     fi | 
|  | 6107   fi | 
|  | 6108 | 
|  | 6109   if [ -z "$_c_home" ] && [ "$LE_CONFIG_HOME" != "$LE_WORKING_DIR" ]; then | 
|  | 6110     _info "Using config home: $LE_CONFIG_HOME" | 
|  | 6111     _c_home="$LE_CONFIG_HOME" | 
|  | 6112   fi | 
|  | 6113 | 
|  | 6114   #convert from le | 
|  | 6115   if [ -d "$HOME/.le" ]; then | 
|  | 6116     for envfile in "le.env" "le.sh.env"; do | 
|  | 6117       if [ -f "$HOME/.le/$envfile" ]; then | 
|  | 6118         if grep "le.sh" "$HOME/.le/$envfile" >/dev/null; then | 
|  | 6119           _upgrading="1" | 
|  | 6120           _info "You are upgrading from le.sh" | 
|  | 6121           _info "Renaming \"$HOME/.le\" to $LE_WORKING_DIR" | 
|  | 6122           mv "$HOME/.le" "$LE_WORKING_DIR" | 
|  | 6123           mv "$LE_WORKING_DIR/$envfile" "$LE_WORKING_DIR/$PROJECT_ENTRY.env" | 
|  | 6124           break | 
|  | 6125         fi | 
|  | 6126       fi | 
|  | 6127     done | 
|  | 6128   fi | 
|  | 6129 | 
|  | 6130   _info "Installing to $LE_WORKING_DIR" | 
|  | 6131 | 
|  | 6132   if [ ! -d "$LE_WORKING_DIR" ]; then | 
|  | 6133     if ! mkdir -p "$LE_WORKING_DIR"; then | 
|  | 6134       _err "Can not create working dir: $LE_WORKING_DIR" | 
|  | 6135       return 1 | 
|  | 6136     fi | 
|  | 6137 | 
|  | 6138     chmod 700 "$LE_WORKING_DIR" | 
|  | 6139   fi | 
|  | 6140 | 
|  | 6141   if [ ! -d "$LE_CONFIG_HOME" ]; then | 
|  | 6142     if ! mkdir -p "$LE_CONFIG_HOME"; then | 
|  | 6143       _err "Can not create config dir: $LE_CONFIG_HOME" | 
|  | 6144       return 1 | 
|  | 6145     fi | 
|  | 6146 | 
|  | 6147     chmod 700 "$LE_CONFIG_HOME" | 
|  | 6148   fi | 
|  | 6149 | 
|  | 6150   cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" | 
|  | 6151 | 
|  | 6152   if [ "$?" != "0" ]; then | 
|  | 6153     _err "Install failed, can not copy $PROJECT_ENTRY" | 
|  | 6154     return 1 | 
|  | 6155   fi | 
|  | 6156 | 
|  | 6157   _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" | 
|  | 6158 | 
|  | 6159   if [ "$_ACME_IN_CRON" != "1" ] && [ -z "$_noprofile" ]; then | 
|  | 6160     _installalias "$_c_home" | 
|  | 6161   fi | 
|  | 6162 | 
|  | 6163   for subf in $_SUB_FOLDERS; do | 
|  | 6164     if [ -d "$subf" ]; then | 
|  | 6165       mkdir -p "$LE_WORKING_DIR/$subf" | 
|  | 6166       cp "$subf"/* "$LE_WORKING_DIR"/"$subf"/ | 
|  | 6167     fi | 
|  | 6168   done | 
|  | 6169 | 
|  | 6170   if [ ! -f "$ACCOUNT_CONF_PATH" ]; then | 
|  | 6171     _initconf | 
|  | 6172   fi | 
|  | 6173 | 
|  | 6174   if [ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ]; then | 
|  | 6175     _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" | 
|  | 6176   fi | 
|  | 6177 | 
|  | 6178   if [ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ]; then | 
|  | 6179     _saveaccountconf "CERT_HOME" "$CERT_HOME" | 
|  | 6180   fi | 
|  | 6181 | 
|  | 6182   if [ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ]; then | 
|  | 6183     _saveaccountconf "ACCOUNT_KEY_PATH" "$ACCOUNT_KEY_PATH" | 
|  | 6184   fi | 
|  | 6185 | 
|  | 6186   if [ -z "$_nocron" ]; then | 
|  | 6187     installcronjob "$_c_home" | 
|  | 6188   fi | 
|  | 6189 | 
|  | 6190   if [ -z "$NO_DETECT_SH" ]; then | 
|  | 6191     #Modify shebang | 
|  | 6192     if _exists bash; then | 
|  | 6193       _bash_path="$(bash -c "command -v bash 2>/dev/null")" | 
|  | 6194       if [ -z "$_bash_path" ]; then | 
|  | 6195         _bash_path="$(bash -c 'echo $SHELL')" | 
|  | 6196       fi | 
|  | 6197     fi | 
|  | 6198     if [ "$_bash_path" ]; then | 
|  | 6199       _info "Good, bash is found, so change the shebang to use bash as preferred." | 
|  | 6200       _shebang='#!'"$_bash_path" | 
|  | 6201       _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" | 
|  | 6202       for subf in $_SUB_FOLDERS; do | 
|  | 6203         if [ -d "$LE_WORKING_DIR/$subf" ]; then | 
|  | 6204           for _apifile in "$LE_WORKING_DIR/$subf/"*.sh; do | 
|  | 6205             _setShebang "$_apifile" "$_shebang" | 
|  | 6206           done | 
|  | 6207         fi | 
|  | 6208       done | 
|  | 6209     fi | 
|  | 6210   fi | 
|  | 6211 | 
|  | 6212   _info OK | 
|  | 6213 } | 
|  | 6214 | 
|  | 6215 # nocron | 
|  | 6216 uninstall() { | 
|  | 6217   _nocron="$1" | 
|  | 6218   if [ -z "$_nocron" ]; then | 
|  | 6219     uninstallcronjob | 
|  | 6220   fi | 
|  | 6221   _initpath | 
|  | 6222 | 
|  | 6223   _uninstallalias | 
|  | 6224 | 
|  | 6225   rm -f "$LE_WORKING_DIR/$PROJECT_ENTRY" | 
|  | 6226   _info "The keys and certs are in \"$(__green "$LE_CONFIG_HOME")\", you can remove them by yourself." | 
|  | 6227 | 
|  | 6228 } | 
|  | 6229 | 
|  | 6230 _uninstallalias() { | 
|  | 6231   _initpath | 
|  | 6232 | 
|  | 6233   _profile="$(_detect_profile)" | 
|  | 6234   if [ "$_profile" ]; then | 
|  | 6235     _info "Uninstalling alias from: '$_profile'" | 
|  | 6236     text="$(cat "$_profile")" | 
|  | 6237     echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" >"$_profile" | 
|  | 6238   fi | 
|  | 6239 | 
|  | 6240   _csh_profile="$HOME/.cshrc" | 
|  | 6241   if [ -f "$_csh_profile" ]; then | 
|  | 6242     _info "Uninstalling alias from: '$_csh_profile'" | 
|  | 6243     text="$(cat "$_csh_profile")" | 
|  | 6244     echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_csh_profile" | 
|  | 6245   fi | 
|  | 6246 | 
|  | 6247   _tcsh_profile="$HOME/.tcshrc" | 
|  | 6248   if [ -f "$_tcsh_profile" ]; then | 
|  | 6249     _info "Uninstalling alias from: '$_csh_profile'" | 
|  | 6250     text="$(cat "$_tcsh_profile")" | 
|  | 6251     echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_tcsh_profile" | 
|  | 6252   fi | 
|  | 6253 | 
|  | 6254 } | 
|  | 6255 | 
|  | 6256 cron() { | 
|  | 6257   export _ACME_IN_CRON=1 | 
|  | 6258   _initpath | 
|  | 6259   _info "$(__green "===Starting cron===")" | 
|  | 6260   if [ "$AUTO_UPGRADE" = "1" ]; then | 
|  | 6261     export LE_WORKING_DIR | 
|  | 6262     ( | 
|  | 6263       if ! upgrade; then | 
|  | 6264         _err "Cron:Upgrade failed!" | 
|  | 6265         return 1 | 
|  | 6266       fi | 
|  | 6267     ) | 
|  | 6268     . "$LE_WORKING_DIR/$PROJECT_ENTRY" >/dev/null | 
|  | 6269 | 
|  | 6270     if [ -t 1 ]; then | 
|  | 6271       __INTERACTIVE="1" | 
|  | 6272     fi | 
|  | 6273 | 
|  | 6274     _info "Auto upgraded to: $VER" | 
|  | 6275   fi | 
|  | 6276   renewAll | 
|  | 6277   _ret="$?" | 
|  | 6278   _ACME_IN_CRON="" | 
|  | 6279   _info "$(__green "===End cron===")" | 
|  | 6280   exit $_ret | 
|  | 6281 } | 
|  | 6282 | 
|  | 6283 version() { | 
|  | 6284   echo "$PROJECT" | 
|  | 6285   echo "v$VER" | 
|  | 6286 } | 
|  | 6287 | 
|  | 6288 # subject content hooks code | 
|  | 6289 _send_notify() { | 
|  | 6290   _nsubject="$1" | 
|  | 6291   _ncontent="$2" | 
|  | 6292   _nhooks="$3" | 
|  | 6293   _nerror="$4" | 
|  | 6294 | 
|  | 6295   if [ "$NOTIFY_LEVEL" = "$NOTIFY_LEVEL_DISABLE" ]; then | 
|  | 6296     _debug "The NOTIFY_LEVEL is $NOTIFY_LEVEL, disabled, just return." | 
|  | 6297     return 0 | 
|  | 6298   fi | 
|  | 6299 | 
|  | 6300   if [ -z "$_nhooks" ]; then | 
|  | 6301     _debug "The NOTIFY_HOOK is empty, just return." | 
|  | 6302     return 0 | 
|  | 6303   fi | 
|  | 6304 | 
|  | 6305   _send_err=0 | 
|  | 6306   for _n_hook in $(echo "$_nhooks" | tr ',' " "); do | 
|  | 6307     _n_hook_file="$(_findHook "" $_SUB_FOLDER_NOTIFY "$_n_hook")" | 
|  | 6308     _info "Sending via: $_n_hook" | 
|  | 6309     _debug "Found $_n_hook_file for $_n_hook" | 
|  | 6310     if [ -z "$_n_hook_file" ]; then | 
|  | 6311       _err "Can not find the hook file for $_n_hook" | 
|  | 6312       continue | 
|  | 6313     fi | 
|  | 6314     if ! ( | 
|  | 6315       if ! . "$_n_hook_file"; then | 
|  | 6316         _err "Load file $_n_hook_file error. Please check your api file and try again." | 
|  | 6317         return 1 | 
|  | 6318       fi | 
|  | 6319 | 
|  | 6320       d_command="${_n_hook}_send" | 
|  | 6321       if ! _exists "$d_command"; then | 
|  | 6322         _err "It seems that your api file is not correct, it must have a function named: $d_command" | 
|  | 6323         return 1 | 
|  | 6324       fi | 
|  | 6325 | 
|  | 6326       if ! $d_command "$_nsubject" "$_ncontent" "$_nerror"; then | 
|  | 6327         _err "Error send message by $d_command" | 
|  | 6328         return 1 | 
|  | 6329       fi | 
|  | 6330 | 
|  | 6331       return 0 | 
|  | 6332     ); then | 
|  | 6333       _err "Set $_n_hook_file error." | 
|  | 6334       _send_err=1 | 
|  | 6335     else | 
|  | 6336       _info "$_n_hook $(__green Success)" | 
|  | 6337     fi | 
|  | 6338   done | 
|  | 6339   return $_send_err | 
|  | 6340 | 
|  | 6341 } | 
|  | 6342 | 
|  | 6343 # hook | 
|  | 6344 _set_notify_hook() { | 
|  | 6345   _nhooks="$1" | 
|  | 6346 | 
|  | 6347   _test_subject="Hello, this is a notification from $PROJECT_NAME" | 
|  | 6348   _test_content="If you receive this message, your notification works." | 
|  | 6349 | 
|  | 6350   _send_notify "$_test_subject" "$_test_content" "$_nhooks" 0 | 
|  | 6351 | 
|  | 6352 } | 
|  | 6353 | 
|  | 6354 #[hook] [level] [mode] | 
|  | 6355 setnotify() { | 
|  | 6356   _nhook="$1" | 
|  | 6357   _nlevel="$2" | 
|  | 6358   _nmode="$3" | 
|  | 6359 | 
|  | 6360   _initpath | 
|  | 6361 | 
|  | 6362   if [ -z "$_nhook$_nlevel$_nmode" ]; then | 
|  | 6363     _usage "Usage: $PROJECT_ENTRY --set-notify [--notify-hook <hookname>] [--notify-level <0|1|2|3>] [--notify-mode <0|1>]" | 
|  | 6364     _usage "$_NOTIFY_WIKI" | 
|  | 6365     return 1 | 
|  | 6366   fi | 
|  | 6367 | 
|  | 6368   if [ "$_nlevel" ]; then | 
|  | 6369     _info "Set notify level to: $_nlevel" | 
|  | 6370     export "NOTIFY_LEVEL=$_nlevel" | 
|  | 6371     _saveaccountconf "NOTIFY_LEVEL" "$NOTIFY_LEVEL" | 
|  | 6372   fi | 
|  | 6373 | 
|  | 6374   if [ "$_nmode" ]; then | 
|  | 6375     _info "Set notify mode to: $_nmode" | 
|  | 6376     export "NOTIFY_MODE=$_nmode" | 
|  | 6377     _saveaccountconf "NOTIFY_MODE" "$NOTIFY_MODE" | 
|  | 6378   fi | 
|  | 6379 | 
|  | 6380   if [ "$_nhook" ]; then | 
|  | 6381     _info "Set notify hook to: $_nhook" | 
|  | 6382     if [ "$_nhook" = "$NO_VALUE" ]; then | 
|  | 6383       _info "Clear notify hook" | 
|  | 6384       _clearaccountconf "NOTIFY_HOOK" | 
|  | 6385     else | 
|  | 6386       if _set_notify_hook "$_nhook"; then | 
|  | 6387         export NOTIFY_HOOK="$_nhook" | 
|  | 6388         _saveaccountconf "NOTIFY_HOOK" "$NOTIFY_HOOK" | 
|  | 6389         return 0 | 
|  | 6390       else | 
|  | 6391         _err "Can not set notify hook to: $_nhook" | 
|  | 6392         return 1 | 
|  | 6393       fi | 
|  | 6394     fi | 
|  | 6395   fi | 
|  | 6396 | 
|  | 6397 } | 
|  | 6398 | 
|  | 6399 showhelp() { | 
|  | 6400   _initpath | 
|  | 6401   version | 
|  | 6402   echo "Usage: $PROJECT_ENTRY <command> ... [parameters ...] | 
|  | 6403 Commands: | 
|  | 6404   -h, --help               Show this help message. | 
|  | 6405   -v, --version            Show version info. | 
|  | 6406   --install                Install $PROJECT_NAME to your system. | 
|  | 6407   --uninstall              Uninstall $PROJECT_NAME, and uninstall the cron job. | 
|  | 6408   --upgrade                Upgrade $PROJECT_NAME to the latest code from $PROJECT. | 
|  | 6409   --issue                  Issue a cert. | 
|  | 6410   --deploy                 Deploy the cert to your server. | 
|  | 6411   -i, --install-cert       Install the issued cert to apache/nginx or any other server. | 
|  | 6412   -r, --renew              Renew a cert. | 
|  | 6413   --renew-all              Renew all the certs. | 
|  | 6414   --revoke                 Revoke a cert. | 
|  | 6415   --remove                 Remove the cert from list of certs known to $PROJECT_NAME. | 
|  | 6416   --list                   List all the certs. | 
|  | 6417   --to-pkcs12              Export the certificate and key to a pfx file. | 
|  | 6418   --to-pkcs8               Convert to pkcs8 format. | 
|  | 6419   --sign-csr               Issue a cert from an existing csr. | 
|  | 6420   --show-csr               Show the content of a csr. | 
|  | 6421   -ccr, --create-csr       Create CSR, professional use. | 
|  | 6422   --create-domain-key      Create an domain private key, professional use. | 
|  | 6423   --update-account         Update account info. | 
|  | 6424   --register-account       Register account key. | 
|  | 6425   --deactivate-account     Deactivate the account. | 
|  | 6426   --create-account-key     Create an account private key, professional use. | 
|  | 6427   --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. | 
|  | 6428   --uninstall-cronjob      Uninstall the cron job. The 'uninstall' command can do this automatically. | 
|  | 6429   --cron                   Run cron job to renew all the certs. | 
|  | 6430   --set-notify             Set the cron notification hook, level or mode. | 
|  | 6431   --deactivate             Deactivate the domain authz, professional use. | 
|  | 6432   --set-default-ca         Used with '--server', Set the default CA to use. | 
|  | 6433                            See: $_SERVER_WIKI | 
|  | 6434 Parameters: | 
|  | 6435   -d, --domain <domain.tld>         Specifies a domain, used to issue, renew or revoke etc. | 
|  | 6436   --challenge-alias <domain.tld>    The challenge domain alias for DNS alias mode. | 
|  | 6437                                     See: $_DNS_ALIAS_WIKI | 
|  | 6438   --domain-alias <domain.tld>       The domain alias for DNS alias mode. | 
|  | 6439                                     See: $_DNS_ALIAS_WIKI | 
|  | 6440   --preferred-chain <chain>         If the CA offers multiple certificate chains, prefer the chain with an issuer matching this Subject Common Name. | 
|  | 6441                                     If no match, the default offered chain will be used. (default: empty) | 
|  | 6442                                     See: $_PREFERRED_CHAIN_WIKI | 
|  | 6443   -f, --force                       Force install, force cert renewal or override sudo restrictions. | 
|  | 6444   --staging, --test                 Use staging server, for testing. | 
|  | 6445   --debug [0|1|2|3]                 Output debug info. Defaults to 1 if argument is omitted. | 
|  | 6446   --output-insecure                 Output all the sensitive messages. | 
|  | 6447                                     By default all the credentials/sensitive messages are hidden from the output/debug/log for security. | 
|  | 6448   -w, --webroot <directory>         Specifies the web root folder for web root mode. | 
|  | 6449   --standalone                      Use standalone mode. | 
|  | 6450   --alpn                            Use standalone alpn mode. | 
|  | 6451   --stateless                       Use stateless mode. | 
|  | 6452                                     See: $_STATELESS_WIKI | 
|  | 6453   --apache                          Use apache mode. | 
|  | 6454   --dns [dns_hook]                  Use dns manual mode or dns api. Defaults to manual mode when argument is omitted. | 
|  | 6455                                     See: $_DNS_API_WIKI | 
|  | 6456   --dnssleep <seconds>              The time in seconds to wait for all the txt records to propagate in dns api mode. | 
|  | 6457                                     It's not necessary to use this by default, $PROJECT_NAME polls dns status by DOH automatically. | 
|  | 6458   -k, --keylength <bits>            Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384, ec-521. | 
|  | 6459   -ak, --accountkeylength <bits>    Specifies the account key length: 2048, 3072, 4096 | 
|  | 6460   --log [file]                      Specifies the log file. Defaults to \"$DEFAULT_LOG_FILE\" if argument is omitted. | 
|  | 6461   --log-level <1|2>                 Specifies the log level, default is 1. | 
|  | 6462   --syslog <0|3|6|7>                Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug. | 
|  | 6463   --eab-kid <eab_key_id>            Key Identifier for External Account Binding. | 
|  | 6464   --eab-hmac-key <eab_hmac_key>     HMAC key for External Account Binding. | 
|  | 6465   These parameters are to install the cert to nginx/apache or any other server after issue/renew a cert: | 
|  | 6466   --cert-file <file>                Path to copy the cert file to after issue/renew.. | 
|  | 6467   --key-file <file>                 Path to copy the key file to after issue/renew. | 
|  | 6468   --ca-file <file>                  Path to copy the intermediate cert file to after issue/renew. | 
|  | 6469   --fullchain-file <file>           Path to copy the fullchain cert file to after issue/renew. | 
|  | 6470   --reloadcmd <command>             Command to execute after issue/renew to reload the server. | 
|  | 6471   --server <server_uri>             ACME Directory Resource URI. (default: $DEFAULT_CA) | 
|  | 6472                                     See: $_SERVER_WIKI | 
|  | 6473   --accountconf <file>              Specifies a customized account config file. | 
|  | 6474   --home <directory>                Specifies the home dir for $PROJECT_NAME. | 
|  | 6475   --cert-home <directory>           Specifies the home dir to save all the certs, only valid for '--install' command. | 
|  | 6476   --config-home <directory>         Specifies the home dir to save all the configurations. | 
|  | 6477   --useragent <string>              Specifies the user agent string. it will be saved for future use too. | 
|  | 6478   -m, --accountemail <email>        Specifies the account email, only valid for the '--install' and '--update-account' command. | 
|  | 6479   --accountkey <file>               Specifies the account key path, only valid for the '--install' command. | 
|  | 6480   --days <ndays>                    Specifies the days to renew the cert when using '--issue' command. The default value is $DEFAULT_RENEW days. | 
|  | 6481   --httpport <port>                 Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer. | 
|  | 6482   --tlsport <port>                  Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer. | 
|  | 6483   --local-address <ip>              Specifies the standalone/tls server listening address, in case you have multiple ip addresses. | 
|  | 6484   --listraw                         Only used for '--list' command, list the certs in raw format. | 
|  | 6485   -se, --stop-renew-on-error        Only valid for '--renew-all' command. Stop if one cert has error in renewal. | 
|  | 6486   --insecure                        Do not check the server certificate, in some devices, the api server's certificate may not be trusted. | 
|  | 6487   --ca-bundle <file>                Specifies the path to the CA certificate bundle to verify api server's certificate. | 
|  | 6488   --ca-path <directory>             Specifies directory containing CA certificates in PEM format, used by wget or curl. | 
|  | 6489   --nocron                          Only valid for '--install' command, which means: do not install the default cron job. | 
|  | 6490                                     In this case, the certs will not be renewed automatically. | 
|  | 6491   --noprofile                       Only valid for '--install' command, which means: do not install aliases to user profile. | 
|  | 6492   --no-color                        Do not output color text. | 
|  | 6493   --force-color                     Force output of color text. Useful for non-interactive use with the aha tool for HTML E-Mails. | 
|  | 6494   --ecc                             Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--to-pkcs12' and '--create-csr' | 
|  | 6495   --csr <file>                      Specifies the input csr. | 
|  | 6496   --pre-hook <command>              Command to be run before obtaining any certificates. | 
|  | 6497   --post-hook <command>             Command to be run after attempting to obtain/renew certificates. Runs regardless of whether obtain/renew succeeded or failed. | 
|  | 6498   --renew-hook <command>            Command to be run after each successfully renewed certificate. | 
|  | 6499   --deploy-hook <hookname>          The hook file to deploy cert | 
|  | 6500   --ocsp, --ocsp-must-staple        Generate OCSP-Must-Staple extension. | 
|  | 6501   --always-force-new-domain-key     Generate new domain key on renewal. Otherwise, the domain key is not changed by default. | 
|  | 6502   --auto-upgrade [0|1]              Valid for '--upgrade' command, indicating whether to upgrade automatically in future. Defaults to 1 if argument is omitted. | 
|  | 6503   --listen-v4                       Force standalone/tls server to listen at ipv4. | 
|  | 6504   --listen-v6                       Force standalone/tls server to listen at ipv6. | 
|  | 6505   --openssl-bin <file>              Specifies a custom openssl bin location. | 
|  | 6506   --use-wget                        Force to use wget, if you have both curl and wget installed. | 
|  | 6507   --yes-I-know-dns-manual-mode-enough-go-ahead-please  Force use of dns manual mode. | 
|  | 6508                                     See:  $_DNS_MANUAL_WIKI | 
|  | 6509   -b, --branch <branch>             Only valid for '--upgrade' command, specifies the branch name to upgrade to. | 
|  | 6510   --notify-level <0|1|2|3>          Set the notification level:  Default value is $NOTIFY_LEVEL_DEFAULT. | 
|  | 6511                                     0: disabled, no notification will be sent. | 
|  | 6512                                     1: send notifications only when there is an error. | 
|  | 6513                                     2: send notifications when a cert is successfully renewed, or there is an error. | 
|  | 6514                                     3: send notifications when a cert is skipped, renewed, or error. | 
|  | 6515   --notify-mode <0|1>               Set notification mode. Default value is $NOTIFY_MODE_DEFAULT. | 
|  | 6516                                     0: Bulk mode. Send all the domain's notifications in one message(mail). | 
|  | 6517                                     1: Cert mode. Send a message for every single cert. | 
|  | 6518   --notify-hook <hookname>          Set the notify hook | 
|  | 6519   --revoke-reason <0-10>            The reason for revocation, can be used in conjunction with the '--revoke' command. | 
|  | 6520                                     See: $_REVOKE_WIKI | 
|  | 6521   --password <password>             Add a password to exported pfx file. Use with --to-pkcs12. | 
|  | 6522 " | 
|  | 6523 } | 
|  | 6524 | 
|  | 6525 # nocron noprofile | 
|  | 6526 _installOnline() { | 
|  | 6527   _info "Installing from online archive." | 
|  | 6528   _nocron="$1" | 
|  | 6529   _noprofile="$2" | 
|  | 6530   if [ ! "$BRANCH" ]; then | 
|  | 6531     BRANCH="master" | 
|  | 6532   fi | 
|  | 6533 | 
|  | 6534   target="$PROJECT/archive/$BRANCH.tar.gz" | 
|  | 6535   _info "Downloading $target" | 
|  | 6536   localname="$BRANCH.tar.gz" | 
|  | 6537   if ! _get "$target" >$localname; then | 
|  | 6538     _err "Download error." | 
|  | 6539     return 1 | 
|  | 6540   fi | 
|  | 6541   ( | 
|  | 6542     _info "Extracting $localname" | 
|  | 6543     if ! (tar xzf $localname || gtar xzf $localname); then | 
|  | 6544       _err "Extraction error." | 
|  | 6545       exit 1 | 
|  | 6546     fi | 
|  | 6547 | 
|  | 6548     cd "$PROJECT_NAME-$BRANCH" | 
|  | 6549     chmod +x $PROJECT_ENTRY | 
|  | 6550     if ./$PROJECT_ENTRY install "$_nocron" "" "$_noprofile"; then | 
|  | 6551       _info "Install success!" | 
|  | 6552       _initpath | 
|  | 6553       _saveaccountconf "UPGRADE_HASH" "$(_getUpgradeHash)" | 
|  | 6554     fi | 
|  | 6555 | 
|  | 6556     cd .. | 
|  | 6557 | 
|  | 6558     rm -rf "$PROJECT_NAME-$BRANCH" | 
|  | 6559     rm -f "$localname" | 
|  | 6560   ) | 
|  | 6561 } | 
|  | 6562 | 
|  | 6563 _getRepoHash() { | 
|  | 6564   _hash_path=$1 | 
|  | 6565   shift | 
|  | 6566   _hash_url="https://api.github.com/repos/acmesh-official/$PROJECT_NAME/git/refs/$_hash_path" | 
|  | 6567   _get $_hash_url | tr -d "\r\n" | tr '{},' '\n' | grep '"sha":' | cut -d '"' -f 4 | 
|  | 6568 } | 
|  | 6569 | 
|  | 6570 _getUpgradeHash() { | 
|  | 6571   _b="$BRANCH" | 
|  | 6572   if [ -z "$_b" ]; then | 
|  | 6573     _b="master" | 
|  | 6574   fi | 
|  | 6575   _hash=$(_getRepoHash "heads/$_b") | 
|  | 6576   if [ -z "$_hash" ]; then _hash=$(_getRepoHash "tags/$_b"); fi | 
|  | 6577   echo $_hash | 
|  | 6578 } | 
|  | 6579 | 
|  | 6580 upgrade() { | 
|  | 6581   if ( | 
|  | 6582     _initpath | 
|  | 6583     [ -z "$FORCE" ] && [ "$(_getUpgradeHash)" = "$(_readaccountconf "UPGRADE_HASH")" ] && _info "Already uptodate!" && exit 0 | 
|  | 6584     export LE_WORKING_DIR | 
|  | 6585     cd "$LE_WORKING_DIR" | 
|  | 6586     _installOnline "nocron" "noprofile" | 
|  | 6587   ); then | 
|  | 6588     _info "Upgrade success!" | 
|  | 6589     exit 0 | 
|  | 6590   else | 
|  | 6591     _err "Upgrade failed!" | 
|  | 6592     exit 1 | 
|  | 6593   fi | 
|  | 6594 } | 
|  | 6595 | 
|  | 6596 _processAccountConf() { | 
|  | 6597   if [ "$_useragent" ]; then | 
|  | 6598     _saveaccountconf "USER_AGENT" "$_useragent" | 
|  | 6599   elif [ "$USER_AGENT" ] && [ "$USER_AGENT" != "$DEFAULT_USER_AGENT" ]; then | 
|  | 6600     _saveaccountconf "USER_AGENT" "$USER_AGENT" | 
|  | 6601   fi | 
|  | 6602 | 
|  | 6603   if [ "$_openssl_bin" ]; then | 
|  | 6604     _saveaccountconf "ACME_OPENSSL_BIN" "$_openssl_bin" | 
|  | 6605   elif [ "$ACME_OPENSSL_BIN" ] && [ "$ACME_OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then | 
|  | 6606     _saveaccountconf "ACME_OPENSSL_BIN" "$ACME_OPENSSL_BIN" | 
|  | 6607   fi | 
|  | 6608 | 
|  | 6609   if [ "$_auto_upgrade" ]; then | 
|  | 6610     _saveaccountconf "AUTO_UPGRADE" "$_auto_upgrade" | 
|  | 6611   elif [ "$AUTO_UPGRADE" ]; then | 
|  | 6612     _saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE" | 
|  | 6613   fi | 
|  | 6614 | 
|  | 6615   if [ "$_use_wget" ]; then | 
|  | 6616     _saveaccountconf "ACME_USE_WGET" "$_use_wget" | 
|  | 6617   elif [ "$ACME_USE_WGET" ]; then | 
|  | 6618     _saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET" | 
|  | 6619   fi | 
|  | 6620 | 
|  | 6621 } | 
|  | 6622 | 
|  | 6623 _checkSudo() { | 
|  | 6624   if [ "$SUDO_GID" ] && [ "$SUDO_COMMAND" ] && [ "$SUDO_USER" ] && [ "$SUDO_UID" ]; then | 
|  | 6625     if [ "$SUDO_USER" = "root" ] && [ "$SUDO_UID" = "0" ]; then | 
|  | 6626       #it's root using sudo, no matter it's using sudo or not, just fine | 
|  | 6627       return 0 | 
|  | 6628     fi | 
|  | 6629     if [ -n "$SUDO_COMMAND" ]; then | 
|  | 6630       #it's a normal user doing "sudo su", or `sudo -i` or `sudo -s` | 
|  | 6631       _endswith "$SUDO_COMMAND" /bin/su || grep "^$SUDO_COMMAND\$" /etc/shells >/dev/null 2>&1 | 
|  | 6632       return $? | 
|  | 6633     fi | 
|  | 6634     #otherwise | 
|  | 6635     return 1 | 
|  | 6636   fi | 
|  | 6637   return 0 | 
|  | 6638 } | 
|  | 6639 | 
|  | 6640 #server | 
|  | 6641 _selectServer() { | 
|  | 6642   _server="$1" | 
|  | 6643   _server_lower="$(echo "$_server" | _lower_case)" | 
|  | 6644   _sindex=0 | 
|  | 6645   for snames in $CA_NAMES; do | 
|  | 6646     snames="$(echo "$snames" | _lower_case)" | 
|  | 6647     _sindex="$(_math $_sindex + 1)" | 
|  | 6648     _debug2 "_selectServer try snames" "$snames" | 
|  | 6649     for sname in $(echo "$snames" | tr ',' ' '); do | 
|  | 6650       if [ "$_server_lower" = "$sname" ]; then | 
|  | 6651         _debug2 "_selectServer match $sname" | 
|  | 6652         _serverdir="$(_getfield "$CA_SERVERS" $_sindex)" | 
|  | 6653         _debug "Selected server: $_serverdir" | 
|  | 6654         ACME_DIRECTORY="$_serverdir" | 
|  | 6655         export ACME_DIRECTORY | 
|  | 6656         return | 
|  | 6657       fi | 
|  | 6658     done | 
|  | 6659   done | 
|  | 6660   ACME_DIRECTORY="$_server" | 
|  | 6661   export ACME_DIRECTORY | 
|  | 6662 } | 
|  | 6663 | 
|  | 6664 #url | 
|  | 6665 _getCAShortName() { | 
|  | 6666   caurl="$1" | 
|  | 6667   if [ -z "$caurl" ]; then | 
|  | 6668     caurl="$DEFAULT_CA" | 
|  | 6669   fi | 
|  | 6670   caurl_lower="$(echo $caurl | _lower_case)" | 
|  | 6671   _sindex=0 | 
|  | 6672   for surl in $(echo "$CA_SERVERS" | _lower_case | tr , ' '); do | 
|  | 6673     _sindex="$(_math $_sindex + 1)" | 
|  | 6674     if [ "$caurl_lower" = "$surl" ]; then | 
|  | 6675       _nindex=0 | 
|  | 6676       for snames in $CA_NAMES; do | 
|  | 6677         _nindex="$(_math $_nindex + 1)" | 
|  | 6678         if [ $_nindex -ge $_sindex ]; then | 
|  | 6679           _getfield "$snames" 1 | 
|  | 6680           return | 
|  | 6681         fi | 
|  | 6682       done | 
|  | 6683     fi | 
|  | 6684   done | 
|  | 6685   echo "$caurl" | 
|  | 6686 } | 
|  | 6687 | 
|  | 6688 #set default ca to $ACME_DIRECTORY | 
|  | 6689 setdefaultca() { | 
|  | 6690   if [ -z "$ACME_DIRECTORY" ]; then | 
|  | 6691     _err "Please give a --server parameter." | 
|  | 6692     return 1 | 
|  | 6693   fi | 
|  | 6694   _saveaccountconf "DEFAULT_ACME_SERVER" "$ACME_DIRECTORY" | 
|  | 6695   _info "Changed default CA to: $(__green "$ACME_DIRECTORY")" | 
|  | 6696 } | 
|  | 6697 | 
|  | 6698 _process() { | 
|  | 6699   _CMD="" | 
|  | 6700   _domain="" | 
|  | 6701   _altdomains="$NO_VALUE" | 
|  | 6702   _webroot="" | 
|  | 6703   _challenge_alias="" | 
|  | 6704   _keylength="" | 
|  | 6705   _accountkeylength="" | 
|  | 6706   _cert_file="" | 
|  | 6707   _key_file="" | 
|  | 6708   _ca_file="" | 
|  | 6709   _fullchain_file="" | 
|  | 6710   _reloadcmd="" | 
|  | 6711   _password="" | 
|  | 6712   _accountconf="" | 
|  | 6713   _useragent="" | 
|  | 6714   _accountemail="" | 
|  | 6715   _accountkey="" | 
|  | 6716   _certhome="" | 
|  | 6717   _confighome="" | 
|  | 6718   _httpport="" | 
|  | 6719   _tlsport="" | 
|  | 6720   _dnssleep="" | 
|  | 6721   _listraw="" | 
|  | 6722   _stopRenewOnError="" | 
|  | 6723   #_insecure="" | 
|  | 6724   _ca_bundle="" | 
|  | 6725   _ca_path="" | 
|  | 6726   _nocron="" | 
|  | 6727   _noprofile="" | 
|  | 6728   _ecc="" | 
|  | 6729   _csr="" | 
|  | 6730   _pre_hook="" | 
|  | 6731   _post_hook="" | 
|  | 6732   _renew_hook="" | 
|  | 6733   _deploy_hook="" | 
|  | 6734   _logfile="" | 
|  | 6735   _log="" | 
|  | 6736   _local_address="" | 
|  | 6737   _log_level="" | 
|  | 6738   _auto_upgrade="" | 
|  | 6739   _listen_v4="" | 
|  | 6740   _listen_v6="" | 
|  | 6741   _openssl_bin="" | 
|  | 6742   _syslog="" | 
|  | 6743   _use_wget="" | 
|  | 6744   _server="" | 
|  | 6745   _notify_hook="" | 
|  | 6746   _notify_level="" | 
|  | 6747   _notify_mode="" | 
|  | 6748   _revoke_reason="" | 
|  | 6749   _eab_kid="" | 
|  | 6750   _eab_hmac_key="" | 
|  | 6751   _preferred_chain="" | 
|  | 6752   while [ ${#} -gt 0 ]; do | 
|  | 6753     case "${1}" in | 
|  | 6754 | 
|  | 6755     --help | -h) | 
|  | 6756       showhelp | 
|  | 6757       return | 
|  | 6758       ;; | 
|  | 6759     --version | -v) | 
|  | 6760       version | 
|  | 6761       return | 
|  | 6762       ;; | 
|  | 6763     --install) | 
|  | 6764       _CMD="install" | 
|  | 6765       ;; | 
|  | 6766     --uninstall) | 
|  | 6767       _CMD="uninstall" | 
|  | 6768       ;; | 
|  | 6769     --upgrade) | 
|  | 6770       _CMD="upgrade" | 
|  | 6771       ;; | 
|  | 6772     --issue) | 
|  | 6773       _CMD="issue" | 
|  | 6774       ;; | 
|  | 6775     --deploy) | 
|  | 6776       _CMD="deploy" | 
|  | 6777       ;; | 
|  | 6778     --sign-csr | --signcsr) | 
|  | 6779       _CMD="signcsr" | 
|  | 6780       ;; | 
|  | 6781     --show-csr | --showcsr) | 
|  | 6782       _CMD="showcsr" | 
|  | 6783       ;; | 
|  | 6784     -i | --install-cert | --installcert) | 
|  | 6785       _CMD="installcert" | 
|  | 6786       ;; | 
|  | 6787     --renew | -r) | 
|  | 6788       _CMD="renew" | 
|  | 6789       ;; | 
|  | 6790     --renew-all | --renewAll | --renewall) | 
|  | 6791       _CMD="renewAll" | 
|  | 6792       ;; | 
|  | 6793     --revoke) | 
|  | 6794       _CMD="revoke" | 
|  | 6795       ;; | 
|  | 6796     --remove) | 
|  | 6797       _CMD="remove" | 
|  | 6798       ;; | 
|  | 6799     --list) | 
|  | 6800       _CMD="list" | 
|  | 6801       ;; | 
|  | 6802     --install-cronjob | --installcronjob) | 
|  | 6803       _CMD="installcronjob" | 
|  | 6804       ;; | 
|  | 6805     --uninstall-cronjob | --uninstallcronjob) | 
|  | 6806       _CMD="uninstallcronjob" | 
|  | 6807       ;; | 
|  | 6808     --cron) | 
|  | 6809       _CMD="cron" | 
|  | 6810       ;; | 
|  | 6811     --to-pkcs12 | --to-pkcs | --toPkcs) | 
|  | 6812       _CMD="toPkcs" | 
|  | 6813       ;; | 
|  | 6814     --to-pkcs8 | --toPkcs8) | 
|  | 6815       _CMD="toPkcs8" | 
|  | 6816       ;; | 
|  | 6817     --create-account-key | --createAccountKey | --createaccountkey | -cak) | 
|  | 6818       _CMD="createAccountKey" | 
|  | 6819       ;; | 
|  | 6820     --create-domain-key | --createDomainKey | --createdomainkey | -cdk) | 
|  | 6821       _CMD="createDomainKey" | 
|  | 6822       ;; | 
|  | 6823     -ccr | --create-csr | --createCSR | --createcsr) | 
|  | 6824       _CMD="createCSR" | 
|  | 6825       ;; | 
|  | 6826     --deactivate) | 
|  | 6827       _CMD="deactivate" | 
|  | 6828       ;; | 
|  | 6829     --update-account | --updateaccount) | 
|  | 6830       _CMD="updateaccount" | 
|  | 6831       ;; | 
|  | 6832     --register-account | --registeraccount) | 
|  | 6833       _CMD="registeraccount" | 
|  | 6834       ;; | 
|  | 6835     --deactivate-account) | 
|  | 6836       _CMD="deactivateaccount" | 
|  | 6837       ;; | 
|  | 6838     --set-notify) | 
|  | 6839       _CMD="setnotify" | 
|  | 6840       ;; | 
|  | 6841     --set-default-ca) | 
|  | 6842       _CMD="setdefaultca" | 
|  | 6843       ;; | 
|  | 6844     -d | --domain) | 
|  | 6845       _dvalue="$2" | 
|  | 6846 | 
|  | 6847       if [ "$_dvalue" ]; then | 
|  | 6848         if _startswith "$_dvalue" "-"; then | 
|  | 6849           _err "'$_dvalue' is not a valid domain for parameter '$1'" | 
|  | 6850           return 1 | 
|  | 6851         fi | 
|  | 6852         if _is_idn "$_dvalue" && ! _exists idn; then | 
|  | 6853           _err "It seems that $_dvalue is an IDN( Internationalized Domain Names), please install 'idn' command first." | 
|  | 6854           return 1 | 
|  | 6855         fi | 
|  | 6856 | 
|  | 6857         if _startswith "$_dvalue" "*."; then | 
|  | 6858           _debug "Wildcard domain" | 
|  | 6859           export ACME_VERSION=2 | 
|  | 6860         fi | 
|  | 6861         if [ -z "$_domain" ]; then | 
|  | 6862           _domain="$_dvalue" | 
|  | 6863         else | 
|  | 6864           if [ "$_altdomains" = "$NO_VALUE" ]; then | 
|  | 6865             _altdomains="$_dvalue" | 
|  | 6866           else | 
|  | 6867             _altdomains="$_altdomains,$_dvalue" | 
|  | 6868           fi | 
|  | 6869         fi | 
|  | 6870       fi | 
|  | 6871 | 
|  | 6872       shift | 
|  | 6873       ;; | 
|  | 6874 | 
|  | 6875     -f | --force) | 
|  | 6876       FORCE="1" | 
|  | 6877       ;; | 
|  | 6878     --staging | --test) | 
|  | 6879       STAGE="1" | 
|  | 6880       ;; | 
|  | 6881     --server) | 
|  | 6882       _server="$2" | 
|  | 6883       _selectServer "$_server" | 
|  | 6884       shift | 
|  | 6885       ;; | 
|  | 6886     --debug) | 
|  | 6887       if [ -z "$2" ] || _startswith "$2" "-"; then | 
|  | 6888         DEBUG="$DEBUG_LEVEL_DEFAULT" | 
|  | 6889       else | 
|  | 6890         DEBUG="$2" | 
|  | 6891         shift | 
|  | 6892       fi | 
|  | 6893       ;; | 
|  | 6894     --output-insecure) | 
|  | 6895       export OUTPUT_INSECURE=1 | 
|  | 6896       ;; | 
|  | 6897     -w | --webroot) | 
|  | 6898       wvalue="$2" | 
|  | 6899       if [ -z "$_webroot" ]; then | 
|  | 6900         _webroot="$wvalue" | 
|  | 6901       else | 
|  | 6902         _webroot="$_webroot,$wvalue" | 
|  | 6903       fi | 
|  | 6904       shift | 
|  | 6905       ;; | 
|  | 6906     --challenge-alias) | 
|  | 6907       cvalue="$2" | 
|  | 6908       _challenge_alias="$_challenge_alias$cvalue," | 
|  | 6909       shift | 
|  | 6910       ;; | 
|  | 6911     --domain-alias) | 
|  | 6912       cvalue="$DNS_ALIAS_PREFIX$2" | 
|  | 6913       _challenge_alias="$_challenge_alias$cvalue," | 
|  | 6914       shift | 
|  | 6915       ;; | 
|  | 6916     --standalone) | 
|  | 6917       wvalue="$NO_VALUE" | 
|  | 6918       if [ -z "$_webroot" ]; then | 
|  | 6919         _webroot="$wvalue" | 
|  | 6920       else | 
|  | 6921         _webroot="$_webroot,$wvalue" | 
|  | 6922       fi | 
|  | 6923       ;; | 
|  | 6924     --alpn) | 
|  | 6925       wvalue="$W_ALPN" | 
|  | 6926       if [ -z "$_webroot" ]; then | 
|  | 6927         _webroot="$wvalue" | 
|  | 6928       else | 
|  | 6929         _webroot="$_webroot,$wvalue" | 
|  | 6930       fi | 
|  | 6931       ;; | 
|  | 6932     --stateless) | 
|  | 6933       wvalue="$MODE_STATELESS" | 
|  | 6934       if [ -z "$_webroot" ]; then | 
|  | 6935         _webroot="$wvalue" | 
|  | 6936       else | 
|  | 6937         _webroot="$_webroot,$wvalue" | 
|  | 6938       fi | 
|  | 6939       ;; | 
|  | 6940     --local-address) | 
|  | 6941       lvalue="$2" | 
|  | 6942       _local_address="$_local_address$lvalue," | 
|  | 6943       shift | 
|  | 6944       ;; | 
|  | 6945     --apache) | 
|  | 6946       wvalue="apache" | 
|  | 6947       if [ -z "$_webroot" ]; then | 
|  | 6948         _webroot="$wvalue" | 
|  | 6949       else | 
|  | 6950         _webroot="$_webroot,$wvalue" | 
|  | 6951       fi | 
|  | 6952       ;; | 
|  | 6953     --nginx) | 
|  | 6954       wvalue="$NGINX" | 
|  | 6955       if [ "$2" ] && ! _startswith "$2" "-"; then | 
|  | 6956         wvalue="$NGINX$2" | 
|  | 6957         shift | 
|  | 6958       fi | 
|  | 6959       if [ -z "$_webroot" ]; then | 
|  | 6960         _webroot="$wvalue" | 
|  | 6961       else | 
|  | 6962         _webroot="$_webroot,$wvalue" | 
|  | 6963       fi | 
|  | 6964       ;; | 
|  | 6965     --dns) | 
|  | 6966       wvalue="$W_DNS" | 
|  | 6967       if [ "$2" ] && ! _startswith "$2" "-"; then | 
|  | 6968         wvalue="$2" | 
|  | 6969         shift | 
|  | 6970       fi | 
|  | 6971       if [ -z "$_webroot" ]; then | 
|  | 6972         _webroot="$wvalue" | 
|  | 6973       else | 
|  | 6974         _webroot="$_webroot,$wvalue" | 
|  | 6975       fi | 
|  | 6976       ;; | 
|  | 6977     --dnssleep) | 
|  | 6978       _dnssleep="$2" | 
|  | 6979       Le_DNSSleep="$_dnssleep" | 
|  | 6980       shift | 
|  | 6981       ;; | 
|  | 6982 | 
|  | 6983     --keylength | -k) | 
|  | 6984       _keylength="$2" | 
|  | 6985       shift | 
|  | 6986       ;; | 
|  | 6987     -ak | --accountkeylength) | 
|  | 6988       _accountkeylength="$2" | 
|  | 6989       shift | 
|  | 6990       ;; | 
|  | 6991 | 
|  | 6992     --cert-file | --certpath) | 
|  | 6993       _cert_file="$2" | 
|  | 6994       shift | 
|  | 6995       ;; | 
|  | 6996     --key-file | --keypath) | 
|  | 6997       _key_file="$2" | 
|  | 6998       shift | 
|  | 6999       ;; | 
|  | 7000     --ca-file | --capath) | 
|  | 7001       _ca_file="$2" | 
|  | 7002       shift | 
|  | 7003       ;; | 
|  | 7004     --fullchain-file | --fullchainpath) | 
|  | 7005       _fullchain_file="$2" | 
|  | 7006       shift | 
|  | 7007       ;; | 
|  | 7008     --reloadcmd | --reloadCmd) | 
|  | 7009       _reloadcmd="$2" | 
|  | 7010       shift | 
|  | 7011       ;; | 
|  | 7012     --password) | 
|  | 7013       _password="$2" | 
|  | 7014       shift | 
|  | 7015       ;; | 
|  | 7016     --accountconf) | 
|  | 7017       _accountconf="$2" | 
|  | 7018       ACCOUNT_CONF_PATH="$_accountconf" | 
|  | 7019       shift | 
|  | 7020       ;; | 
|  | 7021     --home) | 
|  | 7022       LE_WORKING_DIR="$2" | 
|  | 7023       shift | 
|  | 7024       ;; | 
|  | 7025     --cert-home | --certhome) | 
|  | 7026       _certhome="$2" | 
|  | 7027       CERT_HOME="$_certhome" | 
|  | 7028       shift | 
|  | 7029       ;; | 
|  | 7030     --config-home) | 
|  | 7031       _confighome="$2" | 
|  | 7032       LE_CONFIG_HOME="$_confighome" | 
|  | 7033       shift | 
|  | 7034       ;; | 
|  | 7035     --useragent) | 
|  | 7036       _useragent="$2" | 
|  | 7037       USER_AGENT="$_useragent" | 
|  | 7038       shift | 
|  | 7039       ;; | 
|  | 7040     -m | --accountemail) | 
|  | 7041       _accountemail="$2" | 
|  | 7042       ACCOUNT_EMAIL="$_accountemail" | 
|  | 7043       shift | 
|  | 7044       ;; | 
|  | 7045     --accountkey) | 
|  | 7046       _accountkey="$2" | 
|  | 7047       ACCOUNT_KEY_PATH="$_accountkey" | 
|  | 7048       shift | 
|  | 7049       ;; | 
|  | 7050     --days) | 
|  | 7051       _days="$2" | 
|  | 7052       Le_RenewalDays="$_days" | 
|  | 7053       shift | 
|  | 7054       ;; | 
|  | 7055     --httpport) | 
|  | 7056       _httpport="$2" | 
|  | 7057       Le_HTTPPort="$_httpport" | 
|  | 7058       shift | 
|  | 7059       ;; | 
|  | 7060     --tlsport) | 
|  | 7061       _tlsport="$2" | 
|  | 7062       Le_TLSPort="$_tlsport" | 
|  | 7063       shift | 
|  | 7064       ;; | 
|  | 7065     --listraw) | 
|  | 7066       _listraw="raw" | 
|  | 7067       ;; | 
|  | 7068     -se | --stop-renew-on-error | --stopRenewOnError | --stoprenewonerror) | 
|  | 7069       _stopRenewOnError="1" | 
|  | 7070       ;; | 
|  | 7071     --insecure) | 
|  | 7072       #_insecure="1" | 
|  | 7073       HTTPS_INSECURE="1" | 
|  | 7074       ;; | 
|  | 7075     --ca-bundle) | 
|  | 7076       _ca_bundle="$(_readlink "$2")" | 
|  | 7077       CA_BUNDLE="$_ca_bundle" | 
|  | 7078       shift | 
|  | 7079       ;; | 
|  | 7080     --ca-path) | 
|  | 7081       _ca_path="$2" | 
|  | 7082       CA_PATH="$_ca_path" | 
|  | 7083       shift | 
|  | 7084       ;; | 
|  | 7085     --nocron) | 
|  | 7086       _nocron="1" | 
|  | 7087       ;; | 
|  | 7088     --noprofile) | 
|  | 7089       _noprofile="1" | 
|  | 7090       ;; | 
|  | 7091     --no-color) | 
|  | 7092       export ACME_NO_COLOR=1 | 
|  | 7093       ;; | 
|  | 7094     --force-color) | 
|  | 7095       export ACME_FORCE_COLOR=1 | 
|  | 7096       ;; | 
|  | 7097     --ecc) | 
|  | 7098       _ecc="isEcc" | 
|  | 7099       ;; | 
|  | 7100     --csr) | 
|  | 7101       _csr="$2" | 
|  | 7102       shift | 
|  | 7103       ;; | 
|  | 7104     --pre-hook) | 
|  | 7105       _pre_hook="$2" | 
|  | 7106       shift | 
|  | 7107       ;; | 
|  | 7108     --post-hook) | 
|  | 7109       _post_hook="$2" | 
|  | 7110       shift | 
|  | 7111       ;; | 
|  | 7112     --renew-hook) | 
|  | 7113       _renew_hook="$2" | 
|  | 7114       shift | 
|  | 7115       ;; | 
|  | 7116     --deploy-hook) | 
|  | 7117       if [ -z "$2" ] || _startswith "$2" "-"; then | 
|  | 7118         _usage "Please specify a value for '--deploy-hook'" | 
|  | 7119         return 1 | 
|  | 7120       fi | 
|  | 7121       _deploy_hook="$_deploy_hook$2," | 
|  | 7122       shift | 
|  | 7123       ;; | 
|  | 7124     --ocsp-must-staple | --ocsp) | 
|  | 7125       Le_OCSP_Staple="1" | 
|  | 7126       ;; | 
|  | 7127     --always-force-new-domain-key) | 
|  | 7128       if [ -z "$2" ] || _startswith "$2" "-"; then | 
|  | 7129         Le_ForceNewDomainKey=1 | 
|  | 7130       else | 
|  | 7131         Le_ForceNewDomainKey="$2" | 
|  | 7132         shift | 
|  | 7133       fi | 
|  | 7134       ;; | 
|  | 7135     --yes-I-know-dns-manual-mode-enough-go-ahead-please) | 
|  | 7136       export FORCE_DNS_MANUAL=1 | 
|  | 7137       ;; | 
|  | 7138     --log | --logfile) | 
|  | 7139       _log="1" | 
|  | 7140       _logfile="$2" | 
|  | 7141       if _startswith "$_logfile" '-'; then | 
|  | 7142         _logfile="" | 
|  | 7143       else | 
|  | 7144         shift | 
|  | 7145       fi | 
|  | 7146       LOG_FILE="$_logfile" | 
|  | 7147       if [ -z "$LOG_LEVEL" ]; then | 
|  | 7148         LOG_LEVEL="$DEFAULT_LOG_LEVEL" | 
|  | 7149       fi | 
|  | 7150       ;; | 
|  | 7151     --log-level) | 
|  | 7152       _log_level="$2" | 
|  | 7153       LOG_LEVEL="$_log_level" | 
|  | 7154       shift | 
|  | 7155       ;; | 
|  | 7156     --syslog) | 
|  | 7157       if ! _startswith "$2" '-'; then | 
|  | 7158         _syslog="$2" | 
|  | 7159         shift | 
|  | 7160       fi | 
|  | 7161       if [ -z "$_syslog" ]; then | 
|  | 7162         _syslog="$SYSLOG_LEVEL_DEFAULT" | 
|  | 7163       fi | 
|  | 7164       ;; | 
|  | 7165     --auto-upgrade) | 
|  | 7166       _auto_upgrade="$2" | 
|  | 7167       if [ -z "$_auto_upgrade" ] || _startswith "$_auto_upgrade" '-'; then | 
|  | 7168         _auto_upgrade="1" | 
|  | 7169       else | 
|  | 7170         shift | 
|  | 7171       fi | 
|  | 7172       AUTO_UPGRADE="$_auto_upgrade" | 
|  | 7173       ;; | 
|  | 7174     --listen-v4) | 
|  | 7175       _listen_v4="1" | 
|  | 7176       Le_Listen_V4="$_listen_v4" | 
|  | 7177       ;; | 
|  | 7178     --listen-v6) | 
|  | 7179       _listen_v6="1" | 
|  | 7180       Le_Listen_V6="$_listen_v6" | 
|  | 7181       ;; | 
|  | 7182     --openssl-bin) | 
|  | 7183       _openssl_bin="$2" | 
|  | 7184       ACME_OPENSSL_BIN="$_openssl_bin" | 
|  | 7185       shift | 
|  | 7186       ;; | 
|  | 7187     --use-wget) | 
|  | 7188       _use_wget="1" | 
|  | 7189       ACME_USE_WGET="1" | 
|  | 7190       ;; | 
|  | 7191     --branch | -b) | 
|  | 7192       export BRANCH="$2" | 
|  | 7193       shift | 
|  | 7194       ;; | 
|  | 7195     --notify-hook) | 
|  | 7196       _nhook="$2" | 
|  | 7197       if _startswith "$_nhook" "-"; then | 
|  | 7198         _err "'$_nhook' is not a hook name for '$1'" | 
|  | 7199         return 1 | 
|  | 7200       fi | 
|  | 7201       if [ "$_notify_hook" ]; then | 
|  | 7202         _notify_hook="$_notify_hook,$_nhook" | 
|  | 7203       else | 
|  | 7204         _notify_hook="$_nhook" | 
|  | 7205       fi | 
|  | 7206       shift | 
|  | 7207       ;; | 
|  | 7208     --notify-level) | 
|  | 7209       _nlevel="$2" | 
|  | 7210       if _startswith "$_nlevel" "-"; then | 
|  | 7211         _err "'$_nlevel' is not a integer for '$1'" | 
|  | 7212         return 1 | 
|  | 7213       fi | 
|  | 7214       _notify_level="$_nlevel" | 
|  | 7215       shift | 
|  | 7216       ;; | 
|  | 7217     --notify-mode) | 
|  | 7218       _nmode="$2" | 
|  | 7219       if _startswith "$_nmode" "-"; then | 
|  | 7220         _err "'$_nmode' is not a integer for '$1'" | 
|  | 7221         return 1 | 
|  | 7222       fi | 
|  | 7223       _notify_mode="$_nmode" | 
|  | 7224       shift | 
|  | 7225       ;; | 
|  | 7226     --revoke-reason) | 
|  | 7227       _revoke_reason="$2" | 
|  | 7228       if _startswith "$_revoke_reason" "-"; then | 
|  | 7229         _err "'$_revoke_reason' is not a integer for '$1'" | 
|  | 7230         return 1 | 
|  | 7231       fi | 
|  | 7232       shift | 
|  | 7233       ;; | 
|  | 7234     --eab-kid) | 
|  | 7235       _eab_kid="$2" | 
|  | 7236       shift | 
|  | 7237       ;; | 
|  | 7238     --eab-hmac-key) | 
|  | 7239       _eab_hmac_key="$2" | 
|  | 7240       shift | 
|  | 7241       ;; | 
|  | 7242     --preferred-chain) | 
|  | 7243       _preferred_chain="$2" | 
|  | 7244       shift | 
|  | 7245       ;; | 
|  | 7246     *) | 
|  | 7247       _err "Unknown parameter : $1" | 
|  | 7248       return 1 | 
|  | 7249       ;; | 
|  | 7250     esac | 
|  | 7251 | 
|  | 7252     shift 1 | 
|  | 7253   done | 
|  | 7254 | 
|  | 7255   if [ "${_CMD}" != "install" ]; then | 
|  | 7256     if [ "$__INTERACTIVE" ] && ! _checkSudo; then | 
|  | 7257       if [ -z "$FORCE" ]; then | 
|  | 7258         #Use "echo" here, instead of _info. it's too early | 
|  | 7259         echo "It seems that you are using sudo, please read this link first:" | 
|  | 7260         echo "$_SUDO_WIKI" | 
|  | 7261         return 1 | 
|  | 7262       fi | 
|  | 7263     fi | 
|  | 7264     __initHome | 
|  | 7265     if [ "$_log" ]; then | 
|  | 7266       if [ -z "$_logfile" ]; then | 
|  | 7267         _logfile="$DEFAULT_LOG_FILE" | 
|  | 7268       fi | 
|  | 7269     fi | 
|  | 7270     if [ "$_logfile" ]; then | 
|  | 7271       _saveaccountconf "LOG_FILE" "$_logfile" | 
|  | 7272       LOG_FILE="$_logfile" | 
|  | 7273     fi | 
|  | 7274 | 
|  | 7275     if [ "$_log_level" ]; then | 
|  | 7276       _saveaccountconf "LOG_LEVEL" "$_log_level" | 
|  | 7277       LOG_LEVEL="$_log_level" | 
|  | 7278     fi | 
|  | 7279 | 
|  | 7280     if [ "$_syslog" ]; then | 
|  | 7281       if _exists logger; then | 
|  | 7282         if [ "$_syslog" = "0" ]; then | 
|  | 7283           _clearaccountconf "SYS_LOG" | 
|  | 7284         else | 
|  | 7285           _saveaccountconf "SYS_LOG" "$_syslog" | 
|  | 7286         fi | 
|  | 7287         SYS_LOG="$_syslog" | 
|  | 7288       else | 
|  | 7289         _err "The 'logger' command is not found, can not enable syslog." | 
|  | 7290         _clearaccountconf "SYS_LOG" | 
|  | 7291         SYS_LOG="" | 
|  | 7292       fi | 
|  | 7293     fi | 
|  | 7294 | 
|  | 7295     _processAccountConf | 
|  | 7296   fi | 
|  | 7297 | 
|  | 7298   _debug2 LE_WORKING_DIR "$LE_WORKING_DIR" | 
|  | 7299 | 
|  | 7300   if [ "$DEBUG" ]; then | 
|  | 7301     version | 
|  | 7302     if [ "$_server" ]; then | 
|  | 7303       _debug "Using server: $_server" | 
|  | 7304     fi | 
|  | 7305   fi | 
|  | 7306   _debug "Running cmd: ${_CMD}" | 
|  | 7307   case "${_CMD}" in | 
|  | 7308   install) install "$_nocron" "$_confighome" "$_noprofile" ;; | 
|  | 7309   uninstall) uninstall "$_nocron" ;; | 
|  | 7310   upgrade) upgrade ;; | 
|  | 7311   issue) | 
|  | 7312     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" | 
|  | 7313     ;; | 
|  | 7314   deploy) | 
|  | 7315     deploy "$_domain" "$_deploy_hook" "$_ecc" | 
|  | 7316     ;; | 
|  | 7317   signcsr) | 
|  | 7318     signcsr "$_csr" "$_webroot" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" | 
|  | 7319     ;; | 
|  | 7320   showcsr) | 
|  | 7321     showcsr "$_csr" "$_domain" | 
|  | 7322     ;; | 
|  | 7323   installcert) | 
|  | 7324     installcert "$_domain" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_ecc" | 
|  | 7325     ;; | 
|  | 7326   renew) | 
|  | 7327     renew "$_domain" "$_ecc" | 
|  | 7328     ;; | 
|  | 7329   renewAll) | 
|  | 7330     renewAll "$_stopRenewOnError" | 
|  | 7331     ;; | 
|  | 7332   revoke) | 
|  | 7333     revoke "$_domain" "$_ecc" "$_revoke_reason" | 
|  | 7334     ;; | 
|  | 7335   remove) | 
|  | 7336     remove "$_domain" "$_ecc" | 
|  | 7337     ;; | 
|  | 7338   deactivate) | 
|  | 7339     deactivate "$_domain,$_altdomains" | 
|  | 7340     ;; | 
|  | 7341   registeraccount) | 
|  | 7342     registeraccount "$_accountkeylength" "$_eab_kid" "$_eab_hmac_key" | 
|  | 7343     ;; | 
|  | 7344   updateaccount) | 
|  | 7345     updateaccount | 
|  | 7346     ;; | 
|  | 7347   deactivateaccount) | 
|  | 7348     deactivateaccount | 
|  | 7349     ;; | 
|  | 7350   list) | 
|  | 7351     list "$_listraw" "$_domain" | 
|  | 7352     ;; | 
|  | 7353   installcronjob) installcronjob "$_confighome" ;; | 
|  | 7354   uninstallcronjob) uninstallcronjob ;; | 
|  | 7355   cron) cron ;; | 
|  | 7356   toPkcs) | 
|  | 7357     toPkcs "$_domain" "$_password" "$_ecc" | 
|  | 7358     ;; | 
|  | 7359   toPkcs8) | 
|  | 7360     toPkcs8 "$_domain" "$_ecc" | 
|  | 7361     ;; | 
|  | 7362   createAccountKey) | 
|  | 7363     createAccountKey "$_accountkeylength" | 
|  | 7364     ;; | 
|  | 7365   createDomainKey) | 
|  | 7366     createDomainKey "$_domain" "$_keylength" | 
|  | 7367     ;; | 
|  | 7368   createCSR) | 
|  | 7369     createCSR "$_domain" "$_altdomains" "$_ecc" | 
|  | 7370     ;; | 
|  | 7371   setnotify) | 
|  | 7372     setnotify "$_notify_hook" "$_notify_level" "$_notify_mode" | 
|  | 7373     ;; | 
|  | 7374   setdefaultca) | 
|  | 7375     setdefaultca | 
|  | 7376     ;; | 
|  | 7377   *) | 
|  | 7378     if [ "$_CMD" ]; then | 
|  | 7379       _err "Invalid command: $_CMD" | 
|  | 7380     fi | 
|  | 7381     showhelp | 
|  | 7382     return 1 | 
|  | 7383     ;; | 
|  | 7384   esac | 
|  | 7385   _ret="$?" | 
|  | 7386   if [ "$_ret" != "0" ]; then | 
|  | 7387     return $_ret | 
|  | 7388   fi | 
|  | 7389 | 
|  | 7390   if [ "${_CMD}" = "install" ]; then | 
|  | 7391     if [ "$_log" ]; then | 
|  | 7392       if [ -z "$LOG_FILE" ]; then | 
|  | 7393         LOG_FILE="$DEFAULT_LOG_FILE" | 
|  | 7394       fi | 
|  | 7395       _saveaccountconf "LOG_FILE" "$LOG_FILE" | 
|  | 7396     fi | 
|  | 7397 | 
|  | 7398     if [ "$_log_level" ]; then | 
|  | 7399       _saveaccountconf "LOG_LEVEL" "$_log_level" | 
|  | 7400     fi | 
|  | 7401 | 
|  | 7402     if [ "$_syslog" ]; then | 
|  | 7403       if _exists logger; then | 
|  | 7404         if [ "$_syslog" = "0" ]; then | 
|  | 7405           _clearaccountconf "SYS_LOG" | 
|  | 7406         else | 
|  | 7407           _saveaccountconf "SYS_LOG" "$_syslog" | 
|  | 7408         fi | 
|  | 7409       else | 
|  | 7410         _err "The 'logger' command is not found, can not enable syslog." | 
|  | 7411         _clearaccountconf "SYS_LOG" | 
|  | 7412         SYS_LOG="" | 
|  | 7413       fi | 
|  | 7414     fi | 
|  | 7415 | 
|  | 7416     _processAccountConf | 
|  | 7417   fi | 
|  | 7418 | 
|  | 7419 } | 
|  | 7420 | 
|  | 7421 if [ "$INSTALLONLINE" ]; then | 
|  | 7422   INSTALLONLINE="" | 
|  | 7423   _installOnline | 
|  | 7424   exit | 
|  | 7425 fi | 
|  | 7426 | 
|  | 7427 main() { | 
|  | 7428   [ -z "$1" ] && showhelp && return | 
|  | 7429   if _startswith "$1" '-'; then _process "$@"; else "$@"; fi | 
|  | 7430 } | 
|  | 7431 | 
|  | 7432 main "$@" |