mirror of
https://github.com/acmesh-official/acme.sh.git
synced 2025-06-15 19:52:43 +00:00
Merge pull request #1 from Neilpang/master
Merge Neilpang/le into raunsbaekdk/le
This commit is contained in:
commit
0ac62ff701
51
README.md
51
README.md
@ -11,6 +11,7 @@ Do NOT require to be `root/sudoer`.
|
||||
#Tested OS
|
||||
1. Ubuntu/Debian.
|
||||
2. CentOS
|
||||
3. Windows (cygwin with curl, openssl and crontab included)
|
||||
|
||||
|
||||
#Supported Mode
|
||||
@ -27,14 +28,15 @@ Do NOT require to be `root/sudoer`.
|
||||
```
|
||||
./le.sh install
|
||||
```
|
||||
You don't have to be root then, altough it is recommended.
|
||||
You don't have to be root then, although it is recommended.
|
||||
|
||||
Which does 3 jobs:
|
||||
* create and copy `le.sh` to your home dir: `~/.le`
|
||||
All the certs will be placed in this folder.
|
||||
* create symbol link: `/usr/local/bin/le -> ~/.le/le.sh` . (You must be root to do so.)
|
||||
* create alias : `le.sh=~/.le/le.sh` and `le=~/.le/le.sh`.
|
||||
* create everyday cron job to check and renew the cert if needed.
|
||||
|
||||
After install, you must close current terminal and reopen again to make the alias take effect.
|
||||
|
||||
Ok, you are ready to issue cert now.
|
||||
Show help message:
|
||||
@ -43,7 +45,7 @@ root@v1:~# le.sh
|
||||
https://github.com/Neilpang/le
|
||||
v1.1.1
|
||||
Usage: le.sh [command] ...[args]....
|
||||
Avalible commands:
|
||||
Available commands:
|
||||
|
||||
install:
|
||||
Install le.sh to your system.
|
||||
@ -104,7 +106,7 @@ The issued cert will be renewed every 80 days automatically.
|
||||
|
||||
# Install issued cert to apache/nginx etc.
|
||||
```
|
||||
le installcert aa.com /path/to/certfile/in/apache/nginx /path/to/keyfile/in/apache/nginx /path/to/ca/certfile/apahce/nginx "service apache2|nginx reload"
|
||||
le installcert aa.com /path/to/certfile/in/apache/nginx /path/to/keyfile/in/apache/nginx /path/to/ca/certfile/apache/nginx "service apache2|nginx reload"
|
||||
```
|
||||
|
||||
Install the issued cert/key to the production apache or nginx path.
|
||||
@ -139,9 +141,6 @@ Support the latest dns-01 challenge.
|
||||
le issue dns aa.com www.aa.com,user.aa.com
|
||||
```
|
||||
|
||||
Use domain api to automatically add dns record is not finished yet.
|
||||
So, you must manually add the txt record to finish verifying.
|
||||
|
||||
You will get the output like bellow:
|
||||
```
|
||||
Add the following txt record:
|
||||
@ -164,6 +163,42 @@ le renew aa.com
|
||||
Ok, it's finished.
|
||||
|
||||
|
||||
#Automatic dns api integeration
|
||||
|
||||
If your dns provider supports api access, we can use api to automatically issue certs.
|
||||
You don't have do anything manually.
|
||||
|
||||
###Currently we support:
|
||||
|
||||
1. Cloudflare.com api
|
||||
2. Dnspod.cn api
|
||||
3. Cloudxns.com api
|
||||
|
||||
More apis are comming soon....
|
||||
|
||||
If your dns provider is not in the supported list above, you can write your own script api easily.
|
||||
|
||||
For more details: [How to use dns api](dnsapi)
|
||||
|
||||
|
||||
# Issue ECC certificate:
|
||||
LetsEncrypt now can issue ECDSA certificate.
|
||||
And we also support it.
|
||||
|
||||
Just set key length to the `length` paramiter with a prefix "ec-".
|
||||
For example:
|
||||
```
|
||||
le issue /home/wwwroot/aa.com aa.com www.aa.com ec-256
|
||||
```
|
||||
Please look at the last parameter above.
|
||||
|
||||
Valid values are:
|
||||
|
||||
1. ec-256 (prime256v1, "ECDSA P-256")
|
||||
2. ec-384 (secp384r1, "ECDSA P-384")
|
||||
3. ec-521 (secp521r1, "ECDSA P-521", not supported by letsencrypt yet.)
|
||||
|
||||
|
||||
|
||||
#Under the Hood
|
||||
|
||||
@ -185,7 +220,7 @@ License is GPLv3
|
||||
|
||||
Please Star and Fork me.
|
||||
|
||||
Issues and pullrequests are welcomed.
|
||||
Issues and pull requests are welcomed.
|
||||
|
||||
|
||||
|
||||
|
86
dnsapi/README.md
Normal file
86
dnsapi/README.md
Normal file
@ -0,0 +1,86 @@
|
||||
# How to use dns api
|
||||
|
||||
## Use CloudFlare domain api to automatically issue cert
|
||||
|
||||
For now, we support clourflare integeration.
|
||||
|
||||
First you need to login to your clourflare account to get your api key.
|
||||
|
||||
```
|
||||
export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
|
||||
export CF_Email="xxxx@sss.com"
|
||||
|
||||
```
|
||||
|
||||
Ok, let's issue cert now:
|
||||
```
|
||||
le.sh issue dns-cf aa.com www.aa.com
|
||||
```
|
||||
|
||||
The `CF_Key` and `CF_Email` will be saved in `~/.le/account.conf`, when next time you use cloudflare api, it will reuse this key.
|
||||
|
||||
|
||||
|
||||
## Use Dnspod.cn domain api to automatically issue cert
|
||||
|
||||
For now, we support dnspod.cn integeration.
|
||||
|
||||
First you need to login to your dnspod.cn account to get your api key and key id.
|
||||
|
||||
```
|
||||
export DP_Id="1234"
|
||||
|
||||
export DP_Key="sADDsdasdgdsf"
|
||||
|
||||
```
|
||||
|
||||
Ok, let's issue cert now:
|
||||
```
|
||||
le.sh issue dns-dp aa.com www.aa.com
|
||||
```
|
||||
|
||||
The `DP_Id` and `DP_Key` will be saved in `~/.le/account.conf`, when next time you use dnspod.cn api, it will reuse this key.
|
||||
|
||||
|
||||
## Use Cloudxns.com domain api to automatically issue cert
|
||||
|
||||
For now, we support Cloudxns.com integeration.
|
||||
|
||||
First you need to login to your Cloudxns.com account to get your api key and key secret.
|
||||
|
||||
```
|
||||
export CX_Key="1234"
|
||||
|
||||
export CX_Secret="sADDsdasdgdsf"
|
||||
|
||||
```
|
||||
|
||||
Ok, let's issue cert now:
|
||||
```
|
||||
le.sh issue dns-cx aa.com www.aa.com
|
||||
```
|
||||
|
||||
The `CX_Key` and `CX_Secret` will be saved in `~/.le/account.conf`, when next time you use Cloudxns.com api, it will reuse this key.
|
||||
|
||||
|
||||
|
||||
# Use custom api
|
||||
|
||||
If your api is not supported yet, you can write your own dns api.
|
||||
|
||||
Let's assume you want to name it 'myapi',
|
||||
|
||||
1. Create a bash script named `~/.le/dns-myapi.sh`,
|
||||
2. In the scrypt, you must have a function named `dns-myapi-add()`. Which will be called by le.sh to add dns records.
|
||||
3. Then you can use your api to issue cert like:
|
||||
|
||||
```
|
||||
le.sh issue dns-myapi aa.com www.aa.com
|
||||
```
|
||||
|
||||
For more details, please check our sample script: [dns-myapi.sh](dns-myapi.sh)
|
||||
|
||||
|
||||
|
||||
|
168
dnsapi/dns-cf.sh
Executable file
168
dnsapi/dns-cf.sh
Executable file
@ -0,0 +1,168 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
#
|
||||
#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
#CF_Email="xxxx@sss.com"
|
||||
|
||||
|
||||
CF_Api="https://api.cloudflare.com/client/v4/"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns-cf-add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ] ; then
|
||||
_err "You don't specify cloudflare api key and email yet."
|
||||
_err "Please create you key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf CF_Key "$CF_Key"
|
||||
_saveaccountconf CF_Email "$CF_Email"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root $fulldomain ; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Getting txt records"
|
||||
_cf_rest GET "/zones/$_domain_id/dns_records?type=TXT&name=$fulldomain"
|
||||
|
||||
if [ "$?" != "0" ] || ! printf $response | grep \"success\":true > /dev/null ; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
count=$(printf $response | grep -o \"count\":[^,]* | cut -d : -f 2)
|
||||
|
||||
if [ "$count" == "0" ] ; then
|
||||
_info "Adding record"
|
||||
if _cf_rest POST "/zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
|
||||
if printf $response | grep $fulldomain > /dev/null ; then
|
||||
_info "Added, sleeping 10 seconds"
|
||||
sleep 10
|
||||
#todo: check if the record takes effect
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
else
|
||||
_info "Updating record"
|
||||
record_id=$(printf $response | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \")
|
||||
_debug "record_id" $record_id
|
||||
|
||||
_cf_rest PUT "/zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}"
|
||||
if [ "$?" == "0" ]; then
|
||||
_info "Updated, sleeping 10 seconds"
|
||||
sleep 10
|
||||
#todo: check if the record takes effect
|
||||
return 0;
|
||||
fi
|
||||
_err "Update error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#################### Private functions bellow ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
while [ '1' ] ; do
|
||||
h=$(printf $domain | cut -d . -f $i-100)
|
||||
if [ -z "$h" ] ; then
|
||||
#not valid
|
||||
return 1;
|
||||
fi
|
||||
|
||||
if ! _cf_rest GET "zones?name=$h" ; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if printf $response | grep \"name\":\"$h\" ; then
|
||||
_domain_id=$(printf $response | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \")
|
||||
if [ "$_domain_id" ] ; then
|
||||
_sub_domain=$(printf $domain | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
let "i+=1"
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
_cf_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
_debug $ep
|
||||
if [ "$3" ] ; then
|
||||
data="$3"
|
||||
_debug data "$data"
|
||||
response="$(curl --silent -X $m "$CF_Api/$ep" -H "X-Auth-Email: $CF_Email" -H "X-Auth-Key: $CF_Key" -H "Content-Type: application/json" --data $data)"
|
||||
else
|
||||
response="$(curl --silent -X $m "$CF_Api/$ep" -H "X-Auth-Email: $CF_Email" -H "X-Auth-Key: $CF_Key" -H "Content-Type: application/json")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ] ; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
_debug() {
|
||||
|
||||
if [ -z "$DEBUG" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$2" ] ; then
|
||||
echo $1
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_info() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1"
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_err() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1" >&2
|
||||
else
|
||||
echo "$1"="$2" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
|
234
dnsapi/dns-cx.sh
Normal file
234
dnsapi/dns-cx.sh
Normal file
@ -0,0 +1,234 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Cloudxns.com Domain api
|
||||
#
|
||||
#CX_Key="1234"
|
||||
#
|
||||
#CX_Secret="sADDsdasdgdsf"
|
||||
|
||||
|
||||
CX_Api="https://www.cloudxns.net/api2"
|
||||
|
||||
|
||||
#REST_API
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns-cx-add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ] ; then
|
||||
_err "You don't specify cloudxns.com api key or secret yet."
|
||||
_err "Please create you key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
REST_API=$CX_Api
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf CX_Key "$CX_Key"
|
||||
_saveaccountconf CX_Secret "$CX_Secret"
|
||||
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root $fulldomain ; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
existing_records $_domain $_sub_domain
|
||||
_debug count "$count"
|
||||
if [ "$?" != "0" ] ; then
|
||||
_err "Error get existing records."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$count" == "0" ] ; then
|
||||
add_record $_domain $_sub_domain $txtvalue
|
||||
else
|
||||
update_record $_domain $_sub_domain $txtvalue
|
||||
fi
|
||||
|
||||
if [ "$?" == "0" ] ; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#usage: root sub
|
||||
#return if the sub record already exists.
|
||||
#echos the existing records count.
|
||||
# '0' means doesn't exist
|
||||
existing_records() {
|
||||
_debug "Getting txt records"
|
||||
root=$1
|
||||
sub=$2
|
||||
|
||||
if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100" ; then
|
||||
return 1
|
||||
fi
|
||||
count=0
|
||||
seg=$(printf "$response" | grep -o "{[^{]*host\":\"$_sub_domain[^}]*}")
|
||||
_debug seg "$seg"
|
||||
if [ -z "$seg" ] ; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if printf "$response" | grep '"type":"TXT"' > /dev/null ; then
|
||||
count=1
|
||||
record_id=$(printf "$seg" | grep -o \"record_id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \")
|
||||
_debug record_id "$record_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#add the txt record.
|
||||
#usage: root sub txtvalue
|
||||
add_record() {
|
||||
root=$1
|
||||
sub=$2
|
||||
txtvalue=$3
|
||||
fulldomain=$sub.$root
|
||||
|
||||
_info "Adding record"
|
||||
|
||||
if ! _rest POST "record" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#update the txt record
|
||||
#Usage: root sub txtvalue
|
||||
update_record() {
|
||||
root=$1
|
||||
sub=$2
|
||||
txtvalue=$3
|
||||
fulldomain=$sub.$root
|
||||
|
||||
_info "Updating record"
|
||||
|
||||
if _rest PUT "record/$record_id" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}" ; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#################### Private functions bellow ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
|
||||
if ! _rest GET "domain" ; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
while [ '1' ] ; do
|
||||
h=$(printf $domain | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ] ; then
|
||||
#not valid
|
||||
return 1;
|
||||
fi
|
||||
|
||||
if printf "$response" | grep "$h." ; then
|
||||
seg=$(printf "$response" | grep -o "{[^{]*$h\.[^}]*\}" )
|
||||
_debug seg "$seg"
|
||||
_domain_id=$(printf "$seg" | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \")
|
||||
_debug _domain_id "$_domain_id"
|
||||
if [ "$_domain_id" ] ; then
|
||||
_sub_domain=$(printf $domain | cut -d . -f 1-$p)
|
||||
_debug _sub_domain $_sub_domain
|
||||
_domain=$h
|
||||
_debug _domain $_domain
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
let "i+=1"
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
#Usage: method URI data
|
||||
_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
_debug $ep
|
||||
url="$REST_API/$ep"
|
||||
_debug url "$url"
|
||||
|
||||
cdate=$(date -u "+%Y-%m-%d %H:%M:%S UTC")
|
||||
_debug cdate "$cdate"
|
||||
|
||||
data="$3"
|
||||
_debug data "$data"
|
||||
|
||||
sec="$CX_Key$url$data$cdate$CX_Secret"
|
||||
_debug sec "$sec"
|
||||
hmac=$(printf "$sec"| openssl md5 |cut -d " " -f 2)
|
||||
_debug hmac "$hmac"
|
||||
|
||||
if [ "$3" ] ; then
|
||||
response="$(curl --silent -X $m "$url" -H "API-KEY: $CX_Key" -H "API-REQUEST-DATE: $cdate" -H "API-HMAC: $hmac" -H 'Content-Type: application/json' -d "$data")"
|
||||
else
|
||||
response="$(curl --silent -X $m "$url" -H "API-KEY: $CX_Key" -H "API-REQUEST-DATE: $cdate" -H "API-HMAC: $hmac" -H 'Content-Type: application/json')"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ] ; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug response "$response"
|
||||
if ! printf "$response" | grep '"message":"success"' > /dev/null ; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
_debug() {
|
||||
|
||||
if [ -z "$DEBUG" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$2" ] ; then
|
||||
echo $1
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_info() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1"
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_err() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1" >&2
|
||||
else
|
||||
echo "$1"="$2" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
|
229
dnsapi/dns-dp.sh
Normal file
229
dnsapi/dns-dp.sh
Normal file
@ -0,0 +1,229 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Dnspod.cn Domain api
|
||||
#
|
||||
#DP_Id="1234"
|
||||
#
|
||||
#DP_Key="sADDsdasdgdsf"
|
||||
|
||||
|
||||
DP_Api="https://dnsapi.cn"
|
||||
|
||||
|
||||
#REST_API
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns-dp-add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if [ -z "$DP_Id" ] || [ -z "$DP_Key" ] ; then
|
||||
_err "You don't specify dnspod api key and key id yet."
|
||||
_err "Please create you key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
REST_API=$DP_Api
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf DP_Id "$DP_Id"
|
||||
_saveaccountconf DP_Key "$DP_Key"
|
||||
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root $fulldomain ; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
existing_records $_domain $_sub_domain
|
||||
_debug count "$count"
|
||||
if [ "$?" != "0" ] ; then
|
||||
_err "Error get existing records."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$count" == "0" ] ; then
|
||||
add_record $_domain $_sub_domain $txtvalue
|
||||
else
|
||||
update_record $_domain $_sub_domain $txtvalue
|
||||
fi
|
||||
}
|
||||
|
||||
#usage: root sub
|
||||
#return if the sub record already exists.
|
||||
#echos the existing records count.
|
||||
# '0' means doesn't exist
|
||||
existing_records() {
|
||||
_debug "Getting txt records"
|
||||
root=$1
|
||||
sub=$2
|
||||
|
||||
if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&domain_id=$_domain_id&sub_domain=$_sub_domain"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if printf "$response" | grep 'No records' ; then
|
||||
count=0;
|
||||
return 0
|
||||
fi
|
||||
|
||||
if printf "$response" | grep "Action completed successful" >/dev/null ; then
|
||||
count=$(printf "$response" | grep '<type>TXT</type>' | wc -l)
|
||||
|
||||
record_id=$(printf "$response" | grep '^<id>' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1)
|
||||
return 0
|
||||
else
|
||||
_err "get existing records error."
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
count=0
|
||||
}
|
||||
|
||||
#add the txt record.
|
||||
#usage: root sub txtvalue
|
||||
add_record() {
|
||||
root=$1
|
||||
sub=$2
|
||||
txtvalue=$3
|
||||
fulldomain=$sub.$root
|
||||
|
||||
_info "Adding record"
|
||||
|
||||
if ! _rest POST "Record.Create" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if printf "$response" | grep "Action completed successful" ; then
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
return 1 #error
|
||||
}
|
||||
|
||||
#update the txt record
|
||||
#Usage: root sub txtvalue
|
||||
update_record() {
|
||||
root=$1
|
||||
sub=$2
|
||||
txtvalue=$3
|
||||
fulldomain=$sub.$root
|
||||
|
||||
_info "Updating record"
|
||||
|
||||
if ! _rest POST "Record.Modify" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认&record_id=$record_id"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if printf "$response" | grep "Action completed successful" ; then
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1 #error
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#################### Private functions bellow ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
while [ '1' ] ; do
|
||||
h=$(printf $domain | cut -d . -f $i-100)
|
||||
if [ -z "$h" ] ; then
|
||||
#not valid
|
||||
return 1;
|
||||
fi
|
||||
|
||||
if ! _rest POST "Domain.Info" "login_token=$DP_Id,$DP_Key&format=json&domain=$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if printf "$response" | grep "Action completed successful" ; then
|
||||
_domain_id=$(printf "$response" | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \")
|
||||
_debug _domain_id "$_domain_id"
|
||||
if [ "$_domain_id" ] ; then
|
||||
_sub_domain=$(printf $domain | cut -d . -f 1-$p)
|
||||
_debug _sub_domain $_sub_domain
|
||||
_domain=$h
|
||||
_debug _domain $_domain
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
let "i+=1"
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
#Usage: method URI data
|
||||
_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
_debug $ep
|
||||
url="$REST_API/$ep"
|
||||
|
||||
_debug url "$url"
|
||||
|
||||
if [ "$3" ] ; then
|
||||
data="$3"
|
||||
_debug data "$data"
|
||||
response="$(curl --silent -X $m "$url" -d $data)"
|
||||
else
|
||||
response="$(curl --silent -X $m "$url" )"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ] ; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
_debug() {
|
||||
|
||||
if [ -z "$DEBUG" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$2" ] ; then
|
||||
echo $1
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_info() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1"
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_err() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1" >&2
|
||||
else
|
||||
echo "$1"="$2" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
|
61
dnsapi/dns-myapi.sh
Normal file
61
dnsapi/dns-myapi.sh
Normal file
@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
|
||||
#Here is a sample custom api script.
|
||||
#This file name is "dns-myapi.sh"
|
||||
#So, here must be a method dns-myapi-add()
|
||||
#Which will be called by le.sh to add the txt record to your api system.
|
||||
#returns 0 meanst success, otherwise error.
|
||||
|
||||
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns-myapi-add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_err "Not implemented!"
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#################### Private functions bellow ##################################
|
||||
|
||||
|
||||
_debug() {
|
||||
|
||||
if [ -z "$DEBUG" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$2" ] ; then
|
||||
echo $1
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_info() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1"
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_err() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1" >&2
|
||||
else
|
||||
echo "$1"="$2" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
|
384
le.sh
384
le.sh
@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
VER=1.1.1
|
||||
VER=1.1.6
|
||||
PROJECT="https://github.com/Neilpang/le"
|
||||
|
||||
DEFAULT_CA="https://acme-v01.api.letsencrypt.org"
|
||||
@ -41,6 +41,7 @@ _err() {
|
||||
else
|
||||
echo "$1"="$2" >&2
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_h2b() {
|
||||
@ -64,13 +65,19 @@ _base64() {
|
||||
|
||||
#domain [2048]
|
||||
createAccountKey() {
|
||||
_info "Creating account key"
|
||||
if [ -z "$1" ] ; then
|
||||
echo Usage: $0 account-domain [2048]
|
||||
echo Usage: createAccountKey account-domain [2048]
|
||||
return
|
||||
fi
|
||||
|
||||
account=$1
|
||||
length=$2
|
||||
|
||||
if [[ "$length" == "ec-"* ]] ; then
|
||||
length=2048
|
||||
fi
|
||||
|
||||
if [ -z "$2" ] ; then
|
||||
_info "Use default length 2048"
|
||||
length=2048
|
||||
@ -89,20 +96,53 @@ createAccountKey() {
|
||||
|
||||
#domain length
|
||||
createDomainKey() {
|
||||
_info "Creating domain key"
|
||||
if [ -z "$1" ] ; then
|
||||
echo Usage: $0 domain [2048]
|
||||
echo Usage: createDomainKey domain [2048]
|
||||
return
|
||||
fi
|
||||
|
||||
domain=$1
|
||||
length=$2
|
||||
if [ -z "$2" ] ; then
|
||||
_info "Use default length 2048"
|
||||
length=2048
|
||||
isec=""
|
||||
if [[ "$length" == "ec-"* ]] ; then
|
||||
isec="1"
|
||||
length=$(printf $length | cut -d '-' -f 2-100)
|
||||
eccname="$length"
|
||||
fi
|
||||
|
||||
if [ -z "$length" ] ; then
|
||||
if [ "$isec" ] ; then
|
||||
length=256
|
||||
else
|
||||
length=2048
|
||||
fi
|
||||
fi
|
||||
_info "Use length $length"
|
||||
|
||||
if [ "$isec" ] ; then
|
||||
if [ "$length" == "256" ] ; then
|
||||
eccname="prime256v1"
|
||||
fi
|
||||
if [ "$length" == "384" ] ; then
|
||||
eccname="secp384r1"
|
||||
fi
|
||||
if [ "$length" == "521" ] ; then
|
||||
eccname="secp521r1"
|
||||
fi
|
||||
_info "Using ec name: $eccname"
|
||||
fi
|
||||
|
||||
_initpath $domain
|
||||
|
||||
if [ -f "$CERT_KEY_PATH" ] && ! [ "$FORCE" ] ; then
|
||||
if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then
|
||||
#generate account key
|
||||
if [ "$isec" ] ; then
|
||||
openssl ecparam -name $eccname -genkey 2>/dev/null > "$CERT_KEY_PATH"
|
||||
else
|
||||
openssl genrsa $length 2>/dev/null > "$CERT_KEY_PATH"
|
||||
fi
|
||||
else
|
||||
if [ "$IS_RENEW" ] ; then
|
||||
_info "Domain key exists, skip"
|
||||
return 0
|
||||
@ -111,15 +151,13 @@ createDomainKey() {
|
||||
_err "Set FORCE=1, and try again."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
#generate account key
|
||||
openssl genrsa $length > "$CERT_KEY_PATH"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
# domain domainlist
|
||||
createCSR() {
|
||||
_info "Creating csr"
|
||||
if [ -z "$1" ] ; then
|
||||
echo Usage: $0 domain [domainlist]
|
||||
return
|
||||
@ -160,8 +198,8 @@ _send_signed_request() {
|
||||
_debug url $url
|
||||
_debug payload "$payload"
|
||||
|
||||
CURL_HEADER="$WORKING_DIR/curl.header"
|
||||
dp="$WORKING_DIR/curl.dump"
|
||||
CURL_HEADER="$LE_WORKING_DIR/curl.header"
|
||||
dp="$LE_WORKING_DIR/curl.dump"
|
||||
CURL="curl --silent --dump-header $CURL_HEADER "
|
||||
if [ "$DEBUG" ] ; then
|
||||
CURL="$CURL --trace-ascii $dp "
|
||||
@ -239,6 +277,29 @@ _setopt() {
|
||||
_debug "$(grep -H -n "^$__opt$__sep" $__conf)"
|
||||
}
|
||||
|
||||
#_savedomainconf key value
|
||||
#save to domain.conf
|
||||
_savedomainconf() {
|
||||
key="$1"
|
||||
value="$2"
|
||||
if [ "$DOMAIN_CONF" ] ; then
|
||||
_setopt $DOMAIN_CONF "$key" "=" "$value"
|
||||
else
|
||||
_err "DOMAIN_CONF is empty, can not save $key=$value"
|
||||
fi
|
||||
}
|
||||
|
||||
#_saveaccountconf key value
|
||||
_saveaccountconf() {
|
||||
key="$1"
|
||||
value="$2"
|
||||
if [ "$ACCOUNT_CONF_PATH" ] ; then
|
||||
_setopt $ACCOUNT_CONF_PATH "$key" "=" "$value"
|
||||
else
|
||||
_err "ACCOUNT_CONF_PATH is empty, can not save $key=$value"
|
||||
fi
|
||||
}
|
||||
|
||||
_startserver() {
|
||||
content="$1"
|
||||
_NC="nc -q 1"
|
||||
@ -247,9 +308,9 @@ _startserver() {
|
||||
fi
|
||||
# while true ; do
|
||||
if [ "$DEBUG" ] ; then
|
||||
echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p 80 -vv
|
||||
echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort -vv
|
||||
else
|
||||
echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p 80 > /dev/null
|
||||
echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort > /dev/null
|
||||
fi
|
||||
# done
|
||||
}
|
||||
@ -267,6 +328,18 @@ _initpath() {
|
||||
SUDO=sudo
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$LE_WORKING_DIR" ]; then
|
||||
LE_WORKING_DIR=$HOME/.le
|
||||
fi
|
||||
|
||||
if [ -z "$ACCOUNT_CONF_PATH" ] ; then
|
||||
ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf"
|
||||
fi
|
||||
|
||||
if [ -f "$ACCOUNT_CONF_PATH" ] ; then
|
||||
source "$ACCOUNT_CONF_PATH"
|
||||
fi
|
||||
|
||||
if [ -z "$API" ] ; then
|
||||
if [ -z "$STAGE" ] ; then
|
||||
@ -277,48 +350,45 @@ _initpath() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$WORKING_DIR" ]; then
|
||||
WORKING_DIR=$HOME/.le
|
||||
fi
|
||||
|
||||
if [ -z "$ACME_DIR" ] ; then
|
||||
ACME_DIR="/home/.acme"
|
||||
fi
|
||||
|
||||
if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then
|
||||
APACHE_CONF_BACKUP_DIR="$WORKING_DIR/"
|
||||
APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR/"
|
||||
fi
|
||||
|
||||
domain="$1"
|
||||
mkdir -p "$WORKING_DIR"
|
||||
mkdir -p "$LE_WORKING_DIR"
|
||||
|
||||
if [ -z "$ACCOUNT_KEY_PATH" ] ; then
|
||||
ACCOUNT_KEY_PATH="$WORKING_DIR/account.acc"
|
||||
ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key"
|
||||
fi
|
||||
|
||||
|
||||
if [ -z "$domain" ] ; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
mkdir -p "$WORKING_DIR/$domain"
|
||||
domainhome="$LE_WORKING_DIR/$domain"
|
||||
mkdir -p "$domainhome"
|
||||
|
||||
if [ -z "$DOMAIN_CONF" ] ; then
|
||||
DOMAIN_CONF="$WORKING_DIR/$domain/$Le_Domain.conf"
|
||||
fi
|
||||
if [ -z "$CSR_PATH" ] ; then
|
||||
CSR_PATH="$WORKING_DIR/$domain/$domain.csr"
|
||||
fi
|
||||
if [ -z "$CERT_KEY_PATH" ] ; then
|
||||
CERT_KEY_PATH="$WORKING_DIR/$domain/$domain.key"
|
||||
fi
|
||||
if [ -z "$CERT_PATH" ] ; then
|
||||
CERT_PATH="$WORKING_DIR/$domain/$domain.cer"
|
||||
fi
|
||||
if [ -z "$CA_CERT_PATH" ] ; then
|
||||
CA_CERT_PATH="$WORKING_DIR/$domain/ca.cer"
|
||||
DOMAIN_CONF="$domainhome/$Le_Domain.conf"
|
||||
fi
|
||||
|
||||
if [ -z "$CSR_PATH" ] ; then
|
||||
CSR_PATH="$domainhome/$domain.csr"
|
||||
fi
|
||||
if [ -z "$CERT_KEY_PATH" ] ; then
|
||||
CERT_KEY_PATH="$domainhome/$domain.key"
|
||||
fi
|
||||
if [ -z "$CERT_PATH" ] ; then
|
||||
CERT_PATH="$domainhome/$domain.cer"
|
||||
fi
|
||||
if [ -z "$CA_CERT_PATH" ] ; then
|
||||
CA_CERT_PATH="$domainhome/ca.cer"
|
||||
fi
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -422,7 +492,7 @@ _clearupwebbroot() {
|
||||
_debug "remove $__webroot/.well-known/acme-challenge/$3"
|
||||
rm -rf "$__webroot/.well-known/acme-challenge/$3"
|
||||
else
|
||||
_info "skip for removelevel:$2"
|
||||
_info "Skip for removelevel:$2"
|
||||
fi
|
||||
|
||||
return 0
|
||||
@ -488,11 +558,16 @@ issue() {
|
||||
_err "Please install netcat(nc) tools first."
|
||||
return 1
|
||||
fi
|
||||
|
||||
netprc="$(ss -ntpl | grep ':80 ')"
|
||||
|
||||
if [ -z "$Le_HTTPPort" ] ; then
|
||||
Le_HTTPPort=80
|
||||
fi
|
||||
_setopt "$DOMAIN_CONF" "Le_HTTPPort" "=" "$Le_HTTPPort"
|
||||
|
||||
netprc="$(ss -ntpl | grep :$Le_HTTPPort" ")"
|
||||
if [ "$netprc" ] ; then
|
||||
_err "$netprc"
|
||||
_err "tcp port 80 is already used by $(echo "$netprc" | cut -d : -f 4)"
|
||||
_err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)"
|
||||
_err "Please stop it first"
|
||||
return 1
|
||||
fi
|
||||
@ -539,7 +614,7 @@ issue() {
|
||||
_debug HEADER "$HEADER"
|
||||
|
||||
accountkey_json=$(echo -n "$jwk" | sed "s/ //g")
|
||||
thumbprint=$(echo -n "$accountkey_json" | openssl sha -sha256 -binary | _base64 | _b64)
|
||||
thumbprint=$(echo -n "$accountkey_json" | openssl dgst -sha256 -binary | _base64 | _b64)
|
||||
|
||||
|
||||
_info "Registering account"
|
||||
@ -551,7 +626,7 @@ issue() {
|
||||
|
||||
if [ "$code" == "" ] || [ "$code" == '201' ] ; then
|
||||
_info "Registered"
|
||||
echo $response > $WORKING_DIR/account.json
|
||||
echo $response > $LE_WORKING_DIR/account.json
|
||||
elif [ "$code" == '409' ] ; then
|
||||
_info "Already registered"
|
||||
else
|
||||
@ -616,12 +691,49 @@ issue() {
|
||||
_debug txt "$txt"
|
||||
#dns
|
||||
#1. check use api
|
||||
_err "Add the following TXT record:"
|
||||
_err "Domain: $txtdomain"
|
||||
_err "TXT value: $txt"
|
||||
_err "Please be aware that you prepend _acme-challenge. before your domain"
|
||||
_err "so the resulting subdomain will be: $txtdomain"
|
||||
#dnsadded='1'
|
||||
d_api=""
|
||||
if [ -f "$LE_WORKING_DIR/$d/$Le_Webroot" ] ; then
|
||||
d_api="$LE_WORKING_DIR/$d/$Le_Webroot"
|
||||
elif [ -f "$LE_WORKING_DIR/$d/$Le_Webroot.sh" ] ; then
|
||||
d_api="$LE_WORKING_DIR/$d/$Le_Webroot.sh"
|
||||
elif [ -f "$LE_WORKING_DIR/$Le_Webroot" ] ; then
|
||||
d_api="$LE_WORKING_DIR/$Le_Webroot"
|
||||
elif [ -f "$LE_WORKING_DIR/$Le_Webroot.sh" ] ; then
|
||||
d_api="$LE_WORKING_DIR/$Le_Webroot.sh"
|
||||
elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot" ] ; then
|
||||
d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot"
|
||||
elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" ] ; then
|
||||
d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh"
|
||||
fi
|
||||
_debug d_api "$d_api"
|
||||
|
||||
if [ "$d_api" ]; then
|
||||
_info "Found domain api file: $d_api"
|
||||
else
|
||||
_err "Add the following TXT record:"
|
||||
_err "Domain: $txtdomain"
|
||||
_err "TXT value: $txt"
|
||||
_err "Please be aware that you prepend _acme-challenge. before your domain"
|
||||
_err "so the resulting subdomain will be: $txtdomain"
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! source $d_api ; then
|
||||
_err "Load file $d_api error. Please check your api file and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
addcommand="$Le_Webroot-add"
|
||||
if ! command -v $addcommand ; then
|
||||
_err "It seems that your api file is not correct, it must have a function named: $Le_Webroot"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! $addcommand $txtdomain $txt ; then
|
||||
_err "Error add txt for domain:$txtdomain"
|
||||
return 1
|
||||
fi
|
||||
dnsadded='1'
|
||||
fi
|
||||
done
|
||||
|
||||
@ -634,6 +746,10 @@ issue() {
|
||||
|
||||
fi
|
||||
|
||||
if [ "$dnsadded" == '1' ] ; then
|
||||
_info "Sleep 60 seconds for the txt records to take effect"
|
||||
sleep 60
|
||||
fi
|
||||
|
||||
_debug "ok, let's start to verify"
|
||||
ventries=$(echo "$vlist" | sed "s/,/ /g")
|
||||
@ -754,7 +870,7 @@ issue() {
|
||||
|
||||
|
||||
if [ -z "$Le_LinkCert" ] ; then
|
||||
response="$(echo $response | openssl base64 -d)"
|
||||
response="$(echo $response | openssl base64 -d -A)"
|
||||
_err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')"
|
||||
return 1
|
||||
fi
|
||||
@ -803,23 +919,30 @@ renew() {
|
||||
|
||||
_initpath $Le_Domain
|
||||
|
||||
if [ -f "$DOMAIN_CONF" ] ; then
|
||||
source "$DOMAIN_CONF"
|
||||
if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then
|
||||
_info "Skip, Next renewal time is: $Le_NextRenewTimeStr"
|
||||
return 2
|
||||
fi
|
||||
if [ ! -f "$DOMAIN_CONF" ] ; then
|
||||
_info "$Le_Domain is not a issued domain, skip."
|
||||
return 0;
|
||||
fi
|
||||
|
||||
source "$DOMAIN_CONF"
|
||||
if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then
|
||||
_info "Skip, Next renewal time is: $Le_NextRenewTimeStr"
|
||||
return 2
|
||||
fi
|
||||
|
||||
IS_RENEW="1"
|
||||
issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd"
|
||||
local res=$?
|
||||
IS_RENEW=""
|
||||
|
||||
return $res
|
||||
}
|
||||
|
||||
renewAll() {
|
||||
_initpath
|
||||
_info "renewAll"
|
||||
|
||||
for d in $(ls -F $WORKING_DIR | grep '/$') ; do
|
||||
for d in $(ls -F $LE_WORKING_DIR | grep [^.].*[.].*/$ ) ; do
|
||||
d=$(echo $d | cut -d '/' -f 1)
|
||||
_info "renew $d"
|
||||
|
||||
@ -914,13 +1037,13 @@ installcronjob() {
|
||||
_initpath
|
||||
_info "Installing cron job"
|
||||
if ! crontab -l | grep 'le.sh cron' ; then
|
||||
if [ -f "$WORKING_DIR/le.sh" ] ; then
|
||||
lesh="\"$WORKING_DIR\"/le.sh"
|
||||
if [ -f "$LE_WORKING_DIR/le.sh" ] ; then
|
||||
lesh="\"$LE_WORKING_DIR\"/le.sh"
|
||||
else
|
||||
_err "Can not install cronjob, le.sh not found."
|
||||
return 1
|
||||
fi
|
||||
crontab -l | { cat; echo "0 0 * * * $SUDO WORKING_DIR=\"$WORKING_DIR\" $lesh cron > /dev/null"; } | crontab -
|
||||
crontab -l | { cat; echo "0 0 * * * $SUDO LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null"; } | crontab -
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
@ -930,13 +1053,89 @@ uninstallcronjob() {
|
||||
cr="$(crontab -l | grep 'le.sh cron')"
|
||||
if [ "$cr" ] ; then
|
||||
crontab -l | sed "/le.sh cron/d" | crontab -
|
||||
WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 7 | cut -d '=' -f 2 | tr -d '"')"
|
||||
_info WORKING_DIR "$WORKING_DIR"
|
||||
LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 7 | cut -d '=' -f 2 | tr -d '"')"
|
||||
_info LE_WORKING_DIR "$LE_WORKING_DIR"
|
||||
fi
|
||||
_initpath
|
||||
|
||||
}
|
||||
|
||||
|
||||
# Detect profile file if not specified as environment variable
|
||||
_detect_profile() {
|
||||
if [ -n "$PROFILE" -a -f "$PROFILE" ]; then
|
||||
echo "$PROFILE"
|
||||
return
|
||||
fi
|
||||
|
||||
local DETECTED_PROFILE
|
||||
DETECTED_PROFILE=''
|
||||
local SHELLTYPE
|
||||
SHELLTYPE="$(basename "/$SHELL")"
|
||||
|
||||
if [ "$SHELLTYPE" = "bash" ]; then
|
||||
if [ -f "$HOME/.bashrc" ]; then
|
||||
DETECTED_PROFILE="$HOME/.bashrc"
|
||||
elif [ -f "$HOME/.bash_profile" ]; then
|
||||
DETECTED_PROFILE="$HOME/.bash_profile"
|
||||
fi
|
||||
elif [ "$SHELLTYPE" = "zsh" ]; then
|
||||
DETECTED_PROFILE="$HOME/.zshrc"
|
||||
fi
|
||||
|
||||
if [ -z "$DETECTED_PROFILE" ]; then
|
||||
if [ -f "$HOME/.profile" ]; then
|
||||
DETECTED_PROFILE="$HOME/.profile"
|
||||
elif [ -f "$HOME/.bashrc" ]; then
|
||||
DETECTED_PROFILE="$HOME/.bashrc"
|
||||
elif [ -f "$HOME/.bash_profile" ]; then
|
||||
DETECTED_PROFILE="$HOME/.bash_profile"
|
||||
elif [ -f "$HOME/.zshrc" ]; then
|
||||
DETECTED_PROFILE="$HOME/.zshrc"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -z "$DETECTED_PROFILE" ]; then
|
||||
echo "$DETECTED_PROFILE"
|
||||
fi
|
||||
}
|
||||
|
||||
_initconf() {
|
||||
_initpath
|
||||
if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then
|
||||
echo "#Account configurations:
|
||||
#Here are the supported macros, uncomment them to make them take effect.
|
||||
#ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account.
|
||||
|
||||
#STAGE=1 # Use the staging api
|
||||
#FORCE=1 # Force to issue cert
|
||||
#DEBUG=1 # Debug mode
|
||||
|
||||
#dns api
|
||||
#######################
|
||||
#Cloudflare:
|
||||
#api key
|
||||
#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#account email
|
||||
#CF_Email="xxxx@sss.com"
|
||||
|
||||
#######################
|
||||
#Dnspod.cn:
|
||||
#api key id
|
||||
#DP_Id="1234"
|
||||
#api key
|
||||
#DP_Key="sADDsdasdgdsf"
|
||||
|
||||
#######################
|
||||
#Cloudxns.com:
|
||||
#CX_Key="1234"
|
||||
#
|
||||
#CX_Secret="sADDsdasdgdsf"
|
||||
|
||||
" > $ACCOUNT_CONF_PATH
|
||||
fi
|
||||
}
|
||||
|
||||
install() {
|
||||
_initpath
|
||||
|
||||
@ -969,29 +1168,40 @@ install() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Installing to $WORKING_DIR"
|
||||
_info "Installing to $LE_WORKING_DIR"
|
||||
|
||||
#try install to /bin if is root
|
||||
if [ ! -f /usr/local/bin/le.sh ] ; then
|
||||
#if root
|
||||
if $SUDO cp le.sh /usr/local/bin/le.sh > /dev/null 2>&1; then
|
||||
$SUDO chmod 755 /usr/local/bin/le.sh
|
||||
$SUDO ln -s "/usr/local/bin/le.sh" /usr/local/bin/le
|
||||
rm -f $WORKING_DIR/le.sh
|
||||
$SUDO ln -s /usr/local/bin/le.sh $WORKING_DIR/le.sh
|
||||
_info "Installed to /usr/local/bin/le"
|
||||
else
|
||||
#install to home, for non root user
|
||||
cp le.sh $WORKING_DIR/
|
||||
chmod +x $WORKING_DIR/le.sh
|
||||
_info "Installed to $WORKING_DIR/le.sh"
|
||||
fi
|
||||
_info "Installed to $LE_WORKING_DIR/le.sh"
|
||||
cp le.sh $LE_WORKING_DIR/
|
||||
chmod +x $LE_WORKING_DIR/le.sh
|
||||
|
||||
_profile="$(_detect_profile)"
|
||||
if [ "$_profile" ] ; then
|
||||
_debug "Found profile: $_profile"
|
||||
|
||||
echo "LE_WORKING_DIR=$LE_WORKING_DIR
|
||||
alias le=\"$LE_WORKING_DIR/le.sh\"
|
||||
alias le.sh=\"$LE_WORKING_DIR/le.sh\"
|
||||
" > "$LE_WORKING_DIR/le.env"
|
||||
|
||||
_setopt "$_profile" "source \"$LE_WORKING_DIR/le.env\""
|
||||
_info "OK, Close and reopen your terminal to start using le"
|
||||
else
|
||||
_info "No profile is found, you will need to go into $LE_WORKING_DIR to use le.sh"
|
||||
fi
|
||||
rm -f $WORKING_DIR/le
|
||||
ln -s $WORKING_DIR/le.sh $WORKING_DIR/le
|
||||
|
||||
mkdir -p $LE_WORKING_DIR/dnsapi
|
||||
cp dnsapi/* $LE_WORKING_DIR/dnsapi/
|
||||
|
||||
#to keep compatible mv the .acc file to .key file
|
||||
if [ -f "$LE_WORKING_DIR/account.acc" ] ; then
|
||||
mv "$LE_WORKING_DIR/account.acc" "$LE_WORKING_DIR/account.key"
|
||||
fi
|
||||
|
||||
installcronjob
|
||||
|
||||
if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then
|
||||
_initconf
|
||||
fi
|
||||
_info OK
|
||||
}
|
||||
|
||||
@ -999,15 +1209,13 @@ uninstall() {
|
||||
uninstallcronjob
|
||||
_initpath
|
||||
|
||||
if [ -f "/usr/local/bin/le.sh" ] ; then
|
||||
_info "Removing /usr/local/bin/le.sh"
|
||||
if $SUDO rm -f /usr/local/bin/le.sh ; then
|
||||
$SUDO rm -f /usr/local/bin/le
|
||||
fi
|
||||
_profile="$(_detect_profile)"
|
||||
if [ "$_profile" ] ; then
|
||||
sed -i /le.env/d "$_profile"
|
||||
fi
|
||||
rm -f $WORKING_DIR/le
|
||||
rm -f $WORKING_DIR/le.sh
|
||||
_info "The keys and certs are in $WORKING_DIR, you can remove them by yourself."
|
||||
|
||||
rm -f $LE_WORKING_DIR/le.sh
|
||||
_info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself."
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user