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