]> git.proxmox.com Git - mirror_acme.sh.git/blame - acme.sh
Merge pull request #234 from tgoodyear/patch-1
[mirror_acme.sh.git] / acme.sh
CommitLineData
0a7c9364 1#!/usr/bin/env sh
bfdf1f48 2
61623d22 3VER=2.3.0
a7b7355d 4
6cc11ffb 5PROJECT_NAME="acme.sh"
a7b7355d 6
6cc11ffb 7PROJECT_ENTRY="acme.sh"
8
9PROJECT="https://github.com/Neilpang/$PROJECT_NAME"
4c3b3608 10
11DEFAULT_CA="https://acme-v01.api.letsencrypt.org"
12DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf"
13
a7b7355d 14DEFAULT_USER_AGENT="$PROJECT_ENTRY client: $PROJECT"
bbbdcb09 15
4c3b3608 16STAGE_CA="https://acme-staging.api.letsencrypt.org"
17
18VTYPE_HTTP="http-01"
19VTYPE_DNS="dns-01"
e22bcf7c 20VTYPE_TLS="tls-sni-01"
21VTYPE_TLS2="tls-sni-02"
22
523c7682 23MAX_RENEW=80
24
e22bcf7c 25W_TLS="tls"
4c3b3608 26
88fab7d6 27BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----"
28END_CSR="-----END CERTIFICATE REQUEST-----"
29
30BEGIN_CERT="-----BEGIN CERTIFICATE-----"
31END_CERT="-----END CERTIFICATE-----"
32
cc179731 33RENEW_SKIP=2
34
8663fb7e 35if [ -z "$AGREEMENT" ] ; then
4c3b3608 36 AGREEMENT="$DEFAULT_AGREEMENT"
37fi
38
4c3b3608 39
00a50605 40
41_URGLY_PRINTF=""
f4312b44 42if [ "$(printf '\x41')" != 'A' ] ; then
00a50605 43 _URGLY_PRINTF=1
44fi
45
46
4c3b3608 47_info() {
8663fb7e 48 if [ -z "$2" ] ; then
a63b05a9 49 echo "[$(date)] $1"
4c3b3608 50 else
19539575 51 echo "[$(date)] $1='$2'"
4c3b3608 52 fi
53}
54
55_err() {
a63b05a9 56 _info "$@" >&2
4c3b3608 57 return 1
58}
59
c60883ef 60_debug() {
8663fb7e 61 if [ -z "$DEBUG" ] ; then
c60883ef 62 return
63 fi
a63b05a9 64 _err "$@"
c60883ef 65 return 0
66}
67
a63b05a9 68_debug2() {
8663fb7e 69 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
a63b05a9 70 _debug "$@"
71 fi
72 return
73}
74
dceb3aca 75_startswith(){
76 _str="$1"
77 _sub="$2"
19539575 78 echo "$_str" | grep "^$_sub" >/dev/null 2>&1
dceb3aca 79}
80
81_contains(){
82 _str="$1"
83 _sub="$2"
19539575 84 echo "$_str" | grep "$_sub" >/dev/null 2>&1
dceb3aca 85}
86
c53da1ef 87_hasfield() {
88 _str="$1"
89 _field="$2"
90 _sep="$3"
91 if [ -z "$_field" ] ; then
92 _err "Usage: str field [sep]"
93 return 1
94 fi
95
96 if [ -z "$_sep" ] ; then
97 _sep=","
98 fi
99
100 for f in $(echo "$_str" | tr ',' ' ') ; do
101 if [ "$f" = "$_field" ] ; then
102 _debug "'$_str' contains '$_field'"
103 return 0 #contains ok
104 fi
105 done
106 _debug "'$_str' does not contain '$_field'"
107 return 1 #not contains
108}
109
dceb3aca 110_exists(){
c60883ef 111 cmd="$1"
8663fb7e 112 if [ -z "$cmd" ] ; then
c60883ef 113 _err "Usage: _exists cmd"
114 return 1
115 fi
eac18b1c 116 if type command >/dev/null 2>&1 ; then
19539575 117 command -v "$cmd" >/dev/null 2>&1
eac18b1c 118 else
19539575 119 type "$cmd" >/dev/null 2>&1
eac18b1c 120 fi
c60883ef 121 ret="$?"
a63b05a9 122 _debug2 "$cmd exists=$ret"
c60883ef 123 return $ret
124}
125
00a50605 126#a + b
127_math(){
128 expr "$@"
129}
130
131_h_char_2_dec() {
132 _ch=$1
133 case "${_ch}" in
134 a|A)
19539575 135 printf "10"
00a50605 136 ;;
137 b|B)
19539575 138 printf "11"
00a50605 139 ;;
140 c|C)
19539575 141 printf "12"
00a50605 142 ;;
143 d|D)
19539575 144 printf "13"
00a50605 145 ;;
146 e|E)
19539575 147 printf "14"
00a50605 148 ;;
149 f|F)
19539575 150 printf "15"
00a50605 151 ;;
152 *)
19539575 153 printf "%s" "$_ch"
00a50605 154 ;;
19539575 155 esac
00a50605 156
157}
158
4c3b3608 159_h2b() {
160 hex=$(cat)
161 i=1
162 j=2
00a50605 163 if _exists let ; then
164 uselet="1"
165 fi
166 _debug uselet "$uselet"
f4312b44 167 _debug _URGLY_PRINTF "$_URGLY_PRINTF"
19539575 168 while true ; do
00a50605 169 if [ -z "$_URGLY_PRINTF" ] ; then
19539575 170 h="$(printf $hex | cut -c $i-$j)"
00a50605 171 if [ -z "$h" ] ; then
172 break;
173 fi
174 printf "\x$h"
175 else
19539575 176 ic="$(printf $hex | cut -c $i)"
177 jc="$(printf $hex | cut -c $j)"
00a50605 178 if [ -z "$ic$jc" ] ; then
179 break;
180 fi
19539575 181 ic="$(_h_char_2_dec "$ic")"
182 jc="$(_h_char_2_dec "$jc")"
00a50605 183 printf '\'"$(printf %o "$(_math $ic \* 16 + $jc)")"
4c3b3608 184 fi
00a50605 185 if [ "$uselet" ] ; then
f4312b44 186 let "i+=2" >/dev/null
187 let "j+=2" >/dev/null
00a50605 188 else
189 i="$(_math $i + 2)"
190 j="$(_math $j + 2)"
191 fi
4c3b3608 192 done
193}
194
c60883ef 195#options file
196_sed_i() {
197 options="$1"
198 filename="$2"
8663fb7e 199 if [ -z "$filename" ] ; then
c60883ef 200 _err "Usage:_sed_i options filename"
201 return 1
202 fi
14f3dbb7 203 _debug2 options "$options"
204 if sed -h 2>&1 | grep "\-i\[SUFFIX]" >/dev/null 2>&1; then
c60883ef 205 _debug "Using sed -i"
14f3dbb7 206 sed -i "$options" "$filename"
c60883ef 207 else
208 _debug "No -i support in sed"
19539575 209 text="$(cat "$filename")"
c60883ef 210 echo "$text" | sed "$options" > "$filename"
211 fi
212}
213
88fab7d6 214#Usage: file startline endline
215_getfile() {
216 filename="$1"
217 startline="$2"
218 endline="$3"
8663fb7e 219 if [ -z "$endline" ] ; then
88fab7d6 220 _err "Usage: file startline endline"
221 return 1
222 fi
223
19539575 224 i="$(grep -n -- "$startline" "$filename" | cut -d : -f 1)"
8663fb7e 225 if [ -z "$i" ] ; then
88fab7d6 226 _err "Can not find start line: $startline"
227 return 1
228 fi
19539575 229 i="$(_math "$i" + 1)"
230 _debug i "$i"
88fab7d6 231
19539575 232 j="$(grep -n -- "$endline" "$filename" | cut -d : -f 1)"
8663fb7e 233 if [ -z "$j" ] ; then
88fab7d6 234 _err "Can not find end line: $endline"
235 return 1
236 fi
19539575 237 j="$(_math "$j" - 1)"
238 _debug j "$j"
88fab7d6 239
19539575 240 sed -n "$i,${j}p" "$filename"
88fab7d6 241
242}
243
244#Usage: multiline
4c3b3608 245_base64() {
8663fb7e 246 if [ "$1" ] ; then
88fab7d6 247 openssl base64 -e
248 else
249 openssl base64 -e | tr -d '\r\n'
250 fi
251}
252
253#Usage: multiline
254_dbase64() {
8663fb7e 255 if [ "$1" ] ; then
88fab7d6 256 openssl base64 -d -A
257 else
258 openssl base64 -d
259 fi
260}
261
e22bcf7c 262#Usage: hashalg [outputhex]
88fab7d6 263#Output Base64-encoded digest
264_digest() {
265 alg="$1"
8663fb7e 266 if [ -z "$alg" ] ; then
88fab7d6 267 _err "Usage: _digest hashalg"
268 return 1
269 fi
270
e22bcf7c 271 outputhex="$2"
272
8663fb7e 273 if [ "$alg" = "sha256" ] ; then
e22bcf7c 274 if [ "$outputhex" ] ; then
275 echo $(openssl dgst -sha256 -hex | cut -d = -f 2)
276 else
277 openssl dgst -sha256 -binary | _base64
278 fi
88fab7d6 279 else
280 _err "$alg is not supported yet"
281 return 1
282 fi
283
284}
285
286#Usage: keyfile hashalg
287#Output: Base64-encoded signature value
288_sign() {
289 keyfile="$1"
290 alg="$2"
8663fb7e 291 if [ -z "$alg" ] ; then
88fab7d6 292 _err "Usage: _sign keyfile hashalg"
293 return 1
294 fi
295
8663fb7e 296 if [ "$alg" = "sha256" ] ; then
88fab7d6 297 openssl dgst -sha256 -sign "$keyfile" | _base64
298 else
299 _err "$alg is not supported yet"
300 return 1
301 fi
302
4c3b3608 303}
304
e22bcf7c 305# _createkey 2048|ec-256 file
306_createkey() {
307 length="$1"
308 f="$2"
309 isec=""
310 if _startswith "$length" "ec-" ; then
311 isec="1"
312 length=$(printf $length | cut -d '-' -f 2-100)
313 eccname="$length"
314 fi
315
316 if [ -z "$length" ] ; then
317 if [ "$isec" ] ; then
318 length=256
319 else
320 length=2048
321 fi
322 fi
323 _info "Use length $length"
324
325 if [ "$isec" ] ; then
326 if [ "$length" = "256" ] ; then
327 eccname="prime256v1"
328 fi
329 if [ "$length" = "384" ] ; then
330 eccname="secp384r1"
331 fi
332 if [ "$length" = "521" ] ; then
333 eccname="secp521r1"
334 fi
335 _info "Using ec name: $eccname"
336 fi
337
338 #generate account key
339 if [ "$isec" ] ; then
340 openssl ecparam -name $eccname -genkey 2>/dev/null > "$f"
341 else
342 openssl genrsa $length 2>/dev/null > "$f"
343 fi
344}
345
346#_createcsr cn san_list keyfile csrfile conf
347_createcsr() {
348 _debug _createcsr
349 domain="$1"
350 domainlist="$2"
351 key="$3"
352 csr="$4"
353 csrconf="$5"
354 _debug2 domain "$domain"
355 _debug2 domainlist "$domainlist"
356 if [ -z "$domainlist" ] || [ "$domainlist" = "no" ]; then
357 #single domain
358 _info "Single domain" "$domain"
359 printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n" > "$csrconf"
360 openssl req -new -sha256 -key "$key" -subj "/CN=$domain" -config "$csrconf" -out "$csr"
361 else
362 if _contains "$domainlist" "," ; then
363 alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")"
364 else
365 alt="DNS:$domainlist"
366 fi
367 #multi
368 _info "Multi domain" "$alt"
369 printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment\nsubjectAltName=$alt" > "$csrconf"
370 openssl req -new -sha256 -key "$key" -subj "/CN=$domain" -config "$csrconf" -out "$csr"
371 fi
372}
373
374#_signcsr key csr conf cert
375_signcsr() {
376 key="$1"
377 csr="$2"
378 conf="$3"
379 cert="$4"
5aa146a5 380 _debug "_signcsr"
e22bcf7c 381
5aa146a5 382 _msg="$(openssl x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)"
383 _ret="$?"
384 _debug "$_msg"
385 return $_ret
e22bcf7c 386}
387
34c27e09 388_ss() {
389 _port="$1"
edf08da6 390
391 if _exists "ss" ; then
392 _debug "Using: ss"
19539575 393 ss -ntpl | grep ":$_port "
edf08da6 394 return 0
395 fi
396
397 if _exists "netstat" ; then
251fc37c 398 _debug "Using: netstat"
ccb96535 399 if netstat -h 2>&1 | grep "\-p proto" >/dev/null ; then
400 #for windows version netstat tool
19539575 401 netstat -anb -p tcp | grep "LISTENING" | grep ":$_port "
ccb96535 402 else
14165e5a 403 if netstat -help 2>&1 | grep "\-p protocol" >/dev/null ; then
19539575 404 netstat -an -p tcp | grep LISTEN | grep ":$_port "
edf08da6 405 else
19539575 406 netstat -ntpl | grep ":$_port "
edf08da6 407 fi
ccb96535 408 fi
34c27e09 409 return 0
410 fi
edf08da6 411
34c27e09 412 return 1
413}
414
ac2d5123 415toPkcs() {
416 domain="$1"
417 pfxPassword="$2"
8663fb7e 418 if [ -z "$domain" ] ; then
a7b7355d 419 echo "Usage: $PROJECT_ENTRY --toPkcs -d domain [--password pfx-password]"
ac2d5123 420 return 1
421 fi
422
423 _initpath "$domain"
424
8663fb7e 425 if [ "$pfxPassword" ] ; then
ac2d5123 426 openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword"
427 else
428 openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH"
429 fi
430
8663fb7e 431 if [ "$?" = "0" ] ; then
ac2d5123 432 _info "Success, Pfx is exported to: $CERT_PFX_PATH"
433 fi
434
435}
436
4c3b3608 437#domain [2048]
438createAccountKey() {
439 _info "Creating account key"
8663fb7e 440 if [ -z "$1" ] ; then
a7b7355d 441 echo Usage: $PROJECT_ENTRY --createAccountKey -d domain.com [--accountkeylength 2048]
4c3b3608 442 return
443 fi
444
445 account=$1
446 length=$2
b5eb4b90 447 _debug account "$account"
448 _debug length "$length"
dceb3aca 449 if _startswith "$length" "ec-" ; then
4c3b3608 450 length=2048
451 fi
452
8663fb7e 453 if [ -z "$2" ] || [ "$2" = "no" ] ; then
4c3b3608 454 _info "Use default length 2048"
455 length=2048
456 fi
457 _initpath
458
8663fb7e 459 if [ -f "$ACCOUNT_KEY_PATH" ] ; then
4c3b3608 460 _info "Account key exists, skip"
461 return
462 else
463 #generate account key
e22bcf7c 464 _createkey $length "$ACCOUNT_KEY_PATH"
4c3b3608 465 fi
466
467}
468
469#domain length
470createDomainKey() {
471 _info "Creating domain key"
8663fb7e 472 if [ -z "$1" ] ; then
a7b7355d 473 echo Usage: $PROJECT_ENTRY --createDomainKey -d domain.com [ --keylength 2048 ]
4c3b3608 474 return
475 fi
476
477 domain=$1
4c3b3608 478 _initpath $domain
479
e22bcf7c 480 length=$2
481
8663fb7e 482 if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then
e22bcf7c 483 _createkey "$length" "$CERT_KEY_PATH"
4c3b3608 484 else
8663fb7e 485 if [ "$IS_RENEW" ] ; then
4c3b3608 486 _info "Domain key exists, skip"
487 return 0
488 else
489 _err "Domain key exists, do you want to overwrite the key?"
41e3eafa 490 _err "Add '--force', and try again."
4c3b3608 491 return 1
492 fi
493 fi
494
495}
496
497# domain domainlist
498createCSR() {
499 _info "Creating csr"
8663fb7e 500 if [ -z "$1" ] ; then
19539575 501 echo "Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ]"
4c3b3608 502 return
503 fi
504 domain=$1
19539575 505 _initpath "$domain"
4c3b3608 506
507 domainlist=$2
508
8663fb7e 509 if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && [ -z "$FORCE" ]; then
4c3b3608 510 _info "CSR exists, skip"
511 return
512 fi
513
e22bcf7c 514 _createcsr "$domain" "$domainlist" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"
515
4c3b3608 516}
517
166096dc 518_urlencode() {
4c3b3608 519 __n=$(cat)
520 echo $__n | tr '/+' '_-' | tr -d '= '
521}
522
523_time2str() {
524 #BSD
525 if date -u -d@$1 2>/dev/null ; then
526 return
527 fi
528
529 #Linux
530 if date -u -r $1 2>/dev/null ; then
531 return
532 fi
533
534}
535
eae29099 536_normalizeJson() {
537 sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n"
538}
539
44df2967 540_stat() {
541 #Linux
542 if stat -c '%U:%G' "$1" 2>/dev/null ; then
543 return
544 fi
545
546 #BSD
547 if stat -f '%Su:%Sg' "$1" 2>/dev/null ; then
548 return
549 fi
550}
551
166096dc 552#keyfile
553_calcjwk() {
554 keyfile="$1"
8663fb7e 555 if [ -z "$keyfile" ] ; then
166096dc 556 _err "Usage: _calcjwk keyfile"
557 return 1
558 fi
559 EC_SIGN=""
560 if grep "BEGIN RSA PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then
561 _debug "RSA key"
562 pub_exp=$(openssl rsa -in $keyfile -noout -text | grep "^publicExponent:"| cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
8663fb7e 563 if [ "${#pub_exp}" = "5" ] ; then
166096dc 564 pub_exp=0$pub_exp
565 fi
a63b05a9 566 _debug2 pub_exp "$pub_exp"
166096dc 567
568 e=$(echo $pub_exp | _h2b | _base64)
a63b05a9 569 _debug2 e "$e"
166096dc 570
571 modulus=$(openssl rsa -in $keyfile -modulus -noout | cut -d '=' -f 2 )
00a50605 572 _debug2 modulus "$modulus"
19539575 573 n="$(printf "%s" "$modulus"| _h2b | _base64 | _urlencode )"
166096dc 574 jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}'
a63b05a9 575 _debug2 jwk "$jwk"
166096dc 576
577 HEADER='{"alg": "RS256", "jwk": '$jwk'}'
578 HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}'
579 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then
580 _debug "EC key"
581 EC_SIGN="1"
582 crv="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")"
19539575 583 _debug2 crv "$crv"
166096dc 584
585 pubi="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)"
00a50605 586 pubi=$(_math $pubi + 1)
19539575 587 _debug2 pubi "$pubi"
166096dc 588
589 pubj="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)"
00a50605 590 pubj=$(_math $pubj + 1)
19539575 591 _debug2 pubj "$pubj"
166096dc 592
593 pubtext="$(openssl ec -in $keyfile -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")"
a63b05a9 594 _debug2 pubtext "$pubtext"
166096dc 595
596 xlen="$(printf "$pubtext" | tr -d ':' | wc -c)"
00a50605 597 xlen=$(_math $xlen / 4)
19539575 598 _debug2 xlen "$xlen"
00a50605 599
19539575 600 xend=$(_math "$xend" + 1)
166096dc 601 x="$(printf $pubtext | cut -d : -f 2-$xend)"
19539575 602 _debug2 x "$x"
166096dc 603
604 x64="$(printf $x | tr -d : | _h2b | _base64 | _urlencode)"
19539575 605 _debug2 x64 "$x64"
00a50605 606
19539575 607 xend=$(_math "$xend" + 1)
166096dc 608 y="$(printf $pubtext | cut -d : -f $xend-10000)"
19539575 609 _debug2 y "$y"
166096dc 610
611 y64="$(printf $y | tr -d : | _h2b | _base64 | _urlencode)"
19539575 612 _debug2 y64 "$y64"
166096dc 613
614 jwk='{"kty": "EC", "crv": "'$crv'", "x": "'$x64'", "y": "'$y64'"}'
a63b05a9 615 _debug2 jwk "$jwk"
166096dc 616
617 HEADER='{"alg": "ES256", "jwk": '$jwk'}'
618 HEADERPLACE='{"nonce": "NONCE", "alg": "ES256", "jwk": '$jwk'}'
619
620 else
621 _err "Only RSA or EC key is supported."
622 return 1
623 fi
624
a63b05a9 625 _debug2 HEADER "$HEADER"
166096dc 626}
c839b2b0 627# body url [needbase64] [POST|PUT]
c60883ef 628_post() {
629 body="$1"
630 url="$2"
631 needbase64="$3"
a4270efa 632 httpmethod="$4"
c60883ef 633
a4270efa 634 if [ -z "$httpmethod" ] ; then
635 httpmethod="POST"
636 fi
637 _debug $httpmethod
484d9d2a 638 _debug "url" "$url"
c60883ef 639 if _exists "curl" ; then
8f48168c 640 _CURL="$CURL --dump-header $HTTP_HEADER "
ec9fc8cb 641 _debug "_CURL" "$_CURL"
8663fb7e 642 if [ "$needbase64" ] ; then
63a195e5 643 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" | _base64)"
c60883ef 644 else
63a195e5 645 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" )"
c60883ef 646 fi
16679b57 647 _ret="$?"
687cfcc2 648 if [ "$_ret" != "0" ] ; then
87ab2d90 649 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
650 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
651 _err "Here is the curl dump log:"
652 _err "$(cat "$_CURL_DUMP")"
653 fi
687cfcc2 654 fi
d0b748a4 655 elif _exists "wget" ; then
ec9fc8cb 656 _debug "WGET" "$WGET"
8663fb7e 657 if [ "$needbase64" ] ; then
8fb9a709 658 if [ "$httpmethod"="POST" ] ; then
659 response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)"
660 else
661 response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)"
662 fi
c60883ef 663 else
8fb9a709 664 if [ "$httpmethod"="POST" ] ; then
665 response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")"
666 else
667 response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")"
668 fi
c60883ef 669 fi
16679b57 670 _ret="$?"
687cfcc2 671 if [ "$_ret" != "0" ] ; then
672 _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
673 fi
c60883ef 674 _sed_i "s/^ *//g" "$HTTP_HEADER"
d0b748a4 675 else
676 _ret="$?"
677 _err "Neither curl nor wget is found, can not do $httpmethod."
c60883ef 678 fi
16679b57 679 _debug "_ret" "$_ret"
19539575 680 printf "%s" "$response"
16679b57 681 return $_ret
c60883ef 682}
683
684# url getheader
685_get() {
a4270efa 686 _debug GET
c60883ef 687 url="$1"
688 onlyheader="$2"
689 _debug url $url
690 if _exists "curl" ; then
ec9fc8cb 691 _debug "CURL" "$CURL"
8663fb7e 692 if [ "$onlyheader" ] ; then
63a195e5 693 $CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url
c60883ef 694 else
63a195e5 695 $CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url
c60883ef 696 fi
9aaf36cd 697 ret=$?
d0b748a4 698 elif _exists "wget" ; then
bbbdcb09 699 _debug "WGET" "$WGET"
8663fb7e 700 if [ "$onlyheader" ] ; then
a4270efa 701 $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g'
c60883ef 702 else
cc7fdbd6 703 $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url
c60883ef 704 fi
9aaf36cd 705 ret=$?
d0b748a4 706 else
707 ret=$?
708 _err "Neither curl nor wget is found, can not do GET."
9aaf36cd 709 fi
ec9fc8cb 710 _debug "ret" "$ret"
c60883ef 711 return $ret
712}
166096dc 713
714# url payload needbase64 keyfile
4c3b3608 715_send_signed_request() {
716 url=$1
717 payload=$2
718 needbase64=$3
166096dc 719 keyfile=$4
8663fb7e 720 if [ -z "$keyfile" ] ; then
166096dc 721 keyfile="$ACCOUNT_KEY_PATH"
722 fi
4c3b3608 723 _debug url $url
724 _debug payload "$payload"
725
166096dc 726 if ! _calcjwk "$keyfile" ; then
727 return 1
728 fi
c60883ef 729
166096dc 730 payload64=$(echo -n $payload | _base64 | _urlencode)
a63b05a9 731 _debug2 payload64 $payload64
4c3b3608 732
733 nonceurl="$API/directory"
a272ee4f 734 _headers="$(_get $nonceurl "onlyheader")"
735
7012b91f 736 if [ "$?" != "0" ] ; then
737 _err "Can not connect to $nonceurl to get nonce."
738 return 1
739 fi
a272ee4f 740
741 _debug2 _headers "$_headers"
742
743 nonce="$( echo "$_headers" | grep "Replay-Nonce:" | head -1 | tr -d "\r\n " | cut -d ':' -f 2)"
744
4c3b3608 745 _debug nonce "$nonce"
746
747 protected="$(printf "$HEADERPLACE" | sed "s/NONCE/$nonce/" )"
a63b05a9 748 _debug2 protected "$protected"
4c3b3608 749
166096dc 750 protected64="$(printf "$protected" | _base64 | _urlencode)"
a63b05a9 751 _debug2 protected64 "$protected64"
166096dc 752
88fab7d6 753 sig=$(echo -n "$protected64.$payload64" | _sign "$keyfile" "sha256" | _urlencode)
a63b05a9 754 _debug2 sig "$sig"
4c3b3608 755
756 body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
a63b05a9 757 _debug2 body "$body"
4c3b3608 758
bbbdcb09 759
eae29099 760 response="$(_post "$body" $url "$needbase64")"
7012b91f 761 if [ "$?" != "0" ] ; then
762 _err "Can not post to $url."
763 return 1
764 fi
eae29099 765 _debug2 original "$response"
766
767 response="$( echo "$response" | _normalizeJson )"
4c3b3608 768
c60883ef 769 responseHeaders="$(cat $HTTP_HEADER)"
4c3b3608 770
a63b05a9 771 _debug2 responseHeaders "$responseHeaders"
772 _debug2 response "$response"
c60883ef 773 code="$(grep "^HTTP" $HTTP_HEADER | tail -1 | cut -d " " -f 2 | tr -d "\r\n" )"
4c3b3608 774 _debug code $code
775
776}
777
4c3b3608 778
779#setopt "file" "opt" "=" "value" [";"]
780_setopt() {
781 __conf="$1"
782 __opt="$2"
783 __sep="$3"
784 __val="$4"
785 __end="$5"
8663fb7e 786 if [ -z "$__opt" ] ; then
4c3b3608 787 echo usage: _setopt '"file" "opt" "=" "value" [";"]'
788 return
789 fi
8663fb7e 790 if [ ! -f "$__conf" ] ; then
4c3b3608 791 touch "$__conf"
792 fi
793
794 if grep -H -n "^$__opt$__sep" "$__conf" > /dev/null ; then
a63b05a9 795 _debug2 OK
dceb3aca 796 if _contains "$__val" "&" ; then
4c3b3608 797 __val="$(echo $__val | sed 's/&/\\&/g')"
798 fi
799 text="$(cat $__conf)"
6dfaaa70 800 echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf"
4c3b3608 801
802 elif grep -H -n "^#$__opt$__sep" "$__conf" > /dev/null ; then
dceb3aca 803 if _contains "$__val" "&" ; then
4c3b3608 804 __val="$(echo $__val | sed 's/&/\\&/g')"
805 fi
806 text="$(cat $__conf)"
6dfaaa70 807 echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf"
4c3b3608 808
809 else
a63b05a9 810 _debug2 APP
4c3b3608 811 echo "$__opt$__sep$__val$__end" >> "$__conf"
812 fi
813 _debug "$(grep -H -n "^$__opt$__sep" $__conf)"
814}
815
816#_savedomainconf key value
817#save to domain.conf
818_savedomainconf() {
819 key="$1"
820 value="$2"
8663fb7e 821 if [ "$DOMAIN_CONF" ] ; then
4d2f38b0 822 _setopt "$DOMAIN_CONF" "$key" "=" "\"$value\""
823 else
824 _err "DOMAIN_CONF is empty, can not save $key=$value"
825 fi
826}
827
828#_cleardomainconf key
829_cleardomainconf() {
830 key="$1"
831 if [ "$DOMAIN_CONF" ] ; then
832 _sed_i "s/^$key.*$//" "$DOMAIN_CONF"
4c3b3608 833 else
834 _err "DOMAIN_CONF is empty, can not save $key=$value"
835 fi
836}
837
61623d22 838#_readdomainconf key
839_readdomainconf() {
840 key="$1"
841 if [ "$DOMAIN_CONF" ] ; then
842 (
843 eval $(grep "^$key *=" "$DOMAIN_CONF")
844 eval "printf \"%s\" \"\$$key\""
845 )
846 else
847 _err "DOMAIN_CONF is empty, can not read $key"
848 fi
849}
850
4c3b3608 851#_saveaccountconf key value
852_saveaccountconf() {
853 key="$1"
854 value="$2"
8663fb7e 855 if [ "$ACCOUNT_CONF_PATH" ] ; then
4d2f38b0 856 _setopt "$ACCOUNT_CONF_PATH" "$key" "=" "\"$value\""
4c3b3608 857 else
858 _err "ACCOUNT_CONF_PATH is empty, can not save $key=$value"
859 fi
860}
861
862_startserver() {
863 content="$1"
6fc1447f 864 _debug "startserver: $$"
1b2e940d 865 nchelp="$(nc -h 2>&1)"
850c1128 866
399306a1 867 if echo "$nchelp" | grep "\-q[ ,]" >/dev/null ; then
850c1128 868 _NC="nc -q 1 -l"
869 else
f76eb452 870 if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null ; then
871 _NC="nc -c -l"
6d60f288 872 elif echo "$nchelp" | grep "\-N" |grep "Shutdown the network socket after EOF on stdin" >/dev/null ; then
873 _NC="nc -N -l"
f76eb452 874 else
875 _NC="nc -l"
876 fi
4c3b3608 877 fi
1b2e940d 878
f76eb452 879 _debug "_NC" "$_NC"
39c8f79f 880 _debug Le_HTTPPort "$Le_HTTPPort"
4c3b3608 881# while true ; do
8663fb7e 882 if [ "$DEBUG" ] ; then
2c554a4b 883 if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then
884 printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ;
3aff11f6 885 fi
4c3b3608 886 else
2c554a4b 887 if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then
888 printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1
3aff11f6 889 fi
4c3b3608 890 fi
8663fb7e 891 if [ "$?" != "0" ] ; then
051c706d 892 _err "nc listen error."
6fc1447f 893 exit 1
051c706d 894 fi
4c3b3608 895# done
896}
897
6fc1447f 898_stopserver(){
4c3b3608 899 pid="$1"
6fc1447f 900 _debug "pid" "$pid"
8663fb7e 901 if [ -z "$pid" ] ; then
6fc1447f 902 return
903 fi
e22bcf7c 904
3d434e43 905 _get "http://localhost:$Le_HTTPPort" >/dev/null 2>&1
5aa146a5 906 _get "https://localhost:$Le_TLSPort" >/dev/null 2>&1
4c3b3608 907
908}
909
e22bcf7c 910
911# _starttlsserver san_a san_b port content
912_starttlsserver() {
913 _info "Starting tls server."
914 san_a="$1"
915 san_b="$2"
916 port="$3"
917 content="$4"
918
919 _debug san_a "$san_a"
920 _debug san_b "$san_b"
921 _debug port "$port"
922
923 #create key TLS_KEY
924 if ! _createkey "2048" "$TLS_KEY" ; then
925 _err "Create tls validation key error."
926 return 1
927 fi
928
929 #create csr
930 alt="$san_a"
931 if [ "$san_b" ] ; then
932 alt="$alt,$san_b"
933 fi
934 if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" ; then
935 _err "Create tls validation csr error."
936 return 1
937 fi
938
939 #self signed
940 if ! _signcsr "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$TLS_CERT" ; then
941 _err "Create tls validation cert error."
942 return 1
943 fi
944
945 #start openssl
fbad6a39 946 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
5aa146a5 947 (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -naccept 1 -tlsextdebug ) &
331c4bb6 948 else
5aa146a5 949 (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -naccept 1 >/dev/null 2>&1) &
331c4bb6 950 fi
951
e22bcf7c 952 serverproc="$!"
953 sleep 2
954 _debug serverproc $serverproc
955}
956
4c3b3608 957_initpath() {
958
8663fb7e 959 if [ -z "$LE_WORKING_DIR" ] ; then
6cc11ffb 960 LE_WORKING_DIR=$HOME/.$PROJECT_NAME
4c3b3608 961 fi
962
d53289d7 963 _DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf"
964
8663fb7e 965 if [ -z "$ACCOUNT_CONF_PATH" ] ; then
966 if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ] ; then
967 . "$_DEFAULT_ACCOUNT_CONF_PATH"
635695ec 968 fi
d53289d7 969 fi
970
8663fb7e 971 if [ -z "$ACCOUNT_CONF_PATH" ] ; then
d53289d7 972 ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH"
4c3b3608 973 fi
974
8663fb7e 975 if [ -f "$ACCOUNT_CONF_PATH" ] ; then
976 . "$ACCOUNT_CONF_PATH"
4c3b3608 977 fi
978
8663fb7e 979 if [ "$IN_CRON" ] ; then
980 if [ ! "$_USER_PATH_EXPORTED" ] ; then
281aa349 981 _USER_PATH_EXPORTED=1
982 export PATH="$USER_PATH:$PATH"
983 fi
984 fi
985
8663fb7e 986 if [ -z "$API" ] ; then
987 if [ -z "$STAGE" ] ; then
4c3b3608 988 API="$DEFAULT_CA"
989 else
990 API="$STAGE_CA"
991 _info "Using stage api:$API"
992 fi
993 fi
994
8663fb7e 995 if [ -z "$ACME_DIR" ] ; then
4c3b3608 996 ACME_DIR="/home/.acme"
997 fi
998
8663fb7e 999 if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then
8a144f4d 1000 APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR"
4c3b3608 1001 fi
1002
8663fb7e 1003 if [ -z "$USER_AGENT" ] ; then
bbbdcb09 1004 USER_AGENT="$DEFAULT_USER_AGENT"
1005 fi
1006
1007 HTTP_HEADER="$LE_WORKING_DIR/http.header"
1008
1009 WGET="wget -q"
8663fb7e 1010 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
bbbdcb09 1011 WGET="$WGET -d "
1012 fi
1013
87ab2d90 1014 _CURL_DUMP="$LE_WORKING_DIR/curl.dump"
4a0f23e2 1015 CURL="curl -L --silent"
8663fb7e 1016 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
87ab2d90 1017 CURL="$CURL --trace-ascii $_CURL_DUMP "
bbbdcb09 1018 fi
13d7cae9 1019
1020 if [ "$Le_Insecure" ] ; then
1021 WGET="$WGET --no-check-certificate "
1022 CURL="$CURL --insecure "
1023 fi
b2817897 1024
1025 _DEFAULT_ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key"
8663fb7e 1026 if [ -z "$ACCOUNT_KEY_PATH" ] ; then
b2817897 1027 ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH"
4c3b3608 1028 fi
b2817897 1029
a79b26af
RD
1030 _DEFAULT_CERT_HOME="$LE_WORKING_DIR"
1031 if [ -z "$CERT_HOME" ] ; then
1032 CERT_HOME="$_DEFAULT_CERT_HOME"
1033 fi
1034
b2817897 1035 domain="$1"
4c3b3608 1036
8663fb7e 1037 if [ -z "$domain" ] ; then
4c3b3608 1038 return 0
1039 fi
1040
b2817897 1041 domainhome="$CERT_HOME/$domain"
4c3b3608 1042 mkdir -p "$domainhome"
1043
8663fb7e 1044 if [ -z "$DOMAIN_PATH" ] ; then
4c3b3608 1045 DOMAIN_PATH="$domainhome"
1046 fi
8663fb7e 1047 if [ -z "$DOMAIN_CONF" ] ; then
1ad65f7d 1048 DOMAIN_CONF="$domainhome/$domain.conf"
4c3b3608 1049 fi
1050
8663fb7e 1051 if [ -z "$DOMAIN_SSL_CONF" ] ; then
1ad65f7d 1052 DOMAIN_SSL_CONF="$domainhome/$domain.ssl.conf"
4c3b3608 1053 fi
1054
8663fb7e 1055 if [ -z "$CSR_PATH" ] ; then
4c3b3608 1056 CSR_PATH="$domainhome/$domain.csr"
1057 fi
8663fb7e 1058 if [ -z "$CERT_KEY_PATH" ] ; then
4c3b3608 1059 CERT_KEY_PATH="$domainhome/$domain.key"
1060 fi
8663fb7e 1061 if [ -z "$CERT_PATH" ] ; then
4c3b3608 1062 CERT_PATH="$domainhome/$domain.cer"
1063 fi
8663fb7e 1064 if [ -z "$CA_CERT_PATH" ] ; then
4c3b3608 1065 CA_CERT_PATH="$domainhome/ca.cer"
1066 fi
8663fb7e 1067 if [ -z "$CERT_FULLCHAIN_PATH" ] ; then
850db6d4 1068 CERT_FULLCHAIN_PATH="$domainhome/fullchain.cer"
caf1fc10 1069 fi
8663fb7e 1070 if [ -z "$CERT_PFX_PATH" ] ; then
ac2d5123 1071 CERT_PFX_PATH="$domainhome/$domain.pfx"
1072 fi
e22bcf7c 1073
1074 if [ -z "$TLS_CONF" ] ; then
1075 TLS_CONF="$domainhome/tls.valdation.conf"
1076 fi
1077 if [ -z "$TLS_CERT" ] ; then
1078 TLS_CERT="$domainhome/tls.valdation.cert"
1079 fi
1080 if [ -z "$TLS_KEY" ] ; then
1081 TLS_KEY="$domainhome/tls.valdation.key"
1082 fi
1083 if [ -z "$TLS_CSR" ] ; then
1084 TLS_CSR="$domainhome/tls.valdation.csr"
1085 fi
1086
4c3b3608 1087}
1088
1089
1090_apachePath() {
e4a19585 1091 _APAHECTL="apachectl"
80a0a7b5 1092 if ! _exists apachectl ; then
e4a19585 1093 if _exists apache2ctl ; then
1094 _APAHECTL="apache2ctl"
1095 else
bc96082f 1096 _err "'apachectl not found. It seems that apache is not installed, or you are not root user.'"
e4a19585 1097 _err "Please use webroot mode to try again."
1098 return 1
1099 fi
80a0a7b5 1100 fi
e4a19585 1101 httpdconfname="$($_APAHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )"
78768e98 1102 _debug httpdconfname "$httpdconfname"
dceb3aca 1103 if _startswith "$httpdconfname" '/' ; then
d62ee940 1104 httpdconf="$httpdconfname"
c456d954 1105 httpdconfname="$(basename $httpdconfname)"
d62ee940 1106 else
e4a19585 1107 httpdroot="$($_APAHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )"
78768e98 1108 _debug httpdroot "$httpdroot"
d62ee940 1109 httpdconf="$httpdroot/$httpdconfname"
8f63baf7 1110 httpdconfname="$(basename $httpdconfname)"
d62ee940 1111 fi
78768e98 1112 _debug httpdconf "$httpdconf"
8f63baf7 1113 _debug httpdconfname "$httpdconfname"
78768e98 1114 if [ ! -f "$httpdconf" ] ; then
1115 _err "Apache Config file not found" "$httpdconf"
4c3b3608 1116 return 1
1117 fi
1118 return 0
1119}
1120
1121_restoreApache() {
8663fb7e 1122 if [ -z "$usingApache" ] ; then
4c3b3608 1123 return 0
1124 fi
1125 _initpath
1126 if ! _apachePath ; then
1127 return 1
1128 fi
1129
8663fb7e 1130 if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ] ; then
4c3b3608 1131 _debug "No config file to restore."
1132 return 0
1133 fi
1134
ff3bce32 1135 cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" > "$httpdconf"
5ef501c5 1136 _debug "Restored: $httpdconf."
e4a19585 1137 if ! $_APAHECTL -t >/dev/null 2>&1 ; then
4c3b3608 1138 _err "Sorry, restore apache config error, please contact me."
1139 return 1;
1140 fi
5ef501c5 1141 _debug "Restored successfully."
4c3b3608 1142 rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname"
1143 return 0
1144}
1145
1146_setApache() {
1147 _initpath
1148 if ! _apachePath ; then
1149 return 1
1150 fi
1151
5fc5016d 1152 #test the conf first
869578ce 1153 _info "Checking if there is an error in the apache config file before starting."
e4a19585 1154 _msg="$($_APAHECTL -t 2>&1 )"
5fc5016d 1155 if [ "$?" != "0" ] ; then
869578ce 1156 _err "Sorry, apache config file has error, please fix it first, then try again."
1157 _err "Don't worry, there is nothing changed to your system."
5fc5016d 1158 _err "$_msg"
1159 return 1;
1160 else
1161 _info "OK"
1162 fi
1163
4c3b3608 1164 #backup the conf
5778811a 1165 _debug "Backup apache config file" "$httpdconf"
8f63baf7 1166 if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/" ; then
869578ce 1167 _err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed."
8f63baf7 1168 _err "This might be a bug of $PROJECT_NAME , pleae report issue: $PROJECT"
1169 return 1
1170 fi
4c3b3608 1171 _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname"
1172 _info "In case there is an error that can not be restored automatically, you may try restore it yourself."
1173 _info "The backup file will be deleted on sucess, just forget it."
1174
1175 #add alias
b09d597c 1176
e4a19585 1177 apacheVer="$($_APAHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2 )"
b09d597c 1178 _debug "apacheVer" "$apacheVer"
1179 apacheMajer="$(echo "$apacheVer" | cut -d . -f 1)"
1180 apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)"
1181
5778811a 1182 if [ "$apacheVer" ] && [ "$apacheMajer$apacheMinor" -ge "24" ] ; then
b09d597c 1183 echo "
4c3b3608 1184Alias /.well-known/acme-challenge $ACME_DIR
1185
1186<Directory $ACME_DIR >
1187Require all granted
b09d597c 1188</Directory>
5778811a 1189 " >> "$httpdconf"
b09d597c 1190 else
1191 echo "
1192Alias /.well-known/acme-challenge $ACME_DIR
1193
1194<Directory $ACME_DIR >
1195Order allow,deny
1196Allow from all
4c3b3608 1197</Directory>
5778811a 1198 " >> "$httpdconf"
b09d597c 1199 fi
1200
e4a19585 1201 _msg="$($_APAHECTL -t 2>&1 )"
5fc5016d 1202 if [ "$?" != "0" ] ; then
1203 _err "Sorry, apache config error"
1204 if _restoreApache ; then
869578ce 1205 _err "The apache config file is restored."
5fc5016d 1206 else
869578ce 1207 _err "Sorry, The apache config file can not be restored, please report bug."
5fc5016d 1208 fi
4c3b3608 1209 return 1;
1210 fi
1211
8663fb7e 1212 if [ ! -d "$ACME_DIR" ] ; then
4c3b3608 1213 mkdir -p "$ACME_DIR"
1214 chmod 755 "$ACME_DIR"
1215 fi
1216
e4a19585 1217 if ! $_APAHECTL graceful ; then
1218 _err "Sorry, $_APAHECTL graceful error, please contact me."
4c3b3608 1219 _restoreApache
1220 return 1;
1221 fi
1222 usingApache="1"
1223 return 0
1224}
1225
5ef501c5 1226_clearup() {
4c3b3608 1227 _stopserver $serverproc
1228 serverproc=""
1229 _restoreApache
e22bcf7c 1230 if [ -z "$DEBUG" ] ; then
1231 rm -f "$TLS_CONF"
1232 rm -f "$TLS_CERT"
1233 rm -f "$TLS_KEY"
1234 rm -f "$TLS_CSR"
1235 fi
4c3b3608 1236}
1237
1238# webroot removelevel tokenfile
1239_clearupwebbroot() {
1240 __webroot="$1"
8663fb7e 1241 if [ -z "$__webroot" ] ; then
4c3b3608 1242 _debug "no webroot specified, skip"
1243 return 0
1244 fi
1245
8663fb7e 1246 if [ "$2" = '1' ] ; then
4c3b3608 1247 _debug "remove $__webroot/.well-known"
1248 rm -rf "$__webroot/.well-known"
8663fb7e 1249 elif [ "$2" = '2' ] ; then
4c3b3608 1250 _debug "remove $__webroot/.well-known/acme-challenge"
1251 rm -rf "$__webroot/.well-known/acme-challenge"
8663fb7e 1252 elif [ "$2" = '3' ] ; then
4c3b3608 1253 _debug "remove $__webroot/.well-known/acme-challenge/$3"
1254 rm -rf "$__webroot/.well-known/acme-challenge/$3"
1255 else
cc179731 1256 _debug "Skip for removelevel:$2"
4c3b3608 1257 fi
1258
1259 return 0
1260
1261}
1262
1263issue() {
8663fb7e 1264 if [ -z "$2" ] ; then
a7b7355d 1265 echo "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ "
4c3b3608 1266 return 1
1267 fi
1268 Le_Webroot="$1"
1269 Le_Domain="$2"
1270 Le_Alt="$3"
1271 Le_Keylength="$4"
1272 Le_RealCertPath="$5"
1273 Le_RealKeyPath="$6"
1274 Le_RealCACertPath="$7"
1275 Le_ReloadCmd="$8"
a63b05a9 1276 Le_RealFullChainPath="$9"
4c3b3608 1277
eccec5f6 1278 #remove these later.
8663fb7e 1279 if [ "$Le_Webroot" = "dns-cf" ] ; then
eccec5f6 1280 Le_Webroot="dns_cf"
1281 fi
8663fb7e 1282 if [ "$Le_Webroot" = "dns-dp" ] ; then
eccec5f6 1283 Le_Webroot="dns_dp"
1284 fi
8663fb7e 1285 if [ "$Le_Webroot" = "dns-cx" ] ; then
eccec5f6 1286 Le_Webroot="dns_cx"
1287 fi
4c3b3608 1288
eccec5f6 1289 _initpath $Le_Domain
1290
8663fb7e 1291 if [ -f "$DOMAIN_CONF" ] ; then
61623d22 1292 Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime)
a4270efa 1293 _debug Le_NextRenewTime "$Le_NextRenewTime"
1294 if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ $(date -u "+%s" ) -lt $Le_NextRenewTime ] ; then
4c3b3608 1295 _info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)"
cc179731 1296 return $RENEW_SKIP
4c3b3608 1297 fi
1298 fi
96a46cfc 1299
4d2f38b0 1300 _savedomainconf "Le_Domain" "$Le_Domain"
1301 _savedomainconf "Le_Alt" "$Le_Alt"
1302 _savedomainconf "Le_Webroot" "$Le_Webroot"
4c3b3608 1303
61623d22 1304
8663fb7e 1305 if [ "$Le_Alt" = "no" ] ; then
4c3b3608 1306 Le_Alt=""
1307 fi
61623d22 1308
c53da1ef 1309 if _hasfield "$Le_Webroot" "no" ; then
4c3b3608 1310 _info "Standalone mode."
5ef501c5 1311 if ! _exists "nc" ; then
4c3b3608 1312 _err "Please install netcat(nc) tools first."
1313 return 1
1314 fi
1315
8663fb7e 1316 if [ -z "$Le_HTTPPort" ] ; then
4c3b3608 1317 Le_HTTPPort=80
054cb72e 1318 else
1319 _savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
1320 fi
4c3b3608 1321
251fc37c 1322 netprc="$(_ss "$Le_HTTPPort" | grep "$Le_HTTPPort")"
8663fb7e 1323 if [ "$netprc" ] ; then
4c3b3608 1324 _err "$netprc"
1325 _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)"
1326 _err "Please stop it first"
1327 return 1
1328 fi
1329 fi
1330
e22bcf7c 1331 if _hasfield "$Le_Webroot" "$W_TLS" ; then
1332 _info "Standalone tls mode."
1333
1334 if [ -z "$Le_TLSPort" ] ; then
1335 Le_TLSPort=443
1336 else
1337 _savedomainconf "Le_TLSPort" "$Le_TLSPort"
1338 fi
1339
1340 netprc="$(_ss "$Le_TLSPort" | grep "$Le_TLSPort")"
1341 if [ "$netprc" ] ; then
1342 _err "$netprc"
1343 _err "tcp port $Le_TLSPort is already used by $(echo "$netprc" | cut -d : -f 4)"
1344 _err "Please stop it first"
1345 return 1
1346 fi
1347 fi
1348
c53da1ef 1349 if _hasfield "$Le_Webroot" "apache" ; then
4c3b3608 1350 if ! _setApache ; then
1351 _err "set up apache error. Report error to me."
1352 return 1
1353 fi
4c3b3608 1354 else
1355 usingApache=""
1356 fi
1357
8663fb7e 1358 if [ ! -f "$ACCOUNT_KEY_PATH" ] ; then
41e3eafa 1359 if ! createAccountKey $Le_Domain $Le_Keylength ; then
1360 _err "Create account key error."
8663fb7e 1361 if [ "$usingApache" ] ; then
5ef501c5 1362 _restoreApache
1363 fi
41e3eafa 1364 return 1
1365 fi
1366 fi
1367
166096dc 1368 if ! _calcjwk "$ACCOUNT_KEY_PATH" ; then
8663fb7e 1369 if [ "$usingApache" ] ; then
5ef501c5 1370 _restoreApache
1371 fi
166096dc 1372 return 1
1373 fi
1374
1375 accountkey_json=$(echo -n "$jwk" | tr -d ' ' )
88fab7d6 1376 thumbprint=$(echo -n "$accountkey_json" | _digest "sha256" | _urlencode)
4c3b3608 1377
88fab7d6 1378 accountkeyhash="$(cat "$ACCOUNT_KEY_PATH" | _digest "sha256" )"
a63b05a9 1379 accountkeyhash="$(echo $accountkeyhash$API | _digest "sha256" )"
8663fb7e 1380 if [ "$accountkeyhash" != "$ACCOUNT_KEY_HASH" ] ; then
166096dc 1381 _info "Registering account"
1382 regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}'
8663fb7e 1383 if [ "$ACCOUNT_EMAIL" ] ; then
166096dc 1384 regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}'
1385 fi
1386 _send_signed_request "$API/acme/new-reg" "$regjson"
1387
8663fb7e 1388 if [ "$code" = "" ] || [ "$code" = '201' ] ; then
166096dc 1389 _info "Registered"
1390 echo $response > $LE_WORKING_DIR/account.json
8663fb7e 1391 elif [ "$code" = '409' ] ; then
166096dc 1392 _info "Already registered"
1393 else
1394 _err "Register account Error: $response"
1395 _clearup
1396 return 1
1397 fi
1398 ACCOUNT_KEY_HASH="$accountkeyhash"
1399 _saveaccountconf "ACCOUNT_KEY_HASH" "$ACCOUNT_KEY_HASH"
1400 else
1401 _info "Skip register account key"
1402 fi
1403
58f41a19 1404 if [ "$Le_Keylength" = "no" ] ; then
1405 Le_Keylength=""
1406 fi
1407
61623d22 1408 _key=$(_readdomainconf Le_Keylength)
1409 _debug "Read key length:$_key"
d8d10bc4 1410 if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ] ; then
41e3eafa 1411 if ! createDomainKey $Le_Domain $Le_Keylength ; then
1412 _err "Create domain key error."
5ef501c5 1413 _clearup
41e3eafa 1414 return 1
1415 fi
4c3b3608 1416 fi
1417
61623d22 1418 _savedomainconf "Le_Keylength" "$Le_Keylength"
58f41a19 1419
61623d22 1420
4c3b3608 1421 if ! createCSR $Le_Domain $Le_Alt ; then
1422 _err "Create CSR error."
5ef501c5 1423 _clearup
4c3b3608 1424 return 1
1425 fi
a63b05a9 1426
4c3b3608 1427 vlist="$Le_Vlist"
1428 # verify each domain
1429 _info "Verify each domain"
1430 sep='#'
8663fb7e 1431 if [ -z "$vlist" ] ; then
4c3b3608 1432 alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' )
a63b05a9 1433 _index=1
1434 _currentRoot=""
4c3b3608 1435 for d in $alldomains
a63b05a9 1436 do
1437 _info "Getting webroot for domain" $d
1438 _w="$(echo $Le_Webroot | cut -d , -f $_index)"
1439 _debug _w "$_w"
8663fb7e 1440 if [ "$_w" ] ; then
a63b05a9 1441 _currentRoot="$_w"
1442 fi
1443 _debug "_currentRoot" "$_currentRoot"
00a50605 1444 _index=$(_math $_index + 1)
a63b05a9 1445
1446 vtype="$VTYPE_HTTP"
dceb3aca 1447 if _startswith "$_currentRoot" "dns" ; then
a63b05a9 1448 vtype="$VTYPE_DNS"
1449 fi
e22bcf7c 1450
1451 if [ "$_currentRoot" = "$W_TLS" ] ; then
1452 vtype="$VTYPE_TLS"
1453 fi
1454
4c3b3608 1455 _info "Getting token for domain" $d
c4d8fd83 1456
1457 if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" ; then
1458 _err "Can not get domain token."
1459 _clearup
1460 return 1
1461 fi
1462
8663fb7e 1463 if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then
4c3b3608 1464 _err "new-authz error: $response"
1465 _clearup
1466 return 1
1467 fi
1468
230234e7 1469 entry="$(printf "$response" | egrep -o '\{[^{]*"type":"'$vtype'"[^}]*')"
4c3b3608 1470 _debug entry "$entry"
19539575 1471 if [ -z "$entry" ] ; then
1472 _err "Error, can not get domain token $d"
1473 _clearup
1474 return 1
1475 fi
4c3b3608 1476 token="$(printf "$entry" | egrep -o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
1477 _debug token $token
1478
1479 uri="$(printf "$entry" | egrep -o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )"
1480 _debug uri $uri
1481
1482 keyauthorization="$token.$thumbprint"
1483 _debug keyauthorization "$keyauthorization"
1484
a63b05a9 1485 dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot"
4c3b3608 1486 _debug dvlist "$dvlist"
1487
1488 vlist="$vlist$dvlist,"
1489
1490 done
1491
1492 #add entry
1493 dnsadded=""
1494 ventries=$(echo "$vlist" | tr ',' ' ' )
1495 for ventry in $ventries
1496 do
1497 d=$(echo $ventry | cut -d $sep -f 1)
1498 keyauthorization=$(echo $ventry | cut -d $sep -f 2)
a63b05a9 1499 vtype=$(echo $ventry | cut -d $sep -f 4)
1500 _currentRoot=$(echo $ventry | cut -d $sep -f 5)
8663fb7e 1501 if [ "$vtype" = "$VTYPE_DNS" ] ; then
4c3b3608 1502 dnsadded='0'
1503 txtdomain="_acme-challenge.$d"
1504 _debug txtdomain "$txtdomain"
c1c7d87b 1505 txt="$(echo -n $keyauthorization | _digest "sha256" | _urlencode)"
4c3b3608 1506 _debug txt "$txt"
1507 #dns
1508 #1. check use api
1509 d_api=""
8663fb7e 1510 if [ -f "$LE_WORKING_DIR/$d/$_currentRoot" ] ; then
a63b05a9 1511 d_api="$LE_WORKING_DIR/$d/$_currentRoot"
8663fb7e 1512 elif [ -f "$LE_WORKING_DIR/$d/$_currentRoot.sh" ] ; then
a63b05a9 1513 d_api="$LE_WORKING_DIR/$d/$_currentRoot.sh"
8663fb7e 1514 elif [ -f "$LE_WORKING_DIR/$_currentRoot" ] ; then
a63b05a9 1515 d_api="$LE_WORKING_DIR/$_currentRoot"
8663fb7e 1516 elif [ -f "$LE_WORKING_DIR/$_currentRoot.sh" ] ; then
a63b05a9 1517 d_api="$LE_WORKING_DIR/$_currentRoot.sh"
8663fb7e 1518 elif [ -f "$LE_WORKING_DIR/dnsapi/$_currentRoot" ] ; then
a63b05a9 1519 d_api="$LE_WORKING_DIR/dnsapi/$_currentRoot"
8663fb7e 1520 elif [ -f "$LE_WORKING_DIR/dnsapi/$_currentRoot.sh" ] ; then
a63b05a9 1521 d_api="$LE_WORKING_DIR/dnsapi/$_currentRoot.sh"
4c3b3608 1522 fi
1523 _debug d_api "$d_api"
1524
8663fb7e 1525 if [ "$d_api" ] ; then
4c3b3608 1526 _info "Found domain api file: $d_api"
1527 else
1528 _err "Add the following TXT record:"
1529 _err "Domain: $txtdomain"
1530 _err "TXT value: $txt"
1531 _err "Please be aware that you prepend _acme-challenge. before your domain"
1532 _err "so the resulting subdomain will be: $txtdomain"
1533 continue
1534 fi
4c3b3608 1535
73b8b120 1536 (
8663fb7e 1537 if ! . $d_api ; then
73b8b120 1538 _err "Load file $d_api error. Please check your api file and try again."
1539 return 1
1540 fi
1541
158f22f7 1542 addcommand="${_currentRoot}_add"
d53289d7 1543 if ! _exists $addcommand ; then
73b8b120 1544 _err "It seems that your api file is not correct, it must have a function named: $addcommand"
1545 return 1
1546 fi
1547
1548 if ! $addcommand $txtdomain $txt ; then
1549 _err "Error add txt for domain:$txtdomain"
1550 return 1
1551 fi
1552 )
4c3b3608 1553
8663fb7e 1554 if [ "$?" != "0" ] ; then
5ef501c5 1555 _clearup
4c3b3608 1556 return 1
1557 fi
1558 dnsadded='1'
1559 fi
1560 done
1561
8663fb7e 1562 if [ "$dnsadded" = '0' ] ; then
4d2f38b0 1563 _savedomainconf "Le_Vlist" "$vlist"
4c3b3608 1564 _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
1565 _err "Please add the TXT records to the domains, and retry again."
5ef501c5 1566 _clearup
4c3b3608 1567 return 1
1568 fi
1569
1570 fi
1571
8663fb7e 1572 if [ "$dnsadded" = '1' ] ; then
0e38c60d 1573 if [ -z "$Le_DNSSleep" ] ; then
1574 Le_DNSSleep=60
1575 else
1576 _savedomainconf "Le_DNSSleep" "$Le_DNSSleep"
1577 fi
1578
1579 _info "Sleep $Le_DNSSleep seconds for the txt records to take effect"
1580 sleep $Le_DNSSleep
4c3b3608 1581 fi
1582
1583 _debug "ok, let's start to verify"
a63b05a9 1584
4c3b3608 1585 ventries=$(echo "$vlist" | tr ',' ' ' )
1586 for ventry in $ventries
1587 do
1588 d=$(echo $ventry | cut -d $sep -f 1)
1589 keyauthorization=$(echo $ventry | cut -d $sep -f 2)
1590 uri=$(echo $ventry | cut -d $sep -f 3)
a63b05a9 1591 vtype=$(echo $ventry | cut -d $sep -f 4)
1592 _currentRoot=$(echo $ventry | cut -d $sep -f 5)
4c3b3608 1593 _info "Verifying:$d"
1594 _debug "d" "$d"
1595 _debug "keyauthorization" "$keyauthorization"
1596 _debug "uri" "$uri"
1597 removelevel=""
e22bcf7c 1598 token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)"
a63b05a9 1599
1600 _debug "_currentRoot" "$_currentRoot"
1601
1602
8663fb7e 1603 if [ "$vtype" = "$VTYPE_HTTP" ] ; then
1604 if [ "$_currentRoot" = "no" ] ; then
4c3b3608 1605 _info "Standalone mode server"
1606 _startserver "$keyauthorization" &
8663fb7e 1607 if [ "$?" != "0" ] ; then
5ef501c5 1608 _clearup
6fc1447f 1609 return 1
1610 fi
4c3b3608 1611 serverproc="$!"
1612 sleep 2
1613 _debug serverproc $serverproc
6fc1447f 1614
4c3b3608 1615 else
8663fb7e 1616 if [ "$_currentRoot" = "apache" ] ; then
6f930641 1617 wellknown_path="$ACME_DIR"
1618 else
a63b05a9 1619 wellknown_path="$_currentRoot/.well-known/acme-challenge"
8663fb7e 1620 if [ ! -d "$_currentRoot/.well-known" ] ; then
6f930641 1621 removelevel='1'
8663fb7e 1622 elif [ ! -d "$_currentRoot/.well-known/acme-challenge" ] ; then
6f930641 1623 removelevel='2'
1624 else
1625 removelevel='3'
1626 fi
4c3b3608 1627 fi
6f930641 1628
4c3b3608 1629 _debug wellknown_path "$wellknown_path"
6f930641 1630
4c3b3608 1631 _debug "writing token:$token to $wellknown_path/$token"
1632
1633 mkdir -p "$wellknown_path"
7939b419 1634 printf "%s" "$keyauthorization" > "$wellknown_path/$token"
8663fb7e 1635 if [ ! "$usingApache" ] ; then
a63b05a9 1636 webroot_owner=$(_stat $_currentRoot)
df886ffa 1637 _debug "Changing owner/group of .well-known to $webroot_owner"
a63b05a9 1638 chown -R $webroot_owner "$_currentRoot/.well-known"
df886ffa 1639 fi
4c3b3608 1640
1641 fi
e22bcf7c 1642
1643 elif [ "$vtype" = "$VTYPE_TLS" ] ; then
1644 #create A
1645 #_hash_A="$(printf "%s" $token | _digest "sha256" "hex" )"
1646 #_debug2 _hash_A "$_hash_A"
1647 #_x="$(echo $_hash_A | cut -c 1-32)"
1648 #_debug2 _x "$_x"
1649 #_y="$(echo $_hash_A | cut -c 33-64)"
1650 #_debug2 _y "$_y"
1651 #_SAN_A="$_x.$_y.token.acme.invalid"
1652 #_debug2 _SAN_A "$_SAN_A"
1653
1654 #create B
1655 _hash_B="$(printf "%s" $keyauthorization | _digest "sha256" "hex" )"
1656 _debug2 _hash_B "$_hash_B"
1657 _x="$(echo $_hash_B | cut -c 1-32)"
1658 _debug2 _x "$_x"
1659 _y="$(echo $_hash_B | cut -c 33-64)"
1660 _debug2 _y "$_y"
1661
1662 #_SAN_B="$_x.$_y.ka.acme.invalid"
1663
1664 _SAN_B="$_x.$_y.acme.invalid"
1665 _debug2 _SAN_B "$_SAN_B"
1666
1667 if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" ; then
1668 _err "Start tls server error."
1669 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
1670 _clearup
1671 return 1
1672 fi
4c3b3608 1673 fi
1674
c4d8fd83 1675 if ! _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" ; then
1676 _err "$d:Can not get challenge: $response"
1677 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
1678 _clearup
1679 return 1
1680 fi
4c3b3608 1681
8663fb7e 1682 if [ ! -z "$code" ] && [ ! "$code" = '202' ] ; then
c60883ef 1683 _err "$d:Challenge error: $response"
a63b05a9 1684 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 1685 _clearup
1686 return 1
1687 fi
1688
6fc1447f 1689 waittimes=0
8663fb7e 1690 if [ -z "$MAX_RETRY_TIMES" ] ; then
6fc1447f 1691 MAX_RETRY_TIMES=30
1692 fi
1693
2ee5d873 1694 while true ; do
00a50605 1695 waittimes=$(_math $waittimes + 1)
8663fb7e 1696 if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ] ; then
6fc1447f 1697 _err "$d:Timeout"
1698 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
1699 _clearup
1700 return 1
1701 fi
1702
4c3b3608 1703 _debug "sleep 5 secs to verify"
1704 sleep 5
1705 _debug "checking"
9aaf36cd 1706 response="$(_get $uri)"
8663fb7e 1707 if [ "$?" != "0" ] ; then
c60883ef 1708 _err "$d:Verify error:$response"
a63b05a9 1709 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 1710 _clearup
1711 return 1
1712 fi
9aaf36cd 1713 _debug2 original "$response"
1714
1715 response="$(echo "$response" | _normalizeJson )"
7012b91f 1716 _debug2 response "$response"
4c3b3608 1717
7d91e35f 1718 status=$(echo $response | egrep -o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"')
8663fb7e 1719 if [ "$status" = "valid" ] ; then
4c3b3608 1720 _info "Success"
1721 _stopserver $serverproc
1722 serverproc=""
a63b05a9 1723 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 1724 break;
1725 fi
1726
8663fb7e 1727 if [ "$status" = "invalid" ] ; then
6e180343 1728 error="$(echo $response | tr -d "\r\n" | egrep -o '"error":{[^}]*}')"
b7ec6789 1729 _debug2 error "$error"
1730 errordetail="$(echo $error | grep -o '"detail": *"[^"]*"' | cut -d '"' -f 4)"
1731 _debug2 errordetail "$errordetail"
1732 if [ "$errordetail" ] ; then
1733 _err "$d:Verify error:$errordetail"
1734 else
1735 _err "$d:Verify error:$error"
1736 fi
a63b05a9 1737 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 1738 _clearup
1739 return 1;
1740 fi
1741
8663fb7e 1742 if [ "$status" = "pending" ] ; then
4c3b3608 1743 _info "Pending"
1744 else
1745 _err "$d:Verify error:$response"
a63b05a9 1746 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 1747 _clearup
1748 return 1
1749 fi
1750
1751 done
1752
1753 done
1754
1755 _clearup
1756 _info "Verify finished, start to sign."
fa8311dc 1757 der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _urlencode)"
c4d8fd83 1758
1759 if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" ; then
1760 _err "Sign failed."
1761 return 1
1762 fi
4c3b3608 1763
1764
bbbdcb09 1765 Le_LinkCert="$(grep -i -o '^Location.*$' $HTTP_HEADER | head -1 | tr -d "\r\n" | cut -d " " -f 2)"
4d2f38b0 1766 _savedomainconf "Le_LinkCert" "$Le_LinkCert"
4c3b3608 1767
8663fb7e 1768 if [ "$Le_LinkCert" ] ; then
88fab7d6 1769 echo "$BEGIN_CERT" > "$CERT_PATH"
c60883ef 1770 _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH"
88fab7d6 1771 echo "$END_CERT" >> "$CERT_PATH"
4c3b3608 1772 _info "Cert success."
1773 cat "$CERT_PATH"
1774
1775 _info "Your cert is in $CERT_PATH"
caf1fc10 1776 cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH"
281aa349 1777
8663fb7e 1778 if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ] ; then
281aa349 1779 USER_PATH="$PATH"
1780 _saveaccountconf "USER_PATH" "$USER_PATH"
1781 fi
4c3b3608 1782 fi
1783
1784
8663fb7e 1785 if [ -z "$Le_LinkCert" ] ; then
eae29099 1786 response="$(echo $response | _dbase64 "multiline" | _normalizeJson )"
4c3b3608 1787 _err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')"
1788 return 1
1789 fi
1790
4d2f38b0 1791 _cleardomainconf "Le_Vlist"
4c3b3608 1792
bbbdcb09 1793 Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | head -1 | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' )
4d2f38b0 1794 _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer"
4c3b3608 1795
8663fb7e 1796 if [ "$Le_LinkIssuer" ] ; then
88fab7d6 1797 echo "$BEGIN_CERT" > "$CA_CERT_PATH"
c60883ef 1798 _get "$Le_LinkIssuer" | _base64 "multiline" >> "$CA_CERT_PATH"
88fab7d6 1799 echo "$END_CERT" >> "$CA_CERT_PATH"
4c3b3608 1800 _info "The intermediate CA cert is in $CA_CERT_PATH"
caf1fc10 1801 cat "$CA_CERT_PATH" >> "$CERT_FULLCHAIN_PATH"
1802 _info "And the full chain certs is there: $CERT_FULLCHAIN_PATH"
4c3b3608 1803 fi
1804
1805 Le_CertCreateTime=$(date -u "+%s")
4d2f38b0 1806 _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime"
4c3b3608 1807
1808 Le_CertCreateTimeStr=$(date -u )
4d2f38b0 1809 _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr"
4c3b3608 1810
523c7682 1811 if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ] ; then
1812 Le_RenewalDays=$MAX_RENEW
054cb72e 1813 else
1814 _savedomainconf "Le_RenewalDays" "$Le_RenewalDays"
13d7cae9 1815 fi
1816
1817 if [ "$Le_Insecure" ] ; then
1818 _savedomainconf "Le_Insecure" "$Le_Insecure"
1819 fi
00a50605 1820
1821 Le_NextRenewTime=$(_math $Le_CertCreateTime + $Le_RenewalDays \* 24 \* 60 \* 60)
4d2f38b0 1822 _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime"
4c3b3608 1823
1824 Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime )
4d2f38b0 1825 _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr"
4c3b3608 1826
1827
01f54558 1828 _output="$(installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" 2>&1)"
1829 _ret="$?"
1830 if [ "$_ret" = "9" ] ; then
ca2a96b3 1831 #ignore the empty install error.
1832 return 0
1833 fi
01f54558 1834 if [ "$_ret" != "0" ] ; then
1835 _err "$_output"
1836 return 1
1837 fi
4c3b3608 1838}
1839
1840renew() {
1841 Le_Domain="$1"
8663fb7e 1842 if [ -z "$Le_Domain" ] ; then
a7b7355d 1843 _err "Usage: $PROJECT_ENTRY --renew -d domain.com"
4c3b3608 1844 return 1
1845 fi
1846
1847 _initpath $Le_Domain
5aa146a5 1848 _info "Renew: $Le_Domain"
8663fb7e 1849 if [ ! -f "$DOMAIN_CONF" ] ; then
4c3b3608 1850 _info "$Le_Domain is not a issued domain, skip."
1851 return 0;
1852 fi
1853
8663fb7e 1854 . "$DOMAIN_CONF"
1855 if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then
4c3b3608 1856 _info "Skip, Next renewal time is: $Le_NextRenewTimeStr"
cc179731 1857 return $RENEW_SKIP
4c3b3608 1858 fi
1859
1860 IS_RENEW="1"
a63b05a9 1861 issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath"
4c3b3608 1862 local res=$?
1863 IS_RENEW=""
1864
1865 return $res
1866}
1867
cc179731 1868#renewAll [stopRenewOnError]
4c3b3608 1869renewAll() {
1870 _initpath
cc179731 1871 _stopRenewOnError="$1"
1872 _debug "_stopRenewOnError" "$_stopRenewOnError"
1873 _ret="0"
b2817897 1874 for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do
4c3b3608 1875 d=$(echo $d | cut -d '/' -f 1)
5aa146a5 1876 (
4d2f38b0 1877 renew "$d"
1878 )
cc179731 1879 rc="$?"
1880 _debug "Return code: $rc"
1881 if [ "$rc" != "0" ] ; then
1882 if [ "$rc" = "$RENEW_SKIP" ] ; then
1883 _info "Skipped $d"
1884 elif [ "$_stopRenewOnError" ] ; then
1885 _err "Error renew $d, stop now."
1886 return $rc
1887 else
1888 _ret="$rc"
1889 _err "Error renew $d, Go ahead to next one."
1890 fi
1891 fi
4c3b3608 1892 done
cc179731 1893 return $_ret
4c3b3608 1894}
1895
dcf4f8f6 1896
6d7eda3e 1897list() {
dcf4f8f6 1898 local _raw="$1"
6d7eda3e 1899 _initpath
dcf4f8f6 1900
1901 _sep="|"
1902 if [ "$_raw" ] ; then
1903 printf "Main_Domain${_sep}SAN_Domains${_sep}Created${_sep}Renew\n"
1904 for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do
1905 d=$(echo $d | cut -d '/' -f 1)
1906 (
1907 _initpath $d
1908 if [ -f "$DOMAIN_CONF" ] ; then
1909 . "$DOMAIN_CONF"
1910 printf "$Le_Domain${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr\n"
1911 fi
1912 )
1913 done
1914 else
1915 list "raw" | column -t -s "$_sep"
1916 fi
6d7eda3e 1917
1918
1919}
1920
4c3b3608 1921installcert() {
1922 Le_Domain="$1"
8663fb7e 1923 if [ -z "$Le_Domain" ] ; then
a7b7355d 1924 echo "Usage: $PROJECT_ENTRY --installcert -d domain.com [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]"
4c3b3608 1925 return 1
1926 fi
1927
1928 Le_RealCertPath="$2"
1929 Le_RealKeyPath="$3"
1930 Le_RealCACertPath="$4"
1931 Le_ReloadCmd="$5"
a63b05a9 1932 Le_RealFullChainPath="$6"
4c3b3608 1933
1934 _initpath $Le_Domain
1935
4d2f38b0 1936 _savedomainconf "Le_RealCertPath" "$Le_RealCertPath"
1937 _savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath"
1938 _savedomainconf "Le_RealKeyPath" "$Le_RealKeyPath"
1939 _savedomainconf "Le_ReloadCmd" "$Le_ReloadCmd"
1940 _savedomainconf "Le_RealFullChainPath" "$Le_RealFullChainPath"
4c3b3608 1941
4d2f38b0 1942 if [ "$Le_RealCertPath" = "no" ] ; then
1943 Le_RealCertPath=""
1944 fi
1945 if [ "$Le_RealKeyPath" = "no" ] ; then
1946 Le_RealKeyPath=""
1947 fi
1948 if [ "$Le_RealCACertPath" = "no" ] ; then
1949 Le_RealCACertPath=""
1950 fi
1951 if [ "$Le_ReloadCmd" = "no" ] ; then
1952 Le_ReloadCmd=""
1953 fi
1954 if [ "$Le_RealFullChainPath" = "no" ] ; then
1955 Le_RealFullChainPath=""
1956 fi
1957
1958 _installed="0"
8663fb7e 1959 if [ "$Le_RealCertPath" ] ; then
4d2f38b0 1960 _installed=1
1961 _info "Installing cert to:$Le_RealCertPath"
8663fb7e 1962 if [ -f "$Le_RealCertPath" ] ; then
ff3bce32 1963 cp "$Le_RealCertPath" "$Le_RealCertPath".bak
4c3b3608 1964 fi
1965 cat "$CERT_PATH" > "$Le_RealCertPath"
1966 fi
1967
8663fb7e 1968 if [ "$Le_RealCACertPath" ] ; then
4d2f38b0 1969 _installed=1
1970 _info "Installing CA to:$Le_RealCACertPath"
8663fb7e 1971 if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ] ; then
4c3b3608 1972 echo "" >> "$Le_RealCACertPath"
1973 cat "$CA_CERT_PATH" >> "$Le_RealCACertPath"
1974 else
8663fb7e 1975 if [ -f "$Le_RealCACertPath" ] ; then
ff3bce32 1976 cp "$Le_RealCACertPath" "$Le_RealCACertPath".bak
78552b18 1977 fi
4c3b3608 1978 cat "$CA_CERT_PATH" > "$Le_RealCACertPath"
1979 fi
1980 fi
1981
1982
8663fb7e 1983 if [ "$Le_RealKeyPath" ] ; then
4d2f38b0 1984 _installed=1
1985 _info "Installing key to:$Le_RealKeyPath"
8663fb7e 1986 if [ -f "$Le_RealKeyPath" ] ; then
ff3bce32 1987 cp "$Le_RealKeyPath" "$Le_RealKeyPath".bak
4c3b3608 1988 fi
1989 cat "$CERT_KEY_PATH" > "$Le_RealKeyPath"
1990 fi
a63b05a9 1991
8663fb7e 1992 if [ "$Le_RealFullChainPath" ] ; then
4d2f38b0 1993 _installed=1
1994 _info "Installing full chain to:$Le_RealFullChainPath"
8663fb7e 1995 if [ -f "$Le_RealFullChainPath" ] ; then
ff3bce32 1996 cp "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak
a63b05a9 1997 fi
1998 cat "$CERT_FULLCHAIN_PATH" > "$Le_RealFullChainPath"
1999 fi
4c3b3608 2000
8663fb7e 2001 if [ "$Le_ReloadCmd" ] ; then
4d2f38b0 2002 _installed=1
4c3b3608 2003 _info "Run Le_ReloadCmd: $Le_ReloadCmd"
4d2f38b0 2004 if (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd") ; then
2005 _info "Reload success."
2006 else
2007 _err "Reload error for :$Le_Domain"
2008 fi
2009 fi
2010
2011 if [ "$_installed" = "0" ] ; then
2012 _err "Nothing to install. You don't specify any parameter."
ca2a96b3 2013 return 9
4c3b3608 2014 fi
2015
2016}
2017
2018installcronjob() {
2019 _initpath
77546ea5 2020 if ! _exists "crontab" ; then
2021 _err "crontab doesn't exist, so, we can not install cron jobs."
2022 _err "All your certs will not be renewed automatically."
a7b7355d 2023 _err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday."
77546ea5 2024 return 1
2025 fi
2026
4c3b3608 2027 _info "Installing cron job"
a7b7355d 2028 if ! crontab -l | grep "$PROJECT_ENTRY --cron" ; then
8663fb7e 2029 if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ] ; then
a7b7355d 2030 lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY"
4c3b3608 2031 else
a7b7355d 2032 _err "Can not install cronjob, $PROJECT_ENTRY not found."
4c3b3608 2033 return 1
2034 fi
a7b7355d 2035 crontab -l | { cat; echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"; } | crontab -
4c3b3608 2036 fi
8663fb7e 2037 if [ "$?" != "0" ] ; then
4c3b3608 2038 _err "Install cron job failed. You need to manually renew your certs."
2039 _err "Or you can add cronjob by yourself:"
a7b7355d 2040 _err "$lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"
4c3b3608 2041 return 1
2042 fi
2043}
2044
2045uninstallcronjob() {
37db5b81 2046 if ! _exists "crontab" ; then
2047 return
2048 fi
4c3b3608 2049 _info "Removing cron job"
a7b7355d 2050 cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")"
8663fb7e 2051 if [ "$cr" ] ; then
a7b7355d 2052 crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab -
2053 LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')"
4c3b3608 2054 _info LE_WORKING_DIR "$LE_WORKING_DIR"
2055 fi
2056 _initpath
a7b7355d 2057
4c3b3608 2058}
2059
6cb415f5 2060revoke() {
2061 Le_Domain="$1"
8663fb7e 2062 if [ -z "$Le_Domain" ] ; then
a7b7355d 2063 echo "Usage: $PROJECT_ENTRY --revoke -d domain.com"
6cb415f5 2064 return 1
2065 fi
2066
2067 _initpath $Le_Domain
8663fb7e 2068 if [ ! -f "$DOMAIN_CONF" ] ; then
6cb415f5 2069 _err "$Le_Domain is not a issued domain, skip."
2070 return 1;
2071 fi
2072
8663fb7e 2073 if [ ! -f "$CERT_PATH" ] ; then
6cb415f5 2074 _err "Cert for $Le_Domain $CERT_PATH is not found, skip."
2075 return 1
2076 fi
2077
2078 cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}"| tr -d "\r\n" | _urlencode)"
2079
8663fb7e 2080 if [ -z "$cert" ] ; then
6cb415f5 2081 _err "Cert for $Le_Domain is empty found, skip."
2082 return 1
2083 fi
2084
2085 data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}"
2086 uri="$API/acme/revoke-cert"
2087
2088 _info "Try domain key first."
2089 if _send_signed_request $uri "$data" "" "$CERT_KEY_PATH"; then
8663fb7e 2090 if [ -z "$response" ] ; then
6cb415f5 2091 _info "Revoke success."
2092 rm -f $CERT_PATH
2093 return 0
2094 else
2095 _err "Revoke error by domain key."
2096 _err "$resource"
2097 fi
2098 fi
2099
2100 _info "Then try account key."
2101
2102 if _send_signed_request $uri "$data" "" "$ACCOUNT_KEY_PATH" ; then
8663fb7e 2103 if [ -z "$response" ] ; then
6cb415f5 2104 _info "Revoke success."
2105 rm -f $CERT_PATH
2106 return 0
2107 else
2108 _err "Revoke error."
2109 _debug "$resource"
2110 fi
2111 fi
2112 return 1
2113}
4c3b3608 2114
2115# Detect profile file if not specified as environment variable
2116_detect_profile() {
a63b05a9 2117 if [ -n "$PROFILE" -a -f "$PROFILE" ] ; then
4c3b3608 2118 echo "$PROFILE"
2119 return
2120 fi
2121
2122 local DETECTED_PROFILE
2123 DETECTED_PROFILE=''
2124 local SHELLTYPE
2125 SHELLTYPE="$(basename "/$SHELL")"
2126
8663fb7e 2127 if [ "$SHELLTYPE" = "bash" ] ; then
2128 if [ -f "$HOME/.bashrc" ] ; then
4c3b3608 2129 DETECTED_PROFILE="$HOME/.bashrc"
8663fb7e 2130 elif [ -f "$HOME/.bash_profile" ] ; then
4c3b3608 2131 DETECTED_PROFILE="$HOME/.bash_profile"
2132 fi
8663fb7e 2133 elif [ "$SHELLTYPE" = "zsh" ] ; then
4c3b3608 2134 DETECTED_PROFILE="$HOME/.zshrc"
2135 fi
2136
8663fb7e 2137 if [ -z "$DETECTED_PROFILE" ] ; then
2138 if [ -f "$HOME/.profile" ] ; then
4c3b3608 2139 DETECTED_PROFILE="$HOME/.profile"
8663fb7e 2140 elif [ -f "$HOME/.bashrc" ] ; then
4c3b3608 2141 DETECTED_PROFILE="$HOME/.bashrc"
8663fb7e 2142 elif [ -f "$HOME/.bash_profile" ] ; then
4c3b3608 2143 DETECTED_PROFILE="$HOME/.bash_profile"
8663fb7e 2144 elif [ -f "$HOME/.zshrc" ] ; then
4c3b3608 2145 DETECTED_PROFILE="$HOME/.zshrc"
2146 fi
2147 fi
2148
8663fb7e 2149 if [ ! -z "$DETECTED_PROFILE" ] ; then
4c3b3608 2150 echo "$DETECTED_PROFILE"
2151 fi
2152}
2153
2154_initconf() {
2155 _initpath
8663fb7e 2156 if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then
d53289d7 2157 echo "#ACCOUNT_CONF_PATH=xxxx
2158
2159#Account configurations:
4c3b3608 2160#Here are the supported macros, uncomment them to make them take effect.
d53289d7 2161
4c3b3608 2162#ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account.
5fd3f21b 2163#ACCOUNT_KEY_PATH=\"/path/to/account.key\"
b2817897 2164#CERT_HOME=\"/path/to/cert/home\"
4c3b3608 2165
2166#STAGE=1 # Use the staging api
2167#FORCE=1 # Force to issue cert
2168#DEBUG=1 # Debug mode
2169
166096dc 2170#ACCOUNT_KEY_HASH=account key hash
2171
8814a348 2172#USER_AGENT=\"$USER_AGENT\"
281aa349 2173
2174#USER_PATH=""
2175
4c3b3608 2176#dns api
2177#######################
2178#Cloudflare:
2179#api key
3d49985a 2180#CF_Key=\"sdfsdfsdfljlbjkljlkjsdfoiwje\"
4c3b3608 2181#account email
3d49985a 2182#CF_Email=\"xxxx@sss.com\"
4c3b3608 2183
2184#######################
2185#Dnspod.cn:
2186#api key id
3d49985a 2187#DP_Id=\"1234\"
4c3b3608 2188#api key
3d49985a 2189#DP_Key=\"sADDsdasdgdsf\"
4c3b3608 2190
2191#######################
2192#Cloudxns.com:
3d49985a 2193#CX_Key=\"1234\"
4c3b3608 2194#
3d49985a 2195#CX_Secret=\"sADDsdasdgdsf\"
4c3b3608 2196
2197 " > $ACCOUNT_CONF_PATH
2198 fi
2199}
2200
c8e9a31e 2201# nocron
c60883ef 2202_precheck() {
c8e9a31e 2203 _nocron="$1"
2204
c60883ef 2205 if ! _exists "curl" && ! _exists "wget"; then
2206 _err "Please install curl or wget first, we need to access http resources."
4c3b3608 2207 return 1
2208 fi
2209
c8e9a31e 2210 if [ -z "$_nocron" ] ; then
2211 if ! _exists "crontab" ; then
2212 _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'."
2213 _err "We need to set cron job to renew the certs automatically."
2214 _err "Otherwise, your certs will not be able to be renewed automatically."
2215 if [ -z "$FORCE" ] ; then
2216 _err "Please add '--force' and try install again to go without crontab."
2217 _err "./$PROJECT_ENTRY --install --force"
2218 return 1
2219 fi
77546ea5 2220 fi
4c3b3608 2221 fi
2222
c60883ef 2223 if ! _exists "openssl" ; then
2224 _err "Please install openssl first."
2225 _err "We need openssl to generate keys."
4c3b3608 2226 return 1
2227 fi
2228
c60883ef 2229 if ! _exists "nc" ; then
2230 _err "It is recommended to install nc first, try to install 'nc' or 'netcat'."
2231 _err "We use nc for standalone server if you use standalone mode."
2232 _err "If you don't use standalone mode, just ignore this warning."
2233 fi
2234
2235 return 0
2236}
2237
0a7c9364 2238_setShebang() {
2239 _file="$1"
2240 _shebang="$2"
2241 if [ -z "$_shebang" ] ; then
2242 _err "Usage: file shebang"
2243 return 1
2244 fi
2245 cp "$_file" "$_file.tmp"
2246 echo "$_shebang" > "$_file"
2247 sed -n 2,99999p "$_file.tmp" >> "$_file"
2248 rm -f "$_file.tmp"
2249}
2250
94dc5f33 2251_installalias() {
2252 _initpath
2253
2254 _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env"
2255 if [ "$_upgrading" ] && [ "$_upgrading" = "1" ] ; then
2256 echo "$(cat $_envfile)" | sed "s|^LE_WORKING_DIR.*$||" > "$_envfile"
2257 echo "$(cat $_envfile)" | sed "s|^alias le.*$||" > "$_envfile"
2258 echo "$(cat $_envfile)" | sed "s|^alias le.sh.*$||" > "$_envfile"
2259 fi
2260
1786a5e5 2261 _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\""
94dc5f33 2262 _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\""
2263
2264 _profile="$(_detect_profile)"
2265 if [ "$_profile" ] ; then
2266 _debug "Found profile: $_profile"
2267 _setopt "$_profile" ". \"$_envfile\""
2268 _info "OK, Close and reopen your terminal to start using $PROJECT_NAME"
2269 else
2270 _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME"
2271 fi
2272
2273
2274 #for csh
2275 _cshfile="$LE_WORKING_DIR/$PROJECT_ENTRY.csh"
94dc5f33 2276 _csh_profile="$HOME/.cshrc"
2277 if [ -f "$_csh_profile" ] ; then
6626371d 2278 _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
2279 _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\""
94dc5f33 2280 _setopt "$_csh_profile" "source \"$_cshfile\""
2281 fi
acafa585 2282
2283 #for tcsh
2284 _tcsh_profile="$HOME/.tcshrc"
2285 if [ -f "$_tcsh_profile" ] ; then
2286 _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
2287 _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\""
2288 _setopt "$_tcsh_profile" "source \"$_cshfile\""
2289 fi
94dc5f33 2290
2291}
2292
c8e9a31e 2293# nocron
c60883ef 2294install() {
c8e9a31e 2295 _nocron="$1"
c60883ef 2296 if ! _initpath ; then
2297 _err "Install failed."
4c3b3608 2298 return 1
2299 fi
52677b0a 2300 if [ "$_nocron" ] ; then
2301 _debug "Skip install cron job"
2302 fi
2303
c8e9a31e 2304 if ! _precheck "$_nocron" ; then
c60883ef 2305 _err "Pre-check failed, can not install."
4c3b3608 2306 return 1
2307 fi
c60883ef 2308
6cc11ffb 2309 #convert from le
8663fb7e 2310 if [ -d "$HOME/.le" ] ; then
6cc11ffb 2311 for envfile in "le.env" "le.sh.env"
2312 do
8663fb7e 2313 if [ -f "$HOME/.le/$envfile" ] ; then
6cc11ffb 2314 if grep "le.sh" "$HOME/.le/$envfile" >/dev/null ; then
2315 _upgrading="1"
2316 _info "You are upgrading from le.sh"
2317 _info "Renaming \"$HOME/.le\" to $LE_WORKING_DIR"
2318 mv "$HOME/.le" "$LE_WORKING_DIR"
2319 mv "$LE_WORKING_DIR/$envfile" "$LE_WORKING_DIR/$PROJECT_ENTRY.env"
2320 break;
2321 fi
2322 fi
2323 done
2324 fi
2325
4c3b3608 2326 _info "Installing to $LE_WORKING_DIR"
635695ec 2327
4a0f23e2 2328 if ! mkdir -p "$LE_WORKING_DIR" ; then
90035252 2329 _err "Can not create working dir: $LE_WORKING_DIR"
4a0f23e2 2330 return 1
2331 fi
2332
762978f8 2333 chmod 700 "$LE_WORKING_DIR"
2334
a7b7355d 2335 cp $PROJECT_ENTRY "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY"
4c3b3608 2336
8663fb7e 2337 if [ "$?" != "0" ] ; then
a7b7355d 2338 _err "Install failed, can not copy $PROJECT_ENTRY"
4c3b3608 2339 return 1
2340 fi
2341
a7b7355d 2342 _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY"
4c3b3608 2343
94dc5f33 2344 _installalias
4c3b3608 2345
8663fb7e 2346 if [ -d "dnsapi" ] ; then
6ed1c718 2347 mkdir -p $LE_WORKING_DIR/dnsapi
2348 cp dnsapi/* $LE_WORKING_DIR/dnsapi/
2349 fi
d53289d7 2350
8663fb7e 2351 if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then
4c3b3608 2352 _initconf
2353 fi
6cc11ffb 2354
8663fb7e 2355 if [ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ] ; then
635695ec 2356 _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\""
6cc11ffb 2357 fi
2358
8663fb7e 2359 if [ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ] ; then
b2817897 2360 _saveaccountconf "CERT_HOME" "$CERT_HOME"
2361 fi
2362
8663fb7e 2363 if [ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ] ; then
b2817897 2364 _saveaccountconf "ACCOUNT_KEY_PATH" "$ACCOUNT_KEY_PATH"
2365 fi
2366
c8e9a31e 2367 if [ -z "$_nocron" ] ; then
2368 installcronjob
2369 fi
0a7c9364 2370
641989fd 2371 if [ -z "$NO_DETECT_SH" ] ; then
2372 #Modify shebang
2373 if _exists bash ; then
2374 _info "Good, bash is installed, change the shebang to use bash as prefered."
2375 _shebang='#!/usr/bin/env bash'
2376 _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang"
2377 if [ -d "$LE_WORKING_DIR/dnsapi" ] ; then
2378 for _apifile in $(ls "$LE_WORKING_DIR/dnsapi/"*.sh) ; do
2379 _setShebang "$_apifile" "$_shebang"
2380 done
2381 fi
0a7c9364 2382 fi
2383 fi
2384
4c3b3608 2385 _info OK
2386}
2387
52677b0a 2388# nocron
4c3b3608 2389uninstall() {
52677b0a 2390 _nocron="$1"
2391 if [ -z "$_nocron" ] ; then
2392 uninstallcronjob
2393 fi
4c3b3608 2394 _initpath
2395
2396 _profile="$(_detect_profile)"
8663fb7e 2397 if [ "$_profile" ] ; then
7203a1c1 2398 text="$(cat $_profile)"
94dc5f33 2399 echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" > "$_profile"
4c3b3608 2400 fi
2401
94dc5f33 2402 _csh_profile="$HOME/.cshrc"
2403 if [ -f "$_csh_profile" ] ; then
2404 text="$(cat $_csh_profile)"
2405 echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" > "$_csh_profile"
2406 fi
2407
acafa585 2408 _tcsh_profile="$HOME/.tcshrc"
2409 if [ -f "$_tcsh_profile" ] ; then
2410 text="$(cat $_tcsh_profile)"
2411 echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" > "$_tcsh_profile"
2412 fi
2413
a7b7355d 2414 rm -f $LE_WORKING_DIR/$PROJECT_ENTRY
4c3b3608 2415 _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself."
2416
2417}
2418
2419cron() {
281aa349 2420 IN_CRON=1
4c3b3608 2421 renewAll
cc179731 2422 _ret="$?"
281aa349 2423 IN_CRON=""
cc179731 2424 return $_ret
4c3b3608 2425}
2426
2427version() {
a63b05a9 2428 echo "$PROJECT"
2429 echo "v$VER"
4c3b3608 2430}
2431
2432showhelp() {
2433 version
a7b7355d 2434 echo "Usage: $PROJECT_ENTRY command ...[parameters]....
a63b05a9 2435Commands:
2436 --help, -h Show this help message.
2437 --version, -v Show version info.
a7b7355d 2438 --install Install $PROJECT_NAME to your system.
2439 --uninstall Uninstall $PROJECT_NAME, and uninstall the cron job.
52677b0a 2440 --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT
a63b05a9 2441 --issue Issue a cert.
2442 --installcert Install the issued cert to apache/nginx or any other server.
2443 --renew, -r Renew a cert.
2444 --renewAll Renew all the certs
2445 --revoke Revoke a cert.
6d7eda3e 2446 --list List all the certs
a63b05a9 2447 --installcronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
2448 --uninstallcronjob Uninstall the cron job. The 'uninstall' command can do this automatically.
2449 --cron Run cron job to renew all the certs.
2450 --toPkcs Export the certificate and key to a pfx file.
2451 --createAccountKey, -cak Create an account private key, professional use.
2452 --createDomainKey, -cdk Create an domain private key, professional use.
2453 --createCSR, -ccsr Create CSR , professional use.
2454
2455Parameters:
2456 --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc.
2457 --force, -f Used to force to install or force to renew a cert immediately.
2458 --staging, --test Use staging server, just for test.
2459 --debug Output debug info.
2460
2461 --webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
2462 --standalone Use standalone mode.
e22bcf7c 2463 --tls Use standalone tls mode.
a63b05a9 2464 --apache Use apache mode.
eccec5f6 2465 --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
0e38c60d 2466 --dnssleep [60] The time in seconds to wait for all the txt records to take effect in dns api mode. Default 60 seconds.
a63b05a9 2467
2468 --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384.
2469 --accountkeylength, -ak [2048] Specifies the account key length.
2470
2471 These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert:
2472
2473 --certpath /path/to/real/cert/file After issue/renew, the cert will be copied to this path.
2474 --keypath /path/to/real/key/file After issue/renew, the key will be copied to this path.
2475 --capath /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path.
2476 --fullchainpath /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path.
2477
2478 --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server.
2479
2480 --accountconf Specifies a customized account config file.
635695ec 2481 --home Specifies the home dir for $PROJECT_NAME .
39c8f79f 2482 --certhome Specifies the home dir to save all the certs, only valid for '--install' command.
635695ec 2483 --useragent Specifies the user agent string. it will be saved for future use too.
b5eb4b90 2484 --accountemail Specifies the account email for registering, Only valid for the '--install' command.
06625071 2485 --accountkey Specifies the account key path, Only valid for the '--install' command.
523c7682 2486 --days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days.
39c8f79f 2487 --httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
e22bcf7c 2488 --tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer.
dcf4f8f6 2489 --listraw Only used for '--list' command, list the certs in raw format.
c8e9a31e 2490 --stopRenewOnError, -se Only valid for '--renewall' command. Stop if one cert has error in renewal.
13d7cae9 2491 --insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted.
bc96082f 2492 --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.
4c3b3608 2493 "
2494}
2495
52677b0a 2496# nocron
4a0f23e2 2497_installOnline() {
2498 _info "Installing from online archive."
52677b0a 2499 _nocron="$1"
8663fb7e 2500 if [ ! "$BRANCH" ] ; then
4a0f23e2 2501 BRANCH="master"
2502 fi
2503 _initpath
2504 target="$PROJECT/archive/$BRANCH.tar.gz"
2505 _info "Downloading $target"
2506 localname="$BRANCH.tar.gz"
2507 if ! _get "$target" > $localname ; then
2508 _debug "Download error."
2509 return 1
2510 fi
0bbe6eef 2511 (
4a0f23e2 2512 _info "Extracting $localname"
2513 tar xzf $localname
0bbe6eef 2514
6cc11ffb 2515 cd "$PROJECT_NAME-$BRANCH"
a7b7355d 2516 chmod +x $PROJECT_ENTRY
52677b0a 2517 if ./$PROJECT_ENTRY install "$_nocron" ; then
4a0f23e2 2518 _info "Install success!"
2519 fi
2520
2521 cd ..
0bbe6eef 2522
6cc11ffb 2523 rm -rf "$PROJECT_NAME-$BRANCH"
4a0f23e2 2524 rm -f "$localname"
0bbe6eef 2525 )
4a0f23e2 2526}
2527
52677b0a 2528upgrade() {
2529 if (
d0b748a4 2530 cd "$LE_WORKING_DIR"
52677b0a 2531 _installOnline "nocron"
2532 ) ; then
2533 _info "Upgrade success!"
096d8992 2534 exit 0
52677b0a 2535 else
2536 _err "Upgrade failed!"
096d8992 2537 exit 1
52677b0a 2538 fi
2539}
a63b05a9 2540
2541_process() {
2542 _CMD=""
2543 _domain=""
2544 _altdomains="no"
2545 _webroot=""
2546 _keylength="no"
2547 _accountkeylength="no"
2548 _certpath="no"
2549 _keypath="no"
2550 _capath="no"
2551 _fullchainpath="no"
4d2f38b0 2552 _reloadcmd=""
a63b05a9 2553 _password=""
635695ec 2554 _accountconf=""
2555 _useragent=""
b5eb4b90 2556 _accountemail=""
2557 _accountkey=""
b2817897 2558 _certhome=""
39c8f79f 2559 _httpport=""
e22bcf7c 2560 _tlsport=""
0e38c60d 2561 _dnssleep=""
dcf4f8f6 2562 _listraw=""
cc179731 2563 _stopRenewOnError=""
13d7cae9 2564 _insecure=""
c8e9a31e 2565 _nocron=""
8663fb7e 2566 while [ ${#} -gt 0 ] ; do
a63b05a9 2567 case "${1}" in
2568
2569 --help|-h)
2570 showhelp
2571 return
2572 ;;
2573 --version|-v)
2574 version
2575 return
2576 ;;
2577 --install)
2578 _CMD="install"
2579 ;;
2580 --uninstall)
2581 _CMD="uninstall"
2582 ;;
52677b0a 2583 --upgrade)
2584 _CMD="upgrade"
2585 ;;
a63b05a9 2586 --issue)
2587 _CMD="issue"
2588 ;;
2589 --installcert|-i)
2590 _CMD="installcert"
2591 ;;
2592 --renew|-r)
2593 _CMD="renew"
2594 ;;
4d2f38b0 2595 --renewAll|--renewall)
a63b05a9 2596 _CMD="renewAll"
2597 ;;
2598 --revoke)
2599 _CMD="revoke"
2600 ;;
6d7eda3e 2601 --list)
2602 _CMD="list"
2603 ;;
a63b05a9 2604 --installcronjob)
2605 _CMD="installcronjob"
2606 ;;
2607 --uninstallcronjob)
2608 _CMD="uninstallcronjob"
2609 ;;
2610 --cron)
2611 _CMD="cron"
2612 ;;
2613 --toPkcs)
2614 _CMD="toPkcs"
2615 ;;
2616 --createAccountKey|--createaccountkey|-cak)
2617 _CMD="createAccountKey"
2618 ;;
2619 --createDomainKey|--createdomainkey|-cdk)
2620 _CMD="createDomainKey"
2621 ;;
2622 --createCSR|--createcsr|-ccr)
2623 _CMD="createCSR"
2624 ;;
2625
2626
2627 --domain|-d)
2628 _dvalue="$2"
2629
ee1737a5 2630 if [ "$_dvalue" ] ; then
2631 if _startswith "$_dvalue" "-" ; then
2632 _err "'$_dvalue' is not a valid domain for parameter '$1'"
2633 return 1
2634 fi
2635
2636 if [ -z "$_domain" ] ; then
2637 _domain="$_dvalue"
a63b05a9 2638 else
ee1737a5 2639 if [ "$_altdomains" = "no" ] ; then
2640 _altdomains="$_dvalue"
2641 else
2642 _altdomains="$_altdomains,$_dvalue"
2643 fi
a63b05a9 2644 fi
2645 fi
ee1737a5 2646
a63b05a9 2647 shift
2648 ;;
2649
2650 --force|-f)
2651 FORCE="1"
2652 ;;
2653 --staging|--test)
2654 STAGE="1"
2655 ;;
2656 --debug)
8663fb7e 2657 if [ -z "$2" ] || _startswith "$2" "-" ; then
a63b05a9 2658 DEBUG="1"
2659 else
2660 DEBUG="$2"
2661 shift
6fc1447f 2662 fi
a63b05a9 2663 ;;
a63b05a9 2664 --webroot|-w)
2665 wvalue="$2"
8663fb7e 2666 if [ -z "$_webroot" ] ; then
a63b05a9 2667 _webroot="$wvalue"
2668 else
2669 _webroot="$_webroot,$wvalue"
2670 fi
2671 shift
2672 ;;
2673 --standalone)
2674 wvalue="no"
8663fb7e 2675 if [ -z "$_webroot" ] ; then
a63b05a9 2676 _webroot="$wvalue"
2677 else
2678 _webroot="$_webroot,$wvalue"
2679 fi
2680 ;;
2681 --apache)
2682 wvalue="apache"
8663fb7e 2683 if [ -z "$_webroot" ] ; then
a63b05a9 2684 _webroot="$wvalue"
2685 else
2686 _webroot="$_webroot,$wvalue"
2687 fi
2688 ;;
e22bcf7c 2689 --tls)
2690 wvalue="$W_TLS"
2691 if [ -z "$_webroot" ] ; then
2692 _webroot="$wvalue"
2693 else
2694 _webroot="$_webroot,$wvalue"
2695 fi
2696 ;;
a63b05a9 2697 --dns)
2698 wvalue="dns"
dceb3aca 2699 if ! _startswith "$2" "-" ; then
a63b05a9 2700 wvalue="$2"
2701 shift
2702 fi
8663fb7e 2703 if [ -z "$_webroot" ] ; then
a63b05a9 2704 _webroot="$wvalue"
2705 else
2706 _webroot="$_webroot,$wvalue"
2707 fi
2708 ;;
0e38c60d 2709 --dnssleep)
2710 _dnssleep="$2"
2711 Le_DNSSleep="$_dnssleep"
2712 shift
2713 ;;
2714
a63b05a9 2715 --keylength|-k)
2716 _keylength="$2"
2ce87fe2 2717 if [ "$_accountkeylength" = "no" ] ; then
2718 _accountkeylength="$2"
2719 fi
a63b05a9 2720 shift
2721 ;;
2722 --accountkeylength|-ak)
2ce87fe2 2723 _accountkeylength="$2"
a63b05a9 2724 shift
2725 ;;
2726
2727 --certpath)
2728 _certpath="$2"
2729 shift
2730 ;;
2731 --keypath)
2732 _keypath="$2"
2733 shift
2734 ;;
2735 --capath)
2736 _capath="$2"
2737 shift
2738 ;;
2739 --fullchainpath)
2740 _fullchainpath="$2"
2741 shift
2742 ;;
635695ec 2743 --reloadcmd|--reloadCmd)
a63b05a9 2744 _reloadcmd="$2"
2745 shift
2746 ;;
2747 --password)
2748 _password="$2"
2749 shift
2750 ;;
2751 --accountconf)
635695ec 2752 _accountconf="$2"
2753 ACCOUNT_CONF_PATH="$_accountconf"
a7b7355d 2754 shift
a63b05a9 2755 ;;
a7b7355d 2756 --home)
a63b05a9 2757 LE_WORKING_DIR="$2"
a7b7355d 2758 shift
a63b05a9 2759 ;;
b2817897 2760 --certhome)
2761 _certhome="$2"
2762 CERT_HOME="$_certhome"
2763 shift
2764 ;;
635695ec 2765 --useragent)
2766 _useragent="$2"
2767 USER_AGENT="$_useragent"
2768 shift
2769 ;;
b5eb4b90 2770 --accountemail )
2771 _accountemail="$2"
2772 ACCOUNT_EMAIL="$_accountemail"
2773 shift
2774 ;;
2775 --accountkey )
2776 _accountkey="$2"
2777 ACCOUNT_KEY_PATH="$_accountkey"
2778 shift
2779 ;;
06625071 2780 --days )
2781 _days="$2"
2782 Le_RenewalDays="$_days"
2783 shift
2784 ;;
39c8f79f 2785 --httpport )
2786 _httpport="$2"
2787 Le_HTTPPort="$_httpport"
2788 shift
2789 ;;
e22bcf7c 2790 --tlsport )
2791 _tlsport="$2"
2792 Le_TLSPort="$_tlsport"
2793 shift
2794 ;;
2795
dcf4f8f6 2796 --listraw )
2797 _listraw="raw"
2798 ;;
cc179731 2799 --stopRenewOnError|--stoprenewonerror|-se )
2800 _stopRenewOnError="1"
2801 ;;
13d7cae9 2802 --insecure)
2803 _insecure="1"
2804 Le_Insecure="$_insecure"
2805 ;;
c8e9a31e 2806 --nocron)
2807 _nocron="1"
2808 ;;
a63b05a9 2809 *)
2810 _err "Unknown parameter : $1"
2811 return 1
2812 ;;
2813 esac
2814
2815 shift 1
2816 done
2817
2818
2819 case "${_CMD}" in
c8e9a31e 2820 install) install "$_nocron" ;;
bc96082f 2821 uninstall) uninstall "$_nocron" ;;
52677b0a 2822 upgrade) upgrade ;;
a63b05a9 2823 issue)
70a55875 2824 issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath"
a63b05a9 2825 ;;
2826 installcert)
3ed4102a 2827 installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath"
a63b05a9 2828 ;;
2829 renew)
2830 renew "$_domain"
2831 ;;
2832 renewAll)
cc179731 2833 renewAll "$_stopRenewOnError"
a63b05a9 2834 ;;
2835 revoke)
2836 revoke "$_domain"
2837 ;;
6d7eda3e 2838 list)
dcf4f8f6 2839 list "$_listraw"
6d7eda3e 2840 ;;
a63b05a9 2841 installcronjob) installcronjob ;;
2842 uninstallcronjob) uninstallcronjob ;;
2843 cron) cron ;;
2844 toPkcs)
2845 toPkcs "$_domain" "$_password"
2846 ;;
2847 createAccountKey)
2848 createAccountKey "$_domain" "$_accountkeylength"
2849 ;;
2850 createDomainKey)
2851 createDomainKey "$_domain" "$_keylength"
2852 ;;
2853 createCSR)
2854 createCSR "$_domain" "$_altdomains"
2855 ;;
2856
2857 *)
2858 _err "Invalid command: $_CMD"
2859 showhelp;
2860 return 1
2861 ;;
2862 esac
d3595686 2863 _ret="$?"
2864 if [ "$_ret" != "0" ] ; then
2865 return $_ret
2866 fi
a63b05a9 2867
8663fb7e 2868 if [ "$_useragent" ] ; then
635695ec 2869 _saveaccountconf "USER_AGENT" "$_useragent"
2870 fi
8663fb7e 2871 if [ "$_accountemail" ] ; then
b5eb4b90 2872 _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail"
2873 fi
b2817897 2874
635695ec 2875
a63b05a9 2876}
2877
2878
8663fb7e 2879if [ "$INSTALLONLINE" ] ; then
d1f97fc8 2880 INSTALLONLINE=""
4a0f23e2 2881 _installOnline $BRANCH
2882 exit
2883fi
4c3b3608 2884
8663fb7e 2885if [ -z "$1" ] ; then
4c3b3608 2886 showhelp
2887else
036e9d10 2888 if echo "$1" | grep "^-" >/dev/null 2>&1 ; then
a63b05a9 2889 _process "$@"
2890 else
2891 "$@"
2892 fi
4c3b3608 2893fi
a63b05a9 2894
2895