]> git.proxmox.com Git - mirror_acme.sh.git/blame - le.sh
fix nc compatible. try '-p' first
[mirror_acme.sh.git] / le.sh
CommitLineData
4c3b3608 1#!/usr/bin/env bash
2VER=1.1.8
3PROJECT="https://github.com/Neilpang/le"
4
5DEFAULT_CA="https://acme-v01.api.letsencrypt.org"
6DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf"
7
8STAGE_CA="https://acme-staging.api.letsencrypt.org"
9
10VTYPE_HTTP="http-01"
11VTYPE_DNS="dns-01"
12
13if [ -z "$AGREEMENT" ] ; then
14 AGREEMENT="$DEFAULT_AGREEMENT"
15fi
16
17_debug() {
18
19 if [ -z "$DEBUG" ] ; then
20 return
21 fi
22
23 if [ -z "$2" ] ; then
24 echo $1
25 else
26 echo "$1"="$2"
27 fi
28}
29
30_info() {
31 if [ -z "$2" ] ; then
32 echo "$1"
33 else
34 echo "$1"="$2"
35 fi
36}
37
38_err() {
39 if [ -z "$2" ] ; then
40 echo "$1" >&2
41 else
42 echo "$1"="$2" >&2
43 fi
44 return 1
45}
46
47_h2b() {
48 hex=$(cat)
49 i=1
50 j=2
51 while [ '1' ] ; do
52 h=$(printf $hex | cut -c $i-$j)
53 if [ -z "$h" ] ; then
54 break;
55 fi
56 printf "\x$h"
57 let "i+=2"
58 let "j+=2"
59 done
60}
61
62_base64() {
63 openssl base64 -e | tr -d '\n'
64}
65
66#domain [2048]
67createAccountKey() {
68 _info "Creating account key"
69 if [ -z "$1" ] ; then
70 echo Usage: createAccountKey account-domain [2048]
71 return
72 fi
73
74 account=$1
75 length=$2
76
77 if [[ "$length" == "ec-"* ]] ; then
78 length=2048
79 fi
80
81 if [ -z "$2" ] ; then
82 _info "Use default length 2048"
83 length=2048
84 fi
85 _initpath
86
87 if [ -f "$ACCOUNT_KEY_PATH" ] ; then
88 _info "Account key exists, skip"
89 return
90 else
91 #generate account key
f89d991d 92 openssl genrsa $length 2>/dev/null > "$ACCOUNT_KEY_PATH"
4c3b3608 93 fi
94
95}
96
97#domain length
98createDomainKey() {
99 _info "Creating domain key"
100 if [ -z "$1" ] ; then
101 echo Usage: createDomainKey domain [2048]
102 return
103 fi
104
105 domain=$1
106 length=$2
107 isec=""
108 if [[ "$length" == "ec-"* ]] ; then
109 isec="1"
110 length=$(printf $length | cut -d '-' -f 2-100)
111 eccname="$length"
112 fi
113
114 if [ -z "$length" ] ; then
115 if [ "$isec" ] ; then
116 length=256
117 else
118 length=2048
119 fi
120 fi
121 _info "Use length $length"
122
123 if [ "$isec" ] ; then
124 if [ "$length" == "256" ] ; then
125 eccname="prime256v1"
126 fi
127 if [ "$length" == "384" ] ; then
128 eccname="secp384r1"
129 fi
130 if [ "$length" == "521" ] ; then
131 eccname="secp521r1"
132 fi
133 _info "Using ec name: $eccname"
134 fi
135
136 _initpath $domain
137
138 if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then
139 #generate account key
140 if [ "$isec" ] ; then
141 openssl ecparam -name $eccname -genkey 2>/dev/null > "$CERT_KEY_PATH"
142 else
143 openssl genrsa $length 2>/dev/null > "$CERT_KEY_PATH"
144 fi
145 else
146 if [ "$IS_RENEW" ] ; then
147 _info "Domain key exists, skip"
148 return 0
149 else
150 _err "Domain key exists, do you want to overwrite the key?"
151 _err "Set FORCE=1, and try again."
152 return 1
153 fi
154 fi
155
156}
157
158# domain domainlist
159createCSR() {
160 _info "Creating csr"
161 if [ -z "$1" ] ; then
162 echo Usage: $0 domain [domainlist]
163 return
164 fi
165 domain=$1
166 _initpath $domain
167
168 domainlist=$2
169
170 if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && ! [ "$FORCE" ]; then
171 _info "CSR exists, skip"
172 return
173 fi
174
175 if [ -z "$domainlist" ] ; then
176 #single domain
177 _info "Single domain" $domain
1ad65f7d 178 printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n" > "$DOMAIN_SSL_CONF"
179 openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH"
4c3b3608 180 else
181 alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")"
182 #multi
183 _info "Multi domain" "$alt"
184 printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n[SAN]\nsubjectAltName=$alt" > "$DOMAIN_SSL_CONF"
185 openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -reqexts SAN -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH"
186 fi
187
188}
189
190_b64() {
191 __n=$(cat)
192 echo $__n | tr '/+' '_-' | tr -d '= '
193}
194
195_time2str() {
196 #BSD
197 if date -u -d@$1 2>/dev/null ; then
198 return
199 fi
200
201 #Linux
202 if date -u -r $1 2>/dev/null ; then
203 return
204 fi
205
206}
207
44df2967 208_stat() {
209 #Linux
210 if stat -c '%U:%G' "$1" 2>/dev/null ; then
211 return
212 fi
213
214 #BSD
215 if stat -f '%Su:%Sg' "$1" 2>/dev/null ; then
216 return
217 fi
218}
219
4c3b3608 220_send_signed_request() {
221 url=$1
222 payload=$2
223 needbase64=$3
224
225 _debug url $url
226 _debug payload "$payload"
227
228 CURL_HEADER="$LE_WORKING_DIR/curl.header"
229 dp="$LE_WORKING_DIR/curl.dump"
230 CURL="curl --silent --dump-header $CURL_HEADER "
231 if [ "$DEBUG" ] ; then
232 CURL="$CURL --trace-ascii $dp "
233 fi
234 payload64=$(echo -n $payload | _base64 | _b64)
235 _debug payload64 $payload64
236
237 nonceurl="$API/directory"
238 nonce="$($CURL -I $nonceurl | grep -o "^Replay-Nonce:.*$" | tr -d "\r\n" | cut -d ' ' -f 2)"
239
240 _debug nonce "$nonce"
241
242 protected="$(printf "$HEADERPLACE" | sed "s/NONCE/$nonce/" )"
243 _debug protected "$protected"
244
245 protected64="$(printf "$protected" | _base64 | _b64)"
246 _debug protected64 "$protected64"
247
248 sig=$(echo -n "$protected64.$payload64" | openssl dgst -sha256 -sign $ACCOUNT_KEY_PATH | _base64 | _b64)
249 _debug sig "$sig"
250
251 body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
252 _debug body "$body"
253
254 if [ "$needbase64" ] ; then
255 response="$($CURL -X POST --data "$body" $url | _base64)"
256 else
257 response="$($CURL -X POST --data "$body" $url)"
258 fi
259
260 responseHeaders="$(cat $CURL_HEADER)"
261
262 _debug responseHeaders "$responseHeaders"
263 _debug response "$response"
264 code="$(grep ^HTTP $CURL_HEADER | tail -1 | cut -d " " -f 2 | tr -d "\r\n" )"
265 _debug code $code
266
267}
268
269_get() {
270 url="$1"
271 _debug url $url
272 response="$(curl --silent $url)"
273 ret=$?
274 _debug response "$response"
275 code="$(echo $response | grep -o '"status":[0-9]\+' | cut -d : -f 2)"
276 _debug code $code
277 return $ret
278}
279
280#setopt "file" "opt" "=" "value" [";"]
281_setopt() {
282 __conf="$1"
283 __opt="$2"
284 __sep="$3"
285 __val="$4"
286 __end="$5"
287 if [ -z "$__opt" ] ; then
288 echo usage: _setopt '"file" "opt" "=" "value" [";"]'
289 return
290 fi
291 if [ ! -f "$__conf" ] ; then
292 touch "$__conf"
293 fi
294
295 if grep -H -n "^$__opt$__sep" "$__conf" > /dev/null ; then
296 _debug OK
297 if [[ "$__val" == *"&"* ]] ; then
298 __val="$(echo $__val | sed 's/&/\\&/g')"
299 fi
300 text="$(cat $__conf)"
6dfaaa70 301 echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf"
4c3b3608 302
303 elif grep -H -n "^#$__opt$__sep" "$__conf" > /dev/null ; then
304 if [[ "$__val" == *"&"* ]] ; then
305 __val="$(echo $__val | sed 's/&/\\&/g')"
306 fi
307 text="$(cat $__conf)"
6dfaaa70 308 echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf"
4c3b3608 309
310 else
311 _debug APP
4c3b3608 312 echo "$__opt$__sep$__val$__end" >> "$__conf"
313 fi
314 _debug "$(grep -H -n "^$__opt$__sep" $__conf)"
315}
316
317#_savedomainconf key value
318#save to domain.conf
319_savedomainconf() {
320 key="$1"
321 value="$2"
322 if [ "$DOMAIN_CONF" ] ; then
323 _setopt $DOMAIN_CONF "$key" "=" "$value"
324 else
325 _err "DOMAIN_CONF is empty, can not save $key=$value"
326 fi
327}
328
329#_saveaccountconf key value
330_saveaccountconf() {
331 key="$1"
332 value="$2"
333 if [ "$ACCOUNT_CONF_PATH" ] ; then
334 _setopt $ACCOUNT_CONF_PATH "$key" "=" "$value"
335 else
336 _err "ACCOUNT_CONF_PATH is empty, can not save $key=$value"
337 fi
338}
339
340_startserver() {
341 content="$1"
1b2e940d 342 _NC="nc -q 1 -l"
343
344 nchelp="$(nc -h 2>&1)"
bce55f42 345 #centos
1b2e940d 346 if echo "$nchelp" | grep "nmap.org/ncat" >/dev/null ; then
347 _NC="nc -l"
4c3b3608 348 fi
1b2e940d 349
051c706d 350 _debug "$_NC $Le_HTTPPort"
4c3b3608 351# while true ; do
352 if [ "$DEBUG" ] ; then
3aff11f6 353 if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort -vv ; then
354 echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv ;
355 fi
4c3b3608 356 else
3aff11f6 357 if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null ; then
358 echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null
359 fi
4c3b3608 360 fi
051c706d 361 if [ "$?" != "0" ] ; then
362 _err "nc listen error."
363 return 1
364 fi
4c3b3608 365# done
366}
367
368_stopserver() {
369 pid="$1"
370
371}
372
373_initpath() {
374
375 if [ -z "$LE_WORKING_DIR" ]; then
376 LE_WORKING_DIR=$HOME/.le
377 fi
378
379 if [ -z "$ACCOUNT_CONF_PATH" ] ; then
380 ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf"
381 fi
382
383 if [ -f "$ACCOUNT_CONF_PATH" ] ; then
384 source "$ACCOUNT_CONF_PATH"
385 fi
386
387 if [ -z "$API" ] ; then
388 if [ -z "$STAGE" ] ; then
389 API="$DEFAULT_CA"
390 else
391 API="$STAGE_CA"
392 _info "Using stage api:$API"
393 fi
394 fi
395
396 if [ -z "$ACME_DIR" ] ; then
397 ACME_DIR="/home/.acme"
398 fi
399
400 if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then
401 APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR/"
402 fi
403
404 domain="$1"
405 if ! mkdir -p "$LE_WORKING_DIR" ; then
406 _err "Can not craete working dir: $LE_WORKING_DIR"
407 return 1
408 fi
409
410 if [ -z "$ACCOUNT_KEY_PATH" ] ; then
411 ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key"
412 fi
413
414 if [ -z "$domain" ] ; then
415 return 0
416 fi
417
418 domainhome="$LE_WORKING_DIR/$domain"
419 mkdir -p "$domainhome"
420
421 if [ -z "$DOMAIN_PATH" ] ; then
422 DOMAIN_PATH="$domainhome"
423 fi
424 if [ -z "$DOMAIN_CONF" ] ; then
1ad65f7d 425 DOMAIN_CONF="$domainhome/$domain.conf"
4c3b3608 426 fi
427
428 if [ -z "$DOMAIN_SSL_CONF" ] ; then
1ad65f7d 429 DOMAIN_SSL_CONF="$domainhome/$domain.ssl.conf"
4c3b3608 430 fi
431
432 if [ -z "$CSR_PATH" ] ; then
433 CSR_PATH="$domainhome/$domain.csr"
434 fi
435 if [ -z "$CERT_KEY_PATH" ] ; then
436 CERT_KEY_PATH="$domainhome/$domain.key"
437 fi
438 if [ -z "$CERT_PATH" ] ; then
439 CERT_PATH="$domainhome/$domain.cer"
440 fi
441 if [ -z "$CA_CERT_PATH" ] ; then
442 CA_CERT_PATH="$domainhome/ca.cer"
443 fi
caf1fc10 444 if [ -z "$CERT_FULLCHAIN_PATH" ] ; then
850db6d4 445 CERT_FULLCHAIN_PATH="$domainhome/fullchain.cer"
caf1fc10 446 fi
4c3b3608 447
448}
449
450
451_apachePath() {
452 httpdroot="$(apachectl -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )"
453 httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )"
454 httpdconf="$httpdroot/$httpdconfname"
455 if [ ! -f $httpdconf ] ; then
456 _err "Apache Config file not found" $httpdconf
457 return 1
458 fi
459 return 0
460}
461
462_restoreApache() {
463 if [ -z "$usingApache" ] ; then
464 return 0
465 fi
466 _initpath
467 if ! _apachePath ; then
468 return 1
469 fi
470
471 if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ] ; then
472 _debug "No config file to restore."
473 return 0
474 fi
475
476 cp -p "$APACHE_CONF_BACKUP_DIR/$httpdconfname" "$httpdconf"
477 if ! apachectl -t ; then
478 _err "Sorry, restore apache config error, please contact me."
479 return 1;
480 fi
481 rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname"
482 return 0
483}
484
485_setApache() {
486 _initpath
487 if ! _apachePath ; then
488 return 1
489 fi
490
491 #backup the conf
492 _debug "Backup apache config file" $httpdconf
493 cp -p $httpdconf $APACHE_CONF_BACKUP_DIR/
494 _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname"
495 _info "In case there is an error that can not be restored automatically, you may try restore it yourself."
496 _info "The backup file will be deleted on sucess, just forget it."
497
498 #add alias
499 echo "
500Alias /.well-known/acme-challenge $ACME_DIR
501
502<Directory $ACME_DIR >
503Require all granted
504</Directory>
505 " >> $httpdconf
506
507 if ! apachectl -t ; then
508 _err "Sorry, apache config error, please contact me."
509 _restoreApache
510 return 1;
511 fi
512
513 if [ ! -d "$ACME_DIR" ] ; then
514 mkdir -p "$ACME_DIR"
515 chmod 755 "$ACME_DIR"
516 fi
517
518 if ! apachectl graceful ; then
519 _err "Sorry, apachectl graceful error, please contact me."
520 _restoreApache
521 return 1;
522 fi
523 usingApache="1"
524 return 0
525}
526
527_clearup () {
528 _stopserver $serverproc
529 serverproc=""
530 _restoreApache
531}
532
533# webroot removelevel tokenfile
534_clearupwebbroot() {
535 __webroot="$1"
536 if [ -z "$__webroot" ] ; then
537 _debug "no webroot specified, skip"
538 return 0
539 fi
540
541 if [ "$2" == '1' ] ; then
542 _debug "remove $__webroot/.well-known"
543 rm -rf "$__webroot/.well-known"
544 elif [ "$2" == '2' ] ; then
545 _debug "remove $__webroot/.well-known/acme-challenge"
546 rm -rf "$__webroot/.well-known/acme-challenge"
547 elif [ "$2" == '3' ] ; then
548 _debug "remove $__webroot/.well-known/acme-challenge/$3"
549 rm -rf "$__webroot/.well-known/acme-challenge/$3"
550 else
551 _info "Skip for removelevel:$2"
552 fi
553
554 return 0
555
556}
557
558issue() {
559 if [ -z "$2" ] ; then
560 _err "Usage: le issue webroot|no|apache|dns a.com [www.a.com,b.com,c.com]|no [key-length]|no"
561 return 1
562 fi
563 Le_Webroot="$1"
564 Le_Domain="$2"
565 Le_Alt="$3"
566 Le_Keylength="$4"
567 Le_RealCertPath="$5"
568 Le_RealKeyPath="$6"
569 Le_RealCACertPath="$7"
570 Le_ReloadCmd="$8"
571
572
573 _initpath $Le_Domain
574
575 if [ -f "$DOMAIN_CONF" ] ; then
576 Le_NextRenewTime=$(grep "^Le_NextRenewTime=" "$DOMAIN_CONF" | cut -d '=' -f 2)
577 if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then
578 _info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)"
579 return 2
580 fi
581 fi
582
583 if [ "$Le_Alt" == "no" ] ; then
584 Le_Alt=""
585 fi
586 if [ "$Le_Keylength" == "no" ] ; then
587 Le_Keylength=""
588 fi
589 if [ "$Le_RealCertPath" == "no" ] ; then
590 Le_RealCertPath=""
591 fi
592 if [ "$Le_RealKeyPath" == "no" ] ; then
593 Le_RealKeyPath=""
594 fi
595 if [ "$Le_RealCACertPath" == "no" ] ; then
596 Le_RealCACertPath=""
597 fi
598 if [ "$Le_ReloadCmd" == "no" ] ; then
599 Le_ReloadCmd=""
600 fi
601
602 _setopt "$DOMAIN_CONF" "Le_Domain" "=" "$Le_Domain"
603 _setopt "$DOMAIN_CONF" "Le_Alt" "=" "$Le_Alt"
604 _setopt "$DOMAIN_CONF" "Le_Webroot" "=" "$Le_Webroot"
605 _setopt "$DOMAIN_CONF" "Le_Keylength" "=" "$Le_Keylength"
606 _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\""
607 _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\""
608 _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\""
609 _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\""
610
611 if [ "$Le_Webroot" == "no" ] ; then
612 _info "Standalone mode."
613 if ! command -v "nc" > /dev/null ; then
614 _err "Please install netcat(nc) tools first."
615 return 1
616 fi
617
618 if [ -z "$Le_HTTPPort" ] ; then
619 Le_HTTPPort=80
620 fi
621 _setopt "$DOMAIN_CONF" "Le_HTTPPort" "=" "$Le_HTTPPort"
622
623 netprc="$(ss -ntpl | grep :$Le_HTTPPort" ")"
624 if [ "$netprc" ] ; then
625 _err "$netprc"
626 _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)"
627 _err "Please stop it first"
628 return 1
629 fi
630 fi
631
632 if [ "$Le_Webroot" == "apache" ] ; then
633 if ! _setApache ; then
634 _err "set up apache error. Report error to me."
635 return 1
636 fi
637 wellknown_path="$ACME_DIR"
638 else
639 usingApache=""
640 fi
641
642 createAccountKey $Le_Domain $Le_Keylength
643
644 if ! createDomainKey $Le_Domain $Le_Keylength ; then
645 _err "Create domain key error."
646 return 1
647 fi
648
649 if ! createCSR $Le_Domain $Le_Alt ; then
650 _err "Create CSR error."
651 return 1
652 fi
653
654 pub_exp=$(openssl rsa -in $ACCOUNT_KEY_PATH -noout -text | grep "^publicExponent:"| cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
655 if [ "${#pub_exp}" == "5" ] ; then
656 pub_exp=0$pub_exp
657 fi
658 _debug pub_exp "$pub_exp"
659
660 e=$(echo $pub_exp | _h2b | _base64)
661 _debug e "$e"
662
663 modulus=$(openssl rsa -in $ACCOUNT_KEY_PATH -modulus -noout | cut -d '=' -f 2 )
664 n=$(echo $modulus| _h2b | _base64 | _b64 )
665
666 jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}'
667
668 HEADER='{"alg": "RS256", "jwk": '$jwk'}'
669 HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}'
670 _debug HEADER "$HEADER"
671
672 accountkey_json=$(echo -n "$jwk" | tr -d ' ' )
673 thumbprint=$(echo -n "$accountkey_json" | openssl dgst -sha256 -binary | _base64 | _b64)
674
675
676 _info "Registering account"
677 regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}'
678 if [ "$ACCOUNT_EMAIL" ] ; then
679 regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}'
680 fi
681 _send_signed_request "$API/acme/new-reg" "$regjson"
682
683 if [ "$code" == "" ] || [ "$code" == '201' ] ; then
684 _info "Registered"
685 echo $response > $LE_WORKING_DIR/account.json
686 elif [ "$code" == '409' ] ; then
687 _info "Already registered"
688 else
689 _err "Register account Error."
690 _clearup
691 return 1
692 fi
693
694 vtype="$VTYPE_HTTP"
695 if [[ "$Le_Webroot" == "dns"* ]] ; then
696 vtype="$VTYPE_DNS"
697 fi
698
699 vlist="$Le_Vlist"
700 # verify each domain
701 _info "Verify each domain"
702 sep='#'
703 if [ -z "$vlist" ] ; then
704 alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' )
705 for d in $alldomains
706 do
707 _info "Getting token for domain" $d
708 _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}"
709 if [ ! -z "$code" ] && [ ! "$code" == '201' ] ; then
710 _err "new-authz error: $response"
711 _clearup
712 return 1
713 fi
714
348cddd7 715 entry="$(printf $response | egrep -o '\{[^{]*"type":"'$vtype'"[^}]*')"
4c3b3608 716 _debug entry "$entry"
717
718 token="$(printf "$entry" | egrep -o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
719 _debug token $token
720
721 uri="$(printf "$entry" | egrep -o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )"
722 _debug uri $uri
723
724 keyauthorization="$token.$thumbprint"
725 _debug keyauthorization "$keyauthorization"
726
727 dvlist="$d$sep$keyauthorization$sep$uri"
728 _debug dvlist "$dvlist"
729
730 vlist="$vlist$dvlist,"
731
732 done
733
734 #add entry
735 dnsadded=""
736 ventries=$(echo "$vlist" | tr ',' ' ' )
737 for ventry in $ventries
738 do
739 d=$(echo $ventry | cut -d $sep -f 1)
740 keyauthorization=$(echo $ventry | cut -d $sep -f 2)
741
742 if [ "$vtype" == "$VTYPE_DNS" ] ; then
743 dnsadded='0'
744 txtdomain="_acme-challenge.$d"
745 _debug txtdomain "$txtdomain"
746 txt="$(echo -e -n $keyauthorization | openssl dgst -sha256 -binary | _base64 | _b64)"
747 _debug txt "$txt"
748 #dns
749 #1. check use api
750 d_api=""
751 if [ -f "$LE_WORKING_DIR/$d/$Le_Webroot" ] ; then
752 d_api="$LE_WORKING_DIR/$d/$Le_Webroot"
753 elif [ -f "$LE_WORKING_DIR/$d/$Le_Webroot.sh" ] ; then
754 d_api="$LE_WORKING_DIR/$d/$Le_Webroot.sh"
755 elif [ -f "$LE_WORKING_DIR/$Le_Webroot" ] ; then
756 d_api="$LE_WORKING_DIR/$Le_Webroot"
757 elif [ -f "$LE_WORKING_DIR/$Le_Webroot.sh" ] ; then
758 d_api="$LE_WORKING_DIR/$Le_Webroot.sh"
759 elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot" ] ; then
760 d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot"
761 elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" ] ; then
762 d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh"
763 fi
764 _debug d_api "$d_api"
765
766 if [ "$d_api" ]; then
767 _info "Found domain api file: $d_api"
768 else
769 _err "Add the following TXT record:"
770 _err "Domain: $txtdomain"
771 _err "TXT value: $txt"
772 _err "Please be aware that you prepend _acme-challenge. before your domain"
773 _err "so the resulting subdomain will be: $txtdomain"
774 continue
775 fi
776
777 if ! source $d_api ; then
778 _err "Load file $d_api error. Please check your api file and try again."
779 return 1
780 fi
781
782 addcommand="$Le_Webroot-add"
783 if ! command -v $addcommand ; then
f8ad8f34 784 _err "It seems that your api file is not correct, it must have a function named: $addcommand"
4c3b3608 785 return 1
786 fi
787
788 if ! $addcommand $txtdomain $txt ; then
789 _err "Error add txt for domain:$txtdomain"
790 return 1
791 fi
792 dnsadded='1'
793 fi
794 done
795
796 if [ "$dnsadded" == '0' ] ; then
797 _setopt "$DOMAIN_CONF" "Le_Vlist" "=" "\"$vlist\""
798 _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
799 _err "Please add the TXT records to the domains, and retry again."
800 return 1
801 fi
802
803 fi
804
805 if [ "$dnsadded" == '1' ] ; then
806 _info "Sleep 60 seconds for the txt records to take effect"
807 sleep 60
808 fi
809
810 _debug "ok, let's start to verify"
811 ventries=$(echo "$vlist" | tr ',' ' ' )
812 for ventry in $ventries
813 do
814 d=$(echo $ventry | cut -d $sep -f 1)
815 keyauthorization=$(echo $ventry | cut -d $sep -f 2)
816 uri=$(echo $ventry | cut -d $sep -f 3)
817 _info "Verifying:$d"
818 _debug "d" "$d"
819 _debug "keyauthorization" "$keyauthorization"
820 _debug "uri" "$uri"
821 removelevel=""
822 token=""
823 if [ "$vtype" == "$VTYPE_HTTP" ] ; then
824 if [ "$Le_Webroot" == "no" ] ; then
825 _info "Standalone mode server"
826 _startserver "$keyauthorization" &
827 serverproc="$!"
828 sleep 2
829 _debug serverproc $serverproc
830 else
831 if [ -z "$wellknown_path" ] ; then
832 wellknown_path="$Le_Webroot/.well-known/acme-challenge"
833 fi
834 _debug wellknown_path "$wellknown_path"
835
836 if [ ! -d "$Le_Webroot/.well-known" ] ; then
837 removelevel='1'
838 elif [ ! -d "$Le_Webroot/.well-known/acme-challenge" ] ; then
839 removelevel='2'
840 else
841 removelevel='3'
842 fi
843
844 token="$(echo -e -n "$keyauthorization" | cut -d '.' -f 1)"
845 _debug "writing token:$token to $wellknown_path/$token"
846
847 mkdir -p "$wellknown_path"
848 echo -n "$keyauthorization" > "$wellknown_path/$token"
849
44df2967 850 webroot_owner=$(_stat $Le_Webroot)
4c3b3608 851 _debug "Changing owner/group of .well-known to $webroot_owner"
852 chown -R $webroot_owner "$Le_Webroot/.well-known"
853
854 fi
855 fi
856
857 _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"
858
859 if [ ! -z "$code" ] && [ ! "$code" == '202' ] ; then
860 _err "$d:Challenge error: $resource"
861 _clearupwebbroot "$Le_Webroot" "$removelevel" "$token"
862 _clearup
863 return 1
864 fi
865
866 while [ "1" ] ; do
867 _debug "sleep 5 secs to verify"
868 sleep 5
869 _debug "checking"
870
871 if ! _get $uri ; then
872 _err "$d:Verify error:$resource"
873 _clearupwebbroot "$Le_Webroot" "$removelevel" "$token"
874 _clearup
875 return 1
876 fi
877
878 status=$(echo $response | egrep -o '"status":"[^"]+"' | cut -d : -f 2 | tr -d '"')
879 if [ "$status" == "valid" ] ; then
880 _info "Success"
881 _stopserver $serverproc
882 serverproc=""
883 _clearupwebbroot "$Le_Webroot" "$removelevel" "$token"
884 break;
885 fi
886
887 if [ "$status" == "invalid" ] ; then
888 error=$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4)
889 _err "$d:Verify error:$error"
890 _clearupwebbroot "$Le_Webroot" "$removelevel" "$token"
891 _clearup
892 return 1;
893 fi
894
895 if [ "$status" == "pending" ] ; then
896 _info "Pending"
897 else
898 _err "$d:Verify error:$response"
899 _clearupwebbroot "$Le_Webroot" "$removelevel" "$token"
900 _clearup
901 return 1
902 fi
903
904 done
905
906 done
907
908 _clearup
909 _info "Verify finished, start to sign."
910 der="$(openssl req -in $CSR_PATH -outform DER | _base64 | _b64)"
911 _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"
912
913
914 Le_LinkCert="$(grep -i -o '^Location.*$' $CURL_HEADER | tr -d "\r\n" | cut -d " " -f 2)"
915 _setopt "$DOMAIN_CONF" "Le_LinkCert" "=" "$Le_LinkCert"
916
917 if [ "$Le_LinkCert" ] ; then
918 echo -----BEGIN CERTIFICATE----- > "$CERT_PATH"
919 curl --silent "$Le_LinkCert" | openssl base64 -e >> "$CERT_PATH"
920 echo -----END CERTIFICATE----- >> "$CERT_PATH"
921 _info "Cert success."
922 cat "$CERT_PATH"
923
924 _info "Your cert is in $CERT_PATH"
caf1fc10 925 cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH"
4c3b3608 926 fi
927
928
929 if [ -z "$Le_LinkCert" ] ; then
930 response="$(echo $response | openssl base64 -d -A)"
931 _err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')"
932 return 1
933 fi
934
935 _setopt "$DOMAIN_CONF" 'Le_Vlist' '=' "\"\""
936
937 Le_LinkIssuer=$(grep -i '^Link' $CURL_HEADER | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' )
938 _setopt "$DOMAIN_CONF" "Le_LinkIssuer" "=" "$Le_LinkIssuer"
939
940 if [ "$Le_LinkIssuer" ] ; then
941 echo -----BEGIN CERTIFICATE----- > "$CA_CERT_PATH"
942 curl --silent "$Le_LinkIssuer" | openssl base64 -e >> "$CA_CERT_PATH"
943 echo -----END CERTIFICATE----- >> "$CA_CERT_PATH"
944 _info "The intermediate CA cert is in $CA_CERT_PATH"
caf1fc10 945 cat "$CA_CERT_PATH" >> "$CERT_FULLCHAIN_PATH"
946 _info "And the full chain certs is there: $CERT_FULLCHAIN_PATH"
4c3b3608 947 fi
948
949 Le_CertCreateTime=$(date -u "+%s")
950 _setopt "$DOMAIN_CONF" "Le_CertCreateTime" "=" "$Le_CertCreateTime"
951
952 Le_CertCreateTimeStr=$(date -u )
953 _setopt "$DOMAIN_CONF" "Le_CertCreateTimeStr" "=" "\"$Le_CertCreateTimeStr\""
954
955 if [ ! "$Le_RenewalDays" ] ; then
956 Le_RenewalDays=80
957 fi
958
959 _setopt "$DOMAIN_CONF" "Le_RenewalDays" "=" "$Le_RenewalDays"
960
961 let "Le_NextRenewTime=Le_CertCreateTime+Le_RenewalDays*24*60*60"
962 _setopt "$DOMAIN_CONF" "Le_NextRenewTime" "=" "$Le_NextRenewTime"
963
964 Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime )
965 _setopt "$DOMAIN_CONF" "Le_NextRenewTimeStr" "=" "\"$Le_NextRenewTimeStr\""
966
967
968 installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd"
969
970}
971
972renew() {
973 Le_Domain="$1"
974 if [ -z "$Le_Domain" ] ; then
975 _err "Usage: $0 domain.com"
976 return 1
977 fi
978
979 _initpath $Le_Domain
980
981 if [ ! -f "$DOMAIN_CONF" ] ; then
982 _info "$Le_Domain is not a issued domain, skip."
983 return 0;
984 fi
985
986 source "$DOMAIN_CONF"
987 if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then
988 _info "Skip, Next renewal time is: $Le_NextRenewTimeStr"
989 return 2
990 fi
991
992 IS_RENEW="1"
993 issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd"
994 local res=$?
995 IS_RENEW=""
996
997 return $res
998}
999
1000renewAll() {
1001 _initpath
1002 _info "renewAll"
1003
1004 for d in $(ls -F $LE_WORKING_DIR | grep [^.].*[.].*/$ ) ; do
1005 d=$(echo $d | cut -d '/' -f 1)
1006 _info "renew $d"
1007
1008 Le_LinkCert=""
1009 Le_Domain=""
1010 Le_Alt=""
1011 Le_Webroot=""
1012 Le_Keylength=""
1013 Le_LinkIssuer=""
1014
1015 Le_CertCreateTime=""
1016 Le_CertCreateTimeStr=""
1017 Le_RenewalDays=""
1018 Le_NextRenewTime=""
1019 Le_NextRenewTimeStr=""
1020
1021 Le_RealCertPath=""
1022 Le_RealKeyPath=""
1023
1024 Le_RealCACertPath=""
1025
1026 Le_ReloadCmd=""
1027
1028 DOMAIN_PATH=""
1029 DOMAIN_CONF=""
1030 DOMAIN_SSL_CONF=""
1031 CSR_PATH=""
1032 CERT_KEY_PATH=""
1033 CERT_PATH=""
1034 CA_CERT_PATH=""
caf1fc10 1035 CERT_FULLCHAIN_PATH=""
4c3b3608 1036 ACCOUNT_KEY_PATH=""
1037
1038 wellknown_path=""
1039
1040 renew "$d"
1041 done
1042
1043}
1044
1045installcert() {
1046 Le_Domain="$1"
1047 if [ -z "$Le_Domain" ] ; then
1048 _err "Usage: $0 domain.com [cert-file-path]|no [key-file-path]|no [ca-cert-file-path]|no [reloadCmd]|no"
1049 return 1
1050 fi
1051
1052 Le_RealCertPath="$2"
1053 Le_RealKeyPath="$3"
1054 Le_RealCACertPath="$4"
1055 Le_ReloadCmd="$5"
1056
1057 _initpath $Le_Domain
1058
1059 _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\""
1060 _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\""
1061 _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\""
1062 _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\""
1063
1064 if [ "$Le_RealCertPath" ] ; then
1065 if [ -f "$Le_RealCertPath" ] ; then
1066 cp -p "$Le_RealCertPath" "$Le_RealCertPath".bak
1067 fi
1068 cat "$CERT_PATH" > "$Le_RealCertPath"
1069 fi
1070
1071 if [ "$Le_RealCACertPath" ] ; then
1072 if [ -f "$Le_RealCACertPath" ] ; then
1073 cp -p "$Le_RealCACertPath" "$Le_RealCACertPath".bak
1074 fi
1075 if [ "$Le_RealCACertPath" == "$Le_RealCertPath" ] ; then
1076 echo "" >> "$Le_RealCACertPath"
1077 cat "$CA_CERT_PATH" >> "$Le_RealCACertPath"
1078 else
1079 cat "$CA_CERT_PATH" > "$Le_RealCACertPath"
1080 fi
1081 fi
1082
1083
1084 if [ "$Le_RealKeyPath" ] ; then
1085 if [ -f "$Le_RealKeyPath" ] ; then
1086 cp -p "$Le_RealKeyPath" "$Le_RealKeyPath".bak
1087 fi
1088 cat "$CERT_KEY_PATH" > "$Le_RealKeyPath"
1089 fi
1090
1091 if [ "$Le_ReloadCmd" ] ; then
1092 _info "Run Le_ReloadCmd: $Le_ReloadCmd"
1093 (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd")
1094 fi
1095
1096}
1097
1098installcronjob() {
1099 _initpath
1100 _info "Installing cron job"
1101 if ! crontab -l | grep 'le.sh cron' ; then
1102 if [ -f "$LE_WORKING_DIR/le.sh" ] ; then
1103 lesh="\"$LE_WORKING_DIR\"/le.sh"
1104 else
1105 _err "Can not install cronjob, le.sh not found."
1106 return 1
1107 fi
1108 crontab -l | { cat; echo "0 0 * * * LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null"; } | crontab -
1109 fi
1110 if [ "$?" != "0" ] ; then
1111 _err "Install cron job failed. You need to manually renew your certs."
1112 _err "Or you can add cronjob by yourself:"
1113 _err "LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null"
1114 return 1
1115 fi
1116}
1117
1118uninstallcronjob() {
1119 _info "Removing cron job"
1120 cr="$(crontab -l | grep 'le.sh cron')"
1121 if [ "$cr" ] ; then
1122 crontab -l | sed "/le.sh cron/d" | crontab -
1123 LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 6 | cut -d '=' -f 2 | tr -d '"')"
1124 _info LE_WORKING_DIR "$LE_WORKING_DIR"
1125 fi
1126 _initpath
1127
1128}
1129
1130
1131# Detect profile file if not specified as environment variable
1132_detect_profile() {
1133 if [ -n "$PROFILE" -a -f "$PROFILE" ]; then
1134 echo "$PROFILE"
1135 return
1136 fi
1137
1138 local DETECTED_PROFILE
1139 DETECTED_PROFILE=''
1140 local SHELLTYPE
1141 SHELLTYPE="$(basename "/$SHELL")"
1142
1143 if [ "$SHELLTYPE" = "bash" ]; then
1144 if [ -f "$HOME/.bashrc" ]; then
1145 DETECTED_PROFILE="$HOME/.bashrc"
1146 elif [ -f "$HOME/.bash_profile" ]; then
1147 DETECTED_PROFILE="$HOME/.bash_profile"
1148 fi
1149 elif [ "$SHELLTYPE" = "zsh" ]; then
1150 DETECTED_PROFILE="$HOME/.zshrc"
1151 fi
1152
1153 if [ -z "$DETECTED_PROFILE" ]; then
1154 if [ -f "$HOME/.profile" ]; then
1155 DETECTED_PROFILE="$HOME/.profile"
1156 elif [ -f "$HOME/.bashrc" ]; then
1157 DETECTED_PROFILE="$HOME/.bashrc"
1158 elif [ -f "$HOME/.bash_profile" ]; then
1159 DETECTED_PROFILE="$HOME/.bash_profile"
1160 elif [ -f "$HOME/.zshrc" ]; then
1161 DETECTED_PROFILE="$HOME/.zshrc"
1162 fi
1163 fi
1164
1165 if [ ! -z "$DETECTED_PROFILE" ]; then
1166 echo "$DETECTED_PROFILE"
1167 fi
1168}
1169
1170_initconf() {
1171 _initpath
1172 if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then
1173 echo "#Account configurations:
1174#Here are the supported macros, uncomment them to make them take effect.
1175#ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account.
5fd3f21b 1176#ACCOUNT_KEY_PATH=\"/path/to/account.key\"
4c3b3608 1177
1178#STAGE=1 # Use the staging api
1179#FORCE=1 # Force to issue cert
1180#DEBUG=1 # Debug mode
1181
1182#dns api
1183#######################
1184#Cloudflare:
1185#api key
3d49985a 1186#CF_Key=\"sdfsdfsdfljlbjkljlkjsdfoiwje\"
4c3b3608 1187#account email
3d49985a 1188#CF_Email=\"xxxx@sss.com\"
4c3b3608 1189
1190#######################
1191#Dnspod.cn:
1192#api key id
3d49985a 1193#DP_Id=\"1234\"
4c3b3608 1194#api key
3d49985a 1195#DP_Key=\"sADDsdasdgdsf\"
4c3b3608 1196
1197#######################
1198#Cloudxns.com:
3d49985a 1199#CX_Key=\"1234\"
4c3b3608 1200#
3d49985a 1201#CX_Secret=\"sADDsdasdgdsf\"
4c3b3608 1202
1203 " > $ACCOUNT_CONF_PATH
1204 fi
1205}
1206
1207install() {
1208 if ! _initpath ; then
1209 _err "Install failed."
1210 return 1
1211 fi
1212
1213 #check if there is sudo installed, AND if the current user is a sudoer.
1214 if command -v sudo > /dev/null ; then
1215 if [ "$(sudo -n uptime 2>&1|grep "load"|wc -l)" != "0" ] ; then
1216 SUDO=sudo
1217 fi
1218 fi
1219
1220 if command -v yum > /dev/null ; then
1221 YUM="1"
1222 INSTALL="$SUDO yum install -y "
1223 elif command -v apt-get > /dev/null ; then
1224 INSTALL="$SUDO apt-get install -y "
1225 fi
1226
1227 if ! command -v "curl" > /dev/null ; then
1228 _err "Please install curl first."
1229 _err "$INSTALL curl"
1230 return 1
1231 fi
1232
1233 if ! command -v "crontab" > /dev/null ; then
1234 _err "Please install crontab first."
1235 if [ "$YUM" ] ; then
1236 _err "$INSTALL crontabs"
1237 else
1238 _err "$INSTALL crontab"
1239 fi
1240 return 1
1241 fi
1242
1243 if ! command -v "openssl" > /dev/null ; then
1244 _err "Please install openssl first."
1245 _err "$INSTALL openssl"
1246 return 1
1247 fi
1248
1249 _info "Installing to $LE_WORKING_DIR"
1250
1251 cp le.sh "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/le.sh"
1252
1253 if [ "$?" != "0" ] ; then
1254 _err "Install failed, can not copy le.sh"
1255 return 1
1256 fi
1257
1258 _info "Installed to $LE_WORKING_DIR/le.sh"
1259
1260 _profile="$(_detect_profile)"
1261 if [ "$_profile" ] ; then
1262 _debug "Found profile: $_profile"
1263
1264 echo "LE_WORKING_DIR=$LE_WORKING_DIR
1265alias le=\"$LE_WORKING_DIR/le.sh\"
1266alias le.sh=\"$LE_WORKING_DIR/le.sh\"
1267 " > "$LE_WORKING_DIR/le.env"
b86869a0 1268 echo "" >> "$_profile"
4c3b3608 1269 _setopt "$_profile" "source \"$LE_WORKING_DIR/le.env\""
1270 _info "OK, Close and reopen your terminal to start using le"
1271 else
1272 _info "No profile is found, you will need to go into $LE_WORKING_DIR to use le.sh"
1273 fi
1274
1275 mkdir -p $LE_WORKING_DIR/dnsapi
1276 cp dnsapi/* $LE_WORKING_DIR/dnsapi/
1277
1278 #to keep compatible mv the .acc file to .key file
1279 if [ -f "$LE_WORKING_DIR/account.acc" ] ; then
1280 mv "$LE_WORKING_DIR/account.acc" "$LE_WORKING_DIR/account.key"
1281 fi
1282
1283 installcronjob
1284
1285 if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then
1286 _initconf
1287 fi
1288 _info OK
1289}
1290
1291uninstall() {
1292 uninstallcronjob
1293 _initpath
1294
1295 _profile="$(_detect_profile)"
1296 if [ "$_profile" ] ; then
7203a1c1 1297 text="$(cat $_profile)"
1298 echo "$text" | sed "s|^source.*le.env.*$||" > "$_profile"
4c3b3608 1299 fi
1300
1301 rm -f $LE_WORKING_DIR/le.sh
1302 _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself."
1303
1304}
1305
1306cron() {
1307 renewAll
1308}
1309
1310version() {
1311 _info "$PROJECT"
1312 _info "v$VER"
1313}
1314
1315showhelp() {
1316 version
1317 echo "Usage: le.sh [command] ...[args]....
1318Avalible commands:
1319
1320install:
1321 Install le.sh to your system.
1322issue:
1323 Issue a cert.
1324installcert:
1325 Install the issued cert to apache/nginx or any other server.
1326renew:
1327 Renew a cert.
1328renewAll:
1329 Renew all the certs.
1330uninstall:
1331 Uninstall le.sh, and uninstall the cron job.
1332version:
1333 Show version info.
1334installcronjob:
1335 Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
1336uninstallcronjob:
1337 Uninstall the cron job. The 'uninstall' command can do this automatically.
1338createAccountKey:
1339 Create an account private key, professional use.
1340createDomainKey:
1341 Create an domain private key, professional use.
1342createCSR:
1343 Create CSR , professional use.
1344 "
1345}
1346
1347
1348if [ -z "$1" ] ; then
1349 showhelp
1350else
1351 "$@"
1352fi