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