Merge branch 'dev' into dnsapi/dns_dnsever

This commit is contained in:
hiska 2018-07-01 20:11:17 +09:00 committed by GitHub
commit b0dfd5f94d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1403 additions and 384 deletions

View File

@ -13,12 +13,6 @@ env:
global: global:
- SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64 - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64
addons:
apt:
sources:
- debian-sid # Grab shellcheck from the Debian repo (o_O)
packages:
- shellcheck
install: install:
- if [ "$TRAVIS_OS_NAME" = 'osx' ]; then - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then
@ -29,9 +23,7 @@ install:
script: script:
- echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)"
- command -V openssl && openssl version - command -V openssl && openssl version
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt && chmod +x ~/shfmt && ~/shfmt -l -w -i 2 . ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then chmod +x ~/shfmt ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi
@ -40,7 +32,6 @@ script:
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./rundocker.sh testplat ubuntu:latest ; fi - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./rundocker.sh testplat ubuntu:latest ; fi
- if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi
matrix: matrix:
fast_finish: true fast_finish: true

View File

@ -3,6 +3,7 @@ FROM alpine:3.6
RUN apk update -f \ RUN apk update -f \
&& apk --no-cache add -f \ && apk --no-cache add -f \
openssl \ openssl \
coreutils \
curl \ curl \
socat \ socat \
&& rm -rf /var/cache/apk/* && rm -rf /var/cache/apk/*

View File

@ -37,6 +37,8 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
- [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/)
- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient) - [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
- [CentOS Web Panel](http://centos-webpanel.com/)
- [lnmp.org](https://lnmp.org/)
- [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) - [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials)
# Tested OS # Tested OS
@ -220,22 +222,7 @@ acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 5. Use Standalone TLS server to issue cert # 5. Use Apache mode
**(requires you to be root/sudoer or have permission to listen on port 443 (TCP))**
acme.sh supports `tls-sni-01` validation.
Port `443` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again.
```bash
acme.sh --issue --tls -d example.com -d www.example.com -d cp.example.com
```
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 6. Use Apache mode
**(requires you to be root/sudoer, since it is required to interact with Apache server)** **(requires you to be root/sudoer, since it is required to interact with Apache server)**
@ -255,7 +242,7 @@ We don't want to mess your apache server, don't worry.**
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 7. Use Nginx mode # 6. Use Nginx mode
**(requires you to be root/sudoer, since it is required to interact with Nginx server)** **(requires you to be root/sudoer, since it is required to interact with Nginx server)**
@ -279,7 +266,7 @@ We don't want to mess your nginx server, don't worry.**
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 8. Automatic DNS API integration # 7. Automatic DNS API integration
If your DNS provider supports API access, we can use that API to automatically issue the certs. If your DNS provider supports API access, we can use that API to automatically issue the certs.
@ -327,14 +314,14 @@ You don't have to do anything manually!
1. selectel.com(selectel.ru) DNS API 1. selectel.com(selectel.ru) DNS API
1. zonomi.com DNS API 1. zonomi.com DNS API
1. DreamHost.com API 1. DreamHost.com API
1. DirectAdmin API
1. KingHost (https://www.kinghost.com.br/)
1. Zilore (https://zilore.com)
1. Loopia.se API
1. acme-dns (https://github.com/joohoi/acme-dns)
1. TELE3 (https://www.tele3.cz)
1. DNSEver(https://www.dnsever.com) 1. DNSEver(https://www.dnsever.com)
And: And:
**lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api **lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
@ -347,7 +334,9 @@ If your DNS provider is not on the supported list above, you can write your own
For more details: [How to use DNS API](dnsapi) For more details: [How to use DNS API](dnsapi)
# 9. Use DNS manual mode: # 8. Use DNS manual mode:
See: https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode first.
If your dns provider doesn't support any api access, you can add the txt record by your hand. If your dns provider doesn't support any api access, you can add the txt record by your hand.
@ -381,7 +370,7 @@ Ok, it's done.
**Please use dns api mode instead.** **Please use dns api mode instead.**
# 10. Issue ECC certificates # 9. Issue ECC certificates
`Let's Encrypt` can now issue **ECDSA** certificates. `Let's Encrypt` can now issue **ECDSA** certificates.
@ -413,17 +402,17 @@ Valid values are:
# 11. Issue Wildcard certificates # 10. Issue Wildcard certificates
It's simple, just give a wildcard domain as the `-d` parameter. It's simple, just give a wildcard domain as the `-d` parameter.
```sh ```sh
acme.sh --issue -d example.com -d *.example.com --dns dns_cf acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf
``` ```
# 12. How to renew the certs # 11. How to renew the certs
No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days. No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days.
@ -440,7 +429,7 @@ acme.sh --renew -d example.com --force --ecc
``` ```
# 13. How to stop cert renewal # 12. How to stop cert renewal
To stop renewal of a cert, you can execute the following to remove the cert from the renewal list: To stop renewal of a cert, you can execute the following to remove the cert from the renewal list:
@ -453,7 +442,7 @@ The cert/key file is not removed from the disk.
You can remove the respective directory (e.g. `~/.acme.sh/example.com`) by yourself. You can remove the respective directory (e.g. `~/.acme.sh/example.com`) by yourself.
# 14. How to upgrade `acme.sh` # 13. How to upgrade `acme.sh`
acme.sh is in constant development, so it's strongly recommended to use the latest code. acme.sh is in constant development, so it's strongly recommended to use the latest code.
@ -478,25 +467,25 @@ acme.sh --upgrade --auto-upgrade 0
``` ```
# 15. Issue a cert from an existing CSR # 14. Issue a cert from an existing CSR
https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR
# 16. Under the Hood # 15. Under the Hood
Speak ACME language using shell, directly to "Let's Encrypt". Speak ACME language using shell, directly to "Let's Encrypt".
TODO: TODO:
# 17. Acknowledgments # 16. Acknowledgments
1. Acme-tiny: https://github.com/diafygi/acme-tiny 1. Acme-tiny: https://github.com/diafygi/acme-tiny
2. ACME protocol: https://github.com/ietf-wg-acme/acme 2. ACME protocol: https://github.com/ietf-wg-acme/acme
# 18. License & Others # 17. License & Others
License is GPLv3 License is GPLv3
@ -505,7 +494,7 @@ Please Star and Fork me.
[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome. [Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome.
# 19. Donate # 18. Donate
Your donation makes **acme.sh** better: Your donation makes **acme.sh** better:
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/) 1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)

246
acme.sh
View File

@ -1,6 +1,6 @@
#!/usr/bin/env sh #!/usr/bin/env sh
VER=2.7.7 VER=2.7.9
PROJECT_NAME="acme.sh" PROJECT_NAME="acme.sh"
@ -47,6 +47,7 @@ DEFAULT_DNS_SLEEP=120
NO_VALUE="no" NO_VALUE="no"
W_TLS="tls" W_TLS="tls"
W_DNS="dns"
DNS_ALIAS_PREFIX="=" DNS_ALIAS_PREFIX="="
MODE_STATELESS="stateless" MODE_STATELESS="stateless"
@ -63,6 +64,7 @@ END_CSR="-----END CERTIFICATE REQUEST-----"
BEGIN_CERT="-----BEGIN CERTIFICATE-----" BEGIN_CERT="-----BEGIN CERTIFICATE-----"
END_CERT="-----END CERTIFICATE-----" END_CERT="-----END CERTIFICATE-----"
CONTENT_TYPE_JSON="application/jose+json"
RENEW_SKIP=2 RENEW_SKIP=2
ECC_SEP="_" ECC_SEP="_"
@ -108,31 +110,35 @@ _STATELESS_WIKI="https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode"
_DNS_ALIAS_WIKI="https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode" _DNS_ALIAS_WIKI="https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode"
_DNS_MANUAL_WIKI="https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode"
_DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead." _DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead."
_DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR" _DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR"
_DNS_MANUAL_ERROR="It seems that you are using dns manual mode. Read this link first: $_DNS_MANUAL_WIKI"
__INTERACTIVE="" __INTERACTIVE=""
if [ -t 1 ]; then if [ -t 1 ]; then
__INTERACTIVE="1" __INTERACTIVE="1"
fi fi
__green() { __green() {
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then
printf '\033[1;31;32m' printf '\033[1;31;32m'
fi fi
printf -- "%b" "$1" printf -- "%b" "$1"
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then
printf '\033[0m' printf '\033[0m'
fi fi
} }
__red() { __red() {
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then
printf '\033[1;31;40m' printf '\033[1;31;40m'
fi fi
printf -- "%b" "$1" printf -- "%b" "$1"
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then
printf '\033[0m' printf '\033[0m'
fi fi
} }
@ -848,6 +854,16 @@ _dbase64() {
fi fi
} }
#file
_checkcert() {
_cf="$1"
if [ "$DEBUG" ]; then
openssl x509 -noout -text -in "$_cf"
else
openssl x509 -noout -text -in "$_cf" >/dev/null 2>&1
fi
}
#Usage: hashalg [outputhex] #Usage: hashalg [outputhex]
#Output Base64-encoded digest #Output Base64-encoded digest
_digest() { _digest() {
@ -1591,12 +1607,13 @@ _inithttp() {
} }
# body url [needbase64] [POST|PUT] # body url [needbase64] [POST|PUT] [ContentType]
_post() { _post() {
body="$1" body="$1"
_post_url="$2" _post_url="$2"
needbase64="$3" needbase64="$3"
httpmethod="$4" httpmethod="$4"
_postContentType="$5"
if [ -z "$httpmethod" ]; then if [ -z "$httpmethod" ]; then
httpmethod="POST" httpmethod="POST"
@ -1604,6 +1621,7 @@ _post() {
_debug $httpmethod _debug $httpmethod
_debug "_post_url" "$_post_url" _debug "_post_url" "$_post_url"
_debug2 "body" "$body" _debug2 "body" "$body"
_debug2 "_postContentType" "$_postContentType"
_inithttp _inithttp
@ -1614,9 +1632,17 @@ _post() {
fi fi
_debug "_CURL" "$_CURL" _debug "_CURL" "$_CURL"
if [ "$needbase64" ]; then if [ "$needbase64" ]; then
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" if [ "$_postContentType" ]; then
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
else
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
fi
else else
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" if [ "$_postContentType" ]; then
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
else
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
fi
fi fi
_ret="$?" _ret="$?"
if [ "$_ret" != "0" ]; then if [ "$_ret" != "0" ]; then
@ -1634,15 +1660,31 @@ _post() {
_debug "_WGET" "$_WGET" _debug "_WGET" "$_WGET"
if [ "$needbase64" ]; then if [ "$needbase64" ]; then
if [ "$httpmethod" = "POST" ]; then if [ "$httpmethod" = "POST" ]; then
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" if [ "$_postContentType" ]; then
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)"
else
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)"
fi
else else
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" if [ "$_postContentType" ]; then
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)"
else
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)"
fi
fi fi
else else
if [ "$httpmethod" = "POST" ]; then if [ "$httpmethod" = "POST" ]; then
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" if [ "$_postContentType" ]; then
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
else
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
fi
else else
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" if [ "$_postContentType" ]; then
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
else
response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
fi
fi fi
fi fi
_ret="$?" _ret="$?"
@ -1753,19 +1795,25 @@ _send_signed_request() {
return 1 return 1
fi fi
if [ "$ACME_VERSION" = "2" ]; then
__request_conent_type="$CONTENT_TYPE_JSON"
else
__request_conent_type=""
fi
payload64=$(printf "%s" "$payload" | _base64 | _url_replace) payload64=$(printf "%s" "$payload" | _base64 | _url_replace)
_debug3 payload64 "$payload64" _debug3 payload64 "$payload64"
MAX_REQUEST_RETRY_TIMES=5 MAX_REQUEST_RETRY_TIMES=5
_request_retry_times=0 _request_retry_times=0
while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do
_request_retry_times=$(_math "$_request_retry_times" + 1)
_debug3 _request_retry_times "$_request_retry_times" _debug3 _request_retry_times "$_request_retry_times"
if [ -z "$_CACHED_NONCE" ]; then if [ -z "$_CACHED_NONCE" ]; then
_headers="" _headers=""
if [ "$ACME_NEW_NONCE" ]; then if [ "$ACME_NEW_NONCE" ]; then
_debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE"
nonceurl="$ACME_NEW_NONCE" nonceurl="$ACME_NEW_NONCE"
if _post "" "$nonceurl" "" "HEAD"; then if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then
_headers="$(cat "$HTTP_HEADER")" _headers="$(cat "$HTTP_HEADER")"
fi fi
fi fi
@ -1789,7 +1837,11 @@ _send_signed_request() {
fi fi
nonce="$_CACHED_NONCE" nonce="$_CACHED_NONCE"
_debug2 nonce "$nonce" _debug2 nonce "$nonce"
if [ -z "$nonce" ]; then
_info "Could not get nonce, let's try again."
_sleep 2
continue
fi
if [ "$ACME_VERSION" = "2" ]; then if [ "$ACME_VERSION" = "2" ]; then
if [ "$url" = "$ACME_NEW_ACCOUNT" ] || [ "$url" = "$ACME_REVOKE_CERT" ]; then if [ "$url" = "$ACME_NEW_ACCOUNT" ] || [ "$url" = "$ACME_REVOKE_CERT" ]; then
protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}'
@ -1820,7 +1872,7 @@ _send_signed_request() {
fi fi
_debug3 body "$body" _debug3 body "$body"
response="$(_post "$body" "$url" "$needbase64")" response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")"
_CACHED_NONCE="" _CACHED_NONCE=""
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
@ -1841,13 +1893,12 @@ _send_signed_request() {
_body="$response" _body="$response"
if [ "$needbase64" ]; then if [ "$needbase64" ]; then
_body="$(echo "$_body" | _dbase64)" _body="$(echo "$_body" | _dbase64 | tr -d '\0')"
_debug3 _body "$_body" _debug3 _body "$_body"
fi fi
if _contains "$_body" "JWS has invalid anti-replay nonce"; then if _contains "$_body" "JWS has invalid anti-replay nonce"; then
_info "It seems the CA server is busy now, let's wait and retry." _info "It seems the CA server is busy now, let's wait and retry."
_request_retry_times=$(_math "$_request_retry_times" + 1)
_sleep 5 _sleep 5
continue continue
fi fi
@ -2310,7 +2361,7 @@ _initpath() {
fi fi
fi fi
_debug2 ACME_DIRECTORY "$ACME_DIRECTORY" _debug ACME_DIRECTORY "$ACME_DIRECTORY"
_ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)" _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)"
_debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST"
@ -2967,6 +3018,8 @@ _on_before_issue() {
_chk_pre_hook="$4" _chk_pre_hook="$4"
_chk_local_addr="$5" _chk_local_addr="$5"
_debug _on_before_issue _debug _on_before_issue
_debug _chk_main_domain "$_chk_main_domain"
_debug _chk_alt_domains "$_chk_alt_domains"
#run pre hook #run pre hook
if [ "$_chk_pre_hook" ]; then if [ "$_chk_pre_hook" ]; then
_info "Run pre hook:'$_chk_pre_hook'" _info "Run pre hook:'$_chk_pre_hook'"
@ -2987,11 +3040,17 @@ _on_before_issue() {
_debug Le_LocalAddress "$_chk_local_addr" _debug Le_LocalAddress "$_chk_local_addr"
alldomains=$(echo "$_chk_main_domain,$_chk_alt_domains" | tr ',' ' ')
_index=1 _index=1
_currentRoot="" _currentRoot=""
_addrIndex=1 _addrIndex=1
for d in $alldomains; do _w_index=1
while true; do
d="$(echo "$_chk_main_domain,$_chk_alt_domains," | cut -d , -f "$_w_index")"
_w_index="$(_math "$_w_index" + 1)"
_debug d "$d"
if [ -z "$d" ]; then
break
fi
_debug "Check for domain" "$d" _debug "Check for domain" "$d"
_currentRoot="$(_getfield "$_chk_web_roots" $_index)" _currentRoot="$(_getfield "$_chk_web_roots" $_index)"
_debug "_currentRoot" "$_currentRoot" _debug "_currentRoot" "$_currentRoot"
@ -3087,7 +3146,7 @@ _on_issue_err() {
) )
fi fi
if [ "$IS_RENEW" = "1" ] && _hasfield "$Le_Webroot" "dns"; then if [ "$IS_RENEW" = "1" ] && _hasfield "$Le_Webroot" "$W_DNS"; then
_err "$_DNS_MANUAL_ERR" _err "$_DNS_MANUAL_ERR"
fi fi
@ -3123,7 +3182,7 @@ _on_issue_success() {
fi fi
fi fi
if _hasfield "$Le_Webroot" "dns"; then if _hasfield "$Le_Webroot" "$W_DNS"; then
_err "$_DNS_MANUAL_WARN" _err "$_DNS_MANUAL_WARN"
fi fi
@ -3207,10 +3266,16 @@ _regAccount() {
return 1 return 1
fi fi
_debug2 responseHeaders "$responseHeaders"
_accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
_debug "_accUri" "$_accUri" _debug "_accUri" "$_accUri"
if [ -z "$_accUri" ]; then
_err "Can not find account id url."
_err "$responseHeaders"
return 1
fi
_savecaconf "ACCOUNT_URL" "$_accUri" _savecaconf "ACCOUNT_URL" "$_accUri"
export ACCOUNT_URL="$ACCOUNT_URL" export ACCOUNT_URL="$_accUri"
CA_KEY_HASH="$(__calcAccountKeyHash)" CA_KEY_HASH="$(__calcAccountKeyHash)"
_debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
@ -3390,6 +3455,9 @@ issue() {
_main_domain=$(echo "$2,$3" | cut -d , -f 1) _main_domain=$(echo "$2,$3" | cut -d , -f 1)
_alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//")
fi fi
_debug _main_domain "$_main_domain"
_debug _alt_domains "$_alt_domains"
_key_length="$4" _key_length="$4"
_real_cert="$5" _real_cert="$5"
_real_key="$6" _real_key="$6"
@ -3417,6 +3485,11 @@ issue() {
mkdir -p "$DOMAIN_PATH" mkdir -p "$DOMAIN_PATH"
fi fi
if _hasfield "$_web_roots" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then
_err "$_DNS_MANUAL_ERROR"
return 1
fi
_debug "Using ACME_DIRECTORY: $ACME_DIRECTORY" _debug "Using ACME_DIRECTORY: $ACME_DIRECTORY"
_initAPI _initAPI
@ -3478,7 +3551,7 @@ issue() {
_saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")" _saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")"
_debug2 _saved_account_key_hash "$_saved_account_key_hash" _debug2 _saved_account_key_hash "$_saved_account_key_hash"
if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then if [ -z "$ACCOUNT_URL" ] || [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then
if ! _regAccount "$_accountkeylength"; then if ! _regAccount "$_accountkeylength"; then
_on_issue_err "$_post_hook" _on_issue_err "$_post_hook"
return 1 return 1
@ -3520,10 +3593,15 @@ issue() {
if [ "$ACME_VERSION" = "2" ]; then if [ "$ACME_VERSION" = "2" ]; then
#make new order request #make new order request
_identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}" _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}"
for d in $(echo "$_alt_domains" | tr ',' ' '); do _w_index=1
if [ "$d" ]; then while true; do
_identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$d\"}" d="$(echo "$_alt_domains," | cut -d , -f "$_w_index")"
_w_index="$(_math "$_w_index" + 1)"
_debug d "$d"
if [ -z "$d" ]; then
break
fi fi
_identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$d\"}"
done done
_debug2 _identifiers "$_identifiers" _debug2 _identifiers "$_identifiers"
if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then
@ -3560,6 +3638,8 @@ issue() {
_debug2 "_authz_url" "$_authz_url" _debug2 "_authz_url" "$_authz_url"
if ! response="$(_get "$_authz_url")"; then if ! response="$(_get "$_authz_url")"; then
_err "get to authz error." _err "get to authz error."
_err "_authorizations_seg" "$_authorizations_seg"
_err "_authz_url" "$_authz_url"
_clearup _clearup
_on_issue_err "$_post_hook" _on_issue_err "$_post_hook"
return 1 return 1
@ -3578,10 +3658,16 @@ $_authorizations_map"
_debug2 _authorizations_map "$_authorizations_map" _debug2 _authorizations_map "$_authorizations_map"
fi fi
alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ')
_index=0 _index=0
_currentRoot="" _currentRoot=""
for d in $alldomains; do _w_index=1
while true; do
d="$(echo "$_main_domain,$_alt_domains," | cut -d , -f "$_w_index")"
_w_index="$(_math "$_w_index" + 1)"
_debug d "$d"
if [ -z "$d" ]; then
break
fi
_info "Getting webroot for domain" "$d" _info "Getting webroot for domain" "$d"
_index=$(_math $_index + 1) _index=$(_math $_index + 1)
_w="$(echo $_web_roots | cut -d , -f $_index)" _w="$(echo $_web_roots | cut -d , -f $_index)"
@ -3593,7 +3679,7 @@ $_authorizations_map"
vtype="$VTYPE_HTTP" vtype="$VTYPE_HTTP"
#todo, v2 wildcard force to use dns #todo, v2 wildcard force to use dns
if _startswith "$_currentRoot" "dns"; then if _startswith "$_currentRoot" "$W_DNS"; then
vtype="$VTYPE_DNS" vtype="$VTYPE_DNS"
fi fi
@ -3610,6 +3696,7 @@ $_authorizations_map"
_debug2 "response" "$response" _debug2 "response" "$response"
if [ -z "$response" ]; then if [ -z "$response" ]; then
_err "get to authz error." _err "get to authz error."
_err "_authorizations_map" "$_authorizations_map"
_clearup _clearup
_on_issue_err "$_post_hook" _on_issue_err "$_post_hook"
return 1 return 1
@ -3720,6 +3807,10 @@ $_authorizations_map"
if [ "$d_api" ]; then if [ "$d_api" ]; then
_info "Found domain api file: $d_api" _info "Found domain api file: $d_api"
else else
if [ "$_currentRoot" != "$W_DNS" ]; then
_err "Can not find dns api hook for: $_currentRoot"
_info "You need to add the txt record manually."
fi
_info "$(__red "Add the following TXT record:")" _info "$(__red "Add the following TXT record:")"
_info "$(__red "Domain: '$(__green "$txtdomain")'")" _info "$(__red "Domain: '$(__green "$txtdomain")'")"
_info "$(__red "TXT value: '$(__green "$txt")'")" _info "$(__red "TXT value: '$(__green "$txt")'")"
@ -3758,7 +3849,7 @@ $_authorizations_map"
if [ "$dnsadded" = '0' ]; then if [ "$dnsadded" = '0' ]; then
_savedomainconf "Le_Vlist" "$vlist" _savedomainconf "Le_Vlist" "$vlist"
_debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
_err "Please add the TXT records to the domains, and retry again." _err "Please add the TXT records to the domains, and re-run with --renew."
_clearup _clearup
_on_issue_err "$_post_hook" _on_issue_err "$_post_hook"
return 1 return 1
@ -4022,13 +4113,15 @@ $_authorizations_map"
fi fi
if [ "$code" != "200" ]; then if [ "$code" != "200" ]; then
_err "Sign failed, code is not 200." _err "Sign failed, code is not 200."
_err "$response"
_on_issue_err "$_post_hook" _on_issue_err "$_post_hook"
return 1 return 1
fi fi
Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)"
if ! _get "$Le_LinkCert" >"$CERT_PATH"; then if ! _get "$Le_LinkCert" >"$CERT_PATH"; then
_err "Sign failed, code is not 200." _err "Sign failed, can not download cert:$Le_LinkCert."
_err "$response"
_on_issue_err "$_post_hook" _on_issue_err "$_post_hook"
return 1 return 1
fi fi
@ -4044,12 +4137,12 @@ $_authorizations_map"
fi fi
else else
if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
_err "Sign failed." _err "Sign failed. $response"
_on_issue_err "$_post_hook" _on_issue_err "$_post_hook"
return 1 return 1
fi fi
_rcert="$response" _rcert="$response"
Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
echo "$BEGIN_CERT" >"$CERT_PATH" echo "$BEGIN_CERT" >"$CERT_PATH"
#if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then #if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then
@ -4068,6 +4161,13 @@ $_authorizations_map"
_debug "Le_LinkCert" "$Le_LinkCert" _debug "Le_LinkCert" "$Le_LinkCert"
_savedomainconf "Le_LinkCert" "$Le_LinkCert" _savedomainconf "Le_LinkCert" "$Le_LinkCert"
if [ -z "$Le_LinkCert" ] || ! _checkcert "$CERT_PATH"; then
response="$(echo "$response" | _dbase64 "multiline" | tr -d '\0' | _normalizeJson)"
_err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')"
_on_issue_err "$_post_hook"
return 1
fi
if [ "$Le_LinkCert" ]; then if [ "$Le_LinkCert" ]; then
_info "$(__green "Cert success.")" _info "$(__green "Cert success.")"
cat "$CERT_PATH" cat "$CERT_PATH"
@ -4078,26 +4178,18 @@ $_authorizations_map"
_info "Your cert key is in $(__green " $CERT_KEY_PATH ")" _info "Your cert key is in $(__green " $CERT_KEY_PATH ")"
fi fi
cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH"
if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ]; then if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ]; then
USER_PATH="$PATH" USER_PATH="$PATH"
_saveaccountconf "USER_PATH" "$USER_PATH" _saveaccountconf "USER_PATH" "$USER_PATH"
fi fi
fi fi
if [ -z "$Le_LinkCert" ]; then
response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)"
_err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')"
_on_issue_err "$_post_hook"
return 1
fi
_cleardomainconf "Le_Vlist" _cleardomainconf "Le_Vlist"
if [ "$ACME_VERSION" = "2" ]; then if [ "$ACME_VERSION" = "2" ]; then
_debug "v2 chain." _debug "v2 chain."
else else
cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH"
Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>')
if [ "$Le_LinkIssuer" ]; then if [ "$Le_LinkIssuer" ]; then
@ -4121,6 +4213,10 @@ $_authorizations_map"
echo "$BEGIN_CERT" >"$CA_CERT_PATH" echo "$BEGIN_CERT" >"$CA_CERT_PATH"
_base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH"
echo "$END_CERT" >>"$CA_CERT_PATH" echo "$END_CERT" >>"$CA_CERT_PATH"
if ! _checkcert "$CA_CERT_PATH"; then
_err "Can not get the ca cert."
break
fi
cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH"
rm -f "$CA_CERT_PATH.der" rm -f "$CA_CERT_PATH.der"
break break
@ -4191,20 +4287,21 @@ $_authorizations_map"
Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400) Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400)
_savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime"
if ! _on_issue_success "$_post_hook" "$_renew_hook"; then
_err "Call hook error."
return 1
fi
if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then
_savedomainconf "Le_RealCertPath" "$_real_cert" _savedomainconf "Le_RealCertPath" "$_real_cert"
_savedomainconf "Le_RealCACertPath" "$_real_ca" _savedomainconf "Le_RealCACertPath" "$_real_ca"
_savedomainconf "Le_RealKeyPath" "$_real_key" _savedomainconf "Le_RealKeyPath" "$_real_key"
_savedomainconf "Le_ReloadCmd" "$_reload_cmd" _savedomainconf "Le_ReloadCmd" "$_reload_cmd"
_savedomainconf "Le_RealFullChainPath" "$_real_fullchain" _savedomainconf "Le_RealFullChainPath" "$_real_fullchain"
_installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd" if ! _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"; then
return 1
fi
fi fi
if ! _on_issue_success "$_post_hook" "$_renew_hook"; then
_err "Call hook error."
return 1
fi
} }
#domain [isEcc] #domain [isEcc]
@ -4230,7 +4327,7 @@ renew() {
fi fi
. "$DOMAIN_CONF" . "$DOMAIN_CONF"
_debug Le_API "$Le_API"
if [ "$Le_API" ]; then if [ "$Le_API" ]; then
if [ "$_OLD_CA_HOST" = "$Le_API" ]; then if [ "$_OLD_CA_HOST" = "$Le_API" ]; then
export Le_API="$DEFAULT_CA" export Le_API="$DEFAULT_CA"
@ -4579,19 +4676,19 @@ _installcert() {
if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then
cp "$_real_cert" "$_backup_path/cert.bak" cp "$_real_cert" "$_backup_path/cert.bak"
fi fi
cat "$CERT_PATH" >"$_real_cert" cat "$CERT_PATH" >"$_real_cert" || return 1
fi fi
if [ "$_real_ca" ]; then if [ "$_real_ca" ]; then
_info "Installing CA to:$_real_ca" _info "Installing CA to:$_real_ca"
if [ "$_real_ca" = "$_real_cert" ]; then if [ "$_real_ca" = "$_real_cert" ]; then
echo "" >>"$_real_ca" echo "" >>"$_real_ca"
cat "$CA_CERT_PATH" >>"$_real_ca" cat "$CA_CERT_PATH" >>"$_real_ca" || return 1
else else
if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then
cp "$_real_ca" "$_backup_path/ca.bak" cp "$_real_ca" "$_backup_path/ca.bak"
fi fi
cat "$CA_CERT_PATH" >"$_real_ca" cat "$CA_CERT_PATH" >"$_real_ca" || return 1
fi fi
fi fi
@ -4601,9 +4698,9 @@ _installcert() {
cp "$_real_key" "$_backup_path/key.bak" cp "$_real_key" "$_backup_path/key.bak"
fi fi
if [ -f "$_real_key" ]; then if [ -f "$_real_key" ]; then
cat "$CERT_KEY_PATH" >"$_real_key" cat "$CERT_KEY_PATH" >"$_real_key" || return 1
else else
cat "$CERT_KEY_PATH" >"$_real_key" cat "$CERT_KEY_PATH" >"$_real_key" || return 1
chmod 600 "$_real_key" chmod 600 "$_real_key"
fi fi
fi fi
@ -4613,7 +4710,7 @@ _installcert() {
if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then
cp "$_real_fullchain" "$_backup_path/fullchain.bak" cp "$_real_fullchain" "$_backup_path/fullchain.bak"
fi fi
cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" || return 1
fi fi
if [ "$_reload_cmd" ]; then if [ "$_reload_cmd" ]; then
@ -4834,6 +4931,8 @@ _deactivate() {
_debug2 "authzUri" "$authzUri" _debug2 "authzUri" "$authzUri"
if ! response="$(_get "$authzUri")"; then if ! response="$(_get "$authzUri")"; then
_err "get to authz error." _err "get to authz error."
_err "_authorizations_seg" "$_authorizations_seg"
_err "authzUri" "$authzUri"
_clearup _clearup
_on_issue_err "$_post_hook" _on_issue_err "$_post_hook"
return 1 return 1
@ -5365,7 +5464,6 @@ Parameters:
--webroot, -w /path/to/webroot Specifies the web root folder for web root mode. --webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
--standalone Use standalone mode. --standalone Use standalone mode.
--stateless Use stateless mode, see: $_STATELESS_WIKI --stateless Use stateless mode, see: $_STATELESS_WIKI
--tls Use standalone tls mode.
--apache Use apache mode. --apache Use apache mode.
--dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
--dnssleep [$DEFAULT_DNS_SLEEP] The time in seconds to wait for all the txt records to take effect in dns api mode. Default $DEFAULT_DNS_SLEEP seconds. --dnssleep [$DEFAULT_DNS_SLEEP] The time in seconds to wait for all the txt records to take effect in dns api mode. Default $DEFAULT_DNS_SLEEP seconds.
@ -5391,11 +5489,10 @@ Parameters:
--cert-home Specifies the home dir to save all the certs, only valid for '--install' command. --cert-home Specifies the home dir to save all the certs, only valid for '--install' command.
--config-home Specifies the home dir to save all the configurations. --config-home Specifies the home dir to save all the configurations.
--useragent Specifies the user agent string. it will be saved for future use too. --useragent Specifies the user agent string. it will be saved for future use too.
--accountemail Specifies the account email for registering, Only valid for the '--install' command. --accountemail Specifies the account email, only valid for the '--install' and '--update-account' command.
--accountkey Specifies the account key path, Only valid for the '--install' command. --accountkey Specifies the account key path, only valid for the '--install' command.
--days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days. --days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days.
--httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer. --httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
--tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer.
--local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses. --local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses.
--listraw Only used for '--list' command, list the certs in raw format. --listraw Only used for '--list' command, list the certs in raw format.
--stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal. --stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal.
@ -5404,6 +5501,7 @@ Parameters:
--ca-path Specifies directory containing CA certificates in PEM format, used by wget or curl. --ca-path Specifies directory containing CA certificates in PEM format, used by wget or curl.
--nocron Only valid for '--install' command, which means: do not install the default cron job. In this case, the certs will not be renewed automatically. --nocron Only valid for '--install' command, which means: do not install the default cron job. In this case, the certs will not be renewed automatically.
--no-color Do not output color text. --no-color Do not output color text.
--force-color Force output of color text. Useful for non-interactive use with the aha tool for HTML E-Mails.
--ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR'
--csr Specifies the input csr. --csr Specifies the input csr.
--pre-hook Command to be run before obtaining any certificates. --pre-hook Command to be run before obtaining any certificates.
@ -5417,6 +5515,8 @@ Parameters:
--listen-v6 Force standalone/tls server to listen at ipv6. --listen-v6 Force standalone/tls server to listen at ipv6.
--openssl-bin Specifies a custom openssl bin location. --openssl-bin Specifies a custom openssl bin location.
--use-wget Force to use wget, if you have both curl and wget installed. --use-wget Force to use wget, if you have both curl and wget installed.
--yes-I-know-dns-manual-mode-enough-go-ahead-please Force to use dns manual mode: $_DNS_MANUAL_WIKI
--branch, -b Only valid for '--upgrade' command, specifies the branch name to upgrade to.
" "
} }
@ -5746,16 +5846,8 @@ _process() {
_webroot="$_webroot,$wvalue" _webroot="$_webroot,$wvalue"
fi fi
;; ;;
--tls)
wvalue="$W_TLS"
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
;;
--dns) --dns)
wvalue="dns" wvalue="$W_DNS"
if [ "$2" ] && ! _startswith "$2" "-"; then if [ "$2" ] && ! _startswith "$2" "-"; then
wvalue="$2" wvalue="$2"
shift shift
@ -5849,12 +5941,6 @@ _process() {
Le_HTTPPort="$_httpport" Le_HTTPPort="$_httpport"
shift shift
;; ;;
--tlsport)
_tlsport="$2"
Le_TLSPort="$_tlsport"
shift
;;
--listraw) --listraw)
_listraw="raw" _listraw="raw"
;; ;;
@ -5881,6 +5967,9 @@ _process() {
--no-color) --no-color)
export ACME_NO_COLOR=1 export ACME_NO_COLOR=1
;; ;;
--force-color)
export ACME_FORCE_COLOR=1
;;
--ecc) --ecc)
_ecc="isEcc" _ecc="isEcc"
;; ;;
@ -5919,6 +6008,9 @@ _process() {
shift shift
fi fi
;; ;;
--yes-I-know-dns-manual-mode-enough-go-ahead-please)
export FORCE_DNS_MANUAL=1
;;
--log | --logfile) --log | --logfile)
_log="1" _log="1"
_logfile="$2" _logfile="$2"
@ -5972,6 +6064,10 @@ _process() {
_use_wget="1" _use_wget="1"
ACME_USE_WGET="1" ACME_USE_WGET="1"
;; ;;
--branch | -b)
export BRANCH="$2"
shift
;;
*) *)
_err "Unknown parameter : $1" _err "Unknown parameter : $1"
return 1 return 1

View File

@ -2,8 +2,12 @@
# Here is the script to deploy the cert to your cpanel using the cpanel API. # Here is the script to deploy the cert to your cpanel using the cpanel API.
# Uses command line uapi. --user option is needed only if run as root. # Uses command line uapi. --user option is needed only if run as root.
# Returns 0 when success. # Returns 0 when success.
# Written by Santeri Kannisto <santeri.kannisto@2globalnomads.info> #
# Public domain, 2017 # Please note that I am no longer using Github. If you want to report an issue
# or contact me, visit https://forum.webseodesigners.com/web-design-seo-and-hosting-f16/
#
# Written by Santeri Kannisto <santeri.kannisto@webseodesigners.com>
# Public domain, 2017-2018
#export DEPLOY_CPANEL_USER=myusername #export DEPLOY_CPANEL_USER=myusername
@ -28,15 +32,9 @@ cpanel_uapi_deploy() {
_err "The command uapi is not found." _err "The command uapi is not found."
return 1 return 1
fi fi
if ! _exists php; then
_err "The command php is not found."
return 1
fi
# read cert and key files and urlencode both # read cert and key files and urlencode both
_certstr=$(cat "$_ccert") _cert=$(_url_encode <"$_ccert")
_keystr=$(cat "$_ckey") _key=$(_url_encode <"$_ckey")
_cert=$(php -r "echo urlencode(\"$_certstr\");")
_key=$(php -r "echo urlencode(\"$_keystr\");")
_debug _cert "$_cert" _debug _cert "$_cert"
_debug _key "$_key" _debug _key "$_key"

View File

@ -1,11 +1,5 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#Here is a sample custom api script.
#This file name is "myapi.sh"
#So, here must be a method myapi_deploy()
#Which will be called by acme.sh to deploy the cert
#returns 0 means success, otherwise error.
######## Public functions ##################### ######## Public functions #####################
#domain keyfile certfile cafile fullchain #domain keyfile certfile cafile fullchain

View File

@ -51,6 +51,7 @@ vault_cli_deploy() {
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1 $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1 $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1 $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
} }

View File

@ -1,5 +1,9 @@
# How to use DNS API # How to use DNS API
If your dns provider doesn't provide api access, you can use our dns alias mode:
https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode
## 1. Use CloudFlare domain API to automatically issue cert ## 1. Use CloudFlare domain API to automatically issue cert
First you need to login to your CloudFlare account to get your API key. First you need to login to your CloudFlare account to get your API key.
@ -325,6 +329,8 @@ The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.s
## 17. Use Domain-Offensive/Resellerinterface/Domainrobot API ## 17. Use Domain-Offensive/Resellerinterface/Domainrobot API
ATTENTION: You need to be a registered Reseller to be able to use the ResellerInterface. As a normal user you can not use this method.
You will need your login credentials (Partner ID+Password) to the Resellerinterface, and export them before you run `acme.sh`: You will need your login credentials (Partner ID+Password) to the Resellerinterface, and export them before you run `acme.sh`:
``` ```
export DO_PID="KD-1234567" export DO_PID="KD-1234567"
@ -525,8 +531,9 @@ For issues, please report to https://github.com/raidenii/acme.sh/issues.
## 28. Use Name.com API ## 28. Use Name.com API
You'll need to fill out the form at https://www.name.com/reseller/apply to apply Create your API token here: https://www.name.com/account/settings/api
for API username and token.
Note: `Namecom_Username` should be your Name.com username and not the token name. If you accidentally run the script with the token name as the username see `~/.acme.sh/account.conf` to fix the issue
``` ```
export Namecom_Username="testuser" export Namecom_Username="testuser"
@ -638,6 +645,14 @@ acme.sh --issue --dns dns_inwx -d example.com -d www.example.com
The `INWX_User` and `INWX_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. The `INWX_User` and `INWX_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
If your account is secured by mobile tan you have also defined the shared secret.
```
export INWX_Shared_Secret="shared secret"
```
You may need to re-enable the mobile tan to gain the shared secret.
## 34. User Servercow API v1 ## 34. User Servercow API v1
Create a new user from the servercow control center. Don't forget to activate **DNS API** for this user. Create a new user from the servercow control center. Don't forget to activate **DNS API** for this user.
@ -750,23 +765,125 @@ DNS API keys may be created at https://panel.dreamhost.com/?tree=home.api.
Ensure the created key has add and remove privelages. Ensure the created key has add and remove privelages.
``` ```
export DH_API_Key="<api key>" export DH_API_KEY="<api key>"
acme.sh --issue --dns dns_dreamhost -d example.com -d www.example.com acme.sh --issue --dns dns_dreamhost -d example.com -d www.example.com
``` ```
The 'DH_API_KEY' will be saved in `~/.acme.sh/account.conf` and will The 'DH_API_KEY' will be saved in `~/.acme.sh/account.conf` and will
be reused when needed. be reused when needed.
## 41. Use DNSEver (https://www.dnsever.com/) ## 41. Use DirectAdmin API
The DirectAdmin interface has it's own Let's encrypt functionality, but this
script can be used to generate certificates for names which are not hosted on
DirectAdmin
User must provide login data and URL to the DirectAdmin incl. port.
You can create an user which only has access to
- CMD_API_DNS_CONTROL
- CMD_API_SHOW_DOMAINS
By using the Login Keys function.
See also https://www.directadmin.com/api.php and https://www.directadmin.com/features.php?id=1298
```
export DA_Api="https://remoteUser:remotePassword@da.domain.tld:8443"
export DA_Api_Insecure=1
```
Set `DA_Api_Insecure` to 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1)
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_da -d example.com -d www.example.com
```
The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 42. Use KingHost DNS API
API access must be enabled at https://painel.kinghost.com.br/painel.api.php
```
export KINGHOST_Username="yourusername"
export KINGHOST_Password="yourpassword"
acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com
```
The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 43. Use Zilore DNS API
First, get your API key at https://my.zilore.com/account/api
```
export Zilore_Key="5dcad3a2-36cb-50e8-cb92-000002f9"
```
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_zilore -d example.com -d *.example.com
```
The `Zilore_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 44. Use Loopia.se API
User must provide login credentials to the Loopia API.
The user needs the following permissions:
- addSubdomain
- updateZoneRecord
- getDomains
- removeSubdomain
Set the login credentials:
```
export LOOPIA_User="user@loopiaapi"
export LOOPIA_Password="password"
```
And to issue a cert:
```
acme.sh --issue --dns dns_loopia -d example.com -d *.example.com
```
The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 45. Use ACME DNS API
ACME DNS is a limited DNS server with RESTful HTTP API to handle ACME DNS challenges easily and securely.
https://github.com/joohoi/acme-dns
```
export ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update"
export ACMEDNS_USERNAME="<username>"
export ACMEDNS_PASSWORD="<password>"
export ACMEDNS_SUBDOMAIN="<subdomain>"
acme.sh --issue --dns dns_acmedns -d example.com -d www.example.com
```
The credentials will be saved in `~/.acme.sh/account.conf` and will
be reused when needed.
## 46. Use TELE3 API
First you need to login to your TELE3 account to set your API-KEY.
https://www.tele3.cz/system-acme-api.html
```
export TELE3_Key="MS2I4uPPaI..."
export TELE3_Secret="kjhOIHGJKHg"
acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com
```
The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed.
## 47. Use DNSEver (https://www.dnsever.com/)
You will need your login credentials (ID+PW) to the DNSEver, and export them before you run acme.sh: You will need your login credentials (ID+PW) to the DNSEver, and export them before you run acme.sh:
``` ```
export DNSEVER_ID="KD-1234567" export DNSEVER_ID="KD-1234567"
export DNSEVER_PW="cdfkjl3n2" export DNSEVER_PW="cdfkjl3n2"
```
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_dnsever -d example.com -d www.example.com acme.sh --issue --dns dns_dnsever -d example.com -d www.example.com
``` ```
The DNSEVER_ID and DNSEVER_PW will be saved in ~/.acme.sh/account.conf and will be reused when needed. The DNSEVER_ID and DNSEVER_PW will be saved in ~/.acme.sh/account.conf and will be reused when needed.

55
dnsapi/dns_acmedns.sh Normal file
View File

@ -0,0 +1,55 @@
#!/usr/bin/env sh
#
#Author: Wolfgang Ebner
#Report Bugs here: https://github.com/webner/acme.sh
#
######## Public functions #####################
#Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_acmedns_add() {
fulldomain=$1
txtvalue=$2
_info "Using acme-dns"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
ACMEDNS_UPDATE_URL="${ACMEDNS_UPDATE_URL:-$(_readaccountconf_mutable ACMEDNS_UPDATE_URL)}"
ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readaccountconf_mutable ACMEDNS_USERNAME)}"
ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readaccountconf_mutable ACMEDNS_PASSWORD)}"
ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readaccountconf_mutable ACMEDNS_SUBDOMAIN)}"
if [ "$ACMEDNS_UPDATE_URL" = "" ]; then
ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update"
fi
_saveaccountconf_mutable ACMEDNS_UPDATE_URL "$ACMEDNS_UPDATE_URL"
_saveaccountconf_mutable ACMEDNS_USERNAME "$ACMEDNS_USERNAME"
_saveaccountconf_mutable ACMEDNS_PASSWORD "$ACMEDNS_PASSWORD"
_saveaccountconf_mutable ACMEDNS_SUBDOMAIN "$ACMEDNS_SUBDOMAIN"
export _H1="X-Api-User: $ACMEDNS_USERNAME"
export _H2="X-Api-Key: $ACMEDNS_PASSWORD"
data="{\"subdomain\":\"$ACMEDNS_SUBDOMAIN\", \"txt\": \"$txtvalue\"}"
_debug data "$data"
response="$(_post "$data" "$ACMEDNS_UPDATE_URL" "" "POST")"
_debug response "$response"
if ! echo "$response" | grep "\"$txtvalue\"" >/dev/null; then
_err "invalid response of acme-dns"
return 1
fi
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_acmedns_rm() {
fulldomain=$1
txtvalue=$2
_info "Using acme-dns"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
}
#################### Private functions below ##################################

View File

@ -76,10 +76,10 @@ dns_azure_add() {
values="{\"value\":[\"$txtvalue\"]}" values="{\"value\":[\"$txtvalue\"]}"
timestamp="$(_time)" timestamp="$(_time)"
if [ "$_code" = "200" ]; then if [ "$_code" = "200" ]; then
vlist="$(echo "$response" | _egrep_o "\"value\"\s*:\s*\[\s*\"[^\"]*\"\s*]" | cut -d : -f 2 | tr -d "[]\"")" vlist="$(echo "$response" | _egrep_o "\"value\"\\s*:\\s*\\[\\s*\"[^\"]*\"\\s*]" | cut -d : -f 2 | tr -d "[]\"")"
_debug "existing TXT found" _debug "existing TXT found"
_debug "$vlist" _debug "$vlist"
existingts="$(echo "$response" | _egrep_o "\"acmetscheck\"\s*:\s*\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d "\"")" existingts="$(echo "$response" | _egrep_o "\"acmetscheck\"\\s*:\\s*\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d "\"")"
if [ -z "$existingts" ]; then if [ -z "$existingts" ]; then
# the record was not created by acme.sh. Copy the exisiting entires # the record was not created by acme.sh. Copy the exisiting entires
existingts=$timestamp existingts=$timestamp
@ -99,6 +99,7 @@ dns_azure_add() {
_azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken"
if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then
_info "validation value added" _info "validation value added"
return 0
else else
_err "error adding validation value ($_code)" _err "error adding validation value ($_code)"
return 1 return 1
@ -171,7 +172,7 @@ dns_azure_rm() {
_azure_rest GET "$acmeRecordURI" "" "$accesstoken" _azure_rest GET "$acmeRecordURI" "" "$accesstoken"
timestamp="$(_time)" timestamp="$(_time)"
if [ "$_code" = "200" ]; then if [ "$_code" = "200" ]; then
vlist="$(echo "$response" | _egrep_o "\"value\"\s*:\s*\[\s*\"[^\"]*\"\s*]" | cut -d : -f 2 | tr -d "[]\"" | grep -v "$txtvalue")" vlist="$(echo "$response" | _egrep_o "\"value\"\\s*:\\s*\\[\\s*\"[^\"]*\"\\s*]" | cut -d : -f 2 | tr -d "[]\"" | grep -v "$txtvalue")"
values="" values=""
comma="" comma=""
for v in $vlist; do for v in $vlist; do
@ -194,6 +195,7 @@ dns_azure_rm() {
_azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken"
if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then
_info "validation value removed" _info "validation value removed"
return 0
else else
_err "error removing validation value ($_code)" _err "error removing validation value ($_code)"
return 1 return 1
@ -226,8 +228,9 @@ _azure_rest() {
else else
response="$(_get "$ep")" response="$(_get "$ep")"
fi fi
_ret="$?"
_secure_debug2 "response $response" _secure_debug2 "response $response"
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
_debug "http response code $_code" _debug "http response code $_code"
if [ "$_code" = "401" ]; then if [ "$_code" = "401" ]; then
# we have an invalid access token set to expired # we have an invalid access token set to expired
@ -236,7 +239,7 @@ _azure_rest() {
return 1 return 1
fi fi
# See https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes # See https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes
if [ "$?" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then if [ "$_ret" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then
_request_retry_times="$(_math "$_request_retry_times" + 1)" _request_retry_times="$(_math "$_request_retry_times" + 1)"
_info "REST call error $_code retrying $ep in $_request_retry_times s" _info "REST call error $_code retrying $ep in $_request_retry_times s"
_sleep "$_request_retry_times" _sleep "$_request_retry_times"
@ -281,6 +284,7 @@ _azure_getaccess_token() {
body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials" body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
_secure_debug2 "data $body" _secure_debug2 "data $body"
response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")" response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")"
_ret="$?"
_secure_debug2 "response $response" _secure_debug2 "response $response"
response="$(echo "$response" | _normalizeJson)" response="$(echo "$response" | _normalizeJson)"
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
@ -290,7 +294,7 @@ _azure_getaccess_token() {
_err "no acccess token received. Check your Azure settings see $WIKI" _err "no acccess token received. Check your Azure settings see $WIKI"
return 1 return 1
fi fi
if [ "$?" != "0" ]; then if [ "$_ret" != "0" ]; then
_err "error $response" _err "error $response"
return 1 return 1
fi fi
@ -304,7 +308,7 @@ _get_root() {
domain=$1 domain=$1
subscriptionId=$2 subscriptionId=$2
accesstoken=$3 accesstoken=$3
i=2 i=1
p=1 p=1
## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list ## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list
@ -324,9 +328,14 @@ _get_root() {
fi fi
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
_domain_id=$(echo "$response" | _egrep_o "\{\"id\":\"[^\"]*$h\"" | head -n 1 | cut -d : -f 2 | tr -d \") _domain_id=$(echo "$response" | _egrep_o "\\{\"id\":\"[^\"]*$h\"" | head -n 1 | cut -d : -f 2 | tr -d \")
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) if [ "$i" = 1 ]; then
#create the record at the domain apex (@) if only the domain name was provided as --domain-alias
_sub_domain="@"
else
_sub_domain=$(echo "$domain" | cut -d . -f 1-$p)
fi
_domain=$h _domain=$h
return 0 return 0
fi fi

View File

@ -19,8 +19,8 @@ dns_cf_add() {
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
CF_Key="" CF_Key=""
CF_Email="" CF_Email=""
_err "You don't specify cloudflare api key and email yet." _err "You didn't specify a cloudflare api key and email yet."
_err "Please create you key and try again." _err "Please create the key and try again."
return 1 return 1
fi fi
@ -94,8 +94,8 @@ dns_cf_rm() {
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
CF_Key="" CF_Key=""
CF_Email="" CF_Email=""
_err "You don't specify cloudflare api key and email yet." _err "You didn't specify a cloudflare api key and email yet."
_err "Please create you key and try again." _err "Please create the key and try again."
return 1 return 1
fi fi

184
dnsapi/dns_da.sh Executable file
View File

@ -0,0 +1,184 @@
#!/usr/bin/env sh
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
# vim: et ts=2 sw=2
#
# DirectAdmin 1.41.0 API
# The DirectAdmin interface has it's own Let's encrypt functionality, but this
# script can be used to generate certificates for names which are not hosted on
# DirectAdmin
#
# User must provide login data and URL to DirectAdmin incl. port.
# You can create login key, by using the Login Keys function
# ( https://da.example.com:8443/CMD_LOGIN_KEYS ), which only has access to
# - CMD_API_DNS_CONTROL
# - CMD_API_SHOW_DOMAINS
#
# See also https://www.directadmin.com/api.php and
# https://www.directadmin.com/features.php?id=1298
#
# Report bugs to https://github.com/TigerP/acme.sh/issues
#
# Values to export:
# export DA_Api="https://remoteUser:remotePassword@da.example.com:8443"
# export DA_Api_Insecure=1
#
# Set DA_Api_Insecure to 1 for insecure and 0 for secure -> difference is
# whether ssl cert is checked for validity (0) or whether it is just accepted
# (1)
#
######## Public functions #####################
# Usage: dns_myapi_add _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record
dns_da_add() {
fulldomain="${1}"
txtvalue="${2}"
_debug "Calling: dns_da_add() '${fulldomain}' '${txtvalue}'"
_DA_credentials && _DA_getDomainInfo && _DA_addTxt
}
# Usage: dns_da_rm _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to remove the txt record after validation
dns_da_rm() {
fulldomain="${1}"
txtvalue="${2}"
_debug "Calling: dns_da_rm() '${fulldomain}' '${txtvalue}'"
_DA_credentials && _DA_getDomainInfo && _DA_rmTxt
}
#################### Private functions below ##################################
# Usage: _DA_credentials
# It will check if the needed settings are available
_DA_credentials() {
DA_Api="${DA_Api:-$(_readaccountconf_mutable DA_Api)}"
DA_Api_Insecure="${DA_Api_Insecure:-$(_readaccountconf_mutable DA_Api_Insecure)}"
if [ -z "${DA_Api}" ] || [ -z "${DA_Api_Insecure}" ]; then
DA_Api=""
DA_Api_Insecure=""
_err "You haven't specified the DirectAdmin Login data, URL and whether you want check the DirectAdmin SSL cert. Please try again."
return 1
else
_saveaccountconf_mutable DA_Api "${DA_Api}"
_saveaccountconf_mutable DA_Api_Insecure "${DA_Api_Insecure}"
# Set whether curl should use secure or insecure mode
export HTTPS_INSECURE="${DA_Api_Insecure}"
fi
}
# Usage: _get_root _acme-challenge.www.example.com
# Split the full domain to a domain and subdomain
#returns
# _sub_domain=_acme-challenge.www
# _domain=example.com
_get_root() {
domain=$1
i=2
p=1
# Get a list of all the domains
# response will contain "list[]=example.com&list[]=example.org"
_da_api CMD_API_SHOW_DOMAINS "" "${domain}"
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
# not valid
_debug "The given domain $h is not valid"
return 1
fi
if _contains "$response" "$h" >/dev/null; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain=$h
return 0
fi
p=$i
i=$(_math "$i" + 1)
done
_debug "Stop on 100"
return 1
}
# Usage: _da_api CMD_API_* data example.com
# Use the DirectAdmin API and check the result
# returns
# response="error=0&text=Result text&details="
_da_api() {
cmd=$1
data=$2
domain=$3
_debug "$domain; $data"
response="$(_post "$data" "$DA_Api/$cmd" "" "POST")"
if [ "$?" != "0" ]; then
_err "error $cmd"
return 1
fi
_debug response "$response"
case "${cmd}" in
CMD_API_DNS_CONTROL)
# Parse the result in general
# error=0&text=Records Deleted&details=
# error=1&text=Cannot View Dns Record&details=No domain provided
err_field="$(_getfield "$response" 1 '&')"
txt_field="$(_getfield "$response" 2 '&')"
details_field="$(_getfield "$response" 3 '&')"
error="$(_getfield "$err_field" 2 '=')"
text="$(_getfield "$txt_field" 2 '=')"
details="$(_getfield "$details_field" 2 '=')"
_debug "error: ${error}, text: ${text}, details: ${details}"
if [ "$error" != "0" ]; then
_err "error $response"
return 1
fi
;;
CMD_API_SHOW_DOMAINS) ;;
esac
return 0
}
# Usage: _DA_getDomainInfo
# Get the root zone if possible
_DA_getDomainInfo() {
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
else
_debug "The root domain: $_domain"
_debug "The sub domain: $_sub_domain"
fi
return 0
}
# Usage: _DA_addTxt
# Use the API to add a record
_DA_addTxt() {
curData="domain=${_domain}&action=add&type=TXT&name=${_sub_domain}&value=\"${txtvalue}\""
_debug "Calling _DA_addTxt: '${curData}' '${DA_Api}/CMD_API_DNS_CONTROL'"
_da_api CMD_API_DNS_CONTROL "${curData}" "${_domain}"
_debug "Result of _DA_addTxt: '$response'"
if _contains "${response}" 'error=0'; then
_debug "Add TXT succeeded"
return 0
fi
_debug "Add TXT failed"
return 1
}
# Usage: _DA_rmTxt
# Use the API to remove a record
_DA_rmTxt() {
curData="domain=${_domain}&action=select&txtrecs0=name=${_sub_domain}&amp;value=\"${txtvalue}\""
_debug "Calling _DA_rmTxt: '${curData}' '${DA_Api}/CMD_API_DNS_CONTROL'"
if _da_api CMD_API_DNS_CONTROL "${curData}" "${_domain}"; then
_debug "Result of _DA_rmTxt: '$response'"
else
_err "Result of _DA_rmTxt: '$response'"
fi
if _contains "${response}" 'error=0'; then
_debug "RM TXT succeeded"
return 0
fi
_debug "RM TXT failed"
return 1
}

View File

@ -20,12 +20,22 @@
dns_dgon_add() { dns_dgon_add() {
fulldomain="$(echo "$1" | _lower_case)" fulldomain="$(echo "$1" | _lower_case)"
txtvalue=$2 txtvalue=$2
DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}"
# Check if API Key Exist
if [ -z "$DO_API_KEY" ]; then
DO_API_KEY=""
_err "You did not specify DigitalOcean API key."
_err "Please export DO_API_KEY and try again."
return 1
fi
_info "Using digitalocean dns validation - add record" _info "Using digitalocean dns validation - add record"
_debug fulldomain "$fulldomain" _debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue" _debug txtvalue "$txtvalue"
## save the env vars (key and domain split location) for later automated use ## save the env vars (key and domain split location) for later automated use
_saveaccountconf DO_API_KEY "$DO_API_KEY" _saveaccountconf_mutable DO_API_KEY "$DO_API_KEY"
## split the domain for DO API ## split the domain for DO API
if ! _get_base_domain "$fulldomain"; then if ! _get_base_domain "$fulldomain"; then
@ -39,7 +49,7 @@ dns_dgon_add() {
export _H1="Content-Type: application/json" export _H1="Content-Type: application/json"
export _H2="Authorization: Bearer $DO_API_KEY" export _H2="Authorization: Bearer $DO_API_KEY"
PURL='https://api.digitalocean.com/v2/domains/'$_domain'/records' PURL='https://api.digitalocean.com/v2/domains/'$_domain'/records'
PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'"}' PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'","ttl":120}'
_debug PURL "$PURL" _debug PURL "$PURL"
_debug PBODY "$PBODY" _debug PBODY "$PBODY"
@ -65,6 +75,16 @@ dns_dgon_add() {
dns_dgon_rm() { dns_dgon_rm() {
fulldomain="$(echo "$1" | _lower_case)" fulldomain="$(echo "$1" | _lower_case)"
txtvalue=$2 txtvalue=$2
DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}"
# Check if API Key Exist
if [ -z "$DO_API_KEY" ]; then
DO_API_KEY=""
_err "You did not specify DigitalOcean API key."
_err "Please export DO_API_KEY and try again."
return 1
fi
_info "Using digitalocean dns validation - remove record" _info "Using digitalocean dns validation - remove record"
_debug fulldomain "$fulldomain" _debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue" _debug txtvalue "$txtvalue"
@ -92,11 +112,11 @@ dns_dgon_rm() {
domain_list="$(_get "$GURL")" domain_list="$(_get "$GURL")"
## 2) find record ## 2) find record
## check for what we are looing for: "type":"A","name":"$_sub_domain" ## check for what we are looing for: "type":"A","name":"$_sub_domain"
record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*\d+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")" record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[0-9]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")"
## 3) check record and get next page ## 3) check record and get next page
if [ -z "$record" ]; then if [ -z "$record" ]; then
## find the next page if we dont have a match ## find the next page if we dont have a match
nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=\d+")" nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")"
if [ -z "$nextpage" ]; then if [ -z "$nextpage" ]; then
_err "no record and no nextpage in digital ocean DNS removal" _err "no record and no nextpage in digital ocean DNS removal"
return 1 return 1
@ -108,7 +128,7 @@ dns_dgon_rm() {
done done
## we found the record ## we found the record
rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*\d+" | _egrep_o "\d+")" rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
_debug rec_id "$rec_id" _debug rec_id "$rec_id"
## delete the record ## delete the record

View File

@ -39,34 +39,17 @@ dns_dnsimple_add() {
_get_records "$_account_id" "$_domain" "$_sub_domain" _get_records "$_account_id" "$_domain" "$_sub_domain"
if [ "$_records_count" = "0" ]; then _info "Adding record"
_info "Adding record" if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then
if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then _info "Added"
_info "Added"
return 0
else
_err "Unexpected response while adding text record."
return 1
fi
fi
_err "Add txt record error."
else
_info "Updating record"
_extract_record_id "$_records" "$_sub_domain"
if _dnsimple_rest \
PATCH \
"$_account_id/zones/$_domain/records/$_record_id" \
"{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
_info "Updated!"
return 0 return 0
else
_err "Unexpected response while adding text record."
return 1
fi fi
_err "Update error"
return 1
fi fi
_err "Add txt record error."
} }
# fulldomain # fulldomain
@ -84,19 +67,19 @@ dns_dnsimple_rm() {
fi fi
_get_records "$_account_id" "$_domain" "$_sub_domain" _get_records "$_account_id" "$_domain" "$_sub_domain"
_extract_record_id "$_records" "$_sub_domain" _extract_record_id "$_records" "$_sub_domain"
if [ "$_record_id" ]; then if [ "$_record_id" ]; then
echo "$_record_id" | while read -r item; do
if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id"; then if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$item"; then
_info "removed record" "$_record_id" _info "removed record" "$item"
return 0 return 0
fi else
_err "failed to remove record" "$item"
return 1
fi
done
fi fi
_err "failed to remove record" "$_record_id"
return 1
} }
#################### Private functions bellow ################################## #################### Private functions bellow ##################################

View File

@ -53,8 +53,9 @@ dns_freedns_add() {
i="$(_math "$i" - 1)" i="$(_math "$i" - 1)"
sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")"
_debug top_domain "$top_domain" _debug "top_domain: $top_domain"
_debug sub_domain "$sub_domain" _debug "sub_domain: $sub_domain"
# Sometimes FreeDNS does not return the subdomain page but rather # Sometimes FreeDNS does not return the subdomain page but rather
# returns a page regarding becoming a premium member. This usually # returns a page regarding becoming a premium member. This usually
# happens after a period of inactivity. Immediately trying again # happens after a period of inactivity. Immediately trying again
@ -63,6 +64,7 @@ dns_freedns_add() {
attempts=2 attempts=2
while [ "$attempts" -gt "0" ]; do while [ "$attempts" -gt "0" ]; do
attempts="$(_math "$attempts" - 1)" attempts="$(_math "$attempts" - 1)"
htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
if [ "$using_cached_cookies" = "true" ]; then if [ "$using_cached_cookies" = "true" ]; then
@ -71,10 +73,9 @@ dns_freedns_add() {
fi fi
return 1 return 1
fi fi
_debug2 htmlpage "$htmlpage"
subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '<form .*</form>' | sed 's/<tr>/@<tr>/g' | tr '@' '\n' | grep edit.php | grep "$top_domain")" subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '<form .*</form>' | sed 's/<tr>/@<tr>/g' | tr '@' '\n' | grep edit.php | grep "$top_domain")"
_debug2 subdomain_csv "$subdomain_csv" _debug3 "subdomain_csv: $subdomain_csv"
# The above beauty ends with striping out rows that do not have an # The above beauty ends with striping out rows that do not have an
# href to edit.php and do not have the top domain we are looking for. # href to edit.php and do not have the top domain we are looking for.
@ -85,55 +86,25 @@ dns_freedns_add() {
lines="$(echo "$subdomain_csv" | wc -l)" lines="$(echo "$subdomain_csv" | wc -l)"
i=0 i=0
found=0 found=0
DNSdomainid=""
while [ "$i" -lt "$lines" ]; do while [ "$i" -lt "$lines" ]; do
i="$(_math "$i" + 1)" i="$(_math "$i" + 1)"
line="$(echo "$subdomain_csv" | sed -n "${i}p")" line="$(echo "$subdomain_csv" | sed -n "${i}p")"
_debug2 line "$line" _debug2 "line: $line"
if [ $found = 0 ] && _contains "$line" "<td>$top_domain</td>"; then if [ $found = 0 ] && _contains "$line" "<td>$top_domain</td>"; then
# this line will contain DNSdomainid for the top_domain # this line will contain DNSdomainid for the top_domain
DNSdomainid="$(echo "$line" | _egrep_o "edit_domain_id *= *.*>" | cut -d = -f 2 | cut -d '>' -f 1)" DNSdomainid="$(echo "$line" | _egrep_o "edit_domain_id *= *.*>" | cut -d = -f 2 | cut -d '>' -f 1)"
_debug2 DNSdomainid "$DNSdomainid" _debug2 "DNSdomainid: $DNSdomainid"
found=1 found=1
else break
# lines contain DNS records for all subdomains
DNSname="$(echo "$line" | _egrep_o 'edit.php.*</a>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
_debug2 DNSname "$DNSname"
DNStype="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '4p' | cut -d '>' -f 2 | cut -d '<' -f 1)"
_debug2 DNStype "$DNStype"
if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then
DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)"
# Now get current value for the TXT record. This method may
# not produce accurate results as the value field is truncated
# on this webpage. To get full value we would need to load
# another page. However we don't really need this so long as
# there is only one TXT record for the acme challenge subdomain.
DNSvalue="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '5p' | cut -d '>' -f 2 | cut -d '<' -f 1)"
_debug2 DNSvalue "$DNSvalue"
if [ $found != 0 ]; then
break
# we are breaking out of the loop at the first match of DNS name
# and DNS type (if we are past finding the domainid). This assumes
# that there is only ever one TXT record for the LetsEncrypt/acme
# challenge subdomain. This seems to be a reasonable assumption
# as the acme client deletes the TXT record on successful validation.
fi
else
DNSname=""
DNStype=""
fi
fi fi
done done
_debug "DNSname: $DNSname DNStype: $DNStype DNSdomainid: $DNSdomainid DNSdataid: $DNSdataid"
_debug "DNSvalue: $DNSvalue"
if [ -z "$DNSdomainid" ]; then if [ -z "$DNSdomainid" ]; then
# If domain ID is empty then something went wrong (top level # If domain ID is empty then something went wrong (top level
# domain not found at FreeDNS). # domain not found at FreeDNS).
if [ "$attempts" = "0" ]; then if [ "$attempts" = "0" ]; then
# exhausted maximum retry attempts # exhausted maximum retry attempts
_debug "$htmlpage"
_debug "$subdomain_csv"
_err "Domain $top_domain not found at FreeDNS" _err "Domain $top_domain not found at FreeDNS"
return 1 return 1
fi fi
@ -145,33 +116,10 @@ dns_freedns_add() {
_info "Retry loading subdomain page ($attempts attempts remaining)" _info "Retry loading subdomain page ($attempts attempts remaining)"
done done
if [ -z "$DNSdataid" ]; then # Add in new TXT record with the value provided
# If data ID is empty then specific subdomain does not exist yet, need _debug "Adding TXT record for $fulldomain, $txtvalue"
# to create it this should always be the case as the acme client _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue"
# deletes the entry after domain is validated. return $?
_freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue"
return $?
else
if [ "$txtvalue" = "$DNSvalue" ]; then
# if value in TXT record matches value requested then DNS record
# does not need to be updated. But...
# Testing value match fails. Website is truncating the value field.
# So for now we will always go down the else path. Though in theory
# should never come here anyway as the acme client deletes
# the TXT record on successful validation, so we should not even
# have found a TXT record !!
_info "No update necessary for $fulldomain at FreeDNS"
return 0
else
# Delete the old TXT record (with the wrong value)
if _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"; then
# And add in new TXT record with the value provided
_freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue"
fi
return $?
fi
fi
return 0
} }
#Usage: fulldomain txtvalue #Usage: fulldomain txtvalue
@ -205,7 +153,7 @@ dns_freedns_rm() {
fi fi
subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '<form .*</form>' | sed 's/<tr>/@<tr>/g' | tr '@' '\n' | grep edit.php | grep "$fulldomain")" subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '<form .*</form>' | sed 's/<tr>/@<tr>/g' | tr '@' '\n' | grep edit.php | grep "$fulldomain")"
_debug2 subdomain_csv "$subdomain_csv" _debug3 "subdomain_csv: $subdomain_csv"
# The above beauty ends with striping out rows that do not have an # The above beauty ends with striping out rows that do not have an
# href to edit.php and do not have the domain name we are looking for. # href to edit.php and do not have the domain name we are looking for.
@ -216,35 +164,51 @@ dns_freedns_rm() {
lines="$(echo "$subdomain_csv" | wc -l)" lines="$(echo "$subdomain_csv" | wc -l)"
i=0 i=0
found=0 found=0
DNSdataid=""
while [ "$i" -lt "$lines" ]; do while [ "$i" -lt "$lines" ]; do
i="$(_math "$i" + 1)" i="$(_math "$i" + 1)"
line="$(echo "$subdomain_csv" | sed -n "${i}p")" line="$(echo "$subdomain_csv" | sed -n "${i}p")"
_debug2 line "$line" _debug3 "line: $line"
DNSname="$(echo "$line" | _egrep_o 'edit.php.*</a>' | cut -d '>' -f 2 | cut -d '<' -f 1)" DNSname="$(echo "$line" | _egrep_o 'edit.php.*</a>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
_debug2 DNSname "$DNSname" _debug2 "DNSname: $DNSname"
DNStype="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '4p' | cut -d '>' -f 2 | cut -d '<' -f 1)" if [ "$DNSname" = "$fulldomain" ]; then
_debug2 DNStype "$DNStype" DNStype="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '4p' | cut -d '>' -f 2 | cut -d '<' -f 1)"
if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then _debug2 "DNStype: $DNStype"
DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)" if [ "$DNStype" = "TXT" ]; then
_debug2 DNSdataid "$DNSdataid" DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)"
DNSvalue="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '5p' | cut -d '>' -f 2 | cut -d '<' -f 1)" _debug2 "DNSdataid: $DNSdataid"
_debug2 DNSvalue "$DNSvalue" DNSvalue="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '5p' | cut -d '>' -f 2 | cut -d '<' -f 1)"
# if [ "$DNSvalue" = "$txtvalue" ]; then if _startswith "$DNSvalue" "&quot;"; then
# Testing value match fails. Website is truncating the value # remove the quotation from the start
# field. So for now we will assume that there is only one TXT DNSvalue="$(echo "$DNSvalue" | cut -c 7-)"
# field for the sub domain and just delete it. Currently this fi
# is a safe assumption. if _endswith "$DNSvalue" "..."; then
_freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" # value was truncated, remove the dot dot dot from the end
return $? DNSvalue="$(echo "$DNSvalue" | sed 's/...$//')"
# fi elif _endswith "$DNSvalue" "&quot;"; then
# else remove the closing quotation from the end
DNSvalue="$(echo "$DNSvalue" | sed 's/......$//')"
fi
_debug2 "DNSvalue: $DNSvalue"
if [ -n "$DNSdataid" ] && _startswith "$txtvalue" "$DNSvalue"; then
# Found a match. But note... Website is truncating the
# value field so we are only testing that part that is not
# truncated. This should be accurate enough.
_debug "Deleting TXT record for $fulldomain, $txtvalue"
_freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"
return $?
fi
fi
fi fi
done done
done done
# If we get this far we did not find a match (after two attempts) # If we get this far we did not find a match (after two attempts)
# Not necessarily an error, but log anyway. # Not necessarily an error, but log anyway.
_debug2 "$subdomain_csv" _debug3 "$subdomain_csv"
_info "Cannot delete TXT record for $fulldomain/$txtvalue. Does not exist at FreeDNS" _info "Cannot delete TXT record for $fulldomain, $txtvalue. Does not exist at FreeDNS"
return 0 return 0
} }
@ -272,7 +236,7 @@ _freedns_login() {
# if cookies is not empty then logon successful # if cookies is not empty then logon successful
if [ -z "$cookies" ]; then if [ -z "$cookies" ]; then
_debug "$htmlpage" _debug3 "htmlpage: $htmlpage"
_err "FreeDNS login failed for user $username. Check $HTTP_HEADER file" _err "FreeDNS login failed for user $username. Check $HTTP_HEADER file"
return 1 return 1
fi fi
@ -301,7 +265,7 @@ _freedns_retrieve_subdomain_page() {
return 1 return 1
fi fi
_debug2 "$htmlpage" _debug3 "htmlpage: $htmlpage"
printf "%s" "$htmlpage" printf "%s" "$htmlpage"
return 0 return 0
@ -315,7 +279,7 @@ _freedns_add_txt_record() {
domain_id="$2" domain_id="$2"
subdomain="$3" subdomain="$3"
value="$(printf '%s' "$4" | _url_encode)" value="$(printf '%s' "$4" | _url_encode)"
url="http://freedns.afraid.org/subdomain/save.php?step=2" url="https://freedns.afraid.org/subdomain/save.php?step=2"
htmlpage="$(_post "type=TXT&domain_id=$domain_id&subdomain=$subdomain&address=%22$value%22&send=Save%21" "$url")" htmlpage="$(_post "type=TXT&domain_id=$domain_id&subdomain=$subdomain&address=%22$value%22&send=Save%21" "$url")"
@ -323,17 +287,17 @@ _freedns_add_txt_record() {
_err "FreeDNS failed to add TXT record for $subdomain bad RC from _post" _err "FreeDNS failed to add TXT record for $subdomain bad RC from _post"
return 1 return 1
elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then
_debug "$htmlpage" _debug3 "htmlpage: $htmlpage"
_err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file" _err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file"
return 1 return 1
elif _contains "$htmlpage" "security code was incorrect"; then elif _contains "$htmlpage" "security code was incorrect"; then
_debug "$htmlpage" _debug3 "htmlpage: $htmlpage"
_err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested security code" _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested security code"
_err "Note that you cannot use automatic DNS validation for FreeDNS public domains" _err "Note that you cannot use automatic DNS validation for FreeDNS public domains"
return 1 return 1
fi fi
_debug2 "$htmlpage" _debug3 "htmlpage: $htmlpage"
_info "Added acme challenge TXT record for $fulldomain at FreeDNS" _info "Added acme challenge TXT record for $fulldomain at FreeDNS"
return 0 return 0
} }
@ -352,7 +316,7 @@ _freedns_delete_txt_record() {
_err "FreeDNS failed to delete TXT record for $data_id bad RC from _get" _err "FreeDNS failed to delete TXT record for $data_id bad RC from _get"
return 1 return 1
elif ! _contains "$htmlheader" "200 OK"; then elif ! _contains "$htmlheader" "200 OK"; then
_debug "$htmlheader" _debug2 "htmlheader: $htmlheader"
_err "FreeDNS failed to delete TXT record $data_id" _err "FreeDNS failed to delete TXT record $data_id"
return 1 return 1
fi fi

View File

@ -59,19 +59,13 @@ dns_gd_add() {
_info "Adding record" _info "Adding record"
if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then
if [ "$response" = "{}" ]; then _info "Added, sleeping 10 seconds"
_info "Added, sleeping 10 seconds" _sleep 10
_sleep 10 #todo: check if the record takes effect
#todo: check if the record takes effect return 0
return 0
else
_err "Add txt record error."
_err "$response"
return 1
fi
fi fi
_err "Add txt record error." _err "Add txt record error."
return 1
} }
#fulldomain #fulldomain
@ -174,5 +168,9 @@ _gd_rest() {
return 1 return 1
fi fi
_debug2 response "$response" _debug2 response "$response"
if _contains "$response" "UNABLE_TO_AUTHENTICATE"; then
_err "It seems that your api key or secret is not correct."
return 1
fi
return 0 return 0
} }

View File

@ -33,8 +33,9 @@ dns_he_add() {
# Fills in the $_zone_id # Fills in the $_zone_id
_find_zone "$_full_domain" || return 1 _find_zone "$_full_domain" || return 1
_debug "Zone id \"$_zone_id\" will be used." _debug "Zone id \"$_zone_id\" will be used."
username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)"
body="email=${HE_Username}&pass=${HE_Password}" password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)"
body="email=${username_encoded}&pass=${password_encoded}"
body="$body&account=" body="$body&account="
body="$body&menu=edit_zone" body="$body&menu=edit_zone"
body="$body&Type=TXT" body="$body&Type=TXT"
@ -71,7 +72,9 @@ dns_he_rm() {
_debug "Zone id \"$_zone_id\" will be used." _debug "Zone id \"$_zone_id\" will be used."
# Find the record id to clean # Find the record id to clean
body="email=${HE_Username}&pass=${HE_Password}" username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)"
password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)"
body="email=${username_encoded}&pass=${password_encoded}"
body="$body&hosted_dns_zoneid=$_zone_id" body="$body&hosted_dns_zoneid=$_zone_id"
body="$body&menu=edit_zone" body="$body&menu=edit_zone"
body="$body&hosted_dns_editzone=" body="$body&hosted_dns_editzone="
@ -112,9 +115,15 @@ dns_he_rm() {
_find_zone() { _find_zone() {
_domain="$1" _domain="$1"
body="email=${HE_Username}&pass=${HE_Password}" username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)"
password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)"
body="email=${username_encoded}&pass=${password_encoded}"
response="$(_post "$body" "https://dns.he.net/")" response="$(_post "$body" "https://dns.he.net/")"
_debug2 response "$response" _debug2 response "$response"
if _contains "$response" '>Incorrect<'; then
_err "Unable to login to dns.he.net please check username and password"
return 1
fi
_table="$(echo "$response" | tr -d "#" | sed "s/<table/#<table/g" | tr -d "\n" | tr "#" "\n" | grep 'id="domains_table"')" _table="$(echo "$response" | tr -d "#" | sed "s/<table/#<table/g" | tr -d "\n" | tr "#" "\n" | grep 'id="domains_table"')"
_debug2 _table "$_table" _debug2 _table "$_table"
_matches="$(echo "$_table" | sed "s/<tr/#<tr/g" | tr "#" "\n" | grep 'alt="edit"' | tr -d " " | sed "s/<td/#<td/g" | tr "#" "\n" | grep 'hosted_dns_zoneid')" _matches="$(echo "$_table" | sed "s/<tr/#<tr/g" | tr "#" "\n" | grep 'alt="edit"' | tr -d " " | sed "s/<td/#<td/g" | tr "#" "\n" | grep 'hosted_dns_zoneid')"
@ -143,7 +152,7 @@ _find_zone() {
_debug "Looking for zone \"${_attempted_zone}\"" _debug "Looking for zone \"${_attempted_zone}\""
line_num="$(echo "$_zone_names" | grep -n "$_attempted_zone" | cut -d : -f 1)" line_num="$(echo "$_zone_names" | grep -n "^$_attempted_zone" | cut -d : -f 1)"
if [ "$line_num" ]; then if [ "$line_num" ]; then
_zone_id=$(echo "$_zone_ids" | sed -n "${line_num}p") _zone_id=$(echo "$_zone_ids" | sed -n "${line_num}p")

View File

@ -4,6 +4,10 @@
#INWX_User="username" #INWX_User="username"
# #
#INWX_Password="password" #INWX_Password="password"
#
# Dependencies:
# -------------
# - oathtool (When using 2 Factor Authentication)
INWX_Api="https://api.domrobot.com/xmlrpc/" INWX_Api="https://api.domrobot.com/xmlrpc/"
@ -16,6 +20,7 @@ dns_inwx_add() {
INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}" INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}"
INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}" INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}"
INWX_Shared_Secret="${INWX_Shared_Secret:-$(_readaccountconf_mutable INWX_Shared_Secret)}"
if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then
INWX_User="" INWX_User=""
INWX_Password="" INWX_Password=""
@ -27,6 +32,7 @@ dns_inwx_add() {
#save the api key and email to the account conf file. #save the api key and email to the account conf file.
_saveaccountconf_mutable INWX_User "$INWX_User" _saveaccountconf_mutable INWX_User "$INWX_User"
_saveaccountconf_mutable INWX_Password "$INWX_Password" _saveaccountconf_mutable INWX_Password "$INWX_Password"
_saveaccountconf_mutable INWX_Shared_Secret "$INWX_Shared_Secret"
_debug "First detect the root zone" _debug "First detect the root zone"
if ! _get_root "$fulldomain"; then if ! _get_root "$fulldomain"; then
@ -148,8 +154,46 @@ _inwx_login() {
</methodCall>' $INWX_User $INWX_Password) </methodCall>' $INWX_User $INWX_Password)
response="$(_post "$xml_content" "$INWX_Api" "" "POST")" response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
_H1=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')")
export _H1
printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')" #https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71
if _contains "$response" "tfa"; then
if [ -z "$INWX_Shared_Secret" ]; then
_err "Mobile TAN detected."
_err "Please define a shared secret."
return 1
fi
if ! _exists oathtool; then
_err "Please install oathtool to use 2 Factor Authentication."
_err ""
return 1
fi
tan="$(oathtool --base32 --totp "${INWX_Shared_Secret}" 2>/dev/null)"
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>account.unlock</methodName>
<params>
<param>
<value>
<struct>
<member>
<name>tan</name>
<value>
<string>%s</string>
</value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>' "$tan")
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
fi
} }
@ -161,8 +205,8 @@ _get_root() {
i=2 i=2
p=1 p=1
_H1=$(_inwx_login) _inwx_login
export _H1
xml_content='<?xml version="1.0" encoding="UTF-8"?> xml_content='<?xml version="1.0" encoding="UTF-8"?>
<methodCall> <methodCall>
<methodName>nameserver.list</methodName> <methodName>nameserver.list</methodName>

View File

@ -128,7 +128,7 @@ _ISPC_addTxt() {
curSerial="$(date +%s)" curSerial="$(date +%s)"
curStamp="$(date +'%F %T')" curStamp="$(date +'%F %T')"
params="\"server_id\":\"${server_id}\",\"zone\":\"${zone}\",\"name\":\"${fulldomain}.\",\"type\":\"txt\",\"data\":\"${txtvalue}\",\"aux\":\"0\",\"ttl\":\"3600\",\"active\":\"y\",\"stamp\":\"${curStamp}\",\"serial\":\"${curSerial}\"" params="\"server_id\":\"${server_id}\",\"zone\":\"${zone}\",\"name\":\"${fulldomain}.\",\"type\":\"txt\",\"data\":\"${txtvalue}\",\"aux\":\"0\",\"ttl\":\"3600\",\"active\":\"y\",\"stamp\":\"${curStamp}\",\"serial\":\"${curSerial}\""
curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}}}" curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}},\"update_serial\":true}"
curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_add")" curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_add")"
_debug "Calling _ISPC_addTxt: '${curData}' '${ISPC_Api}?dns_txt_add'" _debug "Calling _ISPC_addTxt: '${curData}' '${ISPC_Api}?dns_txt_add'"
_debug "Result of _ISPC_addTxt: '$curResult'" _debug "Result of _ISPC_addTxt: '$curResult'"
@ -160,7 +160,7 @@ _ISPC_rmTxt() {
*) *)
unset IFS unset IFS
_info "Retrieved Record ID." _info "Retrieved Record ID."
curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\"}" curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\",\"update_serial\":true}"
curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")" curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")"
_debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_delete'" _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_delete'"
_debug "Result of _ISPC_rmTxt: '$curResult'" _debug "Result of _ISPC_rmTxt: '$curResult'"

107
dnsapi/dns_kinghost.sh Normal file
View File

@ -0,0 +1,107 @@
#!/usr/bin/env sh
############################################################
# KingHost API support #
# http://api.kinghost.net/doc/ #
# #
# Author: Felipe Keller Braz <felipebraz@kinghost.com.br> #
# Report Bugs here: https://github.com/kinghost/acme.sh #
# #
# Values to export: #
# export KINGHOST_Username="email@provider.com" #
# export KINGHOST_Password="xxxxxxxxxx" #
############################################################
KING_Api="https://api.kinghost.net/acme"
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record
dns_kinghost_add() {
fulldomain=$1
txtvalue=$2
KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}"
KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}"
if [ -z "$KINGHOST_Username" ] || [ -z "$KINGHOST_Password" ]; then
KINGHOST_Username=""
KINGHOST_Password=""
_err "You don't specify KingHost api password and email yet."
_err "Please create you key and try again."
return 1
fi
#save the credentials to the account conf file.
_saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username"
_saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password"
_debug "Getting txt records"
_kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue"
#This API call returns "status":"ok" if dns record does not exists
#We are creating a new txt record here, so we expect the "ok" status
if ! echo "$response" | grep '"status":"ok"' >/dev/null; then
_err "Error"
_err "$response"
return 1
fi
_kinghost_rest POST "dns" "name=$fulldomain&content=$txtvalue"
if ! echo "$response" | grep '"status":"ok"' >/dev/null; then
_err "Error"
_err "$response"
return 1
fi
return 0
}
# Usage: fulldomain txtvalue
# Used to remove the txt record after validation
dns_kinghost_rm() {
fulldomain=$1
txtvalue=$2
KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}"
KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}"
if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then
KINGHOST_Password=""
KINGHOST_Username=""
_err "You don't specify KingHost api key and email yet."
_err "Please create you key and try again."
return 1
fi
_kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue"
if ! echo "$response" | grep '"status":"ok"' >/dev/null; then
_err "Error"
_err "$response"
return 1
fi
return 0
}
#################### Private functions below ##################################
_kinghost_rest() {
method=$1
uri="$2"
data="$3"
_debug "$uri"
export _H1="X-Auth-Email: $KINGHOST_Username"
export _H2="X-Auth-Key: $KINGHOST_Password"
if [ "$method" != "GET" ]; then
_debug data "$data"
response="$(_post "$data" "$KING_Api/$uri.json" "" "$method")"
else
response="$(_get "$KING_Api/$uri.json?$data")"
fi
if [ "$?" != "0" ]; then
_err "error $uri"
return 1
fi
_debug2 response "$response"
return 0
}

227
dnsapi/dns_loopia.sh Normal file
View File

@ -0,0 +1,227 @@
#!/usr/bin/env sh
#
#LOOPIA_User="username"
#
#LOOPIA_Password="password"
LOOPIA_Api="https://api.loopia.se/RPCSERV"
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_loopia_add() {
fulldomain=$1
txtvalue=$2
LOOPIA_User="${LOOPIA_User:-$(_readaccountconf_mutable LOOPIA_User)}"
LOOPIA_Password="${LOOPIA_Password:-$(_readaccountconf_mutable LOOPIA_Password)}"
if [ -z "$LOOPIA_User" ] || [ -z "$LOOPIA_Password" ]; then
LOOPIA_User=""
LOOPIA_Password=""
_err "You don't specify loopia user and password yet."
_err "Please create you key and try again."
return 1
fi
#save the api key and email to the account conf file.
_saveaccountconf_mutable LOOPIA_User "$LOOPIA_User"
_saveaccountconf_mutable LOOPIA_Password "$LOOPIA_Password"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_info "Adding record"
_loopia_add_record "$_domain" "$_sub_domain"
_loopia_update_record "$_domain" "$_sub_domain" "$txtvalue"
}
dns_loopia_rm() {
fulldomain=$1
txtvalue=$2
LOOPIA_User="${LOOPIA_User:-$(_readaccountconf_mutable LOOPIA_User)}"
LOOPIA_Password="${LOOPIA_Password:-$(_readaccountconf_mutable LOOPIA_Password)}"
if [ -z "$LOOPIA_User" ] || [ -z "$LOOPIA_Password" ]; then
LOOPIA_User=""
LOOPIA_Password=""
_err "You don't specify LOOPIA user and password yet."
_err "Please create you key and try again."
return 1
fi
#save the api key and email to the account conf file.
_saveaccountconf_mutable LOOPIA_User "$LOOPIA_User"
_saveaccountconf_mutable LOOPIA_Password "$LOOPIA_Password"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>removeSubdomain</methodName>
<params>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$_domain" "$_sub_domain")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if ! _contains "$response" "OK"; then
_err "Error could not get txt records"
return 1
fi
}
#################### Private functions below ##################################
_get_root() {
domain=$1
_debug "get root"
domain=$1
i=2
p=1
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>getDomains</methodName>
<params>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password)
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
while true; do
h=$(echo "$domain" | cut -d . -f $i-100)
if [ -z "$h" ]; then
#not valid
return 1
fi
if _contains "$response" "$h"; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain="$h"
return 0
fi
p=$i
i=$(_math "$i" + 1)
done
return 1
}
_loopia_update_record() {
domain=$1
sub_domain=$2
txtval=$3
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>updateZoneRecord</methodName>
<params>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
<param>
<struct>
<member>
<name>type</name>
<value><string>TXT</string></value>
</member>
<member>
<name>priority</name>
<value><int>0</int></value>
</member>
<member>
<name>ttl</name>
<value><int>60</int></value>
</member>
<member>
<name>rdata</name>
<value><string>%s</string></value>
</member>
<member>
<name>record_id</name>
<value><int>0</int></value>
</member>
</struct>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain" "$txtval")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if ! _contains "$response" "OK"; then
_err "Error"
return 1
fi
return 0
}
_loopia_add_record() {
domain=$1
sub_domain=$2
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>addSubdomain</methodName>
<params>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if ! _contains "$response" "OK"; then
_err "Error"
return 1
fi
return 0
}

View File

@ -1,11 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#Author: RaidneII #Author: RaidenII
#Created 06/28/2017 #Created 06/28/2017
#Updated 03/01/2018, rewrote to support name.com API v4
#Utilize name.com API to finish dns-01 verifications. #Utilize name.com API to finish dns-01 verifications.
######## Public functions ##################### ######## Public functions #####################
Namecom_API="https://api.name.com/api" Namecom_API="https://api.name.com/v4"
#Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" #Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_namecom_add() { dns_namecom_add() {
@ -39,21 +40,18 @@ dns_namecom_add() {
# Find domain in domain list. # Find domain in domain list.
if ! _namecom_get_root "$fulldomain"; then if ! _namecom_get_root "$fulldomain"; then
_err "Unable to find domain specified." _err "Unable to find domain specified."
_namecom_logout
return 1 return 1
fi fi
# Add TXT record. # Add TXT record.
_namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}" _namecom_addtxt_json="{\"host\":\"$_sub_domain\",\"type\":\"TXT\",\"answer\":\"$txtvalue\",\"ttl\":\"300\"}"
if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then if _namecom_rest POST "domains/$_domain/records" "$_namecom_addtxt_json"; then
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") _retvalue=$(printf "%s\n" "$response" | _egrep_o "\"$_sub_domain\"")
if [ "$retcode" ]; then if [ "$_retvalue" ]; then
_info "Successfully added TXT record, ready for validation." _info "Successfully added TXT record, ready for validation."
_namecom_logout
return 0 return 0
else else
_err "Unable to add the DNS record." _err "Unable to add the DNS record."
_namecom_logout
return 1 return 1
fi fi
fi fi
@ -72,37 +70,28 @@ dns_namecom_rm() {
# Find domain in domain list. # Find domain in domain list.
if ! _namecom_get_root "$fulldomain"; then if ! _namecom_get_root "$fulldomain"; then
_err "Unable to find domain specified." _err "Unable to find domain specified."
_namecom_logout
return 1 return 1
fi fi
# Get the record id. # Get the record id.
if _namecom_rest GET "dns/list/$_domain"; then if _namecom_rest GET "domains/$_domain/records"; then
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") _record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]+,\"domainName\":\"$_domain\",\"host\":\"$_sub_domain\",\"fqdn\":\"$fulldomain.\",\"type\":\"TXT\",\"answer\":\"$txtvalue\"" | cut -d \" -f 3 | _egrep_o [0-9]+)
if [ "$retcode" ]; then _debug record_id "$_record_id"
_record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d \" -f 4) if [ "$_record_id" ]; then
_debug record_id "$_record_id"
_info "Successfully retrieved the record id for ACME challenge." _info "Successfully retrieved the record id for ACME challenge."
else else
_err "Unable to retrieve the record id." _err "Unable to retrieve the record id."
_namecom_logout
return 1 return 1
fi fi
fi fi
# Remove the DNS record using record id. # Remove the DNS record using record id.
_namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}" if _namecom_rest DELETE "domains/$_domain/records/$_record_id"; then
if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then _info "Successfully removed the TXT record."
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") return 0
if [ "$retcode" ]; then else
_info "Successfully removed the TXT record." _err "Unable to delete record id."
_namecom_logout return 1
return 0
else
_err "Unable to remove the DNS record."
_namecom_logout
return 1
fi
fi fi
} }
@ -112,8 +101,9 @@ _namecom_rest() {
param=$2 param=$2
data=$3 data=$3
export _H1="Content-Type: application/json" export _H1="Authorization: Basic $_namecom_auth"
export _H2="Api-Session-Token: $sessionkey" export _H2="Content-Type: application/json"
if [ "$method" != "GET" ]; then if [ "$method" != "GET" ]; then
response="$(_post "$data" "$Namecom_API/$param" "" "$method")" response="$(_post "$data" "$Namecom_API/$param" "" "$method")"
else else
@ -130,20 +120,15 @@ _namecom_rest() {
} }
_namecom_login() { _namecom_login() {
namecom_login_json="{\"username\":\"$Namecom_Username\",\"api_token\":\"$Namecom_Token\"}" # Auth string
# Name.com API v4 uses http basic auth to authenticate
# need to convert the token for http auth
_namecom_auth=$(printf "%s:%s" "$Namecom_Username" "$Namecom_Token" | _base64)
if _namecom_rest POST "login" "$namecom_login_json"; then if _namecom_rest GET "hello"; then
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") retcode=$(printf "%s\n" "$response" | _egrep_o "\"username\"\:\"$Namecom_Username\"")
if [ "$retcode" ]; then if [ "$retcode" ]; then
_info "Successfully logged in. Fetching session token..." _info "Successfully logged in."
sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4)
if [ ! -z "$sessionkey" ]; then
_debug sessionkey "$sessionkey"
_info "Session key obtained."
else
_err "Unable to get session key."
return 1
fi
else else
_err "Logging in failed." _err "Logging in failed."
return 1 return 1
@ -151,24 +136,12 @@ _namecom_login() {
fi fi
} }
_namecom_logout() {
if _namecom_rest GET "logout"; then
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100")
if [ "$retcode" ]; then
_info "Successfully logged out."
else
_err "Error logging out."
return 1
fi
fi
}
_namecom_get_root() { _namecom_get_root() {
domain=$1 domain=$1
i=2 i=2
p=1 p=1
if ! _namecom_rest GET "domain/list"; then if ! _namecom_rest GET "domains"; then
return 1 return 1
fi fi

View File

@ -8,12 +8,14 @@ dns_nsupdate_add() {
txtvalue=$2 txtvalue=$2
_checkKeyFile || return 1 _checkKeyFile || return 1
[ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost"
[ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53
# save the dns server and key to the account conf file. # save the dns server and key to the account conf file.
_saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}" _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}"
_saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}"
_saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}"
_info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\""
nsupdate -k "${NSUPDATE_KEY}" <<EOF nsupdate -k "${NSUPDATE_KEY}" <<EOF
server ${NSUPDATE_SERVER} server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
update add ${fulldomain}. 60 in txt "${txtvalue}" update add ${fulldomain}. 60 in txt "${txtvalue}"
send send
EOF EOF
@ -30,9 +32,10 @@ dns_nsupdate_rm() {
fulldomain=$1 fulldomain=$1
_checkKeyFile || return 1 _checkKeyFile || return 1
[ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost"
[ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53
_info "removing ${fulldomain}. txt" _info "removing ${fulldomain}. txt"
nsupdate -k "${NSUPDATE_KEY}" <<EOF nsupdate -k "${NSUPDATE_KEY}" <<EOF
server ${NSUPDATE_SERVER} server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
update delete ${fulldomain}. txt update delete ${fulldomain}. txt
send send
EOF EOF

View File

@ -69,15 +69,21 @@ dns_pdns_add() {
#fulldomain #fulldomain
dns_pdns_rm() { dns_pdns_rm() {
fulldomain=$1 fulldomain=$1
txtvalue=$2
if [ -z "$PDNS_Ttl" ]; then
PDNS_Ttl="$DEFAULT_PDNS_TTL"
fi
_debug "Detect root zone" _debug "Detect root zone"
if ! _get_root "$fulldomain"; then if ! _get_root "$fulldomain"; then
_err "invalid domain" _err "invalid domain"
return 1 return 1
fi fi
_debug _domain "$_domain" _debug _domain "$_domain"
if ! rm_record "$_domain" "$fulldomain"; then if ! rm_record "$_domain" "$fulldomain" "$txtvalue"; then
return 1 return 1
fi fi
@ -88,9 +94,16 @@ set_record() {
_info "Adding record" _info "Adding record"
root=$1 root=$1
full=$2 full=$2
txtvalue=$3 new_challenge=$3
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then _record_string=""
_build_record_string "$new_challenge"
_list_existingchallenges
for oldchallenge in $_existing_challenges; do
_build_record_string "$oldchallenge"
done
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}"; then
_err "Set txt record error." _err "Set txt record error."
return 1 return 1
fi fi
@ -106,14 +119,37 @@ rm_record() {
_info "Remove record" _info "Remove record"
root=$1 root=$1
full=$2 full=$2
txtvalue=$3
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then #Enumerate existing acme challenges
_err "Delete txt record error." _list_existingchallenges
return 1
fi
if ! notify_slaves "$root"; then if _contains "$_existing_challenges" "$txtvalue"; then
return 1 #Delete all challenges (PowerDNS API does not allow to delete content)
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then
_err "Delete txt record error."
return 1
fi
_record_string=""
#If the only existing challenge was the challenge to delete: nothing to do
if ! [ "$_existing_challenges" = "$txtvalue" ]; then
for oldchallenge in $_existing_challenges; do
#Build up the challenges to re-add, ommitting the one what should be deleted
if ! [ "$oldchallenge" = "$txtvalue" ]; then
_build_record_string "$oldchallenge"
fi
done
#Recreate the existing challenges
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}"; then
_err "Set txt record error."
return 1
fi
fi
if ! notify_slaves "$root"; then
return 1
fi
else
_info "Record not found, nothing to remove"
fi fi
return 0 return 0
@ -122,7 +158,7 @@ rm_record() {
notify_slaves() { notify_slaves() {
root=$1 root=$1
if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root./notify"; then if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root/notify"; then
_err "Notify slaves error." _err "Notify slaves error."
return 1 return 1
fi fi
@ -144,15 +180,18 @@ _get_root() {
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100) h=$(printf "%s" "$domain" | cut -d . -f $i-100)
if [ -z "$h" ]; then
return 1
fi
if _contains "$_zones_response" "\"name\": \"$h.\""; then if _contains "$_zones_response" "\"name\": \"$h.\""; then
_domain="$h" _domain="$h."
if [ -z "$h" ]; then
_domain="=2E"
fi
return 0 return 0
fi fi
if [ -z "$h" ]; then
return 1
fi
i=$(_math $i + 1) i=$(_math $i + 1)
done done
_debug "$domain not found" _debug "$domain not found"
@ -182,3 +221,12 @@ _pdns_rest() {
return 0 return 0
} }
_build_record_string() {
_record_string="${_record_string:+${_record_string}, }{\"content\": \"\\\"${1}\\\"\", \"disabled\": false}"
}
_list_existingchallenges() {
_pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones/$root"
_existing_challenges=$(echo "$response" | _normalizeJson | _egrep_o "\"name\":\"${fulldomain}[^]]*}" | _egrep_o 'content\":\"\\"[^\\]*' | sed -n 's/^content":"\\"//p')
}

69
dnsapi/dns_tele3.sh Normal file
View File

@ -0,0 +1,69 @@
#!/usr/bin/env sh
#
# tele3.cz DNS API
#
# Author: Roman Blizik
# Report Bugs here: https://github.com/par-pa/acme.sh
#
# --
# export TELE3_Key="MS2I4uPPaI..."
# export TELE3_Secret="kjhOIHGJKHg"
# --
TELE3_API="https://www.tele3.cz/acme/"
######## Public functions #####################
dns_tele3_add() {
_info "Using TELE3 DNS"
data="\"ope\":\"add\", \"domain\":\"$1\", \"value\":\"$2\""
if ! _tele3_call; then
_err "Publish zone failed"
return 1
fi
_info "Zone published"
}
dns_tele3_rm() {
_info "Using TELE3 DNS"
data="\"ope\":\"rm\", \"domain\":\"$1\", \"value\":\"$2\""
if ! _tele3_call; then
_err "delete TXT record failed"
return 1
fi
_info "TXT record successfully deleted"
}
#################### Private functions below ##################################
_tele3_init() {
TELE3_Key="${TELE3_Key:-$(_readaccountconf_mutable TELE3_Key)}"
TELE3_Secret="${TELE3_Secret:-$(_readaccountconf_mutable TELE3_Secret)}"
if [ -z "$TELE3_Key" ] || [ -z "$TELE3_Secret" ]; then
TELE3_Key=""
TELE3_Secret=""
_err "You must export variables: TELE3_Key and TELE3_Secret"
return 1
fi
#save the config variables to the account conf file.
_saveaccountconf_mutable TELE3_Key "$TELE3_Key"
_saveaccountconf_mutable TELE3_Secret "$TELE3_Secret"
}
_tele3_call() {
_tele3_init
data="{\"key\":\"$TELE3_Key\", \"secret\":\"$TELE3_Secret\", $data}"
_debug data "$data"
response="$(_post "$data" "$TELE3_API" "" "POST")"
_debug response "$response"
if [ "$response" != "success" ]; then
_err "$response"
return 1
fi
}

View File

@ -50,9 +50,9 @@ _PDD_get_domain() {
__last=0 __last=0
while [ $__last -eq 0 ]; do while [ $__last -eq 0 ]; do
uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20"
res1=$(_get "$uri1" | _normalizeJson) res1="$(_get "$uri1" | _normalizeJson)"
#_debug "$res1" _debug2 "res1" "$res1"
__found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p') __found="$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p')"
_debug "found: $__found results on page" _debug "found: $__found results on page"
if [ "$__found" -lt 20 ]; then if [ "$__found" -lt 20 ]; then
_debug "last page: $__page" _debug "last page: $__page"

139
dnsapi/dns_zilore.sh Normal file
View File

@ -0,0 +1,139 @@
#!/usr/bin/env sh
Zilore_API="https://api.zilore.com/dns/v1"
# Zilore_Key="YOUR-ZILORE-API-KEY"
######## Public functions #####################
dns_zilore_add() {
fulldomain=$1
txtvalue=$2
_info "Using Zilore"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
Zilore_Key="${Zilore_Key:-$(_readaccountconf_mutable Zilore_Key)}"
if [ -z "$Zilore_Key" ]; then
Zilore_Key=""
_err "Please define Zilore API key"
return 1
fi
_saveaccountconf_mutable Zilore_Key "$Zilore_Key"
if ! _get_root "$fulldomain"; then
_err "Unable to determine root domain"
return 1
else
_debug _domain "$_domain"
fi
if _zilore_rest POST "domains/$_domain/records?record_type=TXT&record_ttl=600&record_name=$fulldomain&record_value=\"$txtvalue\""; then
if _contains "$response" '"added"' >/dev/null; then
_info "Added TXT record, waiting for validation"
return 0
else
_debug response "$response"
_err "Error while adding DNS records"
return 1
fi
fi
return 1
}
dns_zilore_rm() {
fulldomain=$1
txtvalue=$2
_info "Using Zilore"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
Zilore_Key="${Zilore_Key:-$(_readaccountconf_mutable Zilore_Key)}"
if [ -z "$Zilore_Key" ]; then
Zilore_Key=""
_err "Please define Zilore API key"
return 1
fi
_saveaccountconf_mutable Zilore_Key "$Zilore_Key"
if ! _get_root "$fulldomain"; then
_err "Unable to determine root domain"
return 1
else
_debug _domain "$_domain"
fi
_debug "Getting TXT records"
_zilore_rest GET "domains/${_domain}/records?search_text=$txtvalue&search_record_type=TXT"
_debug response "$response"
if ! _contains "$response" '"ok"' >/dev/null; then
_err "Error while getting records list"
return 1
else
_record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[^\"]+\"" | cut -d : -f 2 | tr -d \" | _head_n 1)
if [ -z "$_record_id" ]; then
_err "Cannot determine _record_id"
return 1
else
_debug _record_id "$_record_id"
fi
if ! _zilore_rest DELETE "domains/${_domain}/records?record_id=$_record_id"; then
_err "Error while deleting chosen record"
return 1
fi
_contains "$response" '"ok"'
fi
}
#################### Private functions below ##################################
_get_root() {
domain=$1
i=2
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
if ! _zilore_rest GET "domains?search_text=$h"; then
return 1
fi
if _contains "$response" "\"$h\"" >/dev/null; then
_domain=$h
return 0
else
_debug "$h not found"
fi
i=$(_math "$i" + 1)
done
return 1
}
_zilore_rest() {
method=$1
param=$2
data=$3
export _H1="X-Auth-Key: $Zilore_Key"
if [ "$method" != "GET" ]; then
response="$(_post "$data" "$Zilore_API/$param" "" "$method")"
else
response="$(_get "$Zilore_API/$param")"
fi
if [ "$?" != "0" ]; then
_err "error $param"
return 1
fi
_debug2 response "$response"
return 0
}