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