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