]> git.proxmox.com Git - mirror_acme.sh.git/blame - acme.sh
fix format
[mirror_acme.sh.git] / acme.sh
CommitLineData
0a7c9364 1#!/usr/bin/env sh
bfdf1f48 2
8f9a1881 3VER=2.6.5
a7b7355d 4
6cc11ffb 5PROJECT_NAME="acme.sh"
a7b7355d 6
6cc11ffb 7PROJECT_ENTRY="acme.sh"
8
9PROJECT="https://github.com/Neilpang/$PROJECT_NAME"
4c3b3608 10
f3e4cea3 11DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME"
12_SCRIPT_="$0"
13
a61fe418 14_SUB_FOLDERS="dnsapi deploy"
f3e4cea3 15
4c3b3608 16DEFAULT_CA="https://acme-v01.api.letsencrypt.org"
c93ec933 17DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf"
4c3b3608 18
07af4247 19DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
d0871bda 20DEFAULT_ACCOUNT_EMAIL=""
bbbdcb09 21
57e58ce7 22DEFAULT_ACCOUNT_KEY_LENGTH=2048
23DEFAULT_DOMAIN_KEY_LENGTH=2048
24
4c3b3608 25STAGE_CA="https://acme-staging.api.letsencrypt.org"
26
27VTYPE_HTTP="http-01"
28VTYPE_DNS="dns-01"
e22bcf7c 29VTYPE_TLS="tls-sni-01"
e591d5cf 30#VTYPE_TLS2="tls-sni-02"
e22bcf7c 31
0463b5d6 32LOCAL_ANY_ADDRESS="0.0.0.0"
33
656bd330 34MAX_RENEW=60
523c7682 35
4a4dacb5 36DEFAULT_DNS_SLEEP=120
37
3f4513b3 38NO_VALUE="no"
39
e22bcf7c 40W_TLS="tls"
4c3b3608 41
ec603bee 42STATE_VERIFIED="verified_ok"
43
88fab7d6 44BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----"
45END_CSR="-----END CERTIFICATE REQUEST-----"
46
47BEGIN_CERT="-----BEGIN CERTIFICATE-----"
48END_CERT="-----END CERTIFICATE-----"
49
cc179731 50RENEW_SKIP=2
51
43822d37 52ECC_SEP="_"
53ECC_SUFFIX="${ECC_SEP}ecc"
54
a73c5b33 55LOG_LEVEL_1=1
56LOG_LEVEL_2=2
57LOG_LEVEL_3=3
58DEFAULT_LOG_LEVEL="$LOG_LEVEL_1"
59
60_DEBUG_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh"
4c3b3608 61
08ee072f 62__INTERACTIVE=""
4c2a3841 63if [ -t 1 ]; then
08ee072f 64 __INTERACTIVE="1"
65fi
00a50605 66
43822d37 67__green() {
4c2a3841 68 if [ "$__INTERACTIVE" ]; then
2d12b689 69 printf '\033[1;31;32m'
70 fi
43822d37 71 printf -- "$1"
4c2a3841 72 if [ "$__INTERACTIVE" ]; then
2d12b689 73 printf '\033[0m'
74 fi
43822d37 75}
76
77__red() {
4c2a3841 78 if [ "$__INTERACTIVE" ]; then
2d12b689 79 printf '\033[1;31;40m'
80 fi
43822d37 81 printf -- "$1"
4c2a3841 82 if [ "$__INTERACTIVE" ]; then
2d12b689 83 printf '\033[0m'
84 fi
43822d37 85}
00a50605 86
a73c5b33 87_printargs() {
4c2a3841 88 if [ -z "$2" ]; then
a73c5b33 89 printf -- "[$(date)] $1"
43822d37 90 else
a73c5b33 91 printf -- "[$(date)] $1='$2'"
43822d37 92 fi
a73c5b33 93 printf "\n"
43822d37 94}
95
9d548d81 96_dlg_versions() {
97 echo "Diagnosis versions: "
98 echo "openssl:"
4c2a3841 99 if _exists openssl; then
9d548d81 100 openssl version 2>&1
101 else
102 echo "openssl doesn't exists."
103 fi
4c2a3841 104
9d548d81 105 echo "apache:"
4c2a3841 106 if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then
9d548d81 107 _APACHECTL -V 2>&1
108 else
109 echo "apache doesn't exists."
110 fi
4c2a3841 111
9d548d81 112 echo "nc:"
4c2a3841 113 if _exists "nc"; then
9d548d81 114 nc -h 2>&1
115 else
116 _debug "nc doesn't exists."
117 fi
118}
43822d37 119
a73c5b33 120_log() {
121 [ -z "$LOG_FILE" ] && return
95e06de5 122 _printargs "$@" >>"$LOG_FILE"
a73c5b33 123}
124
125_info() {
126 _log "$@"
127 _printargs "$@"
4c3b3608 128}
129
130_err() {
a73c5b33 131 _log "$@"
65de3110 132 printf -- "[$(date)] " >&2
4c2a3841 133 if [ -z "$2" ]; then
65de3110 134 __red "$1" >&2
135 else
136 __red "$1='$2'" >&2
137 fi
b19ba13a 138 printf "\n" >&2
4c3b3608 139 return 1
140}
141
43822d37 142_usage() {
4c2a3841 143 __red "$@" >&2
65de3110 144 printf "\n" >&2
43822d37 145}
146
c60883ef 147_debug() {
4c2a3841 148 if [ -z "$LOG_LEVEL" ] || [ "$LOG_LEVEL" -ge "$LOG_LEVEL_1" ]; then
a73c5b33 149 _log "$@"
150 fi
4c2a3841 151 if [ -z "$DEBUG" ]; then
c60883ef 152 return
153 fi
a73c5b33 154 _printargs "$@" >&2
c60883ef 155}
156
a63b05a9 157_debug2() {
4c2a3841 158 if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_2" ]; then
a73c5b33 159 _log "$@"
160 fi
4c2a3841 161 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
a63b05a9 162 _debug "$@"
163 fi
a63b05a9 164}
165
22ea4004 166_debug3() {
4c2a3841 167 if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_3" ]; then
a73c5b33 168 _log "$@"
169 fi
4c2a3841 170 if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ]; then
22ea4004 171 _debug "$@"
172 fi
22ea4004 173}
174
4c2a3841 175_startswith() {
dceb3aca 176 _str="$1"
177 _sub="$2"
19539575 178 echo "$_str" | grep "^$_sub" >/dev/null 2>&1
dceb3aca 179}
180
4c2a3841 181_endswith() {
43822d37 182 _str="$1"
183 _sub="$2"
184 echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1
185}
186
4c2a3841 187_contains() {
dceb3aca 188 _str="$1"
189 _sub="$2"
43822d37 190 echo "$_str" | grep -- "$_sub" >/dev/null 2>&1
dceb3aca 191}
192
c53da1ef 193_hasfield() {
194 _str="$1"
195 _field="$2"
196 _sep="$3"
4c2a3841 197 if [ -z "$_field" ]; then
43822d37 198 _usage "Usage: str field [sep]"
c53da1ef 199 return 1
200 fi
4c2a3841 201
202 if [ -z "$_sep" ]; then
c53da1ef 203 _sep=","
204 fi
4c2a3841 205
206 for f in $(echo "$_str" | tr ',' ' '); do
207 if [ "$f" = "$_field" ]; then
0c9546cc 208 _debug2 "'$_str' contains '$_field'"
c53da1ef 209 return 0 #contains ok
210 fi
211 done
0c9546cc 212 _debug2 "'$_str' does not contain '$_field'"
c53da1ef 213 return 1 #not contains
214}
215
4c2a3841 216_getfield() {
0463b5d6 217 _str="$1"
218 _findex="$2"
219 _sep="$3"
4c2a3841 220
221 if [ -z "$_findex" ]; then
0463b5d6 222 _usage "Usage: str field [sep]"
223 return 1
224 fi
4c2a3841 225
226 if [ -z "$_sep" ]; then
0463b5d6 227 _sep=","
228 fi
229
201aa244 230 _ffi="$_findex"
4c2a3841 231 while [ "$_ffi" -gt "0" ]; do
201aa244 232 _fv="$(echo "$_str" | cut -d "$_sep" -f "$_ffi")"
4c2a3841 233 if [ "$_fv" ]; then
0463b5d6 234 printf -- "%s" "$_fv"
235 return 0
236 fi
95e06de5 237 _ffi="$(_math "$_ffi" - 1)"
0463b5d6 238 done
4c2a3841 239
0463b5d6 240 printf -- "%s" "$_str"
241
242}
243
4c2a3841 244_exists() {
c60883ef 245 cmd="$1"
4c2a3841 246 if [ -z "$cmd" ]; then
43822d37 247 _usage "Usage: _exists cmd"
c60883ef 248 return 1
249 fi
e591d5cf 250 if command >/dev/null 2>&1; then
19539575 251 command -v "$cmd" >/dev/null 2>&1
7575094c 252 elif which ls >/dev/null 2>&1; then
e591d5cf 253 which "$cmd" >/dev/null 2>&1
eac18b1c 254 fi
c60883ef 255 ret="$?"
690a5e20 256 _debug3 "$cmd exists=$ret"
c60883ef 257 return $ret
258}
259
00a50605 260#a + b
4c2a3841 261_math() {
be68fbd4 262 _m_opts="$@"
263 printf "%s" "$(($_m_opts))"
00a50605 264}
265
266_h_char_2_dec() {
267 _ch=$1
268 case "${_ch}" in
4c2a3841 269 a | A)
19539575 270 printf "10"
4c2a3841 271 ;;
272 b | B)
19539575 273 printf "11"
4c2a3841 274 ;;
275 c | C)
19539575 276 printf "12"
4c2a3841 277 ;;
278 d | D)
19539575 279 printf "13"
4c2a3841 280 ;;
281 e | E)
19539575 282 printf "14"
4c2a3841 283 ;;
284 f | F)
19539575 285 printf "15"
4c2a3841 286 ;;
00a50605 287 *)
19539575 288 printf "%s" "$_ch"
4c2a3841 289 ;;
19539575 290 esac
00a50605 291
292}
293
fac1e367 294_URGLY_PRINTF=""
4c2a3841 295if [ "$(printf '\x41')" != 'A' ]; then
fac1e367 296 _URGLY_PRINTF=1
297fi
298
4c3b3608 299_h2b() {
300 hex=$(cat)
301 i=1
302 j=2
e591d5cf 303
690a5e20 304 _debug3 _URGLY_PRINTF "$_URGLY_PRINTF"
4c2a3841 305 while true; do
306 if [ -z "$_URGLY_PRINTF" ]; then
f9a6988e 307 h="$(printf "%s" "$hex" | cut -c $i-$j)"
4c2a3841 308 if [ -z "$h" ]; then
309 break
00a50605 310 fi
e591d5cf 311 printf "\x$h%s"
00a50605 312 else
95e06de5 313 ic="$(printf "%s" "$hex" | cut -c $i)"
314 jc="$(printf "%s" "$hex" | cut -c $j)"
4c2a3841 315 if [ -z "$ic$jc" ]; then
316 break
00a50605 317 fi
19539575 318 ic="$(_h_char_2_dec "$ic")"
319 jc="$(_h_char_2_dec "$jc")"
e51bef6d 320 printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s"
4c3b3608 321 fi
e591d5cf 322
323 i="$(_math "$i" + 2)"
324 j="$(_math "$j" + 2)"
325
4c3b3608 326 done
327}
328
c60883ef 329#options file
330_sed_i() {
331 options="$1"
332 filename="$2"
4c2a3841 333 if [ -z "$filename" ]; then
43822d37 334 _usage "Usage:_sed_i options filename"
c60883ef 335 return 1
336 fi
14f3dbb7 337 _debug2 options "$options"
338 if sed -h 2>&1 | grep "\-i\[SUFFIX]" >/dev/null 2>&1; then
c60883ef 339 _debug "Using sed -i"
14f3dbb7 340 sed -i "$options" "$filename"
c60883ef 341 else
342 _debug "No -i support in sed"
19539575 343 text="$(cat "$filename")"
4c2a3841 344 echo "$text" | sed "$options" >"$filename"
c60883ef 345 fi
346}
347
22ea4004 348_egrep_o() {
4c2a3841 349 if _contains "$(egrep -o 2>&1)" "egrep: illegal option -- o"; then
22ea4004 350 sed -n 's/.*\('"$1"'\).*/\1/p'
351 else
352 egrep -o "$1"
353 fi
354}
355
88fab7d6 356#Usage: file startline endline
357_getfile() {
358 filename="$1"
359 startline="$2"
360 endline="$3"
4c2a3841 361 if [ -z "$endline" ]; then
43822d37 362 _usage "Usage: file startline endline"
88fab7d6 363 return 1
364 fi
4c2a3841 365
366 i="$(grep -n -- "$startline" "$filename" | cut -d : -f 1)"
367 if [ -z "$i" ]; then
88fab7d6 368 _err "Can not find start line: $startline"
369 return 1
370 fi
19539575 371 i="$(_math "$i" + 1)"
372 _debug i "$i"
4c2a3841 373
374 j="$(grep -n -- "$endline" "$filename" | cut -d : -f 1)"
375 if [ -z "$j" ]; then
88fab7d6 376 _err "Can not find end line: $endline"
377 return 1
378 fi
19539575 379 j="$(_math "$j" - 1)"
380 _debug j "$j"
4c2a3841 381
382 sed -n "$i,${j}p" "$filename"
88fab7d6 383
384}
385
386#Usage: multiline
4c3b3608 387_base64() {
4c2a3841 388 if [ "$1" ]; then
88fab7d6 389 openssl base64 -e
390 else
391 openssl base64 -e | tr -d '\r\n'
392 fi
393}
394
395#Usage: multiline
396_dbase64() {
4c2a3841 397 if [ "$1" ]; then
88fab7d6 398 openssl base64 -d -A
399 else
400 openssl base64 -d
401 fi
402}
403
e22bcf7c 404#Usage: hashalg [outputhex]
88fab7d6 405#Output Base64-encoded digest
406_digest() {
407 alg="$1"
4c2a3841 408 if [ -z "$alg" ]; then
43822d37 409 _usage "Usage: _digest hashalg"
88fab7d6 410 return 1
411 fi
4c2a3841 412
e22bcf7c 413 outputhex="$2"
4c2a3841 414
c7b16249 415 if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then
4c2a3841 416 if [ "$outputhex" ]; then
95e06de5 417 openssl dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' '
e22bcf7c 418 else
95e06de5 419 openssl dgst -"$alg" -binary | _base64
b001840d 420 fi
421 else
422 _err "$alg is not supported yet"
423 return 1
424 fi
425
426}
427
428#Usage: hashalg secret [outputhex]
429#Output Base64-encoded hmac
430_hmac() {
431 alg="$1"
432 hmac_sec="$2"
433 outputhex="$3"
4c2a3841 434
435 if [ -z "$hmac_sec" ]; then
436 _usage "Usage: _hmac hashalg secret [outputhex]"
b001840d 437 return 1
438 fi
439
a6014bf0 440 if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then
4c2a3841 441 if [ "$outputhex" ]; then
95e06de5 442 openssl dgst -"$alg" -hmac "$hmac_sec" | cut -d = -f 2 | tr -d ' '
e22bcf7c 443 else
95e06de5 444 openssl dgst -"$alg" -hmac "$hmac_sec" -binary | _base64
e22bcf7c 445 fi
88fab7d6 446 else
447 _err "$alg is not supported yet"
448 return 1
449 fi
450
451}
452
453#Usage: keyfile hashalg
454#Output: Base64-encoded signature value
455_sign() {
456 keyfile="$1"
457 alg="$2"
4c2a3841 458 if [ -z "$alg" ]; then
43822d37 459 _usage "Usage: _sign keyfile hashalg"
88fab7d6 460 return 1
461 fi
4c2a3841 462
998783eb 463 _sign_openssl="openssl dgst -sign $keyfile "
4c2a3841 464 if [ "$alg" = "sha256" ]; then
998783eb 465 _sign_openssl="$_sign_openssl -$alg"
88fab7d6 466 else
467 _err "$alg is not supported yet"
468 return 1
fac1e367 469 fi
4c2a3841 470
471 if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
998783eb 472 $_sign_openssl | _base64
4c2a3841 473 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
474 if ! _signedECText="$($_sign_openssl | openssl asn1parse -inform DER)"; then
67184d7b 475 _err "Sign failed: $_sign_openssl"
476 _err "Key file: $keyfile"
f9a6988e 477 _err "Key content:$(wc -l <"$keyfile") lises"
67184d7b 478 return 1
479 fi
998783eb 480 _debug3 "_signedECText" "$_signedECText"
481 _ec_r="$(echo "$_signedECText" | _head_n 2 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")"
482 _debug3 "_ec_r" "$_ec_r"
483 _ec_s="$(echo "$_signedECText" | _head_n 3 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")"
484 _debug3 "_ec_s" "$_ec_s"
485 printf "%s" "$_ec_r$_ec_s" | _h2b | _base64
486 else
487 _err "Unknown key file format."
488 return 1
489 fi
4c2a3841 490
4c3b3608 491}
492
43822d37 493#keylength
494_isEccKey() {
495 _length="$1"
496
4c2a3841 497 if [ -z "$_length" ]; then
43822d37 498 return 1
499 fi
500
501 [ "$_length" != "1024" ] \
4c2a3841 502 && [ "$_length" != "2048" ] \
503 && [ "$_length" != "3072" ] \
504 && [ "$_length" != "4096" ] \
505 && [ "$_length" != "8192" ]
43822d37 506}
507
e22bcf7c 508# _createkey 2048|ec-256 file
509_createkey() {
510 length="$1"
511 f="$2"
43822d37 512 eccname="$length"
4c2a3841 513 if _startswith "$length" "ec-"; then
f9a6988e 514 length=$(printf "%s" "$length" | cut -d '-' -f 2-100)
e22bcf7c 515
4c2a3841 516 if [ "$length" = "256" ]; then
e22bcf7c 517 eccname="prime256v1"
518 fi
4c2a3841 519 if [ "$length" = "384" ]; then
e22bcf7c 520 eccname="secp384r1"
521 fi
4c2a3841 522 if [ "$length" = "521" ]; then
e22bcf7c 523 eccname="secp521r1"
524 fi
43822d37 525
e22bcf7c 526 fi
527
4c2a3841 528 if [ -z "$length" ]; then
529 length=2048
43822d37 530 fi
4c2a3841 531
cbcd7e0f 532 _debug "Use length $length"
43822d37 533
4c2a3841 534 if _isEccKey "$length"; then
cbcd7e0f 535 _debug "Using ec name: $eccname"
796e2cc1 536 openssl ecparam -name "$eccname" -genkey 2>/dev/null >"$f"
e22bcf7c 537 else
cbcd7e0f 538 _debug "Using RSA: $length"
796e2cc1 539 openssl genrsa "$length" 2>/dev/null >"$f"
e22bcf7c 540 fi
43822d37 541
4c2a3841 542 if [ "$?" != "0" ]; then
43822d37 543 _err "Create key error."
544 return 1
545 fi
e22bcf7c 546}
547
9774b01b 548#domain
549_is_idn() {
550 _is_idn_d="$1"
049be104 551 _debug2 _is_idn_d "$_is_idn_d"
c7b8f223 552 _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '[0-9]' | tr -d '[a-z]' | tr -d '[A-Z]' | tr -d '.,-')
049be104 553 _debug2 _idn_temp "$_idn_temp"
554 [ "$_idn_temp" ]
9774b01b 555}
556
557#aa.com
558#aa.com,bb.com,cc.com
559_idn() {
560 __idn_d="$1"
4c2a3841 561 if ! _is_idn "$__idn_d"; then
9774b01b 562 printf "%s" "$__idn_d"
563 return 0
564 fi
4c2a3841 565
566 if _exists idn; then
567 if _contains "$__idn_d" ','; then
9774b01b 568 _i_first="1"
4c2a3841 569 for f in $(echo "$__idn_d" | tr ',' ' '); do
9774b01b 570 [ -z "$f" ] && continue
4c2a3841 571 if [ -z "$_i_first" ]; then
9774b01b 572 printf "%s" ","
573 else
574 _i_first=""
575 fi
2a1e06f8 576 idn --quiet "$f" | tr -d "\r\n"
9774b01b 577 done
578 else
579 idn "$__idn_d" | tr -d "\r\n"
580 fi
581 else
582 _err "Please install idn to process IDN names."
583 fi
584}
585
e22bcf7c 586#_createcsr cn san_list keyfile csrfile conf
587_createcsr() {
588 _debug _createcsr
589 domain="$1"
590 domainlist="$2"
0c9546cc 591 csrkey="$3"
e22bcf7c 592 csr="$4"
593 csrconf="$5"
594 _debug2 domain "$domain"
595 _debug2 domainlist "$domainlist"
0c9546cc 596 _debug2 csrkey "$csrkey"
597 _debug2 csr "$csr"
598 _debug2 csrconf "$csrconf"
4c2a3841 599
600 printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf"
601
3f4513b3 602 if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
e22bcf7c 603 #single domain
604 _info "Single domain" "$domain"
e22bcf7c 605 else
f9a6988e 606 domainlist="$(_idn "$domainlist")"
9774b01b 607 _debug2 domainlist "$domainlist"
4c2a3841 608 if _contains "$domainlist" ","; then
f9a6988e 609 alt="DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")"
e22bcf7c 610 else
611 alt="DNS:$domainlist"
612 fi
613 #multi
614 _info "Multi domain" "$alt"
4c2a3841 615 printf -- "\nsubjectAltName=$alt" >>"$csrconf"
0c9546cc 616 fi
4c2a3841 617 if [ "$Le_OCSP_Stable" ]; then
0c9546cc 618 _savedomainconf Le_OCSP_Stable "$Le_OCSP_Stable"
4c2a3841 619 printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf"
e22bcf7c 620 fi
4c2a3841 621
9774b01b 622 _csr_cn="$(_idn "$domain")"
623 _debug2 _csr_cn "$_csr_cn"
624 openssl req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr"
e22bcf7c 625}
626
627#_signcsr key csr conf cert
628_signcsr() {
629 key="$1"
630 csr="$2"
631 conf="$3"
632 cert="$4"
5aa146a5 633 _debug "_signcsr"
4c2a3841 634
635 _msg="$(openssl x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)"
5aa146a5 636 _ret="$?"
637 _debug "$_msg"
638 return $_ret
e22bcf7c 639}
640
10afcaca 641#_csrfile
642_readSubjectFromCSR() {
643 _csrfile="$1"
4c2a3841 644 if [ -z "$_csrfile" ]; then
10afcaca 645 _usage "_readSubjectFromCSR mycsr.csr"
646 return 1
647 fi
4c2a3841 648 openssl req -noout -in "$_csrfile" -subject | _egrep_o "CN=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n'
10afcaca 649}
650
651#_csrfile
652#echo comma separated domain list
653_readSubjectAltNamesFromCSR() {
654 _csrfile="$1"
4c2a3841 655 if [ -z "$_csrfile" ]; then
10afcaca 656 _usage "_readSubjectAltNamesFromCSR mycsr.csr"
657 return 1
658 fi
4c2a3841 659
10afcaca 660 _csrsubj="$(_readSubjectFromCSR "$_csrfile")"
661 _debug _csrsubj "$_csrsubj"
4c2a3841 662
663 _dnsAltnames="$(openssl req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')"
10afcaca 664 _debug _dnsAltnames "$_dnsAltnames"
4c2a3841 665
666 if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then
10afcaca 667 _debug "AltNames contains subject"
1643b476 668 _dnsAltnames="$(printf "%s" "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")"
10afcaca 669 else
670 _debug "AltNames doesn't contain subject"
671 fi
4c2a3841 672
1643b476 673 printf "%s" "$_dnsAltnames" | sed "s/DNS://g"
10afcaca 674}
675
676#_csrfile
677_readKeyLengthFromCSR() {
678 _csrfile="$1"
4c2a3841 679 if [ -z "$_csrfile" ]; then
1643b476 680 _usage "_readKeyLengthFromCSR mycsr.csr"
10afcaca 681 return 1
682 fi
4c2a3841 683
684 _outcsr="$(openssl req -noout -text -in "$_csrfile")"
685 if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then
10afcaca 686 _debug "ECC CSR"
687 echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' '
688 else
689 _debug "RSA CSR"
690 echo "$_outcsr" | _egrep_o "^ *Public-Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1
691 fi
692}
693
34c27e09 694_ss() {
695 _port="$1"
4c2a3841 696
697 if _exists "ss"; then
edf08da6 698 _debug "Using: ss"
19539575 699 ss -ntpl | grep ":$_port "
edf08da6 700 return 0
701 fi
702
4c2a3841 703 if _exists "netstat"; then
251fc37c 704 _debug "Using: netstat"
4c2a3841 705 if netstat -h 2>&1 | grep "\-p proto" >/dev/null; then
ccb96535 706 #for windows version netstat tool
0463b5d6 707 netstat -an -p tcp | grep "LISTENING" | grep ":$_port "
ccb96535 708 else
4c2a3841 709 if netstat -help 2>&1 | grep "\-p protocol" >/dev/null; then
19539575 710 netstat -an -p tcp | grep LISTEN | grep ":$_port "
4c2a3841 711 elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then
22ea4004 712 #for solaris
e3c66532 713 netstat -an -P tcp | grep "\.$_port " | grep "LISTEN"
edf08da6 714 else
19539575 715 netstat -ntpl | grep ":$_port "
edf08da6 716 fi
ccb96535 717 fi
34c27e09 718 return 0
719 fi
edf08da6 720
34c27e09 721 return 1
722}
723
43822d37 724#domain [password] [isEcc]
ac2d5123 725toPkcs() {
726 domain="$1"
727 pfxPassword="$2"
4c2a3841 728 if [ -z "$domain" ]; then
43822d37 729 _usage "Usage: $PROJECT_ENTRY --toPkcs -d domain [--password pfx-password]"
ac2d5123 730 return 1
731 fi
732
43822d37 733 _isEcc="$3"
4c2a3841 734
43822d37 735 _initpath "$domain" "$_isEcc"
736
4c2a3841 737 if [ "$pfxPassword" ]; then
ac2d5123 738 openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword"
739 else
740 openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH"
741 fi
4c2a3841 742
743 if [ "$?" = "0" ]; then
ac2d5123 744 _info "Success, Pfx is exported to: $CERT_PFX_PATH"
745 fi
746
747}
748
5fbc47eb 749#[2048]
4c3b3608 750createAccountKey() {
751 _info "Creating account key"
4c2a3841 752 if [ -z "$1" ]; then
5fbc47eb 753 _usage "Usage: $PROJECT_ENTRY --createAccountKey --accountkeylength 2048"
4c3b3608 754 return
755 fi
4c2a3841 756
5fbc47eb 757 length=$1
57e58ce7 758 _create_account_key "$length"
759
760}
761
762_create_account_key() {
763
5fbc47eb 764 length=$1
4c2a3841 765
766 if [ -z "$length" ] || [ "$length" = "$NO_VALUE" ]; then
57e58ce7 767 _debug "Use default length $DEFAULT_ACCOUNT_KEY_LENGTH"
768 length="$DEFAULT_ACCOUNT_KEY_LENGTH"
4c3b3608 769 fi
4c2a3841 770
5fbc47eb 771 _debug length "$length"
4c3b3608 772 _initpath
5fbc47eb 773
57e58ce7 774 mkdir -p "$CA_DIR"
4c2a3841 775 if [ -f "$ACCOUNT_KEY_PATH" ]; then
4c3b3608 776 _info "Account key exists, skip"
777 return
778 else
779 #generate account key
31a5487c 780 _createkey "$length" "$ACCOUNT_KEY_PATH"
4c3b3608 781 fi
782
783}
784
43822d37 785#domain [length]
4c3b3608 786createDomainKey() {
787 _info "Creating domain key"
4c2a3841 788 if [ -z "$1" ]; then
43822d37 789 _usage "Usage: $PROJECT_ENTRY --createDomainKey -d domain.com [ --keylength 2048 ]"
4c3b3608 790 return
791 fi
4c2a3841 792
4c3b3608 793 domain=$1
e22bcf7c 794 length=$2
795
4c2a3841 796 if [ -z "$length" ]; then
57e58ce7 797 _debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH"
798 length="$DEFAULT_DOMAIN_KEY_LENGTH"
799 fi
e22bcf7c 800
f9a6988e 801 _initpath "$domain" "$length"
4c2a3841 802
803 if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then
e22bcf7c 804 _createkey "$length" "$CERT_KEY_PATH"
4c3b3608 805 else
4c2a3841 806 if [ "$IS_RENEW" ]; then
4c3b3608 807 _info "Domain key exists, skip"
808 return 0
809 else
810 _err "Domain key exists, do you want to overwrite the key?"
41e3eafa 811 _err "Add '--force', and try again."
4c3b3608 812 return 1
813 fi
814 fi
815
816}
817
43822d37 818# domain domainlist isEcc
4c3b3608 819createCSR() {
820 _info "Creating csr"
4c2a3841 821 if [ -z "$1" ]; then
43822d37 822 _usage "Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ]"
4c3b3608 823 return
824 fi
4c2a3841 825
43822d37 826 domain="$1"
827 domainlist="$2"
828 _isEcc="$3"
4c2a3841 829
43822d37 830 _initpath "$domain" "$_isEcc"
4c2a3841 831
832 if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && [ -z "$FORCE" ]; then
4c3b3608 833 _info "CSR exists, skip"
834 return
835 fi
4c2a3841 836
837 if [ ! -f "$CERT_KEY_PATH" ]; then
43822d37 838 _err "The key file is not found: $CERT_KEY_PATH"
839 _err "Please create the key file first."
840 return 1
841 fi
e22bcf7c 842 _createcsr "$domain" "$domainlist" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"
4c2a3841 843
4c3b3608 844}
845
166096dc 846_urlencode() {
f9a6988e 847 tr '/+' '_-' | tr -d '= '
4c3b3608 848}
849
850_time2str() {
851 #BSD
f9a6988e 852 if date -u -d@"$1" 2>/dev/null; then
4c3b3608 853 return
854 fi
4c2a3841 855
4c3b3608 856 #Linux
f9a6988e 857 if date -u -r "$1" 2>/dev/null; then
4c3b3608 858 return
859 fi
4c2a3841 860
22ea4004 861 #Soaris
4c2a3841 862 if _exists adb; then
031e885e 863 _t_s_a=$(echo "0t${1}=Y" | adb)
864 echo "$_t_s_a"
22ea4004 865 fi
4c2a3841 866
4c3b3608 867}
868
eae29099 869_normalizeJson() {
870 sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n"
871}
872
44df2967 873_stat() {
874 #Linux
4c2a3841 875 if stat -c '%U:%G' "$1" 2>/dev/null; then
44df2967 876 return
877 fi
4c2a3841 878
44df2967 879 #BSD
4c2a3841 880 if stat -f '%Su:%Sg' "$1" 2>/dev/null; then
44df2967 881 return
882 fi
4c2a3841 883
884 return 1 #error, 'stat' not found
44df2967 885}
886
166096dc 887#keyfile
888_calcjwk() {
889 keyfile="$1"
4c2a3841 890 if [ -z "$keyfile" ]; then
43822d37 891 _usage "Usage: _calcjwk keyfile"
166096dc 892 return 1
893 fi
4c2a3841 894
895 if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ]; then
ae2db62f 896 _debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE"
897 return 0
898 fi
4c2a3841 899
4c2a3841 900 if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
166096dc 901 _debug "RSA key"
f9a6988e 902 pub_exp=$(openssl rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
4c2a3841 903 if [ "${#pub_exp}" = "5" ]; then
166096dc 904 pub_exp=0$pub_exp
905 fi
22ea4004 906 _debug3 pub_exp "$pub_exp"
4c2a3841 907
f9a6988e 908 e=$(echo "$pub_exp" | _h2b | _base64)
22ea4004 909 _debug3 e "$e"
4c2a3841 910
f9a6988e 911 modulus=$(openssl rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2)
22ea4004 912 _debug3 modulus "$modulus"
4c2a3841 913 n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)"
166096dc 914 jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}'
22ea4004 915 _debug3 jwk "$jwk"
4c2a3841 916
5982f4bc 917 JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}'
918 JWK_HEADERPLACE_PART1='{"nonce": "'
919 JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}'
4c2a3841 920 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
166096dc 921 _debug "EC key"
f9a6988e 922 crv="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")"
22ea4004 923 _debug3 crv "$crv"
4c2a3841 924
925 if [ -z "$crv" ]; then
d22b7938 926 _debug "Let's try ASN1 OID"
f9a6988e 927 crv_oid="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")"
cae9cee2 928 _debug3 crv_oid "$crv_oid"
d22b7938 929 case "${crv_oid}" in
930 "prime256v1")
4c2a3841 931 crv="P-256"
932 ;;
d22b7938 933 "secp384r1")
4c2a3841 934 crv="P-384"
935 ;;
d22b7938 936 "secp521r1")
4c2a3841 937 crv="P-521"
938 ;;
d22b7938 939 *)
4c2a3841 940 _err "ECC oid : $crv_oid"
941 return 1
942 ;;
067d586c 943 esac
d22b7938 944 _debug3 crv "$crv"
945 fi
4c2a3841 946
f9a6988e 947 pubi="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)"
79a267ab 948 pubi=$(_math "$pubi" + 1)
22ea4004 949 _debug3 pubi "$pubi"
4c2a3841 950
f9a6988e 951 pubj="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)"
79a267ab 952 pubj=$(_math "$pubj" - 1)
22ea4004 953 _debug3 pubj "$pubj"
4c2a3841 954
f9a6988e 955 pubtext="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")"
22ea4004 956 _debug3 pubtext "$pubtext"
4c2a3841 957
95e06de5 958 xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)"
79a267ab 959 xlen=$(_math "$xlen" / 4)
22ea4004 960 _debug3 xlen "$xlen"
00a50605 961
998783eb 962 xend=$(_math "$xlen" + 1)
f9a6988e 963 x="$(printf "%s" "$pubtext" | cut -d : -f 2-"$xend")"
22ea4004 964 _debug3 x "$x"
4c2a3841 965
95e06de5 966 x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _urlencode)"
22ea4004 967 _debug3 x64 "$x64"
00a50605 968
19539575 969 xend=$(_math "$xend" + 1)
f9a6988e 970 y="$(printf "%s" "$pubtext" | cut -d : -f "$xend"-10000)"
22ea4004 971 _debug3 y "$y"
4c2a3841 972
95e06de5 973 y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _urlencode)"
22ea4004 974 _debug3 y64 "$y64"
4c2a3841 975
ae2db62f 976 jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}'
22ea4004 977 _debug3 jwk "$jwk"
4c2a3841 978
5982f4bc 979 JWK_HEADER='{"alg": "ES256", "jwk": '$jwk'}'
980 JWK_HEADERPLACE_PART1='{"nonce": "'
981 JWK_HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}'
166096dc 982 else
983 _err "Only RSA or EC key is supported."
984 return 1
985 fi
986
5982f4bc 987 _debug3 JWK_HEADER "$JWK_HEADER"
ae2db62f 988 __CACHED_JWK_KEY_FILE="$keyfile"
166096dc 989}
fac1e367 990
3aae1ae3 991_time() {
992 date -u "+%s"
993}
fac1e367 994
995_mktemp() {
4c2a3841 996 if _exists mktemp; then
997 if mktemp 2>/dev/null; then
610e0f21 998 return 0
4c2a3841 999 elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null; then
5c48e139 1000 #for Mac osx
610e0f21 1001 return 0
b19ba13a 1002 fi
fac1e367 1003 fi
4c2a3841 1004 if [ -d "/tmp" ]; then
3aae1ae3 1005 echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp"
1006 return 0
4c2a3841 1007 elif [ "$LE_TEMP_DIR" ] && mkdir -p "$LE_TEMP_DIR"; then
610e0f21 1008 echo "/$LE_TEMP_DIR/wefADf24sf.$(_time).tmp"
1009 return 0
3aae1ae3 1010 fi
1011 _err "Can not create temp file."
fac1e367 1012}
1013
1014_inithttp() {
1015
4c2a3841 1016 if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER"; then
fac1e367 1017 HTTP_HEADER="$(_mktemp)"
1018 _debug2 HTTP_HEADER "$HTTP_HEADER"
1019 fi
1020
4c2a3841 1021 if [ "$__HTTP_INITIALIZED" ]; then
1022 if [ "$_ACME_CURL$_ACME_WGET" ]; then
1befee5a 1023 _debug2 "Http already initialized."
1024 return 0
1025 fi
1026 fi
4c2a3841 1027
1028 if [ -z "$_ACME_CURL" ] && _exists "curl"; then
1befee5a 1029 _ACME_CURL="curl -L --silent --dump-header $HTTP_HEADER "
4c2a3841 1030 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
fac1e367 1031 _CURL_DUMP="$(_mktemp)"
1befee5a 1032 _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP "
fac1e367 1033 fi
1034
4c2a3841 1035 if [ "$CA_BUNDLE" ]; then
1befee5a 1036 _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE "
78009539
PS
1037 fi
1038
4c2a3841 1039 if [ "$HTTPS_INSECURE" ]; then
1befee5a 1040 _ACME_CURL="$_ACME_CURL --insecure "
fac1e367 1041 fi
1042 fi
4c2a3841 1043
1befee5a 1044 if [ -z "$_ACME_WGET" ] && _exists "wget"; then
1045 _ACME_WGET="wget -q"
4c2a3841 1046 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
1befee5a 1047 _ACME_WGET="$_ACME_WGET -d "
fac1e367 1048 fi
4c2a3841 1049 if [ "$CA_BUNDLE" ]; then
1befee5a 1050 _ACME_WGET="$_ACME_WGET --ca-certificate $CA_BUNDLE "
78009539 1051 fi
4c2a3841 1052 if [ "$HTTPS_INSECURE" ]; then
1befee5a 1053 _ACME_WGET="$_ACME_WGET --no-check-certificate "
fac1e367 1054 fi
1055 fi
1056
1befee5a 1057 __HTTP_INITIALIZED=1
fac1e367 1058
fac1e367 1059}
fac1e367 1060
c839b2b0 1061# body url [needbase64] [POST|PUT]
c60883ef 1062_post() {
1063 body="$1"
1064 url="$2"
1065 needbase64="$3"
a4270efa 1066 httpmethod="$4"
c60883ef 1067
4c2a3841 1068 if [ -z "$httpmethod" ]; then
a4270efa 1069 httpmethod="POST"
1070 fi
1071 _debug $httpmethod
484d9d2a 1072 _debug "url" "$url"
30de13b4 1073 _debug2 "body" "$body"
4c2a3841 1074
fac1e367 1075 _inithttp
4c2a3841 1076
1077 if [ "$_ACME_CURL" ]; then
1befee5a 1078 _CURL="$_ACME_CURL"
ec9fc8cb 1079 _debug "_CURL" "$_CURL"
4c2a3841 1080 if [ "$needbase64" ]; then
690a5e20 1081 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)"
c60883ef 1082 else
4c2a3841 1083 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url")"
c60883ef 1084 fi
16679b57 1085 _ret="$?"
4c2a3841 1086 if [ "$_ret" != "0" ]; then
87ab2d90 1087 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
4c2a3841 1088 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
87ab2d90 1089 _err "Here is the curl dump log:"
1090 _err "$(cat "$_CURL_DUMP")"
1091 fi
687cfcc2 1092 fi
4c2a3841 1093 elif [ "$_ACME_WGET" ]; then
1befee5a 1094 _debug "_ACME_WGET" "$_ACME_WGET"
4c2a3841 1095 if [ "$needbase64" ]; then
1096 if [ "$httpmethod" = "POST" ]; then
1befee5a 1097 response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)"
8fb9a709 1098 else
1befee5a 1099 response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)"
8fb9a709 1100 fi
c60883ef 1101 else
4c2a3841 1102 if [ "$httpmethod" = "POST" ]; then
1befee5a 1103 response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")"
8fb9a709 1104 else
1befee5a 1105 response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")"
8fb9a709 1106 fi
c60883ef 1107 fi
16679b57 1108 _ret="$?"
4c2a3841 1109 if [ "$_ret" = "8" ]; then
9f43c270 1110 _ret=0
1111 _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later."
1112 fi
4c2a3841 1113 if [ "$_ret" != "0" ]; then
1114 _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
687cfcc2 1115 fi
c60883ef 1116 _sed_i "s/^ *//g" "$HTTP_HEADER"
d0b748a4 1117 else
1118 _ret="$?"
1119 _err "Neither curl nor wget is found, can not do $httpmethod."
c60883ef 1120 fi
16679b57 1121 _debug "_ret" "$_ret"
19539575 1122 printf "%s" "$response"
16679b57 1123 return $_ret
c60883ef 1124}
1125
75da0713 1126# url getheader timeout
c60883ef 1127_get() {
a4270efa 1128 _debug GET
c60883ef 1129 url="$1"
1130 onlyheader="$2"
75da0713 1131 t="$3"
79a267ab 1132 _debug url "$url"
75da0713 1133 _debug "timeout" "$t"
fac1e367 1134
1135 _inithttp
1136
4c2a3841 1137 if [ "$_ACME_CURL" ]; then
1befee5a 1138 _CURL="$_ACME_CURL"
4c2a3841 1139 if [ "$t" ]; then
75da0713 1140 _CURL="$_CURL --connect-timeout $t"
1141 fi
1142 _debug "_CURL" "$_CURL"
4c2a3841 1143 if [ "$onlyheader" ]; then
f9a6988e 1144 $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url"
c60883ef 1145 else
f9a6988e 1146 $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url"
c60883ef 1147 fi
9aaf36cd 1148 ret=$?
4c2a3841 1149 if [ "$ret" != "0" ]; then
d529eb6d 1150 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
4c2a3841 1151 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
fac1e367 1152 _err "Here is the curl dump log:"
1153 _err "$(cat "$_CURL_DUMP")"
1154 fi
1155 fi
4c2a3841 1156 elif [ "$_ACME_WGET" ]; then
1befee5a 1157 _WGET="$_ACME_WGET"
4c2a3841 1158 if [ "$t" ]; then
75da0713 1159 _WGET="$_WGET --timeout=$t"
1160 fi
1161 _debug "_WGET" "$_WGET"
4c2a3841 1162 if [ "$onlyheader" ]; then
f9a6988e 1163 $_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'
c60883ef 1164 else
f9a6988e 1165 $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - "$url"
c60883ef 1166 fi
9aaf36cd 1167 ret=$?
4c2a3841 1168 if [ "$_ret" = "8" ]; then
9f43c270 1169 _ret=0
1170 _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later."
1171 fi
4c2a3841 1172 if [ "$ret" != "0" ]; then
1173 _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
fac1e367 1174 fi
d0b748a4 1175 else
1176 ret=$?
1177 _err "Neither curl nor wget is found, can not do GET."
9aaf36cd 1178 fi
ec9fc8cb 1179 _debug "ret" "$ret"
c60883ef 1180 return $ret
1181}
166096dc 1182
c2c8f320 1183_head_n() {
79a267ab 1184 head -n "$1"
c2c8f320 1185}
1186
1187_tail_n() {
f9a6988e 1188 if ! tail -n "$1" 2>/dev/null; then
19ab2a29 1189 #fix for solaris
f9a6988e 1190 tail -"$1"
19ab2a29 1191 fi
c2c8f320 1192}
fac1e367 1193
166096dc 1194# url payload needbase64 keyfile
4c3b3608 1195_send_signed_request() {
1196 url=$1
1197 payload=$2
1198 needbase64=$3
166096dc 1199 keyfile=$4
4c2a3841 1200 if [ -z "$keyfile" ]; then
166096dc 1201 keyfile="$ACCOUNT_KEY_PATH"
1202 fi
f9a6988e 1203 _debug url "$url"
4c3b3608 1204 _debug payload "$payload"
4c2a3841 1205
1206 if ! _calcjwk "$keyfile"; then
166096dc 1207 return 1
1208 fi
c60883ef 1209
22ea4004 1210 payload64=$(printf "%s" "$payload" | _base64 | _urlencode)
f9a6988e 1211 _debug3 payload64 "$payload64"
4c2a3841 1212
1213 if [ -z "$_CACHED_NONCE" ]; then
00bcbd36 1214 _debug2 "Get nonce."
1215 nonceurl="$API/directory"
79a267ab 1216 _headers="$(_get "$nonceurl" "onlyheader")"
4c2a3841 1217
1218 if [ "$?" != "0" ]; then
00bcbd36 1219 _err "Can not connect to $nonceurl to get nonce."
1220 return 1
1221 fi
4c2a3841 1222
1cbf416b 1223 _debug2 _headers "$_headers"
4c2a3841 1224
1225 _CACHED_NONCE="$(echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
1cbf416b 1226 _debug2 _CACHED_NONCE "$_CACHED_NONCE"
00bcbd36 1227 else
1228 _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE"
7012b91f 1229 fi
00bcbd36 1230 nonce="$_CACHED_NONCE"
1cbf416b 1231 _debug2 nonce "$nonce"
a272ee4f 1232
5982f4bc 1233 protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2"
22ea4004 1234 _debug3 protected "$protected"
4c2a3841 1235
95e06de5 1236 protected64="$(printf "%s" "$protected" | _base64 | _urlencode)"
22ea4004 1237 _debug3 protected64 "$protected64"
166096dc 1238
4c2a3841 1239 if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then
29b75109 1240 _err "Sign request failed."
1241 return 1
1242 fi
1243 _debug3 _sig_t "$_sig_t"
4c2a3841 1244
29b75109 1245 sig="$(printf "%s" "$_sig_t" | _urlencode)"
22ea4004 1246 _debug3 sig "$sig"
4c2a3841 1247
5982f4bc 1248 body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
22ea4004 1249 _debug3 body "$body"
bbbdcb09 1250
f9a6988e 1251 response="$(_post "$body" "$url" "$needbase64")"
00bcbd36 1252 _CACHED_NONCE=""
4c2a3841 1253 if [ "$?" != "0" ]; then
9f43c270 1254 _err "Can not post to $url"
7012b91f 1255 return 1
1256 fi
eae29099 1257 _debug2 original "$response"
4c3b3608 1258
4c2a3841 1259 response="$(echo "$response" | _normalizeJson)"
4c3b3608 1260
00bcbd36 1261 responseHeaders="$(cat "$HTTP_HEADER")"
4c2a3841 1262
a63b05a9 1263 _debug2 responseHeaders "$responseHeaders"
4c2a3841 1264 _debug2 response "$response"
79a267ab 1265 code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")"
1266 _debug code "$code"
4c3b3608 1267
00bcbd36 1268 _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
4c3b3608 1269
4c3b3608 1270}
4c3b3608 1271
1272#setopt "file" "opt" "=" "value" [";"]
1273_setopt() {
1274 __conf="$1"
1275 __opt="$2"
1276 __sep="$3"
1277 __val="$4"
1278 __end="$5"
4c2a3841 1279 if [ -z "$__opt" ]; then
1280 _usage usage: _setopt '"file" "opt" "=" "value" [";"]'
4c3b3608 1281 return
1282 fi
4c2a3841 1283 if [ ! -f "$__conf" ]; then
4c3b3608 1284 touch "$__conf"
1285 fi
1286
4c2a3841 1287 if grep -n "^$__opt$__sep" "$__conf" >/dev/null; then
22ea4004 1288 _debug3 OK
4c2a3841 1289 if _contains "$__val" "&"; then
79a267ab 1290 __val="$(echo "$__val" | sed 's/&/\\&/g')"
4c3b3608 1291 fi
79a267ab 1292 text="$(cat "$__conf")"
4c2a3841 1293 echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf"
4c3b3608 1294
4c2a3841 1295 elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then
1296 if _contains "$__val" "&"; then
79a267ab 1297 __val="$(echo "$__val" | sed 's/&/\\&/g')"
4c3b3608 1298 fi
79a267ab 1299 text="$(cat "$__conf")"
4c2a3841 1300 echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf"
4c3b3608 1301
1302 else
22ea4004 1303 _debug3 APP
4c2a3841 1304 echo "$__opt$__sep$__val$__end" >>"$__conf"
4c3b3608 1305 fi
79a267ab 1306 _debug2 "$(grep -n "^$__opt$__sep" "$__conf")"
4c3b3608 1307}
1308
8a29fbc8 1309#_save_conf file key value
1310#save to conf
1311_save_conf() {
1312 _s_c_f="$1"
1313 _sdkey="$2"
1314 _sdvalue="$3"
4c2a3841 1315 if [ "$_s_c_f" ]; then
8a29fbc8 1316 _setopt "$_s_c_f" "$_sdkey" "=" "'$_sdvalue'"
4d2f38b0 1317 else
8a29fbc8 1318 _err "config file is empty, can not save $_sdkey=$_sdvalue"
4d2f38b0 1319 fi
1320}
1321
8a29fbc8 1322#_clear_conf file key
1323_clear_conf() {
1324 _c_c_f="$1"
1325 _sdkey="$2"
4c2a3841 1326 if [ "$_c_c_f" ]; then
20ea8591 1327 _conf_data="$(cat "$_c_c_f")"
fa574fe8 1328 echo "$_conf_data" | sed "s/^$_sdkey *=.*$//" >"$_c_c_f"
4c3b3608 1329 else
8a29fbc8 1330 _err "config file is empty, can not clear"
4c3b3608 1331 fi
1332}
1333
8a29fbc8 1334#_read_conf file key
1335_read_conf() {
1336 _r_c_f="$1"
1337 _sdkey="$2"
4c2a3841 1338 if [ -f "$_r_c_f" ]; then
1339 (
79a267ab 1340 eval "$(grep "^$_sdkey *=" "$_r_c_f")"
4c2a3841 1341 eval "printf \"%s\" \"\$$_sdkey\""
1342 )
61623d22 1343 else
57e58ce7 1344 _debug "config file is empty, can not read $_sdkey"
4c3b3608 1345 fi
4c3b3608 1346}
1347
1348#_savedomainconf key value
1349#save to domain.conf
1350_savedomainconf() {
8a29fbc8 1351 _save_conf "$DOMAIN_CONF" "$1" "$2"
4d2f38b0 1352}
1353
1354#_cleardomainconf key
1355_cleardomainconf() {
8a29fbc8 1356 _clear_conf "$DOMAIN_CONF" "$1"
4c3b3608 1357}
1358
61623d22 1359#_readdomainconf key
1360_readdomainconf() {
8a29fbc8 1361 _read_conf "$DOMAIN_CONF" "$1"
61623d22 1362}
1363
4c3b3608 1364#_saveaccountconf key value
1365_saveaccountconf() {
8a29fbc8 1366 _save_conf "$ACCOUNT_CONF_PATH" "$1" "$2"
4c3b3608 1367}
1368
fac1e367 1369#_clearaccountconf key
1370_clearaccountconf() {
8a29fbc8 1371 _clear_conf "$ACCOUNT_CONF_PATH" "$1"
1372}
1373
1374#_savecaconf key value
1375_savecaconf() {
1376 _save_conf "$CA_CONF" "$1" "$2"
1377}
1378
1379#_readcaconf key
1380_readcaconf() {
1381 _read_conf "$CA_CONF" "$1"
1382}
1383
1384#_clearaccountconf key
1385_clearcaconf() {
1386 _clear_conf "$CA_CONF" "$1"
fac1e367 1387}
1388
0463b5d6 1389# content localaddress
4c3b3608 1390_startserver() {
1391 content="$1"
0463b5d6 1392 ncaddr="$2"
1393 _debug "ncaddr" "$ncaddr"
1394
6fc1447f 1395 _debug "startserver: $$"
1b2e940d 1396 nchelp="$(nc -h 2>&1)"
4c2a3841 1397
39c8f79f 1398 _debug Le_HTTPPort "$Le_HTTPPort"
6ae0f7f5 1399 _debug Le_Listen_V4 "$Le_Listen_V4"
1400 _debug Le_Listen_V6 "$Le_Listen_V6"
f78babfa 1401 _NC="nc"
4c2a3841 1402
1403 if [ "$Le_Listen_V4" ]; then
6ae0f7f5 1404 _NC="$_NC -4"
4c2a3841 1405 elif [ "$Le_Listen_V6" ]; then
6ae0f7f5 1406 _NC="$_NC -6"
1407 fi
4c2a3841 1408
1409 if echo "$nchelp" | grep "\-q[ ,]" >/dev/null; then
f78babfa 1410 _NC="$_NC -q 1 -l $ncaddr"
1411 else
4c2a3841 1412 if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null; then
f78babfa 1413 _NC="$_NC -c -l $ncaddr"
4c2a3841 1414 elif echo "$nchelp" | grep "\-N" | grep "Shutdown the network socket after EOF on stdin" >/dev/null; then
f78babfa 1415 _NC="$_NC -N -l $ncaddr"
1416 else
1417 _NC="$_NC -l $ncaddr"
1418 fi
1419 fi
1420
6ae0f7f5 1421 _debug "_NC" "$_NC"
1422
c9febbdd 1423 #for centos ncat
4c2a3841 1424 if _contains "$nchelp" "nmap.org"; then
c9febbdd 1425 _debug "Using ncat: nmap.org"
3e5b1024 1426 if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2"; then
1427 _exec_err
1428 return 1
c9febbdd 1429 fi
fa574fe8 1430 if [ "$DEBUG" ]; then
3e5b1024 1431 _exec_err
1432 fi
1433 return
c9febbdd 1434 fi
4c2a3841 1435
1436 # while true ; do
3e5b1024 1437 if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC -p \"$Le_HTTPPort\" >&2"; then
1438 _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2"
4c2a3841 1439 fi
3e5b1024 1440
4c2a3841 1441 if [ "$?" != "0" ]; then
1442 _err "nc listen error."
3e5b1024 1443 _exec_err
4c2a3841 1444 exit 1
1445 fi
fa574fe8 1446 if [ "$DEBUG" ]; then
3e5b1024 1447 _exec_err
1448 fi
4c2a3841 1449 # done
4c3b3608 1450}
1451
4c2a3841 1452_stopserver() {
4c3b3608 1453 pid="$1"
6fc1447f 1454 _debug "pid" "$pid"
4c2a3841 1455 if [ -z "$pid" ]; then
6fc1447f 1456 return
1457 fi
e22bcf7c 1458
dcf9cb58 1459 _debug2 "Le_HTTPPort" "$Le_HTTPPort"
4c2a3841 1460 if [ "$Le_HTTPPort" ]; then
1461 if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then
22ea4004 1462 _get "http://localhost:$Le_HTTPPort" "" 1
dcf9cb58 1463 else
22ea4004 1464 _get "http://localhost:$Le_HTTPPort" "" 1 >/dev/null 2>&1
dcf9cb58 1465 fi
1466 fi
4c2a3841 1467
dcf9cb58 1468 _debug2 "Le_TLSPort" "$Le_TLSPort"
4c2a3841 1469 if [ "$Le_TLSPort" ]; then
1470 if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then
75da0713 1471 _get "https://localhost:$Le_TLSPort" "" 1
1472 _get "https://localhost:$Le_TLSPort" "" 1
dcf9cb58 1473 else
75da0713 1474 _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1
1475 _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1
dcf9cb58 1476 fi
1477 fi
4c3b3608 1478}
1479
fdcb6b72 1480# sleep sec
1481_sleep() {
1482 _sleep_sec="$1"
4c2a3841 1483 if [ "$__INTERACTIVE" ]; then
fdcb6b72 1484 _sleep_c="$_sleep_sec"
4c2a3841 1485 while [ "$_sleep_c" -ge "0" ]; do
c583d6bb 1486 printf "\r \r"
fdcb6b72 1487 __green "$_sleep_c"
79a267ab 1488 _sleep_c="$(_math "$_sleep_c" - 1)"
fdcb6b72 1489 sleep 1
1490 done
c583d6bb 1491 printf "\r"
fdcb6b72 1492 else
1493 sleep "$_sleep_sec"
1494 fi
1495}
e22bcf7c 1496
6ae0f7f5 1497# _starttlsserver san_a san_b port content _ncaddr
e22bcf7c 1498_starttlsserver() {
1499 _info "Starting tls server."
1500 san_a="$1"
1501 san_b="$2"
1502 port="$3"
1503 content="$4"
6ae0f7f5 1504 opaddr="$5"
4c2a3841 1505
e22bcf7c 1506 _debug san_a "$san_a"
1507 _debug san_b "$san_b"
1508 _debug port "$port"
4c2a3841 1509
e22bcf7c 1510 #create key TLS_KEY
4c2a3841 1511 if ! _createkey "2048" "$TLS_KEY"; then
e22bcf7c 1512 _err "Create tls validation key error."
1513 return 1
1514 fi
4c2a3841 1515
e22bcf7c 1516 #create csr
1517 alt="$san_a"
4c2a3841 1518 if [ "$san_b" ]; then
e22bcf7c 1519 alt="$alt,$san_b"
1520 fi
4c2a3841 1521 if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF"; then
e22bcf7c 1522 _err "Create tls validation csr error."
1523 return 1
1524 fi
4c2a3841 1525
e22bcf7c 1526 #self signed
4c2a3841 1527 if ! _signcsr "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$TLS_CERT"; then
e22bcf7c 1528 _err "Create tls validation cert error."
1529 return 1
1530 fi
4c2a3841 1531
6ae0f7f5 1532 __S_OPENSSL="openssl s_server -cert $TLS_CERT -key $TLS_KEY "
4c2a3841 1533 if [ "$opaddr" ]; then
6ae0f7f5 1534 __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port"
1535 else
1536 __S_OPENSSL="$__S_OPENSSL -accept $port"
1537 fi
1538
1539 _debug Le_Listen_V4 "$Le_Listen_V4"
1540 _debug Le_Listen_V6 "$Le_Listen_V6"
4c2a3841 1541 if [ "$Le_Listen_V4" ]; then
6ae0f7f5 1542 __S_OPENSSL="$__S_OPENSSL -4"
4c2a3841 1543 elif [ "$Le_Listen_V6" ]; then
6ae0f7f5 1544 __S_OPENSSL="$__S_OPENSSL -6"
1545 fi
4c2a3841 1546
e22bcf7c 1547 #start openssl
6ae0f7f5 1548 _debug "$__S_OPENSSL"
4c2a3841 1549 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
d5ec5f80 1550 (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL -tlsextdebug) &
331c4bb6 1551 else
d5ec5f80 1552 (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL >/dev/null 2>&1) &
331c4bb6 1553 fi
1554
e22bcf7c 1555 serverproc="$!"
5dbf664a 1556 sleep 1
d5ec5f80 1557 _debug serverproc "$serverproc"
e22bcf7c 1558}
1559
18e46962 1560#file
1561_readlink() {
1562 _rf="$1"
1563 if ! readlink -f "$_rf" 2>/dev/null; then
4c2a3841 1564 if _startswith "$_rf" "\./$PROJECT_ENTRY"; then
7da50703 1565 printf -- "%s" "$(pwd)/$PROJECT_ENTRY"
1566 return 0
1567 fi
4c2a3841 1568 readlink "$_rf"
18e46962 1569 fi
1570}
1571
5ea6e9c9 1572__initHome() {
4c2a3841 1573 if [ -z "$_SCRIPT_HOME" ]; then
1574 if _exists readlink && _exists dirname; then
66990cf8 1575 _debug "Lets find script dir."
f3e4cea3 1576 _debug "_SCRIPT_" "$_SCRIPT_"
18e46962 1577 _script="$(_readlink "$_SCRIPT_")"
f3e4cea3 1578 _debug "_script" "$_script"
1579 _script_home="$(dirname "$_script")"
1580 _debug "_script_home" "$_script_home"
4c2a3841 1581 if [ -d "$_script_home" ]; then
f3e4cea3 1582 _SCRIPT_HOME="$_script_home"
1583 else
1584 _err "It seems the script home is not correct:$_script_home"
1585 fi
1586 fi
1587 fi
1588
4c2a3841 1589 if [ -z "$LE_WORKING_DIR" ]; then
1590 if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then
7da50703 1591 _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME"
f3e4cea3 1592 LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
1593 else
1594 LE_WORKING_DIR="$_SCRIPT_HOME"
1595 fi
4c3b3608 1596 fi
4c2a3841 1597
1598 if [ -z "$LE_WORKING_DIR" ]; then
f3e4cea3 1599 _debug "Using default home:$DEFAULT_INSTALL_HOME"
1600 LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
1601 fi
7da50703 1602 export LE_WORKING_DIR
f3e4cea3 1603
d53289d7 1604 _DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf"
1605
4c2a3841 1606 if [ -z "$ACCOUNT_CONF_PATH" ]; then
1607 if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]; then
8663fb7e 1608 . "$_DEFAULT_ACCOUNT_CONF_PATH"
635695ec 1609 fi
d53289d7 1610 fi
4c2a3841 1611
1612 if [ -z "$ACCOUNT_CONF_PATH" ]; then
d53289d7 1613 ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH"
4c3b3608 1614 fi
4c2a3841 1615
d0871bda 1616 DEFAULT_LOG_FILE="$LE_WORKING_DIR/$PROJECT_NAME.log"
4c2a3841 1617
5c48e139 1618 DEFAULT_CA_HOME="$LE_WORKING_DIR/ca"
4c2a3841 1619
1620 if [ -z "$LE_TEMP_DIR" ]; then
610e0f21 1621 LE_TEMP_DIR="$LE_WORKING_DIR/tmp"
1622 fi
5ea6e9c9 1623}
1624
1625#[domain] [keylength]
1626_initpath() {
1627
1628 __initHome
1629
4c2a3841 1630 if [ -f "$ACCOUNT_CONF_PATH" ]; then
8663fb7e 1631 . "$ACCOUNT_CONF_PATH"
4c3b3608 1632 fi
1633
4c2a3841 1634 if [ "$IN_CRON" ]; then
1635 if [ ! "$_USER_PATH_EXPORTED" ]; then
281aa349 1636 _USER_PATH_EXPORTED=1
1637 export PATH="$USER_PATH:$PATH"
1638 fi
1639 fi
4c2a3841 1640
1641 if [ -z "$CA_HOME" ]; then
5c48e139 1642 CA_HOME="$DEFAULT_CA_HOME"
1643 fi
281aa349 1644
4c2a3841 1645 if [ -z "$API" ]; then
1646 if [ -z "$STAGE" ]; then
4c3b3608 1647 API="$DEFAULT_CA"
1648 else
1649 API="$STAGE_CA"
1650 _info "Using stage api:$API"
4c2a3841 1651 fi
4c3b3608 1652 fi
4c2a3841 1653
5c48e139 1654 _API_HOST="$(echo "$API" | cut -d : -f 2 | tr -d '/')"
1655 CA_DIR="$CA_HOME/$_API_HOST"
4c2a3841 1656
5c48e139 1657 _DEFAULT_CA_CONF="$CA_DIR/ca.conf"
4c2a3841 1658
1659 if [ -z "$CA_CONF" ]; then
5c48e139 1660 CA_CONF="$_DEFAULT_CA_CONF"
1661 fi
4c2a3841 1662
1663 if [ -f "$CA_CONF" ]; then
5c48e139 1664 . "$CA_CONF"
1665 fi
1666
4c2a3841 1667 if [ -z "$ACME_DIR" ]; then
4c3b3608 1668 ACME_DIR="/home/.acme"
1669 fi
4c2a3841 1670
1671 if [ -z "$APACHE_CONF_BACKUP_DIR" ]; then
8a144f4d 1672 APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR"
4c3b3608 1673 fi
4c2a3841 1674
1675 if [ -z "$USER_AGENT" ]; then
bbbdcb09 1676 USER_AGENT="$DEFAULT_USER_AGENT"
1677 fi
4c2a3841 1678
1679 if [ -z "$HTTP_HEADER" ]; then
933c169d 1680 HTTP_HEADER="$LE_WORKING_DIR/http.header"
1681 fi
b2817897 1682
5c48e139 1683 _OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key"
1684 _OLD_ACCOUNT_JSON="$LE_WORKING_DIR/account.json"
4c2a3841 1685
5c48e139 1686 _DEFAULT_ACCOUNT_KEY_PATH="$CA_DIR/account.key"
1687 _DEFAULT_ACCOUNT_JSON_PATH="$CA_DIR/account.json"
4c2a3841 1688 if [ -z "$ACCOUNT_KEY_PATH" ]; then
b2817897 1689 ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH"
4c3b3608 1690 fi
4c2a3841 1691
1692 if [ -z "$ACCOUNT_JSON_PATH" ]; then
5c48e139 1693 ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH"
1694 fi
4c2a3841 1695
a79b26af 1696 _DEFAULT_CERT_HOME="$LE_WORKING_DIR"
4c2a3841 1697 if [ -z "$CERT_HOME" ]; then
a79b26af
RD
1698 CERT_HOME="$_DEFAULT_CERT_HOME"
1699 fi
1700
4c2a3841 1701 if [ -z "$1" ]; then
4c3b3608 1702 return 0
1703 fi
4c2a3841 1704
5c48e139 1705 mkdir -p "$CA_DIR"
4c2a3841 1706
5fbc47eb 1707 domain="$1"
1708 _ilength="$2"
4c3b3608 1709
4c2a3841 1710 if [ -z "$DOMAIN_PATH" ]; then
43822d37 1711 domainhome="$CERT_HOME/$domain"
1712 domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX"
4c2a3841 1713
4c3b3608 1714 DOMAIN_PATH="$domainhome"
4c2a3841 1715
1716 if _isEccKey "$_ilength"; then
43822d37 1717 DOMAIN_PATH="$domainhomeecc"
1718 else
4c2a3841 1719 if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ]; then
6d4e903b 1720 _info "The domain '$domain' seems to have a ECC cert already, please add '$(__red "--ecc")' parameter if you want to use that cert."
43822d37 1721 fi
1722 fi
1723 _debug DOMAIN_PATH "$DOMAIN_PATH"
4c3b3608 1724 fi
4c2a3841 1725
1726 if [ ! -d "$DOMAIN_PATH" ]; then
1727 if ! mkdir -p "$DOMAIN_PATH"; then
933c169d 1728 _err "Can not create domain path: $DOMAIN_PATH"
1729 return 1
1730 fi
1731 fi
4c2a3841 1732
1733 if [ -z "$DOMAIN_CONF" ]; then
43822d37 1734 DOMAIN_CONF="$DOMAIN_PATH/$domain.conf"
4c3b3608 1735 fi
4c2a3841 1736
1737 if [ -z "$DOMAIN_SSL_CONF" ]; then
0c9546cc 1738 DOMAIN_SSL_CONF="$DOMAIN_PATH/$domain.csr.conf"
4c3b3608 1739 fi
4c2a3841 1740
1741 if [ -z "$CSR_PATH" ]; then
43822d37 1742 CSR_PATH="$DOMAIN_PATH/$domain.csr"
4c3b3608 1743 fi
4c2a3841 1744 if [ -z "$CERT_KEY_PATH" ]; then
43822d37 1745 CERT_KEY_PATH="$DOMAIN_PATH/$domain.key"
4c3b3608 1746 fi
4c2a3841 1747 if [ -z "$CERT_PATH" ]; then
43822d37 1748 CERT_PATH="$DOMAIN_PATH/$domain.cer"
4c3b3608 1749 fi
4c2a3841 1750 if [ -z "$CA_CERT_PATH" ]; then
43822d37 1751 CA_CERT_PATH="$DOMAIN_PATH/ca.cer"
4c3b3608 1752 fi
4c2a3841 1753 if [ -z "$CERT_FULLCHAIN_PATH" ]; then
43822d37 1754 CERT_FULLCHAIN_PATH="$DOMAIN_PATH/fullchain.cer"
caf1fc10 1755 fi
4c2a3841 1756 if [ -z "$CERT_PFX_PATH" ]; then
43822d37 1757 CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx"
ac2d5123 1758 fi
4c2a3841 1759
1760 if [ -z "$TLS_CONF" ]; then
43822d37 1761 TLS_CONF="$DOMAIN_PATH/tls.valdation.conf"
e22bcf7c 1762 fi
4c2a3841 1763 if [ -z "$TLS_CERT" ]; then
43822d37 1764 TLS_CERT="$DOMAIN_PATH/tls.valdation.cert"
e22bcf7c 1765 fi
4c2a3841 1766 if [ -z "$TLS_KEY" ]; then
43822d37 1767 TLS_KEY="$DOMAIN_PATH/tls.valdation.key"
e22bcf7c 1768 fi
4c2a3841 1769 if [ -z "$TLS_CSR" ]; then
43822d37 1770 TLS_CSR="$DOMAIN_PATH/tls.valdation.csr"
e22bcf7c 1771 fi
4c2a3841 1772
4c3b3608 1773}
1774
610e0f21 1775_exec() {
4c2a3841 1776 if [ -z "$_EXEC_TEMP_ERR" ]; then
610e0f21 1777 _EXEC_TEMP_ERR="$(_mktemp)"
1778 fi
1779
4c2a3841 1780 if [ "$_EXEC_TEMP_ERR" ]; then
3e5b1024 1781 eval "$@ 2>>$_EXEC_TEMP_ERR"
610e0f21 1782 else
3e5b1024 1783 eval "$@"
610e0f21 1784 fi
1785}
1786
1787_exec_err() {
3e5b1024 1788 [ "$_EXEC_TEMP_ERR" ] && _err "$(cat "$_EXEC_TEMP_ERR")" && echo "" >"$_EXEC_TEMP_ERR"
610e0f21 1789}
4c3b3608 1790
1791_apachePath() {
c3dd3ef0 1792 _APACHECTL="apachectl"
4c2a3841 1793 if ! _exists apachectl; then
1794 if _exists apache2ctl; then
1795 _APACHECTL="apache2ctl"
e4a19585 1796 else
bc96082f 1797 _err "'apachectl not found. It seems that apache is not installed, or you are not root user.'"
e4a19585 1798 _err "Please use webroot mode to try again."
1799 return 1
1800 fi
80a0a7b5 1801 fi
4c2a3841 1802
1803 if ! _exec $_APACHECTL -V >/dev/null; then
610e0f21 1804 _exec_err
1805 return 1
1806 fi
4c2a3841 1807
1808 if [ "$APACHE_HTTPD_CONF" ]; then
5be1449d 1809 _saveaccountconf APACHE_HTTPD_CONF "$APACHE_HTTPD_CONF"
1810 httpdconf="$APACHE_HTTPD_CONF"
79a267ab 1811 httpdconfname="$(basename "$httpdconfname")"
d62ee940 1812 else
4c2a3841 1813 httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"')"
5be1449d 1814 _debug httpdconfname "$httpdconfname"
4c2a3841 1815
1816 if [ -z "$httpdconfname" ]; then
5be1449d 1817 _err "Can not read apache config file."
1818 return 1
1819 fi
4c2a3841 1820
1821 if _startswith "$httpdconfname" '/'; then
5be1449d 1822 httpdconf="$httpdconfname"
79a267ab 1823 httpdconfname="$(basename "$httpdconfname")"
5be1449d 1824 else
4c2a3841 1825 httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"')"
5be1449d 1826 _debug httpdroot "$httpdroot"
1827 httpdconf="$httpdroot/$httpdconfname"
79a267ab 1828 httpdconfname="$(basename "$httpdconfname")"
5be1449d 1829 fi
d62ee940 1830 fi
78768e98 1831 _debug httpdconf "$httpdconf"
8f63baf7 1832 _debug httpdconfname "$httpdconfname"
4c2a3841 1833 if [ ! -f "$httpdconf" ]; then
78768e98 1834 _err "Apache Config file not found" "$httpdconf"
4c3b3608 1835 return 1
1836 fi
1837 return 0
1838}
1839
1840_restoreApache() {
4c2a3841 1841 if [ -z "$usingApache" ]; then
4c3b3608 1842 return 0
1843 fi
1844 _initpath
4c2a3841 1845 if ! _apachePath; then
4c3b3608 1846 return 1
1847 fi
4c2a3841 1848
1849 if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ]; then
4c3b3608 1850 _debug "No config file to restore."
1851 return 0
1852 fi
4c2a3841 1853
1854 cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" >"$httpdconf"
5ef501c5 1855 _debug "Restored: $httpdconf."
4c2a3841 1856 if ! _exec $_APACHECTL -t; then
610e0f21 1857 _exec_err
4c3b3608 1858 _err "Sorry, restore apache config error, please contact me."
4c2a3841 1859 return 1
4c3b3608 1860 fi
5ef501c5 1861 _debug "Restored successfully."
4c3b3608 1862 rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname"
4c2a3841 1863 return 0
4c3b3608 1864}
1865
1866_setApache() {
1867 _initpath
4c2a3841 1868 if ! _apachePath; then
4c3b3608 1869 return 1
1870 fi
1871
5fc5016d 1872 #test the conf first
869578ce 1873 _info "Checking if there is an error in the apache config file before starting."
4c2a3841 1874
44edb2bd 1875 if ! _exec "$_APACHECTL" -t >/dev/null; then
610e0f21 1876 _exec_err
1877 _err "The apache config file has error, please fix it first, then try again."
869578ce 1878 _err "Don't worry, there is nothing changed to your system."
4c2a3841 1879 return 1
5fc5016d 1880 else
1881 _info "OK"
1882 fi
4c2a3841 1883
4c3b3608 1884 #backup the conf
5778811a 1885 _debug "Backup apache config file" "$httpdconf"
4c2a3841 1886 if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/"; then
869578ce 1887 _err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed."
8f63baf7 1888 _err "This might be a bug of $PROJECT_NAME , pleae report issue: $PROJECT"
1889 return 1
1890 fi
4c3b3608 1891 _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname"
1892 _info "In case there is an error that can not be restored automatically, you may try restore it yourself."
1893 _info "The backup file will be deleted on sucess, just forget it."
4c2a3841 1894
4c3b3608 1895 #add alias
4c2a3841 1896
1897 apacheVer="$($_APACHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2)"
b09d597c 1898 _debug "apacheVer" "$apacheVer"
1899 apacheMajer="$(echo "$apacheVer" | cut -d . -f 1)"
1900 apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)"
1901
4c2a3841 1902 if [ "$apacheVer" ] && [ "$apacheMajer$apacheMinor" -ge "24" ]; then
b09d597c 1903 echo "
4c3b3608 1904Alias /.well-known/acme-challenge $ACME_DIR
1905
1906<Directory $ACME_DIR >
1907Require all granted
b09d597c 1908</Directory>
4c2a3841 1909 " >>"$httpdconf"
b09d597c 1910 else
1911 echo "
1912Alias /.well-known/acme-challenge $ACME_DIR
1913
1914<Directory $ACME_DIR >
1915Order allow,deny
1916Allow from all
4c3b3608 1917</Directory>
4c2a3841 1918 " >>"$httpdconf"
b09d597c 1919 fi
1920
4c2a3841 1921 _msg="$($_APACHECTL -t 2>&1)"
1922 if [ "$?" != "0" ]; then
5fc5016d 1923 _err "Sorry, apache config error"
4c2a3841 1924 if _restoreApache; then
869578ce 1925 _err "The apache config file is restored."
5fc5016d 1926 else
869578ce 1927 _err "Sorry, The apache config file can not be restored, please report bug."
5fc5016d 1928 fi
4c2a3841 1929 return 1
4c3b3608 1930 fi
4c2a3841 1931
1932 if [ ! -d "$ACME_DIR" ]; then
4c3b3608 1933 mkdir -p "$ACME_DIR"
1934 chmod 755 "$ACME_DIR"
1935 fi
4c2a3841 1936
44edb2bd 1937 if ! _exec "$_APACHECTL" graceful; then
4c2a3841 1938 _exec_err
610e0f21 1939 _err "$_APACHECTL graceful error, please contact me."
4c3b3608 1940 _restoreApache
4c2a3841 1941 return 1
4c3b3608 1942 fi
1943 usingApache="1"
1944 return 0
1945}
1946
5ef501c5 1947_clearup() {
44edb2bd 1948 _stopserver "$serverproc"
4c3b3608 1949 serverproc=""
1950 _restoreApache
800e3f45 1951 _clearupdns
4c2a3841 1952 if [ -z "$DEBUG" ]; then
e22bcf7c 1953 rm -f "$TLS_CONF"
1954 rm -f "$TLS_CERT"
1955 rm -f "$TLS_KEY"
1956 rm -f "$TLS_CSR"
1957 fi
4c3b3608 1958}
1959
800e3f45 1960_clearupdns() {
1961 _debug "_clearupdns"
4c2a3841 1962 if [ "$dnsadded" != 1 ] || [ -z "$vlist" ]; then
93fc48a2 1963 _debug "Dns not added, skip."
800e3f45 1964 return
1965 fi
1966
4c2a3841 1967 ventries=$(echo "$vlist" | tr ',' ' ')
1968 for ventry in $ventries; do
0c538f75 1969 d=$(echo "$ventry" | cut -d "$sep" -f 1)
1970 keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
1971 vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
1972 _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
800e3f45 1973
4c2a3841 1974 if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
800e3f45 1975 _info "$d is already verified, skip $vtype."
1976 continue
1977 fi
1978
4c2a3841 1979 if [ "$vtype" != "$VTYPE_DNS" ]; then
800e3f45 1980 _info "Skip $d for $vtype"
1981 continue
1982 fi
4c2a3841 1983
0c538f75 1984 d_api="$(_findHook "$d" dnsapi "$_currentRoot")"
800e3f45 1985 _debug d_api "$d_api"
4c2a3841 1986
1987 if [ -z "$d_api" ]; then
800e3f45 1988 _info "Not Found domain api file: $d_api"
1989 continue
1990 fi
4c2a3841 1991
800e3f45 1992 (
d5ec5f80 1993 if ! . "$d_api"; then
800e3f45 1994 _err "Load file $d_api error. Please check your api file and try again."
1995 return 1
1996 fi
4c2a3841 1997
800e3f45 1998 rmcommand="${_currentRoot}_rm"
d5ec5f80 1999 if ! _exists "$rmcommand"; then
800e3f45 2000 _err "It seems that your api file doesn't define $rmcommand"
2001 return 1
2002 fi
4c2a3841 2003
800e3f45 2004 txtdomain="_acme-challenge.$d"
4c2a3841 2005
d5ec5f80 2006 if ! $rmcommand "$txtdomain"; then
800e3f45 2007 _err "Error removing txt for domain:$txtdomain"
2008 return 1
2009 fi
2010 )
4c2a3841 2011
800e3f45 2012 done
2013}
2014
4c3b3608 2015# webroot removelevel tokenfile
2016_clearupwebbroot() {
2017 __webroot="$1"
4c2a3841 2018 if [ -z "$__webroot" ]; then
4c3b3608 2019 _debug "no webroot specified, skip"
2020 return 0
2021 fi
4c2a3841 2022
dcf9cb58 2023 _rmpath=""
4c2a3841 2024 if [ "$2" = '1' ]; then
dcf9cb58 2025 _rmpath="$__webroot/.well-known"
4c2a3841 2026 elif [ "$2" = '2' ]; then
dcf9cb58 2027 _rmpath="$__webroot/.well-known/acme-challenge"
4c2a3841 2028 elif [ "$2" = '3' ]; then
dcf9cb58 2029 _rmpath="$__webroot/.well-known/acme-challenge/$3"
4c3b3608 2030 else
cc179731 2031 _debug "Skip for removelevel:$2"
4c3b3608 2032 fi
4c2a3841 2033
2034 if [ "$_rmpath" ]; then
2035 if [ "$DEBUG" ]; then
dcf9cb58 2036 _debug "Debugging, skip removing: $_rmpath"
2037 else
2038 rm -rf "$_rmpath"
2039 fi
2040 fi
4c2a3841 2041
4c3b3608 2042 return 0
2043
2044}
2045
b0070f03 2046_on_before_issue() {
30c2d84c 2047 _debug _on_before_issue
4c2a3841 2048 if _hasfield "$Le_Webroot" "$NO_VALUE"; then
2049 if ! _exists "nc"; then
0463b5d6 2050 _err "Please install netcat(nc) tools first."
2051 return 1
2052 fi
0463b5d6 2053 fi
2054
2055 _debug Le_LocalAddress "$Le_LocalAddress"
4c2a3841 2056
2057 alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ')
0463b5d6 2058 _index=1
2059 _currentRoot=""
2060 _addrIndex=1
4c2a3841 2061 for d in $alldomains; do
d5ec5f80 2062 _debug "Check for domain" "$d"
0463b5d6 2063 _currentRoot="$(_getfield "$Le_Webroot" $_index)"
2064 _debug "_currentRoot" "$_currentRoot"
2065 _index=$(_math $_index + 1)
2066 _checkport=""
4c2a3841 2067 if [ "$_currentRoot" = "$NO_VALUE" ]; then
0463b5d6 2068 _info "Standalone mode."
4c2a3841 2069 if [ -z "$Le_HTTPPort" ]; then
0463b5d6 2070 Le_HTTPPort=80
2071 else
4c2a3841 2072 _savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
0463b5d6 2073 fi
2074 _checkport="$Le_HTTPPort"
4c2a3841 2075 elif [ "$_currentRoot" = "$W_TLS" ]; then
0463b5d6 2076 _info "Standalone tls mode."
4c2a3841 2077 if [ -z "$Le_TLSPort" ]; then
0463b5d6 2078 Le_TLSPort=443
2079 else
4c2a3841 2080 _savedomainconf "Le_TLSPort" "$Le_TLSPort"
0463b5d6 2081 fi
2082 _checkport="$Le_TLSPort"
2083 fi
4c2a3841 2084
2085 if [ "$_checkport" ]; then
0463b5d6 2086 _debug _checkport "$_checkport"
2087 _checkaddr="$(_getfield "$Le_LocalAddress" $_addrIndex)"
2088 _debug _checkaddr "$_checkaddr"
4c2a3841 2089
0463b5d6 2090 _addrIndex="$(_math $_addrIndex + 1)"
4c2a3841 2091
0463b5d6 2092 _netprc="$(_ss "$_checkport" | grep "$_checkport")"
2093 netprc="$(echo "$_netprc" | grep "$_checkaddr")"
4c2a3841 2094 if [ -z "$netprc" ]; then
0463b5d6 2095 netprc="$(echo "$_netprc" | grep "$LOCAL_ANY_ADDRESS")"
2096 fi
4c2a3841 2097 if [ "$netprc" ]; then
0463b5d6 2098 _err "$netprc"
4c2a3841 2099 _err "tcp port $_checkport is already used by $(echo "$netprc" | cut -d : -f 4)"
0463b5d6 2100 _err "Please stop it first"
2101 return 1
2102 fi
2103 fi
2104 done
2105
4c2a3841 2106 if _hasfield "$Le_Webroot" "apache"; then
2107 if ! _setApache; then
0463b5d6 2108 _err "set up apache error. Report error to me."
2109 return 1
2110 fi
2111 else
2112 usingApache=""
2113 fi
2114
b0070f03 2115 #run pre hook
4c2a3841 2116 if [ "$Le_PreHook" ]; then
b0070f03 2117 _info "Run pre hook:'$Le_PreHook'"
2118 if ! (
2119 cd "$DOMAIN_PATH" && eval "$Le_PreHook"
4c2a3841 2120 ); then
b0070f03 2121 _err "Error when run pre hook."
2122 return 1
2123 fi
2124 fi
2125}
2126
2127_on_issue_err() {
30c2d84c 2128 _debug _on_issue_err
4c2a3841 2129 if [ "$LOG_FILE" ]; then
a73c5b33 2130 _err "Please check log file for more details: $LOG_FILE"
2131 else
54ae008d 2132 _err "Please add '--debug' or '--log' to check more details."
a73c5b33 2133 _err "See: $_DEBUG_WIKI"
2134 fi
4c2a3841 2135
2136 if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then
9d548d81 2137 _debug "$(_dlg_versions)"
2138 fi
4c2a3841 2139
b0070f03 2140 #run the post hook
4c2a3841 2141 if [ "$Le_PostHook" ]; then
b0070f03 2142 _info "Run post hook:'$Le_PostHook'"
2143 if ! (
2144 cd "$DOMAIN_PATH" && eval "$Le_PostHook"
4c2a3841 2145 ); then
b0070f03 2146 _err "Error when run post hook."
2147 return 1
2148 fi
2149 fi
2150}
2151
2152_on_issue_success() {
30c2d84c 2153 _debug _on_issue_success
b0070f03 2154 #run the post hook
4c2a3841 2155 if [ "$Le_PostHook" ]; then
b0070f03 2156 _info "Run post hook:'$Le_PostHook'"
2157 if ! (
2158 cd "$DOMAIN_PATH" && eval "$Le_PostHook"
4c2a3841 2159 ); then
b0070f03 2160 _err "Error when run post hook."
2161 return 1
2162 fi
2163 fi
4c2a3841 2164
b0070f03 2165 #run renew hook
4c2a3841 2166 if [ "$IS_RENEW" ] && [ "$Le_RenewHook" ]; then
b0070f03 2167 _info "Run renew hook:'$Le_RenewHook'"
2168 if ! (
2169 cd "$DOMAIN_PATH" && eval "$Le_RenewHook"
4c2a3841 2170 ); then
b0070f03 2171 _err "Error when run renew hook."
2172 return 1
2173 fi
4c2a3841 2174 fi
2175
b0070f03 2176}
2177
eb59817e 2178updateaccount() {
2179 _initpath
2180 _regAccount
2181}
b0070f03 2182
eb59817e 2183registeraccount() {
57e58ce7 2184 _reg_length="$1"
eb59817e 2185 _initpath
57e58ce7 2186 _regAccount "$_reg_length"
eb59817e 2187}
d404e92d 2188
8a29fbc8 2189__calcAccountKeyHash() {
ca7202eb 2190 [ -f "$ACCOUNT_KEY_PATH" ] && _digest sha256 <"$ACCOUNT_KEY_PATH"
8a29fbc8 2191}
2192
57e58ce7 2193#keylength
d404e92d 2194_regAccount() {
2195 _initpath
57e58ce7 2196 _reg_length="$1"
4c2a3841 2197
5c48e139 2198 if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then
2199 _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH"
2200 mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH"
2201 fi
4c2a3841 2202
5c48e139 2203 if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then
2204 _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH"
2205 mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH"
2206 fi
4c2a3841 2207
2208 if [ ! -f "$ACCOUNT_KEY_PATH" ]; then
2209 if ! _create_account_key "$_reg_length"; then
d404e92d 2210 _err "Create account key error."
2211 return 1
2212 fi
2213 fi
4c2a3841 2214
2215 if ! _calcjwk "$ACCOUNT_KEY_PATH"; then
d404e92d 2216 return 1
2217 fi
2218
2219 _updateTos=""
2220 _reg_res="new-reg"
4c2a3841 2221 while true; do
d404e92d 2222 _debug AGREEMENT "$AGREEMENT"
4c2a3841 2223
d404e92d 2224 regjson='{"resource": "'$_reg_res'", "agreement": "'$AGREEMENT'"}'
2225
4c2a3841 2226 if [ "$ACCOUNT_EMAIL" ]; then
d404e92d 2227 regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}'
2228 fi
2229
4c2a3841 2230 if [ -z "$_updateTos" ]; then
d404e92d 2231 _info "Registering account"
2232
4c2a3841 2233 if ! _send_signed_request "$API/acme/new-reg" "$regjson"; then
d404e92d 2234 _err "Register account Error: $response"
2235 return 1
2236 fi
2237
4c2a3841 2238 if [ "$code" = "" ] || [ "$code" = '201' ]; then
ca7202eb 2239 echo "$response" >"$ACCOUNT_JSON_PATH"
d404e92d 2240 _info "Registered"
4c2a3841 2241 elif [ "$code" = '409' ]; then
d404e92d 2242 _info "Already registered"
2243 else
2244 _err "Register account Error: $response"
2245 return 1
2246 fi
2247
4c2a3841 2248 _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
d404e92d 2249 _debug "_accUri" "$_accUri"
d404e92d 2250
c2c8f320 2251 _tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _head_n 1 | _egrep_o "<.*>" | tr -d '<>')"
d404e92d 2252 _debug "_tos" "$_tos"
4c2a3841 2253 if [ -z "$_tos" ]; then
d404e92d 2254 _debug "Use default tos: $DEFAULT_AGREEMENT"
2255 _tos="$DEFAULT_AGREEMENT"
2256 fi
2257 if [ "$_tos" != "$AGREEMENT" ]; then
2258 _updateTos=1
2259 AGREEMENT="$_tos"
2260 _reg_res="reg"
2261 continue
2262 fi
4c2a3841 2263
d404e92d 2264 else
2265 _debug "Update tos: $_tos"
4c2a3841 2266 if ! _send_signed_request "$_accUri" "$regjson"; then
d404e92d 2267 _err "Update tos error."
2268 return 1
2269 fi
4c2a3841 2270 if [ "$code" = '202' ]; then
eb59817e 2271 _info "Update success."
4c2a3841 2272
8a29fbc8 2273 CA_KEY_HASH="$(__calcAccountKeyHash)"
2274 _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
2275 _savecaconf CA_KEY_HASH "$CA_KEY_HASH"
d404e92d 2276 else
800e3f45 2277 _err "Update account error."
d404e92d 2278 return 1
2279 fi
2280 fi
2281 return 0
2282 done
2283
2284}
2285
a61fe418 2286# domain folder file
2287_findHook() {
2288 _hookdomain="$1"
2289 _hookcat="$2"
2290 _hookname="$3"
2291
c7b16249 2292 if [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname" ]; then
2293 d_api="$_SCRIPT_HOME/$_hookcat/$_hookname"
2294 elif [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname.sh" ]; then
2295 d_api="$_SCRIPT_HOME/$_hookcat/$_hookname.sh"
4c2a3841 2296 elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ]; then
a61fe418 2297 d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname"
4c2a3841 2298 elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ]; then
a61fe418 2299 d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname.sh"
4c2a3841 2300 elif [ -f "$LE_WORKING_DIR/$_hookname" ]; then
a61fe418 2301 d_api="$LE_WORKING_DIR/$_hookname"
4c2a3841 2302 elif [ -f "$LE_WORKING_DIR/$_hookname.sh" ]; then
a61fe418 2303 d_api="$LE_WORKING_DIR/$_hookname.sh"
4c2a3841 2304 elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname" ]; then
a61fe418 2305 d_api="$LE_WORKING_DIR/$_hookcat/$_hookname"
4c2a3841 2306 elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname.sh" ]; then
a61fe418 2307 d_api="$LE_WORKING_DIR/$_hookcat/$_hookname.sh"
2308 fi
2309
2310 printf "%s" "$d_api"
2311}
2312
f940b2a5 2313#domain
2314__get_domain_new_authz() {
2315 _gdnd="$1"
2316 _info "Getting new-authz for domain" "$_gdnd"
4c2a3841 2317
f940b2a5 2318 _Max_new_authz_retry_times=5
2319 _authz_i=0
4c2a3841 2320 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do
efd96153 2321 _debug "Try new-authz for the $_authz_i time."
4c2a3841 2322 if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then
f940b2a5 2323 _err "Can not get domain new authz."
2324 return 1
2325 fi
4c2a3841 2326 if ! _contains "$response" "An error occurred while processing your request"; then
f940b2a5 2327 _info "The new-authz request is ok."
2328 break
2329 fi
2330 _authz_i="$(_math "$_authz_i" + 1)"
9e45ac93 2331 _info "The server is busy, Sleep $_authz_i to retry."
f940b2a5 2332 _sleep "$_authz_i"
4c2a3841 2333 done
f940b2a5 2334
4c2a3841 2335 if [ "$_authz_i" = "$_Max_new_authz_retry_times" ]; then
efd96153 2336 _err "new-authz retry reach the max $_Max_new_authz_retry_times times."
f940b2a5 2337 fi
4c2a3841 2338
2339 if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then
f940b2a5 2340 _err "new-authz error: $response"
2341 return 1
2342 fi
2343
2344}
2345
10afcaca 2346#webroot, domain domainlist keylength
4c3b3608 2347issue() {
4c2a3841 2348 if [ -z "$2" ]; then
43822d37 2349 _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ "
4c3b3608 2350 return 1
2351 fi
2352 Le_Webroot="$1"
2353 Le_Domain="$2"
2354 Le_Alt="$3"
2355 Le_Keylength="$4"
2356 Le_RealCertPath="$5"
2357 Le_RealKeyPath="$6"
2358 Le_RealCACertPath="$7"
2359 Le_ReloadCmd="$8"
a63b05a9 2360 Le_RealFullChainPath="$9"
b0070f03 2361 Le_PreHook="${10}"
2362 Le_PostHook="${11}"
2363 Le_RenewHook="${12}"
0463b5d6 2364 Le_LocalAddress="${13}"
4c2a3841 2365
eccec5f6 2366 #remove these later.
4c2a3841 2367 if [ "$Le_Webroot" = "dns-cf" ]; then
eccec5f6 2368 Le_Webroot="dns_cf"
2369 fi
4c2a3841 2370 if [ "$Le_Webroot" = "dns-dp" ]; then
eccec5f6 2371 Le_Webroot="dns_dp"
2372 fi
4c2a3841 2373 if [ "$Le_Webroot" = "dns-cx" ]; then
eccec5f6 2374 Le_Webroot="dns_cx"
2375 fi
950172dc 2376 _debug "Using api: $API"
4c2a3841 2377
2378 if [ ! "$IS_RENEW" ]; then
ca7202eb 2379 _initpath "$Le_Domain" "$Le_Keylength"
43822d37 2380 mkdir -p "$DOMAIN_PATH"
2381 fi
eccec5f6 2382
4c2a3841 2383 if [ -f "$DOMAIN_CONF" ]; then
61623d22 2384 Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime)
a4270efa 2385 _debug Le_NextRenewTime "$Le_NextRenewTime"
95e06de5 2386 if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
bb25febd 2387 _saved_domain=$(_readdomainconf Le_Domain)
2388 _debug _saved_domain "$_saved_domain"
2389 _saved_alt=$(_readdomainconf Le_Alt)
2390 _debug _saved_alt "$_saved_alt"
4c2a3841 2391 if [ "$_saved_domain,$_saved_alt" = "$Le_Domain,$Le_Alt" ]; then
bb25febd 2392 _info "Domains not changed."
2393 _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")"
4c2a3841 2394 _info "Add '$(__red '--force')' to force to renew."
bb25febd 2395 return $RENEW_SKIP
2396 else
2397 _info "Domains have changed."
2398 fi
4c3b3608 2399 fi
2400 fi
96a46cfc 2401
4c2a3841 2402 _savedomainconf "Le_Domain" "$Le_Domain"
2403 _savedomainconf "Le_Alt" "$Le_Alt"
2404 _savedomainconf "Le_Webroot" "$Le_Webroot"
2405
2406 _savedomainconf "Le_PreHook" "$Le_PreHook"
2407 _savedomainconf "Le_PostHook" "$Le_PostHook"
2408 _savedomainconf "Le_RenewHook" "$Le_RenewHook"
2409
2410 if [ "$Le_LocalAddress" ]; then
2411 _savedomainconf "Le_LocalAddress" "$Le_LocalAddress"
72518d48 2412 else
2413 _cleardomainconf "Le_LocalAddress"
2414 fi
6ae0f7f5 2415
f6dcd989 2416 Le_API="$API"
2417 _savedomainconf "Le_API" "$Le_API"
4c2a3841 2418
2419 if [ "$Le_Alt" = "$NO_VALUE" ]; then
4c3b3608 2420 Le_Alt=""
2421 fi
4c2a3841 2422
2423 if [ "$Le_Keylength" = "$NO_VALUE" ]; then
d404e92d 2424 Le_Keylength=""
2425 fi
4c2a3841 2426
2427 if ! _on_before_issue; then
0463b5d6 2428 _err "_on_before_issue."
2429 return 1
4c3b3608 2430 fi
0463b5d6 2431
8a29fbc8 2432 _saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")"
2433 _debug2 _saved_account_key_hash "$_saved_account_key_hash"
4c2a3841 2434
2435 if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then
57e58ce7 2436 if ! _regAccount "$_accountkeylength"; then
8a29fbc8 2437 _on_issue_err
2438 return 1
2439 fi
57e58ce7 2440 else
2441 _debug "_saved_account_key_hash is not changed, skip register account."
166096dc 2442 fi
166096dc 2443
4c2a3841 2444 if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ]; then
10afcaca 2445 _info "Signing from existing CSR."
2446 else
2447 _key=$(_readdomainconf Le_Keylength)
2448 _debug "Read key length:$_key"
4c2a3841 2449 if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ]; then
ca7202eb 2450 if ! createDomainKey "$Le_Domain" "$Le_Keylength"; then
10afcaca 2451 _err "Create domain key error."
2452 _clearup
b0070f03 2453 _on_issue_err
10afcaca 2454 return 1
2455 fi
2456 fi
2457
4c2a3841 2458 if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then
10afcaca 2459 _err "Create CSR error."
5ef501c5 2460 _clearup
b0070f03 2461 _on_issue_err
41e3eafa 2462 return 1
2463 fi
4c3b3608 2464 fi
10afcaca 2465
4c2a3841 2466 _savedomainconf "Le_Keylength" "$Le_Keylength"
2467
4c3b3608 2468 vlist="$Le_Vlist"
cae203be 2469
2470 _info "Getting domain auth token for each domain"
4c3b3608 2471 sep='#'
4c2a3841 2472 if [ -z "$vlist" ]; then
2473 alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ')
a63b05a9 2474 _index=1
2475 _currentRoot=""
4c2a3841 2476 for d in $alldomains; do
ca7202eb 2477 _info "Getting webroot for domain" "$d"
a63b05a9 2478 _w="$(echo $Le_Webroot | cut -d , -f $_index)"
0463b5d6 2479 _info _w "$_w"
4c2a3841 2480 if [ "$_w" ]; then
a63b05a9 2481 _currentRoot="$_w"
2482 fi
2483 _debug "_currentRoot" "$_currentRoot"
00a50605 2484 _index=$(_math $_index + 1)
4c2a3841 2485
a63b05a9 2486 vtype="$VTYPE_HTTP"
4c2a3841 2487 if _startswith "$_currentRoot" "dns"; then
a63b05a9 2488 vtype="$VTYPE_DNS"
2489 fi
4c2a3841 2490
2491 if [ "$_currentRoot" = "$W_TLS" ]; then
e22bcf7c 2492 vtype="$VTYPE_TLS"
2493 fi
c4d8fd83 2494
4c2a3841 2495 if ! __get_domain_new_authz "$d"; then
c4d8fd83 2496 _clearup
b0070f03 2497 _on_issue_err
c4d8fd83 2498 return 1
2499 fi
2500
4c2a3841 2501 if [ -z "$thumbprint" ]; then
2502 accountkey_json=$(printf "%s" "$jwk" | tr -d ' ')
ae2db62f 2503 thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode)
4c3b3608 2504 fi
2505
4c2a3841 2506 entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
4c3b3608 2507 _debug entry "$entry"
4c2a3841 2508 if [ -z "$entry" ]; then
19539575 2509 _err "Error, can not get domain token $d"
2510 _clearup
b0070f03 2511 _on_issue_err
19539575 2512 return 1
2513 fi
22ea4004 2514 token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
ca7202eb 2515 _debug token "$token"
4c2a3841 2516
2517 uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')"
ca7202eb 2518 _debug uri "$uri"
cae203be 2519
4c3b3608 2520 keyauthorization="$token.$thumbprint"
2521 _debug keyauthorization "$keyauthorization"
2522
95e06de5 2523 if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
d35bf517 2524 _info "$d is already verified, skip."
ca7202eb 2525 keyauthorization="$STATE_VERIFIED"
d35bf517 2526 _debug keyauthorization "$keyauthorization"
ec603bee 2527 fi
2528
a63b05a9 2529 dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot"
4c3b3608 2530 _debug dvlist "$dvlist"
4c2a3841 2531
4c3b3608 2532 vlist="$vlist$dvlist,"
2533
2534 done
2535
2536 #add entry
2537 dnsadded=""
4c2a3841 2538 ventries=$(echo "$vlist" | tr ',' ' ')
2539 for ventry in $ventries; do
ca7202eb 2540 d=$(echo "$ventry" | cut -d "$sep" -f 1)
2541 keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
2542 vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
2543 _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
ec603bee 2544
4c2a3841 2545 if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
ec603bee 2546 _info "$d is already verified, skip $vtype."
2547 continue
2548 fi
2549
4c2a3841 2550 if [ "$vtype" = "$VTYPE_DNS" ]; then
4c3b3608 2551 dnsadded='0'
2552 txtdomain="_acme-challenge.$d"
2553 _debug txtdomain "$txtdomain"
22ea4004 2554 txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _urlencode)"
4c3b3608 2555 _debug txt "$txt"
a61fe418 2556
0c538f75 2557 d_api="$(_findHook "$d" dnsapi "$_currentRoot")"
a61fe418 2558
4c3b3608 2559 _debug d_api "$d_api"
4c2a3841 2560
2561 if [ "$d_api" ]; then
4c3b3608 2562 _info "Found domain api file: $d_api"
2563 else
2564 _err "Add the following TXT record:"
0c538f75 2565 _err "Domain: '$(__green "$txtdomain")'"
2566 _err "TXT value: '$(__green "$txt")'"
4c3b3608 2567 _err "Please be aware that you prepend _acme-challenge. before your domain"
2568 _err "so the resulting subdomain will be: $txtdomain"
2569 continue
2570 fi
4c2a3841 2571
73b8b120 2572 (
ca7202eb 2573 if ! . "$d_api"; then
73b8b120 2574 _err "Load file $d_api error. Please check your api file and try again."
2575 return 1
2576 fi
4c2a3841 2577
158f22f7 2578 addcommand="${_currentRoot}_add"
ca7202eb 2579 if ! _exists "$addcommand"; then
73b8b120 2580 _err "It seems that your api file is not correct, it must have a function named: $addcommand"
2581 return 1
2582 fi
4c2a3841 2583
ca7202eb 2584 if ! $addcommand "$txtdomain" "$txt"; then
73b8b120 2585 _err "Error add txt for domain:$txtdomain"
2586 return 1
2587 fi
2588 )
4c2a3841 2589
2590 if [ "$?" != "0" ]; then
5ef501c5 2591 _clearup
b0070f03 2592 _on_issue_err
4c3b3608 2593 return 1
2594 fi
2595 dnsadded='1'
2596 fi
2597 done
2598
4c2a3841 2599 if [ "$dnsadded" = '0' ]; then
2600 _savedomainconf "Le_Vlist" "$vlist"
4c3b3608 2601 _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
2602 _err "Please add the TXT records to the domains, and retry again."
5ef501c5 2603 _clearup
b0070f03 2604 _on_issue_err
4c3b3608 2605 return 1
2606 fi
4c2a3841 2607
4c3b3608 2608 fi
4c2a3841 2609
2610 if [ "$dnsadded" = '1' ]; then
2611 if [ -z "$Le_DNSSleep" ]; then
ca7202eb 2612 Le_DNSSleep="$DEFAULT_DNS_SLEEP"
0e38c60d 2613 else
4c2a3841 2614 _savedomainconf "Le_DNSSleep" "$Le_DNSSleep"
0e38c60d 2615 fi
2616
5fbc47eb 2617 _info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect"
ca7202eb 2618 _sleep "$Le_DNSSleep"
4c3b3608 2619 fi
4c2a3841 2620
4c3b3608 2621 _debug "ok, let's start to verify"
a63b05a9 2622
0463b5d6 2623 _ncIndex=1
4c2a3841 2624 ventries=$(echo "$vlist" | tr ',' ' ')
2625 for ventry in $ventries; do
ca7202eb 2626 d=$(echo "$ventry" | cut -d "$sep" -f 1)
2627 keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
2628 uri=$(echo "$ventry" | cut -d "$sep" -f 3)
2629 vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
2630 _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
ec603bee 2631
4c2a3841 2632 if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
ec603bee 2633 _info "$d is already verified, skip $vtype."
2634 continue
2635 fi
2636
4c3b3608 2637 _info "Verifying:$d"
2638 _debug "d" "$d"
2639 _debug "keyauthorization" "$keyauthorization"
2640 _debug "uri" "$uri"
2641 removelevel=""
e22bcf7c 2642 token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)"
a63b05a9 2643
2644 _debug "_currentRoot" "$_currentRoot"
2645
4c2a3841 2646 if [ "$vtype" = "$VTYPE_HTTP" ]; then
2647 if [ "$_currentRoot" = "$NO_VALUE" ]; then
4c3b3608 2648 _info "Standalone mode server"
4c2a3841 2649 _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")"
0463b5d6 2650 _ncIndex="$(_math $_ncIndex + 1)"
2651 _startserver "$keyauthorization" "$_ncaddr" &
4c2a3841 2652 if [ "$?" != "0" ]; then
5ef501c5 2653 _clearup
b0070f03 2654 _on_issue_err
6fc1447f 2655 return 1
2656 fi
4c3b3608 2657 serverproc="$!"
5dbf664a 2658 sleep 1
ca7202eb 2659 _debug serverproc "$serverproc"
6fc1447f 2660
4c3b3608 2661 else
4c2a3841 2662 if [ "$_currentRoot" = "apache" ]; then
6f930641 2663 wellknown_path="$ACME_DIR"
2664 else
a63b05a9 2665 wellknown_path="$_currentRoot/.well-known/acme-challenge"
4c2a3841 2666 if [ ! -d "$_currentRoot/.well-known" ]; then
6f930641 2667 removelevel='1'
4c2a3841 2668 elif [ ! -d "$_currentRoot/.well-known/acme-challenge" ]; then
6f930641 2669 removelevel='2'
2670 else
2671 removelevel='3'
2672 fi
4c3b3608 2673 fi
6f930641 2674
4c3b3608 2675 _debug wellknown_path "$wellknown_path"
6f930641 2676
4c3b3608 2677 _debug "writing token:$token to $wellknown_path/$token"
2678
2679 mkdir -p "$wellknown_path"
93fc48a2 2680
4c2a3841 2681 if ! printf "%s" "$keyauthorization" >"$wellknown_path/$token"; then
93fc48a2 2682 _err "$d:Can not write token to file : $wellknown_path/$token"
2683 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
2684 _clearup
2685 _on_issue_err
2686 return 1
2687 fi
2688
4c2a3841 2689 if [ ! "$usingApache" ]; then
44edb2bd 2690 if webroot_owner=$(_stat "$_currentRoot"); then
32fdc196 2691 _debug "Changing owner/group of .well-known to $webroot_owner"
ca7202eb 2692 chown -R "$webroot_owner" "$_currentRoot/.well-known"
32fdc196 2693 else
4c2a3841 2694 _debug "not chaning owner/group of webroot"
32fdc196 2695 fi
df886ffa 2696 fi
4c2a3841 2697
4c3b3608 2698 fi
4c2a3841 2699
2700 elif [ "$vtype" = "$VTYPE_TLS" ]; then
e22bcf7c 2701 #create A
2702 #_hash_A="$(printf "%s" $token | _digest "sha256" "hex" )"
2703 #_debug2 _hash_A "$_hash_A"
2704 #_x="$(echo $_hash_A | cut -c 1-32)"
2705 #_debug2 _x "$_x"
2706 #_y="$(echo $_hash_A | cut -c 33-64)"
2707 #_debug2 _y "$_y"
2708 #_SAN_A="$_x.$_y.token.acme.invalid"
2709 #_debug2 _SAN_A "$_SAN_A"
4c2a3841 2710
e22bcf7c 2711 #create B
0c538f75 2712 _hash_B="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")"
e22bcf7c 2713 _debug2 _hash_B "$_hash_B"
0c538f75 2714 _x="$(echo "$_hash_B" | cut -c 1-32)"
e22bcf7c 2715 _debug2 _x "$_x"
0c538f75 2716 _y="$(echo "$_hash_B" | cut -c 33-64)"
e22bcf7c 2717 _debug2 _y "$_y"
4c2a3841 2718
e22bcf7c 2719 #_SAN_B="$_x.$_y.ka.acme.invalid"
4c2a3841 2720
e22bcf7c 2721 _SAN_B="$_x.$_y.acme.invalid"
2722 _debug2 _SAN_B "$_SAN_B"
4c2a3841 2723
2724 _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")"
0c538f75 2725 _ncIndex="$(_math "$_ncIndex" + 1)"
0463b5d6 2726 if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" "$_ncaddr"; then
e22bcf7c 2727 _err "Start tls server error."
2728 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
2729 _clearup
b0070f03 2730 _on_issue_err
e22bcf7c 2731 return 1
2732 fi
4c3b3608 2733 fi
4c2a3841 2734
ca7202eb 2735 if ! _send_signed_request "$uri" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"; then
c4d8fd83 2736 _err "$d:Can not get challenge: $response"
2737 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
2738 _clearup
b0070f03 2739 _on_issue_err
c4d8fd83 2740 return 1
2741 fi
4c2a3841 2742
2743 if [ ! -z "$code" ] && [ ! "$code" = '202' ]; then
c60883ef 2744 _err "$d:Challenge error: $response"
a63b05a9 2745 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 2746 _clearup
b0070f03 2747 _on_issue_err
4c3b3608 2748 return 1
2749 fi
4c2a3841 2750
6fc1447f 2751 waittimes=0
4c2a3841 2752 if [ -z "$MAX_RETRY_TIMES" ]; then
6fc1447f 2753 MAX_RETRY_TIMES=30
2754 fi
4c2a3841 2755
2756 while true; do
0c538f75 2757 waittimes=$(_math "$waittimes" + 1)
4c2a3841 2758 if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ]; then
6fc1447f 2759 _err "$d:Timeout"
2760 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
2761 _clearup
b0070f03 2762 _on_issue_err
6fc1447f 2763 return 1
2764 fi
4c2a3841 2765
5dbf664a 2766 _debug "sleep 2 secs to verify"
2767 sleep 2
4c3b3608 2768 _debug "checking"
44edb2bd 2769 response="$(_get "$uri")"
4c2a3841 2770 if [ "$?" != "0" ]; then
c60883ef 2771 _err "$d:Verify error:$response"
a63b05a9 2772 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 2773 _clearup
b0070f03 2774 _on_issue_err
4c3b3608 2775 return 1
2776 fi
9aaf36cd 2777 _debug2 original "$response"
4c2a3841 2778
2779 response="$(echo "$response" | _normalizeJson)"
7012b91f 2780 _debug2 response "$response"
4c2a3841 2781
2782 status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"')
2783 if [ "$status" = "valid" ]; then
4c3b3608 2784 _info "Success"
ca7202eb 2785 _stopserver "$serverproc"
4c3b3608 2786 serverproc=""
a63b05a9 2787 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c2a3841 2788 break
4c3b3608 2789 fi
4c2a3841 2790
2791 if [ "$status" = "invalid" ]; then
2792 error="$(echo "$response" | tr -d "\r\n" | _egrep_o '"error":\{[^\}]*')"
2793 _debug2 error "$error"
2794 errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)"
2795 _debug2 errordetail "$errordetail"
2796 if [ "$errordetail" ]; then
2797 _err "$d:Verify error:$errordetail"
2798 else
2799 _err "$d:Verify error:$error"
2800 fi
2801 if [ "$DEBUG" ]; then
2802 if [ "$vtype" = "$VTYPE_HTTP" ]; then
2803 _debug "Debug: get token url."
2804 _get "http://$d/.well-known/acme-challenge/$token" "" 1
2805 fi
2806 fi
a63b05a9 2807 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 2808 _clearup
b0070f03 2809 _on_issue_err
4c2a3841 2810 return 1
4c3b3608 2811 fi
4c2a3841 2812
2813 if [ "$status" = "pending" ]; then
4c3b3608 2814 _info "Pending"
2815 else
4c2a3841 2816 _err "$d:Verify error:$response"
a63b05a9 2817 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 2818 _clearup
b0070f03 2819 _on_issue_err
4c3b3608 2820 return 1
2821 fi
4c2a3841 2822
4c3b3608 2823 done
4c2a3841 2824
4c3b3608 2825 done
2826
2827 _clearup
2828 _info "Verify finished, start to sign."
fa8311dc 2829 der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _urlencode)"
4c2a3841 2830
2831 if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then
c4d8fd83 2832 _err "Sign failed."
b0070f03 2833 _on_issue_err
c4d8fd83 2834 return 1
2835 fi
4c2a3841 2836
d404e92d 2837 _rcert="$response"
0c538f75 2838 Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
4c2a3841 2839 _savedomainconf "Le_LinkCert" "$Le_LinkCert"
4c3b3608 2840
4c2a3841 2841 if [ "$Le_LinkCert" ]; then
2842 echo "$BEGIN_CERT" >"$CERT_PATH"
4c3b3608 2843
72518d48 2844 #if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then
2845 # _debug "Get cert failed. Let's try last response."
2846 # printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH"
2847 #fi
4c2a3841 2848
2849 if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >>"$CERT_PATH"; then
72518d48 2850 _debug "Try cert link."
4c2a3841 2851 _get "$Le_LinkCert" | _base64 "multiline" >>"$CERT_PATH"
d404e92d 2852 fi
2853
4c2a3841 2854 echo "$END_CERT" >>"$CERT_PATH"
43822d37 2855 _info "$(__green "Cert success.")"
4c3b3608 2856 cat "$CERT_PATH"
5980ebc7 2857
4c2a3841 2858 _info "Your cert is in $(__green " $CERT_PATH ")"
2859
2860 if [ -f "$CERT_KEY_PATH" ]; then
2861 _info "Your cert key is in $(__green " $CERT_KEY_PATH ")"
5980ebc7 2862 fi
2863
caf1fc10 2864 cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH"
281aa349 2865
4c2a3841 2866 if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ]; then
281aa349 2867 USER_PATH="$PATH"
2868 _saveaccountconf "USER_PATH" "$USER_PATH"
2869 fi
4c3b3608 2870 fi
4c3b3608 2871
4c2a3841 2872 if [ -z "$Le_LinkCert" ]; then
0c538f75 2873 response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)"
4c2a3841 2874 _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')"
b0070f03 2875 _on_issue_err
4c3b3608 2876 return 1
2877 fi
4c2a3841 2878
2879 _cleardomainconf "Le_Vlist"
2880
0c538f75 2881 Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>')
4c2a3841 2882 if ! _contains "$Le_LinkIssuer" ":"; then
fac1e367 2883 Le_LinkIssuer="$API$Le_LinkIssuer"
2884 fi
4c2a3841 2885
2886 _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer"
2887
2888 if [ "$Le_LinkIssuer" ]; then
2889 echo "$BEGIN_CERT" >"$CA_CERT_PATH"
2890 _get "$Le_LinkIssuer" | _base64 "multiline" >>"$CA_CERT_PATH"
2891 echo "$END_CERT" >>"$CA_CERT_PATH"
2892 _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")"
2893 cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH"
2894 _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")"
4c3b3608 2895 fi
4c2a3841 2896
3aae1ae3 2897 Le_CertCreateTime=$(_time)
4c2a3841 2898 _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime"
2899
2900 Le_CertCreateTimeStr=$(date -u)
2901 _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr"
2902
2903 if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ]; then
ca7202eb 2904 Le_RenewalDays="$MAX_RENEW"
054cb72e 2905 else
4c2a3841 2906 _savedomainconf "Le_RenewalDays" "$Le_RenewalDays"
13d7cae9 2907 fi
4c2a3841 2908
2909 if [ "$CA_BUNDLE" ]; then
78009539
PS
2910 _saveaccountconf CA_BUNDLE "$CA_BUNDLE"
2911 else
2912 _clearaccountconf "CA_BUNDLE"
2913 fi
2914
4c2a3841 2915 if [ "$HTTPS_INSECURE" ]; then
fac1e367 2916 _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE"
2917 else
4c2a3841 2918 _clearaccountconf "HTTPS_INSECURE"
13d7cae9 2919 fi
00a50605 2920
4c2a3841 2921 if [ "$Le_Listen_V4" ]; then
2922 _savedomainconf "Le_Listen_V4" "$Le_Listen_V4"
50827188 2923 _cleardomainconf Le_Listen_V6
4c2a3841 2924 elif [ "$Le_Listen_V6" ]; then
2925 _savedomainconf "Le_Listen_V6" "$Le_Listen_V6"
50827188 2926 _cleardomainconf Le_Listen_V4
2927 fi
f6dcd989 2928
ca7202eb 2929 Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60)
4c2a3841 2930
ca7202eb 2931 Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime")
4c2a3841 2932 _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr"
2933
ca7202eb 2934 Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400)
4c2a3841 2935 _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime"
f6dcd989 2936
b0070f03 2937 _on_issue_success
4c3b3608 2938
4c2a3841 2939 if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ]; then
43822d37 2940 _installcert
01f54558 2941 fi
4c0d3f1b 2942
4c3b3608 2943}
2944
43822d37 2945#domain [isEcc]
4c3b3608 2946renew() {
2947 Le_Domain="$1"
4c2a3841 2948 if [ -z "$Le_Domain" ]; then
43822d37 2949 _usage "Usage: $PROJECT_ENTRY --renew -d domain.com [--ecc]"
4c3b3608 2950 return 1
2951 fi
2952
43822d37 2953 _isEcc="$2"
2954
e799ef29 2955 _initpath "$Le_Domain" "$_isEcc"
43822d37 2956
e2053b22 2957 _info "$(__green "Renew: '$Le_Domain'")"
4c2a3841 2958 if [ ! -f "$DOMAIN_CONF" ]; then
43822d37 2959 _info "'$Le_Domain' is not a issued domain, skip."
4c2a3841 2960 return 0
4c3b3608 2961 fi
4c2a3841 2962
2963 if [ "$Le_RenewalDays" ]; then
1e6b68f5 2964 _savedomainconf Le_RenewalDays "$Le_RenewalDays"
2965 fi
2966
8663fb7e 2967 . "$DOMAIN_CONF"
4c2a3841 2968
2969 if [ "$Le_API" ]; then
5c48e139 2970 API="$Le_API"
2971 fi
4c2a3841 2972
2973 if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
e2053b22 2974 _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")"
2975 _info "Add '$(__red '--force')' to force to renew."
e799ef29 2976 return "$RENEW_SKIP"
4c3b3608 2977 fi
4c2a3841 2978
4c3b3608 2979 IS_RENEW="1"
0463b5d6 2980 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"
e799ef29 2981 res="$?"
4c2a3841 2982 if [ "$res" != "0" ]; then
e799ef29 2983 return "$res"
a61fe418 2984 fi
4c2a3841 2985
2986 if [ "$Le_DeployHook" ]; then
e799ef29 2987 deploy "$Le_Domain" "$Le_DeployHook" "$Le_Keylength"
2988 res="$?"
a61fe418 2989 fi
4c2a3841 2990
4c3b3608 2991 IS_RENEW=""
2992
e799ef29 2993 return "$res"
4c3b3608 2994}
2995
cc179731 2996#renewAll [stopRenewOnError]
4c3b3608 2997renewAll() {
2998 _initpath
cc179731 2999 _stopRenewOnError="$1"
3000 _debug "_stopRenewOnError" "$_stopRenewOnError"
3001 _ret="0"
43822d37 3002
e591d5cf 3003 for di in "${CERT_HOME}"/*.*/; do
3004 _debug di "$di"
3005 d=$(basename "$di")
201aa244 3006 _debug d "$d"
43822d37 3007 (
201aa244 3008 if _endswith "$d" "$ECC_SUFFIX"; then
3009 _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2)
3010 d=$(echo "$d" | cut -d "$ECC_SEP" -f 1)
43822d37 3011 fi
3012 renew "$d" "$_isEcc"
4d2f38b0 3013 )
cc179731 3014 rc="$?"
3015 _debug "Return code: $rc"
4c2a3841 3016 if [ "$rc" != "0" ]; then
3017 if [ "$rc" = "$RENEW_SKIP" ]; then
cc179731 3018 _info "Skipped $d"
4c2a3841 3019 elif [ "$_stopRenewOnError" ]; then
cc179731 3020 _err "Error renew $d, stop now."
201aa244 3021 return "$rc"
cc179731 3022 else
3023 _ret="$rc"
3024 _err "Error renew $d, Go ahead to next one."
3025 fi
3026 fi
4c3b3608 3027 done
201aa244 3028 return "$_ret"
4c3b3608 3029}
3030
10afcaca 3031#csr webroot
4c2a3841 3032signcsr() {
10afcaca 3033 _csrfile="$1"
3034 _csrW="$2"
3035 if [ -z "$_csrfile" ] || [ -z "$_csrW" ]; then
3036 _usage "Usage: $PROJECT_ENTRY --signcsr --csr mycsr.csr -w /path/to/webroot/a.com/ "
3037 return 1
3038 fi
3039
3040 _initpath
3041
3042 _csrsubj=$(_readSubjectFromCSR "$_csrfile")
4c2a3841 3043 if [ "$?" != "0" ]; then
10afcaca 3044 _err "Can not read subject from csr: $_csrfile"
3045 return 1
3046 fi
ad752b31 3047 _debug _csrsubj "$_csrsubj"
10afcaca 3048
3049 _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile")
4c2a3841 3050 if [ "$?" != "0" ]; then
10afcaca 3051 _err "Can not read domain list from csr: $_csrfile"
3052 return 1
3053 fi
3054 _debug "_csrdomainlist" "$_csrdomainlist"
4c2a3841 3055
3056 if [ -z "$_csrsubj" ]; then
ad752b31 3057 _csrsubj="$(_getfield "$_csrdomainlist" 1)"
3058 _debug _csrsubj "$_csrsubj"
3059 _csrdomainlist="$(echo "$_csrdomainlist" | cut -d , -f 2-)"
3060 _debug "_csrdomainlist" "$_csrdomainlist"
3061 fi
4c2a3841 3062
3063 if [ -z "$_csrsubj" ]; then
ad752b31 3064 _err "Can not read subject from csr: $_csrfile"
3065 return 1
3066 fi
4c2a3841 3067
10afcaca 3068 _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile")
4c2a3841 3069 if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then
10afcaca 3070 _err "Can not read key length from csr: $_csrfile"
3071 return 1
3072 fi
4c2a3841 3073
10afcaca 3074 _initpath "$_csrsubj" "$_csrkeylength"
3075 mkdir -p "$DOMAIN_PATH"
4c2a3841 3076
10afcaca 3077 _info "Copy csr to: $CSR_PATH"
3078 cp "$_csrfile" "$CSR_PATH"
4c2a3841 3079
10afcaca 3080 issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength"
4c2a3841 3081
10afcaca 3082}
3083
3084showcsr() {
4c2a3841 3085 _csrfile="$1"
10afcaca 3086 _csrd="$2"
3087 if [ -z "$_csrfile" ] && [ -z "$_csrd" ]; then
3088 _usage "Usage: $PROJECT_ENTRY --showcsr --csr mycsr.csr"
3089 return 1
3090 fi
3091
3092 _initpath
4c2a3841 3093
10afcaca 3094 _csrsubj=$(_readSubjectFromCSR "$_csrfile")
4c2a3841 3095 if [ "$?" != "0" ] || [ -z "$_csrsubj" ]; then
10afcaca 3096 _err "Can not read subject from csr: $_csrfile"
3097 return 1
3098 fi
4c2a3841 3099
10afcaca 3100 _info "Subject=$_csrsubj"
3101
3102 _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile")
4c2a3841 3103 if [ "$?" != "0" ]; then
10afcaca 3104 _err "Can not read domain list from csr: $_csrfile"
3105 return 1
3106 fi
3107 _debug "_csrdomainlist" "$_csrdomainlist"
3108
3109 _info "SubjectAltNames=$_csrdomainlist"
3110
10afcaca 3111 _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile")
4c2a3841 3112 if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then
10afcaca 3113 _err "Can not read key length from csr: $_csrfile"
3114 return 1
3115 fi
3116 _info "KeyLength=$_csrkeylength"
3117}
3118
6d7eda3e 3119list() {
22ea4004 3120 _raw="$1"
6d7eda3e 3121 _initpath
4c2a3841 3122
dcf4f8f6 3123 _sep="|"
4c2a3841 3124 if [ "$_raw" ]; then
d5ec5f80 3125 printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew"
e591d5cf 3126 for di in "${CERT_HOME}"/*.*/; do
3127 d=$(basename "$di")
201aa244 3128 _debug d "$d"
dcf4f8f6 3129 (
201aa244 3130 if _endswith "$d" "$ECC_SUFFIX"; then
3131 _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2)
3132 d=$(echo "$d" | cut -d "$ECC_SEP" -f 1)
43822d37 3133 fi
e591d5cf 3134 _initpath "$d" "$_isEcc"
4c2a3841 3135 if [ -f "$DOMAIN_CONF" ]; then
dcf4f8f6 3136 . "$DOMAIN_CONF"
d5ec5f80 3137 printf "%s\n" "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr"
dcf4f8f6 3138 fi
3139 )
3140 done
3141 else
4c2a3841 3142 if _exists column; then
22ea4004 3143 list "raw" | column -t -s "$_sep"
3144 else
43822d37 3145 list "raw" | tr "$_sep" '\t'
22ea4004 3146 fi
dcf4f8f6 3147 fi
6d7eda3e 3148
6d7eda3e 3149}
3150
a61fe418 3151deploy() {
3152 Le_Domain="$1"
3153 Le_DeployHook="$2"
3154 _isEcc="$3"
4c2a3841 3155 if [ -z "$Le_DeployHook" ]; then
a61fe418 3156 _usage "Usage: $PROJECT_ENTRY --deploy -d domain.com --deploy-hook cpanel [--ecc] "
3157 return 1
3158 fi
3159
e591d5cf 3160 _initpath "$Le_Domain" "$_isEcc"
4c2a3841 3161 if [ ! -d "$DOMAIN_PATH" ]; then
a61fe418 3162 _err "Domain is not valid:'$Le_Domain'"
3163 return 1
3164 fi
3165
e591d5cf 3166 _deployApi="$(_findHook "$Le_Domain" deploy "$Le_DeployHook")"
4c2a3841 3167 if [ -z "$_deployApi" ]; then
a61fe418 3168 _err "The deploy hook $Le_DeployHook is not found."
3169 return 1
3170 fi
3171 _debug _deployApi "$_deployApi"
4c2a3841 3172
a61fe418 3173 _savedomainconf Le_DeployHook "$Le_DeployHook"
4c2a3841 3174
a61fe418 3175 if ! (
e591d5cf 3176 if ! . "$_deployApi"; then
a61fe418 3177 _err "Load file $_deployApi error. Please check your api file and try again."
3178 return 1
3179 fi
4c2a3841 3180
a61fe418 3181 d_command="${Le_DeployHook}_deploy"
e591d5cf 3182 if ! _exists "$d_command"; then
a61fe418 3183 _err "It seems that your api file is not correct, it must have a function named: $d_command"
3184 return 1
3185 fi
4c2a3841 3186
e591d5cf 3187 if ! $d_command "$Le_Domain" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then
a61fe418 3188 _err "Error deploy for domain:$Le_Domain"
3189 _on_issue_err
3190 return 1
3191 fi
4c2a3841 3192 ); then
a61fe418 3193 _err "Deploy error."
3194 return 1
3195 else
3196 _info "$(__green Success)"
3197 fi
4c2a3841 3198
a61fe418 3199}
3200
4c3b3608 3201installcert() {
3202 Le_Domain="$1"
4c2a3841 3203 if [ -z "$Le_Domain" ]; then
43822d37 3204 _usage "Usage: $PROJECT_ENTRY --installcert -d domain.com [--ecc] [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]"
4c3b3608 3205 return 1
3206 fi
3207
3208 Le_RealCertPath="$2"
3209 Le_RealKeyPath="$3"
3210 Le_RealCACertPath="$4"
3211 Le_ReloadCmd="$5"
a63b05a9 3212 Le_RealFullChainPath="$6"
43822d37 3213 _isEcc="$7"
3214
4bd31f49 3215 _initpath "$Le_Domain" "$_isEcc"
4c2a3841 3216 if [ ! -d "$DOMAIN_PATH" ]; then
43822d37 3217 _err "Domain is not valid:'$Le_Domain'"
3218 return 1
3219 fi
3220
3221 _installcert
3222}
4c3b3608 3223
43822d37 3224_installcert() {
4c2a3841 3225 _savedomainconf "Le_RealCertPath" "$Le_RealCertPath"
3226 _savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath"
3227 _savedomainconf "Le_RealKeyPath" "$Le_RealKeyPath"
3228 _savedomainconf "Le_ReloadCmd" "$Le_ReloadCmd"
3229 _savedomainconf "Le_RealFullChainPath" "$Le_RealFullChainPath"
4c3b3608 3230
4c2a3841 3231 if [ "$Le_RealCertPath" = "$NO_VALUE" ]; then
4d2f38b0 3232 Le_RealCertPath=""
3233 fi
4c2a3841 3234 if [ "$Le_RealKeyPath" = "$NO_VALUE" ]; then
4d2f38b0 3235 Le_RealKeyPath=""
3236 fi
4c2a3841 3237 if [ "$Le_RealCACertPath" = "$NO_VALUE" ]; then
4d2f38b0 3238 Le_RealCACertPath=""
3239 fi
4c2a3841 3240 if [ "$Le_ReloadCmd" = "$NO_VALUE" ]; then
4d2f38b0 3241 Le_ReloadCmd=""
3242 fi
4c2a3841 3243 if [ "$Le_RealFullChainPath" = "$NO_VALUE" ]; then
4d2f38b0 3244 Le_RealFullChainPath=""
3245 fi
4c2a3841 3246
4c2a3841 3247 if [ "$Le_RealCertPath" ]; then
4bd31f49 3248
4d2f38b0 3249 _info "Installing cert to:$Le_RealCertPath"
4c2a3841 3250 if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ]; then
ff3bce32 3251 cp "$Le_RealCertPath" "$Le_RealCertPath".bak
4c3b3608 3252 fi
4c2a3841 3253 cat "$CERT_PATH" >"$Le_RealCertPath"
4c3b3608 3254 fi
4c2a3841 3255
3256 if [ "$Le_RealCACertPath" ]; then
4bd31f49 3257
4d2f38b0 3258 _info "Installing CA to:$Le_RealCACertPath"
4c2a3841 3259 if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ]; then
3260 echo "" >>"$Le_RealCACertPath"
3261 cat "$CA_CERT_PATH" >>"$Le_RealCACertPath"
4c3b3608 3262 else
4c2a3841 3263 if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ]; then
ff3bce32 3264 cp "$Le_RealCACertPath" "$Le_RealCACertPath".bak
78552b18 3265 fi
4c2a3841 3266 cat "$CA_CERT_PATH" >"$Le_RealCACertPath"
4c3b3608 3267 fi
3268 fi
3269
4c2a3841 3270 if [ "$Le_RealKeyPath" ]; then
4c3b3608 3271
4d2f38b0 3272 _info "Installing key to:$Le_RealKeyPath"
4c2a3841 3273 if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ]; then
ff3bce32 3274 cp "$Le_RealKeyPath" "$Le_RealKeyPath".bak
4c3b3608 3275 fi
4c2a3841 3276 cat "$CERT_KEY_PATH" >"$Le_RealKeyPath"
4c3b3608 3277 fi
4c2a3841 3278
3279 if [ "$Le_RealFullChainPath" ]; then
4bd31f49 3280
4d2f38b0 3281 _info "Installing full chain to:$Le_RealFullChainPath"
4c2a3841 3282 if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ]; then
ff3bce32 3283 cp "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak
a63b05a9 3284 fi
4c2a3841 3285 cat "$CERT_FULLCHAIN_PATH" >"$Le_RealFullChainPath"
3286 fi
4c3b3608 3287
4c2a3841 3288 if [ "$Le_ReloadCmd" ]; then
4c3b3608 3289
4c3b3608 3290 _info "Run Le_ReloadCmd: $Le_ReloadCmd"
4c2a3841 3291 if (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd"); then
43822d37 3292 _info "$(__green "Reload success")"
4d2f38b0 3293 else
3294 _err "Reload error for :$Le_Domain"
3295 fi
3296 fi
3297
4c3b3608 3298}
3299
3300installcronjob() {
3301 _initpath
4c2a3841 3302 if ! _exists "crontab"; then
77546ea5 3303 _err "crontab doesn't exist, so, we can not install cron jobs."
3304 _err "All your certs will not be renewed automatically."
a7b7355d 3305 _err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday."
77546ea5 3306 return 1
3307 fi
3308
4c3b3608 3309 _info "Installing cron job"
4c2a3841 3310 if ! crontab -l | grep "$PROJECT_ENTRY --cron"; then
3311 if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then
a7b7355d 3312 lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY"
4c3b3608 3313 else
a7b7355d 3314 _err "Can not install cronjob, $PROJECT_ENTRY not found."
4c3b3608 3315 return 1
3316 fi
4c2a3841 3317 if _exists uname && uname -a | grep solaris >/dev/null; then
3318 crontab -l | {
3319 cat
3320 echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"
3321 } | crontab --
22ea4004 3322 else
4c2a3841 3323 crontab -l | {
3324 cat
3325 echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"
3326 } | crontab -
22ea4004 3327 fi
4c3b3608 3328 fi
4c2a3841 3329 if [ "$?" != "0" ]; then
4c3b3608 3330 _err "Install cron job failed. You need to manually renew your certs."
3331 _err "Or you can add cronjob by yourself:"
a7b7355d 3332 _err "$lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"
4c3b3608 3333 return 1
3334 fi
3335}
3336
3337uninstallcronjob() {
4c2a3841 3338 if ! _exists "crontab"; then
37db5b81 3339 return
3340 fi
4c3b3608 3341 _info "Removing cron job"
a7b7355d 3342 cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")"
4c2a3841 3343 if [ "$cr" ]; then
3344 if _exists uname && uname -a | grep solaris >/dev/null; then
22ea4004 3345 crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab --
3346 else
3347 crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab -
3348 fi
a7b7355d 3349 LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')"
4c3b3608 3350 _info LE_WORKING_DIR "$LE_WORKING_DIR"
4c2a3841 3351 fi
4c3b3608 3352 _initpath
a7b7355d 3353
4c3b3608 3354}
3355
6cb415f5 3356revoke() {
3357 Le_Domain="$1"
4c2a3841 3358 if [ -z "$Le_Domain" ]; then
43822d37 3359 _usage "Usage: $PROJECT_ENTRY --revoke -d domain.com"
6cb415f5 3360 return 1
3361 fi
4c2a3841 3362
43822d37 3363 _isEcc="$2"
3364
c4a375b3 3365 _initpath "$Le_Domain" "$_isEcc"
4c2a3841 3366 if [ ! -f "$DOMAIN_CONF" ]; then
6cb415f5 3367 _err "$Le_Domain is not a issued domain, skip."
4c2a3841 3368 return 1
6cb415f5 3369 fi
4c2a3841 3370
3371 if [ ! -f "$CERT_PATH" ]; then
6cb415f5 3372 _err "Cert for $Le_Domain $CERT_PATH is not found, skip."
3373 return 1
3374 fi
6cb415f5 3375
4c2a3841 3376 cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _urlencode)"
3377
3378 if [ -z "$cert" ]; then
6cb415f5 3379 _err "Cert for $Le_Domain is empty found, skip."
3380 return 1
3381 fi
4c2a3841 3382
6cb415f5 3383 data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}"
3384 uri="$API/acme/revoke-cert"
3385
4c2a3841 3386 if [ -f "$CERT_KEY_PATH" ]; then
1befee5a 3387 _info "Try domain key first."
c4a375b3 3388 if _send_signed_request "$uri" "$data" "" "$CERT_KEY_PATH"; then
4c2a3841 3389 if [ -z "$response" ]; then
1befee5a 3390 _info "Revoke success."
c4a375b3 3391 rm -f "$CERT_PATH"
1befee5a 3392 return 0
4c2a3841 3393 else
1befee5a 3394 _err "Revoke error by domain key."
3395 _err "$response"
3396 fi
6cb415f5 3397 fi
4c2a3841 3398 else
1befee5a 3399 _info "Domain key file doesn't exists."
6cb415f5 3400 fi
6cb415f5 3401
1befee5a 3402 _info "Try account key."
6cb415f5 3403
c4a375b3 3404 if _send_signed_request "$uri" "$data" "" "$ACCOUNT_KEY_PATH"; then
4c2a3841 3405 if [ -z "$response" ]; then
6cb415f5 3406 _info "Revoke success."
c4a375b3 3407 rm -f "$CERT_PATH"
6cb415f5 3408 return 0
4c2a3841 3409 else
6cb415f5 3410 _err "Revoke error."
c9c31c04 3411 _debug "$response"
6cb415f5 3412 fi
3413 fi
3414 return 1
3415}
4c3b3608 3416
0c00e870 3417#domain vtype
3418_deactivate() {
3419 _d_domain="$1"
3420 _d_type="$2"
3421 _initpath
4c2a3841 3422
0c00e870 3423 _d_i=0
3424 _d_max_retry=9
4c2a3841 3425 while [ "$_d_i" -lt "$_d_max_retry" ]; do
0407c4e0 3426 _info "Deactivate: $_d_domain"
0c00e870 3427 _d_i="$(_math $_d_i + 1)"
4c2a3841 3428
3429 if ! __get_domain_new_authz "$_d_domain"; then
f940b2a5 3430 _err "Can not get domain new authz token."
0c00e870 3431 return 1
3432 fi
4c2a3841 3433
c2c8f320 3434 authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
3f4513b3 3435 _debug "authzUri" "$authzUri"
0c00e870 3436
4c2a3841 3437 if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then
0c00e870 3438 _err "new-authz error: $response"
3439 return 1
3440 fi
4c2a3841 3441
3442 entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"status":"valid","uri"[^\}]*')"
0c00e870 3443 _debug entry "$entry"
4c2a3841 3444
3445 if [ -z "$entry" ]; then
fb2029e7 3446 _info "No more valid entry found."
0c00e870 3447 break
3448 fi
4c2a3841 3449
0c00e870 3450 _vtype="$(printf "%s\n" "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')"
c4a375b3 3451 _debug _vtype "$_vtype"
0c00e870 3452 _info "Found $_vtype"
3453
4c2a3841 3454 uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')"
c4a375b3 3455 _debug uri "$uri"
4c2a3841 3456
3457 if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then
0c00e870 3458 _info "Skip $_vtype"
3459 continue
3460 fi
4c2a3841 3461
0c00e870 3462 _info "Deactivate: $_vtype"
4c2a3841 3463
3464 if ! _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}"; then
0c00e870 3465 _err "Can not deactivate $_vtype."
3466 return 1
3467 fi
4c2a3841 3468
fb2029e7 3469 _info "Deactivate: $_vtype success."
4c2a3841 3470
0c00e870 3471 done
3472 _debug "$_d_i"
4c2a3841 3473 if [ "$_d_i" -lt "$_d_max_retry" ]; then
0c00e870 3474 _info "Deactivated success!"
3475 else
3476 _err "Deactivate failed."
3477 fi
3478
3479}
3480
3481deactivate() {
3f4513b3 3482 _d_domain_list="$1"
0c00e870 3483 _d_type="$2"
3484 _initpath
3f4513b3 3485 _debug _d_domain_list "$_d_domain_list"
4c2a3841 3486 if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then
3f4513b3 3487 _usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]"
0c00e870 3488 return 1
3489 fi
4c2a3841 3490 for _d_dm in $(echo "$_d_domain_list" | tr ',' ' '); do
3491 if [ -z "$_d_dm" ] || [ "$_d_dm" = "$NO_VALUE" ]; then
3f4513b3 3492 continue
3493 fi
c4a375b3 3494 if ! _deactivate "$_d_dm" "$_d_type"; then
86c017ec 3495 return 1
3496 fi
3f4513b3 3497 done
0c00e870 3498}
3499
4c3b3608 3500# Detect profile file if not specified as environment variable
3501_detect_profile() {
4c2a3841 3502 if [ -n "$PROFILE" -a -f "$PROFILE" ]; then
4c3b3608 3503 echo "$PROFILE"
3504 return
3505 fi
3506
4c3b3608 3507 DETECTED_PROFILE=''
4c3b3608 3508 SHELLTYPE="$(basename "/$SHELL")"
3509
4c2a3841 3510 if [ "$SHELLTYPE" = "bash" ]; then
3511 if [ -f "$HOME/.bashrc" ]; then
4c3b3608 3512 DETECTED_PROFILE="$HOME/.bashrc"
4c2a3841 3513 elif [ -f "$HOME/.bash_profile" ]; then
4c3b3608 3514 DETECTED_PROFILE="$HOME/.bash_profile"
3515 fi
4c2a3841 3516 elif [ "$SHELLTYPE" = "zsh" ]; then
4c3b3608 3517 DETECTED_PROFILE="$HOME/.zshrc"
3518 fi
3519
4c2a3841 3520 if [ -z "$DETECTED_PROFILE" ]; then
3521 if [ -f "$HOME/.profile" ]; then
4c3b3608 3522 DETECTED_PROFILE="$HOME/.profile"
4c2a3841 3523 elif [ -f "$HOME/.bashrc" ]; then
4c3b3608 3524 DETECTED_PROFILE="$HOME/.bashrc"
4c2a3841 3525 elif [ -f "$HOME/.bash_profile" ]; then
4c3b3608 3526 DETECTED_PROFILE="$HOME/.bash_profile"
4c2a3841 3527 elif [ -f "$HOME/.zshrc" ]; then
4c3b3608 3528 DETECTED_PROFILE="$HOME/.zshrc"
3529 fi
3530 fi
3531
4c2a3841 3532 if [ ! -z "$DETECTED_PROFILE" ]; then
4c3b3608 3533 echo "$DETECTED_PROFILE"
3534 fi
3535}
3536
3537_initconf() {
3538 _initpath
4c2a3841 3539 if [ ! -f "$ACCOUNT_CONF_PATH" ]; then
d53289d7 3540 echo "#ACCOUNT_CONF_PATH=xxxx
3541
3542#Account configurations:
4c3b3608 3543#Here are the supported macros, uncomment them to make them take effect.
d53289d7 3544
caa2e45a 3545#ACCOUNT_EMAIL=aaa@example.com # the account email used to register account.
5fd3f21b 3546#ACCOUNT_KEY_PATH=\"/path/to/account.key\"
b2817897 3547#CERT_HOME=\"/path/to/cert/home\"
4c3b3608 3548
d404e92d 3549
3550
d0871bda 3551#LOG_FILE=\"$DEFAULT_LOG_FILE\"
6b500036 3552#LOG_LEVEL=1
5ea6e9c9 3553
251d1c5c 3554#AUTO_UPGRADE=\"1\"
89002ed2 3555
4c3b3608 3556#STAGE=1 # Use the staging api
3557#FORCE=1 # Force to issue cert
3558#DEBUG=1 # Debug mode
3559
166096dc 3560
8814a348 3561#USER_AGENT=\"$USER_AGENT\"
281aa349 3562
c4a375b3 3563#USER_PATH=
281aa349 3564
4c3b3608 3565#dns api
3566#######################
3567#Cloudflare:
3568#api key
3d49985a 3569#CF_Key=\"sdfsdfsdfljlbjkljlkjsdfoiwje\"
4c3b3608 3570#account email
3d49985a 3571#CF_Email=\"xxxx@sss.com\"
4c3b3608 3572
3573#######################
3574#Dnspod.cn:
3575#api key id
3d49985a 3576#DP_Id=\"1234\"
4c3b3608 3577#api key
3d49985a 3578#DP_Key=\"sADDsdasdgdsf\"
4c3b3608 3579
3580#######################
3581#Cloudxns.com:
3d49985a 3582#CX_Key=\"1234\"
4c3b3608 3583#
3d49985a 3584#CX_Secret=\"sADDsdasdgdsf\"
30de13b4 3585
3586#######################
3587#Godaddy.com:
3588#GD_Key=\"sdfdsgdgdfdasfds\"
3589#
3590#GD_Secret=\"sADDsdasdfsdfdssdgdsf\"
4c3b3608 3591
2d279c4c
PK
3592#######################
3593#nsupdate:
3594#NSUPDATE_KEY=\"/path/to/update.key\"
3595#NSUPDATE_SERVER=\"192.168.0.1\"
3596
d6f0c2b5
MZ
3597#######################
3598#PowerDNS:
3599#PDNS_Url=\"http://ns.example.com:8081\"
3600#PDNS_ServerId=\"localhost\"
3601#PDNS_Token=\"0123456789ABCDEF\"
3602#PDNS_Ttl=60
3603
d5ec5f80 3604 " >"$ACCOUNT_CONF_PATH"
4c3b3608 3605 fi
3606}
3607
c8e9a31e 3608# nocron
c60883ef 3609_precheck() {
c8e9a31e 3610 _nocron="$1"
4c2a3841 3611
3612 if ! _exists "curl" && ! _exists "wget"; then
c60883ef 3613 _err "Please install curl or wget first, we need to access http resources."
4c3b3608 3614 return 1
3615 fi
4c2a3841 3616
3617 if [ -z "$_nocron" ]; then
3618 if ! _exists "crontab"; then
c8e9a31e 3619 _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'."
3620 _err "We need to set cron job to renew the certs automatically."
3621 _err "Otherwise, your certs will not be able to be renewed automatically."
4c2a3841 3622 if [ -z "$FORCE" ]; then
c8e9a31e 3623 _err "Please add '--force' and try install again to go without crontab."
3624 _err "./$PROJECT_ENTRY --install --force"
3625 return 1
3626 fi
77546ea5 3627 fi
4c3b3608 3628 fi
4c2a3841 3629
3630 if ! _exists "openssl"; then
c60883ef 3631 _err "Please install openssl first."
3632 _err "We need openssl to generate keys."
4c3b3608 3633 return 1
3634 fi
4c2a3841 3635
3636 if ! _exists "nc"; then
c60883ef 3637 _err "It is recommended to install nc first, try to install 'nc' or 'netcat'."
3638 _err "We use nc for standalone server if you use standalone mode."
3639 _err "If you don't use standalone mode, just ignore this warning."
3640 fi
4c2a3841 3641
c60883ef 3642 return 0
3643}
3644
0a7c9364 3645_setShebang() {
3646 _file="$1"
3647 _shebang="$2"
4c2a3841 3648 if [ -z "$_shebang" ]; then
43822d37 3649 _usage "Usage: file shebang"
0a7c9364 3650 return 1
3651 fi
3652 cp "$_file" "$_file.tmp"
4c2a3841 3653 echo "$_shebang" >"$_file"
3654 sed -n 2,99999p "$_file.tmp" >>"$_file"
3655 rm -f "$_file.tmp"
0a7c9364 3656}
3657
94dc5f33 3658_installalias() {
3659 _initpath
3660
3661 _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env"
4c2a3841 3662 if [ "$_upgrading" ] && [ "$_upgrading" = "1" ]; then
44edb2bd 3663 echo "$(cat "$_envfile")" | sed "s|^LE_WORKING_DIR.*$||" >"$_envfile"
3664 echo "$(cat "$_envfile")" | sed "s|^alias le.*$||" >"$_envfile"
3665 echo "$(cat "$_envfile")" | sed "s|^alias le.sh.*$||" >"$_envfile"
94dc5f33 3666 fi
3667
1786a5e5 3668 _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\""
94dc5f33 3669 _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\""
3670
3671 _profile="$(_detect_profile)"
4c2a3841 3672 if [ "$_profile" ]; then
94dc5f33 3673 _debug "Found profile: $_profile"
aba5c634 3674 _info "Installing alias to '$_profile'"
94dc5f33 3675 _setopt "$_profile" ". \"$_envfile\""
3676 _info "OK, Close and reopen your terminal to start using $PROJECT_NAME"
3677 else
3678 _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME"
3679 fi
94dc5f33 3680
3681 #for csh
3682 _cshfile="$LE_WORKING_DIR/$PROJECT_ENTRY.csh"
94dc5f33 3683 _csh_profile="$HOME/.cshrc"
4c2a3841 3684 if [ -f "$_csh_profile" ]; then
aba5c634 3685 _info "Installing alias to '$_csh_profile'"
6626371d 3686 _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
3687 _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\""
4c2a3841 3688 _setopt "$_csh_profile" "source \"$_cshfile\""
94dc5f33 3689 fi
4c2a3841 3690
acafa585 3691 #for tcsh
3692 _tcsh_profile="$HOME/.tcshrc"
4c2a3841 3693 if [ -f "$_tcsh_profile" ]; then
aba5c634 3694 _info "Installing alias to '$_tcsh_profile'"
acafa585 3695 _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
3696 _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\""
4c2a3841 3697 _setopt "$_tcsh_profile" "source \"$_cshfile\""
acafa585 3698 fi
94dc5f33 3699
3700}
3701
c8e9a31e 3702# nocron
c60883ef 3703install() {
f3e4cea3 3704
4c2a3841 3705 if [ -z "$LE_WORKING_DIR" ]; then
f3e4cea3 3706 LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
3707 fi
4c2a3841 3708
c8e9a31e 3709 _nocron="$1"
4c2a3841 3710 if ! _initpath; then
c60883ef 3711 _err "Install failed."
4c3b3608 3712 return 1
3713 fi
4c2a3841 3714 if [ "$_nocron" ]; then
52677b0a 3715 _debug "Skip install cron job"
3716 fi
4c2a3841 3717
3718 if ! _precheck "$_nocron"; then
c60883ef 3719 _err "Pre-check failed, can not install."
4c3b3608 3720 return 1
3721 fi
4c2a3841 3722
6cc11ffb 3723 #convert from le
4c2a3841 3724 if [ -d "$HOME/.le" ]; then
3725 for envfile in "le.env" "le.sh.env"; do
3726 if [ -f "$HOME/.le/$envfile" ]; then
3727 if grep "le.sh" "$HOME/.le/$envfile" >/dev/null; then
3728 _upgrading="1"
3729 _info "You are upgrading from le.sh"
3730 _info "Renaming \"$HOME/.le\" to $LE_WORKING_DIR"
3731 mv "$HOME/.le" "$LE_WORKING_DIR"
3732 mv "$LE_WORKING_DIR/$envfile" "$LE_WORKING_DIR/$PROJECT_ENTRY.env"
3733 break
6cc11ffb 3734 fi
3735 fi
3736 done
3737 fi
3738
4c3b3608 3739 _info "Installing to $LE_WORKING_DIR"
635695ec 3740
4c2a3841 3741 if ! mkdir -p "$LE_WORKING_DIR"; then
90035252 3742 _err "Can not create working dir: $LE_WORKING_DIR"
4a0f23e2 3743 return 1
3744 fi
4c2a3841 3745
762978f8 3746 chmod 700 "$LE_WORKING_DIR"
3747
d5ec5f80 3748 cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY"
4c3b3608 3749
4c2a3841 3750 if [ "$?" != "0" ]; then
a7b7355d 3751 _err "Install failed, can not copy $PROJECT_ENTRY"
4c3b3608 3752 return 1
3753 fi
3754
a7b7355d 3755 _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY"
4c3b3608 3756
94dc5f33 3757 _installalias
4c3b3608 3758
4c2a3841 3759 for subf in $_SUB_FOLDERS; do
3760 if [ -d "$subf" ]; then
d5ec5f80 3761 mkdir -p "$LE_WORKING_DIR/$subf"
3762 cp "$subf"/* "$LE_WORKING_DIR"/"$subf"/
a61fe418 3763 fi
3764 done
3765
4c2a3841 3766 if [ ! -f "$ACCOUNT_CONF_PATH" ]; then
4c3b3608 3767 _initconf
3768 fi
6cc11ffb 3769
4c2a3841 3770 if [ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ]; then
635695ec 3771 _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\""
6cc11ffb 3772 fi
3773
4c2a3841 3774 if [ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ]; then
b2817897 3775 _saveaccountconf "CERT_HOME" "$CERT_HOME"
3776 fi
3777
4c2a3841 3778 if [ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ]; then
b2817897 3779 _saveaccountconf "ACCOUNT_KEY_PATH" "$ACCOUNT_KEY_PATH"
3780 fi
4c2a3841 3781
3782 if [ -z "$_nocron" ]; then
c8e9a31e 3783 installcronjob
3784 fi
0a7c9364 3785
4c2a3841 3786 if [ -z "$NO_DETECT_SH" ]; then
641989fd 3787 #Modify shebang
4c2a3841 3788 if _exists bash; then
66990cf8 3789 _info "Good, bash is found, so change the shebang to use bash as prefered."
641989fd 3790 _shebang='#!/usr/bin/env bash'
3791 _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang"
4c2a3841 3792 for subf in $_SUB_FOLDERS; do
3793 if [ -d "$LE_WORKING_DIR/$subf" ]; then
3794 for _apifile in "$LE_WORKING_DIR/$subf/"*.sh; do
a61fe418 3795 _setShebang "$_apifile" "$_shebang"
3796 done
3797 fi
3798 done
0a7c9364 3799 fi
3800 fi
3801
4c3b3608 3802 _info OK
3803}
3804
52677b0a 3805# nocron
4c3b3608 3806uninstall() {
52677b0a 3807 _nocron="$1"
4c2a3841 3808 if [ -z "$_nocron" ]; then
52677b0a 3809 uninstallcronjob
3810 fi
4c3b3608 3811 _initpath
3812
9aa3be7f 3813 _uninstallalias
4c2a3841 3814
d5ec5f80 3815 rm -f "$LE_WORKING_DIR/$PROJECT_ENTRY"
9aa3be7f 3816 _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself."
3817
3818}
3819
3820_uninstallalias() {
3821 _initpath
3822
4c3b3608 3823 _profile="$(_detect_profile)"
4c2a3841 3824 if [ "$_profile" ]; then
9aa3be7f 3825 _info "Uninstalling alias from: '$_profile'"
d5ec5f80 3826 text="$(cat "$_profile")"
4c2a3841 3827 echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" >"$_profile"
4c3b3608 3828 fi
3829
94dc5f33 3830 _csh_profile="$HOME/.cshrc"
4c2a3841 3831 if [ -f "$_csh_profile" ]; then
9aa3be7f 3832 _info "Uninstalling alias from: '$_csh_profile'"
d5ec5f80 3833 text="$(cat "$_csh_profile")"
4c2a3841 3834 echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_csh_profile"
94dc5f33 3835 fi
4c2a3841 3836
acafa585 3837 _tcsh_profile="$HOME/.tcshrc"
4c2a3841 3838 if [ -f "$_tcsh_profile" ]; then
9aa3be7f 3839 _info "Uninstalling alias from: '$_csh_profile'"
d5ec5f80 3840 text="$(cat "$_tcsh_profile")"
4c2a3841 3841 echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_tcsh_profile"
acafa585 3842 fi
4c3b3608 3843
3844}
3845
3846cron() {
281aa349 3847 IN_CRON=1
89002ed2 3848 _initpath
4c2a3841 3849 if [ "$AUTO_UPGRADE" = "1" ]; then
89002ed2 3850 export LE_WORKING_DIR
3851 (
4c2a3841 3852 if ! upgrade; then
3853 _err "Cron:Upgrade failed!"
3854 return 1
3855 fi
89002ed2 3856 )
d5ec5f80 3857 . "$LE_WORKING_DIR/$PROJECT_ENTRY" >/dev/null
1ab63043 3858
4c2a3841 3859 if [ -t 1 ]; then
1ab63043 3860 __INTERACTIVE="1"
3861 fi
4c2a3841 3862
89002ed2 3863 _info "Auto upgraded to: $VER"
3864 fi
4c3b3608 3865 renewAll
cc179731 3866 _ret="$?"
281aa349 3867 IN_CRON=""
0ba95a3d 3868 exit $_ret
4c3b3608 3869}
3870
3871version() {
a63b05a9 3872 echo "$PROJECT"
3873 echo "v$VER"
4c3b3608 3874}
3875
3876showhelp() {
d0871bda 3877 _initpath
4c3b3608 3878 version
a7b7355d 3879 echo "Usage: $PROJECT_ENTRY command ...[parameters]....
a63b05a9 3880Commands:
3881 --help, -h Show this help message.
3882 --version, -v Show version info.
a7b7355d 3883 --install Install $PROJECT_NAME to your system.
3884 --uninstall Uninstall $PROJECT_NAME, and uninstall the cron job.
10afcaca 3885 --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT .
a63b05a9 3886 --issue Issue a cert.
10afcaca 3887 --signcsr Issue a cert from an existing csr.
a61fe418 3888 --deploy Deploy the cert to your server.
a63b05a9 3889 --installcert Install the issued cert to apache/nginx or any other server.
3890 --renew, -r Renew a cert.
10afcaca 3891 --renewAll Renew all the certs.
a63b05a9 3892 --revoke Revoke a cert.
10afcaca 3893 --list List all the certs.
3894 --showcsr Show the content of a csr.
a63b05a9 3895 --installcronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
3896 --uninstallcronjob Uninstall the cron job. The 'uninstall' command can do this automatically.
3897 --cron Run cron job to renew all the certs.
3898 --toPkcs Export the certificate and key to a pfx file.
eb59817e 3899 --updateaccount Update account info.
3900 --registeraccount Register account key.
a63b05a9 3901 --createAccountKey, -cak Create an account private key, professional use.
3902 --createDomainKey, -cdk Create an domain private key, professional use.
3903 --createCSR, -ccsr Create CSR , professional use.
0c00e870 3904 --deactivate Deactivate the domain authz, professional use.
a63b05a9 3905
3906Parameters:
3907 --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc.
3908 --force, -f Used to force to install or force to renew a cert immediately.
3909 --staging, --test Use staging server, just for test.
3910 --debug Output debug info.
3911
3912 --webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
3913 --standalone Use standalone mode.
e22bcf7c 3914 --tls Use standalone tls mode.
a63b05a9 3915 --apache Use apache mode.
eccec5f6 3916 --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
4a4dacb5 3917 --dnssleep [$DEFAULT_DNS_SLEEP] The time in seconds to wait for all the txt records to take effect in dns api mode. Default $DEFAULT_DNS_SLEEP seconds.
a63b05a9 3918
3919 --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384.
3920 --accountkeylength, -ak [2048] Specifies the account key length.
d0871bda 3921 --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here.
a73c5b33 3922 --log-level 1|2 Specifies the log level, default is 1.
a63b05a9 3923
3924 These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert:
3925
3926 --certpath /path/to/real/cert/file After issue/renew, the cert will be copied to this path.
3927 --keypath /path/to/real/key/file After issue/renew, the key will be copied to this path.
3928 --capath /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path.
3929 --fullchainpath /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path.
3930
3931 --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server.
3932
3933 --accountconf Specifies a customized account config file.
635695ec 3934 --home Specifies the home dir for $PROJECT_NAME .
39c8f79f 3935 --certhome Specifies the home dir to save all the certs, only valid for '--install' command.
635695ec 3936 --useragent Specifies the user agent string. it will be saved for future use too.
b5eb4b90 3937 --accountemail Specifies the account email for registering, Only valid for the '--install' command.
06625071 3938 --accountkey Specifies the account key path, Only valid for the '--install' command.
523c7682 3939 --days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days.
39c8f79f 3940 --httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
e22bcf7c 3941 --tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer.
6ae0f7f5 3942 --local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses.
dcf4f8f6 3943 --listraw Only used for '--list' command, list the certs in raw format.
c8e9a31e 3944 --stopRenewOnError, -se Only valid for '--renewall' command. Stop if one cert has error in renewal.
13d7cae9 3945 --insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted.
78009539 3946 --ca-bundle Specifices the path to the CA certificate bundle to verify api server's certificate.
bc96082f 3947 --nocron Only valid for '--install' command, which means: do not install the default cron job. In this case, the certs will not be renewed automatically.
43822d37 3948 --ecc Specifies to use the ECC cert. Valid for '--installcert', '--renew', '--revoke', '--toPkcs' and '--createCSR'
10afcaca 3949 --csr Specifies the input csr.
b0070f03 3950 --pre-hook Command to be run before obtaining any certificates.
3951 --post-hook Command to be run after attempting to obtain/renew certificates. No matter the obain/renew is success or failed.
3952 --renew-hook Command to be run once for each successfully renewed certificate.
a61fe418 3953 --deploy-hook The hook file to deploy cert
0c9546cc 3954 --ocsp-must-staple, --ocsp Generate ocsp must Staple extension.
6bf281f9 3955 --auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future.
6ae0f7f5 3956 --listen-v4 Force standalone/tls server to listen at ipv4.
3957 --listen-v6 Force standalone/tls server to listen at ipv6.
4c3b3608 3958 "
3959}
3960
52677b0a 3961# nocron
4a0f23e2 3962_installOnline() {
3963 _info "Installing from online archive."
52677b0a 3964 _nocron="$1"
4c2a3841 3965 if [ ! "$BRANCH" ]; then
4a0f23e2 3966 BRANCH="master"
3967 fi
a8df88ab 3968
4a0f23e2 3969 target="$PROJECT/archive/$BRANCH.tar.gz"
3970 _info "Downloading $target"
3971 localname="$BRANCH.tar.gz"
4c2a3841 3972 if ! _get "$target" >$localname; then
df9547ae 3973 _err "Download error."
4a0f23e2 3974 return 1
3975 fi
0bbe6eef 3976 (
4c2a3841 3977 _info "Extracting $localname"
3978 tar xzf $localname
3979
3980 cd "$PROJECT_NAME-$BRANCH"
3981 chmod +x $PROJECT_ENTRY
3982 if ./$PROJECT_ENTRY install "$_nocron"; then
3983 _info "Install success!"
3984 fi
3985
3986 cd ..
3987
3988 rm -rf "$PROJECT_NAME-$BRANCH"
3989 rm -f "$localname"
0bbe6eef 3990 )
4a0f23e2 3991}
3992
52677b0a 3993upgrade() {
3994 if (
267f283a 3995 _initpath
3996 export LE_WORKING_DIR
d0b748a4 3997 cd "$LE_WORKING_DIR"
52677b0a 3998 _installOnline "nocron"
4c2a3841 3999 ); then
52677b0a 4000 _info "Upgrade success!"
096d8992 4001 exit 0
52677b0a 4002 else
4003 _err "Upgrade failed!"
096d8992 4004 exit 1
52677b0a 4005 fi
4006}
a63b05a9 4007
5ea6e9c9 4008_processAccountConf() {
4c2a3841 4009 if [ "$_useragent" ]; then
5ea6e9c9 4010 _saveaccountconf "USER_AGENT" "$_useragent"
4c2a3841 4011 elif [ "$USER_AGENT" ] && [ "$USER_AGENT" != "$DEFAULT_USER_AGENT" ]; then
d0871bda 4012 _saveaccountconf "USER_AGENT" "$USER_AGENT"
5ea6e9c9 4013 fi
4c2a3841 4014
4015 if [ "$_accountemail" ]; then
5ea6e9c9 4016 _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail"
4c2a3841 4017 elif [ "$ACCOUNT_EMAIL" ] && [ "$ACCOUNT_EMAIL" != "$DEFAULT_ACCOUNT_EMAIL" ]; then
d0871bda 4018 _saveaccountconf "ACCOUNT_EMAIL" "$ACCOUNT_EMAIL"
5ea6e9c9 4019 fi
4c2a3841 4020
4021 if [ "$_auto_upgrade" ]; then
6bf281f9 4022 _saveaccountconf "AUTO_UPGRADE" "$_auto_upgrade"
4c2a3841 4023 elif [ "$AUTO_UPGRADE" ]; then
6bf281f9 4024 _saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE"
4025 fi
4c2a3841 4026
5ea6e9c9 4027}
4028
a63b05a9 4029_process() {
4030 _CMD=""
4031 _domain=""
3f4513b3 4032 _altdomains="$NO_VALUE"
a63b05a9 4033 _webroot=""
bdbf323f 4034 _keylength=""
4035 _accountkeylength=""
4036 _certpath=""
4037 _keypath=""
4038 _capath=""
4039 _fullchainpath=""
4d2f38b0 4040 _reloadcmd=""
a63b05a9 4041 _password=""
635695ec 4042 _accountconf=""
4043 _useragent=""
b5eb4b90 4044 _accountemail=""
4045 _accountkey=""
b2817897 4046 _certhome=""
39c8f79f 4047 _httpport=""
e22bcf7c 4048 _tlsport=""
0e38c60d 4049 _dnssleep=""
dcf4f8f6 4050 _listraw=""
cc179731 4051 _stopRenewOnError=""
e3698edd 4052 #_insecure=""
78009539 4053 _ca_bundle=""
c8e9a31e 4054 _nocron=""
43822d37 4055 _ecc=""
10afcaca 4056 _csr=""
b0070f03 4057 _pre_hook=""
4058 _post_hook=""
4059 _renew_hook=""
a61fe418 4060 _deploy_hook=""
5ea6e9c9 4061 _logfile=""
d0871bda 4062 _log=""
0463b5d6 4063 _local_address=""
a73c5b33 4064 _log_level=""
6bf281f9 4065 _auto_upgrade=""
6ae0f7f5 4066 _listen_v4=""
4067 _listen_v6=""
4c2a3841 4068 while [ ${#} -gt 0 ]; do
a63b05a9 4069 case "${1}" in
4c2a3841 4070
4071 --help | -h)
a63b05a9 4072 showhelp
4073 return
4074 ;;
4c2a3841 4075 --version | -v)
a63b05a9 4076 version
4077 return
4078 ;;
4c2a3841 4079 --install)
a63b05a9 4080 _CMD="install"
4081 ;;
4c2a3841 4082 --uninstall)
a63b05a9 4083 _CMD="uninstall"
4084 ;;
4c2a3841 4085 --upgrade)
52677b0a 4086 _CMD="upgrade"
4087 ;;
4c2a3841 4088 --issue)
a63b05a9 4089 _CMD="issue"
4090 ;;
4c2a3841 4091 --deploy)
a61fe418 4092 _CMD="deploy"
4093 ;;
4c2a3841 4094 --signcsr)
10afcaca 4095 _CMD="signcsr"
4096 ;;
4c2a3841 4097 --showcsr)
10afcaca 4098 _CMD="showcsr"
4099 ;;
4c2a3841 4100 --installcert | -i)
a63b05a9 4101 _CMD="installcert"
4102 ;;
4c2a3841 4103 --renew | -r)
a63b05a9 4104 _CMD="renew"
4105 ;;
4c2a3841 4106 --renewAll | --renewall)
a63b05a9 4107 _CMD="renewAll"
4108 ;;
4c2a3841 4109 --revoke)
a63b05a9 4110 _CMD="revoke"
4111 ;;
4c2a3841 4112 --list)
6d7eda3e 4113 _CMD="list"
4114 ;;
4c2a3841 4115 --installcronjob)
a63b05a9 4116 _CMD="installcronjob"
4117 ;;
4c2a3841 4118 --uninstallcronjob)
a63b05a9 4119 _CMD="uninstallcronjob"
4120 ;;
4c2a3841 4121 --cron)
a63b05a9 4122 _CMD="cron"
4123 ;;
4c2a3841 4124 --toPkcs)
a63b05a9 4125 _CMD="toPkcs"
4c2a3841 4126 ;;
4127 --createAccountKey | --createaccountkey | -cak)
a63b05a9 4128 _CMD="createAccountKey"
4129 ;;
4c2a3841 4130 --createDomainKey | --createdomainkey | -cdk)
a63b05a9 4131 _CMD="createDomainKey"
4132 ;;
4c2a3841 4133 --createCSR | --createcsr | -ccr)
a63b05a9 4134 _CMD="createCSR"
4135 ;;
4c2a3841 4136 --deactivate)
0c00e870 4137 _CMD="deactivate"
4138 ;;
4c2a3841 4139 --updateaccount)
eb59817e 4140 _CMD="updateaccount"
4141 ;;
4c2a3841 4142 --registeraccount)
eb59817e 4143 _CMD="registeraccount"
4144 ;;
4c2a3841 4145 --domain | -d)
a63b05a9 4146 _dvalue="$2"
4c2a3841 4147
4148 if [ "$_dvalue" ]; then
4149 if _startswith "$_dvalue" "-"; then
ee1737a5 4150 _err "'$_dvalue' is not a valid domain for parameter '$1'"
4151 return 1
4152 fi
4c2a3841 4153 if _is_idn "$_dvalue" && ! _exists idn; then
9774b01b 4154 _err "It seems that $_dvalue is an IDN( Internationalized Domain Names), please install 'idn' command first."
4155 return 1
4156 fi
4c2a3841 4157
4158 if [ -z "$_domain" ]; then
ee1737a5 4159 _domain="$_dvalue"
a63b05a9 4160 else
4c2a3841 4161 if [ "$_altdomains" = "$NO_VALUE" ]; then
ee1737a5 4162 _altdomains="$_dvalue"
4163 else
4164 _altdomains="$_altdomains,$_dvalue"
4165 fi
a63b05a9 4166 fi
4167 fi
4c2a3841 4168
a63b05a9 4169 shift
4170 ;;
4171
4c2a3841 4172 --force | -f)
a63b05a9 4173 FORCE="1"
4174 ;;
4c2a3841 4175 --staging | --test)
a63b05a9 4176 STAGE="1"
4177 ;;
4c2a3841 4178 --debug)
4179 if [ -z "$2" ] || _startswith "$2" "-"; then
a63b05a9 4180 DEBUG="1"
4181 else
4182 DEBUG="$2"
4183 shift
4c2a3841 4184 fi
a63b05a9 4185 ;;
4c2a3841 4186 --webroot | -w)
a63b05a9 4187 wvalue="$2"
4c2a3841 4188 if [ -z "$_webroot" ]; then
a63b05a9 4189 _webroot="$wvalue"
4190 else
4191 _webroot="$_webroot,$wvalue"
4192 fi
4193 shift
4c2a3841 4194 ;;
4195 --standalone)
3f4513b3 4196 wvalue="$NO_VALUE"
4c2a3841 4197 if [ -z "$_webroot" ]; then
a63b05a9 4198 _webroot="$wvalue"
4199 else
4200 _webroot="$_webroot,$wvalue"
4201 fi
4202 ;;
4c2a3841 4203 --local-address)
0463b5d6 4204 lvalue="$2"
4205 _local_address="$_local_address$lvalue,"
4206 shift
4207 ;;
4c2a3841 4208 --apache)
a63b05a9 4209 wvalue="apache"
4c2a3841 4210 if [ -z "$_webroot" ]; then
a63b05a9 4211 _webroot="$wvalue"
4212 else
4213 _webroot="$_webroot,$wvalue"
4214 fi
4215 ;;
4c2a3841 4216 --tls)
e22bcf7c 4217 wvalue="$W_TLS"
4c2a3841 4218 if [ -z "$_webroot" ]; then
e22bcf7c 4219 _webroot="$wvalue"
4220 else
4221 _webroot="$_webroot,$wvalue"
4222 fi
4223 ;;
4c2a3841 4224 --dns)
a63b05a9 4225 wvalue="dns"
4c2a3841 4226 if ! _startswith "$2" "-"; then
a63b05a9 4227 wvalue="$2"
4228 shift
4229 fi
4c2a3841 4230 if [ -z "$_webroot" ]; then
a63b05a9 4231 _webroot="$wvalue"
4232 else
4233 _webroot="$_webroot,$wvalue"
4234 fi
4235 ;;
4c2a3841 4236 --dnssleep)
0e38c60d 4237 _dnssleep="$2"
4238 Le_DNSSleep="$_dnssleep"
4239 shift
4240 ;;
4c2a3841 4241
4242 --keylength | -k)
a63b05a9 4243 _keylength="$2"
a63b05a9 4244 shift
4245 ;;
4c2a3841 4246 --accountkeylength | -ak)
2ce87fe2 4247 _accountkeylength="$2"
a63b05a9 4248 shift
4249 ;;
4250
4c2a3841 4251 --certpath)
a63b05a9 4252 _certpath="$2"
4253 shift
4254 ;;
4c2a3841 4255 --keypath)
a63b05a9 4256 _keypath="$2"
4257 shift
4258 ;;
4c2a3841 4259 --capath)
a63b05a9 4260 _capath="$2"
4261 shift
4262 ;;
4c2a3841 4263 --fullchainpath)
a63b05a9 4264 _fullchainpath="$2"
4265 shift
4266 ;;
4c2a3841 4267 --reloadcmd | --reloadCmd)
a63b05a9 4268 _reloadcmd="$2"
4269 shift
4270 ;;
4c2a3841 4271 --password)
a63b05a9 4272 _password="$2"
4273 shift
4274 ;;
4c2a3841 4275 --accountconf)
635695ec 4276 _accountconf="$2"
4277 ACCOUNT_CONF_PATH="$_accountconf"
a7b7355d 4278 shift
a63b05a9 4279 ;;
4c2a3841 4280 --home)
a63b05a9 4281 LE_WORKING_DIR="$2"
a7b7355d 4282 shift
a63b05a9 4283 ;;
4c2a3841 4284 --certhome)
b2817897 4285 _certhome="$2"
4286 CERT_HOME="$_certhome"
4287 shift
4c2a3841 4288 ;;
4289 --useragent)
635695ec 4290 _useragent="$2"
4291 USER_AGENT="$_useragent"
4292 shift
4293 ;;
4c2a3841 4294 --accountemail)
b5eb4b90 4295 _accountemail="$2"
4296 ACCOUNT_EMAIL="$_accountemail"
4297 shift
4298 ;;
4c2a3841 4299 --accountkey)
b5eb4b90 4300 _accountkey="$2"
4301 ACCOUNT_KEY_PATH="$_accountkey"
4302 shift
4303 ;;
4c2a3841 4304 --days)
06625071 4305 _days="$2"
4306 Le_RenewalDays="$_days"
4307 shift
4308 ;;
4c2a3841 4309 --httpport)
39c8f79f 4310 _httpport="$2"
4311 Le_HTTPPort="$_httpport"
4312 shift
4313 ;;
4c2a3841 4314 --tlsport)
e22bcf7c 4315 _tlsport="$2"
4316 Le_TLSPort="$_tlsport"
4317 shift
4318 ;;
4c2a3841 4319
4320 --listraw)
dcf4f8f6 4321 _listraw="raw"
4c2a3841 4322 ;;
4323 --stopRenewOnError | --stoprenewonerror | -se)
cc179731 4324 _stopRenewOnError="1"
4325 ;;
4c2a3841 4326 --insecure)
e3698edd 4327 #_insecure="1"
fac1e367 4328 HTTPS_INSECURE="1"
13d7cae9 4329 ;;
4c2a3841 4330 --ca-bundle)
d5ec5f80 4331 _ca_bundle="$(readlink -f "$2")"
78009539
PS
4332 CA_BUNDLE="$_ca_bundle"
4333 shift
4334 ;;
4c2a3841 4335 --nocron)
c8e9a31e 4336 _nocron="1"
4337 ;;
4c2a3841 4338 --ecc)
43822d37 4339 _ecc="isEcc"
4340 ;;
4c2a3841 4341 --csr)
10afcaca 4342 _csr="$2"
4343 shift
4344 ;;
4c2a3841 4345 --pre-hook)
b0070f03 4346 _pre_hook="$2"
4347 shift
4348 ;;
4c2a3841 4349 --post-hook)
b0070f03 4350 _post_hook="$2"
4351 shift
4352 ;;
4c2a3841 4353 --renew-hook)
b0070f03 4354 _renew_hook="$2"
4355 shift
4356 ;;
4c2a3841 4357 --deploy-hook)
a61fe418 4358 _deploy_hook="$2"
4359 shift
4360 ;;
4c2a3841 4361 --ocsp-must-staple | --ocsp)
0c9546cc 4362 Le_OCSP_Stable="1"
4363 ;;
4c2a3841 4364 --log | --logfile)
d0871bda 4365 _log="1"
5ea6e9c9 4366 _logfile="$2"
4c2a3841 4367 if _startswith "$_logfile" '-'; then
d0871bda 4368 _logfile=""
4369 else
4370 shift
4371 fi
5ea6e9c9 4372 LOG_FILE="$_logfile"
4c2a3841 4373 if [ -z "$LOG_LEVEL" ]; then
a73c5b33 4374 LOG_LEVEL="$DEFAULT_LOG_LEVEL"
4375 fi
4376 ;;
4c2a3841 4377 --log-level)
30bfc2ce 4378 _log_level="$2"
a73c5b33 4379 LOG_LEVEL="$_log_level"
4380 shift
5ea6e9c9 4381 ;;
4c2a3841 4382 --auto-upgrade)
6bf281f9 4383 _auto_upgrade="$2"
4c2a3841 4384 if [ -z "$_auto_upgrade" ] || _startswith "$_auto_upgrade" '-'; then
6bf281f9 4385 _auto_upgrade="1"
4386 else
4387 shift
4388 fi
4389 AUTO_UPGRADE="$_auto_upgrade"
4390 ;;
4c2a3841 4391 --listen-v4)
6ae0f7f5 4392 _listen_v4="1"
4393 Le_Listen_V4="$_listen_v4"
4394 ;;
4c2a3841 4395 --listen-v6)
6ae0f7f5 4396 _listen_v6="1"
4397 Le_Listen_V6="$_listen_v6"
4398 ;;
4c2a3841 4399
4400 *)
a63b05a9 4401 _err "Unknown parameter : $1"
4402 return 1
4403 ;;
4404 esac
4405
4406 shift 1
4407 done
4408
4c2a3841 4409 if [ "${_CMD}" != "install" ]; then
5ea6e9c9 4410 __initHome
661f0583 4411 if [ "$_log" ]; then
4c2a3841 4412 if [ -z "$_logfile" ]; then
661f0583 4413 _logfile="$DEFAULT_LOG_FILE"
4414 fi
d0871bda 4415 fi
4c2a3841 4416 if [ "$_logfile" ]; then
5ea6e9c9 4417 _saveaccountconf "LOG_FILE" "$_logfile"
661f0583 4418 LOG_FILE="$_logfile"
5ea6e9c9 4419 fi
a73c5b33 4420
4c2a3841 4421 if [ "$_log_level" ]; then
a73c5b33 4422 _saveaccountconf "LOG_LEVEL" "$_log_level"
4423 LOG_LEVEL="$_log_level"
4424 fi
4c2a3841 4425
5ea6e9c9 4426 _processAccountConf
4427 fi
4c2a3841 4428
9d548d81 4429 _debug2 LE_WORKING_DIR "$LE_WORKING_DIR"
4c2a3841 4430
4431 if [ "$DEBUG" ]; then
dcf9cb58 4432 version
4433 fi
a63b05a9 4434
4435 case "${_CMD}" in
c8e9a31e 4436 install) install "$_nocron" ;;
bc96082f 4437 uninstall) uninstall "$_nocron" ;;
52677b0a 4438 upgrade) upgrade ;;
a63b05a9 4439 issue)
4c2a3841 4440 issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address"
a63b05a9 4441 ;;
a61fe418 4442 deploy)
4443 deploy "$_domain" "$_deploy_hook" "$_ecc"
4444 ;;
10afcaca 4445 signcsr)
4446 signcsr "$_csr" "$_webroot"
4447 ;;
4448 showcsr)
4449 showcsr "$_csr" "$_domain"
4450 ;;
a63b05a9 4451 installcert)
43822d37 4452 installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_ecc"
a63b05a9 4453 ;;
4c2a3841 4454 renew)
43822d37 4455 renew "$_domain" "$_ecc"
a63b05a9 4456 ;;
4c2a3841 4457 renewAll)
cc179731 4458 renewAll "$_stopRenewOnError"
a63b05a9 4459 ;;
4c2a3841 4460 revoke)
43822d37 4461 revoke "$_domain" "$_ecc"
a63b05a9 4462 ;;
4c2a3841 4463 deactivate)
3f4513b3 4464 deactivate "$_domain,$_altdomains"
eb59817e 4465 ;;
4c2a3841 4466 registeraccount)
57e58ce7 4467 registeraccount "$_accountkeylength"
eb59817e 4468 ;;
4c2a3841 4469 updateaccount)
eb59817e 4470 updateaccount
4471 ;;
4c2a3841 4472 list)
dcf4f8f6 4473 list "$_listraw"
6d7eda3e 4474 ;;
a63b05a9 4475 installcronjob) installcronjob ;;
4476 uninstallcronjob) uninstallcronjob ;;
4477 cron) cron ;;
4c2a3841 4478 toPkcs)
43822d37 4479 toPkcs "$_domain" "$_password" "$_ecc"
a63b05a9 4480 ;;
4c2a3841 4481 createAccountKey)
5fbc47eb 4482 createAccountKey "$_accountkeylength"
a63b05a9 4483 ;;
4c2a3841 4484 createDomainKey)
a63b05a9 4485 createDomainKey "$_domain" "$_keylength"
4486 ;;
4c2a3841 4487 createCSR)
43822d37 4488 createCSR "$_domain" "$_altdomains" "$_ecc"
a63b05a9 4489 ;;
4490
4491 *)
4492 _err "Invalid command: $_CMD"
4c2a3841 4493 showhelp
a63b05a9 4494 return 1
4c2a3841 4495 ;;
a63b05a9 4496 esac
d3595686 4497 _ret="$?"
4c2a3841 4498 if [ "$_ret" != "0" ]; then
d3595686 4499 return $_ret
4500 fi
4c2a3841 4501
4502 if [ "${_CMD}" = "install" ]; then
4503 if [ "$_log" ]; then
4504 if [ -z "$LOG_FILE" ]; then
d0871bda 4505 LOG_FILE="$DEFAULT_LOG_FILE"
4506 fi
4507 _saveaccountconf "LOG_FILE" "$LOG_FILE"
5ea6e9c9 4508 fi
4c2a3841 4509
4510 if [ "$_log_level" ]; then
a73c5b33 4511 _saveaccountconf "LOG_LEVEL" "$_log_level"
4512 fi
5ea6e9c9 4513 _processAccountConf
b5eb4b90 4514 fi
635695ec 4515
a63b05a9 4516}
4517
4c2a3841 4518if [ "$INSTALLONLINE" ]; then
d1f97fc8 4519 INSTALLONLINE=""
4a0f23e2 4520 _installOnline $BRANCH
4521 exit
4522fi
4c3b3608 4523
319e0ae3 4524main() {
4525 [ -z "$1" ] && showhelp && return
4c2a3841 4526 if _startswith "$1" '-'; then _process "$@"; else "$@"; fi
319e0ae3 4527}
e69a7c38 4528
aa7b82de 4529main "$@"