mirror of
https://github.com/plantroon/acme.sh.git
synced 2024-11-08 23:41:45 +00:00
Merge branch 'dev' of https://github.com/Neilpang/acme.sh into ssh-deploy
This commit is contained in:
commit
98b8bfb3fa
23
.travis.yml
23
.travis.yml
@ -1,10 +1,14 @@
|
|||||||
language: shell
|
language: shell
|
||||||
sudo: required
|
sudo: required
|
||||||
|
dist: trusty
|
||||||
|
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
- osx
|
- osx
|
||||||
|
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64
|
- SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64
|
||||||
@ -18,21 +22,10 @@ addons:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
- if [ "$TRAVIS_OS_NAME" = 'osx' ]; then
|
- if [ "$TRAVIS_OS_NAME" = 'osx' ]; then
|
||||||
brew update && brew install openssl socat;
|
brew update && brew install socat;
|
||||||
brew info openssl;
|
export PATH="/usr/local/opt/openssl@1.1/bin:$PATH" ;
|
||||||
ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/;
|
|
||||||
ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/;
|
|
||||||
ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl;
|
|
||||||
_old_path="$PATH";
|
|
||||||
echo "PATH=$PATH";
|
|
||||||
export PATH="";
|
|
||||||
export ACME_OPENSSL_BIN="/usr/local/openssl";
|
|
||||||
openssl version 2>&1 || true;
|
|
||||||
$ACME_OPENSSL_BIN version 2>&1 || true;
|
|
||||||
export PATH="$_old_path";
|
|
||||||
else sudo apt-get install socat;
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)"
|
- echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)"
|
||||||
- command -V openssl && openssl version
|
- command -V openssl && openssl version
|
||||||
@ -44,7 +37,7 @@ script:
|
|||||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi
|
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi
|
||||||
- cd ..
|
- cd ..
|
||||||
- git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest
|
- git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest
|
||||||
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi
|
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./rundocker.sh testplat ubuntu:latest ; fi
|
||||||
- if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi
|
- if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM alpine
|
FROM alpine:3.6
|
||||||
|
|
||||||
RUN apk update -f \
|
RUN apk update -f \
|
||||||
&& apk --no-cache add -f \
|
&& apk --no-cache add -f \
|
||||||
|
174
README.md
174
README.md
@ -3,6 +3,8 @@
|
|||||||
[![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
- An ACME protocol client written purely in Shell (Unix shell) language.
|
- An ACME protocol client written purely in Shell (Unix shell) language.
|
||||||
- Full ACME protocol implementation.
|
- Full ACME protocol implementation.
|
||||||
|
- Support ACME v1 and ACME v2
|
||||||
|
- Support ACME v2 wildcard certs
|
||||||
- Simple, powerful and very easy to use. You only need 3 minutes to learn it.
|
- Simple, powerful and very easy to use. You only need 3 minutes to learn it.
|
||||||
- Bash, dash and sh compatible.
|
- Bash, dash and sh compatible.
|
||||||
- Simplest shell script for Let's Encrypt free certificate client.
|
- Simplest shell script for Let's Encrypt free certificate client.
|
||||||
@ -23,7 +25,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
|||||||
|
|
||||||
# [中文说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E)
|
# [中文说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E)
|
||||||
|
|
||||||
# Who are using **acme.sh**
|
# Who:
|
||||||
- [FreeBSD.org](https://blog.crashed.org/letsencrypt-in-freebsd-org/)
|
- [FreeBSD.org](https://blog.crashed.org/letsencrypt-in-freebsd-org/)
|
||||||
- [ruby-china.org](https://ruby-china.org/topics/31983)
|
- [ruby-china.org](https://ruby-china.org/topics/31983)
|
||||||
- [Proxmox](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x_and_newer))
|
- [Proxmox](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x_and_newer))
|
||||||
@ -72,7 +74,7 @@ https://github.com/Neilpang/acmetest
|
|||||||
- Webroot mode
|
- Webroot mode
|
||||||
- Standalone mode
|
- Standalone mode
|
||||||
- Apache mode
|
- Apache mode
|
||||||
- Nginx mode ( Beta )
|
- Nginx mode
|
||||||
- DNS mode
|
- DNS mode
|
||||||
- [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode)
|
- [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode)
|
||||||
|
|
||||||
@ -127,7 +129,7 @@ Ok, you are ready to issue certs now.
|
|||||||
|
|
||||||
Show help message:
|
Show help message:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
root@v1:~# acme.sh -h
|
root@v1:~# acme.sh -h
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -164,16 +166,16 @@ You must have at least one domain there.
|
|||||||
|
|
||||||
You must point and bind all the domains to the same webroot dir: `/home/wwwroot/example.com`.
|
You must point and bind all the domains to the same webroot dir: `/home/wwwroot/example.com`.
|
||||||
|
|
||||||
Generated/issued certs will be placed in `~/.acme.sh/example.com/`
|
The certs will be placed in `~/.acme.sh/example.com/`
|
||||||
|
|
||||||
The issued cert will be renewed automatically every **60** days.
|
The certs will be renewed automatically every **60** days.
|
||||||
|
|
||||||
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
|
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
|
||||||
|
|
||||||
|
|
||||||
# 3. Install the issued cert to Apache/Nginx etc.
|
# 3. Install the cert to Apache/Nginx etc.
|
||||||
|
|
||||||
After you issue a cert, you probably want to install/copy the cert to your Apache/Nginx or other servers.
|
After the cert is generated, you probably want to install/copy the cert to your Apache/Nginx or other servers.
|
||||||
You **MUST** use this command to copy the certs to the target files, **DO NOT** use the certs files in **~/.acme.sh/** folder, they are for internal use only, the folder structure may change in the future.
|
You **MUST** use this command to copy the certs to the target files, **DO NOT** use the certs files in **~/.acme.sh/** folder, they are for internal use only, the folder structure may change in the future.
|
||||||
|
|
||||||
**Apache** example:
|
**Apache** example:
|
||||||
@ -195,13 +197,15 @@ acme.sh --install-cert -d example.com \
|
|||||||
|
|
||||||
Only the domain is required, all the other parameters are optional.
|
Only the domain is required, all the other parameters are optional.
|
||||||
|
|
||||||
The ownership and permission info of existing files are preserved. You may want to precreate the files to have defined ownership and permission.
|
The ownership and permission info of existing files are preserved. You can pre-create the files to define the ownership and permission.
|
||||||
|
|
||||||
Install/copy the issued cert/key to the production Apache or Nginx path.
|
Install/copy the cert/key to the production Apache or Nginx path.
|
||||||
|
|
||||||
The cert will be renewed every **60** days by default (which is configurable). Once the cert is renewed, the Apache/Nginx service will be reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`.
|
The cert will be renewed every **60** days by default (which is configurable). Once the cert is renewed, the Apache/Nginx service will be reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`.
|
||||||
|
|
||||||
|
|
||||||
|
**Please take care: The reloadcmd is very important. The cert can be automatically renewed, but, without a correct 'reloadcmd' the cert may not be flushed to your server(like nginx or apache), then your website will not be able to show renewed cert in 60 days.**
|
||||||
|
|
||||||
# 4. Use Standalone server to issue cert
|
# 4. Use Standalone server to issue cert
|
||||||
|
|
||||||
**(requires you to be root/sudoer or have permission to listen on port 80 (TCP))**
|
**(requires you to be root/sudoer or have permission to listen on port 80 (TCP))**
|
||||||
@ -236,14 +240,18 @@ More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
|
|||||||
|
|
||||||
If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`.
|
If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`.
|
||||||
|
|
||||||
Particularly, if you are running an Apache server, you should use Apache mode instead. This mode doesn't write any files to your web root folder.
|
Particularly, if you are running an Apache server, you can use Apache mode instead. This mode doesn't write any files to your web root folder.
|
||||||
|
|
||||||
Just set string "apache" as the second argument and it will force use of apache plugin automatically.
|
Just set string "apache" as the second argument and it will force use of apache plugin automatically.
|
||||||
|
|
||||||
```
|
```sh
|
||||||
acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com
|
acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**This apache mode is only to issue the cert, it will not change your apache config files.
|
||||||
|
You will need to configure your website config files to use the cert by yourself.
|
||||||
|
We don't want to mess your apache server, don't worry.**
|
||||||
|
|
||||||
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
|
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
|
||||||
|
|
||||||
# 7. Use Nginx mode
|
# 7. Use Nginx mode
|
||||||
@ -260,47 +268,17 @@ It will configure nginx server automatically to verify the domain and then resto
|
|||||||
|
|
||||||
So, the config is not changed.
|
So, the config is not changed.
|
||||||
|
|
||||||
```
|
```sh
|
||||||
acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com
|
acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**This nginx mode is only to issue the cert, it will not change your nginx config files.
|
||||||
|
You will need to configure your website config files to use the cert by yourself.
|
||||||
|
We don't want to mess your nginx server, don't worry.**
|
||||||
|
|
||||||
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
|
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
|
||||||
|
|
||||||
# 8. Use DNS mode:
|
# 8. Automatic DNS API integration
|
||||||
|
|
||||||
Support the `dns-01` challenge.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
acme.sh --issue --dns -d example.com -d www.example.com -d cp.example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
You should get an output like below:
|
|
||||||
|
|
||||||
```
|
|
||||||
Add the following txt record:
|
|
||||||
Domain:_acme-challenge.example.com
|
|
||||||
Txt value:9ihDbjYfTExAYeDs4DBUeuTo18KBzwvTEjUnSwd32-c
|
|
||||||
|
|
||||||
Add the following txt record:
|
|
||||||
Domain:_acme-challenge.www.example.com
|
|
||||||
Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
||||||
|
|
||||||
Please add those txt records to the domains. Waiting for the dns to take effect.
|
|
||||||
```
|
|
||||||
|
|
||||||
Then just rerun with `renew` argument:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
acme.sh --renew -d example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
Ok, it's finished.
|
|
||||||
|
|
||||||
**Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.**
|
|
||||||
|
|
||||||
**Please use dns api mode instead.**
|
|
||||||
|
|
||||||
# 9. Automatic DNS API integration
|
|
||||||
|
|
||||||
If your DNS provider supports API access, we can use that API to automatically issue the certs.
|
If your DNS provider supports API access, we can use that API to automatically issue the certs.
|
||||||
|
|
||||||
@ -339,21 +317,62 @@ You don't have to do anything manually!
|
|||||||
1. Dyn Managed DNS API
|
1. Dyn Managed DNS API
|
||||||
1. Yandex PDD API (https://pdd.yandex.ru)
|
1. Yandex PDD API (https://pdd.yandex.ru)
|
||||||
1. Hurricane Electric DNS service (https://dns.he.net)
|
1. Hurricane Electric DNS service (https://dns.he.net)
|
||||||
|
1. UnoEuro API (https://www.unoeuro.com/)
|
||||||
|
1. INWX (https://www.inwx.de/)
|
||||||
|
1. Servercow (https://servercow.de)
|
||||||
|
1. Namesilo (https://www.namesilo.com)
|
||||||
|
1. InternetX autoDNS API (https://internetx.com)
|
||||||
|
1. Azure DNS
|
||||||
|
1. selectel.com(selectel.ru) DNS API
|
||||||
|
1. zonomi.com DNS API
|
||||||
|
1. DreamHost.com API
|
||||||
|
|
||||||
|
|
||||||
And:
|
And:
|
||||||
|
|
||||||
1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
|
**lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
|
||||||
(DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)
|
(DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)**
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**More APIs coming soon...**
|
**More APIs coming soon...**
|
||||||
|
|
||||||
If your DNS provider is not on the supported list above, you can write your own DNS API script easily. If you do, please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute it to the project.
|
If your DNS provider is not on the supported list above, you can write your own DNS API script easily. If you do, please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute it to the project.
|
||||||
|
|
||||||
For more details: [How to use DNS API](dnsapi)
|
For more details: [How to use DNS API](dnsapi)
|
||||||
|
|
||||||
|
# 9. Use DNS manual mode:
|
||||||
|
|
||||||
|
If your dns provider doesn't support any api access, you can add the txt record by your hand.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
acme.sh --issue --dns -d example.com -d www.example.com -d cp.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
You should get an output like below:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
Add the following txt record:
|
||||||
|
Domain:_acme-challenge.example.com
|
||||||
|
Txt value:9ihDbjYfTExAYeDs4DBUeuTo18KBzwvTEjUnSwd32-c
|
||||||
|
|
||||||
|
Add the following txt record:
|
||||||
|
Domain:_acme-challenge.www.example.com
|
||||||
|
Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
|
||||||
|
Please add those txt records to the domains. Waiting for the dns to take effect.
|
||||||
|
```
|
||||||
|
|
||||||
|
Then just rerun with `renew` argument:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
acme.sh --renew -d example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Ok, it's done.
|
||||||
|
|
||||||
|
**Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.**
|
||||||
|
|
||||||
|
**Please use dns api mode instead.**
|
||||||
|
|
||||||
# 10. Issue ECC certificates
|
# 10. Issue ECC certificates
|
||||||
|
|
||||||
@ -361,7 +380,7 @@ For more details: [How to use DNS API](dnsapi)
|
|||||||
|
|
||||||
And we support them too!
|
And we support them too!
|
||||||
|
|
||||||
Just set the `length` parameter with a prefix `ec-`.
|
Just set the `keylength` parameter with a prefix `ec-`.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
@ -377,7 +396,7 @@ acme.sh --issue -w /home/wwwroot/example.com -d example.com --keylength ec-256
|
|||||||
acme.sh --issue -w /home/wwwroot/example.com -d example.com -d www.example.com --keylength ec-256
|
acme.sh --issue -w /home/wwwroot/example.com -d example.com -d www.example.com --keylength ec-256
|
||||||
```
|
```
|
||||||
|
|
||||||
Please look at the last parameter above.
|
Please look at the `keylength` parameter above.
|
||||||
|
|
||||||
Valid values are:
|
Valid values are:
|
||||||
|
|
||||||
@ -386,36 +405,60 @@ Valid values are:
|
|||||||
3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)**
|
3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)**
|
||||||
|
|
||||||
|
|
||||||
# 11. How to renew the issued certs
|
|
||||||
|
# 11. Issue Wildcard certificates
|
||||||
|
|
||||||
|
It's simple, just give a wildcard domain as the `-d` parameter.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
acme.sh --issue -d example.com -d *.example.com --dns dns_cf
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 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.
|
No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days.
|
||||||
|
|
||||||
However, you can also force to renew any cert:
|
However, you can also force to renew a cert:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
acme.sh --renew -d example.com --force
|
acme.sh --renew -d example.com --force
|
||||||
```
|
```
|
||||||
|
|
||||||
or, for ECC cert:
|
or, for ECC cert:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
acme.sh --renew -d example.com --force --ecc
|
acme.sh --renew -d example.com --force --ecc
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
# 12. How to upgrade `acme.sh`
|
# 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:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
acme.sh --remove -d example.com [--ecc]
|
||||||
|
```
|
||||||
|
|
||||||
|
The cert/key file is not removed from the disk.
|
||||||
|
|
||||||
|
You can remove the respective directory (e.g. `~/.acme.sh/example.com`) by yourself.
|
||||||
|
|
||||||
|
|
||||||
|
# 14. How to upgrade `acme.sh`
|
||||||
|
|
||||||
acme.sh is in constant development, so it's strongly recommended to use the latest code.
|
acme.sh is in constant development, so it's strongly recommended to use the latest code.
|
||||||
|
|
||||||
You can update acme.sh to the latest code:
|
You can update acme.sh to the latest code:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
acme.sh --upgrade
|
acme.sh --upgrade
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also enable auto upgrade:
|
You can also enable auto upgrade:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
acme.sh --upgrade --auto-upgrade
|
acme.sh --upgrade --auto-upgrade
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -423,31 +466,30 @@ Then **acme.sh** will be kept up to date automatically.
|
|||||||
|
|
||||||
Disable auto upgrade:
|
Disable auto upgrade:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
acme.sh --upgrade --auto-upgrade 0
|
acme.sh --upgrade --auto-upgrade 0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
# 13. 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
|
https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR
|
||||||
|
|
||||||
|
|
||||||
# 14. Under the Hood
|
# 16. Under the Hood
|
||||||
|
|
||||||
Speak ACME language using shell, directly to "Let's Encrypt".
|
Speak ACME language using shell, directly to "Let's Encrypt".
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
|
|
||||||
|
|
||||||
# 15. Acknowledgments
|
# 17. Acknowledgments
|
||||||
|
|
||||||
1. Acme-tiny: https://github.com/diafygi/acme-tiny
|
1. Acme-tiny: https://github.com/diafygi/acme-tiny
|
||||||
2. ACME protocol: https://github.com/ietf-wg-acme/acme
|
2. ACME protocol: https://github.com/ietf-wg-acme/acme
|
||||||
3. Certbot: https://github.com/certbot/certbot
|
|
||||||
|
|
||||||
|
|
||||||
# 16. License & Others
|
# 18. License & Others
|
||||||
|
|
||||||
License is GPLv3
|
License is GPLv3
|
||||||
|
|
||||||
@ -456,7 +498,7 @@ Please Star and Fork me.
|
|||||||
[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome.
|
[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome.
|
||||||
|
|
||||||
|
|
||||||
# 17. Donate
|
# 19. Donate
|
||||||
Your donation makes **acme.sh** better:
|
Your donation makes **acme.sh** better:
|
||||||
|
|
||||||
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)
|
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)
|
||||||
|
@ -16,17 +16,40 @@ strongswan_deploy() {
|
|||||||
_cca="$4"
|
_cca="$4"
|
||||||
_cfullchain="$5"
|
_cfullchain="$5"
|
||||||
|
|
||||||
|
_info "Using strongswan"
|
||||||
|
|
||||||
|
if [ -x /usr/sbin/ipsec ]; then
|
||||||
|
_ipsec=/usr/sbin/ipsec
|
||||||
|
elif [ -x /usr/sbin/strongswan ]; then
|
||||||
|
_ipsec=/usr/sbin/strongswan
|
||||||
|
elif [ -x /usr/local/sbin/ipsec ]; then
|
||||||
|
_ipsec=/usr/local/sbin/ipsec
|
||||||
|
else
|
||||||
|
_err "no strongswan or ipsec command is detected"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info _ipsec "$_ipsec"
|
||||||
|
|
||||||
|
_confdir=$($_ipsec --confdir)
|
||||||
|
if [ $? -ne 0 ] || [ -z "$_confdir" ]; then
|
||||||
|
_err "no strongswan --confdir is detected"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info _confdir "$_confdir"
|
||||||
|
|
||||||
_debug _cdomain "$_cdomain"
|
_debug _cdomain "$_cdomain"
|
||||||
_debug _ckey "$_ckey"
|
_debug _ckey "$_ckey"
|
||||||
_debug _ccert "$_ccert"
|
_debug _ccert "$_ccert"
|
||||||
_debug _cca "$_cca"
|
_debug _cca "$_cca"
|
||||||
_debug _cfullchain "$_cfullchain"
|
_debug _cfullchain "$_cfullchain"
|
||||||
|
|
||||||
cat "$_ckey" >"/etc/ipsec.d/private/$(basename "$_ckey")"
|
cat "$_ckey" >"${_confdir}/ipsec.d/private/$(basename "$_ckey")"
|
||||||
cat "$_ccert" >"/etc/ipsec.d/certs/$(basename "$_ccert")"
|
cat "$_ccert" >"${_confdir}/ipsec.d/certs/$(basename "$_ccert")"
|
||||||
cat "$_cca" >"/etc/ipsec.d/cacerts/$(basename "$_cca")"
|
cat "$_cca" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cca")"
|
||||||
cat "$_cfullchain" >"/etc/ipsec.d/cacerts/$(basename "$_cfullchain")"
|
cat "$_cfullchain" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cfullchain")"
|
||||||
|
|
||||||
ipsec reload
|
$_ipsec reload
|
||||||
|
|
||||||
}
|
}
|
||||||
|
56
deploy/vault_cli.sh
Normal file
56
deploy/vault_cli.sh
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
# Here is a script to deploy cert to hashicorp vault
|
||||||
|
# (https://www.vaultproject.io/)
|
||||||
|
#
|
||||||
|
# it requires the vault binary to be available in PATH, and the following
|
||||||
|
# environment variables:
|
||||||
|
#
|
||||||
|
# VAULT_PREFIX - this contains the prefix path in vault
|
||||||
|
# VAULT_ADDR - vault requires this to find your vault server
|
||||||
|
#
|
||||||
|
# additionally, you need to ensure that VAULT_TOKEN is avialable or
|
||||||
|
# `vault auth` has applied the appropriate authorization for the vault binary
|
||||||
|
# to access the vault server
|
||||||
|
|
||||||
|
#returns 0 means success, otherwise error.
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#domain keyfile certfile cafile fullchain
|
||||||
|
vault_cli_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"
|
||||||
|
|
||||||
|
# validate required env vars
|
||||||
|
if [ -z "$VAULT_PREFIX" ]; then
|
||||||
|
_err "VAULT_PREFIX needs to be defined (contains prefix path in vault)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$VAULT_ADDR" ]; then
|
||||||
|
_err "VAULT_ADDR needs to be defined (contains vault connection address)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VAULT_CMD=$(which vault)
|
||||||
|
if [ ! $? ]; then
|
||||||
|
_err "cannot find vault binary!"
|
||||||
|
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}/fullchain.pem" value=@"$_cfullchain" || return 1
|
||||||
|
|
||||||
|
}
|
163
dnsapi/README.md
163
dnsapi/README.md
@ -409,10 +409,13 @@ acme.sh --issue --dns dns_dgon -d example.com -d www.example.com
|
|||||||
|
|
||||||
## 21. Use ClouDNS.net API
|
## 21. Use ClouDNS.net API
|
||||||
|
|
||||||
You need to set the HTTP API user ID and password credentials. See: https://www.cloudns.net/wiki/article/42/
|
You need to set the HTTP API user ID and password credentials. See: https://www.cloudns.net/wiki/article/42/. For security reasons, it's recommended to use a sub user ID that only has access to the necessary zones, as a regular API user has access to your entire account.
|
||||||
|
|
||||||
```
|
```
|
||||||
export CLOUDNS_AUTH_ID=XXXXX
|
# Use this for a sub auth ID
|
||||||
|
export CLOUDNS_SUB_AUTH_ID=XXXXX
|
||||||
|
# Use this for a regular auth ID
|
||||||
|
#export CLOUDNS_AUTH_ID=XXXXX
|
||||||
export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
|
export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -512,7 +515,7 @@ acme.sh --issue --dns dns_nsone -d example.com -d www.example.com
|
|||||||
export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||||
```
|
```
|
||||||
|
|
||||||
Please note that since DuckDNS uses StartSSL as their cert provider, thus
|
Please note that since DuckDNS uses StartSSL as their cert provider, thus
|
||||||
--insecure may need to be used when issuing certs:
|
--insecure may need to be used when issuing certs:
|
||||||
```
|
```
|
||||||
acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org
|
acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org
|
||||||
@ -585,7 +588,7 @@ For issues, please report to https://github.com/non7top/acme.sh/issues.
|
|||||||
|
|
||||||
## 31. Use Hurricane Electric
|
## 31. Use Hurricane Electric
|
||||||
|
|
||||||
Hurricane Electric doesn't have an API so just set your login credentials like so:
|
Hurricane Electric (https://dns.he.net/) doesn't have an API so just set your login credentials like so:
|
||||||
|
|
||||||
```
|
```
|
||||||
export HE_Username="yourusername"
|
export HE_Username="yourusername"
|
||||||
@ -602,6 +605,158 @@ The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/accoun
|
|||||||
|
|
||||||
Please report any issues to https://github.com/angel333/acme.sh or to <me@ondrejsimek.com>.
|
Please report any issues to https://github.com/angel333/acme.sh or to <me@ondrejsimek.com>.
|
||||||
|
|
||||||
|
## 32. Use UnoEuro API to automatically issue cert
|
||||||
|
|
||||||
|
First you need to login to your UnoEuro account to get your API key.
|
||||||
|
|
||||||
|
```
|
||||||
|
export UNO_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||||
|
export UNO_User="UExxxxxx"
|
||||||
|
```
|
||||||
|
|
||||||
|
Ok, let's issue a cert now:
|
||||||
|
```
|
||||||
|
acme.sh --issue --dns dns_unoeuro -d example.com -d www.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
The `UNO_Key` and `UNO_User` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||||
|
|
||||||
|
## 33. Use INWX
|
||||||
|
|
||||||
|
[INWX](https://www.inwx.de/) offers an [xmlrpc api](https://www.inwx.de/de/help/apidoc) with your standard login credentials, set them like so:
|
||||||
|
|
||||||
|
```
|
||||||
|
export INWX_User="yourusername"
|
||||||
|
export INWX_Password="password"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can issue your certificates with:
|
||||||
|
|
||||||
|
```
|
||||||
|
acme.sh --issue --dns dns_inwx -d example.com -d www.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
The `INWX_User` and `INWX_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||||
|
|
||||||
|
## 34. User Servercow API v1
|
||||||
|
|
||||||
|
Create a new user from the servercow control center. Don't forget to activate **DNS API** for this user.
|
||||||
|
|
||||||
|
```
|
||||||
|
export SERVERCOW_API_Username=username
|
||||||
|
export SERVERCOW_API_Password=password
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you cann issue a cert:
|
||||||
|
|
||||||
|
```
|
||||||
|
acme.sh --issue --dns dns_servercow -d example.com -d www.example.com
|
||||||
|
```
|
||||||
|
Both, `SERVERCOW_API_Username` and `SERVERCOW_API_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||||
|
|
||||||
|
## 35. Use Namesilo.com API
|
||||||
|
|
||||||
|
You'll need to generate an API key at https://www.namesilo.com/account_api.php
|
||||||
|
Optionally you may restrict the access to an IP range there.
|
||||||
|
|
||||||
|
```
|
||||||
|
export Namesilo_Key="xxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
```
|
||||||
|
|
||||||
|
And now you can issue certs with:
|
||||||
|
|
||||||
|
```
|
||||||
|
acme.sh --issue --dns dns_namesilo --dnssleep 900 -d example.com -d www.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## 36. Use autoDNS (InternetX)
|
||||||
|
|
||||||
|
[InternetX](https://www.internetx.com/) offers an [xml api](https://help.internetx.com/display/API/AutoDNS+XML-API) with your standard login credentials, set them like so:
|
||||||
|
|
||||||
|
```
|
||||||
|
export AUTODNS_USER="yourusername"
|
||||||
|
export AUTODNS_PASSWORD="password"
|
||||||
|
export AUTODNS_CONTEXT="context"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can issue your certificates with:
|
||||||
|
|
||||||
|
```
|
||||||
|
acme.sh --issue --dns dns_autodns -d example.com -d www.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
The `AUTODNS_USER`, `AUTODNS_PASSWORD` and `AUTODNS_CONTEXT` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||||
|
|
||||||
|
## 37. Use Azure DNS
|
||||||
|
|
||||||
|
You have to create a service principal first. See:[How to use Azure DNS](../../../wiki/How-to-use-Azure-DNS)
|
||||||
|
|
||||||
|
```
|
||||||
|
export AZUREDNS_SUBSCRIPTIONID="12345678-9abc-def0-1234-567890abcdef"
|
||||||
|
export AZUREDNS_TENANTID="11111111-2222-3333-4444-555555555555"
|
||||||
|
export AZUREDNS_APPID="3b5033b5-7a66-43a5-b3b9-a36b9e7c25ed"
|
||||||
|
export AZUREDNS_CLIENTSECRET="1b0224ef-34d4-5af9-110f-77f527d561bd"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can issue your certificates with:
|
||||||
|
|
||||||
|
```
|
||||||
|
acme.sh --issue --dns dns_azure -d example.com -d www.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
`AZUREDNS_SUBSCRIPTIONID`, `AZUREDNS_TENANTID`,`AZUREDNS_APPID` and `AZUREDNS_CLIENTSECRET` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||||
|
|
||||||
|
## 38. Use selectel.com(selectel.ru) domain API to automatically issue cert
|
||||||
|
|
||||||
|
First you need to login to your account to get your API key from: https://my.selectel.ru/profile/apikeys.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
export SL_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Ok, let's issue a cert now:
|
||||||
|
```
|
||||||
|
acme.sh --issue --dns dns_selectel -d example.com -d www.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
The `SL_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||||
|
|
||||||
|
## 39. Use zonomi.com domain API to automatically issue cert
|
||||||
|
|
||||||
|
First you need to login to your account to find your API key from: http://zonomi.com/app/dns/dyndns.jsp
|
||||||
|
|
||||||
|
Your will find your api key in the example urls:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
https://zonomi.com/app/dns/dyndns.jsp?host=example.com&api_key=1063364558943540954358668888888888
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
export ZM_Key="1063364558943540954358668888888888"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Ok, let's issue a cert now:
|
||||||
|
```
|
||||||
|
acme.sh --issue --dns dns_zonomi -d example.com -d www.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ZM_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||||
|
|
||||||
|
## 40. Use DreamHost DNS API
|
||||||
|
|
||||||
|
DNS API keys may be created at https://panel.dreamhost.com/?tree=home.api.
|
||||||
|
Ensure the created key has add and remove privelages.
|
||||||
|
|
||||||
|
```
|
||||||
|
export DH_API_Key="<api key>"
|
||||||
|
acme.sh --issue --dns dns_dreamhost -d example.com -d www.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
The 'DH_API_KEY' will be saved in `~/.acme.sh/account.conf` and will
|
||||||
|
be reused when needed.
|
||||||
|
|
||||||
# Use custom API
|
# Use custom API
|
||||||
|
|
||||||
If your API is not supported yet, you can write your own DNS API.
|
If your API is not supported yet, you can write your own DNS API.
|
||||||
|
@ -10,6 +10,8 @@ dns_ali_add() {
|
|||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
|
Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}"
|
||||||
|
Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}"
|
||||||
if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then
|
if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then
|
||||||
Ali_Key=""
|
Ali_Key=""
|
||||||
Ali_Secret=""
|
Ali_Secret=""
|
||||||
@ -18,8 +20,8 @@ dns_ali_add() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
#save the api key and secret to the account conf file.
|
#save the api key and secret to the account conf file.
|
||||||
_saveaccountconf Ali_Key "$Ali_Key"
|
_saveaccountconf_mutable Ali_Key "$Ali_Key"
|
||||||
_saveaccountconf Ali_Secret "$Ali_Secret"
|
_saveaccountconf_mutable Ali_Secret "$Ali_Secret"
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
@ -32,6 +34,15 @@ dns_ali_add() {
|
|||||||
|
|
||||||
dns_ali_rm() {
|
dns_ali_rm() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}"
|
||||||
|
Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}"
|
||||||
|
|
||||||
|
_debug "First detect the root zone"
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
_clean
|
_clean
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,16 +87,14 @@ _ali_rest() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
_debug2 response "$response"
|
||||||
if [ -z "$2" ]; then
|
if [ -z "$2" ]; then
|
||||||
message="$(printf "%s" "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")"
|
message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")"
|
||||||
if [ -n "$message" ]; then
|
if [ "$message" ]; then
|
||||||
_err "$message"
|
_err "$message"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_debug2 response "$response"
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ali_urlencode() {
|
_ali_urlencode() {
|
||||||
@ -112,12 +121,14 @@ _ali_nonce() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_check_exist_query() {
|
_check_exist_query() {
|
||||||
|
_qdomain="$1"
|
||||||
|
_qsubdomain="$2"
|
||||||
query=''
|
query=''
|
||||||
query=$query'AccessKeyId='$Ali_Key
|
query=$query'AccessKeyId='$Ali_Key
|
||||||
query=$query'&Action=DescribeDomainRecords'
|
query=$query'&Action=DescribeDomainRecords'
|
||||||
query=$query'&DomainName='$1
|
query=$query'&DomainName='$_qdomain
|
||||||
query=$query'&Format=json'
|
query=$query'&Format=json'
|
||||||
query=$query'&RRKeyWord=_acme-challenge'
|
query=$query'&RRKeyWord='$_qsubdomain
|
||||||
query=$query'&SignatureMethod=HMAC-SHA1'
|
query=$query'&SignatureMethod=HMAC-SHA1'
|
||||||
query=$query"&SignatureNonce=$(_ali_nonce)"
|
query=$query"&SignatureNonce=$(_ali_nonce)"
|
||||||
query=$query'&SignatureVersion=1.0'
|
query=$query'&SignatureVersion=1.0'
|
||||||
@ -169,17 +180,21 @@ _describe_records_query() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_clean() {
|
_clean() {
|
||||||
_check_exist_query "$_domain"
|
_check_exist_query "$_domain" "$_sub_domain"
|
||||||
if ! _ali_rest "Check exist records" "ignore"; then
|
if ! _ali_rest "Check exist records" "ignore"; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
records="$(echo "$response" -n | _egrep_o "\"RecordId\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")"
|
record_id="$(echo "$response" | tr '{' "\n" | grep "$_sub_domain" | grep "$txtvalue" | tr "," "\n" | grep RecordId | cut -d '"' -f 4)"
|
||||||
printf "%s" "$records" \
|
_debug2 record_id "$record_id"
|
||||||
| while read -r record_id; do
|
|
||||||
_delete_record_query "$record_id"
|
if [ -z "$record_id" ]; then
|
||||||
_ali_rest "Delete record $record_id" "ignore"
|
_debug "record not found, skip"
|
||||||
done
|
else
|
||||||
|
_delete_record_query "$record_id"
|
||||||
|
_ali_rest "Delete record $record_id" "ignore"
|
||||||
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_timestamp() {
|
_timestamp() {
|
||||||
|
264
dnsapi/dns_autodns.sh
Normal file
264
dnsapi/dns_autodns.sh
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
|
||||||
|
|
||||||
|
# This is the InternetX autoDNS xml api wrapper for acme.sh
|
||||||
|
# Author: auerswald@gmail.com
|
||||||
|
# Created: 2018-01-14
|
||||||
|
#
|
||||||
|
# export AUTODNS_USER="username"
|
||||||
|
# export AUTODNS_PASSWORD="password"
|
||||||
|
# export AUTODNS_CONTEXT="context"
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# acme.sh --issue --dns dns_autodns -d example.com
|
||||||
|
|
||||||
|
AUTODNS_API="https://gateway.autodns.com"
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
# txtdomain
|
||||||
|
# txt
|
||||||
|
dns_autodns_add() {
|
||||||
|
fulldomain="$1"
|
||||||
|
txtvalue="$2"
|
||||||
|
|
||||||
|
AUTODNS_USER="${AUTODNS_USER:-$(_readaccountconf_mutable AUTODNS_USER)}"
|
||||||
|
AUTODNS_PASSWORD="${AUTODNS_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}"
|
||||||
|
AUTODNS_CONTEXT="${AUTODNS_CONTEXT:-$(_readaccountconf_mutable AUTODNS_CONTEXT)}"
|
||||||
|
|
||||||
|
if [ -z "$AUTODNS_USER" ] || [ -z "$AUTODNS_CONTEXT" ] || [ -z "$AUTODNS_PASSWORD" ]; then
|
||||||
|
_err "You don't specify autodns user, password and context."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_saveaccountconf_mutable AUTODNS_USER "$AUTODNS_USER"
|
||||||
|
_saveaccountconf_mutable AUTODNS_PASSWORD "$AUTODNS_PASSWORD"
|
||||||
|
_saveaccountconf_mutable AUTODNS_CONTEXT "$AUTODNS_CONTEXT"
|
||||||
|
|
||||||
|
_debug "First detect the root zone"
|
||||||
|
|
||||||
|
if ! _get_autodns_zone "$fulldomain"; then
|
||||||
|
_err "invalid domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _zone "$_zone"
|
||||||
|
_debug _system_ns "$_system_ns"
|
||||||
|
|
||||||
|
_info "Adding TXT record"
|
||||||
|
|
||||||
|
autodns_response="$(_autodns_zone_update "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")"
|
||||||
|
|
||||||
|
if [ "$?" -eq "0" ]; then
|
||||||
|
_info "Added, OK"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
# txtdomain
|
||||||
|
# txt
|
||||||
|
dns_autodns_rm() {
|
||||||
|
fulldomain="$1"
|
||||||
|
txtvalue="$2"
|
||||||
|
|
||||||
|
AUTODNS_USER="${AUTODNS_USER:-$(_readaccountconf_mutable AUTODNS_USER)}"
|
||||||
|
AUTODNS_PASSWORD="${AUTODNS_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}"
|
||||||
|
AUTODNS_CONTEXT="${AUTODNS_CONTEXT:-$(_readaccountconf_mutable AUTODNS_CONTEXT)}"
|
||||||
|
|
||||||
|
if [ -z "$AUTODNS_USER" ] || [ -z "$AUTODNS_CONTEXT" ] || [ -z "$AUTODNS_PASSWORD" ]; then
|
||||||
|
_err "You don't specify autodns user, password and context."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug "First detect the root zone"
|
||||||
|
|
||||||
|
if ! _get_autodns_zone "$fulldomain"; then
|
||||||
|
_err "zone not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _zone "$_zone"
|
||||||
|
_debug _system_ns "$_system_ns"
|
||||||
|
|
||||||
|
_info "Delete TXT record"
|
||||||
|
|
||||||
|
autodns_response="$(_autodns_zone_cleanup "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")"
|
||||||
|
|
||||||
|
if [ "$?" -eq "0" ]; then
|
||||||
|
_info "Deleted, OK"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
# fulldomain
|
||||||
|
# Returns:
|
||||||
|
# _sub_domain=_acme-challenge.www
|
||||||
|
# _zone=domain.com
|
||||||
|
# _system_ns
|
||||||
|
_get_autodns_zone() {
|
||||||
|
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
|
||||||
|
|
||||||
|
autodns_response="$(_autodns_zone_inquire "$h")"
|
||||||
|
|
||||||
|
if [ "$?" -ne "0" ]; then
|
||||||
|
_err "invalid domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$autodns_response" "<summary>1</summary>" >/dev/null; then
|
||||||
|
_zone="$(echo "$autodns_response" | _egrep_o '<name>[^<]*</name>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||||
|
_system_ns="$(echo "$autodns_response" | _egrep_o '<system_ns>[^<]*</system_ns>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
p=$i
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_build_request_auth_xml() {
|
||||||
|
printf "<auth>
|
||||||
|
<user>%s</user>
|
||||||
|
<password>%s</password>
|
||||||
|
<context>%s</context>
|
||||||
|
</auth>" "$AUTODNS_USER" "$AUTODNS_PASSWORD" "$AUTODNS_CONTEXT"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
# zone
|
||||||
|
_build_zone_inquire_xml() {
|
||||||
|
printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
||||||
|
<request>
|
||||||
|
%s
|
||||||
|
<task>
|
||||||
|
<code>0205</code>
|
||||||
|
<view>
|
||||||
|
<children>1</children>
|
||||||
|
<limit>1</limit>
|
||||||
|
</view>
|
||||||
|
<where>
|
||||||
|
<key>name</key>
|
||||||
|
<operator>eq</operator>
|
||||||
|
<value>%s</value>
|
||||||
|
</where>
|
||||||
|
</task>
|
||||||
|
</request>" "$(_build_request_auth_xml)" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
# zone
|
||||||
|
# subdomain
|
||||||
|
# txtvalue
|
||||||
|
# system_ns
|
||||||
|
_build_zone_update_xml() {
|
||||||
|
printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
||||||
|
<request>
|
||||||
|
%s
|
||||||
|
<task>
|
||||||
|
<code>0202001</code>
|
||||||
|
<default>
|
||||||
|
<rr_add>
|
||||||
|
<name>%s</name>
|
||||||
|
<ttl>600</ttl>
|
||||||
|
<type>TXT</type>
|
||||||
|
<value>%s</value>
|
||||||
|
</rr_add>
|
||||||
|
</default>
|
||||||
|
<zone>
|
||||||
|
<name>%s</name>
|
||||||
|
<system_ns>%s</system_ns>
|
||||||
|
</zone>
|
||||||
|
</task>
|
||||||
|
</request>" "$(_build_request_auth_xml)" "$2" "$3" "$1" "$4"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
# zone
|
||||||
|
_autodns_zone_inquire() {
|
||||||
|
request_data="$(_build_zone_inquire_xml "$1")"
|
||||||
|
autodns_response="$(_autodns_api_call "$request_data")"
|
||||||
|
ret="$?"
|
||||||
|
|
||||||
|
printf "%s" "$autodns_response"
|
||||||
|
return "$ret"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
# zone
|
||||||
|
# subdomain
|
||||||
|
# txtvalue
|
||||||
|
# system_ns
|
||||||
|
_autodns_zone_update() {
|
||||||
|
request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")"
|
||||||
|
autodns_response="$(_autodns_api_call "$request_data")"
|
||||||
|
ret="$?"
|
||||||
|
|
||||||
|
printf "%s" "$autodns_response"
|
||||||
|
return "$ret"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
# zone
|
||||||
|
# subdomain
|
||||||
|
# txtvalue
|
||||||
|
# system_ns
|
||||||
|
_autodns_zone_cleanup() {
|
||||||
|
request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")"
|
||||||
|
# replace 'rr_add>' with 'rr_rem>' in request_data
|
||||||
|
request_data="$(printf -- "%s" "$request_data" | sed 's/rr_add>/rr_rem>/g')"
|
||||||
|
autodns_response="$(_autodns_api_call "$request_data")"
|
||||||
|
ret="$?"
|
||||||
|
|
||||||
|
printf "%s" "$autodns_response"
|
||||||
|
return "$ret"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
# request_data
|
||||||
|
_autodns_api_call() {
|
||||||
|
request_data="$1"
|
||||||
|
|
||||||
|
_debug request_data "$request_data"
|
||||||
|
|
||||||
|
autodns_response="$(_post "$request_data" "$AUTODNS_API")"
|
||||||
|
ret="$?"
|
||||||
|
|
||||||
|
_debug autodns_response "$autodns_response"
|
||||||
|
|
||||||
|
if [ "$ret" -ne "0" ]; then
|
||||||
|
_err "error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$autodns_response" "<type>success</type>" >/dev/null; then
|
||||||
|
_info "success"
|
||||||
|
printf "%s" "$autodns_response"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
@ -19,17 +19,25 @@ dns_aws_add() {
|
|||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}"
|
||||||
|
AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}"
|
||||||
|
|
||||||
|
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
|
||||||
|
_use_instance_role
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
|
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
|
||||||
AWS_ACCESS_KEY_ID=""
|
AWS_ACCESS_KEY_ID=""
|
||||||
AWS_SECRET_ACCESS_KEY=""
|
AWS_SECRET_ACCESS_KEY=""
|
||||||
_err "You don't specify aws route53 api key id and and api key secret yet."
|
_err "You don't specify aws route53 api key id and and api key secret yet."
|
||||||
_err "Please create you key and try again. see $(__green $AWS_WIKI)"
|
_err "Please create your key and try again. see $(__green $AWS_WIKI)"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$AWS_SESSION_TOKEN" ]; then
|
#save for future use, unless using a role which will be fetched as needed
|
||||||
_saveaccountconf AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID"
|
if [ -z "$_using_role" ]; then
|
||||||
_saveaccountconf AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY"
|
_saveaccountconf_mutable AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID"
|
||||||
|
_saveaccountconf_mutable AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
@ -41,7 +49,26 @@ dns_aws_add() {
|
|||||||
_debug _sub_domain "$_sub_domain"
|
_debug _sub_domain "$_sub_domain"
|
||||||
_debug _domain "$_domain"
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
_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><ResourceRecord><Value>\"$txtvalue\"</Value></ResourceRecord></ResourceRecords></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
|
_info "Geting existing records for $fulldomain"
|
||||||
|
if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$response" "<Name>$fulldomain.</Name>"; then
|
||||||
|
_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 "single new add"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$_resource_record" ] && _contains "$response" "$txtvalue"; then
|
||||||
|
_info "The txt record already exists, skip"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug "Adding records"
|
||||||
|
|
||||||
|
_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
|
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 success."
|
||||||
@ -56,6 +83,13 @@ dns_aws_rm() {
|
|||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}"
|
||||||
|
AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}"
|
||||||
|
|
||||||
|
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
|
||||||
|
_use_instance_role
|
||||||
|
fi
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
_err "invalid domain"
|
_err "invalid domain"
|
||||||
@ -65,7 +99,20 @@ dns_aws_rm() {
|
|||||||
_debug _sub_domain "$_sub_domain"
|
_debug _sub_domain "$_sub_domain"
|
||||||
_debug _domain "$_domain"
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
_aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>DELETE</Action><ResourceRecordSet><ResourceRecords><ResourceRecord><Value>\"$txtvalue\"</Value></ResourceRecord></ResourceRecords><Name>$fulldomain.</Name><Type>TXT</Type><TTL>300</TTL></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
|
_info "Geting existing records for $fulldomain"
|
||||||
|
if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$response" "<Name>$fulldomain.</Name>"; then
|
||||||
|
_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"
|
||||||
|
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
|
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 success."
|
||||||
@ -84,7 +131,6 @@ _get_root() {
|
|||||||
p=1
|
p=1
|
||||||
|
|
||||||
if aws_rest GET "2013-04-01/hostedzone"; then
|
if aws_rest GET "2013-04-01/hostedzone"; then
|
||||||
_debug "response" "$response"
|
|
||||||
while true; do
|
while true; do
|
||||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
_debug2 "Checking domain: $h"
|
_debug2 "Checking domain: $h"
|
||||||
@ -128,6 +174,37 @@ _get_root() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_use_instance_role() {
|
||||||
|
_url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
||||||
|
_debug "_url" "$_url"
|
||||||
|
if ! _get "$_url" true 1 | _head_n 1 | grep -Fq 200; then
|
||||||
|
_err "Unable to fetch IAM role from AWS instance metadata."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
_aws_role=$(_get "$_url" "" 1)
|
||||||
|
_debug "_aws_role" "$_aws_role"
|
||||||
|
_aws_creds="$(
|
||||||
|
_get "$_url$_aws_role" "" 1 \
|
||||||
|
| _normalizeJson \
|
||||||
|
| tr '{,}' '\n' \
|
||||||
|
| while read -r _line; do
|
||||||
|
_key="$(echo "${_line%%:*}" | tr -d '"')"
|
||||||
|
_value="${_line#*:}"
|
||||||
|
_debug3 "_key" "$_key"
|
||||||
|
_secure_debug3 "_value" "$_value"
|
||||||
|
case "$_key" in
|
||||||
|
AccessKeyId) echo "AWS_ACCESS_KEY_ID=$_value" ;;
|
||||||
|
SecretAccessKey) echo "AWS_SECRET_ACCESS_KEY=$_value" ;;
|
||||||
|
Token) echo "AWS_SESSION_TOKEN=$_value" ;;
|
||||||
|
esac
|
||||||
|
done \
|
||||||
|
| paste -sd' ' -
|
||||||
|
)"
|
||||||
|
_secure_debug "_aws_creds" "$_aws_creds"
|
||||||
|
eval "$_aws_creds"
|
||||||
|
_using_role=true
|
||||||
|
}
|
||||||
|
|
||||||
#method uri qstr data
|
#method uri qstr data
|
||||||
aws_rest() {
|
aws_rest() {
|
||||||
mtd="$1"
|
mtd="$1"
|
||||||
@ -233,6 +310,7 @@ aws_rest() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
_ret="$?"
|
_ret="$?"
|
||||||
|
_debug2 response "$response"
|
||||||
if [ "$_ret" = "0" ]; then
|
if [ "$_ret" = "0" ]; then
|
||||||
if _contains "$response" "<ErrorResponse"; then
|
if _contains "$response" "<ErrorResponse"; then
|
||||||
_err "Response error:$response"
|
_err "Response error:$response"
|
||||||
|
249
dnsapi/dns_azure.sh
Normal file
249
dnsapi/dns_azure.sh
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
# Used to add txt record
|
||||||
|
#
|
||||||
|
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate
|
||||||
|
#
|
||||||
|
dns_azure_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}"
|
||||||
|
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
||||||
|
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
||||||
|
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
||||||
|
|
||||||
|
if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then
|
||||||
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
|
AZUREDNS_TENANTID=""
|
||||||
|
AZUREDNS_APPID=""
|
||||||
|
AZUREDNS_CLIENTSECRET=""
|
||||||
|
_err "You didn't specify the Azure Subscription ID "
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||||
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
|
AZUREDNS_TENANTID=""
|
||||||
|
AZUREDNS_APPID=""
|
||||||
|
AZUREDNS_CLIENTSECRET=""
|
||||||
|
_err "You didn't specify the Azure Tenant ID "
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$AZUREDNS_APPID" ]; then
|
||||||
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
|
AZUREDNS_TENANTID=""
|
||||||
|
AZUREDNS_APPID=""
|
||||||
|
AZUREDNS_CLIENTSECRET=""
|
||||||
|
_err "You didn't specify the Azure App ID"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
|
||||||
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
|
AZUREDNS_TENANTID=""
|
||||||
|
AZUREDNS_APPID=""
|
||||||
|
AZUREDNS_CLIENTSECRET=""
|
||||||
|
_err "You didn't specify the Azure Client Secret"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
#save account details to account conf file.
|
||||||
|
_saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID"
|
||||||
|
_saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID"
|
||||||
|
_saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID"
|
||||||
|
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET"
|
||||||
|
|
||||||
|
accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||||
|
|
||||||
|
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
|
||||||
|
_err "invalid domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01"
|
||||||
|
_debug "$acmeRecordURI"
|
||||||
|
body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}"
|
||||||
|
_azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken"
|
||||||
|
if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then
|
||||||
|
_info "validation record added"
|
||||||
|
else
|
||||||
|
_err "error adding validation record ($_code)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Usage: fulldomain txtvalue
|
||||||
|
# Used to remove the txt record after validation
|
||||||
|
#
|
||||||
|
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/delete
|
||||||
|
#
|
||||||
|
dns_azure_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}"
|
||||||
|
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
||||||
|
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
||||||
|
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
||||||
|
|
||||||
|
if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then
|
||||||
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
|
AZUREDNS_TENANTID=""
|
||||||
|
AZUREDNS_APPID=""
|
||||||
|
AZUREDNS_CLIENTSECRET=""
|
||||||
|
_err "You didn't specify the Azure Subscription ID "
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||||
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
|
AZUREDNS_TENANTID=""
|
||||||
|
AZUREDNS_APPID=""
|
||||||
|
AZUREDNS_CLIENTSECRET=""
|
||||||
|
_err "You didn't specify the Azure Tenant ID "
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$AZUREDNS_APPID" ]; then
|
||||||
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
|
AZUREDNS_TENANTID=""
|
||||||
|
AZUREDNS_APPID=""
|
||||||
|
AZUREDNS_CLIENTSECRET=""
|
||||||
|
_err "You didn't specify the Azure App ID"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
|
||||||
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
|
AZUREDNS_TENANTID=""
|
||||||
|
AZUREDNS_APPID=""
|
||||||
|
AZUREDNS_CLIENTSECRET=""
|
||||||
|
_err "You didn't specify the Azure Client Secret"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||||
|
|
||||||
|
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
|
||||||
|
_err "invalid domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01"
|
||||||
|
_debug "$acmeRecordURI"
|
||||||
|
body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}"
|
||||||
|
_azure_rest DELETE "$acmeRecordURI" "" "$accesstoken"
|
||||||
|
if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then
|
||||||
|
_info "validation record removed"
|
||||||
|
else
|
||||||
|
_err "error removing validation record ($_code)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
################### Private functions below ##################################
|
||||||
|
|
||||||
|
_azure_rest() {
|
||||||
|
m=$1
|
||||||
|
ep="$2"
|
||||||
|
data="$3"
|
||||||
|
accesstoken="$4"
|
||||||
|
|
||||||
|
export _H1="authorization: Bearer $accesstoken"
|
||||||
|
export _H2="accept: application/json"
|
||||||
|
export _H3="Content-Type: application/json"
|
||||||
|
|
||||||
|
_debug "$ep"
|
||||||
|
if [ "$m" != "GET" ]; then
|
||||||
|
_debug data "$data"
|
||||||
|
response="$(_post "$data" "$ep" "" "$m")"
|
||||||
|
else
|
||||||
|
response="$(_get "$ep")"
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
|
||||||
|
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")"
|
||||||
|
_debug2 "http response code $_code"
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error $ep"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token
|
||||||
|
_azure_getaccess_token() {
|
||||||
|
TENANTID=$1
|
||||||
|
clientID=$2
|
||||||
|
clientSecret=$3
|
||||||
|
|
||||||
|
export _H1="accept: application/json"
|
||||||
|
export _H2="Content-Type: application/x-www-form-urlencoded"
|
||||||
|
|
||||||
|
body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
|
||||||
|
_debug data "$body"
|
||||||
|
response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST")"
|
||||||
|
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||||
|
_debug2 "response $response"
|
||||||
|
|
||||||
|
if [ -z "$accesstoken" ]; then
|
||||||
|
_err "no acccess token received"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error $response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
printf "%s" "$accesstoken"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_root() {
|
||||||
|
domain=$1
|
||||||
|
subscriptionId=$2
|
||||||
|
accesstoken=$3
|
||||||
|
i=2
|
||||||
|
p=1
|
||||||
|
|
||||||
|
## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list
|
||||||
|
## returns up to 100 zones in one response therefore handling more results is not not implemented
|
||||||
|
## (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"
|
||||||
|
|
||||||
|
# Find matching domain name is Json response
|
||||||
|
while true; do
|
||||||
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
|
_debug2 "Checking domain: $h"
|
||||||
|
if [ -z "$h" ]; then
|
||||||
|
#not valid
|
||||||
|
_err "Invalid domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||||
|
_domain_id=$(echo "$response" | _egrep_o "\{\"id\":\"[^\"]*$h\"" | head -n 1 | cut -d : -f 2 | tr -d \")
|
||||||
|
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
|
||||||
|
}
|
@ -51,33 +51,36 @@ dns_cf_add() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
|
# For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so
|
||||||
_debug count "$count"
|
# we can not use updating anymore.
|
||||||
if [ "$count" = "0" ]; then
|
# count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
|
||||||
_info "Adding record"
|
# _debug count "$count"
|
||||||
if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
|
# if [ "$count" = "0" ]; then
|
||||||
if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then
|
_info "Adding record"
|
||||||
_info "Added, OK"
|
if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
|
||||||
return 0
|
if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then
|
||||||
else
|
_info "Added, OK"
|
||||||
_err "Add txt record error."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
_err "Add txt record error."
|
|
||||||
else
|
|
||||||
_info "Updating record"
|
|
||||||
record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1)
|
|
||||||
_debug "record_id" "$record_id"
|
|
||||||
|
|
||||||
_cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}"
|
|
||||||
if [ "$?" = "0" ]; then
|
|
||||||
_info "Updated, OK"
|
|
||||||
return 0
|
return 0
|
||||||
|
else
|
||||||
|
_err "Add txt record error."
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
_err "Update error"
|
|
||||||
return 1
|
|
||||||
fi
|
fi
|
||||||
|
_err "Add txt record error."
|
||||||
|
return 1
|
||||||
|
# else
|
||||||
|
# _info "Updating record"
|
||||||
|
# record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1)
|
||||||
|
# _debug "record_id" "$record_id"
|
||||||
|
#
|
||||||
|
# _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}"
|
||||||
|
# if [ "$?" = "0" ]; then
|
||||||
|
# _info "Updated, OK"
|
||||||
|
# return 0
|
||||||
|
# fi
|
||||||
|
# _err "Update error"
|
||||||
|
# return 1
|
||||||
|
# fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
# Repository: https://github.com/ClouDNS/acme.sh/
|
# Repository: https://github.com/ClouDNS/acme.sh/
|
||||||
|
|
||||||
#CLOUDNS_AUTH_ID=XXXXX
|
#CLOUDNS_AUTH_ID=XXXXX
|
||||||
|
#CLOUDNS_SUB_AUTH_ID=XXXXX
|
||||||
#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
|
#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
|
||||||
CLOUDNS_API="https://api.cloudns.net"
|
CLOUDNS_API="https://api.cloudns.net"
|
||||||
|
|
||||||
@ -97,17 +98,19 @@ _dns_cloudns_init_check() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}"
|
CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}"
|
||||||
|
CLOUDNS_SUB_AUTH_ID="${CLOUDNS_SUB_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_SUB_AUTH_ID)}"
|
||||||
CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}"
|
CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}"
|
||||||
if [ -z "$CLOUDNS_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then
|
if [ -z "$CLOUDNS_AUTH_ID$CLOUDNS_SUB_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then
|
||||||
CLOUDNS_AUTH_ID=""
|
CLOUDNS_AUTH_ID=""
|
||||||
|
CLOUDNS_SUB_AUTH_ID=""
|
||||||
CLOUDNS_AUTH_PASSWORD=""
|
CLOUDNS_AUTH_PASSWORD=""
|
||||||
_err "You don't specify cloudns api id and password yet."
|
_err "You don't specify cloudns api id and password yet."
|
||||||
_err "Please create you id and password and try again."
|
_err "Please create you id and password and try again."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$CLOUDNS_AUTH_ID" ]; then
|
if [ -z "$CLOUDNS_AUTH_ID" ] && [ -z "$CLOUDNS_SUB_AUTH_ID" ]; then
|
||||||
_err "CLOUDNS_AUTH_ID is not configured"
|
_err "CLOUDNS_AUTH_ID or CLOUDNS_SUB_AUTH_ID is not configured"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -125,6 +128,7 @@ _dns_cloudns_init_check() {
|
|||||||
|
|
||||||
#save the api id and password to the account conf file.
|
#save the api id and password to the account conf file.
|
||||||
_saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID"
|
_saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID"
|
||||||
|
_saveaccountconf_mutable CLOUDNS_SUB_AUTH_ID "$CLOUDNS_SUB_AUTH_ID"
|
||||||
_saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD"
|
_saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD"
|
||||||
|
|
||||||
CLOUDNS_INIT_CHECK_COMPLETED=1
|
CLOUDNS_INIT_CHECK_COMPLETED=1
|
||||||
@ -168,12 +172,19 @@ _dns_cloudns_http_api_call() {
|
|||||||
method=$1
|
method=$1
|
||||||
|
|
||||||
_debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID"
|
_debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID"
|
||||||
|
_debug CLOUDNS_SUB_AUTH_ID "$CLOUDNS_SUB_AUTH_ID"
|
||||||
_debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD"
|
_debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD"
|
||||||
|
|
||||||
if [ -z "$2" ]; then
|
if [ ! -z "$CLOUDNS_SUB_AUTH_ID" ]; then
|
||||||
data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD"
|
auth_user="sub-auth-id=$CLOUDNS_SUB_AUTH_ID"
|
||||||
else
|
else
|
||||||
data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2"
|
auth_user="auth-id=$CLOUDNS_AUTH_ID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
data="$auth_user&auth-password=$CLOUDNS_AUTH_PASSWORD"
|
||||||
|
else
|
||||||
|
data="$auth_user&auth-password=$CLOUDNS_AUTH_PASSWORD&$2"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
response="$(_get "$CLOUDNS_API/$method?$data")"
|
response="$(_get "$CLOUDNS_API/$method?$data")"
|
||||||
|
@ -36,33 +36,18 @@ dns_cx_add() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
existing_records "$_domain" "$_sub_domain"
|
add_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||||
_debug count "$count"
|
|
||||||
if [ "$?" != "0" ]; then
|
|
||||||
_err "Error get existing records."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$count" = "0" ]; then
|
|
||||||
add_record "$_domain" "$_sub_domain" "$txtvalue"
|
|
||||||
else
|
|
||||||
update_record "$_domain" "$_sub_domain" "$txtvalue"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$?" = "0" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#fulldomain
|
#fulldomain txtvalue
|
||||||
dns_cx_rm() {
|
dns_cx_rm() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
REST_API="$CX_Api"
|
REST_API="$CX_Api"
|
||||||
if _get_root "$fulldomain"; then
|
if _get_root "$fulldomain"; then
|
||||||
record_id=""
|
record_id=""
|
||||||
existing_records "$_domain" "$_sub_domain"
|
existing_records "$_domain" "$_sub_domain" "$txtvalue"
|
||||||
if ! [ "$record_id" = "" ]; then
|
if [ "$record_id" ]; then
|
||||||
_rest DELETE "record/$record_id/$_domain_id" "{}"
|
_rest DELETE "record/$record_id/$_domain_id" "{}"
|
||||||
_info "Deleted record ${fulldomain}"
|
_info "Deleted record ${fulldomain}"
|
||||||
fi
|
fi
|
||||||
@ -77,7 +62,6 @@ existing_records() {
|
|||||||
_debug "Getting txt records"
|
_debug "Getting txt records"
|
||||||
root=$1
|
root=$1
|
||||||
sub=$2
|
sub=$2
|
||||||
count=0
|
|
||||||
if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then
|
if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@ -89,7 +73,6 @@ existing_records() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then
|
if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then
|
||||||
count=1
|
|
||||||
record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1)
|
record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1)
|
||||||
_debug record_id "$record_id"
|
_debug record_id "$record_id"
|
||||||
return 0
|
return 0
|
||||||
@ -114,23 +97,6 @@ add_record() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#update the txt record
|
|
||||||
#Usage: root sub txtvalue
|
|
||||||
update_record() {
|
|
||||||
root=$1
|
|
||||||
sub=$2
|
|
||||||
txtvalue=$3
|
|
||||||
fulldomain="$sub.$root"
|
|
||||||
|
|
||||||
_info "Updating record"
|
|
||||||
|
|
||||||
if _rest PUT "record/$record_id" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
#################### Private functions below ##################################
|
||||||
#_acme-challenge.www.domain.com
|
#_acme-challenge.www.domain.com
|
||||||
#returns
|
#returns
|
||||||
|
@ -15,6 +15,8 @@ dns_dp_add() {
|
|||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
|
DP_Id="${DP_Id:-$(_readaccountconf_mutable DP_Id)}"
|
||||||
|
DP_Key="${DP_Key:-$(_readaccountconf_mutable DP_Key)}"
|
||||||
if [ -z "$DP_Id" ] || [ -z "$DP_Key" ]; then
|
if [ -z "$DP_Id" ] || [ -z "$DP_Key" ]; then
|
||||||
DP_Id=""
|
DP_Id=""
|
||||||
DP_Key=""
|
DP_Key=""
|
||||||
@ -24,8 +26,8 @@ dns_dp_add() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
#save the api key and email to the account conf file.
|
#save the api key and email to the account conf file.
|
||||||
_saveaccountconf DP_Id "$DP_Id"
|
_saveaccountconf_mutable DP_Id "$DP_Id"
|
||||||
_saveaccountconf DP_Key "$DP_Key"
|
_saveaccountconf_mutable DP_Key "$DP_Key"
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
@ -33,24 +35,18 @@ dns_dp_add() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
existing_records "$_domain" "$_sub_domain"
|
add_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||||
_debug count "$count"
|
|
||||||
if [ "$?" != "0" ]; then
|
|
||||||
_err "Error get existing records."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$count" = "0" ]; then
|
|
||||||
add_record "$_domain" "$_sub_domain" "$txtvalue"
|
|
||||||
else
|
|
||||||
update_record "$_domain" "$_sub_domain" "$txtvalue"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#fulldomain txtvalue
|
#fulldomain txtvalue
|
||||||
dns_dp_rm() {
|
dns_dp_rm() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
|
DP_Id="${DP_Id:-$(_readaccountconf_mutable DP_Id)}"
|
||||||
|
DP_Key="${DP_Key:-$(_readaccountconf_mutable DP_Key)}"
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
_err "invalid domain"
|
_err "invalid domain"
|
||||||
@ -83,37 +79,6 @@ dns_dp_rm() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#usage: root sub
|
|
||||||
#return if the sub record already exists.
|
|
||||||
#echos the existing records count.
|
|
||||||
# '0' means doesn't exist
|
|
||||||
existing_records() {
|
|
||||||
_debug "Getting txt records"
|
|
||||||
root=$1
|
|
||||||
sub=$2
|
|
||||||
|
|
||||||
if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&domain_id=$_domain_id&sub_domain=$_sub_domain"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if _contains "$response" 'No records'; then
|
|
||||||
count=0
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if _contains "$response" "Action completed successful"; then
|
|
||||||
count=$(printf "%s" "$response" | grep -c '<type>TXT</type>' | tr -d ' ')
|
|
||||||
record_id=$(printf "%s" "$response" | grep '^<id>' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1)
|
|
||||||
_debug record_id "$record_id"
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
_err "get existing records error."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
count=0
|
|
||||||
}
|
|
||||||
|
|
||||||
#add the txt record.
|
#add the txt record.
|
||||||
#usage: root sub txtvalue
|
#usage: root sub txtvalue
|
||||||
add_record() {
|
add_record() {
|
||||||
@ -128,34 +93,7 @@ add_record() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if _contains "$response" "Action completed successful"; then
|
_contains "$response" "Action completed successful" || _contains "$response" "Domain record already exists"
|
||||||
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 1 #error
|
|
||||||
}
|
|
||||||
|
|
||||||
#update the txt record
|
|
||||||
#Usage: root sub txtvalue
|
|
||||||
update_record() {
|
|
||||||
root=$1
|
|
||||||
sub=$2
|
|
||||||
txtvalue=$3
|
|
||||||
fulldomain="$sub.$root"
|
|
||||||
|
|
||||||
_info "Updating record"
|
|
||||||
|
|
||||||
if ! _rest POST "Record.Modify" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认&record_id=$record_id"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if _contains "$response" "Action completed successful"; then
|
|
||||||
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 1 #error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
#################### Private functions below ##################################
|
||||||
|
97
dnsapi/dns_dreamhost.sh
Normal file
97
dnsapi/dns_dreamhost.sh
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#Author: RhinoLance
|
||||||
|
#Report Bugs here: https://github.com/RhinoLance/acme.sh
|
||||||
|
#
|
||||||
|
|
||||||
|
#define the api endpoint
|
||||||
|
DH_API_ENDPOINT="https://api.dreamhost.com/"
|
||||||
|
querystring=""
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_dreamhost_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
if ! validate "$fulldomain" "$txtvalue"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
querystring="key=$DH_API_KEY&cmd=dns-add_record&record=$fulldomain&type=TXT&value=$txtvalue"
|
||||||
|
if ! submit "$querystring"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#Usage: fulldomain txtvalue
|
||||||
|
#Remove the txt record after validation.
|
||||||
|
dns_dreamhost_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
if ! validate "$fulldomain" "$txtvalue"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
querystring="key=$DH_API_KEY&cmd=dns-remove_record&record=$fulldomain&type=TXT&value=$txtvalue"
|
||||||
|
if ! submit "$querystring"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
|
||||||
|
#send the command to the api endpoint.
|
||||||
|
submit() {
|
||||||
|
querystring=$1
|
||||||
|
|
||||||
|
url="$DH_API_ENDPOINT?$querystring"
|
||||||
|
|
||||||
|
_debug url "$url"
|
||||||
|
|
||||||
|
if ! response="$(_get "$url")"; then
|
||||||
|
_err "Error <$1>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")"
|
||||||
|
if [ -n "$message" ]; then
|
||||||
|
_err "$message"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug response "$response"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#check that we have a valid API Key
|
||||||
|
validate() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
_info "Using dreamhost"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
#retrieve the API key from the environment variable if it exists, otherwise look for a saved key.
|
||||||
|
DH_API_KEY="${DH_API_KEY:-$(_readaccountconf_mutable DH_API_KEY)}"
|
||||||
|
|
||||||
|
if [ -z "$DH_API_KEY" ]; then
|
||||||
|
DH_API_KEY=""
|
||||||
|
_err "You didn't specify the DreamHost api key yet (export DH_API_KEY=\"<api key>\")"
|
||||||
|
_err "Please login to your control panel, create a key and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#save the api key to the account conf file.
|
||||||
|
_saveaccountconf_mutable DH_API_KEY "$DH_API_KEY"
|
||||||
|
}
|
@ -53,6 +53,8 @@ dns_freedns_add() {
|
|||||||
i="$(_math "$i" - 1)"
|
i="$(_math "$i" - 1)"
|
||||||
sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")"
|
sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")"
|
||||||
|
|
||||||
|
_debug top_domain "$top_domain"
|
||||||
|
_debug sub_domain "$sub_domain"
|
||||||
# Sometimes FreeDNS does not return the subdomain page but rather
|
# Sometimes FreeDNS does not return the subdomain page but rather
|
||||||
# returns a page regarding becoming a premium member. This usually
|
# returns a page regarding becoming a premium member. This usually
|
||||||
# happens after a period of inactivity. Immediately trying again
|
# happens after a period of inactivity. Immediately trying again
|
||||||
@ -61,7 +63,6 @@ dns_freedns_add() {
|
|||||||
attempts=2
|
attempts=2
|
||||||
while [ "$attempts" -gt "0" ]; do
|
while [ "$attempts" -gt "0" ]; do
|
||||||
attempts="$(_math "$attempts" - 1)"
|
attempts="$(_math "$attempts" - 1)"
|
||||||
|
|
||||||
htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
|
htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
|
||||||
if [ "$?" != "0" ]; then
|
if [ "$?" != "0" ]; then
|
||||||
if [ "$using_cached_cookies" = "true" ]; then
|
if [ "$using_cached_cookies" = "true" ]; then
|
||||||
@ -70,19 +71,11 @@ dns_freedns_add() {
|
|||||||
fi
|
fi
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
_debug2 htmlpage "$htmlpage"
|
||||||
|
|
||||||
|
subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '<form .*</form>' | sed 's/<tr>/@<tr>/g' | tr '@' '\n' | grep edit.php | grep "$top_domain")"
|
||||||
|
_debug2 subdomain_csv "$subdomain_csv"
|
||||||
|
|
||||||
# Now convert the tables in the HTML to CSV. This litte gem from
|
|
||||||
# http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv
|
|
||||||
subdomain_csv="$(echo "$htmlpage" \
|
|
||||||
| grep -i -e '</\?TABLE\|</\?TD\|</\?TR\|</\?TH' \
|
|
||||||
| sed 's/^[\ \t]*//g' \
|
|
||||||
| tr -d '\n' \
|
|
||||||
| sed 's/<\/TR[^>]*>/\n/Ig' \
|
|
||||||
| sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \
|
|
||||||
| sed 's/^<T[DH][^>]*>\|<\/\?T[DH][^>]*>$//Ig' \
|
|
||||||
| sed 's/<\/T[DH][^>]*><T[DH][^>]*>/,/Ig' \
|
|
||||||
| grep 'edit.php?' \
|
|
||||||
| grep "$top_domain")"
|
|
||||||
# The above beauty ends with striping out rows that do not have an
|
# The above beauty ends with striping out rows that do not have an
|
||||||
# href to edit.php and do not have the top domain we are looking for.
|
# href to edit.php and do not have the top domain we are looking for.
|
||||||
# So all we should be left with is CSV of table of subdomains we are
|
# So all we should be left with is CSV of table of subdomains we are
|
||||||
@ -90,30 +83,32 @@ dns_freedns_add() {
|
|||||||
|
|
||||||
# Now we have to read through this table and extract the data we need
|
# Now we have to read through this table and extract the data we need
|
||||||
lines="$(echo "$subdomain_csv" | wc -l)"
|
lines="$(echo "$subdomain_csv" | wc -l)"
|
||||||
nl='
|
|
||||||
'
|
|
||||||
i=0
|
i=0
|
||||||
found=0
|
found=0
|
||||||
while [ "$i" -lt "$lines" ]; do
|
while [ "$i" -lt "$lines" ]; do
|
||||||
i="$(_math "$i" + 1)"
|
i="$(_math "$i" + 1)"
|
||||||
line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")"
|
line="$(echo "$subdomain_csv" | sed -n "${i}p")"
|
||||||
tmp="$(echo "$line" | cut -d ',' -f 1)"
|
_debug2 line "$line"
|
||||||
if [ $found = 0 ] && _startswith "$tmp" "<td>$top_domain"; then
|
if [ $found = 0 ] && _contains "$line" "<td>$top_domain</td>"; then
|
||||||
# this line will contain DNSdomainid for the top_domain
|
# this line will contain DNSdomainid for the top_domain
|
||||||
DNSdomainid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*domain_id=//;s/>.*//')"
|
DNSdomainid="$(echo "$line" | _egrep_o "edit_domain_id *= *.*>" | cut -d = -f 2 | cut -d '>' -f 1)"
|
||||||
|
_debug2 DNSdomainid "$DNSdomainid"
|
||||||
found=1
|
found=1
|
||||||
else
|
else
|
||||||
# lines contain DNS records for all subdomains
|
# lines contain DNS records for all subdomains
|
||||||
DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')"
|
DNSname="$(echo "$line" | _egrep_o 'edit.php.*</a>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||||
DNStype="$(echo "$line" | cut -d ',' -f 3)"
|
_debug2 DNSname "$DNSname"
|
||||||
|
DNStype="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '4p' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||||
|
_debug2 DNStype "$DNStype"
|
||||||
if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then
|
if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then
|
||||||
DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')"
|
DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)"
|
||||||
# Now get current value for the TXT record. This method may
|
# Now get current value for the TXT record. This method may
|
||||||
# not produce accurate results as the value field is truncated
|
# not produce accurate results as the value field is truncated
|
||||||
# on this webpage. To get full value we would need to load
|
# on this webpage. To get full value we would need to load
|
||||||
# another page. However we don't really need this so long as
|
# another page. However we don't really need this so long as
|
||||||
# there is only one TXT record for the acme challenge subdomain.
|
# there is only one TXT record for the acme challenge subdomain.
|
||||||
DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')"
|
DNSvalue="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '5p' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||||
|
_debug2 DNSvalue "$DNSvalue"
|
||||||
if [ $found != 0 ]; then
|
if [ $found != 0 ]; then
|
||||||
break
|
break
|
||||||
# we are breaking out of the loop at the first match of DNS name
|
# we are breaking out of the loop at the first match of DNS name
|
||||||
@ -169,8 +164,7 @@ dns_freedns_add() {
|
|||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
# Delete the old TXT record (with the wrong value)
|
# Delete the old TXT record (with the wrong value)
|
||||||
_freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"
|
if _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"; then
|
||||||
if [ "$?" = "0" ]; then
|
|
||||||
# And add in new TXT record with the value provided
|
# And add in new TXT record with the value provided
|
||||||
_freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue"
|
_freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue"
|
||||||
fi
|
fi
|
||||||
@ -210,18 +204,9 @@ dns_freedns_rm() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Now convert the tables in the HTML to CSV. This litte gem from
|
subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '<form .*</form>' | sed 's/<tr>/@<tr>/g' | tr '@' '\n' | grep edit.php | grep "$fulldomain")"
|
||||||
# http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv
|
_debug2 subdomain_csv "$subdomain_csv"
|
||||||
subdomain_csv="$(echo "$htmlpage" \
|
|
||||||
| grep -i -e '</\?TABLE\|</\?TD\|</\?TR\|</\?TH' \
|
|
||||||
| sed 's/^[\ \t]*//g' \
|
|
||||||
| tr -d '\n' \
|
|
||||||
| sed 's/<\/TR[^>]*>/\n/Ig' \
|
|
||||||
| sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \
|
|
||||||
| sed 's/^<T[DH][^>]*>\|<\/\?T[DH][^>]*>$//Ig' \
|
|
||||||
| sed 's/<\/T[DH][^>]*><T[DH][^>]*>/,/Ig' \
|
|
||||||
| grep 'edit.php?' \
|
|
||||||
| grep "$fulldomain")"
|
|
||||||
# The above beauty ends with striping out rows that do not have an
|
# The above beauty ends with striping out rows that do not have an
|
||||||
# href to edit.php and do not have the domain name we are looking for.
|
# href to edit.php and do not have the domain name we are looking for.
|
||||||
# So all we should be left with is CSV of table of subdomains we are
|
# So all we should be left with is CSV of table of subdomains we are
|
||||||
@ -229,19 +214,21 @@ dns_freedns_rm() {
|
|||||||
|
|
||||||
# Now we have to read through this table and extract the data we need
|
# Now we have to read through this table and extract the data we need
|
||||||
lines="$(echo "$subdomain_csv" | wc -l)"
|
lines="$(echo "$subdomain_csv" | wc -l)"
|
||||||
nl='
|
|
||||||
'
|
|
||||||
i=0
|
i=0
|
||||||
found=0
|
found=0
|
||||||
while [ "$i" -lt "$lines" ]; do
|
while [ "$i" -lt "$lines" ]; do
|
||||||
i="$(_math "$i" + 1)"
|
i="$(_math "$i" + 1)"
|
||||||
line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")"
|
line="$(echo "$subdomain_csv" | sed -n "${i}p")"
|
||||||
DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')"
|
_debug2 line "$line"
|
||||||
DNStype="$(echo "$line" | cut -d ',' -f 3)"
|
DNSname="$(echo "$line" | _egrep_o 'edit.php.*</a>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||||
|
_debug2 DNSname "$DNSname"
|
||||||
|
DNStype="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '4p' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||||
|
_debug2 DNStype "$DNStype"
|
||||||
if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then
|
if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then
|
||||||
DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')"
|
DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)"
|
||||||
DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')"
|
_debug2 DNSdataid "$DNSdataid"
|
||||||
_debug "DNSvalue: $DNSvalue"
|
DNSvalue="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '5p' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||||
|
_debug2 DNSvalue "$DNSvalue"
|
||||||
# if [ "$DNSvalue" = "$txtvalue" ]; then
|
# if [ "$DNSvalue" = "$txtvalue" ]; then
|
||||||
# Testing value match fails. Website is truncating the value
|
# Testing value match fails. Website is truncating the value
|
||||||
# field. So for now we will assume that there is only one TXT
|
# field. So for now we will assume that there is only one TXT
|
||||||
|
@ -15,6 +15,8 @@ dns_gd_add() {
|
|||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
|
GD_Key="${GD_Key:-$(_readaccountconf_mutable GD_Key)}"
|
||||||
|
GD_Secret="${GD_Secret:-$(_readaccountconf_mutable GD_Secret)}"
|
||||||
if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then
|
if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then
|
||||||
GD_Key=""
|
GD_Key=""
|
||||||
GD_Secret=""
|
GD_Secret=""
|
||||||
@ -24,8 +26,8 @@ dns_gd_add() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
#save the api key and email to the account conf file.
|
#save the api key and email to the account conf file.
|
||||||
_saveaccountconf GD_Key "$GD_Key"
|
_saveaccountconf_mutable GD_Key "$GD_Key"
|
||||||
_saveaccountconf GD_Secret "$GD_Secret"
|
_saveaccountconf_mutable GD_Secret "$GD_Secret"
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
@ -36,8 +38,27 @@ dns_gd_add() {
|
|||||||
_debug _sub_domain "$_sub_domain"
|
_debug _sub_domain "$_sub_domain"
|
||||||
_debug _domain "$_domain"
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
_debug "Getting existing records"
|
||||||
|
if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$response" "$txtvalue"; then
|
||||||
|
_info "The record is existing, skip"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_add_data="{\"data\":\"$txtvalue\"}"
|
||||||
|
for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do
|
||||||
|
_debug2 t "$t"
|
||||||
|
if [ "$t" ]; then
|
||||||
|
_add_data="$_add_data,{\"data\":$t}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
_debug2 _add_data "$_add_data"
|
||||||
|
|
||||||
_info "Adding record"
|
_info "Adding record"
|
||||||
if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then
|
if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then
|
||||||
if [ "$response" = "{}" ]; then
|
if [ "$response" = "{}" ]; then
|
||||||
_info "Added, sleeping 10 seconds"
|
_info "Added, sleeping 10 seconds"
|
||||||
_sleep 10
|
_sleep 10
|
||||||
@ -56,7 +77,47 @@ dns_gd_add() {
|
|||||||
#fulldomain
|
#fulldomain
|
||||||
dns_gd_rm() {
|
dns_gd_rm() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
GD_Key="${GD_Key:-$(_readaccountconf_mutable GD_Key)}"
|
||||||
|
GD_Secret="${GD_Secret:-$(_readaccountconf_mutable GD_Secret)}"
|
||||||
|
|
||||||
|
_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 existing records"
|
||||||
|
if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _contains "$response" "$txtvalue"; then
|
||||||
|
_info "The record is not existing, skip"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_add_data=""
|
||||||
|
for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do
|
||||||
|
_debug2 t "$t"
|
||||||
|
if [ "$t" ] && [ "$t" != "\"$txtvalue\"" ]; then
|
||||||
|
if [ "$_add_data" ]; then
|
||||||
|
_add_data="$_add_data,{\"data\":$t}"
|
||||||
|
else
|
||||||
|
_add_data="{\"data\":$t}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ -z "$_add_data" ]; then
|
||||||
|
_add_data="{\"data\":\"\"}"
|
||||||
|
fi
|
||||||
|
_debug2 _add_data "$_add_data"
|
||||||
|
|
||||||
|
_gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"
|
||||||
}
|
}
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
#################### Private functions below ##################################
|
||||||
|
@ -19,14 +19,16 @@ dns_he_add() {
|
|||||||
_txt_value=$2
|
_txt_value=$2
|
||||||
_info "Using DNS-01 Hurricane Electric hook"
|
_info "Using DNS-01 Hurricane Electric hook"
|
||||||
|
|
||||||
|
HE_Username="${HE_Username:-$(_readaccountconf_mutable HE_Username)}"
|
||||||
|
HE_Password="${HE_Password:-$(_readaccountconf_mutable HE_Password)}"
|
||||||
if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then
|
if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then
|
||||||
HE_Username=
|
HE_Username=
|
||||||
HE_Password=
|
HE_Password=
|
||||||
_err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables."
|
_err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_saveaccountconf HE_Username "$HE_Username"
|
_saveaccountconf_mutable HE_Username "$HE_Username"
|
||||||
_saveaccountconf HE_Password "$HE_Password"
|
_saveaccountconf_mutable HE_Password "$HE_Password"
|
||||||
|
|
||||||
# Fills in the $_zone_id
|
# Fills in the $_zone_id
|
||||||
_find_zone "$_full_domain" || return 1
|
_find_zone "$_full_domain" || return 1
|
||||||
@ -62,7 +64,8 @@ dns_he_rm() {
|
|||||||
_full_domain=$1
|
_full_domain=$1
|
||||||
_txt_value=$2
|
_txt_value=$2
|
||||||
_info "Cleaning up after DNS-01 Hurricane Electric hook"
|
_info "Cleaning up after DNS-01 Hurricane Electric hook"
|
||||||
|
HE_Username="${HE_Username:-$(_readaccountconf_mutable HE_Username)}"
|
||||||
|
HE_Password="${HE_Password:-$(_readaccountconf_mutable HE_Password)}"
|
||||||
# fills in the $_zone_id
|
# fills in the $_zone_id
|
||||||
_find_zone "$_full_domain" || return 1
|
_find_zone "$_full_domain" || return 1
|
||||||
_debug "Zone id \"$_zone_id\" will be used."
|
_debug "Zone id \"$_zone_id\" will be used."
|
||||||
@ -72,17 +75,19 @@ dns_he_rm() {
|
|||||||
body="$body&hosted_dns_zoneid=$_zone_id"
|
body="$body&hosted_dns_zoneid=$_zone_id"
|
||||||
body="$body&menu=edit_zone"
|
body="$body&menu=edit_zone"
|
||||||
body="$body&hosted_dns_editzone="
|
body="$body&hosted_dns_editzone="
|
||||||
domain_regex="$(echo "$_full_domain" | sed 's/\./\\./g')" # escape dots
|
|
||||||
_record_id=$(_post "$body" "https://dns.he.net/" \
|
|
||||||
| tr -d '\n' \
|
|
||||||
| _egrep_o "data=\""${_txt_value}"([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${domain_regex}','TXT'\)" \
|
|
||||||
| _egrep_o "[0-9]+','${domain_regex}','TXT'\)$" \
|
|
||||||
| _egrep_o "^[0-9]+"
|
|
||||||
)
|
|
||||||
# The series of egreps above could have been done a bit shorter but
|
|
||||||
# I wanted to double-check whether it's the correct record (in case
|
|
||||||
# HE changes their website somehow).
|
|
||||||
|
|
||||||
|
response="$(_post "$body" "https://dns.he.net/")"
|
||||||
|
_debug2 "response" "$response"
|
||||||
|
if ! _contains "$response" "$_txt_value"; then
|
||||||
|
_debug "The txt record is not found, just skip"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
_record_id="$(echo "$response" | tr -d "#" | sed "s/<tr/#<tr/g" | tr -d "\n" | tr "#" "\n" | grep "$_full_domain" | grep '"dns_tr"' | grep "$_txt_value" | cut -d '"' -f 4)"
|
||||||
|
_debug2 _record_id "$_record_id"
|
||||||
|
if [ -z "$_record_id" ]; then
|
||||||
|
_err "Can not find record id"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
# Remove the record
|
# Remove the record
|
||||||
body="email=${HE_Username}&pass=${HE_Password}"
|
body="email=${HE_Username}&pass=${HE_Password}"
|
||||||
body="$body&menu=edit_zone"
|
body="$body&menu=edit_zone"
|
||||||
@ -105,41 +110,26 @@ dns_he_rm() {
|
|||||||
|
|
||||||
########################## PRIVATE FUNCTIONS ###########################
|
########################## PRIVATE FUNCTIONS ###########################
|
||||||
|
|
||||||
#-- _find_zone() -------------------------------------------------------
|
|
||||||
# Returns the most specific zone found in administration interface.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
#
|
|
||||||
# _find_zone first.second.third.co.uk
|
|
||||||
#
|
|
||||||
# ... will return the first zone that exists in admin out of these:
|
|
||||||
# - "first.second.third.co.uk"
|
|
||||||
# - "second.third.co.uk"
|
|
||||||
# - "third.co.uk"
|
|
||||||
# - "co.uk" <-- unlikely
|
|
||||||
# - "uk" <-'
|
|
||||||
#
|
|
||||||
# (another approach would be something like this:
|
|
||||||
# https://github.com/hlandau/acme/blob/master/_doc/dns.hook
|
|
||||||
# - that's better if there are multiple pages. It's so much simpler.
|
|
||||||
# )
|
|
||||||
|
|
||||||
_find_zone() {
|
_find_zone() {
|
||||||
|
|
||||||
_domain="$1"
|
_domain="$1"
|
||||||
|
|
||||||
body="email=${HE_Username}&pass=${HE_Password}"
|
body="email=${HE_Username}&pass=${HE_Password}"
|
||||||
_matches=$(_post "$body" "https://dns.he.net/" \
|
response="$(_post "$body" "https://dns.he.net/")"
|
||||||
| _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+"
|
_debug2 response "$response"
|
||||||
)
|
_table="$(echo "$response" | tr -d "#" | sed "s/<table/#<table/g" | tr -d "\n" | tr "#" "\n" | grep 'id="domains_table"')"
|
||||||
|
_debug2 _table "$_table"
|
||||||
|
_matches="$(echo "$_table" | sed "s/<tr/#<tr/g" | tr "#" "\n" | grep 'alt="edit"' | tr -d " " | sed "s/<td/#<td/g" | tr "#" "\n" | sed -n 3p)"
|
||||||
|
_debug2 _matches "$_matches"
|
||||||
# Zone names and zone IDs are in same order
|
# Zone names and zone IDs are in same order
|
||||||
_zone_ids=$(echo "$_matches" | cut -d '"' -f 5)
|
_zone_ids=$(echo "$_matches" | _egrep_o "hosted_dns_zoneid=[0-9]*&" | cut -d = -f 2 | tr -d '&')
|
||||||
_zone_names=$(echo "$_matches" | cut -d '"' -f 3)
|
_zone_names=$(echo "$_matches" | _egrep_o "name=.*onclick" | cut -d '"' -f 2)
|
||||||
_debug2 "These are the zones on this HE account:"
|
_debug2 "These are the zones on this HE account:"
|
||||||
_debug2 "$_zone_names"
|
_debug2 "$_zone_names"
|
||||||
_debug2 "And these are their respective IDs:"
|
_debug2 "And these are their respective IDs:"
|
||||||
_debug2 "$_zone_ids"
|
_debug2 "$_zone_ids"
|
||||||
|
if [ -z "$_zone_names" ] || [ -z "$_zone_ids" ]; then
|
||||||
|
_err "Can not get zone names."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
# Walk through all possible zone names
|
# Walk through all possible zone names
|
||||||
_strip_counter=1
|
_strip_counter=1
|
||||||
while true; do
|
while true; do
|
||||||
@ -153,17 +143,10 @@ _find_zone() {
|
|||||||
|
|
||||||
_debug "Looking for zone \"${_attempted_zone}\""
|
_debug "Looking for zone \"${_attempted_zone}\""
|
||||||
|
|
||||||
# Take care of "." and only match whole lines. Note that grep -F
|
line_num="$(echo "$_zone_names" | grep -n "$_attempted_zone" | cut -d : -f 1)"
|
||||||
# cannot be used because there's no way to make it match whole
|
|
||||||
# lines.
|
|
||||||
regex="^$(echo "$_attempted_zone" | sed 's/\./\\./g')$"
|
|
||||||
line_num=$(echo "$_zone_names" \
|
|
||||||
| grep -n "$regex" \
|
|
||||||
| cut -d : -f 1
|
|
||||||
)
|
|
||||||
|
|
||||||
if [ -n "$line_num" ]; then
|
if [ "$line_num" ]; then
|
||||||
_zone_id=$(echo "$_zone_ids" | sed "${line_num}q;d")
|
_zone_id=$(echo "$_zone_ids" | sed -n "${line_num}p")
|
||||||
_debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"."
|
_debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
311
dnsapi/dns_inwx.sh
Executable file
311
dnsapi/dns_inwx.sh
Executable file
@ -0,0 +1,311 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#
|
||||||
|
#INWX_User="username"
|
||||||
|
#
|
||||||
|
#INWX_Password="password"
|
||||||
|
|
||||||
|
INWX_Api="https://api.domrobot.com/xmlrpc/"
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_inwx_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}"
|
||||||
|
INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}"
|
||||||
|
if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then
|
||||||
|
INWX_User=""
|
||||||
|
INWX_Password=""
|
||||||
|
_err "You don't specify inwx user and password yet."
|
||||||
|
_err "Please create you key and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#save the api key and email to the account conf file.
|
||||||
|
_saveaccountconf_mutable INWX_User "$INWX_User"
|
||||||
|
_saveaccountconf_mutable INWX_Password "$INWX_Password"
|
||||||
|
|
||||||
|
_debug "First detect the root zone"
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "invalid domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
_info "Adding record"
|
||||||
|
_inwx_add_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#fulldomain txtvalue
|
||||||
|
dns_inwx_rm() {
|
||||||
|
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}"
|
||||||
|
INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}"
|
||||||
|
if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then
|
||||||
|
INWX_User=""
|
||||||
|
INWX_Password=""
|
||||||
|
_err "You don't specify inwx user and password yet."
|
||||||
|
_err "Please create you key and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#save the api key and email to the account conf file.
|
||||||
|
_saveaccountconf_mutable INWX_User "$INWX_User"
|
||||||
|
_saveaccountconf_mutable INWX_Password "$INWX_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"
|
||||||
|
|
||||||
|
_debug "Getting txt records"
|
||||||
|
|
||||||
|
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<methodCall>
|
||||||
|
<methodName>nameserver.info</methodName>
|
||||||
|
<params>
|
||||||
|
<param>
|
||||||
|
<value>
|
||||||
|
<struct>
|
||||||
|
<member>
|
||||||
|
<name>domain</name>
|
||||||
|
<value>
|
||||||
|
<string>%s</string>
|
||||||
|
</value>
|
||||||
|
</member>
|
||||||
|
<member>
|
||||||
|
<name>type</name>
|
||||||
|
<value>
|
||||||
|
<string>TXT</string>
|
||||||
|
</value>
|
||||||
|
</member>
|
||||||
|
<member>
|
||||||
|
<name>name</name>
|
||||||
|
<value>
|
||||||
|
<string>%s</string>
|
||||||
|
</value>
|
||||||
|
</member>
|
||||||
|
</struct>
|
||||||
|
</value>
|
||||||
|
</param>
|
||||||
|
</params>
|
||||||
|
</methodCall>' "$_domain" "$_sub_domain")
|
||||||
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||||
|
|
||||||
|
if ! _contains "$response" "Command completed successfully"; then
|
||||||
|
_err "Error could not get txt records"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! printf "%s" "$response" | grep "count" >/dev/null; then
|
||||||
|
_info "Do not need to delete record"
|
||||||
|
else
|
||||||
|
_record_id=$(printf '%s' "$response" | _egrep_o '.*(<member><name>record){1}(.*)([0-9]+){1}' | _egrep_o '<name>id<\/name><value><int>[0-9]+' | _egrep_o '[0-9]+')
|
||||||
|
_info "Deleting record"
|
||||||
|
_inwx_delete_record "$_record_id"
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
|
||||||
|
_inwx_login() {
|
||||||
|
|
||||||
|
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<methodCall>
|
||||||
|
<methodName>account.login</methodName>
|
||||||
|
<params>
|
||||||
|
<param>
|
||||||
|
<value>
|
||||||
|
<struct>
|
||||||
|
<member>
|
||||||
|
<name>user</name>
|
||||||
|
<value>
|
||||||
|
<string>%s</string>
|
||||||
|
</value>
|
||||||
|
</member>
|
||||||
|
<member>
|
||||||
|
<name>pass</name>
|
||||||
|
<value>
|
||||||
|
<string>%s</string>
|
||||||
|
</value>
|
||||||
|
</member>
|
||||||
|
</struct>
|
||||||
|
</value>
|
||||||
|
</param>
|
||||||
|
</params>
|
||||||
|
</methodCall>' $INWX_User $INWX_Password)
|
||||||
|
|
||||||
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||||
|
|
||||||
|
printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_root() {
|
||||||
|
domain=$1
|
||||||
|
_debug "get root"
|
||||||
|
|
||||||
|
domain=$1
|
||||||
|
i=2
|
||||||
|
p=1
|
||||||
|
|
||||||
|
_H1=$(_inwx_login)
|
||||||
|
export _H1
|
||||||
|
xml_content='<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<methodCall>
|
||||||
|
<methodName>nameserver.list</methodName>
|
||||||
|
</methodCall>'
|
||||||
|
|
||||||
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||||
|
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
|
||||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||||
|
_domain="$h"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
p=$i
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_inwx_delete_record() {
|
||||||
|
record_id=$1
|
||||||
|
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<methodCall>
|
||||||
|
<methodName>nameserver.deleteRecord</methodName>
|
||||||
|
<params>
|
||||||
|
<param>
|
||||||
|
<value>
|
||||||
|
<struct>
|
||||||
|
<member>
|
||||||
|
<name>id</name>
|
||||||
|
<value>
|
||||||
|
<int>%s</int>
|
||||||
|
</value>
|
||||||
|
</member>
|
||||||
|
</struct>
|
||||||
|
</value>
|
||||||
|
</param>
|
||||||
|
</params>
|
||||||
|
</methodCall>' "$record_id")
|
||||||
|
|
||||||
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||||
|
|
||||||
|
if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
|
||||||
|
_err "Error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_inwx_update_record() {
|
||||||
|
record_id=$1
|
||||||
|
txtval=$2
|
||||||
|
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<methodCall>
|
||||||
|
<methodName>nameserver.updateRecord</methodName>
|
||||||
|
<params>
|
||||||
|
<param>
|
||||||
|
<value>
|
||||||
|
<struct>
|
||||||
|
<member>
|
||||||
|
<name>content</name>
|
||||||
|
<value>
|
||||||
|
<string>%s</string>
|
||||||
|
</value>
|
||||||
|
</member>
|
||||||
|
<member>
|
||||||
|
<name>id</name>
|
||||||
|
<value>
|
||||||
|
<int>%s</int>
|
||||||
|
</value>
|
||||||
|
</member>
|
||||||
|
</struct>
|
||||||
|
</value>
|
||||||
|
</param>
|
||||||
|
</params>
|
||||||
|
</methodCall>' "$txtval" "$record_id")
|
||||||
|
|
||||||
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||||
|
|
||||||
|
if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
|
||||||
|
_err "Error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_inwx_add_record() {
|
||||||
|
|
||||||
|
domain=$1
|
||||||
|
sub_domain=$2
|
||||||
|
txtval=$3
|
||||||
|
|
||||||
|
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<methodCall>
|
||||||
|
<methodName>nameserver.createRecord</methodName>
|
||||||
|
<params>
|
||||||
|
<param>
|
||||||
|
<value>
|
||||||
|
<struct>
|
||||||
|
<member>
|
||||||
|
<name>domain</name>
|
||||||
|
<value>
|
||||||
|
<string>%s</string>
|
||||||
|
</value>
|
||||||
|
</member>
|
||||||
|
<member>
|
||||||
|
<name>type</name>
|
||||||
|
<value>
|
||||||
|
<string>TXT</string>
|
||||||
|
</value>
|
||||||
|
</member>
|
||||||
|
<member>
|
||||||
|
<name>content</name>
|
||||||
|
<value>
|
||||||
|
<string>%s</string>
|
||||||
|
</value>
|
||||||
|
</member>
|
||||||
|
<member>
|
||||||
|
<name>name</name>
|
||||||
|
<value>
|
||||||
|
<string>%s</string>
|
||||||
|
</value>
|
||||||
|
</member>
|
||||||
|
</struct>
|
||||||
|
</value>
|
||||||
|
</param>
|
||||||
|
</params>
|
||||||
|
</methodCall>' "$domain" "$txtval" "$sub_domain")
|
||||||
|
|
||||||
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||||
|
|
||||||
|
if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
|
||||||
|
_err "Error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
# ISPConfig 3.1 API
|
# ISPConfig 3.1 API
|
||||||
# User must provide login data and URL to the ISPConfig installation incl. port. The remote user in ISPConfig must have access to:
|
# User must provide login data and URL to the ISPConfig installation incl. port. The remote user in ISPConfig must have access to:
|
||||||
# - DNS zone Functions
|
|
||||||
# - DNS txt Functions
|
# - DNS txt Functions
|
||||||
|
|
||||||
# Report bugs to https://github.com/sjau/acme.sh
|
# Report bugs to https://github.com/sjau/acme.sh
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#LUA_Email="user@luadns.net"
|
#LUA_Email="user@luadns.net"
|
||||||
|
|
||||||
LUA_Api="https://api.luadns.com/v1"
|
LUA_Api="https://api.luadns.com/v1"
|
||||||
LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64)
|
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
@ -17,6 +16,10 @@ dns_lua_add() {
|
|||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
|
LUA_Key="${LUA_Key:-$(_readaccountconf_mutable LUA_Key)}"
|
||||||
|
LUA_Email="${LUA_Email:-$(_readaccountconf_mutable LUA_Email)}"
|
||||||
|
LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64)
|
||||||
|
|
||||||
if [ -z "$LUA_Key" ] || [ -z "$LUA_Email" ]; then
|
if [ -z "$LUA_Key" ] || [ -z "$LUA_Email" ]; then
|
||||||
LUA_Key=""
|
LUA_Key=""
|
||||||
LUA_Email=""
|
LUA_Email=""
|
||||||
@ -26,8 +29,8 @@ dns_lua_add() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
#save the api key and email to the account conf file.
|
#save the api key and email to the account conf file.
|
||||||
_saveaccountconf LUA_Key "$LUA_Key"
|
_saveaccountconf_mutable LUA_Key "$LUA_Key"
|
||||||
_saveaccountconf LUA_Email "$LUA_Email"
|
_saveaccountconf_mutable LUA_Email "$LUA_Email"
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
@ -38,50 +41,27 @@ dns_lua_add() {
|
|||||||
_debug _sub_domain "$_sub_domain"
|
_debug _sub_domain "$_sub_domain"
|
||||||
_debug _domain "$_domain"
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
_debug "Getting txt records"
|
_info "Adding record"
|
||||||
_LUA_rest GET "zones/${_domain_id}/records"
|
if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
|
||||||
|
if _contains "$response" "$fulldomain"; then
|
||||||
if ! _contains "$response" "\"id\":"; then
|
_info "Added"
|
||||||
_err "Error"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ")
|
|
||||||
_debug count "$count"
|
|
||||||
if [ "$count" = "0" ]; then
|
|
||||||
_info "Adding record"
|
|
||||||
if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
|
|
||||||
if _contains "$response" "$fulldomain"; then
|
|
||||||
_info "Added"
|
|
||||||
#todo: check if the record takes effect
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
_err "Add txt record error."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
_err "Add txt record error."
|
|
||||||
else
|
|
||||||
_info "Updating record"
|
|
||||||
record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1)
|
|
||||||
_debug "record_id" "$record_id"
|
|
||||||
|
|
||||||
_LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":$record_id,\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":$_domain_id,\"ttl\":120}"
|
|
||||||
if [ "$?" = "0" ] && _contains "$response" "updated_at"; then
|
|
||||||
_info "Updated!"
|
|
||||||
#todo: check if the record takes effect
|
#todo: check if the record takes effect
|
||||||
return 0
|
return 0
|
||||||
|
else
|
||||||
|
_err "Add txt record error."
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
_err "Update error"
|
|
||||||
return 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#fulldomain
|
#fulldomain
|
||||||
dns_lua_rm() {
|
dns_lua_rm() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
|
LUA_Key="${LUA_Key:-$(_readaccountconf_mutable LUA_Key)}"
|
||||||
|
LUA_Email="${LUA_Email:-$(_readaccountconf_mutable LUA_Email)}"
|
||||||
|
LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64)
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
_err "invalid domain"
|
_err "invalid domain"
|
||||||
|
137
dnsapi/dns_namesilo.sh
Executable file
137
dnsapi/dns_namesilo.sh
Executable file
@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#Author: meowthink
|
||||||
|
#Created 01/14/2017
|
||||||
|
#Utilize namesilo.com API to finish dns-01 verifications.
|
||||||
|
|
||||||
|
Namesilo_API="https://www.namesilo.com/api"
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_namesilo_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
if [ -z "$Namesilo_Key" ]; then
|
||||||
|
Namesilo_Key=""
|
||||||
|
_err "API token for namesilo.com is missing."
|
||||||
|
_err "Please specify that in your environment variable."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#save the api key and email to the account conf file.
|
||||||
|
_saveaccountconf Namesilo_Key "$Namesilo_Key"
|
||||||
|
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "Unable to find domain specified."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
if _namesilo_rest GET "dnsAddRecord?version=1&type=xml&key=$Namesilo_Key&domain=$_domain&rrtype=TXT&rrhost=$_sub_domain&rrvalue=$txtvalue"; then
|
||||||
|
retcode=$(printf "%s\n" "$response" | _egrep_o "<code>300")
|
||||||
|
if [ "$retcode" ]; then
|
||||||
|
_info "Successfully added TXT record, ready for validation."
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_err "Unable to add the DNS record."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#Usage: fulldomain txtvalue
|
||||||
|
#Remove the txt record after validation.
|
||||||
|
dns_namesilo_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "Unable to find domain specified."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the record id.
|
||||||
|
if _namesilo_rest GET "dnsListRecords?version=1&type=xml&key=$Namesilo_Key&domain=$_domain"; then
|
||||||
|
retcode=$(printf "%s\n" "$response" | _egrep_o "<code>300")
|
||||||
|
if [ "$retcode" ]; then
|
||||||
|
_record_id=$(printf "%s\n" "$response" | _egrep_o "<record_id>([^<]*)</record_id><type>TXT</type><host>$fulldomain</host>" | _egrep_o "<record_id>([^<]*)</record_id>" | sed -r "s/<record_id>([^<]*)<\/record_id>/\1/" | tail -n 1)
|
||||||
|
_debug record_id "$_record_id"
|
||||||
|
_info "Successfully retrieved the record id for ACME challenge."
|
||||||
|
else
|
||||||
|
_err "Unable to retrieve the record id."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove the DNS record using record id.
|
||||||
|
if _namesilo_rest GET "dnsDeleteRecord?version=1&type=xml&key=$Namesilo_Key&domain=$_domain&rrid=$_record_id"; then
|
||||||
|
retcode=$(printf "%s\n" "$response" | _egrep_o "<code>300")
|
||||||
|
if [ "$retcode" ]; then
|
||||||
|
_info "Successfully removed the TXT record."
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_err "Unable to remove the DNS record."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
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
|
||||||
|
|
||||||
|
if ! _namesilo_rest GET "listDomains?version=1&type=xml&key=$Namesilo_Key"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Need to exclude the last field (tld)
|
||||||
|
numfields=$(echo "$domain" | _egrep_o "\." | wc -l)
|
||||||
|
while [ $i -le "$numfields" ]; do
|
||||||
|
host=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
|
_debug host "$host"
|
||||||
|
if [ -z "$host" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$response" "$host"; then
|
||||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||||
|
_domain="$host"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
p=$i
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_namesilo_rest() {
|
||||||
|
method=$1
|
||||||
|
param=$2
|
||||||
|
data=$3
|
||||||
|
|
||||||
|
if [ "$method" != "GET" ]; then
|
||||||
|
response="$(_post "$data" "$Namesilo_API/$param" "" "$method")"
|
||||||
|
else
|
||||||
|
response="$(_get "$Namesilo_API/$param")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error $param"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
@ -59,10 +59,10 @@ dns_nsone_add() {
|
|||||||
_err "Add txt record error."
|
_err "Add txt record error."
|
||||||
else
|
else
|
||||||
_info "Updating record"
|
_info "Updating record"
|
||||||
record_id=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\",\"id\":\"[^,]*\"" | _head_n 1 | cut -d: -f7 | cut -d, -f1)
|
prev_txt=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",\"short_answers\":\[\"[^,]*\]" | _head_n 1 | cut -d: -f3 | cut -d, -f1)
|
||||||
_debug "record_id" "$record_id"
|
_debug "prev_txt" "$prev_txt"
|
||||||
|
|
||||||
_nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}"
|
_nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]},{\"answer\": $prev_txt}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}"
|
||||||
if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then
|
if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then
|
||||||
_info "Updated!"
|
_info "Updated!"
|
||||||
#todo: check if the record takes effect
|
#todo: check if the record takes effect
|
||||||
|
@ -78,12 +78,9 @@ _ovh_get_api() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
######## Public functions #####################
|
_initAuth() {
|
||||||
|
OVH_AK="${OVH_AK:-$(_readaccountconf_mutable OVH_AK)}"
|
||||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
OVH_AS="${OVH_AS:-$(_readaccountconf_mutable OVH_AS)}"
|
||||||
dns_ovh_add() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then
|
if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then
|
||||||
OVH_AK=""
|
OVH_AK=""
|
||||||
@ -93,21 +90,26 @@ dns_ovh_add() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#save the api key and email to the account conf file.
|
if [ "$OVH_AK" != "$(_readaccountconf OVH_AK)" ]; then
|
||||||
_saveaccountconf OVH_AK "$OVH_AK"
|
_info "It seems that your ovh key is changed, let's clear consumer key first."
|
||||||
_saveaccountconf OVH_AS "$OVH_AS"
|
_clearaccountconf OVH_CK
|
||||||
|
fi
|
||||||
|
_saveaccountconf_mutable OVH_AK "$OVH_AK"
|
||||||
|
_saveaccountconf_mutable OVH_AS "$OVH_AS"
|
||||||
|
|
||||||
|
OVH_END_POINT="${OVH_END_POINT:-$(_readaccountconf_mutable OVH_END_POINT)}"
|
||||||
if [ -z "$OVH_END_POINT" ]; then
|
if [ -z "$OVH_END_POINT" ]; then
|
||||||
OVH_END_POINT="ovh-eu"
|
OVH_END_POINT="ovh-eu"
|
||||||
fi
|
fi
|
||||||
_info "Using OVH endpoint: $OVH_END_POINT"
|
_info "Using OVH endpoint: $OVH_END_POINT"
|
||||||
if [ "$OVH_END_POINT" != "ovh-eu" ]; then
|
if [ "$OVH_END_POINT" != "ovh-eu" ]; then
|
||||||
_saveaccountconf OVH_END_POINT "$OVH_END_POINT"
|
_saveaccountconf_mutable OVH_END_POINT "$OVH_END_POINT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
OVH_API="$(_ovh_get_api $OVH_END_POINT)"
|
OVH_API="$(_ovh_get_api $OVH_END_POINT)"
|
||||||
_debug OVH_API "$OVH_API"
|
_debug OVH_API "$OVH_API"
|
||||||
|
|
||||||
|
OVH_CK="${OVH_CK:-$(_readaccountconf_mutable OVH_CK)}"
|
||||||
if [ -z "$OVH_CK" ]; then
|
if [ -z "$OVH_CK" ]; then
|
||||||
_info "OVH consumer key is empty, Let's get one:"
|
_info "OVH consumer key is empty, Let's get one:"
|
||||||
if ! _ovh_authentication; then
|
if ! _ovh_authentication; then
|
||||||
@ -119,14 +121,26 @@ dns_ovh_add() {
|
|||||||
|
|
||||||
_info "Checking authentication"
|
_info "Checking authentication"
|
||||||
|
|
||||||
response="$(_ovh_rest GET "domain")"
|
if ! _ovh_rest GET "domain" || _contains "$response" "INVALID_CREDENTIAL"; then
|
||||||
if _contains "$response" "INVALID_CREDENTIAL"; then
|
|
||||||
_err "The consumer key is invalid: $OVH_CK"
|
_err "The consumer key is invalid: $OVH_CK"
|
||||||
_err "Please retry to create a new one."
|
_err "Please retry to create a new one."
|
||||||
_clearaccountconf OVH_CK
|
_clearaccountconf OVH_CK
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_info "Consumer key is ok."
|
_info "Consumer key is ok."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_ovh_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
if ! _initAuth; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
@ -137,49 +151,58 @@ dns_ovh_add() {
|
|||||||
_debug _sub_domain "$_sub_domain"
|
_debug _sub_domain "$_sub_domain"
|
||||||
_debug _domain "$_domain"
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
_debug "Getting txt records"
|
_info "Adding record"
|
||||||
_ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain"
|
if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then
|
||||||
|
if _contains "$response" "$txtvalue"; then
|
||||||
if _contains "$response" '\[\]' || _contains "$response" "This service does not exist"; then
|
_ovh_rest POST "domain/zone/$_domain/refresh"
|
||||||
_info "Adding record"
|
_debug "Refresh:$response"
|
||||||
if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then
|
_info "Added, sleep 10 seconds."
|
||||||
if _contains "$response" "$txtvalue"; then
|
_sleep 10
|
||||||
_ovh_rest POST "domain/zone/$_domain/refresh"
|
return 0
|
||||||
_debug "Refresh:$response"
|
|
||||||
_info "Added, sleeping 10 seconds"
|
|
||||||
sleep 10
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
_err "Add txt record error."
|
|
||||||
else
|
|
||||||
_info "Updating record"
|
|
||||||
record_id=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 1)
|
|
||||||
if [ -z "$record_id" ]; then
|
|
||||||
_err "Can not get record id."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug "record_id" "$record_id"
|
|
||||||
|
|
||||||
if _ovh_rest PUT "domain/zone/$_domain/record/$record_id" "{\"target\":\"$txtvalue\",\"subDomain\":\"$_sub_domain\",\"ttl\":60}"; then
|
|
||||||
if _contains "$response" "null"; then
|
|
||||||
_ovh_rest POST "domain/zone/$_domain/refresh"
|
|
||||||
_debug "Refresh:$response"
|
|
||||||
_info "Updated, sleeping 10 seconds"
|
|
||||||
sleep 10
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
_err "Update error"
|
|
||||||
return 1
|
|
||||||
fi
|
fi
|
||||||
|
_err "Add txt record error."
|
||||||
|
return 1
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#fulldomain
|
#fulldomain
|
||||||
dns_ovh_rm() {
|
dns_ovh_rm() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
if ! _initAuth; 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"
|
||||||
|
if ! _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for rid in $(echo "$response" | tr '][,' ' '); do
|
||||||
|
_debug rid "$rid"
|
||||||
|
if ! _ovh_rest GET "domain/zone/$_domain/record/$rid"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if _contains "$response" "\"target\":\"$txtvalue\""; then
|
||||||
|
_debug "Found txt id:$rid"
|
||||||
|
if ! _ovh_rest DELETE "domain/zone/$_domain/record/$rid"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
#################### Private functions below ##################################
|
||||||
@ -191,7 +214,7 @@ _ovh_authentication() {
|
|||||||
_H3=""
|
_H3=""
|
||||||
_H4=""
|
_H4=""
|
||||||
|
|
||||||
_ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}'
|
_ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"},{"method": "DELETE","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}'
|
||||||
|
|
||||||
response="$(_post "$_ovhdata" "$OVH_API/auth/credential")"
|
response="$(_post "$_ovhdata" "$OVH_API/auth/credential")"
|
||||||
_debug3 response "$response"
|
_debug3 response "$response"
|
||||||
@ -279,15 +302,15 @@ _ovh_rest() {
|
|||||||
export _H3="X-Ovh-Timestamp: $_ovh_t"
|
export _H3="X-Ovh-Timestamp: $_ovh_t"
|
||||||
export _H4="X-Ovh-Consumer: $OVH_CK"
|
export _H4="X-Ovh-Consumer: $OVH_CK"
|
||||||
export _H5="Content-Type: application/json;charset=utf-8"
|
export _H5="Content-Type: application/json;charset=utf-8"
|
||||||
if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ]; then
|
if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] || [ "$m" = "DELETE" ]; then
|
||||||
_debug data "$data"
|
_debug data "$data"
|
||||||
response="$(_post "$data" "$_ovh_url" "" "$m")"
|
response="$(_post "$data" "$_ovh_url" "" "$m")"
|
||||||
else
|
else
|
||||||
response="$(_get "$_ovh_url")"
|
response="$(_get "$_ovh_url")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$?" != "0" ]; then
|
if [ "$?" != "0" ] || _contains "$response" "INVALID_CREDENTIAL"; then
|
||||||
_err "error $ep"
|
_err "error $response"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_debug2 response "$response"
|
_debug2 response "$response"
|
||||||
|
161
dnsapi/dns_selectel.sh
Normal file
161
dnsapi/dns_selectel.sh
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#
|
||||||
|
#SL_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||||
|
#
|
||||||
|
|
||||||
|
SL_Api="https://api.selectel.ru/domains/v1"
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_selectel_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
SL_Key="${SL_Key:-$(_readaccountconf_mutable SL_Key)}"
|
||||||
|
|
||||||
|
if [ -z "$SL_Key" ]; then
|
||||||
|
SL_Key=""
|
||||||
|
_err "You don't specify selectel.ru api key yet."
|
||||||
|
_err "Please create you key and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#save the api key to the account conf file.
|
||||||
|
_saveaccountconf_mutable SL_Key "$SL_Key"
|
||||||
|
|
||||||
|
_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"
|
||||||
|
|
||||||
|
_info "Adding record"
|
||||||
|
if _sl_rest POST "/$_domain_id/records/" "{\"type\": \"TXT\", \"ttl\": 60, \"name\": \"$fulldomain\", \"content\": \"$txtvalue\"}"; then
|
||||||
|
if _contains "$response" "$txtvalue" || _contains "$response" "record_already_exists"; then
|
||||||
|
_info "Added, OK"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
_err "Add txt record error."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#fulldomain txtvalue
|
||||||
|
dns_selectel_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
SL_Key="${SL_Key:-$(_readaccountconf_mutable SL_Key)}"
|
||||||
|
|
||||||
|
if [ -z "$SL_Key" ]; then
|
||||||
|
SL_Key=""
|
||||||
|
_err "You don't specify slectel api key yet."
|
||||||
|
_err "Please create you 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 _domain_id "$_domain_id"
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
_debug "Getting txt records"
|
||||||
|
_sl_rest GET "/${_domain_id}/records/"
|
||||||
|
|
||||||
|
if ! _contains "$response" "$txtvalue"; then
|
||||||
|
_err "Txt record not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_record_seg="$(echo "$response" | _egrep_o "\"content\" *: *\"$txtvalue\"[^}]*}")"
|
||||||
|
_debug2 "_record_seg" "$_record_seg"
|
||||||
|
if [ -z "$_record_seg" ]; then
|
||||||
|
_err "can not find _record_seg"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_record_id="$(echo "$_record_seg" | tr "," "\n" | tr "}" "\n" | tr -d " " | grep "\"id\"" | cut -d : -f 2)"
|
||||||
|
_debug2 "_record_id" "$_record_id"
|
||||||
|
if [ -z "$_record_id" ]; then
|
||||||
|
_err "can not find _record_id"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _sl_rest DELETE "/$_domain_id/records/$_record_id"; then
|
||||||
|
_err "Delete record error."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### 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 ! _sl_rest GET "/"; 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" "\"name\": \"$h\","; then
|
||||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||||
|
_domain=$h
|
||||||
|
_debug "Getting domain id for $h"
|
||||||
|
if ! _sl_rest GET "/$h"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_domain_id="$(echo "$response" | tr "," "\n" | tr "}" "\n" | tr -d " " | grep "\"id\":" | cut -d : -f 2)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
p=$i
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_sl_rest() {
|
||||||
|
m=$1
|
||||||
|
ep="$2"
|
||||||
|
data="$3"
|
||||||
|
_debug "$ep"
|
||||||
|
|
||||||
|
export _H1="X-Token: $SL_Key"
|
||||||
|
export _H2="Content-Type: application/json"
|
||||||
|
|
||||||
|
if [ "$m" != "GET" ]; then
|
||||||
|
_debug data "$data"
|
||||||
|
response="$(_post "$data" "$SL_Api/$ep" "" "$m")"
|
||||||
|
else
|
||||||
|
response="$(_get "$SL_Api/$ep")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error $ep"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
170
dnsapi/dns_servercow.sh
Executable file
170
dnsapi/dns_servercow.sh
Executable file
@ -0,0 +1,170 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
##########
|
||||||
|
# Custom servercow.de DNS API v1 for use with [acme.sh](https://github.com/Neilpang/acme.sh)
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# export SERVERCOW_API_Username=username
|
||||||
|
# export SERVERCOW_API_Password=password
|
||||||
|
# acme.sh --issue -d example.com --dns dns_servercow
|
||||||
|
#
|
||||||
|
# Issues:
|
||||||
|
# Any issues / questions / suggestions can be posted here:
|
||||||
|
# https://github.com/jhartlep/servercow-dns-api/issues
|
||||||
|
#
|
||||||
|
# Author: Jens Hartlep
|
||||||
|
##########
|
||||||
|
|
||||||
|
SERVERCOW_API="https://api.servercow.de/dns/v1/domains"
|
||||||
|
|
||||||
|
# Usage dns_servercow_add _acme-challenge.www.domain.com "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
dns_servercow_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
_info "Using servercow"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}"
|
||||||
|
SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}"
|
||||||
|
if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then
|
||||||
|
SERVERCOW_API_Username=""
|
||||||
|
SERVERCOW_API_Password=""
|
||||||
|
_err "You don't specify servercow api username and password yet."
|
||||||
|
_err "Please create your username and password and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# save the credentials to the account conf file
|
||||||
|
_saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username"
|
||||||
|
_saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_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 _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; 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_servercow_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
_info "Using servercow"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$fulldomain"
|
||||||
|
|
||||||
|
SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}"
|
||||||
|
SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}"
|
||||||
|
if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then
|
||||||
|
SERVERCOW_API_Username=""
|
||||||
|
SERVERCOW_API_Password=""
|
||||||
|
_err "You don't specify servercow api username and password yet."
|
||||||
|
_err "Please create your username and 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 _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then
|
||||||
|
if printf -- "%s" "$response" | grep "ok" >/dev/null; then
|
||||||
|
_info "Deleted, OK"
|
||||||
|
_contains "$response" '"message":"ok"'
|
||||||
|
else
|
||||||
|
_err "delete txt record error."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### 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
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
_domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100)
|
||||||
|
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
if [ -z "$_domain" ]; then
|
||||||
|
# not valid
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _servercow_api GET "$_domain"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _contains "$response" '"error":"no such domain in user context"' >/dev/null; then
|
||||||
|
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p)
|
||||||
|
if [ -z "$_sub_domain" ]; then
|
||||||
|
# not valid
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
p=$i
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_servercow_api() {
|
||||||
|
method=$1
|
||||||
|
domain=$2
|
||||||
|
data="$3"
|
||||||
|
|
||||||
|
export _H1="Content-Type: application/json"
|
||||||
|
export _H2="X-Auth-Username: $SERVERCOW_API_Username"
|
||||||
|
export _H3="X-Auth-Password: $SERVERCOW_API_Password"
|
||||||
|
|
||||||
|
if [ "$method" != "GET" ]; then
|
||||||
|
_debug data "$data"
|
||||||
|
response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")"
|
||||||
|
else
|
||||||
|
response="$(_get "$SERVERCOW_API/$domain")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error $domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
202
dnsapi/dns_unoeuro.sh
Normal file
202
dnsapi/dns_unoeuro.sh
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#
|
||||||
|
#UNO_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||||
|
#
|
||||||
|
#UNO_User="UExxxxxx"
|
||||||
|
|
||||||
|
Uno_Api="https://api.unoeuro.com/1"
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_unoeuro_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}"
|
||||||
|
UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}"
|
||||||
|
if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then
|
||||||
|
UNO_Key=""
|
||||||
|
UNO_User=""
|
||||||
|
_err "You haven't specified a UnoEuro api key and account yet."
|
||||||
|
_err "Please create your key and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _contains "$UNO_User" "UE"; then
|
||||||
|
_err "It seems that the UNO_User=$UNO_User is not a valid username."
|
||||||
|
_err "Please check and retry."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#save the api key and email to the account conf file.
|
||||||
|
_saveaccountconf_mutable UNO_Key "$UNO_Key"
|
||||||
|
_saveaccountconf_mutable UNO_User "$UNO_User"
|
||||||
|
|
||||||
|
_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"
|
||||||
|
_uno_rest GET "my/products/$h/dns/records"
|
||||||
|
|
||||||
|
if ! _contains "$response" "\"status\": 200" >/dev/null; then
|
||||||
|
_err "Error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
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 _contains "$response" "\"status\": 200" >/dev/null; then
|
||||||
|
_info "Updated, OK"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
_err "Update error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#fulldomain txtvalue
|
||||||
|
dns_unoeuro_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}"
|
||||||
|
UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}"
|
||||||
|
if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then
|
||||||
|
UNO_Key=""
|
||||||
|
UNO_User=""
|
||||||
|
_err "You haven't specified a UnoEuro api key and account yet."
|
||||||
|
_err "Please create your key and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _contains "$UNO_User" "UE"; then
|
||||||
|
_err "It seems that the UNO_User=$UNO_User is not a valid username."
|
||||||
|
_err "Please check and retry."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_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"
|
||||||
|
_uno_rest GET "my/products/$h/dns/records"
|
||||||
|
|
||||||
|
if ! _contains "$response" "\"status\": 200"; then
|
||||||
|
_err "Error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
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"
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### 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)
|
||||||
|
_debug h "$h"
|
||||||
|
if [ -z "$h" ]; then
|
||||||
|
#not valid
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _uno_rest GET "my/products/$h/dns/records"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$response" "\"status\": 200"; then
|
||||||
|
_domain_id=$h
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
_uno_rest() {
|
||||||
|
m=$1
|
||||||
|
ep="$2"
|
||||||
|
data="$3"
|
||||||
|
_debug "$ep"
|
||||||
|
|
||||||
|
export _H1="Content-Type: application/json"
|
||||||
|
|
||||||
|
if [ "$m" != "GET" ]; then
|
||||||
|
_debug data "$data"
|
||||||
|
response="$(_post "$data" "$Uno_Api/$UNO_User/$UNO_Key/$ep" "" "$m")"
|
||||||
|
else
|
||||||
|
response="$(_get "$Uno_Api/$UNO_User/$UNO_Key/$ep")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error $ep"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
@ -16,9 +16,8 @@ dns_yandex_add() {
|
|||||||
_PDD_credentials || return 1
|
_PDD_credentials || return 1
|
||||||
export _H1="PddToken: $PDD_Token"
|
export _H1="PddToken: $PDD_Token"
|
||||||
|
|
||||||
curDomain=$(_PDD_get_domain "$fulldomain")
|
_PDD_get_domain "$fulldomain"
|
||||||
_debug "Found suitable domain in pdd: $curDomain"
|
_debug "Found suitable domain in pdd: $curDomain"
|
||||||
curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")"
|
|
||||||
curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}"
|
curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}"
|
||||||
curUri="https://pddimp.yandex.ru/api2/admin/dns/add"
|
curUri="https://pddimp.yandex.ru/api2/admin/dns/add"
|
||||||
curResult="$(_post "${curData}" "${curUri}")"
|
curResult="$(_post "${curData}" "${curUri}")"
|
||||||
@ -34,9 +33,8 @@ dns_yandex_rm() {
|
|||||||
record_id=$(pdd_get_record_id "${fulldomain}")
|
record_id=$(pdd_get_record_id "${fulldomain}")
|
||||||
_debug "Result: $record_id"
|
_debug "Result: $record_id"
|
||||||
|
|
||||||
curDomain=$(_PDD_get_domain "$fulldomain")
|
_PDD_get_domain "$fulldomain"
|
||||||
_debug "Found suitable domain in pdd: $curDomain"
|
_debug "Found suitable domain in pdd: $curDomain"
|
||||||
curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")"
|
|
||||||
|
|
||||||
curUri="https://pddimp.yandex.ru/api2/admin/dns/del"
|
curUri="https://pddimp.yandex.ru/api2/admin/dns/del"
|
||||||
curData="domain=${curDomain}&record_id=${record_id}"
|
curData="domain=${curDomain}&record_id=${record_id}"
|
||||||
@ -61,7 +59,7 @@ _PDD_get_domain() {
|
|||||||
__last=1
|
__last=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
__all_domains="$__all_domains $(echo "$res1" | sed -e "s@,@\n@g" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')"
|
__all_domains="$__all_domains $(echo "$res1" | tr "," "\n" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')"
|
||||||
|
|
||||||
__page=$(_math $__page + 1)
|
__page=$(_math $__page + 1)
|
||||||
done
|
done
|
||||||
@ -72,8 +70,10 @@ _PDD_get_domain() {
|
|||||||
_debug "finding zone for domain $__t"
|
_debug "finding zone for domain $__t"
|
||||||
for d in $__all_domains; do
|
for d in $__all_domains; do
|
||||||
if [ "$d" = "$__t" ]; then
|
if [ "$d" = "$__t" ]; then
|
||||||
echo "$__t"
|
p=$(_math $k - 1)
|
||||||
return
|
curSubdomain="$(echo "$fulldomain" | cut -d . -f "1-$p")"
|
||||||
|
curDomain="$__t"
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
k=$(_math $k + 1)
|
k=$(_math $k + 1)
|
||||||
@ -96,9 +96,8 @@ _PDD_credentials() {
|
|||||||
pdd_get_record_id() {
|
pdd_get_record_id() {
|
||||||
fulldomain="${1}"
|
fulldomain="${1}"
|
||||||
|
|
||||||
curDomain=$(_PDD_get_domain "$fulldomain")
|
_PDD_get_domain "$fulldomain"
|
||||||
_debug "Found suitable domain in pdd: $curDomain"
|
_debug "Found suitable domain in pdd: $curDomain"
|
||||||
curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")"
|
|
||||||
|
|
||||||
curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}"
|
curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}"
|
||||||
curResult="$(_get "${curUri}" | _normalizeJson)"
|
curResult="$(_get "${curUri}" | _normalizeJson)"
|
||||||
|
85
dnsapi/dns_zonomi.sh
Normal file
85
dnsapi/dns_zonomi.sh
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#
|
||||||
|
#ZM_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||||
|
#
|
||||||
|
#https://zonomi.com dns api
|
||||||
|
|
||||||
|
ZM_Api="https://zonomi.com/app/dns/dyndns.jsp"
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_zonomi_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
ZM_Key="${ZM_Key:-$(_readaccountconf_mutable ZM_Key)}"
|
||||||
|
|
||||||
|
if [ -z "$ZM_Key" ]; then
|
||||||
|
ZM_Key=""
|
||||||
|
_err "You don't specify zonomi api key yet."
|
||||||
|
_err "Please create your key and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#save the api key to the account conf file.
|
||||||
|
_saveaccountconf_mutable ZM_Key "$ZM_Key"
|
||||||
|
|
||||||
|
_info "Get existing txt records for $fulldomain"
|
||||||
|
if ! _zm_request "action=QUERY&name=$fulldomain"; then
|
||||||
|
_err "error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$response" "<record"; then
|
||||||
|
_debug "get and update records"
|
||||||
|
_qstr="action[1]=SET&type[1]=TXT&name[1]=$fulldomain&value[1]=$txtvalue"
|
||||||
|
_qindex=2
|
||||||
|
for t in $(echo "$response" | tr -d "\r\n" | _egrep_o '<action.*</action>' | tr "<" "\n" | grep record | grep 'type="TXT"' | cut -d '"' -f 6); do
|
||||||
|
_debug2 t "$t"
|
||||||
|
_qstr="$_qstr&action[$_qindex]=SET&type[$_qindex]=TXT&name[$_qindex]=$fulldomain&value[$_qindex]=$t"
|
||||||
|
_qindex="$(_math "$_qindex" + 1)"
|
||||||
|
done
|
||||||
|
_zm_request "$_qstr"
|
||||||
|
else
|
||||||
|
_debug "Just add record"
|
||||||
|
_zm_request "action=SET&type=TXT&name=$fulldomain&value=$txtvalue"
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#fulldomain txtvalue
|
||||||
|
dns_zonomi_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
ZM_Key="${ZM_Key:-$(_readaccountconf_mutable ZM_Key)}"
|
||||||
|
if [ -z "$ZM_Key" ]; then
|
||||||
|
ZM_Key=""
|
||||||
|
_err "You don't specify zonomi api key yet."
|
||||||
|
_err "Please create your key and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_zm_request "action=DELETE&type=TXT&name=$fulldomain"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
#qstr
|
||||||
|
_zm_request() {
|
||||||
|
qstr="$1"
|
||||||
|
|
||||||
|
_debug2 "qstr" "$qstr"
|
||||||
|
|
||||||
|
_zm_url="$ZM_Api?api_key=$ZM_Key&$qstr"
|
||||||
|
_debug2 "_zm_url" "$_zm_url"
|
||||||
|
response="$(_get "$_zm_url")"
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
_contains "$response" "<is_ok>OK:"
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user