mirror of
https://github.com/acmesh-official/acme.sh.git
synced 2025-12-25 21:02:10 +08:00
Compare commits
246 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f62a4a0c0c | ||
|
|
8dacd51abb | ||
|
|
06302871bc | ||
|
|
c1ec2afeca | ||
|
|
572adbaad2 | ||
|
|
f4c7822bc9 | ||
|
|
89561b8d45 | ||
|
|
b0775f7a58 | ||
|
|
2dc50e6633 | ||
|
|
ad2a3d603e | ||
|
|
545f23551f | ||
|
|
b15c1ffedc | ||
|
|
56d70e4ea7 | ||
|
|
0b934232fd | ||
|
|
a4a53e1355 | ||
|
|
c445e70cff | ||
|
|
e8eec2cb41 | ||
|
|
dd6fa4af00 | ||
|
|
afdb9a63ff | ||
|
|
10ba2cd312 | ||
|
|
4c1fa9c242 | ||
|
|
3c6b707353 | ||
|
|
96efc8c7f0 | ||
|
|
0cd6afde6f | ||
|
|
82b11da4ca | ||
|
|
4ec39ab707 | ||
|
|
d2a60f3ca4 | ||
|
|
3bc6628227 | ||
|
|
27579e0701 | ||
|
|
f91bcfeb4b | ||
|
|
e19809d5b5 | ||
|
|
dd068467de | ||
|
|
3099c799b2 | ||
|
|
cd3ef8fa5a | ||
|
|
72ce37704b | ||
|
|
4420d073bb | ||
|
|
9cc9f519fc | ||
|
|
0483d841e3 | ||
|
|
5546120312 | ||
|
|
ad613e2437 | ||
|
|
c544759d36 | ||
|
|
20503d3c58 | ||
|
|
3fb17c5de8 | ||
|
|
a5e4bf16d3 | ||
|
|
68d9aad3a2 | ||
|
|
0aba1b4ad3 | ||
|
|
e12c7c8d27 | ||
|
|
83a040722e | ||
|
|
b7b504d43a | ||
|
|
b18804f57f | ||
|
|
550a5fb4c0 | ||
|
|
40f0238bb7 | ||
|
|
089823785e | ||
|
|
ecf7dded07 | ||
|
|
909aba27d1 | ||
|
|
cd4f29135b | ||
|
|
68c5c366f4 | ||
|
|
29a5311ae0 | ||
|
|
62d774a548 | ||
|
|
c9baca7910 | ||
|
|
86366ae157 | ||
|
|
c4094c68ee | ||
|
|
ec67a1b2c1 | ||
|
|
7ba9a5972d | ||
|
|
b32071ad04 | ||
|
|
b38c4e1a28 | ||
|
|
a13b2b4018 | ||
|
|
65a2f789dc | ||
|
|
8bd12ed040 | ||
|
|
6914662dd8 | ||
|
|
bcb11d9b7e | ||
|
|
920cab6f12 | ||
|
|
9756adb933 | ||
|
|
2671af13cd | ||
|
|
37792e9b38 | ||
|
|
ebb1a8af1b | ||
|
|
f4ba7fcaf4 | ||
|
|
13964ac726 | ||
|
|
c8c1140f15 | ||
|
|
9a473640fb | ||
|
|
405173a0b4 | ||
|
|
8e43b86f06 | ||
|
|
eea9aaf940 | ||
|
|
67d3e8d049 | ||
|
|
f99ca918db | ||
|
|
79a0a66f1f | ||
|
|
08681f4a8b | ||
|
|
a58ef94a9c | ||
|
|
2b9ebd6662 | ||
|
|
6fdd2f40ed | ||
|
|
238990a285 | ||
|
|
1a77490969 | ||
|
|
5431d05168 | ||
|
|
eb97cdc33a | ||
|
|
b54d6589c3 | ||
|
|
463768fcf7 | ||
|
|
a43545c6ea | ||
|
|
9f067d7f56 | ||
|
|
8907e2d850 | ||
|
|
c84466b131 | ||
|
|
f62b956e74 | ||
|
|
9841063df9 | ||
|
|
803c8177d3 | ||
|
|
7ff525468f | ||
|
|
7c1c36f043 | ||
|
|
565e3f75c7 | ||
|
|
842f030355 | ||
|
|
f4ad42bb84 | ||
|
|
fb08b53f0b | ||
|
|
598becf619 | ||
|
|
9a27b38976 | ||
|
|
7917aa2a7c | ||
|
|
d0c97a589b | ||
|
|
8ec1ea7b7a | ||
|
|
71cb6d2bce | ||
|
|
ee258f1425 | ||
|
|
50278674f0 | ||
|
|
be5085f205 | ||
|
|
ca9476f72a | ||
|
|
d55c64c838 | ||
|
|
563de2cc90 | ||
|
|
6afe3ccc3b | ||
|
|
14ad5955b5 | ||
|
|
a6f2110141 | ||
|
|
393d8b9ded | ||
|
|
137dc1eac0 | ||
|
|
5fee82ce39 | ||
|
|
552710ac2a | ||
|
|
0a9a11636a | ||
|
|
e550631275 | ||
|
|
87d2f7f27a | ||
|
|
a40cd2b46f | ||
|
|
4b581f3720 | ||
|
|
12956679e7 | ||
|
|
7903fcb48c | ||
|
|
9672c6b885 | ||
|
|
55369d30a6 | ||
|
|
a894b7cc9b | ||
|
|
46b3a9158c | ||
|
|
26421684dc | ||
|
|
fd536d373e | ||
|
|
4f59a821d3 | ||
|
|
b29e21efa8 | ||
|
|
9f6f721a13 | ||
|
|
4c1f70af4b | ||
|
|
6a81b0f807 | ||
|
|
3322630732 | ||
|
|
d8885984ab | ||
|
|
4a18c45e4f | ||
|
|
5b7cac1002 | ||
|
|
5aef9266cb | ||
|
|
80b40c02b4 | ||
|
|
56d6079c4a | ||
|
|
3975792bf1 | ||
|
|
697e694de6 | ||
|
|
828d8eaadb | ||
|
|
30ee00ff50 | ||
|
|
7e130c2618 | ||
|
|
b859dd660c | ||
|
|
8868783476 | ||
|
|
dc0dd6588c | ||
|
|
f7e7e885a9 | ||
|
|
d813be1f48 | ||
|
|
0d03309c2f | ||
|
|
1dab353fdb | ||
|
|
8eb4efaddb | ||
|
|
12c900ea7d | ||
|
|
c31db83b26 | ||
|
|
98ce8f4c2f | ||
|
|
1f25b4a8a9 | ||
|
|
1756bbff84 | ||
|
|
21b2ffa42e | ||
|
|
b6efdac1db | ||
|
|
fc9d321ebe | ||
|
|
68a290c347 | ||
|
|
9133de50e9 | ||
|
|
73d04b976e | ||
|
|
a35d271669 | ||
|
|
72a7f932c6 | ||
|
|
2e74df2583 | ||
|
|
4fffb3c816 | ||
|
|
840b3a34cb | ||
|
|
dc267663a7 | ||
|
|
8d6443b25d | ||
|
|
e3c7fc8077 | ||
|
|
bbf2a15f27 | ||
|
|
5a326b82bd | ||
|
|
f1b0dd7836 | ||
|
|
c205777542 | ||
|
|
329a1e6f16 | ||
|
|
9c39121e99 | ||
|
|
e5e57e684e | ||
|
|
659a60aeec | ||
|
|
b0268adad9 | ||
|
|
71e4bbfc99 | ||
|
|
c6bd004d63 | ||
|
|
8b6986ba18 | ||
|
|
b23718f3ad | ||
|
|
8113548920 | ||
|
|
b401dbbf65 | ||
|
|
75dd0a770f | ||
|
|
6d8292cdd8 | ||
|
|
0575eb671a | ||
|
|
d06eea53ef | ||
|
|
9e96a93172 | ||
|
|
441f8f3ce8 | ||
|
|
1d4dec5510 | ||
|
|
167758003c | ||
|
|
0a3ac1f5c3 | ||
|
|
9173140ddf | ||
|
|
7aeb113c62 | ||
|
|
22cd408efb | ||
|
|
4fbd21da57 | ||
|
|
ed95509a4f | ||
|
|
4162975f9f | ||
|
|
ac0cdcf70b | ||
|
|
63134fafec | ||
|
|
5494e88e08 | ||
|
|
86276ad17b | ||
|
|
c883ec40d7 | ||
|
|
d19bc328f3 | ||
|
|
f286f904dc | ||
|
|
150029a5e2 | ||
|
|
709a3fb06f | ||
|
|
d3c9d0b331 | ||
|
|
cc2d59468d | ||
|
|
91391fba5d | ||
|
|
4369402855 | ||
|
|
0bc556618f | ||
|
|
cb11580981 | ||
|
|
0366e8758c | ||
|
|
8d230dd798 | ||
|
|
411b342a27 | ||
|
|
b9b7032386 | ||
|
|
69b780ee32 | ||
|
|
c7b904501c | ||
|
|
48e8022095 | ||
|
|
4715a1a5e0 | ||
|
|
ed2ba6bc3a | ||
|
|
ca1d62bec0 | ||
|
|
6a4aad1aa8 | ||
|
|
3f0462b68b | ||
|
|
f3a622d1a7 | ||
|
|
3cd5b9ca2e | ||
|
|
e9782c3219 | ||
|
|
e36fbd6af5 |
@@ -4,6 +4,7 @@ RUN apk update -f \
|
||||
&& apk --no-cache add -f \
|
||||
openssl \
|
||||
coreutils \
|
||||
bind-tools \
|
||||
curl \
|
||||
socat \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
61
README.md
61
README.md
@@ -35,7 +35,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
||||
- [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709)
|
||||
- [Centminmod](https://centminmod.com/letsencrypt-acmetool-https.html)
|
||||
- [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://www.archlinux.org/packages/community/any/acme.sh)
|
||||
- [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/)
|
||||
@@ -70,11 +70,16 @@ For all build statuses, check our [weekly build project](https://github.com/Neil
|
||||
|
||||
https://github.com/Neilpang/acmetest
|
||||
|
||||
# Supported CA
|
||||
|
||||
- Letsencrypt.org CA(default)
|
||||
- [BuyPass.com CA](https://github.com/Neilpang/acme.sh/wiki/BuyPass.com-CA)
|
||||
|
||||
# Supported modes
|
||||
|
||||
- Webroot mode
|
||||
- Standalone mode
|
||||
- Standalone tls-alpn mode
|
||||
- Apache mode
|
||||
- Nginx mode
|
||||
- DNS mode
|
||||
@@ -221,8 +226,20 @@ 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
|
||||
|
||||
# 5. Use Standalone ssl server to issue cert
|
||||
|
||||
# 5. Use Apache mode
|
||||
**(requires you to be root/sudoer or have permission to listen on port 443 (TCP))**
|
||||
|
||||
Port `443` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again.
|
||||
|
||||
```bash
|
||||
acme.sh --issue --alpn -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)**
|
||||
|
||||
@@ -242,7 +259,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
|
||||
|
||||
# 6. Use Nginx mode
|
||||
# 7. Use Nginx mode
|
||||
|
||||
**(requires you to be root/sudoer, since it is required to interact with Nginx server)**
|
||||
|
||||
@@ -266,7 +283,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
|
||||
|
||||
# 7. Automatic DNS API integration
|
||||
# 8. Automatic DNS API integration
|
||||
|
||||
If your DNS provider supports API access, we can use that API to automatically issue the certs.
|
||||
|
||||
@@ -321,8 +338,20 @@ You don't have to do anything manually!
|
||||
1. acme-dns (https://github.com/joohoi/acme-dns)
|
||||
1. TELE3 (https://www.tele3.cz)
|
||||
1. EUSERV.EU (https://www.euserv.eu)
|
||||
1. DNSPod.com API (https://www.dnspod.com)
|
||||
1. Google Cloud DNS API
|
||||
1. ConoHa (https://www.conoha.jp)
|
||||
1. netcup DNS API (https://www.netcup.de)
|
||||
1. GratisDNS.dk (https://gratisdns.dk)
|
||||
1. Namecheap API (https://www.namecheap.com/)
|
||||
1. MyDNS.JP API (https://www.mydns.jp/)
|
||||
1. hosting.de (https://www.hosting.de)
|
||||
1. Neodigit.net API (https://www.neodigit.net)
|
||||
1. Exoscale.com API (https://www.exoscale.com/)
|
||||
1. PointDNS API (https://pointhq.com/)
|
||||
1. Active24.cz API (https://www.active24.cz/)
|
||||
|
||||
And:
|
||||
And:
|
||||
|
||||
**lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
|
||||
(DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)**
|
||||
@@ -334,7 +363,7 @@ 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)
|
||||
|
||||
# 8. Use DNS manual mode:
|
||||
# 9. Use DNS manual mode:
|
||||
|
||||
See: https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode first.
|
||||
|
||||
@@ -370,7 +399,7 @@ Ok, it's done.
|
||||
|
||||
**Please use dns api mode instead.**
|
||||
|
||||
# 9. Issue ECC certificates
|
||||
# 10. Issue ECC certificates
|
||||
|
||||
`Let's Encrypt` can now issue **ECDSA** certificates.
|
||||
|
||||
@@ -402,7 +431,7 @@ Valid values are:
|
||||
|
||||
|
||||
|
||||
# 10. Issue Wildcard certificates
|
||||
# 11. Issue Wildcard certificates
|
||||
|
||||
It's simple, just give a wildcard domain as the `-d` parameter.
|
||||
|
||||
@@ -412,7 +441,7 @@ acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf
|
||||
|
||||
|
||||
|
||||
# 11. How to renew the certs
|
||||
# 12. 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.
|
||||
|
||||
@@ -429,7 +458,7 @@ acme.sh --renew -d example.com --force --ecc
|
||||
```
|
||||
|
||||
|
||||
# 12. How to stop cert renewal
|
||||
# 13. How to stop cert renewal
|
||||
|
||||
To stop renewal of a cert, you can execute the following to remove the cert from the renewal list:
|
||||
|
||||
@@ -442,7 +471,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.
|
||||
|
||||
|
||||
# 13. How to upgrade `acme.sh`
|
||||
# 14. How to upgrade `acme.sh`
|
||||
|
||||
acme.sh is in constant development, so it's strongly recommended to use the latest code.
|
||||
|
||||
@@ -467,25 +496,25 @@ acme.sh --upgrade --auto-upgrade 0
|
||||
```
|
||||
|
||||
|
||||
# 14. Issue a cert from an existing CSR
|
||||
# 15. Issue a cert from an existing CSR
|
||||
|
||||
https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR
|
||||
|
||||
|
||||
# 15. Under the Hood
|
||||
# 16. Under the Hood
|
||||
|
||||
Speak ACME language using shell, directly to "Let's Encrypt".
|
||||
|
||||
TODO:
|
||||
|
||||
|
||||
# 16. Acknowledgments
|
||||
# 17. Acknowledgments
|
||||
|
||||
1. Acme-tiny: https://github.com/diafygi/acme-tiny
|
||||
2. ACME protocol: https://github.com/ietf-wg-acme/acme
|
||||
|
||||
|
||||
# 17. License & Others
|
||||
# 18. License & Others
|
||||
|
||||
License is GPLv3
|
||||
|
||||
@@ -494,7 +523,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.
|
||||
|
||||
|
||||
# 18. Donate
|
||||
# 19. Donate
|
||||
Your donation makes **acme.sh** better:
|
||||
|
||||
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)
|
||||
|
||||
193
acme.sh
193
acme.sh
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
VER=2.7.9
|
||||
VER=2.8.0
|
||||
|
||||
PROJECT_NAME="acme.sh"
|
||||
|
||||
@@ -36,11 +36,11 @@ _OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org"
|
||||
VTYPE_HTTP="http-01"
|
||||
VTYPE_DNS="dns-01"
|
||||
VTYPE_TLS="tls-sni-01"
|
||||
VTYPE_TLS2="tls-sni-02"
|
||||
VTYPE_ALPN="tls-alpn-01"
|
||||
|
||||
LOCAL_ANY_ADDRESS="0.0.0.0"
|
||||
|
||||
MAX_RENEW=60
|
||||
DEFAULT_RENEW=60
|
||||
|
||||
DEFAULT_DNS_SLEEP=120
|
||||
|
||||
@@ -48,6 +48,7 @@ NO_VALUE="no"
|
||||
|
||||
W_TLS="tls"
|
||||
W_DNS="dns"
|
||||
W_ALPN="alpn"
|
||||
DNS_ALIAS_PREFIX="="
|
||||
|
||||
MODE_STATELESS="stateless"
|
||||
@@ -124,23 +125,19 @@ if [ -t 1 ]; then
|
||||
fi
|
||||
|
||||
__green() {
|
||||
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then
|
||||
printf '\033[1;31;32m'
|
||||
if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then
|
||||
printf '\033[1;31;32m%b\033[0m' "$1"
|
||||
return
|
||||
fi
|
||||
printf -- "%b" "$1"
|
||||
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then
|
||||
printf '\033[0m'
|
||||
fi
|
||||
}
|
||||
|
||||
__red() {
|
||||
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then
|
||||
printf '\033[1;31;40m'
|
||||
if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then
|
||||
printf '\033[1;31;40m%b\033[0m' "$1"
|
||||
return
|
||||
fi
|
||||
printf -- "%b" "$1"
|
||||
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then
|
||||
printf '\033[0m'
|
||||
fi
|
||||
}
|
||||
|
||||
_printargs() {
|
||||
@@ -1050,7 +1047,7 @@ _idn() {
|
||||
fi
|
||||
}
|
||||
|
||||
#_createcsr cn san_list keyfile csrfile conf
|
||||
#_createcsr cn san_list keyfile csrfile conf acmeValidationv1
|
||||
_createcsr() {
|
||||
_debug _createcsr
|
||||
domain="$1"
|
||||
@@ -1058,6 +1055,7 @@ _createcsr() {
|
||||
csrkey="$3"
|
||||
csr="$4"
|
||||
csrconf="$5"
|
||||
acmeValidationv1="$6"
|
||||
_debug2 domain "$domain"
|
||||
_debug2 domainlist "$domainlist"
|
||||
_debug2 csrkey "$csrkey"
|
||||
@@ -1066,7 +1064,9 @@ _createcsr() {
|
||||
|
||||
printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf"
|
||||
|
||||
if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
|
||||
if [ "$acmeValidationv1" ]; then
|
||||
printf -- "\nsubjectAltName=DNS:$domainlist" >>"$csrconf"
|
||||
elif [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
|
||||
#single domain
|
||||
_info "Single domain" "$domain"
|
||||
printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf"
|
||||
@@ -1088,6 +1088,10 @@ _createcsr() {
|
||||
printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf"
|
||||
fi
|
||||
|
||||
if [ "$acmeValidationv1" ]; then
|
||||
printf "\n1.3.6.1.5.5.7.1.31=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}"
|
||||
fi
|
||||
|
||||
_csr_cn="$(_idn "$domain")"
|
||||
_debug2 _csr_cn "$_csr_cn"
|
||||
if _contains "$(uname -a)" "MINGW"; then
|
||||
@@ -1138,12 +1142,17 @@ _readSubjectAltNamesFromCSR() {
|
||||
|
||||
if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then
|
||||
_debug "AltNames contains subject"
|
||||
_dnsAltnames="$(printf "%s" "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")"
|
||||
_excapedAlgnames="$(echo "$_dnsAltnames" | tr '*' '#')"
|
||||
_debug _excapedAlgnames "$_excapedAlgnames"
|
||||
_escapedSubject="$(echo "$_csrsubj" | tr '*' '#')"
|
||||
_debug _escapedSubject "$_escapedSubject"
|
||||
_dnsAltnames="$(echo "$_excapedAlgnames," | sed "s/DNS:$_escapedSubject,//g" | tr '#' '*' | sed "s/,\$//g")"
|
||||
_debug _dnsAltnames "$_dnsAltnames"
|
||||
else
|
||||
_debug "AltNames doesn't contain subject"
|
||||
fi
|
||||
|
||||
printf "%s" "$_dnsAltnames" | sed "s/DNS://g"
|
||||
echo "$_dnsAltnames" | sed "s/DNS://g"
|
||||
}
|
||||
|
||||
#_csrfile
|
||||
@@ -1327,6 +1336,7 @@ createDomainKey() {
|
||||
if _createkey "$_cdl" "$CERT_KEY_PATH"; then
|
||||
_savedomainconf Le_Keylength "$_cdl"
|
||||
_info "The domain key is here: $(__green $CERT_KEY_PATH)"
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
if [ "$IS_RENEW" ]; then
|
||||
@@ -1374,17 +1384,17 @@ _url_replace() {
|
||||
}
|
||||
|
||||
_time2str() {
|
||||
#Linux
|
||||
if date -u -d@"$1" 2>/dev/null; then
|
||||
return
|
||||
fi
|
||||
|
||||
#BSD
|
||||
if date -u -r "$1" 2>/dev/null; then
|
||||
return
|
||||
fi
|
||||
|
||||
#Soaris
|
||||
#Linux
|
||||
if date -u -d@"$1" 2>/dev/null; then
|
||||
return
|
||||
fi
|
||||
|
||||
#Solaris
|
||||
if _exists adb; then
|
||||
_t_s_a=$(echo "0t${1}=Y" | adb)
|
||||
echo "$_t_s_a"
|
||||
@@ -1519,7 +1529,8 @@ _calcjwk() {
|
||||
JWK_HEADERPLACE_PART1='{"nonce": "'
|
||||
JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"'
|
||||
else
|
||||
_err "Only RSA or EC key is supported."
|
||||
_err "Only RSA or EC key is supported. keyfile=$keyfile"
|
||||
_debug2 "$(cat "$keyfile")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -1795,15 +1806,13 @@ _send_signed_request() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$ACME_VERSION" = "2" ]; then
|
||||
__request_conent_type="$CONTENT_TYPE_JSON"
|
||||
else
|
||||
__request_conent_type=""
|
||||
fi
|
||||
__request_conent_type="$CONTENT_TYPE_JSON"
|
||||
|
||||
payload64=$(printf "%s" "$payload" | _base64 | _url_replace)
|
||||
_debug3 payload64 "$payload64"
|
||||
|
||||
MAX_REQUEST_RETRY_TIMES=5
|
||||
MAX_REQUEST_RETRY_TIMES=20
|
||||
_sleep_retry_sec=1
|
||||
_request_retry_times=0
|
||||
while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do
|
||||
_request_retry_times=$(_math "$_request_retry_times" + 1)
|
||||
@@ -1811,14 +1820,14 @@ _send_signed_request() {
|
||||
if [ -z "$_CACHED_NONCE" ]; then
|
||||
_headers=""
|
||||
if [ "$ACME_NEW_NONCE" ]; then
|
||||
_debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE"
|
||||
_debug2 "Get nonce with HEAD. ACME_NEW_NONCE" "$ACME_NEW_NONCE"
|
||||
nonceurl="$ACME_NEW_NONCE"
|
||||
if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then
|
||||
_headers="$(cat "$HTTP_HEADER")"
|
||||
fi
|
||||
fi
|
||||
if [ -z "$_headers" ]; then
|
||||
_debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY"
|
||||
_debug2 "Get nonce with GET. ACME_DIRECTORY" "$ACME_DIRECTORY"
|
||||
nonceurl="$ACME_DIRECTORY"
|
||||
_headers="$(_get "$nonceurl" "onlyheader")"
|
||||
fi
|
||||
@@ -1865,11 +1874,7 @@ _send_signed_request() {
|
||||
sig="$(printf "%s" "$_sig_t" | _url_replace)"
|
||||
_debug3 sig "$sig"
|
||||
|
||||
if [ "$ACME_VERSION" = "2" ]; then
|
||||
body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
|
||||
else
|
||||
body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
|
||||
fi
|
||||
body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
|
||||
_debug3 body "$body"
|
||||
|
||||
response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")"
|
||||
@@ -1898,8 +1903,9 @@ _send_signed_request() {
|
||||
fi
|
||||
|
||||
if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then
|
||||
_info "It seems the CA server is busy now, let's wait and retry."
|
||||
_sleep 5
|
||||
_info "It seems the CA server is busy now, let's wait and retry. Sleeping $_sleep_retry_sec seconds."
|
||||
_CACHED_NONCE=""
|
||||
_sleep $_sleep_retry_sec
|
||||
continue
|
||||
fi
|
||||
break
|
||||
@@ -2105,7 +2111,7 @@ _sleep() {
|
||||
fi
|
||||
}
|
||||
|
||||
# _starttlsserver san_a san_b port content _ncaddr
|
||||
# _starttlsserver san_a san_b port content _ncaddr acmeValidationv1
|
||||
_starttlsserver() {
|
||||
_info "Starting tls server."
|
||||
san_a="$1"
|
||||
@@ -2113,10 +2119,12 @@ _starttlsserver() {
|
||||
port="$3"
|
||||
content="$4"
|
||||
opaddr="$5"
|
||||
acmeValidationv1="$6"
|
||||
|
||||
_debug san_a "$san_a"
|
||||
_debug san_b "$san_b"
|
||||
_debug port "$port"
|
||||
_debug acmeValidationv1 "$acmeValidationv1"
|
||||
|
||||
#create key TLS_KEY
|
||||
if ! _createkey "2048" "$TLS_KEY"; then
|
||||
@@ -2129,7 +2137,7 @@ _starttlsserver() {
|
||||
if [ "$san_b" ]; then
|
||||
alt="$alt,$san_b"
|
||||
fi
|
||||
if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF"; then
|
||||
if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$acmeValidationv1"; then
|
||||
_err "Create tls validation csr error."
|
||||
return 1
|
||||
fi
|
||||
@@ -2155,6 +2163,10 @@ _starttlsserver() {
|
||||
__S_OPENSSL="$__S_OPENSSL -6"
|
||||
fi
|
||||
|
||||
if [ "$acmeValidationv1" ]; then
|
||||
__S_OPENSSL="$__S_OPENSSL -alpn acme-tls/1"
|
||||
fi
|
||||
|
||||
_debug "$__S_OPENSSL"
|
||||
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
|
||||
$__S_OPENSSL -tlsextdebug &
|
||||
@@ -2843,7 +2855,7 @@ _isRealNginxConf() {
|
||||
_skip_ssl=1
|
||||
for _listen_i in $(echo "$_seg_n" | tr "\t" ' ' | grep "^ *listen" | tr -d " "); do
|
||||
if [ "$_listen_i" ]; then
|
||||
if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl[ |;]")" ]; then
|
||||
if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl")" ]; then
|
||||
_debug2 "$_listen_i is ssl"
|
||||
else
|
||||
_debug2 "$_listen_i is plain text"
|
||||
@@ -2909,7 +2921,10 @@ _clearup() {
|
||||
|
||||
_clearupdns() {
|
||||
_debug "_clearupdns"
|
||||
if [ "$dnsadded" != 1 ] || [ -z "$vlist" ]; then
|
||||
_debug "dnsadded" "$dnsadded"
|
||||
_debug "vlist" "$vlist"
|
||||
#dnsadded is "0" or "1" means dns-01 method was used for at least one domain
|
||||
if [ -z "$dnsadded" ] || [ -z "$vlist" ]; then
|
||||
_debug "skip dns."
|
||||
return
|
||||
fi
|
||||
@@ -2925,6 +2940,7 @@ _clearupdns() {
|
||||
_debug txt "$txt"
|
||||
if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
|
||||
_debug "$d is already verified, skip $vtype."
|
||||
_alias_index="$(_math "$_alias_index" + 1)"
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -3064,8 +3080,8 @@ _on_before_issue() {
|
||||
_savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
|
||||
fi
|
||||
_checkport="$Le_HTTPPort"
|
||||
elif [ "$_currentRoot" = "$W_TLS" ]; then
|
||||
_info "Standalone tls mode."
|
||||
elif [ "$_currentRoot" = "$W_TLS" ] || [ "$_currentRoot" = "$W_ALPN" ]; then
|
||||
_info "Standalone tls/alpn mode."
|
||||
if [ -z "$Le_TLSPort" ]; then
|
||||
Le_TLSPort=443
|
||||
else
|
||||
@@ -3425,15 +3441,17 @@ __get_domain_new_authz() {
|
||||
|
||||
#uri keyAuthorization
|
||||
__trigger_validation() {
|
||||
_debug2 "tigger domain validation."
|
||||
_debug2 "Trigger domain validation."
|
||||
_t_url="$1"
|
||||
_debug2 _t_url "$_t_url"
|
||||
_t_key_authz="$2"
|
||||
_debug2 _t_key_authz "$_t_key_authz"
|
||||
_t_vtype="$3"
|
||||
_debug2 _t_vtype "$_t_vtype"
|
||||
if [ "$ACME_VERSION" = "2" ]; then
|
||||
_send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}"
|
||||
else
|
||||
_send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}"
|
||||
_send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"type\": \"$_t_vtype\", \"keyAuthorization\": \"$_t_key_authz\"}"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -3636,7 +3654,7 @@ issue() {
|
||||
_authorizations_map=""
|
||||
for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' '); do
|
||||
_debug2 "_authz_url" "$_authz_url"
|
||||
if ! response="$(_get "$_authz_url")"; then
|
||||
if ! _send_signed_request "$_authz_url"; then
|
||||
_err "get to authz error."
|
||||
_err "_authorizations_seg" "$_authorizations_seg"
|
||||
_err "_authz_url" "$_authz_url"
|
||||
@@ -3684,11 +3702,11 @@ $_authorizations_map"
|
||||
fi
|
||||
|
||||
if [ "$_currentRoot" = "$W_TLS" ]; then
|
||||
if [ "$ACME_VERSION" = "2" ]; then
|
||||
vtype="$VTYPE_TLS2"
|
||||
else
|
||||
vtype="$VTYPE_TLS"
|
||||
fi
|
||||
vtype="$VTYPE_TLS"
|
||||
fi
|
||||
|
||||
if [ "$_currentRoot" = "$W_ALPN" ]; then
|
||||
vtype="$VTYPE_ALPN"
|
||||
fi
|
||||
|
||||
if [ "$ACME_VERSION" = "2" ]; then
|
||||
@@ -3775,6 +3793,7 @@ $_authorizations_map"
|
||||
_debug d "$d"
|
||||
if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
|
||||
_debug "$d is already verified, skip $vtype."
|
||||
_alias_index="$(_math "$_alias_index" + 1)"
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -3838,8 +3857,8 @@ $_authorizations_map"
|
||||
)
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_clearup
|
||||
_on_issue_err "$_post_hook" "$vlist"
|
||||
_clearup
|
||||
return 1
|
||||
fi
|
||||
dnsadded='1'
|
||||
@@ -3850,8 +3869,8 @@ $_authorizations_map"
|
||||
_savedomainconf "Le_Vlist" "$vlist"
|
||||
_debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
|
||||
_err "Please add the TXT records to the domains, and re-run with --renew."
|
||||
_clearup
|
||||
_on_issue_err "$_post_hook"
|
||||
_clearup
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -3885,7 +3904,7 @@ $_authorizations_map"
|
||||
continue
|
||||
fi
|
||||
|
||||
_info "Verifying:$d"
|
||||
_info "Verifying: $d"
|
||||
_debug "d" "$d"
|
||||
_debug "keyauthorization" "$keyauthorization"
|
||||
_debug "uri" "$uri"
|
||||
@@ -4003,9 +4022,19 @@ $_authorizations_map"
|
||||
_on_issue_err "$_post_hook" "$vlist"
|
||||
return 1
|
||||
fi
|
||||
elif [ "$vtype" = "$VTYPE_ALPN" ]; then
|
||||
acmevalidationv1="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")"
|
||||
_debug acmevalidationv1 "$acmevalidationv1"
|
||||
if ! _starttlsserver "$d" "" "$Le_TLSPort" "$keyauthorization" "$_ncaddr" "$acmevalidationv1"; then
|
||||
_err "Start tls server error."
|
||||
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
||||
_clearup
|
||||
_on_issue_err "$_post_hook" "$vlist"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! __trigger_validation "$uri" "$keyauthorization"; then
|
||||
if ! __trigger_validation "$uri" "$keyauthorization" "$vtype"; then
|
||||
_err "$d:Can not get challenge: $response"
|
||||
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
||||
_clearup
|
||||
@@ -4014,7 +4043,7 @@ $_authorizations_map"
|
||||
fi
|
||||
|
||||
if [ "$code" ] && [ "$code" != '202' ]; then
|
||||
if [ "$ACME_VERSION" = "2" ] && [ "$code" = '200' ]; then
|
||||
if [ "$code" = '200' ]; then
|
||||
_debug "trigger validation code: $code"
|
||||
else
|
||||
_err "$d:Challenge error: $response"
|
||||
@@ -4043,7 +4072,11 @@ $_authorizations_map"
|
||||
_debug "sleep 2 secs to verify"
|
||||
sleep 2
|
||||
_debug "checking"
|
||||
response="$(_get "$uri")"
|
||||
if [ "$ACME_VERSION" = "2" ]; then
|
||||
_send_signed_request "$uri"
|
||||
else
|
||||
response="$(_get "$uri")"
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "$d:Verify error:$response"
|
||||
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
||||
@@ -4119,13 +4152,16 @@ $_authorizations_map"
|
||||
fi
|
||||
Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)"
|
||||
|
||||
if ! _get "$Le_LinkCert" >"$CERT_PATH"; then
|
||||
_tempSignedResponse="$response"
|
||||
if ! _send_signed_request "$Le_LinkCert" "" "needbase64"; then
|
||||
_err "Sign failed, can not download cert:$Le_LinkCert."
|
||||
_err "$response"
|
||||
_on_issue_err "$_post_hook"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$response" | _dbase64 "multiline" >"$CERT_PATH"
|
||||
|
||||
if [ "$(grep -- "$BEGIN_CERT" "$CERT_PATH" | wc -l)" -gt "1" ]; then
|
||||
_debug "Found cert chain"
|
||||
cat "$CERT_PATH" >"$CERT_FULLCHAIN_PATH"
|
||||
@@ -4135,6 +4171,7 @@ $_authorizations_map"
|
||||
_end_n="$(_math $_end_n + 1)"
|
||||
sed -n "${_end_n},9999p" "$CERT_FULLCHAIN_PATH" >"$CA_CERT_PATH"
|
||||
fi
|
||||
response="$_tempSignedResponse"
|
||||
else
|
||||
if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
|
||||
_err "Sign failed. $response"
|
||||
@@ -4205,7 +4242,8 @@ $_authorizations_map"
|
||||
while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do
|
||||
_debug _link_issuer_retry "$_link_issuer_retry"
|
||||
if [ "$ACME_VERSION" = "2" ]; then
|
||||
if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then
|
||||
if _send_signed_request "$Le_LinkIssuer"; then
|
||||
echo "$response" >"$CA_CERT_PATH"
|
||||
break
|
||||
fi
|
||||
else
|
||||
@@ -4241,8 +4279,8 @@ $_authorizations_map"
|
||||
Le_CertCreateTimeStr=$(date -u)
|
||||
_savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr"
|
||||
|
||||
if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ]; then
|
||||
Le_RenewalDays="$MAX_RENEW"
|
||||
if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ]; then
|
||||
Le_RenewalDays="$DEFAULT_RENEW"
|
||||
else
|
||||
_savedomainconf "Le_RenewalDays" "$Le_RenewalDays"
|
||||
fi
|
||||
@@ -4602,7 +4640,8 @@ deploy() {
|
||||
|
||||
_initpath "$_d" "$_isEcc"
|
||||
if [ ! -d "$DOMAIN_PATH" ]; then
|
||||
_err "Domain is not valid:'$_d'"
|
||||
_err "The domain '$_d' is not a cert name. You must use the cert name to specify the cert to install."
|
||||
_err "Can not find path:'$DOMAIN_PATH'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -4629,7 +4668,8 @@ installcert() {
|
||||
|
||||
_initpath "$_main_domain" "$_isEcc"
|
||||
if [ ! -d "$DOMAIN_PATH" ]; then
|
||||
_err "Domain is not valid:'$_main_domain'"
|
||||
_err "The domain '$_main_domain' is not a cert name. You must use the cert name to specify the cert to install."
|
||||
_err "Can not find path:'$DOMAIN_PATH'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -4929,7 +4969,7 @@ _deactivate() {
|
||||
|
||||
authzUri="$_authorizations_seg"
|
||||
_debug2 "authzUri" "$authzUri"
|
||||
if ! response="$(_get "$authzUri")"; then
|
||||
if ! _send_signed_request "$authzUri"; then
|
||||
_err "get to authz error."
|
||||
_err "_authorizations_seg" "$_authorizations_seg"
|
||||
_err "authzUri" "$authzUri"
|
||||
@@ -5463,6 +5503,7 @@ Parameters:
|
||||
--output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure.
|
||||
--webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
|
||||
--standalone Use standalone mode.
|
||||
--alpn Use standalone alpn mode.
|
||||
--stateless Use stateless mode, see: $_STATELESS_WIKI
|
||||
--apache Use apache mode.
|
||||
--dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
|
||||
@@ -5474,7 +5515,7 @@ Parameters:
|
||||
--log-level 1|2 Specifies the log level, default is 1.
|
||||
--syslog [0|3|6|7] Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug.
|
||||
|
||||
These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert:
|
||||
These parameters are to install the cert to nginx/apache or any other server after issue/renew a cert:
|
||||
|
||||
--cert-file After issue/renew, the cert will be copied to this path.
|
||||
--key-file After issue/renew, the key will be copied to this path.
|
||||
@@ -5485,14 +5526,15 @@ Parameters:
|
||||
|
||||
--server SERVER ACME Directory Resource URI. (default: https://acme-v01.api.letsencrypt.org/directory)
|
||||
--accountconf Specifies a customized account config file.
|
||||
--home Specifies the home dir for $PROJECT_NAME .
|
||||
--home Specifies the home dir for $PROJECT_NAME.
|
||||
--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.
|
||||
--useragent Specifies the user agent string. it will be saved for future use too.
|
||||
--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.
|
||||
--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 default value is $DEFAULT_RENEW days.
|
||||
--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.
|
||||
--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.
|
||||
@@ -5817,6 +5859,14 @@ _process() {
|
||||
_webroot="$_webroot,$wvalue"
|
||||
fi
|
||||
;;
|
||||
--alpn)
|
||||
wvalue="$W_ALPN"
|
||||
if [ -z "$_webroot" ]; then
|
||||
_webroot="$wvalue"
|
||||
else
|
||||
_webroot="$_webroot,$wvalue"
|
||||
fi
|
||||
;;
|
||||
--stateless)
|
||||
wvalue="$MODE_STATELESS"
|
||||
if [ -z "$_webroot" ]; then
|
||||
@@ -5941,6 +5991,11 @@ _process() {
|
||||
Le_HTTPPort="$_httpport"
|
||||
shift
|
||||
;;
|
||||
--tlsport)
|
||||
_tlsport="$2"
|
||||
Le_TLSPort="$_tlsport"
|
||||
shift
|
||||
;;
|
||||
--listraw)
|
||||
_listraw="raw"
|
||||
;;
|
||||
|
||||
106
deploy/README.md
106
deploy/README.md
@@ -275,3 +275,109 @@ acme.sh --deploy -d haproxy.example.com --deploy-hook haproxy
|
||||
```
|
||||
|
||||
The path for the PEM file will be stored with the domain configuration and will be available when renewing, so that deploy will happen automatically when renewed.
|
||||
|
||||
## 11. Deploy your cert to Gitlab pages
|
||||
|
||||
You must define the API key and the informations for the project and Gitlab page you are updating the certificate for.
|
||||
|
||||
```sh
|
||||
# The token can be created in your user settings under "Access Tokens"
|
||||
export GITLAB_TOKEN="xxxxxxxxxxx"
|
||||
|
||||
# The project ID is displayed on the home page of the project
|
||||
export GITLAB_PROJECT_ID=12345678
|
||||
|
||||
# The domain must match the one defined for the Gitlab page, without "https://"
|
||||
export GITLAB_DOMAIN="www.mydomain.com"
|
||||
```
|
||||
|
||||
You can then deploy the certificate as follows
|
||||
|
||||
```sh
|
||||
acme.sh --deploy -d www.mydomain.com --deploy-hook gitlab
|
||||
```
|
||||
|
||||
## 12. Deploy your cert to Hashicorp Vault
|
||||
|
||||
```sh
|
||||
export VAULT_PREFIX="acme"
|
||||
```
|
||||
|
||||
You can then deploy the certificate as follows
|
||||
|
||||
```sh
|
||||
acme.sh --deploy -d www.mydomain.com --deploy-hook vault_cli
|
||||
```
|
||||
|
||||
Your certs will be saved in Vault using this structure:
|
||||
|
||||
```sh
|
||||
vault write "${VAULT_PREFIX}/${domain}/cert.pem" value=@"..."
|
||||
vault write "${VAULT_PREFIX}/${domain}/cert.key" value=@"..."
|
||||
vault write "${VAULT_PREFIX}/${domain}/chain.pem" value=@"..."
|
||||
vault write "${VAULT_PREFIX}/${domain}/fullchain.pem" value=@"..."
|
||||
```
|
||||
|
||||
You might be using Fabio load balancer (which can get certs from
|
||||
Vault). It needs a bit different structure of your certs in Vault. It
|
||||
gets certs only from keys that were saved in `prefix/domain`, like this:
|
||||
|
||||
```bash
|
||||
vault write <PREFIX>/www.domain.com cert=@cert.pem key=@key.pem
|
||||
```
|
||||
|
||||
If you want to save certs in Vault this way just set "FABIO" env
|
||||
variable to anything (ex: "1") before running `acme.sh`:
|
||||
|
||||
```sh
|
||||
export FABIO="1"
|
||||
```
|
||||
|
||||
## 13. Deploy your certificate to Qiniu.com
|
||||
|
||||
使用 acme.sh 部署到七牛之前,需要确保部署的域名已打开 HTTPS 功能,您可以访问[融合 CDN - 域名管理](https://portal.qiniu.com/cdn/domain) 设置。
|
||||
另外还需要先导出 AK/SK 环境变量,您可以访问[密钥管理](https://portal.qiniu.com/user/key) 获得。
|
||||
|
||||
```sh
|
||||
$ export QINIU_AK="foo"
|
||||
$ export QINIU_SK="bar"
|
||||
```
|
||||
|
||||
完成准备工作之后,您就可以通过下面的命令开始部署 SSL 证书到七牛上:
|
||||
|
||||
```sh
|
||||
$ acme.sh --deploy -d example.com --deploy-hook qiniu
|
||||
```
|
||||
|
||||
假如您部署的证书为泛域名证书,您还需要设置 `QINIU_CDN_DOMAIN` 变量,指定实际需要部署的域名:
|
||||
|
||||
```sh
|
||||
$ export QINIU_CDN_DOMAIN="cdn.example.com"
|
||||
$ acme.sh --deploy -d example.com --deploy-hook qiniu
|
||||
```
|
||||
|
||||
### English version
|
||||
|
||||
You should create AccessKey/SecretKey pair in https://portal.qiniu.com/user/key
|
||||
before deploying your certificate, and please ensure you have enabled HTTPS for
|
||||
your domain name. You can enable it in https://portal.qiniu.com/cdn/domain.
|
||||
|
||||
```sh
|
||||
$ export QINIU_AK="foo"
|
||||
$ export QINIU_SK="bar"
|
||||
```
|
||||
|
||||
then you can deploy certificate by following command:
|
||||
|
||||
```sh
|
||||
$ acme.sh --deploy -d example.com --deploy-hook qiniu
|
||||
```
|
||||
|
||||
(Optional), If you are using wildcard certificate,
|
||||
you may need export `QINIU_CDN_DOMAIN` to specify which domain
|
||||
you want to update:
|
||||
|
||||
```sh
|
||||
$ export QINIU_CDN_DOMAIN="cdn.example.com"
|
||||
$ acme.sh --deploy -d example.com --deploy-hook qiniu
|
||||
```
|
||||
|
||||
@@ -28,8 +28,10 @@ fritzbox_deploy() {
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
if ! _exists iconv; then
|
||||
_err "iconv not found"
|
||||
return 1
|
||||
if ! _exists perl; then
|
||||
_err "iconv or perl not found"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
_fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}"
|
||||
@@ -61,7 +63,11 @@ fritzbox_deploy() {
|
||||
|
||||
_info "Log in to the FRITZ!Box"
|
||||
_fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//')"
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')"
|
||||
if _exists iconv; then
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')"
|
||||
else
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | md5sum | awk '{print $1}')"
|
||||
fi
|
||||
_fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*<SID>//' -e 's/<\/SID>.*$//')"
|
||||
|
||||
if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then
|
||||
|
||||
80
deploy/gitlab.sh
Normal file
80
deploy/gitlab.sh
Normal file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Script to deploy certificate to a Gitlab hosted page
|
||||
|
||||
# The following variables exported from environment will be used.
|
||||
# If not set then values previously saved in domain.conf file are used.
|
||||
|
||||
# All the variables are required
|
||||
|
||||
# export GITLAB_TOKEN="xxxxxxx"
|
||||
# export GITLAB_PROJECT_ID=012345
|
||||
# export GITLAB_DOMAIN="mydomain.com"
|
||||
|
||||
gitlab_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
if [ -z "$GITLAB_TOKEN" ]; then
|
||||
if [ -z "$Le_Deploy_gitlab_token" ]; then
|
||||
_err "GITLAB_TOKEN not defined."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
Le_Deploy_gitlab_token="$GITLAB_TOKEN"
|
||||
_savedomainconf Le_Deploy_gitlab_token "$Le_Deploy_gitlab_token"
|
||||
fi
|
||||
|
||||
if [ -z "$GITLAB_PROJECT_ID" ]; then
|
||||
if [ -z "$Le_Deploy_gitlab_project_id" ]; then
|
||||
_err "GITLAB_PROJECT_ID not defined."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
Le_Deploy_gitlab_project_id="$GITLAB_PROJECT_ID"
|
||||
_savedomainconf Le_Deploy_gitlab_project_id "$Le_Deploy_gitlab_project_id"
|
||||
fi
|
||||
|
||||
if [ -z "$GITLAB_DOMAIN" ]; then
|
||||
if [ -z "$Le_Deploy_gitlab_domain" ]; then
|
||||
_err "GITLAB_DOMAIN not defined."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
Le_Deploy_gitlab_domain="$GITLAB_DOMAIN"
|
||||
_savedomainconf Le_Deploy_gitlab_domain "$Le_Deploy_gitlab_domain"
|
||||
fi
|
||||
|
||||
string_fullchain=$(_url_encode <"$_cfullchain")
|
||||
string_key=$(_url_encode <"$_ckey")
|
||||
|
||||
body="certificate=$string_fullchain&key=$string_key"
|
||||
|
||||
export _H1="PRIVATE-TOKEN: $Le_Deploy_gitlab_token"
|
||||
|
||||
gitlab_url="https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain"
|
||||
|
||||
_response=$(_post "$body" "$gitlab_url" 0 PUT | _dbase64 "multiline")
|
||||
|
||||
error_response="error"
|
||||
|
||||
if test "${_response#*$error_response}" != "$_response"; then
|
||||
_err "Error in deploying certificate:"
|
||||
_err "$_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug response "$_response"
|
||||
_info "Certificate successfully deployed"
|
||||
|
||||
return 0
|
||||
}
|
||||
92
deploy/qiniu.sh
Normal file
92
deploy/qiniu.sh
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Script to create certificate to qiniu.com
|
||||
#
|
||||
# This deployment required following variables
|
||||
# export QINIU_AK="QINIUACCESSKEY"
|
||||
# export QINIU_SK="QINIUSECRETKEY"
|
||||
# export QINIU_CDN_DOMAIN="cdn.example.com"
|
||||
|
||||
QINIU_API_BASE="https://api.qiniu.com"
|
||||
|
||||
qiniu_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
if [ -z "$QINIU_AK" ]; then
|
||||
_err "QINIU_AK is not defined."
|
||||
return 1
|
||||
else
|
||||
_savedomainconf QINIU_AK "$QINIU_AK"
|
||||
fi
|
||||
|
||||
if [ -z "$QINIU_SK" ]; then
|
||||
_err "QINIU_SK is not defined."
|
||||
return 1
|
||||
else
|
||||
_savedomainconf QINIU_SK "$QINIU_SK"
|
||||
fi
|
||||
|
||||
if [ "$QINIU_CDN_DOMAIN" ]; then
|
||||
_savedomainconf QINIU_CDN_DOMAIN "$QINIU_CDN_DOMAIN"
|
||||
else
|
||||
QINIU_CDN_DOMAIN="$_cdomain"
|
||||
fi
|
||||
|
||||
## upload certificate
|
||||
string_fullchain=$(sed 's/$/\\n/' "$_cfullchain" | tr -d '\n')
|
||||
string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n')
|
||||
|
||||
sslcert_path="/sslcert"
|
||||
sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$QINIU_CDN_DOMAIN\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}"
|
||||
sslcert_access_token="$(_make_access_token "$sslcert_path")"
|
||||
_debug sslcert_access_token "$sslcert_access_token"
|
||||
export _H1="Authorization: QBox $sslcert_access_token"
|
||||
sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline")
|
||||
|
||||
if ! _contains "$sslcert_response" "certID"; then
|
||||
_err "Error in creating certificate:"
|
||||
_err "$sslcert_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug sslcert_response "$sslcert_response"
|
||||
_info "Certificate successfully uploaded, updating domain $_cdomain"
|
||||
|
||||
## extract certId
|
||||
_certId="$(printf "%s" "$sslcert_response" | _normalizeJson | _egrep_o "certID\": *\"[^\"]*\"" | cut -d : -f 2)"
|
||||
_debug certId "$_certId"
|
||||
|
||||
## update domain ssl config
|
||||
update_path="/domain/$QINIU_CDN_DOMAIN/httpsconf"
|
||||
update_body="{\"certid\":$_certId,\"forceHttps\":false}"
|
||||
update_access_token="$(_make_access_token "$update_path")"
|
||||
_debug update_access_token "$update_access_token"
|
||||
export _H1="Authorization: QBox $update_access_token"
|
||||
update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline")
|
||||
|
||||
if _contains "$update_response" "error"; then
|
||||
_err "Error in updating domain httpsconf:"
|
||||
_err "$update_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug update_response "$update_response"
|
||||
_info "Certificate successfully deployed"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_make_access_token() {
|
||||
_token="$(printf "%s\n" "$1" | _hmac "sha1" "$(printf "%s" "$QINIU_SK" | _hex_dump | tr -d " ")" | _base64)"
|
||||
echo "$QINIU_AK:$_token"
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# Only a username is required. All others are optional.
|
||||
#
|
||||
# The following examples are for QNAP NAS running QTS 4.2
|
||||
# The following examples are for QNAP NAS running QTS 4.2
|
||||
# export DEPLOY_SSH_CMD="" # defaults to ssh
|
||||
# export DEPLOY_SSH_USER="admin" # required
|
||||
# export DEPLOY_SSH_SERVER="qnap" # defaults to domain name
|
||||
@@ -101,7 +101,7 @@ ssh_deploy() {
|
||||
fi
|
||||
|
||||
# CERTFILE is optional.
|
||||
# If provided then private key will be copied or appended to provided filename.
|
||||
# If provided then certificate will be copied or appended to provided filename.
|
||||
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE"
|
||||
_savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile"
|
||||
@@ -190,7 +190,7 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
_info "Backup directories erased after 180 days."
|
||||
fi
|
||||
|
||||
_debug "Remote commands to execute: $_cmdstr"
|
||||
_secure_debug "Remote commands to execute: " "$_cmdstr"
|
||||
_info "Submitting sequence of commands to remote server by ssh"
|
||||
# quotations in bash cmd below intended. Squash travis spellcheck error
|
||||
# shellcheck disable=SC2029
|
||||
|
||||
@@ -49,9 +49,13 @@ vault_cli_deploy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
$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}/chain.pem" value=@"$_cca" || return 1
|
||||
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
|
||||
if [ -n "$FABIO" ]; then
|
||||
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1
|
||||
else
|
||||
$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}/chain.pem" value=@"$_cca" || return 1
|
||||
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
278
dnsapi/README.md
278
dnsapi/README.md
@@ -6,7 +6,7 @@ https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode
|
||||
|
||||
## 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](https://dash.cloudflare.com/profile).
|
||||
|
||||
```
|
||||
export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
@@ -146,13 +146,17 @@ Finally, make the DNS server and update Key available to `acme.sh`
|
||||
export NSUPDATE_SERVER="dns.example.com"
|
||||
export NSUPDATE_KEY="/path/to/your/nsupdate.key"
|
||||
```
|
||||
and optionally (depending on DNS server)
|
||||
```
|
||||
export NSUPDATE_ZONE="example.com"
|
||||
```
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
```
|
||||
acme.sh --issue --dns dns_nsupdate -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `NSUPDATE_SERVER` and `NSUPDATE_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
The `NSUPDATE_SERVER`, `NSUPDATE_KEY`, and `NSUPDATE_ZONE` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
|
||||
## 8. Use LuaDNS domain API
|
||||
@@ -263,16 +267,26 @@ when needed.
|
||||
|
||||
## 14. Use Linode domain API
|
||||
|
||||
First you need to login to your Linode account to get your API Key.
|
||||
[https://manager.linode.com/profile/api](https://manager.linode.com/profile/api)
|
||||
The tokens created in the classic manager and cloud manager are incompatible
|
||||
with one another. While the classic manager makes an all or nothing API, the
|
||||
newer cloud manager interface promises to produce API keys with a finer
|
||||
permission system. However, either way works just fine.
|
||||
|
||||
Then add an API key with label *ACME* and copy the new key.
|
||||
### Classic Manager ###
|
||||
|
||||
Classic Manager: https://manager.linode.com/profile/api
|
||||
|
||||
First you need to login to your Linode account to get your API Key.
|
||||
|
||||
Then add an API key with label *ACME* and copy the new key into the following
|
||||
command.
|
||||
|
||||
```sh
|
||||
export LINODE_API_KEY="..."
|
||||
```
|
||||
|
||||
Due to the reload time of any changes in the DNS records, we have to use the `dnssleep` option to wait at least 15 minutes for the changes to take effect.
|
||||
Due to the reload time of any changes in the DNS records, we have to use the
|
||||
`dnssleep` option to wait at least 15 minutes for the changes to take effect.
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
|
||||
@@ -280,7 +294,35 @@ Ok, let's issue a cert now:
|
||||
acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be
|
||||
reused when needed.
|
||||
|
||||
### Cloud Manager ###
|
||||
|
||||
Cloud Manager: https://cloud.linode.com/profile/tokens
|
||||
|
||||
First you need to login to your Linode account to get your API Key.
|
||||
|
||||
1. Click on "Add a Personal Access Token".
|
||||
2. Give the new key a "Label" (we recommend *ACME*)
|
||||
3. Give it Read/Write access to "Domains"
|
||||
4. "Submit" and copy the new key into the `LINODE_V4_API_KEY` command below.
|
||||
|
||||
```sh
|
||||
export LINODE_V4_API_KEY="..."
|
||||
```
|
||||
|
||||
Due to the reload time of any changes in the DNS records, we have to use the
|
||||
`dnssleep` option to wait at least 15 minutes for the changes to take effect.
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
|
||||
```sh
|
||||
acme.sh --issue --dns dns_linode_v4 --dnssleep 900 -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `LINODE_V4_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be
|
||||
reused when needed.
|
||||
|
||||
## 15. Use FreeDNS
|
||||
|
||||
@@ -454,7 +496,7 @@ The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.
|
||||
First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/).
|
||||
|
||||
```
|
||||
VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
export VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
```
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
@@ -876,6 +918,7 @@ 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 Euserv.eu API
|
||||
|
||||
First you need to login to your euserv.eu account and activate your API Administration (API Verwaltung).
|
||||
@@ -897,6 +940,223 @@ acme.sh --issue --dns dns_euserv -d example.com -d *.example.com --insecure
|
||||
The `EUSERV_Username` and `EUSERV_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
Please report any issues to https://github.com/initit/acme.sh or to <github@initit.de>
|
||||
|
||||
## 48. Use DNSPod.com domain API to automatically issue cert
|
||||
|
||||
First you need to get your API Key and ID by this [get-the-user-token](https://www.dnspod.com/docs/info.html#get-the-user-token).
|
||||
|
||||
```
|
||||
export DPI_Id="1234"
|
||||
export DPI_Key="sADDsdasdgdsf"
|
||||
```
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
```
|
||||
acme.sh --issue --dns dns_dpi -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `DPI_Id` and `DPI_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
## 49. Use Google Cloud DNS API to automatically issue cert
|
||||
|
||||
First you need to authenticate to gcloud.
|
||||
|
||||
```
|
||||
gcloud init
|
||||
```
|
||||
|
||||
**The `dns_gcloud` script uses the active gcloud configuration and credentials.**
|
||||
There is no logic inside `dns_gcloud` to override the project and other settings.
|
||||
If needed, create additional [gcloud configurations](https://cloud.google.com/sdk/gcloud/reference/topic/configurations).
|
||||
You can change the configuration being used without *activating* it; simply set the `CLOUDSDK_ACTIVE_CONFIG_NAME` environment variable.
|
||||
|
||||
To issue a certificate you can:
|
||||
```
|
||||
export CLOUDSDK_ACTIVE_CONFIG_NAME=default # see the note above
|
||||
acme.sh --issue --dns dns_gcloud -d example.com -d '*.example.com'
|
||||
```
|
||||
|
||||
`dns_gcloud` also supports [DNS alias mode](https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode).
|
||||
|
||||
## 50. Use ConoHa API
|
||||
|
||||
First you need to login to your ConoHa account to get your API credentials.
|
||||
|
||||
```
|
||||
export CONOHA_Username="xxxxxx"
|
||||
export CONOHA_Password="xxxxxx"
|
||||
export CONOHA_TenantId="xxxxxx"
|
||||
export CONOHA_IdentityServiceApi="https://identity.xxxx.conoha.io/v2.0"
|
||||
```
|
||||
|
||||
To issue a cert:
|
||||
```
|
||||
acme.sh --issue --dns dns_conoha -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `CONOHA_Username`, `CONOHA_Password`, `CONOHA_TenantId` and `CONOHA_IdentityServiceApi` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
## 51. Use netcup DNS API to automatically issue cert
|
||||
|
||||
First you need to login in your CCP account to get your API Key and API Password.
|
||||
```
|
||||
export NC_Apikey="<Apikey>"
|
||||
export NC_Apipw="<Apipassword>"
|
||||
export NC_CID="<Customernumber>"
|
||||
```
|
||||
|
||||
Now, let's issue a cert:
|
||||
```
|
||||
acme.sh --issue --dns dns_netcup -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `NC_Apikey`,`NC_Apipw` and `NC_CID` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
## 52. Use GratisDNS.dk
|
||||
|
||||
GratisDNS.dk (https://gratisdns.dk/) does not provide an API to update DNS records (other than IPv4 and IPv6
|
||||
dynamic DNS addresses). The acme.sh plugin therefore retrieves and updates domain TXT records by logging
|
||||
into the GratisDNS website to read the HTML and posting updates as HTTP. The plugin needs to know your
|
||||
userid and password for the GratisDNS website.
|
||||
|
||||
```sh
|
||||
export GDNSDK_Username="..."
|
||||
export GDNSDK_Password="..."
|
||||
```
|
||||
The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
|
||||
Now you can issue a certificate.
|
||||
|
||||
Note: It usually takes a few minutes (usually 3-4 minutes) before the changes propagates to gratisdns.dk nameservers (ns3.gratisdns.dk often are slow),
|
||||
and in rare cases I have seen over 5 minutes before google DNS catches it. Therefor a DNS sleep of at least 300 seconds are recommended-
|
||||
|
||||
```sh
|
||||
acme.sh --issue --dns dns_gdnsdk --dnssleep 300 -d example.com -d *.example.com
|
||||
```
|
||||
|
||||
## 53. Use Namecheap
|
||||
|
||||
You will need your namecheap username, API KEY (https://www.namecheap.com/support/api/intro.aspx) and your external IP address (or an URL to get it), this IP will need to be whitelisted at Namecheap.
|
||||
Due to Namecheap's API limitation all the records of your domain will be read and re applied, make sure to have a backup of your records you could apply if any issue would arise.
|
||||
|
||||
```sh
|
||||
export NAMECHEAP_USERNAME="..."
|
||||
export NAMECHEAP_API_KEY="..."
|
||||
export NAMECHEAP_SOURCEIP="..."
|
||||
```
|
||||
|
||||
NAMECHEAP_SOURCEIP can either be an IP address or an URL to provide it (e.g. https://ifconfig.co/ip).
|
||||
|
||||
The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
Now you can issue a certificate.
|
||||
|
||||
```sh
|
||||
acme.sh --issue --dns dns_namecheap -d example.com -d *.example.com
|
||||
```
|
||||
|
||||
## 54. Use MyDNS.JP API
|
||||
|
||||
First, register to MyDNS.JP and get MasterID and Password.
|
||||
|
||||
```
|
||||
export MYDNSJP_MasterID=MasterID
|
||||
export MYDNSJP_Password=Password
|
||||
```
|
||||
|
||||
To issue a certificate:
|
||||
|
||||
```
|
||||
acme.sh --issue --dns dns_mydnsjp -d example.com -d www.example.com
|
||||
```
|
||||
The `MYDNSJP_MasterID` and `MYDNSJP_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
## 55. Use hosting.de API
|
||||
|
||||
Create an API key in your hosting.de account here: https://secure.hosting.de
|
||||
|
||||
The key needs the following rights:
|
||||
- DNS_ZONES_EDIT
|
||||
- DNS_ZONES_LIST
|
||||
|
||||
Set your API Key and endpoint:
|
||||
|
||||
```
|
||||
export HOSTINGDE_APIKEY='xxx'
|
||||
export HOSTINGDE_ENDPOINT='https://secure.hosting.de'
|
||||
```
|
||||
|
||||
The plugin can also be used for the http.net API. http.net customers have to set endpoint to https://partner.http.net.
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
```
|
||||
acme.sh --issue --dns dns_hostingde -d example.com -d *.example.com
|
||||
```
|
||||
|
||||
The hosting.de API key and endpoint will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
## 56. Use Neodigit.net API
|
||||
|
||||
```
|
||||
export NEODIGIT_API_TOKEN="eXJxTkdUVUZmcHQ3QWJackQ4ZGlMejRDSklRYmo5VG5zcFFKK2thYnE0WnVnNnMy"
|
||||
```
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
```
|
||||
acme.sh --issue --dns dns_neodigit -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
Neodigit API Token will be saved in `~/.acme.sh/account.conf` and will be used when needed.
|
||||
|
||||
## 57. Use Exoscale API
|
||||
|
||||
Create an API key and secret key in the Exoscale account section
|
||||
|
||||
Set your API and secret key:
|
||||
|
||||
```
|
||||
export EXOSCALE_API_KEY='xxx'
|
||||
export EXOSCALE_SECRET_KEY='xxx'
|
||||
```
|
||||
|
||||
Now, let's issue a cert:
|
||||
```
|
||||
acme.sh --issue --dns dns_exoscale -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `EXOSCALE_API_KEY` and `EXOSCALE_SECRET_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
## 58. Using PointHQ API to issue certs
|
||||
|
||||
Log into [PointHQ account management](https://app.pointhq.com/profile) and copy the API key from the page there.
|
||||
|
||||
```export PointHQ_Key="apikeystringgoeshere"
|
||||
exportPointHQ_Email="accountemail@yourdomain.com"
|
||||
```
|
||||
|
||||
You can then issue certs by using:
|
||||
```acme.sh --issue --dns dns_pointhq -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
## 59. Use Active24 API
|
||||
|
||||
Create an API token in the Active24 account section, documentation on https://faq.active24.com/cz/790131-REST-API-rozhran%C3%AD.
|
||||
|
||||
Set your API token:
|
||||
|
||||
```
|
||||
export ACTIVE24_Token='xxx'
|
||||
```
|
||||
|
||||
Now, let's issue a cert, set `dnssleep` for propagation new DNS record:
|
||||
```
|
||||
acme.sh --issue --dns dns_active24 -d example.com -d www.example.com --dnssleep 1000
|
||||
```
|
||||
|
||||
The `ACTIVE24_Token` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
|
||||
# Use custom API
|
||||
|
||||
If your API is not supported yet, you can write your own DNS API.
|
||||
@@ -917,4 +1177,4 @@ See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
|
||||
|
||||
# Use lexicon DNS API
|
||||
|
||||
https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
|
||||
https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
|
||||
|
||||
141
dnsapi/dns_active24.sh
Executable file
141
dnsapi/dns_active24.sh
Executable file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#ACTIVE24_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
|
||||
ACTIVE24_Api="https://api.active24.com"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
dns_active24_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_active24_init
|
||||
|
||||
_info "Adding txt record"
|
||||
if _active24_rest POST "dns/$_domain/txt/v1" "{\"name\":\"$_sub_domain\",\"text\":\"$txtvalue\",\"ttl\":0}"; then
|
||||
if _contains "$response" "errors"; then
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
else
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
}
|
||||
|
||||
# Usage: fulldomain txtvalue
|
||||
# Used to remove the txt record after validation
|
||||
dns_active24_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_active24_init
|
||||
|
||||
_debug "Getting txt records"
|
||||
_active24_rest GET "dns/$_domain/records/v1"
|
||||
|
||||
if _contains "$response" "errors"; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
hash_ids=$(echo "$response" | _egrep_o "[^{]+${txtvalue}[^}]+" | _egrep_o "hashId\":\"[^\"]+" | cut -c10-)
|
||||
|
||||
for hash_id in $hash_ids; do
|
||||
_debug "Removing hash_id" "$hash_id"
|
||||
if _active24_rest DELETE "dns/$_domain/$hash_id/v1" ""; then
|
||||
if _contains "$response" "errors"; then
|
||||
_err "Unable to remove txt record."
|
||||
return 1
|
||||
else
|
||||
_info "Removed txt record."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
_err "No txt records found."
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
|
||||
if ! _active24_rest GET "dns/domains/v1"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
i=2
|
||||
p=1
|
||||
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 _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
|
||||
return 1
|
||||
}
|
||||
|
||||
_active24_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
export _H1="Authorization: Bearer $ACTIVE24_Token"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug "data" "$data"
|
||||
response="$(_post "$data" "$ACTIVE24_Api/$ep" "" "$m" "application/json")"
|
||||
else
|
||||
response="$(_get "$ACTIVE24_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
_active24_init() {
|
||||
ACTIVE24_Token="${ACTIVE24_Token:-$(_readaccountconf_mutable ACTIVE24_Token)}"
|
||||
if [ -z "$ACTIVE24_Token" ]; then
|
||||
ACTIVE24_Token=""
|
||||
_err "You didn't specify a Active24 api token yet."
|
||||
_err "Please create the token and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable ACTIVE24_Token "ACTIVE24_Token"
|
||||
|
||||
_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"
|
||||
}
|
||||
@@ -29,7 +29,7 @@ dns_aws_add() {
|
||||
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
|
||||
AWS_ACCESS_KEY_ID=""
|
||||
AWS_SECRET_ACCESS_KEY=""
|
||||
_err "You don't specify aws route53 api key id and and api key secret yet."
|
||||
_err "You haven't specifed the aws route53 api key id and and api key secret yet."
|
||||
_err "Please create your key and try again. see $(__green $AWS_WIKI)"
|
||||
return 1
|
||||
fi
|
||||
@@ -62,7 +62,7 @@ dns_aws_add() {
|
||||
fi
|
||||
|
||||
if [ "$_resource_record" ] && _contains "$response" "$txtvalue"; then
|
||||
_info "The txt record already exists, skip"
|
||||
_info "The TXT record already exists. Skipping."
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -71,7 +71,7 @@ dns_aws_add() {
|
||||
_aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>UPSERT</Action><ResourceRecordSet><Name>$fulldomain</Name><Type>TXT</Type><TTL>300</TTL><ResourceRecords>$_resource_record<ResourceRecord><Value>\"$txtvalue\"</Value></ResourceRecord></ResourceRecords></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
|
||||
|
||||
if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
|
||||
_info "txt record updated success."
|
||||
_info "TXT record updated successfully."
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -99,7 +99,7 @@ dns_aws_rm() {
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_info "Geting existing records for $fulldomain"
|
||||
_info "Getting existing records for $fulldomain"
|
||||
if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then
|
||||
return 1
|
||||
fi
|
||||
@@ -108,14 +108,14 @@ dns_aws_rm() {
|
||||
_resource_record="$(echo "$response" | sed 's/<ResourceRecordSet>/"/g' | tr '"' "\n" | grep "<Name>$fulldomain.</Name>" | _egrep_o "<ResourceRecords.*</ResourceRecords>" | sed "s/<ResourceRecords>//" | sed "s#</ResourceRecords>##")"
|
||||
_debug "_resource_record" "$_resource_record"
|
||||
else
|
||||
_debug "no records exists, skip"
|
||||
_debug "no records exist, skip"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>DELETE</Action><ResourceRecordSet><ResourceRecords>$_resource_record</ResourceRecords><Name>$fulldomain.</Name><Type>TXT</Type><TTL>300</TTL></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
|
||||
|
||||
if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
|
||||
_info "txt record deleted success."
|
||||
_info "TXT record deleted successfully."
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -163,7 +163,7 @@ _get_root() {
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
_err "Can not find domain id: $h"
|
||||
_err "Can't find domain with id: $h"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -316,7 +316,7 @@ _get_root() {
|
||||
## (ZoneListResult with continuation token for the next page of results)
|
||||
## Per https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#dns-limits you are limited to 100 Zone/subscriptions anyways
|
||||
##
|
||||
_azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?api-version=2017-09-01" "" "$accesstoken"
|
||||
_azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?\$top=500&api-version=2017-09-01" "" "$accesstoken"
|
||||
# Find matching domain name is Json response
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
|
||||
@@ -19,8 +19,8 @@ dns_cf_add() {
|
||||
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
|
||||
CF_Key=""
|
||||
CF_Email=""
|
||||
_err "You didn't specify a cloudflare api key and email yet."
|
||||
_err "Please create the key and try again."
|
||||
_err "You didn't specify a Cloudflare api key and email yet."
|
||||
_err "You can get yours from here https://dash.cloudflare.com/profile."
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -58,9 +58,12 @@ dns_cf_add() {
|
||||
# if [ "$count" = "0" ]; then
|
||||
_info "Adding record"
|
||||
if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
|
||||
if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then
|
||||
if _contains "$response" "$fulldomain"; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
elif _contains "$response" "The record already exists"; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
@@ -94,8 +97,8 @@ dns_cf_rm() {
|
||||
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
|
||||
CF_Key=""
|
||||
CF_Email=""
|
||||
_err "You didn't specify a cloudflare api key and email yet."
|
||||
_err "Please create the key and try again."
|
||||
_err "You didn't specify a Cloudflare api key and email yet."
|
||||
_err "You can get yours from here https://dash.cloudflare.com/profile."
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -159,7 +162,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \")
|
||||
_domain_id=$(echo "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
|
||||
253
dnsapi/dns_conoha.sh
Executable file
253
dnsapi/dns_conoha.sh
Executable file
@@ -0,0 +1,253 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
CONOHA_DNS_EP_PREFIX_REGEXP="https://dns-service\."
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_conoha_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_conoha_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using conoha"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_debug "Check uesrname and password"
|
||||
CONOHA_Username="${CONOHA_Username:-$(_readaccountconf_mutable CONOHA_Username)}"
|
||||
CONOHA_Password="${CONOHA_Password:-$(_readaccountconf_mutable CONOHA_Password)}"
|
||||
CONOHA_TenantId="${CONOHA_TenantId:-$(_readaccountconf_mutable CONOHA_TenantId)}"
|
||||
CONOHA_IdentityServiceApi="${CONOHA_IdentityServiceApi:-$(_readaccountconf_mutable CONOHA_IdentityServiceApi)}"
|
||||
if [ -z "$CONOHA_Username" ] || [ -z "$CONOHA_Password" ] || [ -z "$CONOHA_TenantId" ] || [ -z "$CONOHA_IdentityServiceApi" ]; then
|
||||
CONOHA_Username=""
|
||||
CONOHA_Password=""
|
||||
CONOHA_TenantId=""
|
||||
CONOHA_IdentityServiceApi=""
|
||||
_err "You didn't specify a conoha api username and password yet."
|
||||
_err "Please create the user and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable CONOHA_Username "$CONOHA_Username"
|
||||
_saveaccountconf_mutable CONOHA_Password "$CONOHA_Password"
|
||||
_saveaccountconf_mutable CONOHA_TenantId "$CONOHA_TenantId"
|
||||
_saveaccountconf_mutable CONOHA_IdentityServiceApi "$CONOHA_IdentityServiceApi"
|
||||
|
||||
if token="$(_conoha_get_accesstoken "$CONOHA_IdentityServiceApi/tokens" "$CONOHA_Username" "$CONOHA_Password" "$CONOHA_TenantId")"; then
|
||||
accesstoken="$(printf "%s" "$token" | sed -n 1p)"
|
||||
CONOHA_Api="$(printf "%s" "$token" | sed -n 2p)"
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain" "$CONOHA_Api" "$accesstoken"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_info "Adding record"
|
||||
body="{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"data\":\"$txtvalue\",\"ttl\":60}"
|
||||
if _conoha_rest POST "$CONOHA_Api/v1/domains/$_domain_id/records" "$body" "$accesstoken"; then
|
||||
if _contains "$response" '"data":"'"$txtvalue"'"'; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_conoha_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using conoha"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_debug "Check uesrname and password"
|
||||
CONOHA_Username="${CONOHA_Username:-$(_readaccountconf_mutable CONOHA_Username)}"
|
||||
CONOHA_Password="${CONOHA_Password:-$(_readaccountconf_mutable CONOHA_Password)}"
|
||||
CONOHA_TenantId="${CONOHA_TenantId:-$(_readaccountconf_mutable CONOHA_TenantId)}"
|
||||
CONOHA_IdentityServiceApi="${CONOHA_IdentityServiceApi:-$(_readaccountconf_mutable CONOHA_IdentityServiceApi)}"
|
||||
if [ -z "$CONOHA_Username" ] || [ -z "$CONOHA_Password" ] || [ -z "$CONOHA_TenantId" ] || [ -z "$CONOHA_IdentityServiceApi" ]; then
|
||||
CONOHA_Username=""
|
||||
CONOHA_Password=""
|
||||
CONOHA_TenantId=""
|
||||
CONOHA_IdentityServiceApi=""
|
||||
_err "You didn't specify a conoha api username and password yet."
|
||||
_err "Please create the user and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable CONOHA_Username "$CONOHA_Username"
|
||||
_saveaccountconf_mutable CONOHA_Password "$CONOHA_Password"
|
||||
_saveaccountconf_mutable CONOHA_TenantId "$CONOHA_TenantId"
|
||||
_saveaccountconf_mutable CONOHA_IdentityServiceApi "$CONOHA_IdentityServiceApi"
|
||||
|
||||
if token="$(_conoha_get_accesstoken "$CONOHA_IdentityServiceApi/tokens" "$CONOHA_Username" "$CONOHA_Password" "$CONOHA_TenantId")"; then
|
||||
accesstoken="$(printf "%s" "$token" | sed -n 1p)"
|
||||
CONOHA_Api="$(printf "%s" "$token" | sed -n 2p)"
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain" "$CONOHA_Api" "$accesstoken"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
if ! _conoha_rest GET "$CONOHA_Api/v1/domains/$_domain_id/records" "" "$accesstoken"; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
record_id=$(printf "%s" "$response" | _egrep_o '{[^}]*}' \
|
||||
| grep '"type":"TXT"' | grep "\"data\":\"$txtvalue\"" | _egrep_o "\"id\":\"[^\"]*\"" \
|
||||
| _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
_debug record_id "$record_id"
|
||||
|
||||
_info "Removing the txt record"
|
||||
if ! _conoha_rest DELETE "$CONOHA_Api/v1/domains/$_domain_id/records/$record_id" "" "$accesstoken"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_conoha_rest() {
|
||||
m="$1"
|
||||
ep="$2"
|
||||
data="$3"
|
||||
accesstoken="$4"
|
||||
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="Content-Type: application/json"
|
||||
if [ -n "$accesstoken" ]; then
|
||||
export _H3="X-Auth-Token: $accesstoken"
|
||||
fi
|
||||
|
||||
_debug "$ep"
|
||||
if [ "$m" != "GET" ]; then
|
||||
_secure_debug2 data "$data"
|
||||
response="$(_post "$data" "$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$ep")"
|
||||
fi
|
||||
_ret="$?"
|
||||
_secure_debug2 response "$response"
|
||||
if [ "$_ret" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
|
||||
response="$(printf "%s" "$response" | _normalizeJson)"
|
||||
return 0
|
||||
}
|
||||
|
||||
_conoha_get_accesstoken() {
|
||||
ep="$1"
|
||||
username="$2"
|
||||
password="$3"
|
||||
tenantId="$4"
|
||||
|
||||
accesstoken="$(_readaccountconf_mutable conoha_accesstoken)"
|
||||
expires="$(_readaccountconf_mutable conoha_tokenvalidto)"
|
||||
CONOHA_Api="$(_readaccountconf_mutable conoha_dns_ep)"
|
||||
|
||||
# can we reuse the access token?
|
||||
if [ -n "$accesstoken" ] && [ -n "$expires" ] && [ -n "$CONOHA_Api" ]; then
|
||||
utc_date="$(_utc_date | sed "s/ /T/")"
|
||||
if expr "$utc_date" "<" "$expires" >/dev/null; then
|
||||
# access token is still valid - reuse it
|
||||
_debug "reusing access token"
|
||||
printf "%s\n%s\n" "$accesstoken" "$CONOHA_Api"
|
||||
return 0
|
||||
else
|
||||
_debug "access token expired"
|
||||
fi
|
||||
fi
|
||||
_debug "getting new access token"
|
||||
|
||||
body="$(printf '{"auth":{"passwordCredentials":{"username":"%s","password":"%s"},"tenantId":"%s"}}' "$username" "$password" "$tenantId")"
|
||||
if ! _conoha_rest POST "$ep" "$body" ""; then
|
||||
_err error "$response"
|
||||
return 1
|
||||
fi
|
||||
accesstoken=$(printf "%s" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
expires=$(printf "%s" "$response" | _egrep_o "\"expires\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2-4 | tr -d \" | tr -d Z) #expect UTC
|
||||
if [ -z "$accesstoken" ] || [ -z "$expires" ]; then
|
||||
_err "no acccess token received. Check your Conoha settings see $WIKI"
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable conoha_accesstoken "$accesstoken"
|
||||
_saveaccountconf_mutable conoha_tokenvalidto "$expires"
|
||||
|
||||
CONOHA_Api=$(printf "%s" "$response" | _egrep_o 'publicURL":"'"$CONOHA_DNS_EP_PREFIX_REGEXP"'[^"]*"' | _head_n 1 | cut -d : -f 2-3 | tr -d \")
|
||||
if [ -z "$CONOHA_Api" ]; then
|
||||
_err "failed to get conoha dns endpoint url"
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable conoha_dns_ep "$CONOHA_Api"
|
||||
|
||||
printf "%s\n%s\n" "$accesstoken" "$CONOHA_Api"
|
||||
return 0
|
||||
}
|
||||
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
ep="$2"
|
||||
accesstoken="$3"
|
||||
i=2
|
||||
p=1
|
||||
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 ! _conoha_rest GET "$ep/v1/domains?name=$h" "" "$accesstoken"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \")
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Cloudxns.com Domain api
|
||||
# CloudXNS Domain api
|
||||
#
|
||||
#CX_Key="1234"
|
||||
#
|
||||
@@ -19,7 +19,7 @@ dns_cx_add() {
|
||||
if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then
|
||||
CX_Key=""
|
||||
CX_Secret=""
|
||||
_err "You don't specify cloudxns.com api key or secret yet."
|
||||
_err "You don't specify cloudxns.net api key or secret yet."
|
||||
_err "Please create you key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -104,48 +104,60 @@ dns_dgon_rm() {
|
||||
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
|
||||
GURL="https://api.digitalocean.com/v2/domains/$_domain/records"
|
||||
|
||||
## while we dont have a record ID we keep going
|
||||
while [ -z "$record" ]; do
|
||||
## Get all the matching records
|
||||
while true; do
|
||||
## 1) get the URL
|
||||
## the create request - get
|
||||
## args: URL, [onlyheader, timeout]
|
||||
domain_list="$(_get "$GURL")"
|
||||
## 2) find record
|
||||
## check for what we are looing for: "type":"A","name":"$_sub_domain"
|
||||
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
|
||||
if [ -z "$record" ]; then
|
||||
## find the next page if we dont have a match
|
||||
nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")"
|
||||
if [ -z "$nextpage" ]; then
|
||||
_err "no record and no nextpage in digital ocean DNS removal"
|
||||
return 1
|
||||
fi
|
||||
_debug2 nextpage "$nextpage"
|
||||
GURL="$nextpage"
|
||||
|
||||
## check response
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in domain_list response: $domain_list"
|
||||
return 1
|
||||
fi
|
||||
## we break out of the loop when we have a record
|
||||
_debug2 domain_list "$domain_list"
|
||||
|
||||
## 2) find records
|
||||
## check for what we are looking for: "type":"A","name":"$_sub_domain"
|
||||
record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[0-9]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")"
|
||||
|
||||
if [ ! -z "$record" ]; then
|
||||
|
||||
## we found records
|
||||
rec_ids="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
|
||||
_debug rec_ids "$rec_ids"
|
||||
if [ ! -z "$rec_ids" ]; then
|
||||
echo "$rec_ids" | while IFS= read -r rec_id; do
|
||||
## delete the record
|
||||
## delete URL for removing the one we dont want
|
||||
DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id"
|
||||
|
||||
## the create request - delete
|
||||
## args: BODY, URL, [need64, httpmethod]
|
||||
response="$(_post "" "$DURL" "" "DELETE")"
|
||||
|
||||
## check response (sort of)
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in remove response: $response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
## 3) find the next page
|
||||
nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")"
|
||||
if [ -z "$nextpage" ]; then
|
||||
break
|
||||
fi
|
||||
_debug2 nextpage "$nextpage"
|
||||
GURL="$nextpage"
|
||||
|
||||
done
|
||||
|
||||
## we found the record
|
||||
rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
|
||||
_debug rec_id "$rec_id"
|
||||
|
||||
## delete the record
|
||||
## delete URL for removing the one we dont want
|
||||
DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id"
|
||||
|
||||
## the create request - delete
|
||||
## args: BODY, URL, [need64, httpmethod]
|
||||
response="$(_post "" "$DURL" "" "DELETE")"
|
||||
|
||||
## check response (sort of)
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in remove response: $response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
|
||||
## finished correctly
|
||||
return 0
|
||||
}
|
||||
@@ -178,44 +190,57 @@ _get_base_domain() {
|
||||
export _H2="Authorization: Bearer $DO_API_KEY"
|
||||
_debug DO_API_KEY "$DO_API_KEY"
|
||||
## get URL for the list of domains
|
||||
## havent seen this request paginated, tested with 18 domains (more requires manual requests with DO)
|
||||
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
|
||||
DOMURL="https://api.digitalocean.com/v2/domains"
|
||||
|
||||
## get the domain list (DO gives basically a full XFER!)
|
||||
domain_list="$(_get "$DOMURL")"
|
||||
## while we dont have a matching domain we keep going
|
||||
while [ -z "$found" ]; do
|
||||
## get the domain list (current page)
|
||||
domain_list="$(_get "$DOMURL")"
|
||||
|
||||
## check response
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in domain_list response: $domain_list"
|
||||
return 1
|
||||
fi
|
||||
_debug2 domain_list "$domain_list"
|
||||
|
||||
## for each shortening of our $fulldomain, check if it exists in the $domain_list
|
||||
## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge"
|
||||
i=2
|
||||
while [ $i -gt 0 ]; do
|
||||
## get next longest domain
|
||||
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
|
||||
## check we got something back from our cut (or are we at the end)
|
||||
if [ -z "$_domain" ]; then
|
||||
## we got to the end of the domain - invalid domain
|
||||
_err "domain not found in DigitalOcean account"
|
||||
## check response
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in domain_list response: $domain_list"
|
||||
return 1
|
||||
fi
|
||||
## we got part of a domain back - grep it out
|
||||
found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")"
|
||||
## check if it exists
|
||||
if [ ! -z "$found" ]; then
|
||||
## exists - exit loop returning the parts
|
||||
sub_point=$(_math $i - 1)
|
||||
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
|
||||
_debug _domain "$_domain"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
return 0
|
||||
_debug2 domain_list "$domain_list"
|
||||
|
||||
## for each shortening of our $fulldomain, check if it exists in the $domain_list
|
||||
## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge"
|
||||
i=2
|
||||
while [ $i -gt 0 ]; do
|
||||
## get next longest domain
|
||||
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
|
||||
## check we got something back from our cut (or are we at the end)
|
||||
if [ -z "$_domain" ]; then
|
||||
break
|
||||
fi
|
||||
## we got part of a domain back - grep it out
|
||||
found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")"
|
||||
## check if it exists
|
||||
if [ ! -z "$found" ]; then
|
||||
## exists - exit loop returning the parts
|
||||
sub_point=$(_math $i - 1)
|
||||
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
|
||||
_debug _domain "$_domain"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
return 0
|
||||
fi
|
||||
## increment cut point $i
|
||||
i=$(_math $i + 1)
|
||||
done
|
||||
|
||||
if [ -z "$found" ]; then
|
||||
## find the next page if we dont have a match
|
||||
nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")"
|
||||
if [ -z "$nextpage" ]; then
|
||||
_err "no record and no nextpage in digital ocean DNS removal"
|
||||
return 1
|
||||
fi
|
||||
_debug2 nextpage "$nextpage"
|
||||
DOMURL="$nextpage"
|
||||
fi
|
||||
## increment cut point $i
|
||||
i=$(_math $i + 1)
|
||||
|
||||
done
|
||||
|
||||
## we went through the entire domain zone list and dint find one that matched
|
||||
|
||||
@@ -152,7 +152,7 @@ _get_records() {
|
||||
sub_domain=$3
|
||||
|
||||
_debug "fetching txt records"
|
||||
_dnsimple_rest GET "$account_id/zones/$domain/records?per_page=100"
|
||||
_dnsimple_rest GET "$account_id/zones/$domain/records?per_page=5000&sort=id:desc"
|
||||
|
||||
if ! _contains "$response" "\"id\":"; then
|
||||
_err "failed to retrieve records"
|
||||
|
||||
161
dnsapi/dns_dpi.sh
Executable file
161
dnsapi/dns_dpi.sh
Executable file
@@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Dnspod.com Domain api
|
||||
#
|
||||
#DPI_Id="1234"
|
||||
#
|
||||
#DPI_Key="sADDsdasdgdsf"
|
||||
|
||||
REST_API="https://api.dnspod.com"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_dpi_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
DPI_Id="${DPI_Id:-$(_readaccountconf_mutable DPI_Id)}"
|
||||
DPI_Key="${DPI_Key:-$(_readaccountconf_mutable DPI_Key)}"
|
||||
if [ -z "$DPI_Id" ] || [ -z "$DPI_Key" ]; then
|
||||
DPI_Id=""
|
||||
DPI_Key=""
|
||||
_err "You don't specify dnspod api key and key id 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 DPI_Id "$DPI_Id"
|
||||
_saveaccountconf_mutable DPI_Key "$DPI_Key"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
add_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_dpi_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
DPI_Id="${DPI_Id:-$(_readaccountconf_mutable DPI_Id)}"
|
||||
DPI_Key="${DPI_Key:-$(_readaccountconf_mutable DPI_Key)}"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _rest POST "Record.List" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then
|
||||
_err "Record.Lis error."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" 'No records'; then
|
||||
_info "Don't need to remove."
|
||||
return 0
|
||||
fi
|
||||
|
||||
record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'"$txtvalue"'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \")
|
||||
_debug record_id "$record_id"
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _rest POST "Record.Remove" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then
|
||||
_err "Record.Remove error."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_contains "$response" "Action completed successful"
|
||||
|
||||
}
|
||||
|
||||
#add the txt record.
|
||||
#usage: root sub txtvalue
|
||||
add_record() {
|
||||
root=$1
|
||||
sub=$2
|
||||
txtvalue=$3
|
||||
fulldomain="$sub.$root"
|
||||
|
||||
_info "Adding record"
|
||||
|
||||
if ! _rest POST "Record.Create" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=default"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_contains "$response" "Action completed successful" || _contains "$response" "Domain record already exists"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _rest POST "Domain.Info" "user_token=$DPI_Id,$DPI_Key&format=json&domain=$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "Action completed successful"; then
|
||||
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
|
||||
_debug _domain_id "$_domain_id"
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_domain="$h"
|
||||
_debug _domain "$_domain"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p="$i"
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: method URI data
|
||||
_rest() {
|
||||
m="$1"
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
url="$REST_API/$ep"
|
||||
|
||||
_debug url "$url"
|
||||
|
||||
if [ "$m" = "GET" ]; then
|
||||
response="$(_get "$url" | tr -d '\r')"
|
||||
else
|
||||
_debug2 data "$data"
|
||||
response="$(_post "$data" "$url" | tr -d '\r')"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
Dynu_Token=""
|
||||
#
|
||||
#Endpoint
|
||||
Dynu_EndPoint="https://api.dynu.com/v1"
|
||||
Dynu_EndPoint="https://api.dynu.com/v2"
|
||||
#
|
||||
#Author: Dynu Systems, Inc.
|
||||
#Report Bugs here: https://github.com/shar0119/acme.sh
|
||||
@@ -51,11 +51,11 @@ dns_dynu_add() {
|
||||
_debug _domain_name "$_domain_name"
|
||||
|
||||
_info "Creating TXT record."
|
||||
if ! _dynu_rest POST "dns/record/add" "{\"domain_name\":\"$_domain_name\",\"node_name\":\"$_node\",\"record_type\":\"TXT\",\"text_data\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then
|
||||
if ! _dynu_rest POST "dns/$dnsId/record" "{\"domainId\":\"$dnsId\",\"nodeName\":\"$_node\",\"recordType\":\"TXT\",\"textData\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "text_data"; then
|
||||
if ! _contains "$response" "200"; then
|
||||
_err "Could not add TXT record."
|
||||
return 1
|
||||
fi
|
||||
@@ -132,11 +132,12 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _dynu_rest GET "dns/get/$h"; then
|
||||
if ! _dynu_rest GET "dns/getroot/$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||
if _contains "$response" "\"domainName\":\"$h\"" >/dev/null; then
|
||||
dnsId=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 2 | cut -d : -f 2)
|
||||
_domain_name=$h
|
||||
_node=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
return 0
|
||||
@@ -152,7 +153,7 @@ _get_recordid() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _dynu_rest GET "dns/record/get?hostname=$fulldomain&rrtype=TXT"; then
|
||||
if ! _dynu_rest GET "dns/$dnsId/record"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -161,19 +162,18 @@ _get_recordid() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
_dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | _egrep_o ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2)
|
||||
|
||||
_dns_record_id=$(printf "%s" "$response" | sed -e 's/[^{]*\({[^}]*}\)[^{]*/\1\n/g' | grep "\"textData\":\"$txtvalue\"" | sed -e 's/.*"id":\([^,]*\).*/\1/')
|
||||
return 0
|
||||
}
|
||||
|
||||
_delete_txt_record() {
|
||||
_dns_record_id=$1
|
||||
|
||||
if ! _dynu_rest GET "dns/record/delete/$_dns_record_id"; then
|
||||
if ! _dynu_rest DELETE "dns/$dnsId/record/$_dns_record_id"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "true"; then
|
||||
if ! _contains "$response" "200"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -189,7 +189,7 @@ _dynu_rest() {
|
||||
export _H1="Authorization: Bearer $Dynu_Token"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
if [ "$data" ]; then
|
||||
if [ "$data" ] || [ "$m" = "DELETE" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")"
|
||||
else
|
||||
@@ -216,8 +216,8 @@ _dynu_authentication() {
|
||||
_err "Authentication failed."
|
||||
return 1
|
||||
fi
|
||||
if _contains "$response" "accessToken"; then
|
||||
Dynu_Token=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 2 | cut -d : -f 2 | cut -d '"' -f 2)
|
||||
if _contains "$response" "access_token"; then
|
||||
Dynu_Token=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 1 | cut -d : -f 2 | cut -d '"' -f 2)
|
||||
fi
|
||||
if _contains "$Dynu_Token" "null"; then
|
||||
Dynu_Token=""
|
||||
|
||||
168
dnsapi/dns_exoscale.sh
Executable file
168
dnsapi/dns_exoscale.sh
Executable file
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
EXOSCALE_API=https://api.exoscale.com/dns/v1
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
dns_exoscale_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _checkAuth; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_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"
|
||||
if _exoscale_rest POST "domains/$_domain_id/records" "{\"record\":{\"name\":\"$_sub_domain\",\"record_type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":120}}" "$_domain_token"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
# Usage: fulldomain txtvalue
|
||||
# Used to remove the txt record after validation
|
||||
dns_exoscale_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _checkAuth; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_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"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_exoscale_rest GET "domains/${_domain_id}/records?type=TXT&name=$_sub_domain" "" "$_domain_token"
|
||||
if _contains "$response" "\"name\":\"$_sub_domain\"" >/dev/null; then
|
||||
_record_id=$(echo "$response" | tr '{' "\n" | grep "\"content\":\"$txtvalue\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
fi
|
||||
|
||||
if [ -z "$_record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Deleting record $_record_id"
|
||||
|
||||
if ! _exoscale_rest DELETE "domains/$_domain_id/records/$_record_id" "" "$_domain_token"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_checkAuth() {
|
||||
EXOSCALE_API_KEY="${EXOSCALE_API_KEY:-$(_readaccountconf_mutable EXOSCALE_API_KEY)}"
|
||||
EXOSCALE_SECRET_KEY="${EXOSCALE_SECRET_KEY:-$(_readaccountconf_mutable EXOSCALE_SECRET_KEY)}"
|
||||
|
||||
if [ -z "$EXOSCALE_API_KEY" ] || [ -z "$EXOSCALE_SECRET_KEY" ]; then
|
||||
EXOSCALE_API_KEY=""
|
||||
EXOSCALE_SECRET_KEY=""
|
||||
_err "You don't specify Exoscale application key and application secret yet."
|
||||
_err "Please create you key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable EXOSCALE_API_KEY "$EXOSCALE_API_KEY"
|
||||
_saveaccountconf_mutable EXOSCALE_SECRET_KEY "$EXOSCALE_SECRET_KEY"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
# _domain_token=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
|
||||
if ! _exoscale_rest GET "domains"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
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 _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||
_domain_id=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
_domain_token=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
if [ "$_domain_token" ] && [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# returns response
|
||||
_exoscale_rest() {
|
||||
method=$1
|
||||
path="$2"
|
||||
data="$3"
|
||||
token="$4"
|
||||
request_url="$EXOSCALE_API/$path"
|
||||
_debug "$path"
|
||||
|
||||
export _H1="Accept: application/json"
|
||||
|
||||
if [ "$token" ]; then
|
||||
export _H2="X-DNS-Domain-Token: $token"
|
||||
else
|
||||
export _H2="X-DNS-Token: $EXOSCALE_API_KEY:$EXOSCALE_SECRET_KEY"
|
||||
fi
|
||||
|
||||
if [ "$data" ] || [ "$method" = "DELETE" ]; then
|
||||
export _H3="Content-Type: application/json"
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$request_url" "" "$method")"
|
||||
else
|
||||
response="$(_get "$request_url" "" "" "$method")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $request_url"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
60
dnsapi/dns_gandi_livedns.sh
Executable file → Normal file
60
dnsapi/dns_gandi_livedns.sh
Executable file → Normal file
@@ -7,6 +7,7 @@
|
||||
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
|
||||
#
|
||||
#Author: Frédéric Crozat <fcrozat@suse.com>
|
||||
# Dominik Röttsches <drott@google.com>
|
||||
#Report Bugs here: https://github.com/fcrozat/acme.sh
|
||||
#
|
||||
######## Public functions #####################
|
||||
@@ -36,9 +37,7 @@ dns_gandi_livedns_add() {
|
||||
_debug domain "$_domain"
|
||||
_debug sub_domain "$_sub_domain"
|
||||
|
||||
_gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \
|
||||
&& _contains "$response" '{"message": "DNS Record Created"}' \
|
||||
&& _info "Add $(__green "success")"
|
||||
_dns_gandi_append_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
@@ -56,9 +55,23 @@ dns_gandi_livedns_rm() {
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug domain "$_domain"
|
||||
_debug sub_domain "$_sub_domain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_gandi_livedns_rest DELETE "domains/$_domain/records/$_sub_domain/TXT" ""
|
||||
if ! _dns_gandi_existing_rrset_values "$_domain" "$_sub_domain"; then
|
||||
return 1
|
||||
fi
|
||||
_new_rrset_values=$(echo "$_rrset_values" | sed "s/...$txtvalue...//g")
|
||||
# Cleanup dangling commata.
|
||||
_new_rrset_values=$(echo "$_new_rrset_values" | sed "s/, ,/ ,/g")
|
||||
_new_rrset_values=$(echo "$_new_rrset_values" | sed "s/, *\]/\]/g")
|
||||
_new_rrset_values=$(echo "$_new_rrset_values" | sed "s/\[ *,/\[/g")
|
||||
_debug "New rrset_values" "$_new_rrset_values"
|
||||
|
||||
_gandi_livedns_rest PUT \
|
||||
"domains/$_domain/records/$_sub_domain/TXT" \
|
||||
"{\"rrset_ttl\": 300, \"rrset_values\": $_new_rrset_values}" \
|
||||
&& _contains "$response" '{"message": "DNS Record Created"}' \
|
||||
&& _info "Removing record $(__green "success")"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
@@ -98,6 +111,45 @@ _get_root() {
|
||||
return 1
|
||||
}
|
||||
|
||||
_dns_gandi_append_record() {
|
||||
domain=$1
|
||||
sub_domain=$2
|
||||
txtvalue=$3
|
||||
|
||||
if _dns_gandi_existing_rrset_values "$domain" "$sub_domain"; then
|
||||
_debug "Appending new value"
|
||||
_rrset_values=$(echo "$_rrset_values" | sed "s/\"]/\",\"$txtvalue\"]/")
|
||||
else
|
||||
_debug "Creating new record" "$_rrset_values"
|
||||
_rrset_values="[\"$txtvalue\"]"
|
||||
fi
|
||||
_debug new_rrset_values "$_rrset_values"
|
||||
_gandi_livedns_rest PUT "domains/$_domain/records/$sub_domain/TXT" \
|
||||
"{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" \
|
||||
&& _contains "$response" '{"message": "DNS Record Created"}' \
|
||||
&& _info "Adding record $(__green "success")"
|
||||
}
|
||||
|
||||
_dns_gandi_existing_rrset_values() {
|
||||
domain=$1
|
||||
sub_domain=$2
|
||||
if ! _gandi_livedns_rest GET "domains/$domain/records/$sub_domain"; then
|
||||
return 1
|
||||
fi
|
||||
if ! _contains "$response" '"rrset_type": "TXT"'; then
|
||||
_debug "Does not have a _acme-challenge TXT record yet."
|
||||
return 1
|
||||
fi
|
||||
if _contains "$response" '"rrset_values": \[\]'; then
|
||||
_debug "Empty rrset_values for TXT record, no previous TXT record."
|
||||
return 1
|
||||
fi
|
||||
_debug "Already has TXT record."
|
||||
_rrset_values=$(echo "$response" | _egrep_o 'rrset_values.*\[.*\]' \
|
||||
| _egrep_o '\[".*\"]')
|
||||
return 0
|
||||
}
|
||||
|
||||
_gandi_livedns_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
|
||||
167
dnsapi/dns_gcloud.sh
Executable file
167
dnsapi/dns_gcloud.sh
Executable file
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Author: Janos Lenart <janos@lenart.io>
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: dns_gcloud_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_gcloud_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using gcloud"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_dns_gcloud_find_zone || return $?
|
||||
|
||||
# Add an extra RR
|
||||
_dns_gcloud_start_tr || return $?
|
||||
_dns_gcloud_get_rrdatas || return $?
|
||||
echo "$rrdatas" | _dns_gcloud_remove_rrs || return $?
|
||||
printf "%s\n%s\n" "$rrdatas" "\"$txtvalue\"" | grep -v '^$' | _dns_gcloud_add_rrs || return $?
|
||||
_dns_gcloud_execute_tr || return $?
|
||||
|
||||
_info "$fulldomain record added"
|
||||
}
|
||||
|
||||
# Usage: dns_gcloud_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Remove the txt record after validation.
|
||||
dns_gcloud_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using gcloud"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_dns_gcloud_find_zone || return $?
|
||||
|
||||
# Remove one RR
|
||||
_dns_gcloud_start_tr || return $?
|
||||
_dns_gcloud_get_rrdatas || return $?
|
||||
echo "$rrdatas" | _dns_gcloud_remove_rrs || return $?
|
||||
echo "$rrdatas" | grep -F -v "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $?
|
||||
_dns_gcloud_execute_tr || return $?
|
||||
|
||||
_info "$fulldomain record added"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_dns_gcloud_start_tr() {
|
||||
if ! trd=$(mktemp -d); then
|
||||
_err "_dns_gcloud_start_tr: failed to create temporary directory"
|
||||
return 1
|
||||
fi
|
||||
tr="$trd/tr.yaml"
|
||||
_debug tr "$tr"
|
||||
|
||||
if ! gcloud dns record-sets transaction start \
|
||||
--transaction-file="$tr" \
|
||||
--zone="$managedZone"; then
|
||||
rm -r "$trd"
|
||||
_err "_dns_gcloud_start_tr: failed to execute transaction"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_dns_gcloud_execute_tr() {
|
||||
if ! gcloud dns record-sets transaction execute \
|
||||
--transaction-file="$tr" \
|
||||
--zone="$managedZone"; then
|
||||
_debug tr "$(cat "$tr")"
|
||||
rm -r "$trd"
|
||||
_err "_dns_gcloud_execute_tr: failed to execute transaction"
|
||||
return 1
|
||||
fi
|
||||
rm -r "$trd"
|
||||
|
||||
for i in $(seq 1 120); do
|
||||
if gcloud dns record-sets changes list \
|
||||
--zone="$managedZone" \
|
||||
--filter='status != done' \
|
||||
| grep -q '^.*'; then
|
||||
_info "_dns_gcloud_execute_tr: waiting for transaction to be comitted ($i/120)..."
|
||||
sleep 5
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
_err "_dns_gcloud_execute_tr: transaction is still pending after 10 minutes"
|
||||
rm -r "$trd"
|
||||
return 1
|
||||
}
|
||||
|
||||
_dns_gcloud_remove_rrs() {
|
||||
if ! xargs --no-run-if-empty gcloud dns record-sets transaction remove \
|
||||
--name="$fulldomain." \
|
||||
--ttl="$ttl" \
|
||||
--type=TXT \
|
||||
--zone="$managedZone" \
|
||||
--transaction-file="$tr"; then
|
||||
_debug tr "$(cat "$tr")"
|
||||
rm -r "$trd"
|
||||
_err "_dns_gcloud_remove_rrs: failed to remove RRs"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_dns_gcloud_add_rrs() {
|
||||
ttl=60
|
||||
if ! xargs --no-run-if-empty gcloud dns record-sets transaction add \
|
||||
--name="$fulldomain." \
|
||||
--ttl="$ttl" \
|
||||
--type=TXT \
|
||||
--zone="$managedZone" \
|
||||
--transaction-file="$tr"; then
|
||||
_debug tr "$(cat "$tr")"
|
||||
rm -r "$trd"
|
||||
_err "_dns_gcloud_add_rrs: failed to add RRs"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_dns_gcloud_find_zone() {
|
||||
# Prepare a filter that matches zones that are suiteable for this entry.
|
||||
# For example, _acme-challenge.something.domain.com might need to go into something.domain.com or domain.com;
|
||||
# this function finds the longest postfix that has a managed zone.
|
||||
part="$fulldomain"
|
||||
filter="dnsName=( "
|
||||
while [ "$part" != "" ]; do
|
||||
filter="$filter$part. "
|
||||
part="$(echo "$part" | sed 's/[^.]*\.*//')"
|
||||
done
|
||||
filter="$filter)"
|
||||
_debug filter "$filter"
|
||||
|
||||
# List domains and find the longest match (in case of some levels of delegation)
|
||||
if ! match=$(gcloud dns managed-zones list \
|
||||
--format="value(name, dnsName)" \
|
||||
--filter="$filter" \
|
||||
| while read -r dnsName name; do
|
||||
printf "%s\t%s\t%s\n" "${#dnsName}" "$dnsName" "$name"
|
||||
done \
|
||||
| sort -n -r | _head_n 1 | cut -f2,3 | grep '^.*'); then
|
||||
_err "_dns_gcloud_find_zone: Can't find a matching managed zone! Perhaps wrong project or gcloud credentials?"
|
||||
return 1
|
||||
fi
|
||||
|
||||
dnsName=$(echo "$match" | cut -f2)
|
||||
_debug dnsName "$dnsName"
|
||||
managedZone=$(echo "$match" | cut -f1)
|
||||
_debug managedZone "$managedZone"
|
||||
}
|
||||
|
||||
_dns_gcloud_get_rrdatas() {
|
||||
if ! rrdatas=$(gcloud dns record-sets list \
|
||||
--zone="$managedZone" \
|
||||
--name="$fulldomain." \
|
||||
--type=TXT \
|
||||
--format="value(ttl,rrdatas)"); then
|
||||
_err "_dns_gcloud_get_rrdatas: Failed to list record-sets"
|
||||
rm -r "$trd"
|
||||
return 1
|
||||
fi
|
||||
ttl=$(echo "$rrdatas" | cut -f1)
|
||||
rrdatas=$(echo "$rrdatas" | cut -f2 | sed 's/","/"\n"/g')
|
||||
}
|
||||
168
dnsapi/dns_gdnsdk.sh
Executable file
168
dnsapi/dns_gdnsdk.sh
Executable file
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env sh
|
||||
#Author: Herman Sletteng
|
||||
#Report Bugs here: https://github.com/loial/acme.sh
|
||||
#
|
||||
#
|
||||
# Note, gratisdns requires a login first, so the script needs to handle
|
||||
# temporary cookies. Since acme.sh _get/_post currently don't directly support
|
||||
# cookies, I've defined wrapper functions _myget/_mypost to set the headers
|
||||
|
||||
GDNSDK_API="https://admin.gratisdns.com"
|
||||
######## Public functions #####################
|
||||
#Usage: dns_gdnsdk_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_gdnsdk_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using gratisdns.dk"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
if ! _gratisdns_login; then
|
||||
_err "Login failed!"
|
||||
return 1
|
||||
fi
|
||||
#finding domain zone
|
||||
if ! _get_domain; then
|
||||
_err "No matching root domain for $fulldomain found"
|
||||
return 1
|
||||
fi
|
||||
# adding entry
|
||||
_info "Adding the entry"
|
||||
_mypost "action=dns_primary_record_added_txt&user_domain=$_domain&name=$fulldomain&txtdata=$txtvalue&ttl=1"
|
||||
if _successful_update; then return 0; fi
|
||||
_err "Couldn't create entry!"
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_gdnsdk_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using gratisdns.dk"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
if ! _gratisdns_login; then
|
||||
_err "Login failed!"
|
||||
return 1
|
||||
fi
|
||||
if ! _get_domain; then
|
||||
_err "No matching root domain for $fulldomain found"
|
||||
return 1
|
||||
fi
|
||||
_findentry "$fulldomain" "$txtvalue"
|
||||
if [ -z "$_id" ]; then
|
||||
_info "Entry doesn't exist, nothing to delete"
|
||||
return 0
|
||||
fi
|
||||
_debug "Deleting record..."
|
||||
_mypost "action=dns_primary_delete_txt&user_domain=$_domain&id=$_id"
|
||||
# removing entry
|
||||
|
||||
if _successful_update; then return 0; fi
|
||||
_err "Couldn't delete entry!"
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_checkcredentials() {
|
||||
GDNSDK_Username="${GDNSDK_Username:-$(_readaccountconf_mutable GDNSDK_Username)}"
|
||||
GDNSDK_Password="${GDNSDK_Password:-$(_readaccountconf_mutable GDNSDK_Password)}"
|
||||
|
||||
if [ -z "$GDNSDK_Username" ] || [ -z "$GDNSDK_Password" ]; then
|
||||
GDNSDK_Username=""
|
||||
GDNSDK_Password=""
|
||||
_err "You haven't specified gratisdns.dk username and password yet."
|
||||
_err "Please add credentials and try again."
|
||||
return 1
|
||||
fi
|
||||
#save the credentials to the account conf file.
|
||||
_saveaccountconf_mutable GDNSDK_Username "$GDNSDK_Username"
|
||||
_saveaccountconf_mutable GDNSDK_Password "$GDNSDK_Password"
|
||||
return 0
|
||||
}
|
||||
|
||||
_checkcookie() {
|
||||
GDNSDK_Cookie="${GDNSDK_Cookie:-$(_readaccountconf_mutable GDNSDK_Cookie)}"
|
||||
if [ -z "$GDNSDK_Cookie" ]; then
|
||||
_debug "No cached cookie found"
|
||||
return 1
|
||||
fi
|
||||
_myget "action="
|
||||
if (echo "$_result" | grep -q "logmeout"); then
|
||||
_debug "Cached cookie still valid"
|
||||
return 0
|
||||
fi
|
||||
_debug "Cached cookie no longer valid"
|
||||
GDNSDK_Cookie=""
|
||||
_saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie"
|
||||
return 1
|
||||
}
|
||||
|
||||
_gratisdns_login() {
|
||||
if ! _checkcredentials; then return 1; fi
|
||||
|
||||
if _checkcookie; then
|
||||
_debug "Already logged in"
|
||||
return 0
|
||||
fi
|
||||
_debug "Logging into GratisDNS with user $GDNSDK_Username"
|
||||
|
||||
if ! _mypost "login=$GDNSDK_Username&password=$GDNSDK_Password&action=logmein"; then
|
||||
_err "GratisDNS login failed for user $GDNSDK_Username bad RC from _post"
|
||||
return 1
|
||||
fi
|
||||
|
||||
GDNSDK_Cookie="$(grep -A 15 '302 Found' "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]*' | _head_n 1 | cut -d ' ' -f2)"
|
||||
|
||||
if [ -z "$GDNSDK_Cookie" ]; then
|
||||
_err "GratisDNS login failed for user $GDNSDK_Username. Check $HTTP_HEADER file"
|
||||
return 1
|
||||
fi
|
||||
export GDNSDK_Cookie
|
||||
_saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie"
|
||||
return 0
|
||||
}
|
||||
|
||||
_myget() {
|
||||
#Adds cookie to request
|
||||
export _H1="Cookie: $GDNSDK_Cookie"
|
||||
_result=$(_get "$GDNSDK_API?$1")
|
||||
}
|
||||
_mypost() {
|
||||
#Adds cookie to request
|
||||
export _H1="Cookie: $GDNSDK_Cookie"
|
||||
_result=$(_post "$1" "$GDNSDK_API")
|
||||
}
|
||||
|
||||
_get_domain() {
|
||||
_myget 'action=dns_primarydns'
|
||||
_domains=$(echo "$_result" | _egrep_o ' domain="[[:alnum:].-_]+' | sed 's/^.*"//')
|
||||
if [ -z "$_domains" ]; then
|
||||
_err "Primary domain list not found!"
|
||||
return 1
|
||||
fi
|
||||
for _domain in $_domains; do
|
||||
if (_endswith "$fulldomain" "$_domain"); then
|
||||
_debug "Root domain: $_domain"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_successful_update() {
|
||||
if (echo "$_result" | grep -q 'table-success'); then return 0; fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_findentry() {
|
||||
#returns id of dns entry, if it exists
|
||||
_myget "action=dns_primary_changeDNSsetup&user_domain=$_domain"
|
||||
_id=$(echo "$_result" | _egrep_o "<td>$1</td>\s*<td>$2</td>[^?]*[^&]*&id=[^&]*" | sed 's/^.*=//')
|
||||
if [ -n "$_id" ]; then
|
||||
_debug "Entry found with _id=$_id"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
@@ -92,7 +92,9 @@ dns_he_rm() {
|
||||
return 1
|
||||
fi
|
||||
# Remove the record
|
||||
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&menu=edit_zone"
|
||||
body="$body&hosted_dns_zoneid=$_zone_id"
|
||||
body="$body&hosted_dns_recordid=$_record_id"
|
||||
|
||||
147
dnsapi/dns_hostingde.sh
Normal file
147
dnsapi/dns_hostingde.sh
Normal file
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# hosting.de API
|
||||
|
||||
# Values to export:
|
||||
# export HOSTINGDE_ENDPOINT='https://secure.hosting.de'
|
||||
# export HOSTINGDE_APIKEY='xxxxx'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
dns_hostingde_add() {
|
||||
fulldomain="${1}"
|
||||
txtvalue="${2}"
|
||||
_debug "Calling: _hostingde_addRecord() '${fulldomain}' '${txtvalue}'"
|
||||
_hostingde_apiKey && _hostingde_getZoneConfig && _hostingde_addRecord
|
||||
}
|
||||
|
||||
dns_hostingde_rm() {
|
||||
fulldomain="${1}"
|
||||
txtvalue="${2}"
|
||||
_debug "Calling: _hostingde_removeRecord() '${fulldomain}' '${txtvalue}'"
|
||||
_hostingde_apiKey && _hostingde_getZoneConfig && _hostingde_removeRecord
|
||||
}
|
||||
|
||||
#################### own Private functions below ##################################
|
||||
|
||||
_hostingde_apiKey() {
|
||||
HOSTINGDE_APIKEY="${HOSTINGDE_APIKEY:-$(_readaccountconf_mutable HOSTINGDE_APIKEY)}"
|
||||
if [ -z "$HOSTINGDE_APIKEY" ] || [ -z "$HOSTINGDE_ENDPOINT" ]; then
|
||||
HOSTINGDE_APIKEY=""
|
||||
HOSTINGDE_ENDPOINT=""
|
||||
_err "You haven't specified hosting.de API key or endpoint yet."
|
||||
_err "Please create your key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable HOSTINGDE_APIKEY "$HOSTINGDE_APIKEY"
|
||||
_saveaccountconf_mutable HOSTINGDE_ENDPOINT "$HOSTINGDE_ENDPOINT"
|
||||
}
|
||||
|
||||
_hostingde_getZoneConfig() {
|
||||
_info "Getting ZoneConfig"
|
||||
curZone="${fulldomain#*.}"
|
||||
returnCode=1
|
||||
while _contains "${curZone}" "\\."; do
|
||||
curData="{\"filter\":{\"field\":\"zoneName\",\"value\":\"${curZone}\"},\"limit\":1,\"authToken\":\"${HOSTINGDE_APIKEY}\"}"
|
||||
curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneConfigsFind")"
|
||||
_debug "Calling zoneConfigsFind: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneConfigsFind'"
|
||||
_debug "Result of zoneConfigsFind: '$curResult'"
|
||||
if _contains "${curResult}" '"status": "error"'; then
|
||||
if _contains "${curResult}" '"code": 10109'; then
|
||||
_err "The API-Key is invalid or could not be found"
|
||||
else
|
||||
_err "UNKNOWN API ERROR"
|
||||
fi
|
||||
returnCode=1
|
||||
break
|
||||
fi
|
||||
if _contains "${curResult}" '"totalEntries": 1'; then
|
||||
_info "Retrieved zone data."
|
||||
_debug "Zone data: '${curResult}'"
|
||||
zoneConfigId=$(echo "${curResult}" | _egrep_o '"id":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
zoneConfigName=$(echo "${curResult}" | _egrep_o '"name":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
zoneConfigType=$(echo "${curResult}" | grep -v "FindZoneConfigsResult" | _egrep_o '"type":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
zoneConfigExpire=$(echo "${curResult}" | _egrep_o '"expire":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1)
|
||||
zoneConfigNegativeTtl=$(echo "${curResult}" | _egrep_o '"negativeTtl":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1)
|
||||
zoneConfigRefresh=$(echo "${curResult}" | _egrep_o '"refresh":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1)
|
||||
zoneConfigRetry=$(echo "${curResult}" | _egrep_o '"retry":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1)
|
||||
zoneConfigTtl=$(echo "${curResult}" | _egrep_o '"ttl":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1)
|
||||
zoneConfigDnsServerGroupId=$(echo "${curResult}" | _egrep_o '"dnsServerGroupId":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
zoneConfigEmailAddress=$(echo "${curResult}" | _egrep_o '"emailAddress":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
zoneConfigDnsSecMode=$(echo "${curResult}" | _egrep_o '"dnsSecMode":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
if [ "${zoneConfigType}" != "NATIVE" ]; then
|
||||
_err "Zone is not native"
|
||||
returnCode=1
|
||||
break
|
||||
fi
|
||||
_debug "zoneConfigId '${zoneConfigId}'"
|
||||
returnCode=0
|
||||
break
|
||||
fi
|
||||
curZone="${curZone#*.}"
|
||||
done
|
||||
if [ $returnCode -ne 0 ]; then
|
||||
_info "ZoneEnd reached, Zone ${curZone} not found in hosting.de API"
|
||||
fi
|
||||
return $returnCode
|
||||
}
|
||||
|
||||
_hostingde_getZoneStatus() {
|
||||
_debug "Checking Zone status"
|
||||
curData="{\"filter\":{\"field\":\"zoneConfigId\",\"value\":\"${zoneConfigId}\"},\"limit\":1,\"authToken\":\"${HOSTINGDE_APIKEY}\"}"
|
||||
curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zonesFind")"
|
||||
_debug "Calling zonesFind '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zonesFind'"
|
||||
_debug "Result of zonesFind '$curResult'"
|
||||
zoneStatus=$(echo "${curResult}" | grep -v success | _egrep_o '"status":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
_debug "zoneStatus '${zoneStatus}'"
|
||||
return 0
|
||||
}
|
||||
|
||||
_hostingde_addRecord() {
|
||||
_info "Adding record to zone"
|
||||
_hostingde_getZoneStatus
|
||||
_debug "Result of zoneStatus: '${zoneStatus}'"
|
||||
while [ "${zoneStatus}" != "active" ]; do
|
||||
_sleep 5
|
||||
_hostingde_getZoneStatus
|
||||
_debug "Result of zoneStatus: '${zoneStatus}'"
|
||||
done
|
||||
curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\",\"name\":\"${zoneConfigName}\",\"type\":\"${zoneConfigType}\",\"dnsServerGroupId\":\"${zoneConfigDnsServerGroupId}\",\"dnsSecMode\":\"${zoneConfigDnsSecMode}\",\"emailAddress\":\"${zoneConfigEmailAddress}\",\"soaValues\":{\"expire\":${zoneConfigExpire},\"negativeTtl\":${zoneConfigNegativeTtl},\"refresh\":${zoneConfigRefresh},\"retry\":${zoneConfigRetry},\"ttl\":${zoneConfigTtl}}},\"recordsToAdd\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\",\"ttl\":3600}]}"
|
||||
curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")"
|
||||
_debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'"
|
||||
_debug "Result of zoneUpdate: '$curResult'"
|
||||
if _contains "${curResult}" '"status": "error"'; then
|
||||
if _contains "${curResult}" '"code": 10109'; then
|
||||
_err "The API-Key is invalid or could not be found"
|
||||
else
|
||||
_err "UNKNOWN API ERROR"
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
_hostingde_removeRecord() {
|
||||
_info "Removing record from zone"
|
||||
_hostingde_getZoneStatus
|
||||
_debug "Result of zoneStatus: '$zoneStatus'"
|
||||
while [ "$zoneStatus" != "active" ]; do
|
||||
_sleep 5
|
||||
_hostingde_getZoneStatus
|
||||
_debug "Result of zoneStatus: '$zoneStatus'"
|
||||
done
|
||||
curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\",\"name\":\"${zoneConfigName}\",\"type\":\"${zoneConfigType}\",\"dnsServerGroupId\":\"${zoneConfigDnsServerGroupId}\",\"dnsSecMode\":\"${zoneConfigDnsSecMode}\",\"emailAddress\":\"${zoneConfigEmailAddress}\",\"soaValues\":{\"expire\":${zoneConfigExpire},\"negativeTtl\":${zoneConfigNegativeTtl},\"refresh\":${zoneConfigRefresh},\"retry\":${zoneConfigRetry},\"ttl\":${zoneConfigTtl}}},\"recordsToDelete\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\"}]}"
|
||||
curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")"
|
||||
_debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'"
|
||||
_debug "Result of zoneUpdate: '$curResult'"
|
||||
if _contains "${curResult}" '"status": "error"'; then
|
||||
if _contains "${curResult}" '"code": 10109'; then
|
||||
_err "The API-Key is invalid or could not be found"
|
||||
else
|
||||
_err "UNKNOWN API ERROR"
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
@@ -158,7 +158,8 @@ _inwx_login() {
|
||||
export _H1
|
||||
|
||||
#https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71
|
||||
if _contains "$response" "tfa"; then
|
||||
if _contains "$response" "<member><name>code</name><value><int>1000</int></value></member>" \
|
||||
&& _contains "$response" "<member><name>tfa</name><value><string>GOOGLE-AUTH</string></value></member>"; then
|
||||
if [ -z "$INWX_Shared_Secret" ]; then
|
||||
_err "Mobile TAN detected."
|
||||
_err "Please define a shared secret."
|
||||
|
||||
@@ -7,20 +7,13 @@ lexicon_cmd="lexicon"
|
||||
|
||||
wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_lexicon_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999)
|
||||
|
||||
_lexicon_init() {
|
||||
if ! _exists "$lexicon_cmd"; then
|
||||
_err "Please install $lexicon_cmd first: $wiki"
|
||||
return 1
|
||||
fi
|
||||
|
||||
PROVIDER="${PROVIDER:-$(_readdomainconf PROVIDER)}"
|
||||
if [ -z "$PROVIDER" ]; then
|
||||
PROVIDER=""
|
||||
_err "Please define env PROVIDER first: $wiki"
|
||||
@@ -33,46 +26,78 @@ dns_lexicon_add() {
|
||||
# e.g. busybox-ash does not know [:upper:]
|
||||
# shellcheck disable=SC2018,SC2019
|
||||
Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z')
|
||||
eval "$Lx_name=\${$Lx_name:-$(_readaccountconf_mutable "$Lx_name")}"
|
||||
Lx_name_v=$(eval echo \$"$Lx_name")
|
||||
_secure_debug "$Lx_name" "$Lx_name_v"
|
||||
if [ "$Lx_name_v" ]; then
|
||||
_saveaccountconf "$Lx_name" "$Lx_name_v"
|
||||
_saveaccountconf_mutable "$Lx_name" "$Lx_name_v"
|
||||
eval export "$Lx_name"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2018,SC2019
|
||||
Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z')
|
||||
eval "$Lx_token=\${$Lx_token:-$(_readaccountconf_mutable "$Lx_token")}"
|
||||
Lx_token_v=$(eval echo \$"$Lx_token")
|
||||
_secure_debug "$Lx_token" "$Lx_token_v"
|
||||
if [ "$Lx_token_v" ]; then
|
||||
_saveaccountconf "$Lx_token" "$Lx_token_v"
|
||||
_saveaccountconf_mutable "$Lx_token" "$Lx_token_v"
|
||||
eval export "$Lx_token"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2018,SC2019
|
||||
Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z')
|
||||
eval "$Lx_password=\${$Lx_password:-$(_readaccountconf_mutable "$Lx_password")}"
|
||||
Lx_password_v=$(eval echo \$"$Lx_password")
|
||||
_secure_debug "$Lx_password" "$Lx_password_v"
|
||||
if [ "$Lx_password_v" ]; then
|
||||
_saveaccountconf "$Lx_password" "$Lx_password_v"
|
||||
_saveaccountconf_mutable "$Lx_password" "$Lx_password_v"
|
||||
eval export "$Lx_password"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2018,SC2019
|
||||
Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z')
|
||||
eval "$Lx_domaintoken=\${$Lx_domaintoken:-$(_readaccountconf_mutable "$Lx_domaintoken")}"
|
||||
Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken")
|
||||
_secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v"
|
||||
if [ "$Lx_domaintoken_v" ]; then
|
||||
_saveaccountconf_mutable "$Lx_domaintoken" "$Lx_domaintoken_v"
|
||||
eval export "$Lx_domaintoken"
|
||||
_saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v"
|
||||
fi
|
||||
}
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_lexicon_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_lexicon_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _lexicon_init; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
$lexicon_cmd "$PROVIDER" create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}"
|
||||
domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999)
|
||||
|
||||
_secure_debug LEXICON_OPTS "$LEXICON_OPTS"
|
||||
_savedomainconf LEXICON_OPTS "$LEXICON_OPTS"
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
$lexicon_cmd "$PROVIDER" $LEXICON_OPTS create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}"
|
||||
|
||||
}
|
||||
|
||||
#fulldomain
|
||||
#Usage: dns_lexicon_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_lexicon_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _lexicon_init; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999)
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
$lexicon_cmd "$PROVIDER" $LEXICON_OPTS delete "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}"
|
||||
|
||||
}
|
||||
|
||||
185
dnsapi/dns_linode_v4.sh
Executable file
185
dnsapi/dns_linode_v4.sh
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Original Author: Philipp Grosswiler <philipp.grosswiler@swiss-design.net>
|
||||
#v4 Update Author: Aaron W. Swenson <aaron@grandmasfridge.org>
|
||||
|
||||
LINODE_V4_API_URL="https://api.linode.com/v4/domains"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_linode_add() {
|
||||
fulldomain="${1}"
|
||||
txtvalue="${2}"
|
||||
|
||||
if ! _Linode_API; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using Linode"
|
||||
_debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Domain does not exist."
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_payload="{
|
||||
\"type\": \"TXT\",
|
||||
\"name\": \"$_sub_domain\",
|
||||
\"target\": \"$txtvalue\"
|
||||
}"
|
||||
|
||||
if _rest POST "/$_domain_id/records" "$_payload" && [ -n "$response" ]; then
|
||||
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
|
||||
_debug _resource_id "$_resource_id"
|
||||
|
||||
if [ -z "$_resource_id" ]; then
|
||||
_err "Error adding the domain resource."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Domain resource successfully added."
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: dns_linode_rm _acme-challenge.www.domain.com
|
||||
dns_linode_rm() {
|
||||
fulldomain="${1}"
|
||||
|
||||
if ! _Linode_API; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using Linode"
|
||||
_debug "Calling: dns_linode_rm() '${fulldomain}'"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Domain does not exist."
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
if _rest GET "/$_domain_id/records" && [ -n "$response" ]; then
|
||||
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
||||
|
||||
resource="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$_sub_domain\".*}")"
|
||||
if [ "$resource" ]; then
|
||||
_resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
||||
if [ "$_resource_id" ]; then
|
||||
_debug _resource_id "$_resource_id"
|
||||
|
||||
if _rest DELETE "/$_domain_id/records/$_resource_id" && [ -n "$response" ]; then
|
||||
# On 200/OK, empty set is returned. Check for error, if any.
|
||||
_error_response=$(printf "%s\n" "$response" | _egrep_o "\"errors\"" | cut -d : -f 2 | tr -d " " | _head_n 1)
|
||||
|
||||
if [ -n "$_error_response" ]; then
|
||||
_err "Error deleting the domain resource: $_error_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Domain resource successfully deleted."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_Linode_API() {
|
||||
if [ -z "$LINODE_V4_API_KEY" ]; then
|
||||
LINODE_V4_API_KEY=""
|
||||
|
||||
_err "You didn't specify the Linode v4 API key yet."
|
||||
_err "Please create your key and try again."
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf LINODE_V4_API_KEY "$LINODE_V4_API_KEY"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=12345
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
|
||||
if _rest GET; then
|
||||
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
hostedzone="$(echo "$response" | _egrep_o "{.*\"domain\":\s*\"$h\".*}")"
|
||||
if [ "$hostedzone" ]; then
|
||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#method method action data
|
||||
_rest() {
|
||||
mtd="$1"
|
||||
ep="$2"
|
||||
data="$3"
|
||||
|
||||
_debug mtd "$mtd"
|
||||
_debug ep "$ep"
|
||||
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H3="Authorization: Bearer $LINODE_V4_API_KEY"
|
||||
|
||||
if [ "$mtd" != "GET" ]; then
|
||||
# both POST and DELETE.
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$LINODE_V4_API_URL$ep" "" "$mtd")"
|
||||
else
|
||||
response="$(_get "$LINODE_V4_API_URL$ep$data")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -38,8 +38,8 @@ dns_loopia_add() {
|
||||
|
||||
_info "Adding record"
|
||||
|
||||
_loopia_add_record "$_domain" "$_sub_domain"
|
||||
_loopia_update_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||
_loopia_add_sub_domain "$_domain" "$_sub_domain"
|
||||
_loopia_add_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||
|
||||
}
|
||||
|
||||
@@ -96,6 +96,37 @@ dns_loopia_rm() {
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_loopia_get_records() {
|
||||
domain=$1
|
||||
sub_domain=$2
|
||||
|
||||
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>getZoneRecords</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" "<array>"; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain=$1
|
||||
_debug "get root"
|
||||
@@ -137,14 +168,14 @@ _get_root() {
|
||||
|
||||
}
|
||||
|
||||
_loopia_update_record() {
|
||||
_loopia_add_record() {
|
||||
domain=$1
|
||||
sub_domain=$2
|
||||
txtval=$3
|
||||
|
||||
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>updateZoneRecord</methodName>
|
||||
<methodName>addZoneRecord</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value><string>%s</string></value>
|
||||
@@ -176,10 +207,6 @@ _loopia_update_record() {
|
||||
<name>rdata</name>
|
||||
<value><string>%s</string></value>
|
||||
</member>
|
||||
<member>
|
||||
<name>record_id</name>
|
||||
<value><int>0</int></value>
|
||||
</member>
|
||||
</struct>
|
||||
</param>
|
||||
</params>
|
||||
@@ -194,10 +221,42 @@ _loopia_update_record() {
|
||||
return 0
|
||||
}
|
||||
|
||||
_loopia_add_record() {
|
||||
_sub_domain_exists() {
|
||||
domain=$1
|
||||
sub_domain=$2
|
||||
|
||||
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>getSubdomains</methodName>
|
||||
<params>
|
||||
<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")
|
||||
|
||||
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
||||
|
||||
if _contains "$response" "$sub_domain"; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_loopia_add_sub_domain() {
|
||||
domain=$1
|
||||
sub_domain=$2
|
||||
|
||||
if _sub_domain_exists "$domain" "$sub_domain"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>addSubdomain</methodName>
|
||||
|
||||
210
dnsapi/dns_mydnsjp.sh
Executable file
210
dnsapi/dns_mydnsjp.sh
Executable file
@@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Here is a api script for MyDNS.JP.
|
||||
#This file name is "dns_mydnsjp.sh"
|
||||
#So, here must be a method dns_mydnsjp_add()
|
||||
#Which will be called by acme.sh to add the txt record to your api system.
|
||||
#returns 0 means success, otherwise error.
|
||||
#
|
||||
#Author: epgdatacapbon
|
||||
#Report Bugs here: https://github.com/epgdatacapbon/acme.sh
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
# Export MyDNS.JP MasterID and Password in following variables...
|
||||
# MYDNSJP_MasterID=MasterID
|
||||
# MYDNSJP_Password=Password
|
||||
|
||||
MYDNSJP_API="https://www.mydns.jp"
|
||||
|
||||
#Usage: dns_mydnsjp_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_mydnsjp_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Using mydnsjp"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
# Load the credentials from the account conf file
|
||||
MYDNSJP_MasterID="${MYDNSJP_MasterID:-$(_readaccountconf_mutable MYDNSJP_MasterID)}"
|
||||
MYDNSJP_Password="${MYDNSJP_Password:-$(_readaccountconf_mutable MYDNSJP_Password)}"
|
||||
if [ -z "$MYDNSJP_MasterID" ] || [ -z "$MYDNSJP_Password" ]; then
|
||||
MYDNSJP_MasterID=""
|
||||
MYDNSJP_Password=""
|
||||
_err "You don't specify mydnsjp api MasterID and Password yet."
|
||||
_err "Please export as MYDNSJP_MasterID / MYDNSJP_Password and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Save the credentials to the account conf file
|
||||
_saveaccountconf_mutable MYDNSJP_MasterID "$MYDNSJP_MasterID"
|
||||
_saveaccountconf_mutable MYDNSJP_Password "$MYDNSJP_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"
|
||||
|
||||
if _mydnsjp_api "REGIST" "$_domain" "$txtvalue"; then
|
||||
if printf -- "%s" "$response" | grep "OK." >/dev/null; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_mydnsjp_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Removing TXT record"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
# Load the credentials from the account conf file
|
||||
MYDNSJP_MasterID="${MYDNSJP_MasterID:-$(_readaccountconf_mutable MYDNSJP_MasterID)}"
|
||||
MYDNSJP_Password="${MYDNSJP_Password:-$(_readaccountconf_mutable MYDNSJP_Password)}"
|
||||
if [ -z "$MYDNSJP_MasterID" ] || [ -z "$MYDNSJP_Password" ]; then
|
||||
MYDNSJP_MasterID=""
|
||||
MYDNSJP_Password=""
|
||||
_err "You don't specify mydnsjp api MasterID and Password yet."
|
||||
_err "Please export as MYDNSJP_MasterID / MYDNSJP_Password and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_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"
|
||||
|
||||
if _mydnsjp_api "DELETE" "$_domain" "$txtvalue"; then
|
||||
if printf -- "%s" "$response" | grep "OK." >/dev/null; then
|
||||
_info "Deleted, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Delete txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Delete txt record error."
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
# _acme-challenge.www.domain.com
|
||||
# returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
fulldomain=$1
|
||||
i=2
|
||||
p=1
|
||||
|
||||
# Get the root domain
|
||||
_mydnsjp_retrieve_domain
|
||||
if [ "$?" != "0" ]; then
|
||||
# not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
while true; do
|
||||
_domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100)
|
||||
|
||||
if [ -z "$_domain" ]; then
|
||||
# not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$_domain" = "$_root_domain" ]; then
|
||||
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p)
|
||||
return 0
|
||||
fi
|
||||
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Retrieve the root domain
|
||||
# returns 0 success
|
||||
_mydnsjp_retrieve_domain() {
|
||||
_debug "Login to MyDNS.JP"
|
||||
|
||||
response="$(_post "masterid=$MYDNSJP_MasterID&masterpwd=$MYDNSJP_Password" "$MYDNSJP_API/?MENU=100")"
|
||||
cookie="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2)"
|
||||
|
||||
# If cookies is not empty then logon successful
|
||||
if [ -z "$cookie" ]; then
|
||||
_err "Fail to get a cookie."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Retrieve DOMAIN INFO page"
|
||||
|
||||
export _H1="Cookie:${cookie}"
|
||||
|
||||
response="$(_get "$MYDNSJP_API/?MENU=300")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Fail to retrieve DOMAIN INFO."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_root_domain=$(echo "$response" | grep "DNSINFO\[domainname\]" | sed 's/^.*value="\([^"]*\)".*/\1/')
|
||||
|
||||
# Logout
|
||||
response="$(_get "$MYDNSJP_API/?MENU=090")"
|
||||
|
||||
_debug _root_domain "$_root_domain"
|
||||
|
||||
if [ -z "$_root_domain" ]; then
|
||||
_err "Fail to get the root domain."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_mydnsjp_api() {
|
||||
cmd=$1
|
||||
domain=$2
|
||||
txtvalue=$3
|
||||
|
||||
# Base64 encode the credentials
|
||||
credentials=$(printf "%s:%s" "$MYDNSJP_MasterID" "$MYDNSJP_Password" | _base64)
|
||||
|
||||
# Construct the HTTP Authorization header
|
||||
export _H1="Content-Type: application/x-www-form-urlencoded"
|
||||
export _H2="Authorization: Basic ${credentials}"
|
||||
|
||||
response="$(_post "CERTBOT_DOMAIN=$domain&CERTBOT_VALIDATION=$txtvalue&EDIT_CMD=$cmd" "$MYDNSJP_API/directedit.html")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
|
||||
return 0
|
||||
}
|
||||
356
dnsapi/dns_namecheap.sh
Executable file
356
dnsapi/dns_namecheap.sh
Executable file
@@ -0,0 +1,356 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Namecheap API
|
||||
# https://www.namecheap.com/support/api/intro.aspx
|
||||
#
|
||||
# Requires Namecheap API key set in NAMECHEAP_API_KEY, NAMECHEAP_SOURCEIP and NAMECHEAP_USERNAME set as environment variable
|
||||
# Due to Namecheap's API limitation all the records of your domain will be read and re applied, make sure to have a backup of your records you could apply if any issue would arise.
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
if [ "$STAGE" -eq 1 ]; then
|
||||
NAMECHEAP_API="https://api.sandbox.namecheap.com/xml.response"
|
||||
else
|
||||
NAMECHEAP_API="https://api.namecheap.com/xml.response"
|
||||
fi
|
||||
|
||||
#Usage: dns_namecheap_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_namecheap_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _namecheap_check_config; then
|
||||
_err "$error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _namecheap_set_publicip; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
_debug domain "$_domain"
|
||||
_debug sub_domain "$_sub_domain"
|
||||
|
||||
_set_namecheap_TXT "$_domain" "$_sub_domain" "$txtvalue"
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_namecheap_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _namecheap_set_publicip; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _namecheap_check_config; then
|
||||
_err "$error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
_debug domain "$_domain"
|
||||
_debug sub_domain "$_sub_domain"
|
||||
|
||||
_del_namecheap_TXT "$_domain" "$_sub_domain" "$txtvalue"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
|
||||
if ! _namecheap_post "namecheap.domains.getList"; then
|
||||
_err "$error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
i=2
|
||||
p=1
|
||||
|
||||
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 ! _contains "$response" "$h"; then
|
||||
_debug "$h not found"
|
||||
else
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
p="$i"
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_namecheap_set_publicip() {
|
||||
|
||||
if [ -z "$NAMECHEAP_SOURCEIP" ]; then
|
||||
_err "No Source IP specified for Namecheap API."
|
||||
_err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
|
||||
return 1
|
||||
else
|
||||
_saveaccountconf NAMECHEAP_SOURCEIP "$NAMECHEAP_SOURCEIP"
|
||||
_debug sourceip "$NAMECHEAP_SOURCEIP"
|
||||
|
||||
ip=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
|
||||
addr=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '(http|https)://.*')
|
||||
|
||||
_debug2 ip "$ip"
|
||||
_debug2 addr "$addr"
|
||||
|
||||
if [ -n "$ip" ]; then
|
||||
_publicip="$ip"
|
||||
elif [ -n "$addr" ]; then
|
||||
_publicip=$(_get "$addr")
|
||||
else
|
||||
_err "No Source IP specified for Namecheap API."
|
||||
_err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
_debug publicip "$_publicip"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_namecheap_post() {
|
||||
command=$1
|
||||
data="ApiUser=${NAMECHEAP_USERNAME}&ApiKey=${NAMECHEAP_API_KEY}&ClientIp=${_publicip}&UserName=${NAMECHEAP_USERNAME}&Command=${command}"
|
||||
|
||||
response="$(_post "$data" "$NAMECHEAP_API" "" "POST")"
|
||||
_debug2 response "$response"
|
||||
|
||||
if _contains "$response" "Status=\"ERROR\"" >/dev/null; then
|
||||
error=$(echo "$response" | _egrep_o ">.*<\\/Error>" | cut -d '<' -f 1 | tr -d '>')
|
||||
_err "error $error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_namecheap_parse_host() {
|
||||
_host=$1
|
||||
_debug _host "$_host"
|
||||
|
||||
_hostid=$(echo "$_host" | _egrep_o ' HostId="[^"]*' | cut -d '"' -f 2)
|
||||
_hostname=$(echo "$_host" | _egrep_o ' Name="[^"]*' | cut -d '"' -f 2)
|
||||
_hosttype=$(echo "$_host" | _egrep_o ' Type="[^"]*' | cut -d '"' -f 2)
|
||||
_hostaddress=$(echo "$_host" | _egrep_o ' Address="[^"]*' | cut -d '"' -f 2)
|
||||
_hostmxpref=$(echo "$_host" | _egrep_o ' MXPref="[^"]*' | cut -d '"' -f 2)
|
||||
_hostttl=$(echo "$_host" | _egrep_o ' TTL="[^"]*' | cut -d '"' -f 2)
|
||||
|
||||
_debug hostid "$_hostid"
|
||||
_debug hostname "$_hostname"
|
||||
_debug hosttype "$_hosttype"
|
||||
_debug hostaddress "$_hostaddress"
|
||||
_debug hostmxpref "$_hostmxpref"
|
||||
_debug hostttl "$_hostttl"
|
||||
}
|
||||
|
||||
_namecheap_check_config() {
|
||||
|
||||
if [ -z "$NAMECHEAP_API_KEY" ]; then
|
||||
_err "No API key specified for Namecheap API."
|
||||
_err "Create your key and export it as NAMECHEAP_API_KEY"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$NAMECHEAP_USERNAME" ]; then
|
||||
_err "No username key specified for Namecheap API."
|
||||
_err "Create your key and export it as NAMECHEAP_USERNAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf NAMECHEAP_API_KEY "$NAMECHEAP_API_KEY"
|
||||
_saveaccountconf NAMECHEAP_USERNAME "$NAMECHEAP_USERNAME"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_set_namecheap_TXT() {
|
||||
subdomain=$2
|
||||
txt=$3
|
||||
|
||||
if ! _namecheap_set_tld_sld "$1"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}"
|
||||
|
||||
if ! _namecheap_post "$request"; then
|
||||
_err "$error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
hosts=$(echo "$response" | _egrep_o '<host[^>]*')
|
||||
_debug hosts "$hosts"
|
||||
|
||||
if [ -z "$hosts" ]; then
|
||||
_error "Hosts not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_namecheap_reset_hostList
|
||||
|
||||
while read -r host; do
|
||||
if _contains "$host" "<host"; then
|
||||
_namecheap_parse_host "$host"
|
||||
_namecheap_add_host "$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl"
|
||||
fi
|
||||
done <<EOT
|
||||
echo "$hosts"
|
||||
EOT
|
||||
|
||||
_namecheap_add_host "$subdomain" "TXT" "$txt" 10 120
|
||||
|
||||
_debug hostrequestfinal "$_hostrequest"
|
||||
|
||||
request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}"
|
||||
|
||||
if ! _namecheap_post "$request"; then
|
||||
_err "$error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_del_namecheap_TXT() {
|
||||
subdomain=$2
|
||||
txt=$3
|
||||
|
||||
if ! _namecheap_set_tld_sld "$1"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}"
|
||||
|
||||
if ! _namecheap_post "$request"; then
|
||||
_err "$error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
hosts=$(echo "$response" | _egrep_o '<host[^>]*')
|
||||
_debug hosts "$hosts"
|
||||
|
||||
if [ -z "$hosts" ]; then
|
||||
_error "Hosts not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_namecheap_reset_hostList
|
||||
|
||||
found=0
|
||||
|
||||
while read -r host; do
|
||||
if _contains "$host" "<host"; then
|
||||
_namecheap_parse_host "$host"
|
||||
if [ "$_hosttype" = "TXT" ] && [ "$_hostname" = "$subdomain" ] && [ "$_hostaddress" = "$txt" ]; then
|
||||
_debug "TXT entry found"
|
||||
found=1
|
||||
else
|
||||
_namecheap_add_host "$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl"
|
||||
fi
|
||||
fi
|
||||
done <<EOT
|
||||
echo "$hosts"
|
||||
EOT
|
||||
|
||||
if [ $found -eq 0 ]; then
|
||||
_debug "TXT entry not found"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_debug hostrequestfinal "$_hostrequest"
|
||||
|
||||
request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}"
|
||||
|
||||
if ! _namecheap_post "$request"; then
|
||||
_err "$error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_namecheap_reset_hostList() {
|
||||
_hostindex=0
|
||||
_hostrequest=""
|
||||
}
|
||||
|
||||
#Usage: _namecheap_add_host HostName RecordType Address MxPref TTL
|
||||
_namecheap_add_host() {
|
||||
_hostindex=$(_math "$_hostindex" + 1)
|
||||
_hostrequest=$(printf '%s&HostName%d=%s&RecordType%d=%s&Address%d=%s&MXPref%d=%d&TTL%d=%d' "$_hostrequest" "$_hostindex" "$1" "$_hostindex" "$2" "$_hostindex" "$3" "$_hostindex" "$4" "$_hostindex" "$5")
|
||||
}
|
||||
|
||||
_namecheap_set_tld_sld() {
|
||||
domain=$1
|
||||
_tld=""
|
||||
_sld=""
|
||||
|
||||
i=2
|
||||
|
||||
while true; do
|
||||
|
||||
_tld=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug tld "$_tld"
|
||||
|
||||
if [ -z "$_tld" ]; then
|
||||
_debug "invalid tld"
|
||||
return 1
|
||||
fi
|
||||
|
||||
j=$(_math "$i" - 1)
|
||||
|
||||
_sld=$(printf "%s" "$domain" | cut -d . -f 1-"$j")
|
||||
_debug sld "$_sld"
|
||||
|
||||
if [ -z "$_sld" ]; then
|
||||
_debug "invalid sld"
|
||||
return 1
|
||||
fi
|
||||
|
||||
request="namecheap.domains.dns.getHosts&SLD=$_sld&TLD=$_tld"
|
||||
|
||||
if ! _namecheap_post "$request"; then
|
||||
_debug "sld($_sld)/tld($_tld) not found"
|
||||
else
|
||||
_debug "sld($_sld)/tld($_tld) found"
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=$(_math "$i" + 1)
|
||||
|
||||
done
|
||||
|
||||
}
|
||||
181
dnsapi/dns_neodigit.sh
Normal file
181
dnsapi/dns_neodigit.sh
Normal file
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# NEODIGIT_API_TOKEN="jasdfhklsjadhflnhsausdfas"
|
||||
|
||||
# This is Neodigit.net api wrapper for acme.sh
|
||||
#
|
||||
# Author: Adrian Almenar
|
||||
# Report Bugs here: https://github.com/tecnocratica/acme.sh
|
||||
#
|
||||
NEODIGIT_API_URL="https://api.neodigit.net/v1"
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_neodigit_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}"
|
||||
if [ -z "$NEODIGIT_API_TOKEN" ]; then
|
||||
NEODIGIT_API_TOKEN=""
|
||||
_err "You haven't specified a Token api key."
|
||||
_err "Please create the key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable NEODIGIT_API_TOKEN "$NEODIGIT_API_TOKEN"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
_debug domain "$_domain"
|
||||
_debug sub_domain "$_sub_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_neo_rest GET "dns/zones/${_domain_id}/records?type=TXT&name=$fulldomain"
|
||||
|
||||
_debug _code "$_code"
|
||||
|
||||
if [ "$_code" != "200" ]; then
|
||||
_err "error retrieving data!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
_debug domain "$_domain"
|
||||
_debug sub_domain "$_sub_domain"
|
||||
|
||||
_info "Adding record"
|
||||
if _neo_rest POST "dns/zones/$_domain_id/records" "{\"record\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":60}}"; then
|
||||
if printf -- "%s" "$response" | grep "$_sub_domain" >/dev/null; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_neodigit_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}"
|
||||
if [ -z "$NEODIGIT_API_TOKEN" ]; then
|
||||
NEODIGIT_API_TOKEN=""
|
||||
_err "You haven't specified a Token api key."
|
||||
_err "Please create the key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable NEODIGIT_API_TOKEN "$NEODIGIT_API_TOKEN"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_neo_rest GET "dns/zones/${_domain_id}/records?type=TXT&name=$fulldomain&content=$txtvalue"
|
||||
|
||||
if [ "$_code" != "200" ]; then
|
||||
_err "error retrieving data!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
record_id=$(echo "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1)
|
||||
_debug "record_id" "$record_id"
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
if ! _neo_rest DELETE "dns/zones/$_domain_id/records/$record_id"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=dasfdsafsadg5ythd
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
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 ! _neo_rest GET "dns/zones?name=$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug p "$p"
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||
_domain_id=$(echo "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1)
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_neo_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
export _H1="X-TCPanel-Token: $NEODIGIT_API_TOKEN"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$NEODIGIT_API_URL/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$NEODIGIT_API_URL/$ep")"
|
||||
fi
|
||||
|
||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
133
dnsapi/dns_netcup.sh
Normal file
133
dnsapi/dns_netcup.sh
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env sh
|
||||
#developed by linux-insideDE
|
||||
|
||||
NC_Apikey="${NC_Apikey:-$(_readaccountconf_mutable NC_Apikey)}"
|
||||
NC_Apipw="${NC_Apipw:-$(_readaccountconf_mutable NC_Apipw)}"
|
||||
NC_CID="${NC_CID:-$(_readaccountconf_mutable NC_CID)}"
|
||||
end="https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
|
||||
client=""
|
||||
|
||||
dns_netcup_add() {
|
||||
login
|
||||
if [ "$NC_Apikey" = "" ] || [ "$NC_Apipw" = "" ] || [ "$NC_CID" = "" ]; then
|
||||
_err "No Credentials given"
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable NC_Apikey "$NC_Apikey"
|
||||
_saveaccountconf_mutable NC_Apipw "$NC_Apipw"
|
||||
_saveaccountconf_mutable NC_CID "$NC_CID"
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
domain=""
|
||||
exit=$(echo "$fulldomain" | tr -dc '.' | wc -c)
|
||||
exit=$(_math "$exit" + 1)
|
||||
i=$exit
|
||||
|
||||
while
|
||||
[ "$exit" -gt 0 ]
|
||||
do
|
||||
tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit")
|
||||
if [ "$(_math "$i" - "$exit")" -eq 0 ]; then
|
||||
domain="$tmp"
|
||||
else
|
||||
domain="$tmp.$domain"
|
||||
fi
|
||||
if [ "$(_math "$i" - "$exit")" -ge 1 ]; then
|
||||
msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"false\", \"state\": \"yes\"} ]}}}" "$end" "" "POST")
|
||||
_debug "$msg"
|
||||
if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then
|
||||
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
|
||||
_err "$msg"
|
||||
return 1
|
||||
else
|
||||
break
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
exit=$(_math "$exit" - 1)
|
||||
done
|
||||
logout
|
||||
}
|
||||
|
||||
dns_netcup_rm() {
|
||||
login
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
domain=""
|
||||
exit=$(echo "$fulldomain" | tr -dc '.' | wc -c)
|
||||
exit=$(_math "$exit" + 1)
|
||||
i=$exit
|
||||
rec=""
|
||||
|
||||
while
|
||||
[ "$exit" -gt 0 ]
|
||||
do
|
||||
tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit")
|
||||
if [ "$(_math "$i" - "$exit")" -eq 0 ]; then
|
||||
domain="$tmp"
|
||||
else
|
||||
domain="$tmp.$domain"
|
||||
fi
|
||||
if [ "$(_math "$i" - "$exit")" -ge 1 ]; then
|
||||
msg=$(_post "{\"action\": \"infoDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\", \"domainname\": \"$domain\"}}" "$end" "" "POST")
|
||||
rec=$(echo "$msg" | sed 's/\[//g' | sed 's/\]//g' | sed 's/{\"serverrequestid\".*\"dnsrecords\"://g' | sed 's/},{/};{/g' | sed 's/{//g' | sed 's/}//g')
|
||||
_debug "$msg"
|
||||
if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then
|
||||
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
|
||||
_err "$msg"
|
||||
return 1
|
||||
else
|
||||
break
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
exit=$(_math "$exit" - 1)
|
||||
done
|
||||
|
||||
ida=0000
|
||||
idv=0001
|
||||
ids=0000000000
|
||||
i=1
|
||||
while
|
||||
[ "$i" -ne 0 ]
|
||||
do
|
||||
specrec=$(_getfield "$rec" "$i" ";")
|
||||
idv="$ida"
|
||||
ida=$(_getfield "$specrec" "1" "," | sed 's/\"id\":\"//g' | sed 's/\"//g')
|
||||
txtv=$(_getfield "$specrec" "5" "," | sed 's/\"destination\":\"//g' | sed 's/\"//g')
|
||||
i=$(_math "$i" + 1)
|
||||
if [ "$txtvalue" = "$txtv" ]; then
|
||||
i=0
|
||||
ids="$ida"
|
||||
fi
|
||||
if [ "$ida" = "$idv" ]; then
|
||||
i=0
|
||||
fi
|
||||
done
|
||||
msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"$ids\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"TRUE\", \"state\": \"yes\"} ]}}}" "$end" "" "POST")
|
||||
_debug "$msg"
|
||||
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
|
||||
_err "$msg"
|
||||
return 1
|
||||
fi
|
||||
logout
|
||||
}
|
||||
|
||||
login() {
|
||||
tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST")
|
||||
sid=$(_getfield "$tmp" "8" | sed s/\"responsedata\":\{\"apisessionid\":\"//g | sed 's/\"\}\}//g')
|
||||
_debug "$tmp"
|
||||
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
|
||||
_err "$msg"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
logout() {
|
||||
tmp=$(_post "{\"action\": \"logout\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST")
|
||||
_debug "$tmp"
|
||||
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
|
||||
_err "$msg"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
@@ -13,12 +13,24 @@ dns_nsupdate_add() {
|
||||
_saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}"
|
||||
_saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}"
|
||||
_saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}"
|
||||
_saveaccountconf NSUPDATE_ZONE "${NSUPDATE_ZONE}"
|
||||
_info "adding ${fulldomain}. 60 in txt \"${txtvalue}\""
|
||||
nsupdate -k "${NSUPDATE_KEY}" <<EOF
|
||||
[ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d"
|
||||
[ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D"
|
||||
if [ -z "${NSUPDATE_ZONE}" ]; then
|
||||
nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF
|
||||
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
|
||||
update add ${fulldomain}. 60 in txt "${txtvalue}"
|
||||
send
|
||||
EOF
|
||||
else
|
||||
nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF
|
||||
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
|
||||
zone ${NSUPDATE_ZONE}.
|
||||
update add ${fulldomain}. 60 in txt "${txtvalue}"
|
||||
send
|
||||
EOF
|
||||
fi
|
||||
if [ $? -ne 0 ]; then
|
||||
_err "error updating domain"
|
||||
return 1
|
||||
@@ -34,11 +46,22 @@ dns_nsupdate_rm() {
|
||||
[ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost"
|
||||
[ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53
|
||||
_info "removing ${fulldomain}. txt"
|
||||
nsupdate -k "${NSUPDATE_KEY}" <<EOF
|
||||
[ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d"
|
||||
[ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D"
|
||||
if [ -z "${NSUPDATE_ZONE}" ]; then
|
||||
nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF
|
||||
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
|
||||
update delete ${fulldomain}. txt
|
||||
send
|
||||
EOF
|
||||
else
|
||||
nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF
|
||||
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
|
||||
zone ${NSUPDATE_ZONE}.
|
||||
update delete ${fulldomain}. txt
|
||||
send
|
||||
EOF
|
||||
fi
|
||||
if [ $? -ne 0 ]; then
|
||||
_err "error updating domain"
|
||||
return 1
|
||||
|
||||
164
dnsapi/dns_pointhq.sh
Normal file
164
dnsapi/dns_pointhq.sh
Normal file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#PointHQ_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
#PointHQ_Email="xxxx@sss.com"
|
||||
|
||||
PointHQ_Api="https://api.pointhq.com"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_pointhq_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
PointHQ_Key="${PointHQ_Key:-$(_readaccountconf_mutable PointHQ_Key)}"
|
||||
PointHQ_Email="${PointHQ_Email:-$(_readaccountconf_mutable PointHQ_Email)}"
|
||||
if [ -z "$PointHQ_Key" ] || [ -z "$PointHQ_Email" ]; then
|
||||
PointHQ_Key=""
|
||||
PointHQ_Email=""
|
||||
_err "You didn't specify a PointHQ API key and email yet."
|
||||
_err "Please create the key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$PointHQ_Email" "@"; then
|
||||
_err "It seems that the PointHQ_Email=$PointHQ_Email is not a valid email address."
|
||||
_err "Please check and retry."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable PointHQ_Key "$PointHQ_Key"
|
||||
_saveaccountconf_mutable PointHQ_Email "$PointHQ_Email"
|
||||
|
||||
_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"
|
||||
if _pointhq_rest POST "zones/$_domain/records" "{\"zone_record\": {\"name\":\"$_sub_domain\",\"record_type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":3600}}"; then
|
||||
if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_pointhq_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
PointHQ_Key="${PointHQ_Key:-$(_readaccountconf_mutable PointHQ_Key)}"
|
||||
PointHQ_Email="${PointHQ_Email:-$(_readaccountconf_mutable PointHQ_Email)}"
|
||||
if [ -z "$PointHQ_Key" ] || [ -z "$PointHQ_Email" ]; then
|
||||
PointHQ_Key=""
|
||||
PointHQ_Email=""
|
||||
_err "You didn't specify a PointHQ API key and email yet."
|
||||
_err "Please create the key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_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"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_pointhq_rest GET "zones/${_domain}/records?record_type=TXT&name=$_sub_domain"
|
||||
|
||||
if ! printf "%s" "$response" | grep "^\[" >/dev/null; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$response" = "[]" ]; then
|
||||
_info "No records to remove."
|
||||
else
|
||||
record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | tr -d \" | head -n 1)
|
||||
_debug "record_id" "$record_id"
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
if ! _pointhq_rest DELETE "zones/$_domain/records/$record_id"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
_contains "$response" '"status":"OK"'
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
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 ! _pointhq_rest GET "zones"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$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
|
||||
return 1
|
||||
}
|
||||
|
||||
_pointhq_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
_pointhq_auth=$(printf "%s:%s" "$PointHQ_Email" "$PointHQ_Key" | _base64)
|
||||
|
||||
export _H1="Authorization: Basic $_pointhq_auth"
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H3="Accept: application/json"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$PointHQ_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$PointHQ_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -50,34 +50,16 @@ dns_unoeuro_add() {
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
_info "Adding record"
|
||||
|
||||
if ! _contains "$response" "$_sub_domain" >/dev/null; then
|
||||
_info "Adding record"
|
||||
|
||||
if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then
|
||||
if _contains "$response" "\"status\": 200" >/dev/null; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
else
|
||||
_info "Updating record"
|
||||
record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1)
|
||||
record_line_number=$(_math "$record_line_number" - 1)
|
||||
record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}")
|
||||
_debug "record_id" "$record_id"
|
||||
|
||||
_uno_rest PUT "my/products/$h/dns/records/$record_id" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"
|
||||
if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then
|
||||
if _contains "$response" "\"status\": 200" >/dev/null; then
|
||||
_info "Updated, OK"
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
_err "Update error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -122,23 +104,24 @@ dns_unoeuro_rm() {
|
||||
if ! _contains "$response" "$_sub_domain"; then
|
||||
_info "Don't need to remove."
|
||||
else
|
||||
record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1)
|
||||
record_line_number=$(_math "$record_line_number" - 1)
|
||||
record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}")
|
||||
_debug "record_id" "$record_id"
|
||||
for record_line_number in $(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1); do
|
||||
record_line_number=$(_math "$record_line_number" - 1)
|
||||
_debug "record_line_number" "$record_line_number"
|
||||
record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}")
|
||||
_debug "record_id" "$record_id"
|
||||
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _uno_rest DELETE "my/products/$h/dns/records/$record_id"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
_contains "$response" "\"status\": 200"
|
||||
if ! _uno_rest DELETE "my/products/$h/dns/records/$record_id"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
_contains "$response" "\"status\": 200"
|
||||
done
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
Reference in New Issue
Block a user