mirror of
https://github.com/acmesh-official/acme.sh.git
synced 2025-04-30 06:22:46 +00:00
Merge remote-tracking branch 'refs/remotes/Neilpang/master'
This commit is contained in:
commit
6a7b084f97
203
README.md
203
README.md
@ -1,20 +1,28 @@
|
||||
# le
|
||||
# le: means simp`Le`
|
||||
Simplest shell script for LetsEncrypt free Certificate client
|
||||
|
||||
This is a shell version from https://github.com/diafygi/acme-tiny
|
||||
Simple and Powerful, you only need 3 minutes to learn.
|
||||
|
||||
Pure written in bash, no dependencies to python , acme-tiny or LetsEncrypt official client (https://github.com/letsencrypt/letsencrypt)
|
||||
|
||||
Just one script, to issue, renew your certiricates automatically.
|
||||
Pure written in bash, no dependencies to python , acme-tiny or LetsEncrypt official client.
|
||||
Just one script, to issue, renew your certificates automatically.
|
||||
|
||||
Probably it's the smallest&easiest&smartest shell script to automatically issue&renew the free certificates from LetsEncrypt.
|
||||
|
||||
Do NOT require to be `root/sudoer`.
|
||||
|
||||
#Supported OS
|
||||
1. Tested on Ubuntu/Debian.
|
||||
2. CentOS is Not tested yet, It should work.
|
||||
#Tested OS
|
||||
1. Ubuntu/Debian.
|
||||
2. CentOS
|
||||
3. Windows (cygwin with curl, openssl and crontab included)
|
||||
4. FreeBSD with bash
|
||||
|
||||
|
||||
#Supported Mode
|
||||
1. Webroot mode
|
||||
2. Standalone mode
|
||||
3. Apache mode
|
||||
4. Dns mode
|
||||
|
||||
#How to use
|
||||
|
||||
1. Clone this project: https://github.com/Neilpang/le.git
|
||||
@ -23,64 +31,199 @@ Probably it's the smallest&easiest&smartest shell script to automatically issue
|
||||
```
|
||||
./le.sh install
|
||||
```
|
||||
Which does 2 things:
|
||||
* create and copy le.sh to your home dir: `~/.le`
|
||||
All the certs will be placed in this folder.
|
||||
* create symbol link: `/bin/le -> ~/.le/le.sh`
|
||||
You don't have to be root then, although it is recommended.
|
||||
|
||||
3. Ok, you are ready to issue cert now.
|
||||
Which does 3 jobs:
|
||||
* create and copy `le.sh` to your home dir: `~/.le`
|
||||
All the certs will be placed in this folder.
|
||||
* 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:
|
||||
```
|
||||
root@xvm:~# le
|
||||
Usage: issue|renew|renewAll|createAccountKey|createDomainKey|createCSR|install|uninstall
|
||||
root@v1:~# le.sh
|
||||
https://github.com/Neilpang/le
|
||||
v1.1.1
|
||||
Usage: le.sh [command] ...[args]....
|
||||
Available commands:
|
||||
|
||||
install:
|
||||
Install le.sh to your system.
|
||||
issue:
|
||||
Issue a cert.
|
||||
installcert:
|
||||
Install the issued cert to apache/nginx or any other server.
|
||||
renew:
|
||||
Renew a cert.
|
||||
renewAll:
|
||||
Renew all the certs.
|
||||
uninstall:
|
||||
Uninstall le.sh, and uninstall the cron job.
|
||||
version:
|
||||
Show version info.
|
||||
installcronjob:
|
||||
Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
|
||||
uninstallcronjob:
|
||||
Uninstall the cron job. The 'uninstall' command can do this automatically.
|
||||
createAccountKey:
|
||||
Create an account private key, professional use.
|
||||
createDomainKey:
|
||||
Create an domain private key, professional use.
|
||||
createCSR:
|
||||
Create CSR , professional use.
|
||||
|
||||
|
||||
root@v1:~/le# le issue
|
||||
Usage: le issue webroot|no|apache|dns a.com [www.a.com,b.com,c.com]|no [key-length]|no
|
||||
|
||||
root@xvm:~# le issue
|
||||
Usage: /bin/le webroot a.com [www.a.com,b.com,c.com] [key-length] [cert-file-path] [key-file-path] [reloadCmd]
|
||||
|
||||
```
|
||||
|
||||
Set the param value to "no" means you want to ignore it.
|
||||
|
||||
For example, if you give "no" to "key-length", it will use default length 2048.
|
||||
|
||||
And if you give 'no' to 'cert-file-path', it will not copy the issued cert to the "cert-file-path".
|
||||
|
||||
In all the cases, the issued cert will be placed in "~/.le/domain.com/"
|
||||
|
||||
|
||||
# Just issue a cert:
|
||||
```
|
||||
le issue /home/wwwroot/aa.com aa.com www.aa.com,cp.aa.com
|
||||
```
|
||||
First argument " /home/wwwroot/aa.com" is the web root folder
|
||||
First argument `/home/wwwroot/aa.com` is the web root folder, You must have `write` access to this folder.
|
||||
|
||||
Second argument "aa.com" is the domain you want to issue cert for.
|
||||
Second argument "aa.com" is the main domain you want to issue cert for.
|
||||
|
||||
Third argument is the additional domain list you want to use. Comma sperated list, Optional.
|
||||
Third argument is the additional domain list you want to use. Comma separated list, which is Optional.
|
||||
|
||||
'You must point and bind all the domains to the same webroot dir:/home/wwwroot/aa.com'
|
||||
You must point and bind all the domains to the same webroot dir:`/home/wwwroot/aa.com`
|
||||
|
||||
The cert will be placed in `~/.le/aa.com/`
|
||||
|
||||
The issued cert will be renewed every 80 days automatically.
|
||||
|
||||
The issued cert will be renewed every 50 days automatically.
|
||||
|
||||
|
||||
# Issue a cert, and install to apache
|
||||
# Install issued cert to apache/nginx etc.
|
||||
```
|
||||
le issue /home/wwwroot/aa.com aa.com www.aa.com,cp.aa.com 2048 /path/to/certfile/in/apache/nginx /path/to/keyfile/in/apache/nginx "service apache2 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"
|
||||
```
|
||||
This can link the issued cert to the production apache or nginx path.
|
||||
Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: ` service apache2 reload`
|
||||
|
||||
Install the issued cert/key to the production apache or nginx path.
|
||||
|
||||
The cert will be renewed every 80 days by default (which is configurable), Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: ` service apache2 reload` or `service nginx reload`
|
||||
|
||||
|
||||
# Use Standalone server to issue cert( requires you be root/sudoer, or you have permission to listen tcp 80 port):
|
||||
Same usage as all above, just give `no` as the webroot.
|
||||
The tcp `80` port must be free to listen, otherwise you will be prompted to free the `80` port and try again.
|
||||
|
||||
```
|
||||
le issue no aa.com www.aa.com,cp.aa.com
|
||||
```
|
||||
|
||||
# Use Apache mode(requires you be root/sudoer, since it is required to interact with apache server):
|
||||
If you are running a web server, apache or nginx, it is recommended to use the Webroot mode.
|
||||
Particularly, if you are running an apache server, you can use apache mode instead. Which doesn't write any file to your web root folder.
|
||||
|
||||
Just set string "apache" to the first argument, it will use apache plugin automatically.
|
||||
|
||||
```
|
||||
le issue apache aa.com www.aa.com,user.aa.com
|
||||
```
|
||||
All the other arguments are the same with previous.
|
||||
|
||||
|
||||
# Use DNS mode:
|
||||
Support the latest dns-01 challenge.
|
||||
|
||||
```
|
||||
le issue dns aa.com www.aa.com,user.aa.com
|
||||
```
|
||||
|
||||
You will get the output like bellow:
|
||||
```
|
||||
Add the following txt record:
|
||||
Domain:_acme-challenge.aa.com
|
||||
Txt value:9ihDbjYfTExAYeDs4DBUeuTo18KBzwvTEjUnSwd32-c
|
||||
|
||||
Add the following txt record:
|
||||
Domain:_acme-challenge.www.aa.com
|
||||
Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
Please add those txt records to the domains. Waiting for the dns to take effect.
|
||||
|
||||
Then just retry with 'renew' command:
|
||||
|
||||
```
|
||||
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 the `length` parameter 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", which is not supported by letsencrypt yet.)
|
||||
|
||||
|
||||
|
||||
#Under the Hood
|
||||
|
||||
Use bash to say ACME language directly to Let's encrypt.
|
||||
Speak ACME language with bash directly to Let's encrypt.
|
||||
|
||||
TODO:
|
||||
|
||||
|
||||
#Acknowledgment
|
||||
1. Acme-tiny: https://github.com/diafygi/acme-tiny
|
||||
2. ACME protocol: https://github.com/ietf-wg-acme/acme
|
||||
3. letsencrypt: https://github.com/letsencrypt/letsencrypt
|
||||
|
||||
|
||||
|
||||
#License & Other
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
171
dnsapi/dns-cf.sh
Executable file
171
dnsapi/dns-cf.sh
Executable file
@ -0,0 +1,171 @@
|
||||
#!/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 _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_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\":\"[^\"]*\" | head -1 | 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
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user