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