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