mirror of
				https://github.com/hiskang/acme.sh
				synced 2025-10-31 10:27:22 +00:00 
			
		
		
		
	
						commit
						6e2669ed1d
					
				
							
								
								
									
										4
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,6 @@ | |||||||
| <!-- | <!-- | ||||||
|  | 请确保已经更新到最新的代码, 然后贴上来 `--debug 2` 的调试输出. 没有调试输出,我帮不了你. | ||||||
|  | 如何调试 https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh | ||||||
| 
 | 
 | ||||||
| If it is a bug report: | If it is a bug report: | ||||||
| - make sure you are able to repro it on the latest released version.  | - make sure you are able to repro it on the latest released version.  | ||||||
| @ -8,13 +10,11 @@ You can install the latest version by: `acme.sh --upgrade` | |||||||
| - Refer to the [WIKI](https://wiki.acme.sh). | - Refer to the [WIKI](https://wiki.acme.sh). | ||||||
| - Debug info [Debug](https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh). | - Debug info [Debug](https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh). | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| --> | --> | ||||||
| 
 | 
 | ||||||
| Steps to reproduce | Steps to reproduce | ||||||
| ------------------ | ------------------ | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| Debug log | Debug log | ||||||
| ----------------- | ----------------- | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							| @ -1,14 +1,9 @@ | |||||||
| <!-- | <!-- | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Do NOT send pull request to `master` branch. | Do NOT send pull request to `master` branch. | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| Please send to `dev` branch instead. | Please send to `dev` branch instead. | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| Any PR to `master` branch will NOT be merged. | Any PR to `master` branch will NOT be merged. | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| --> | --> | ||||||
							
								
								
									
										39
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								.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 | ||||||
| @ -17,35 +21,24 @@ addons: | |||||||
|     - shellcheck |     - shellcheck | ||||||
| 
 | 
 | ||||||
| install: | install: | ||||||
|   - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then  |   - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then | ||||||
|       brew update && brew install openssl; |       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 OPENSSL_BIN="/usr/local/openssl"; |  | ||||||
|       openssl version 2>&1 || true; |  | ||||||
|       $OPENSSL_BIN version 2>&1 || true; |  | ||||||
|       export PATH="$_old_path"; |  | ||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
| script: | script: | ||||||
|   - echo "TEST_LOCAL=$TEST_LOCAL" |  | ||||||
|   - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" |   - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" | ||||||
|   - which openssl && openssl version |   - command -V openssl && openssl version | ||||||
|   - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi |   - if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi | ||||||
|   - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi |   - if [ "$TRAVIS_OS_NAME" = "linux" ]; then chmod +x ~/shfmt ; fi | ||||||
|   - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi |   - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi | ||||||
|   - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi |   - if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi | ||||||
|   - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi |   - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi | ||||||
|   - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.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" ]] && [[ "$NGROK_TOKEN" ]]; then sudo 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" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi |   - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| matrix: | matrix: | ||||||
|  | |||||||
							
								
								
									
										63
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | |||||||
|  | FROM alpine:3.6 | ||||||
|  | 
 | ||||||
|  | RUN apk update -f \ | ||||||
|  |   && apk --no-cache add -f \ | ||||||
|  |   openssl \ | ||||||
|  |   curl \ | ||||||
|  |   socat \ | ||||||
|  |   && rm -rf /var/cache/apk/* | ||||||
|  | 
 | ||||||
|  | ENV LE_CONFIG_HOME /acme.sh | ||||||
|  | 
 | ||||||
|  | ENV AUTO_UPGRADE 1 | ||||||
|  | 
 | ||||||
|  | #Install | ||||||
|  | ADD ./ /install_acme.sh/ | ||||||
|  | RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | RUN ln -s  /root/.acme.sh/acme.sh  /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab - | ||||||
|  | 
 | ||||||
|  | RUN for verb in help \  | ||||||
|  |   version \ | ||||||
|  |   install \ | ||||||
|  |   uninstall \ | ||||||
|  |   upgrade \ | ||||||
|  |   issue \ | ||||||
|  |   signcsr \ | ||||||
|  |   deploy \ | ||||||
|  |   install-cert \ | ||||||
|  |   renew \ | ||||||
|  |   renew-all \ | ||||||
|  |   revoke \ | ||||||
|  |   remove \ | ||||||
|  |   list \ | ||||||
|  |   showcsr \ | ||||||
|  |   install-cronjob \ | ||||||
|  |   uninstall-cronjob \ | ||||||
|  |   cron \ | ||||||
|  |   toPkcs \ | ||||||
|  |   toPkcs8 \ | ||||||
|  |   update-account \ | ||||||
|  |   register-account \ | ||||||
|  |   create-account-key \ | ||||||
|  |   create-domain-key \ | ||||||
|  |   createCSR \ | ||||||
|  |   deactivate \ | ||||||
|  |   deactivate-account \ | ||||||
|  |   ; do \ | ||||||
|  |     printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \ | ||||||
|  |   ; done | ||||||
|  | 
 | ||||||
|  | RUN printf "%b" '#!'"/usr/bin/env sh\n \ | ||||||
|  | if [ \"\$1\" = \"daemon\" ];  then \n \ | ||||||
|  |  trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \ | ||||||
|  |  crond && while true; do sleep 1; done;\n \ | ||||||
|  | else \n \ | ||||||
|  |  exec -- \"\$@\"\n \ | ||||||
|  | fi" >/entry.sh && chmod +x /entry.sh | ||||||
|  | 
 | ||||||
|  | VOLUME /acme.sh | ||||||
|  | 
 | ||||||
|  | ENTRYPOINT ["/entry.sh"] | ||||||
|  | CMD ["--help"] | ||||||
							
								
								
									
										151
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										151
									
								
								README.md
									
									
									
									
									
								
							| @ -1,4 +1,6 @@ | |||||||
| # An ACME Shell script: acme.sh [](https://travis-ci.org/Neilpang/acme.sh) | # An ACME Shell script: acme.sh [](https://travis-ci.org/Neilpang/acme.sh) | ||||||
|  | 
 | ||||||
|  | [](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. | ||||||
| - 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. | ||||||
| @ -7,14 +9,33 @@ | |||||||
| - Purely written in Shell with no dependencies on python or the official Let's Encrypt client. | - Purely written in Shell with no dependencies on python or the official Let's Encrypt client. | ||||||
| - Just one script to issue, renew and install your certificates automatically. | - Just one script to issue, renew and install your certificates automatically. | ||||||
| - DOES NOT require `root/sudoer` access. | - DOES NOT require `root/sudoer` access. | ||||||
|  | - Docker friendly | ||||||
|  | - IPv6 support | ||||||
| 
 | 
 | ||||||
| It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. | It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. | ||||||
| 
 | 
 | ||||||
| Wiki: https://github.com/Neilpang/acme.sh/wiki | Wiki: https://github.com/Neilpang/acme.sh/wiki | ||||||
| 
 | 
 | ||||||
|  | For Docker Fans: [acme.sh :two_hearts: Docker ](https://github.com/Neilpang/acme.sh/wiki/Run-acme.sh-in-docker) | ||||||
|  | 
 | ||||||
|  | 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** | ||||||
|  | - [FreeBSD.org](https://blog.crashed.org/letsencrypt-in-freebsd-org/) | ||||||
|  | - [ruby-china.org](https://ruby-china.org/topics/31983) | ||||||
|  | - [Proxmox](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x_and_newer)) | ||||||
|  | - [pfsense](https://github.com/pfsense/FreeBSD-ports/pull/89) | ||||||
|  | - [webfaction](https://community.webfaction.com/questions/19988/using-letsencrypt) | ||||||
|  | - [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty) | ||||||
|  | - [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709) | ||||||
|  | - [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html) | ||||||
|  | - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) | ||||||
|  | - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) | ||||||
|  | - [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient) | ||||||
|  | - [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) | ||||||
| 
 | 
 | ||||||
| # Tested OS | # Tested OS | ||||||
| 
 | 
 | ||||||
| @ -39,8 +60,9 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki | |||||||
| |17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT) | |17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT) | ||||||
| |18|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris | |18|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris | ||||||
| |19|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux | |19|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux | ||||||
|  | |20|[](https://travis-ci.org/Neilpang/acme.sh)|Mac OSX | ||||||
| 
 | 
 | ||||||
| For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): | For all build statuses, check our [weekly build project](https://github.com/Neilpang/acmetest): | ||||||
| 
 | 
 | ||||||
| https://github.com/Neilpang/acmetest | https://github.com/Neilpang/acmetest | ||||||
| 
 | 
 | ||||||
| @ -50,7 +72,9 @@ https://github.com/Neilpang/acmetest | |||||||
| - Webroot mode | - Webroot mode | ||||||
| - Standalone mode | - Standalone mode | ||||||
| - Apache mode | - Apache mode | ||||||
|  | - Nginx mode ( Beta ) | ||||||
| - DNS mode | - DNS mode | ||||||
|  | - [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # 1. How to install | # 1. How to install | ||||||
| @ -115,13 +139,25 @@ root@v1:~# acme.sh -h | |||||||
| acme.sh --issue -d example.com -w /home/wwwroot/example.com | acme.sh --issue -d example.com -w /home/wwwroot/example.com | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | or: | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | acme.sh --issue -d example.com -w /home/username/public_html | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | or: | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | acme.sh --issue -d example.com -w /var/www/html | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| **Example 2:** Multiple domains in the same cert. | **Example 2:** Multiple domains in the same cert. | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| acme.sh --issue -d example.com -d www.example.com -d cp.example.com -w /home/wwwroot/example.com | acme.sh --issue -d example.com -d www.example.com -d cp.example.com -w /home/wwwroot/example.com | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| The parameter `/home/wwwroot/example.com` is the web root folder. You **MUST** have `write access` to this folder. | The parameter `/home/wwwroot/example.com` or `/home/username/public_html` or `/var/www/html` is the web root folder where you host your website files. You **MUST** have `write access` to this folder. | ||||||
| 
 | 
 | ||||||
| Second argument **"example.com"** is the main domain you want to issue the cert for. | Second argument **"example.com"** is the main domain you want to issue the cert for. | ||||||
| You must have at least one domain there. | You must have at least one domain there. | ||||||
| @ -142,26 +178,28 @@ You **MUST** use this command to copy the certs to the target files, **DO NOT** | |||||||
| 
 | 
 | ||||||
| **Apache** example: | **Apache** example: | ||||||
| ```bash | ```bash | ||||||
| acme.sh --installcert -d example.com \ | acme.sh --install-cert -d example.com \ | ||||||
| --certpath      /path/to/certfile/in/apache/cert.pem  \ | --cert-file      /path/to/certfile/in/apache/cert.pem  \ | ||||||
| --keypath       /path/to/keyfile/in/apache/key.pem  \ | --key-file       /path/to/keyfile/in/apache/key.pem  \ | ||||||
| --fullchainpath /path/to/fullchain/certfile/apache/fullchain.pem \ | --fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \ | ||||||
| --reloadcmd     "service apache2 restart" | --reloadcmd     "service apache2 force-reload" | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| **Nginx** example: | **Nginx** example: | ||||||
| ```bash | ```bash | ||||||
| acme.sh --installcert -d example.com \ | acme.sh --install-cert -d example.com \ | ||||||
| --keypath       /path/to/keyfile/in/nginx/key.pem  \ | --key-file       /path/to/keyfile/in/nginx/key.pem  \ | ||||||
| --fullchainpath /path/to/fullchain/nginx/cert.pem \ | --fullchain-file /path/to/fullchain/nginx/cert.pem \ | ||||||
| --reloadcmd     "service nginx restart" | --reloadcmd     "service nginx force-reload" | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| 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. | ||||||
|  | 
 | ||||||
| Install/copy the issued cert/key to the production Apache or Nginx path. | Install/copy the issued 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 restarted automatically by the command: `service apache2 restart` or `service nginx restart`. | 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`. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # 4. Use Standalone server to issue cert | # 4. Use Standalone server to issue cert | ||||||
| @ -208,8 +246,27 @@ acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com | |||||||
| 
 | 
 | ||||||
| More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert | More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert | ||||||
| 
 | 
 | ||||||
|  | # 7. Use Nginx mode | ||||||
| 
 | 
 | ||||||
| # 7. Use DNS mode: | **(requires you to be root/sudoer, since it is required to interact with Nginx server)** | ||||||
|  | 
 | ||||||
|  | If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`. | ||||||
|  | 
 | ||||||
|  | Particularly, if you are running an nginx server, you can use nginx mode instead. This mode doesn't write any files to your web root folder. | ||||||
|  | 
 | ||||||
|  | Just set string "nginx" as the second argument. | ||||||
|  | 
 | ||||||
|  | It will configure nginx server automatically to verify the domain and then restore the nginx config to the original version. | ||||||
|  | 
 | ||||||
|  | So, the config is not changed. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert | ||||||
|  | 
 | ||||||
|  | # 8. Use DNS mode: | ||||||
| 
 | 
 | ||||||
| Support the `dns-01` challenge. | Support the `dns-01` challenge. | ||||||
| 
 | 
 | ||||||
| @ -239,8 +296,11 @@ acme.sh --renew -d example.com | |||||||
| 
 | 
 | ||||||
| Ok, it's finished. | 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.** | ||||||
| 
 | 
 | ||||||
| # 8. Automatic DNS API integration | **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. | ||||||
| 
 | 
 | ||||||
| @ -252,16 +312,44 @@ You don't have to do anything manually! | |||||||
| 1. DNSPod.cn API | 1. DNSPod.cn API | ||||||
| 1. CloudXNS.com API | 1. CloudXNS.com API | ||||||
| 1. GoDaddy.com API | 1. GoDaddy.com API | ||||||
| 1. OVH, kimsufi, soyoustart and runabove API |  | ||||||
| 1. AWS Route 53 |  | ||||||
| 1. PowerDNS.com API | 1. PowerDNS.com API | ||||||
| 1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api | 1. OVH, kimsufi, soyoustart and runabove API | ||||||
|    (DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.) | 1. nsupdate API | ||||||
| 1. LuaDNS.com API | 1. LuaDNS.com API | ||||||
| 1. DNSMadeEasy.com API | 1. DNSMadeEasy.com API | ||||||
| 1. nsupdate API | 1. AWS Route 53 | ||||||
| 1. aliyun.com(阿里云) API | 1. aliyun.com(阿里云) API | ||||||
| 1. ISPConfig 3.1 API | 1. ISPConfig 3.1 API | ||||||
|  | 1. Alwaysdata.com API | ||||||
|  | 1. Linode.com API | ||||||
|  | 1. FreeDNS (https://freedns.afraid.org/) | ||||||
|  | 1. cyon.ch | ||||||
|  | 1. Domain-Offensive/Resellerinterface/Domainrobot API | ||||||
|  | 1. Gandi LiveDNS API | ||||||
|  | 1. Knot DNS API | ||||||
|  | 1. DigitalOcean API (native) | ||||||
|  | 1. ClouDNS.net API | ||||||
|  | 1. Infoblox NIOS API (https://www.infoblox.com/) | ||||||
|  | 1. VSCALE (https://vscale.io/) | ||||||
|  | 1. Dynu API (https://www.dynu.com) | ||||||
|  | 1. DNSimple API | ||||||
|  | 1. NS1.com API | ||||||
|  | 1. DuckDNS.org API | ||||||
|  | 1. Name.com API | ||||||
|  | 1. Dyn Managed DNS API | ||||||
|  | 1. Yandex PDD API (https://pdd.yandex.ru) | ||||||
|  | 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) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | And:  | ||||||
|  | 
 | ||||||
|  | 1. 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.) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     |     | ||||||
| **More APIs coming soon...** | **More APIs coming soon...** | ||||||
| 
 | 
 | ||||||
| @ -270,7 +358,7 @@ If your DNS provider is not on the supported list above, you can write your own | |||||||
| For more details: [How to use DNS API](dnsapi) | For more details: [How to use DNS API](dnsapi) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # 9. Issue ECC certificates | # 10. Issue ECC certificates | ||||||
| 
 | 
 | ||||||
| `Let's Encrypt` can now issue **ECDSA** certificates. | `Let's Encrypt` can now issue **ECDSA** certificates. | ||||||
| 
 | 
 | ||||||
| @ -280,7 +368,7 @@ Just set the `length` parameter with a prefix `ec-`. | |||||||
| 
 | 
 | ||||||
| For example: | For example: | ||||||
| 
 | 
 | ||||||
| ### Single domain ECC cerfiticate | ### Single domain ECC certificate | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| 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 --keylength ec-256 | ||||||
| @ -301,7 +389,7 @@ 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.)** | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # 10. How to renew the issued certs | # 11. How to renew the issued 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. | ||||||
| 
 | 
 | ||||||
| @ -318,9 +406,9 @@ acme.sh --renew -d example.com --force --ecc | |||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # 11. How to upgrade `acme.sh` | # 12. How to upgrade `acme.sh` | ||||||
| 
 | 
 | ||||||
| acme.sh is in constant developement, 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: | ||||||
| 
 | 
 | ||||||
| @ -343,26 +431,26 @@ acme.sh --upgrade --auto-upgrade 0 | |||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # 12. Issue a cert from an existing CSR | # 13. 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 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # Under the Hood | # 14. 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: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # Acknowledgments | # 15. 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 | 3. Certbot: https://github.com/certbot/certbot | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # License & Others | # 16. License & Others | ||||||
| 
 | 
 | ||||||
| License is GPLv3 | License is GPLv3 | ||||||
| 
 | 
 | ||||||
| @ -371,8 +459,9 @@ 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. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # Donate | # 17. Donate | ||||||
|  | Your donation makes **acme.sh** better: | ||||||
| 
 | 
 | ||||||
| 1. PayPal: donate@acme.sh | 1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/) | ||||||
|    |    | ||||||
| [Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list) | [Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list) | ||||||
|  | |||||||
							
								
								
									
										118
									
								
								deploy/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								deploy/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,118 @@ | |||||||
|  | # Using deploy api | ||||||
|  | 
 | ||||||
|  | Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). | ||||||
|  | 
 | ||||||
|  | Here are the scripts to deploy the certs/key to the server/services. | ||||||
|  | 
 | ||||||
|  | ## 1. Deploy the certs to your cpanel host | ||||||
|  | 
 | ||||||
|  | If you want to deploy using cpanel UAPI see 7. | ||||||
|  | 
 | ||||||
|  | (cpanel deploy hook is not finished yet, this is just an example.) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Then you can deploy now: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | export DEPLOY_CPANEL_USER=myusername | ||||||
|  | export DEPLOY_CPANEL_PASSWORD=PASSWORD | ||||||
|  | acme.sh --deploy -d example.com --deploy-hook cpanel | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 2. Deploy ssl cert on kong proxy engine based on api | ||||||
|  | 
 | ||||||
|  | Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). | ||||||
|  | Currently supports Kong-v0.10.x. | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | acme.sh --deploy -d ftp.example.com --deploy-hook kong | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 3. Deploy the cert to remote server through SSH access | ||||||
|  | 
 | ||||||
|  | (TODO) | ||||||
|  | 
 | ||||||
|  | ## 4. Deploy the cert to local vsftpd server | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The default vsftpd conf file is `/etc/vsftpd.conf`,  if your vsftpd conf is not in the default location, you can specify one: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | export DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf" | ||||||
|  | 
 | ||||||
|  | acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The default command to restart vsftpd server is `service vsftpd restart`, if it doesn't work, you can specify one: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | export DEPLOY_VSFTPD_RELOAD="/etc/init.d/vsftpd restart" | ||||||
|  | 
 | ||||||
|  | acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 5. Deploy the cert to local exim4 server | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | acme.sh --deploy -d ftp.example.com --deploy-hook exim4 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The default exim4 conf file is `/etc/exim/exim.conf`,  if your exim4 conf is not in the default location, you can specify one: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | export DEPLOY_EXIM4_CONF="/etc/exim4/exim4.conf.template" | ||||||
|  | 
 | ||||||
|  | acme.sh --deploy -d ftp.example.com --deploy-hook exim4 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The default command to restart exim4 server is `service exim4 restart`, if it doesn't work, you can specify one: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | export DEPLOY_EXIM4_RELOAD="/etc/init.d/exim4 restart" | ||||||
|  | 
 | ||||||
|  | acme.sh --deploy -d ftp.example.com --deploy-hook exim4 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 6. Deploy the cert to OSX Keychain | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | acme.sh --deploy -d ftp.example.com --deploy-hook keychain | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 7. Deploy to cpanel host using UAPI | ||||||
|  | 
 | ||||||
|  | This hook is using UAPI and works in cPanel & WHM version 56 or newer. | ||||||
|  | ``` | ||||||
|  | acme.sh  --deploy  -d example.com  --deploy-hook cpanel_uapi | ||||||
|  | ``` | ||||||
|  | DEPLOY_CPANEL_USER is required only if you run the script as root and it should contain cpanel username. | ||||||
|  | ```sh | ||||||
|  | export DEPLOY_CPANEL_USER=username | ||||||
|  | acme.sh  --deploy  -d example.com  --deploy-hook cpanel_uapi | ||||||
|  | ``` | ||||||
|  | Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separete certificate for each domain.  | ||||||
|  | 
 | ||||||
|  | ## 8. Deploy the cert to your FRITZ!Box router | ||||||
|  | 
 | ||||||
|  | You must specify the credentials that have administrative privileges on the FRITZ!Box in order to deploy the certificate, plus the URL of your FRITZ!Box, through the following environment variables: | ||||||
|  | ```sh | ||||||
|  | $ export DEPLOY_FRITZBOX_USERNAME=my_username | ||||||
|  | $ export DEPLOY_FRITZBOX_PASSWORD=the_password | ||||||
|  | $ export DEPLOY_FRITZBOX_URL=https://fritzbox.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | After the first deployment, these values will be stored in your $HOME/.acme.sh/account.conf. You may now deploy the certificate like this: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | acme.sh --deploy -d fritzbox.example.com --deploy-hook fritzbox | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 9. Deploy the cert to strongswan | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | acme.sh --deploy -d ftp.example.com --deploy-hook strongswan | ||||||
|  | ``` | ||||||
							
								
								
									
										26
									
								
								deploy/apache.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/apache.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a script to deploy cert to apache server. | ||||||
|  | 
 | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | apache_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" | ||||||
|  | 
 | ||||||
|  |   _err "Deploy cert to apache server, Not implemented yet" | ||||||
|  |   return 1 | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										64
									
								
								deploy/cpanel_uapi.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								deploy/cpanel_uapi.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | # Here is the script to deploy the cert to your cpanel using the cpanel API. | ||||||
|  | # Uses command line uapi.  --user option is needed only if run as root. | ||||||
|  | # Returns 0 when success. | ||||||
|  | # Written by Santeri Kannisto <santeri.kannisto@2globalnomads.info> | ||||||
|  | # Public domain, 2017 | ||||||
|  | 
 | ||||||
|  | #export DEPLOY_CPANEL_USER=myusername | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | 
 | ||||||
|  | cpanel_uapi_deploy() { | ||||||
|  |   _cdomain="$1" | ||||||
|  |   _ckey="$2" | ||||||
|  |   _ccert="$3" | ||||||
|  |   _cca="$4" | ||||||
|  |   _cfullchain="$5" | ||||||
|  | 
 | ||||||
|  |   _debug _cdomain "$_cdomain" | ||||||
|  |   _debug _ckey "$_ckey" | ||||||
|  |   _debug _ccert "$_ccert" | ||||||
|  |   _debug _cca "$_cca" | ||||||
|  |   _debug _cfullchain "$_cfullchain" | ||||||
|  | 
 | ||||||
|  |   if ! _exists uapi; then | ||||||
|  |     _err "The command uapi is not found." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   if ! _exists php; then | ||||||
|  |     _err "The command php is not found." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   # read cert and key files and urlencode both | ||||||
|  |   _certstr=$(cat "$_ccert") | ||||||
|  |   _keystr=$(cat "$_ckey") | ||||||
|  |   _cert=$(php -r "echo urlencode(\"$_certstr\");") | ||||||
|  |   _key=$(php -r "echo urlencode(\"$_keystr\");") | ||||||
|  | 
 | ||||||
|  |   _debug _cert "$_cert" | ||||||
|  |   _debug _key "$_key" | ||||||
|  | 
 | ||||||
|  |   if [ "$(id -u)" = 0 ]; then | ||||||
|  |     if [ -z "$DEPLOY_CPANEL_USER" ]; then | ||||||
|  |       _err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER" | ||||||
|  |     _response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") | ||||||
|  |   else | ||||||
|  |     _response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") | ||||||
|  |   fi | ||||||
|  |   error_response="status: 0" | ||||||
|  |   if test "${_response#*$error_response}" != "$_response"; then | ||||||
|  |     _err "Error in deploying certificate:" | ||||||
|  |     _err "$_response" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug response "$_response" | ||||||
|  |   _info "Certificate successfully deployed" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								deploy/dovecot.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/dovecot.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a script to deploy cert to dovecot server. | ||||||
|  | 
 | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | dovecot_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" | ||||||
|  | 
 | ||||||
|  |   _err "Not implemented yet" | ||||||
|  |   return 1 | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										114
									
								
								deploy/exim4.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								deploy/exim4.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,114 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a script to deploy cert to exim4 server. | ||||||
|  | 
 | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | #DEPLOY_EXIM4_CONF="/etc/exim/exim.conf" | ||||||
|  | #DEPLOY_EXIM4_RELOAD="service exim4 restart" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | exim4_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" | ||||||
|  | 
 | ||||||
|  |   _ssl_path="/etc/acme.sh/exim4" | ||||||
|  |   if ! mkdir -p "$_ssl_path"; then | ||||||
|  |     _err "Can not create folder:$_ssl_path" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Copying key and cert" | ||||||
|  |   _real_key="$_ssl_path/exim4.key" | ||||||
|  |   if ! cat "$_ckey" >"$_real_key"; then | ||||||
|  |     _err "Error: write key file to: $_real_key" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _real_fullchain="$_ssl_path/exim4.pem" | ||||||
|  |   if ! cat "$_cfullchain" >"$_real_fullchain"; then | ||||||
|  |     _err "Error: write key file to: $_real_fullchain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   DEFAULT_EXIM4_RELOAD="service exim4 restart" | ||||||
|  |   _reload="${DEPLOY_EXIM4_RELOAD:-$DEFAULT_EXIM4_RELOAD}" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$IS_RENEW" ]; then | ||||||
|  |     DEFAULT_EXIM4_CONF="/etc/exim/exim.conf" | ||||||
|  |     if [ ! -f "$DEFAULT_EXIM4_CONF" ]; then | ||||||
|  |       DEFAULT_EXIM4_CONF="/etc/exim4/exim4.conf.template" | ||||||
|  |     fi | ||||||
|  |     _exim4_conf="${DEPLOY_EXIM4_CONF:-$DEFAULT_EXIM4_CONF}" | ||||||
|  |     _debug _exim4_conf "$_exim4_conf" | ||||||
|  |     if [ ! -f "$_exim4_conf" ]; then | ||||||
|  |       if [ -z "$DEPLOY_EXIM4_CONF" ]; then | ||||||
|  |         _err "exim4 conf is not found, please define DEPLOY_EXIM4_CONF" | ||||||
|  |         return 1 | ||||||
|  |       else | ||||||
|  |         _err "It seems that the specified exim4 conf is not valid, please check." | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |     fi | ||||||
|  |     if [ ! -w "$_exim4_conf" ]; then | ||||||
|  |       _err "The file $_exim4_conf is not writable, please change the permission." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _backup_conf="$DOMAIN_BACKUP_PATH/exim4.conf.bak" | ||||||
|  |     _info "Backup $_exim4_conf to $_backup_conf" | ||||||
|  |     cp "$_exim4_conf" "$_backup_conf" | ||||||
|  | 
 | ||||||
|  |     _info "Modify exim4 conf: $_exim4_conf" | ||||||
|  |     if _setopt "$_exim4_conf" "tls_certificate" "=" "$_real_fullchain" \ | ||||||
|  |       && _setopt "$_exim4_conf" "tls_privatekey" "=" "$_real_key"; then | ||||||
|  |       _info "Set config success!" | ||||||
|  |     else | ||||||
|  |       _err "Config exim4 server error, please report bug to us." | ||||||
|  |       _info "Restoring exim4 conf" | ||||||
|  |       if cat "$_backup_conf" >"$_exim4_conf"; then | ||||||
|  |         _info "Restore conf success" | ||||||
|  |         eval "$_reload" | ||||||
|  |       else | ||||||
|  |         _err "Oops, error restore exim4 conf, please report bug to us." | ||||||
|  |       fi | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Run reload: $_reload" | ||||||
|  |   if eval "$_reload"; then | ||||||
|  |     _info "Reload success!" | ||||||
|  |     if [ "$DEPLOY_EXIM4_CONF" ]; then | ||||||
|  |       _savedomainconf DEPLOY_EXIM4_CONF "$DEPLOY_EXIM4_CONF" | ||||||
|  |     else | ||||||
|  |       _cleardomainconf DEPLOY_EXIM4_CONF | ||||||
|  |     fi | ||||||
|  |     if [ "$DEPLOY_EXIM4_RELOAD" ]; then | ||||||
|  |       _savedomainconf DEPLOY_EXIM4_RELOAD "$DEPLOY_EXIM4_RELOAD" | ||||||
|  |     else | ||||||
|  |       _cleardomainconf DEPLOY_EXIM4_RELOAD | ||||||
|  |     fi | ||||||
|  |     return 0 | ||||||
|  |   else | ||||||
|  |     _err "Reload error, restoring" | ||||||
|  |     if cat "$_backup_conf" >"$_exim4_conf"; then | ||||||
|  |       _info "Restore conf success" | ||||||
|  |       eval "$_reload" | ||||||
|  |     else | ||||||
|  |       _err "Oops, error restore exim4 conf, please report bug to us." | ||||||
|  |     fi | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   return 0 | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										108
									
								
								deploy/fritzbox.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								deploy/fritzbox.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,108 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a script to deploy cert to an AVM FRITZ!Box router. | ||||||
|  | 
 | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | #DEPLOY_FRITZBOX_USERNAME="username" | ||||||
|  | #DEPLOY_FRITZBOX_PASSWORD="password" | ||||||
|  | #DEPLOY_FRITZBOX_URL="https://fritz.box" | ||||||
|  | 
 | ||||||
|  | # Kudos to wikrie at Github for his FRITZ!Box update script: | ||||||
|  | # https://gist.github.com/wikrie/f1d5747a714e0a34d0582981f7cb4cfb | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | fritzbox_deploy() { | ||||||
|  |   _cdomain="$1" | ||||||
|  |   _ckey="$2" | ||||||
|  |   _ccert="$3" | ||||||
|  |   _cca="$4" | ||||||
|  |   _cfullchain="$5" | ||||||
|  | 
 | ||||||
|  |   _debug _cdomain "$_cdomain" | ||||||
|  |   _debug _ckey "$_ckey" | ||||||
|  |   _debug _ccert "$_ccert" | ||||||
|  |   _debug _cca "$_cca" | ||||||
|  |   _debug _cfullchain "$_cfullchain" | ||||||
|  | 
 | ||||||
|  |   if ! _exists iconv; then | ||||||
|  |     _err "iconv not found" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}" | ||||||
|  |   _fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}" | ||||||
|  |   _fritzbox_url="${DEPLOY_FRITZBOX_URL}" | ||||||
|  | 
 | ||||||
|  |   _debug _fritzbox_url "$_fritzbox_url" | ||||||
|  |   _debug _fritzbox_username "$_fritzbox_username" | ||||||
|  |   _secure_debug _fritzbox_password "$_fritzbox_password" | ||||||
|  |   if [ -z "$_fritzbox_username" ]; then | ||||||
|  |     _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   if [ -z "$_fritzbox_password" ]; then | ||||||
|  |     _err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   if [ -z "$_fritzbox_url" ]; then | ||||||
|  |     _err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}" | ||||||
|  |   _saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}" | ||||||
|  |   _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" | ||||||
|  | 
 | ||||||
|  |   # Do not check for a valid SSL certificate, because initially the cert is not valid, so it could not install the LE generated certificate | ||||||
|  |   export HTTPS_INSECURE=1 | ||||||
|  | 
 | ||||||
|  |   _info "Log in to the FRITZ!Box" | ||||||
|  |   _fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//')" | ||||||
|  |   _fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" | ||||||
|  |   _fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*<SID>//' -e 's/<\/SID>.*$//')" | ||||||
|  | 
 | ||||||
|  |   if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then | ||||||
|  |     _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Generate form POST request" | ||||||
|  |   _post_request="$(_mktemp)" | ||||||
|  |   _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" | ||||||
|  |   # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a password. But if they ever do, here's the place to use it! | ||||||
|  |   _CERTPASSWORD_= | ||||||
|  |   { | ||||||
|  |     printf -- "--" | ||||||
|  |     printf -- "%s\r\n" "${_post_boundary}" | ||||||
|  |     printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}" | ||||||
|  |     printf -- "--" | ||||||
|  |     printf -- "%s\r\n" "${_post_boundary}" | ||||||
|  |     printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}" | ||||||
|  |     printf -- "--" | ||||||
|  |     printf -- "%s\r\n" "${_post_boundary}" | ||||||
|  |     printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" | ||||||
|  |     printf "Content-Type: application/octet-stream\r\n\r\n" | ||||||
|  |     cat "${_ckey}" "${_cfullchain}" | ||||||
|  |     printf "\r\n" | ||||||
|  |     printf -- "--" | ||||||
|  |     printf -- "%s--" "${_post_boundary}" | ||||||
|  |   } >>"${_post_request}" | ||||||
|  | 
 | ||||||
|  |   _info "Upload certificate to the FRITZ!Box" | ||||||
|  | 
 | ||||||
|  |   export _H1="Content-type: multipart/form-data boundary=${_post_boundary}" | ||||||
|  |   _post "$(cat "${_post_request}")" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL | ||||||
|  | 
 | ||||||
|  |   retval=$? | ||||||
|  |   if [ $retval = 0 ]; then | ||||||
|  |     _info "Upload successful" | ||||||
|  |   else | ||||||
|  |     _err "Upload failed" | ||||||
|  |   fi | ||||||
|  |   rm "${_post_request}" | ||||||
|  | 
 | ||||||
|  |   return $retval | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								deploy/haproxy.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/haproxy.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a script to deploy cert to haproxy server. | ||||||
|  | 
 | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | haproxy_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" | ||||||
|  | 
 | ||||||
|  |   _err "deploy cert to haproxy server, Not implemented yet" | ||||||
|  |   return 1 | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								deploy/keychain.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								deploy/keychain.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a sample custom api script. | ||||||
|  | #This file name is "myapi.sh" | ||||||
|  | #So, here must be a method   myapi_deploy() | ||||||
|  | #Which will be called by acme.sh to deploy the cert | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | keychain_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" | ||||||
|  | 
 | ||||||
|  |   /usr/bin/security import "$_ckey" -k "/Library/Keychains/System.keychain" | ||||||
|  |   /usr/bin/security import "$_ccert" -k "/Library/Keychains/System.keychain" | ||||||
|  |   /usr/bin/security import "$_cca" -k "/Library/Keychains/System.keychain" | ||||||
|  |   /usr/bin/security import "$_cfullchain" -k "/Library/Keychains/System.keychain" | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
							
								
								
									
										77
									
								
								deploy/kong.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										77
									
								
								deploy/kong.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,77 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | # If certificate already exist it will update only cert and key not touching other parameter | ||||||
|  | # If certificate  doesn't exist it will only upload cert and key and not set other parameter | ||||||
|  | # Note that we deploy full chain | ||||||
|  | # Written by Geoffroi Genot <ggenot@voxbone.com> | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | kong_deploy() { | ||||||
|  |   _cdomain="$1" | ||||||
|  |   _ckey="$2" | ||||||
|  |   _ccert="$3" | ||||||
|  |   _cca="$4" | ||||||
|  |   _cfullchain="$5" | ||||||
|  |   _info "Deploying certificate on Kong instance" | ||||||
|  |   if [ -z "$KONG_URL" ]; then | ||||||
|  |     _debug "KONG_URL Not set, using default http://localhost:8001" | ||||||
|  |     KONG_URL="http://localhost:8001" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug _cdomain "$_cdomain" | ||||||
|  |   _debug _ckey "$_ckey" | ||||||
|  |   _debug _ccert "$_ccert" | ||||||
|  |   _debug _cca "$_cca" | ||||||
|  |   _debug _cfullchain "$_cfullchain" | ||||||
|  | 
 | ||||||
|  |   #Get ssl_uuid linked to the domain | ||||||
|  |   ssl_uuid=$(_get "$KONG_URL/certificates/$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') | ||||||
|  |   if [ -z "$ssl_uuid" ]; then | ||||||
|  |     _debug "Unable to get Kong ssl_uuid for domain $_cdomain" | ||||||
|  |     _debug "Make sure that KONG_URL is correctly configured" | ||||||
|  |     _debug "Make sure that a Kong certificate match the sni" | ||||||
|  |     _debug "Kong url: $KONG_URL" | ||||||
|  |     _info "No existing certificate, creating..." | ||||||
|  |     #return 1 | ||||||
|  |   fi | ||||||
|  |   #Save kong url if it's succesful (First run case) | ||||||
|  |   _saveaccountconf KONG_URL "$KONG_URL" | ||||||
|  |   #Generate DEIM | ||||||
|  |   delim="-----MultipartDelimiter$(date "+%s%N")" | ||||||
|  |   nl="\015\012" | ||||||
|  |   #Set Header | ||||||
|  |   _H1="Content-Type: multipart/form-data; boundary=$delim" | ||||||
|  |   #Generate data for request (Multipart/form-data with mixed content) | ||||||
|  |   if [ -z "$ssl_uuid" ]; then | ||||||
|  |     #set sni to domain | ||||||
|  |     content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" | ||||||
|  |   fi | ||||||
|  |   #add key | ||||||
|  |   content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" | ||||||
|  |   #Add cert | ||||||
|  |   content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")" | ||||||
|  |   #Close multipart | ||||||
|  |   content="$content${nl}--$delim--${nl}" | ||||||
|  |   #Convert CRLF | ||||||
|  |   content=$(printf %b "$content") | ||||||
|  |   #DEBUG | ||||||
|  |   _debug header "$_H1" | ||||||
|  |   _debug content "$content" | ||||||
|  |   #Check if sslcreated (if not => POST else => PATCH) | ||||||
|  | 
 | ||||||
|  |   if [ -z "$ssl_uuid" ]; then | ||||||
|  |     #Post certificate to Kong | ||||||
|  |     response=$(_post "$content" "$KONG_URL/certificates" "" "POST") | ||||||
|  |   else | ||||||
|  |     #patch | ||||||
|  |     response=$(_post "$content" "$KONG_URL/certificates/$ssl_uuid" "" "PATCH") | ||||||
|  |   fi | ||||||
|  |   if ! [ "$(echo "$response" | _egrep_o "created_at")" = "created_at" ]; then | ||||||
|  |     _err "An error occurred with cert upload. Check response:" | ||||||
|  |     _err "$response" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug response "$response" | ||||||
|  |   _info "Certificate successfully deployed" | ||||||
|  | } | ||||||
							
								
								
									
										0
									
								
								deploy/myapi.sh
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								deploy/myapi.sh
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
								
								
									
										26
									
								
								deploy/mysqld.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/mysqld.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a script to deploy cert to mysqld server. | ||||||
|  | 
 | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | mysqld_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" | ||||||
|  | 
 | ||||||
|  |   _err "deploy cert to mysqld server, Not implemented yet" | ||||||
|  |   return 1 | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								deploy/nginx.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/nginx.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a script to deploy cert to nginx server. | ||||||
|  | 
 | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | nginx_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" | ||||||
|  | 
 | ||||||
|  |   _err "deploy cert to nginx server, Not implemented yet" | ||||||
|  |   return 1 | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								deploy/opensshd.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/opensshd.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a script to deploy cert to opensshd server. | ||||||
|  | 
 | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | opensshd_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" | ||||||
|  | 
 | ||||||
|  |   _err "deploy cert to opensshd server, Not implemented yet" | ||||||
|  |   return 1 | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								deploy/pureftpd.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/pureftpd.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a script to deploy cert to pureftpd server. | ||||||
|  | 
 | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | pureftpd_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" | ||||||
|  | 
 | ||||||
|  |   _err "deploy cert to pureftpd server, Not implemented yet" | ||||||
|  |   return 1 | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								deploy/strongswan.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								deploy/strongswan.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a sample custom api script. | ||||||
|  | #This file name is "myapi.sh" | ||||||
|  | #So, here must be a method   myapi_deploy() | ||||||
|  | #Which will be called by acme.sh to deploy the cert | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | strongswan_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" | ||||||
|  | 
 | ||||||
|  |   cat "$_ckey" >"/etc/ipsec.d/private/$(basename "$_ckey")" | ||||||
|  |   cat "$_ccert" >"/etc/ipsec.d/certs/$(basename "$_ccert")" | ||||||
|  |   cat "$_cca" >"/etc/ipsec.d/cacerts/$(basename "$_cca")" | ||||||
|  |   cat "$_cfullchain" >"/etc/ipsec.d/cacerts/$(basename "$_cfullchain")" | ||||||
|  | 
 | ||||||
|  |   ipsec reload | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										100
									
								
								deploy/unifi.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								deploy/unifi.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,100 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a script to deploy cert to unifi server. | ||||||
|  | 
 | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | #DEPLOY_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore" | ||||||
|  | #DEPLOY_UNIFI_KEYPASS="aircontrolenterprise" | ||||||
|  | #DEPLOY_UNIFI_RELOAD="service unifi restart" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | unifi_deploy() { | ||||||
|  |   _cdomain="$1" | ||||||
|  |   _ckey="$2" | ||||||
|  |   _ccert="$3" | ||||||
|  |   _cca="$4" | ||||||
|  |   _cfullchain="$5" | ||||||
|  | 
 | ||||||
|  |   _debug _cdomain "$_cdomain" | ||||||
|  |   _debug _ckey "$_ckey" | ||||||
|  |   _debug _ccert "$_ccert" | ||||||
|  |   _debug _cca "$_cca" | ||||||
|  |   _debug _cfullchain "$_cfullchain" | ||||||
|  | 
 | ||||||
|  |   if ! _exists keytool; then | ||||||
|  |     _err "keytool not found" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   DEFAULT_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore" | ||||||
|  |   _unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-$DEFAULT_UNIFI_KEYSTORE}" | ||||||
|  |   DEFAULT_UNIFI_KEYPASS="aircontrolenterprise" | ||||||
|  |   _unifi_keypass="${DEPLOY_UNIFI_KEYPASS:-$DEFAULT_UNIFI_KEYPASS}" | ||||||
|  |   DEFAULT_UNIFI_RELOAD="service unifi restart" | ||||||
|  |   _reload="${DEPLOY_UNIFI_RELOAD:-$DEFAULT_UNIFI_RELOAD}" | ||||||
|  | 
 | ||||||
|  |   _debug _unifi_keystore "$_unifi_keystore" | ||||||
|  |   if [ ! -f "$_unifi_keystore" ]; then | ||||||
|  |     if [ -z "$DEPLOY_UNIFI_KEYSTORE" ]; then | ||||||
|  |       _err "unifi keystore is not found, please define DEPLOY_UNIFI_KEYSTORE" | ||||||
|  |       return 1 | ||||||
|  |     else | ||||||
|  |       _err "It seems that the specified unifi keystore is not valid, please check." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  |   if [ ! -w "$_unifi_keystore" ]; then | ||||||
|  |     _err "The file $_unifi_keystore is not writable, please change the permission." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Generate import pkcs12" | ||||||
|  |   _import_pkcs12="$(_mktemp)" | ||||||
|  |   _toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "Oops, error creating import pkcs12, please report bug to us." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Modify unifi keystore: $_unifi_keystore" | ||||||
|  |   if keytool -importkeystore \ | ||||||
|  |     -deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \ | ||||||
|  |     -srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \ | ||||||
|  |     -alias unifi -noprompt; then | ||||||
|  |     _info "Import keystore success!" | ||||||
|  |     rm "$_import_pkcs12" | ||||||
|  |   else | ||||||
|  |     _err "Import unifi keystore error, please report bug to us." | ||||||
|  |     rm "$_import_pkcs12" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Run reload: $_reload" | ||||||
|  |   if eval "$_reload"; then | ||||||
|  |     _info "Reload success!" | ||||||
|  |     if [ "$DEPLOY_UNIFI_KEYSTORE" ]; then | ||||||
|  |       _savedomainconf DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE" | ||||||
|  |     else | ||||||
|  |       _cleardomainconf DEPLOY_UNIFI_KEYSTORE | ||||||
|  |     fi | ||||||
|  |     if [ "$DEPLOY_UNIFI_KEYPASS" ]; then | ||||||
|  |       _savedomainconf DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS" | ||||||
|  |     else | ||||||
|  |       _cleardomainconf DEPLOY_UNIFI_KEYPASS | ||||||
|  |     fi | ||||||
|  |     if [ "$DEPLOY_UNIFI_RELOAD" ]; then | ||||||
|  |       _savedomainconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD" | ||||||
|  |     else | ||||||
|  |       _cleardomainconf DEPLOY_UNIFI_RELOAD | ||||||
|  |     fi | ||||||
|  |     return 0 | ||||||
|  |   else | ||||||
|  |     _err "Reload error" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   return 0 | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										110
									
								
								deploy/vsftpd.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								deploy/vsftpd.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,110 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Here is a script to deploy cert to vsftpd server. | ||||||
|  | 
 | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | #DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf" | ||||||
|  | #DEPLOY_VSFTPD_RELOAD="service vsftpd restart" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #domain keyfile certfile cafile fullchain | ||||||
|  | vsftpd_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" | ||||||
|  | 
 | ||||||
|  |   _ssl_path="/etc/acme.sh/vsftpd" | ||||||
|  |   if ! mkdir -p "$_ssl_path"; then | ||||||
|  |     _err "Can not create folder:$_ssl_path" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Copying key and cert" | ||||||
|  |   _real_key="$_ssl_path/vsftpd.key" | ||||||
|  |   if ! cat "$_ckey" >"$_real_key"; then | ||||||
|  |     _err "Error: write key file to: $_real_key" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _real_fullchain="$_ssl_path/vsftpd.chain.pem" | ||||||
|  |   if ! cat "$_cfullchain" >"$_real_fullchain"; then | ||||||
|  |     _err "Error: write key file to: $_real_fullchain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   DEFAULT_VSFTPD_RELOAD="service vsftpd restart" | ||||||
|  |   _reload="${DEPLOY_VSFTPD_RELOAD:-$DEFAULT_VSFTPD_RELOAD}" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$IS_RENEW" ]; then | ||||||
|  |     DEFAULT_VSFTPD_CONF="/etc/vsftpd.conf" | ||||||
|  |     _vsftpd_conf="${DEPLOY_VSFTPD_CONF:-$DEFAULT_VSFTPD_CONF}" | ||||||
|  |     if [ ! -f "$_vsftpd_conf" ]; then | ||||||
|  |       if [ -z "$DEPLOY_VSFTPD_CONF" ]; then | ||||||
|  |         _err "vsftpd conf is not found, please define DEPLOY_VSFTPD_CONF" | ||||||
|  |         return 1 | ||||||
|  |       else | ||||||
|  |         _err "It seems that the specified vsftpd conf is not valid, please check." | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |     fi | ||||||
|  |     if [ ! -w "$_vsftpd_conf" ]; then | ||||||
|  |       _err "The file $_vsftpd_conf is not writable, please change the permission." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak" | ||||||
|  |     _info "Backup $_vsftpd_conf to $_backup_conf" | ||||||
|  |     cp "$_vsftpd_conf" "$_backup_conf" | ||||||
|  | 
 | ||||||
|  |     _info "Modify vsftpd conf: $_vsftpd_conf" | ||||||
|  |     if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \ | ||||||
|  |       && _setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" \ | ||||||
|  |       && _setopt "$_vsftpd_conf" "ssl_enable" "=" "YES"; then | ||||||
|  |       _info "Set config success!" | ||||||
|  |     else | ||||||
|  |       _err "Config vsftpd server error, please report bug to us." | ||||||
|  |       _info "Restoring vsftpd conf" | ||||||
|  |       if cat "$_backup_conf" >"$_vsftpd_conf"; then | ||||||
|  |         _info "Restore conf success" | ||||||
|  |         eval "$_reload" | ||||||
|  |       else | ||||||
|  |         _err "Oops, error restore vsftpd conf, please report bug to us." | ||||||
|  |       fi | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Run reload: $_reload" | ||||||
|  |   if eval "$_reload"; then | ||||||
|  |     _info "Reload success!" | ||||||
|  |     if [ "$DEPLOY_VSFTPD_CONF" ]; then | ||||||
|  |       _savedomainconf DEPLOY_VSFTPD_CONF "$DEPLOY_VSFTPD_CONF" | ||||||
|  |     else | ||||||
|  |       _cleardomainconf DEPLOY_VSFTPD_CONF | ||||||
|  |     fi | ||||||
|  |     if [ "$DEPLOY_VSFTPD_RELOAD" ]; then | ||||||
|  |       _savedomainconf DEPLOY_VSFTPD_RELOAD "$DEPLOY_VSFTPD_RELOAD" | ||||||
|  |     else | ||||||
|  |       _cleardomainconf DEPLOY_VSFTPD_RELOAD | ||||||
|  |     fi | ||||||
|  |     return 0 | ||||||
|  |   else | ||||||
|  |     _err "Reload error, restoring" | ||||||
|  |     if cat "$_backup_conf" >"$_vsftpd_conf"; then | ||||||
|  |       _info "Restore conf success" | ||||||
|  |       eval "$_reload" | ||||||
|  |     else | ||||||
|  |       _err "Oops, error restore vsftpd conf, please report bug to us." | ||||||
|  |     fi | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
							
								
								
									
										418
									
								
								dnsapi/README.md
									
									
									
									
									
								
							
							
						
						
									
										418
									
								
								dnsapi/README.md
									
									
									
									
									
								
							| @ -140,7 +140,7 @@ Finally, make the DNS server and update Key available to `acme.sh` | |||||||
| 
 | 
 | ||||||
| ``` | ``` | ||||||
| export NSUPDATE_SERVER="dns.example.com" | export NSUPDATE_SERVER="dns.example.com" | ||||||
| export NSUPDATE_KEY="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa==" | export NSUPDATE_KEY="/path/to/your/nsupdate.key" | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Ok, let's issue a cert now: | Ok, let's issue a cert now: | ||||||
| @ -240,7 +240,418 @@ acme.sh --issue --dns dns_ispconfig -d example.com -d www.example.com | |||||||
| 
 | 
 | ||||||
| The `ISPC_User`, `ISPC_Password`, `ISPC_Api`and `ISPC_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | The `ISPC_User`, `ISPC_Password`, `ISPC_Api`and `ISPC_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||||
| 
 | 
 | ||||||
| # 13. Use custom API | ## 13. Use Alwaysdata domain API | ||||||
|  | 
 | ||||||
|  | First you need to login to your Alwaysdata account to get your API Key. | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | export AD_API_KEY="myalwaysdataapikey" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | acme.sh --issue --dns dns_ad -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The `AD_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused | ||||||
|  | when needed. | ||||||
|  | 
 | ||||||
|  | ## 14. Use Linode domain API | ||||||
|  | 
 | ||||||
|  | First you need to login to your Linode account to get your API Key. | ||||||
|  | [https://manager.linode.com/profile/api](https://manager.linode.com/profile/api) | ||||||
|  | 
 | ||||||
|  | Then add an API key with label *ACME* and copy the new key. | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | export LINODE_API_KEY="..." | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Due to the reload time of any changes in the DNS records, we have to use the `dnssleep` option to wait at least 15 minutes for the changes to take effect. | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||||
|  | 
 | ||||||
|  | ## 15. Use FreeDNS | ||||||
|  | 
 | ||||||
|  | FreeDNS (https://freedns.afraid.org/) does not provide an API to update DNS records (other than IPv4 and IPv6 | ||||||
|  | dynamic DNS addresses).  The acme.sh plugin therefore retrieves and updates domain TXT records by logging | ||||||
|  | into the FreeDNS website to read the HTML and posting updates as HTTP.  The plugin needs to know your | ||||||
|  | userid and password for the FreeDNS website. | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | export FREEDNS_User="..." | ||||||
|  | export FREEDNS_Password="..." | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | You need only provide this the first time you run the acme.sh client with FreeDNS validation and then again | ||||||
|  | whenever you change your password at the FreeDNS site.  The acme.sh FreeDNS plugin does not store your userid | ||||||
|  | or password but rather saves an authentication token returned by FreeDNS in `~/.acme.sh/account.conf` and | ||||||
|  | reuses that when needed. | ||||||
|  | 
 | ||||||
|  | Now you can issue a certificate. | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | acme.sh --issue --dns dns_freedns -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Note that you cannot use acme.sh automatic DNS validation for FreeDNS public domains or for a subdomain that | ||||||
|  | you create under a FreeDNS public domain.  You must own the top level domain in order to automatically | ||||||
|  | validate with acme.sh at FreeDNS. | ||||||
|  | 
 | ||||||
|  | ## 16. Use cyon.ch | ||||||
|  | 
 | ||||||
|  | You only need to set your cyon.ch login credentials. | ||||||
|  | If you also have 2 Factor Authentication (OTP) enabled, you need to set your secret token too and have `oathtool` installed. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export CY_Username="your_cyon_username" | ||||||
|  | export CY_Password="your_cyon_password" | ||||||
|  | export CY_OTP_Secret="your_otp_secret" # Only required if using 2FA | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | To issue a cert: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_cyon -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||||
|  | 
 | ||||||
|  | ## 17. Use Domain-Offensive/Resellerinterface/Domainrobot API | ||||||
|  | 
 | ||||||
|  | You will need your login credentials (Partner ID+Password) to the Resellerinterface, and export them before you run `acme.sh`: | ||||||
|  | ``` | ||||||
|  | export DO_PID="KD-1234567" | ||||||
|  | export DO_PW="cdfkjl3n2" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_do -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 18. Use Gandi LiveDNS API | ||||||
|  | 
 | ||||||
|  | You must enable the new Gandi LiveDNS API first and the create your api key, See: http://doc.livedns.gandi.net/ | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export GANDI_LIVEDNS_KEY="fdmlfsdklmfdkmqsdfk" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_gandi_livedns -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 19. Use Knot (knsupdate) DNS API to automatically issue cert | ||||||
|  | 
 | ||||||
|  | First, generate a TSIG key for updating the zone. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | keymgr tsig generate acme_key algorithm hmac-sha512 > /etc/knot/acme.key | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Include this key in your knot configuration file. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | include: /etc/knot/acme.key | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Next, configure your zone to allow dynamic updates. | ||||||
|  | 
 | ||||||
|  | Dynamic updates for the zone are allowed via proper ACL rule with the `update` action. For in-depth instructions, please see [Knot DNS's documentation](https://www.knot-dns.cz/documentation/). | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | acl: | ||||||
|  |   - id: acme_acl | ||||||
|  |     address: 192.168.1.0/24 | ||||||
|  |     key: acme_key | ||||||
|  |     action: update | ||||||
|  | 
 | ||||||
|  | zone: | ||||||
|  |   - domain: example.com | ||||||
|  |     file: example.com.zone | ||||||
|  |     acl: acme_acl | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Finally, make the DNS server and TSIG Key available to `acme.sh` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export KNOT_SERVER="dns.example.com" | ||||||
|  | export KNOT_KEY=`grep \# /etc/knot/acme.key | cut -d' ' -f2` | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_knot -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The `KNOT_SERVER` and `KNOT_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||||
|  | 
 | ||||||
|  | ## 20. Use DigitalOcean API (native) | ||||||
|  | 
 | ||||||
|  | You need to obtain a read and write capable API key from your DigitalOcean account. See: https://www.digitalocean.com/help/api/ | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_dgon -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 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/ | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export CLOUDNS_AUTH_ID=XXXXX | ||||||
|  | export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | The `CLOUDNS_AUTH_ID` and `CLOUDNS_AUTH_PASSWORD` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||||
|  | 
 | ||||||
|  | ## 22. Use Infoblox API | ||||||
|  | 
 | ||||||
|  | First you need to create/obtain API credentials on your Infoblox appliance. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export Infoblox_Creds="username:password" | ||||||
|  | export Infoblox_Server="ip or fqdn of infoblox appliance" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Note: This script will automatically create and delete the ephemeral txt record. | ||||||
|  | The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## 23. Use VSCALE API | ||||||
|  | 
 | ||||||
|  | First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_vscale -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ##  24. Use Dynu API | ||||||
|  | 
 | ||||||
|  | First you need to create/obtain API credentials from your Dynu account. See: https://www.dynu.com/resources/api/documentation | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export Dynu_ClientId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" | ||||||
|  | export Dynu_Secret="yyyyyyyyyyyyyyyyyyyyyyyyy" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_dynu -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The `Dynu_ClientId` and `Dynu_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||||
|  | 
 | ||||||
|  | ## 25. Use DNSimple API | ||||||
|  | 
 | ||||||
|  | First you need to login to your DNSimple account and generate a new oauth token. | ||||||
|  | 
 | ||||||
|  | https://dnsimple.com/a/{your account id}/account/access_tokens | ||||||
|  | 
 | ||||||
|  | Note that this is an _account_ token and not a user token. The account token is | ||||||
|  | needed to infer the `account_id` used in requests. A user token will not be able | ||||||
|  | to determine the correct account to use. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | To issue the cert just specify the `dns_dnsimple` API. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_dnsimple -d example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The `DNSimple_OAUTH_TOKEN` will be saved in `~/.acme.sh/account.conf` and will | ||||||
|  | be reused when needed. | ||||||
|  | 
 | ||||||
|  | If you have any issues with this integration please report them to | ||||||
|  | https://github.com/pho3nixf1re/acme.sh/issues. | ||||||
|  | 
 | ||||||
|  | ## 26. Use NS1.com API | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export NS1_Key="fdmlfsdklmfdkmqsdfk" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_nsone -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 27. Use DuckDNS.org API | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Please note that since DuckDNS uses StartSSL as their cert provider, thus  | ||||||
|  | --insecure may need to be used when issuing certs: | ||||||
|  | ``` | ||||||
|  | acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | For issues, please report to https://github.com/raidenii/acme.sh/issues. | ||||||
|  | 
 | ||||||
|  | ## 28. Use Name.com API | ||||||
|  | 
 | ||||||
|  | You'll need to fill out the form at https://www.name.com/reseller/apply to apply | ||||||
|  | for API username and token. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export Namecom_Username="testuser" | ||||||
|  | export Namecom_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | And now you can issue certs with: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_namecom -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | For issues, please report to https://github.com/raidenii/acme.sh/issues. | ||||||
|  | 
 | ||||||
|  | ## 29. Use Dyn Managed DNS API to automatically issue cert | ||||||
|  | 
 | ||||||
|  | First, login to your Dyn Managed DNS account: https://portal.dynect.net/login/ | ||||||
|  | 
 | ||||||
|  | It is recommended to add a new user specific for API access. | ||||||
|  | 
 | ||||||
|  | The minimum "Zones & Records Permissions" required are: | ||||||
|  | ``` | ||||||
|  | RecordAdd | ||||||
|  | RecordUpdate | ||||||
|  | RecordDelete | ||||||
|  | RecordGet | ||||||
|  | ZoneGet | ||||||
|  | ZoneAddNode | ||||||
|  | ZoneRemoveNode | ||||||
|  | ZonePublish | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Pass the API user credentials to the environment: | ||||||
|  | ``` | ||||||
|  | export DYN_Customer="customer" | ||||||
|  | export DYN_Username="apiuser" | ||||||
|  | export DYN_Password="secret" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_dyn -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The `DYN_Customer`, `DYN_Username` and `DYN_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||||
|  | 
 | ||||||
|  | ## 30. Use pdd.yandex.ru API | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Follow these instructions to get the token for your domain https://tech.yandex.com/domain/doc/concepts/access-docpage/ | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_yandex -d mydomain.example.org | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | For issues, please report to https://github.com/non7top/acme.sh/issues. | ||||||
|  | 
 | ||||||
|  | ## 31. Use Hurricane Electric | ||||||
|  | 
 | ||||||
|  | Hurricane Electric doesn't have an API so just set your login credentials like so: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export HE_Username="yourusername" | ||||||
|  | export HE_Password="password" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Then you can issue your certificate: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_he -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||||
|  | 
 | ||||||
|  | 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. | ||||||
|  | 
 | ||||||
|  | # 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. | ||||||
| 
 | 
 | ||||||
| @ -256,7 +667,8 @@ acme.sh --issue --dns dns_myapi -d example.com -d www.example.com | |||||||
| 
 | 
 | ||||||
| For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) | For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) | ||||||
| 
 | 
 | ||||||
|  | See:  https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide | ||||||
| 
 | 
 | ||||||
| ## 14. Use lexicon DNS API | # Use lexicon DNS API | ||||||
| 
 | 
 | ||||||
| https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api | https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api | ||||||
|  | |||||||
							
								
								
									
										147
									
								
								dnsapi/dns_ad.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										147
									
								
								dnsapi/dns_ad.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,147 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | #AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||||
|  | 
 | ||||||
|  | #This is the Alwaysdata api wrapper for acme.sh | ||||||
|  | # | ||||||
|  | #Author: Paul Koppen | ||||||
|  | #Report Bugs here: https://github.com/wpk-/acme.sh | ||||||
|  | 
 | ||||||
|  | AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_ad_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if [ -z "$AD_API_KEY" ]; then | ||||||
|  |     AD_API_KEY="" | ||||||
|  |     _err "You didn't specify the AD api key yet." | ||||||
|  |     _err "Please create you key and try again." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _saveaccountconf AD_API_KEY "$AD_API_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" | ||||||
|  | 
 | ||||||
|  |   _ad_tmpl_json="{\"domain\":$_domain_id,\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}" | ||||||
|  | 
 | ||||||
|  |   if _ad_rest POST "record/" "$_ad_tmpl_json" && [ -z "$response" ]; then | ||||||
|  |     _info "txt record updated success." | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #fulldomain txtvalue | ||||||
|  | dns_ad_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   _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" | ||||||
|  |   _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain" | ||||||
|  | 
 | ||||||
|  |   if [ -n "$response" ]; then | ||||||
|  |     record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) | ||||||
|  |     _debug record_id "$record_id" | ||||||
|  |     if [ -z "$record_id" ]; then | ||||||
|  |       _err "Can not get record id to remove." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     if _ad_rest DELETE "record/$record_id/" && [ -z "$response" ]; then | ||||||
|  |       _info "txt record deleted success." | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |     _debug response "$response" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | #_acme-challenge.www.domain.com | ||||||
|  | #returns | ||||||
|  | # _sub_domain=_acme-challenge.www | ||||||
|  | # _domain=domain.com | ||||||
|  | # _domain_id=12345 | ||||||
|  | _get_root() { | ||||||
|  |   domain=$1 | ||||||
|  |   i=2 | ||||||
|  |   p=1 | ||||||
|  | 
 | ||||||
|  |   if _ad_rest GET "domain/"; then | ||||||
|  |     response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" | ||||||
|  |     while true; do | ||||||
|  |       h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||||
|  |       _debug h "$h" | ||||||
|  |       if [ -z "$h" ]; then | ||||||
|  |         #not valid | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  | 
 | ||||||
|  |       hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")" | ||||||
|  |       if [ "$hostedzone" ]; then | ||||||
|  |         _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) | ||||||
|  |         if [ "$_domain_id" ]; then | ||||||
|  |           _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) | ||||||
|  |           _domain=$h | ||||||
|  |           return 0 | ||||||
|  |         fi | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |       p=$i | ||||||
|  |       i=$(_math "$i" + 1) | ||||||
|  |     done | ||||||
|  |   fi | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #method uri qstr data | ||||||
|  | _ad_rest() { | ||||||
|  |   mtd="$1" | ||||||
|  |   ep="$2" | ||||||
|  |   data="$3" | ||||||
|  | 
 | ||||||
|  |   _debug mtd "$mtd" | ||||||
|  |   _debug ep "$ep" | ||||||
|  | 
 | ||||||
|  |   export _H1="Accept: application/json" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |   if [ "$mtd" != "GET" ]; then | ||||||
|  |     # both POST and DELETE. | ||||||
|  |     _debug data "$data" | ||||||
|  |     response="$(_post "$data" "$AD_API_URL/$ep" "" "$mtd")" | ||||||
|  |   else | ||||||
|  |     response="$(_get "$AD_API_URL/$ep")" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error $ep" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								dnsapi/dns_ali.sh
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										4
									
								
								dnsapi/dns_ali.sh
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -35,7 +35,7 @@ dns_ali_rm() { | |||||||
|   _clean |   _clean | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| 
 | 
 | ||||||
| _get_root() { | _get_root() { | ||||||
|   domain=$1 |   domain=$1 | ||||||
| @ -67,7 +67,7 @@ _get_root() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| _ali_rest() { | _ali_rest() { | ||||||
|   signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(_hex "$Ali_Secret&")" | _base64) |   signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64) | ||||||
|   signature=$(_ali_urlencode "$signature") |   signature=$(_ali_urlencode "$signature") | ||||||
|   url="$Ali_API?$query&Signature=$signature" |   url="$Ali_API?$query&Signature=$signature" | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										78
									
								
								dnsapi/dns_aws.sh
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										78
									
								
								dnsapi/dns_aws.sh
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -27,8 +27,10 @@ dns_aws_add() { | |||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|  |   if [ -z "$AWS_SESSION_TOKEN" ]; then | ||||||
|     _saveaccountconf AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" |     _saveaccountconf AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" | ||||||
|     _saveaccountconf AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" |     _saveaccountconf AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" | ||||||
|  |   fi | ||||||
| 
 | 
 | ||||||
|   _debug "First detect the root zone" |   _debug "First detect the root zone" | ||||||
|   if ! _get_root "$fulldomain"; then |   if ! _get_root "$fulldomain"; then | ||||||
| @ -42,20 +44,39 @@ dns_aws_add() { | |||||||
|   _aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>UPSERT</Action><ResourceRecordSet><Name>$fulldomain</Name><Type>TXT</Type><TTL>300</TTL><ResourceRecords><ResourceRecord><Value>\"$txtvalue\"</Value></ResourceRecord></ResourceRecords></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>" |   _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>" | ||||||
| 
 | 
 | ||||||
|   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 sucess." |     _info "txt record updated success." | ||||||
|     return 0 |     return 0 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   return 1 |   return 1 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #fulldomain | #fulldomain txtvalue | ||||||
| dns_aws_rm() { | dns_aws_rm() { | ||||||
|   fulldomain=$1 |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   _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" | ||||||
|  | 
 | ||||||
|  |   _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>" | ||||||
|  | 
 | ||||||
|  |   if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then | ||||||
|  |     _info "txt record deleted success." | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 1 | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| 
 | 
 | ||||||
| _get_root() { | _get_root() { | ||||||
|   domain=$1 |   domain=$1 | ||||||
| @ -66,26 +87,40 @@ _get_root() { | |||||||
|     _debug "response" "$response" |     _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" | ||||||
|       if [ -z "$h" ]; then |       if [ -z "$h" ]; then | ||||||
|  |         if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then | ||||||
|  |           _debug "IsTruncated" | ||||||
|  |           _nextMarker="$(echo "$response" | _egrep_o "<NextMarker>.*</NextMarker>" | cut -d '>' -f 2 | cut -d '<' -f 1)" | ||||||
|  |           _debug "NextMarker" "$_nextMarker" | ||||||
|  |           if aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"; then | ||||||
|  |             _debug "Truncated request OK" | ||||||
|  |             i=2 | ||||||
|  |             p=1 | ||||||
|  |             continue | ||||||
|  |           else | ||||||
|  |             _err "Truncated request error." | ||||||
|  |           fi | ||||||
|  |         fi | ||||||
|         #not valid |         #not valid | ||||||
|  |         _err "Invalid domain" | ||||||
|         return 1 |         return 1 | ||||||
|       fi |       fi | ||||||
| 
 | 
 | ||||||
|       if _contains "$response" "<Name>$h.</Name>"; then |       if _contains "$response" "<Name>$h.</Name>"; then | ||||||
|         hostedzone="$(echo "$response" | _egrep_o "<HostedZone>.*<Name>$h.</Name>.*</HostedZone>")" |         hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")" | ||||||
|         _debug hostedzone "$hostedzone" |         _debug hostedzone "$hostedzone" | ||||||
|         if [ -z "$hostedzone" ]; then |         if [ "$hostedzone" ]; then | ||||||
|           _err "Error, can not get hostedzone." |           _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") | ||||||
|           return 1 |  | ||||||
|         fi |  | ||||||
|         _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*</Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") |  | ||||||
|           if [ "$_domain_id" ]; then |           if [ "$_domain_id" ]; then | ||||||
|             _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) |             _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) | ||||||
|             _domain=$h |             _domain=$h | ||||||
|             return 0 |             return 0 | ||||||
|           fi |           fi | ||||||
|  |           _err "Can not find domain id: $h" | ||||||
|           return 1 |           return 1 | ||||||
|         fi |         fi | ||||||
|  |       fi | ||||||
|       p=$i |       p=$i | ||||||
|       i=$(_math "$i" + 1) |       i=$(_math "$i" + 1) | ||||||
|     done |     done | ||||||
| @ -116,13 +151,17 @@ aws_rest() { | |||||||
| 
 | 
 | ||||||
|   #RequestDate="20161120T141056Z" ############## |   #RequestDate="20161120T141056Z" ############## | ||||||
| 
 | 
 | ||||||
|   _H1="x-amz-date: $RequestDate" |   export _H1="x-amz-date: $RequestDate" | ||||||
| 
 | 
 | ||||||
|   aws_host="$AWS_HOST" |   aws_host="$AWS_HOST" | ||||||
|   CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" |   CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" | ||||||
|   _debug2 CanonicalHeaders "$CanonicalHeaders" |  | ||||||
| 
 |  | ||||||
|   SignedHeaders="host;x-amz-date" |   SignedHeaders="host;x-amz-date" | ||||||
|  |   if [ -n "$AWS_SESSION_TOKEN" ]; then | ||||||
|  |     export _H3="x-amz-security-token: $AWS_SESSION_TOKEN" | ||||||
|  |     CanonicalHeaders="${CanonicalHeaders}x-amz-security-token:$AWS_SESSION_TOKEN\n" | ||||||
|  |     SignedHeaders="${SignedHeaders};x-amz-security-token" | ||||||
|  |   fi | ||||||
|  |   _debug2 CanonicalHeaders "$CanonicalHeaders" | ||||||
|   _debug2 SignedHeaders "$SignedHeaders" |   _debug2 SignedHeaders "$SignedHeaders" | ||||||
| 
 | 
 | ||||||
|   RequestPayload="$data" |   RequestPayload="$data" | ||||||
| @ -156,10 +195,10 @@ aws_rest() { | |||||||
| 
 | 
 | ||||||
|   #kSecret="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ############################ |   #kSecret="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ############################ | ||||||
| 
 | 
 | ||||||
|   _debug2 kSecret "$kSecret" |   _secure_debug2 kSecret "$kSecret" | ||||||
| 
 | 
 | ||||||
|   kSecretH="$(_hex "$kSecret")" |   kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")" | ||||||
|   _debug2 kSecretH "$kSecretH" |   _secure_debug2 kSecretH "$kSecretH" | ||||||
| 
 | 
 | ||||||
|   kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" |   kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" | ||||||
|   _debug2 kDateH "$kDateH" |   _debug2 kDateH "$kDateH" | ||||||
| @ -170,7 +209,7 @@ aws_rest() { | |||||||
|   kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)" |   kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)" | ||||||
|   _debug2 kServiceH "$kServiceH" |   _debug2 kServiceH "$kServiceH" | ||||||
| 
 | 
 | ||||||
|   kSigningH="$(printf "aws4_request%s" | _hmac "$Hash" "$kServiceH" hex)" |   kSigningH="$(printf "%s" "aws4_request" | _hmac "$Hash" "$kServiceH" hex)" | ||||||
|   _debug2 kSigningH "$kSigningH" |   _debug2 kSigningH "$kSigningH" | ||||||
| 
 | 
 | ||||||
|   signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)" |   signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)" | ||||||
| @ -179,10 +218,13 @@ aws_rest() { | |||||||
|   Authorization="$Algorithm Credential=$AWS_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" |   Authorization="$Algorithm Credential=$AWS_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" | ||||||
|   _debug2 Authorization "$Authorization" |   _debug2 Authorization "$Authorization" | ||||||
| 
 | 
 | ||||||
|   _H3="Authorization: $Authorization" |   _H2="Authorization: $Authorization" | ||||||
|   _debug _H3 "$_H3" |   _debug _H2 "$_H2" | ||||||
| 
 | 
 | ||||||
|   url="$AWS_URL/$ep" |   url="$AWS_URL/$ep" | ||||||
|  |   if [ "$qsr" ]; then | ||||||
|  |     url="$AWS_URL/$ep?$qsr" | ||||||
|  |   fi | ||||||
| 
 | 
 | ||||||
|   if [ "$mtd" = "GET" ]; then |   if [ "$mtd" = "GET" ]; then | ||||||
|     response="$(_get "$url")" |     response="$(_get "$url")" | ||||||
|  | |||||||
| @ -14,6 +14,8 @@ dns_cf_add() { | |||||||
|   fulldomain=$1 |   fulldomain=$1 | ||||||
|   txtvalue=$2 |   txtvalue=$2 | ||||||
| 
 | 
 | ||||||
|  |   CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" | ||||||
|  |   CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" | ||||||
|   if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then |   if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then | ||||||
|     CF_Key="" |     CF_Key="" | ||||||
|     CF_Email="" |     CF_Email="" | ||||||
| @ -29,8 +31,8 @@ dns_cf_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 CF_Key "$CF_Key" |   _saveaccountconf_mutable CF_Key "$CF_Key" | ||||||
|   _saveaccountconf CF_Email "$CF_Email" |   _saveaccountconf_mutable CF_Email "$CF_Email" | ||||||
| 
 | 
 | ||||||
|   _debug "First detect the root zone" |   _debug "First detect the root zone" | ||||||
|   if ! _get_root "$fulldomain"; then |   if ! _get_root "$fulldomain"; then | ||||||
| @ -55,9 +57,7 @@ dns_cf_add() { | |||||||
|     _info "Adding record" |     _info "Adding record" | ||||||
|     if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then |     if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then | ||||||
|       if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then |       if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then | ||||||
|         _info "Added, sleeping 10 seconds" |         _info "Added, OK" | ||||||
|         sleep 10 |  | ||||||
|         #todo: check if the record takes effect |  | ||||||
|         return 0 |         return 0 | ||||||
|       else |       else | ||||||
|         _err "Add txt record error." |         _err "Add txt record error." | ||||||
| @ -72,9 +72,7 @@ dns_cf_add() { | |||||||
| 
 | 
 | ||||||
|     _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\"}" |     _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 |     if [ "$?" = "0" ]; then | ||||||
|       _info "Updated, sleeping 10 seconds" |       _info "Updated, OK" | ||||||
|       sleep 10 |  | ||||||
|       #todo: check if the record takes effect |  | ||||||
|       return 0 |       return 0 | ||||||
|     fi |     fi | ||||||
|     _err "Update error" |     _err "Update error" | ||||||
| @ -83,13 +81,59 @@ dns_cf_add() { | |||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #fulldomain | #fulldomain txtvalue | ||||||
| dns_cf_rm() { | dns_cf_rm() { | ||||||
|   fulldomain=$1 |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" | ||||||
|  |   CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" | ||||||
|  |   if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then | ||||||
|  |     CF_Key="" | ||||||
|  |     CF_Email="" | ||||||
|  |     _err "You don't specify cloudflare api key and email 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" | ||||||
|  |   _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain&content=$txtvalue" | ||||||
|  | 
 | ||||||
|  |   if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then | ||||||
|  |     _err "Error" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) | ||||||
|  |   _debug count "$count" | ||||||
|  |   if [ "$count" = "0" ]; then | ||||||
|  |     _info "Don't need to remove." | ||||||
|  |   else | ||||||
|  |     record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) | ||||||
|  |     _debug "record_id" "$record_id" | ||||||
|  |     if [ -z "$record_id" ]; then | ||||||
|  |       _err "Can not get record id to remove." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     if ! _cf_rest DELETE "zones/$_domain_id/dns_records/$record_id"; then | ||||||
|  |       _err "Delete record error." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _contains "$response" '"success":true' | ||||||
|  |   fi | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| #_acme-challenge.www.domain.com | #_acme-challenge.www.domain.com | ||||||
| #returns | #returns | ||||||
| # _sub_domain=_acme-challenge.www | # _sub_domain=_acme-challenge.www | ||||||
| @ -101,6 +145,7 @@ _get_root() { | |||||||
|   p=1 |   p=1 | ||||||
|   while true; do |   while true; do | ||||||
|     h=$(printf "%s" "$domain" | cut -d . -f $i-100) |     h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||||
|  |     _debug h "$h" | ||||||
|     if [ -z "$h" ]; then |     if [ -z "$h" ]; then | ||||||
|       #not valid |       #not valid | ||||||
|       return 1 |       return 1 | ||||||
| @ -110,8 +155,8 @@ _get_root() { | |||||||
|       return 1 |       return 1 | ||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     if printf "%s" "$response" | grep "\"name\":\"$h\"" >/dev/null; then |     if _contains "$response" "\"name\":\"$h\"" >/dev/null; then | ||||||
|       _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") |       _domain_id=$(printf "%s\n" "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") | ||||||
|       if [ "$_domain_id" ]; then |       if [ "$_domain_id" ]; then | ||||||
|         _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) |         _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) | ||||||
|         _domain=$h |         _domain=$h | ||||||
| @ -131,11 +176,11 @@ _cf_rest() { | |||||||
|   data="$3" |   data="$3" | ||||||
|   _debug "$ep" |   _debug "$ep" | ||||||
| 
 | 
 | ||||||
|   _H1="X-Auth-Email: $CF_Email" |   export _H1="X-Auth-Email: $CF_Email" | ||||||
|   _H2="X-Auth-Key: $CF_Key" |   export _H2="X-Auth-Key: $CF_Key" | ||||||
|   _H3="Content-Type: application/json" |   export _H3="Content-Type: application/json" | ||||||
| 
 | 
 | ||||||
|   if [ "$data" ]; then |   if [ "$m" != "GET" ]; then | ||||||
|     _debug data "$data" |     _debug data "$data" | ||||||
|     response="$(_post "$data" "$CF_Api/$ep" "" "$m")" |     response="$(_post "$data" "$CF_Api/$ep" "" "$m")" | ||||||
|   else |   else | ||||||
|  | |||||||
							
								
								
									
										184
									
								
								dnsapi/dns_cloudns.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										184
									
								
								dnsapi/dns_cloudns.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,184 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | # Author: Boyan Peychev <boyan at cloudns dot net> | ||||||
|  | # Repository: https://github.com/ClouDNS/acme.sh/ | ||||||
|  | 
 | ||||||
|  | #CLOUDNS_AUTH_ID=XXXXX | ||||||
|  | #CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" | ||||||
|  | CLOUDNS_API="https://api.cloudns.net" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: dns_cloudns_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_cloudns_add() { | ||||||
|  |   _info "Using cloudns" | ||||||
|  | 
 | ||||||
|  |   if ! _dns_cloudns_init_check; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   zone="$(_dns_cloudns_get_zone_name "$1")" | ||||||
|  |   if [ -z "$zone" ]; then | ||||||
|  |     _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   host="$(echo "$1" | sed "s/\.$zone\$//")" | ||||||
|  |   record=$2 | ||||||
|  |   record_id=$(_dns_cloudns_get_record_id "$zone" "$host") | ||||||
|  | 
 | ||||||
|  |   _debug zone "$zone" | ||||||
|  |   _debug host "$host" | ||||||
|  |   _debug record "$record" | ||||||
|  |   _debug record_id "$record_id" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$record_id" ]; then | ||||||
|  |     _info "Adding the TXT record for $1" | ||||||
|  |     _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" | ||||||
|  |     if ! _contains "$response" "\"status\":\"Success\""; then | ||||||
|  |       _err "Record cannot be added." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _info "Added." | ||||||
|  |   else | ||||||
|  |     _info "Updating the TXT record for $1" | ||||||
|  |     _dns_cloudns_http_api_call "dns/mod-record.json" "domain-name=$zone&record-id=$record_id&record-type=TXT&host=$host&record=$record&ttl=60" | ||||||
|  |     if ! _contains "$response" "\"status\":\"Success\""; then | ||||||
|  |       _err "The TXT record for $1 cannot be updated." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _info "Updated." | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: dns_cloudns_rm   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_cloudns_rm() { | ||||||
|  |   _info "Using cloudns" | ||||||
|  | 
 | ||||||
|  |   if ! _dns_cloudns_init_check; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ -z "$zone" ]; then | ||||||
|  |     zone="$(_dns_cloudns_get_zone_name "$1")" | ||||||
|  |     if [ -z "$zone" ]; then | ||||||
|  |       _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   host="$(echo "$1" | sed "s/\.$zone\$//")" | ||||||
|  |   record=$2 | ||||||
|  |   record_id=$(_dns_cloudns_get_record_id "$zone" "$host") | ||||||
|  | 
 | ||||||
|  |   _debug zone "$zone" | ||||||
|  |   _debug host "$host" | ||||||
|  |   _debug record "$record" | ||||||
|  |   _debug record_id "$record_id" | ||||||
|  | 
 | ||||||
|  |   if [ ! -z "$record_id" ]; then | ||||||
|  |     _info "Deleting the TXT record for $1" | ||||||
|  |     _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=$record_id" | ||||||
|  |     if ! _contains "$response" "\"status\":\"Success\""; then | ||||||
|  |       _err "The TXT record for $1 cannot be deleted." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _info "Deleted." | ||||||
|  |   fi | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | _dns_cloudns_init_check() { | ||||||
|  |   if [ ! -z "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}" | ||||||
|  |   CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}" | ||||||
|  |   if [ -z "$CLOUDNS_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then | ||||||
|  |     CLOUDNS_AUTH_ID="" | ||||||
|  |     CLOUDNS_AUTH_PASSWORD="" | ||||||
|  |     _err "You don't specify cloudns api id and password yet." | ||||||
|  |     _err "Please create you id and password and try again." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ -z "$CLOUDNS_AUTH_ID" ]; then | ||||||
|  |     _err "CLOUDNS_AUTH_ID is not configured" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then | ||||||
|  |     _err "CLOUDNS_AUTH_PASSWORD is not configured" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _dns_cloudns_http_api_call "dns/login.json" "" | ||||||
|  | 
 | ||||||
|  |   if ! _contains "$response" "\"status\":\"Success\""; then | ||||||
|  |     _err "Invalid CLOUDNS_AUTH_ID or CLOUDNS_AUTH_PASSWORD. Please check your login credentials." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   #save the api id and password to the account conf file. | ||||||
|  |   _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" | ||||||
|  |   _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" | ||||||
|  | 
 | ||||||
|  |   CLOUDNS_INIT_CHECK_COMPLETED=1 | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _dns_cloudns_get_zone_name() { | ||||||
|  |   i=2 | ||||||
|  |   while true; do | ||||||
|  |     zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) | ||||||
|  | 
 | ||||||
|  |     if [ -z "$zoneForCheck" ]; then | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     _debug zoneForCheck "$zoneForCheck" | ||||||
|  | 
 | ||||||
|  |     _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" | ||||||
|  | 
 | ||||||
|  |     if ! _contains "$response" "\"status\":\"Failed\""; then | ||||||
|  |       echo "$zoneForCheck" | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     i=$(_math "$i" + 1) | ||||||
|  |   done | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _dns_cloudns_get_record_id() { | ||||||
|  |   _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" | ||||||
|  |   if _contains "$response" "\"id\":"; then | ||||||
|  |     echo "$response" | cut -d '"' -f 2 | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _dns_cloudns_http_api_call() { | ||||||
|  |   method=$1 | ||||||
|  | 
 | ||||||
|  |   _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" | ||||||
|  |   _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$2" ]; then | ||||||
|  |     data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD" | ||||||
|  |   else | ||||||
|  |     data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   response="$(_get "$CLOUDNS_API/$method?$data")" | ||||||
|  | 
 | ||||||
|  |   _debug2 response "$response" | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
| @ -58,7 +58,15 @@ dns_cx_add() { | |||||||
| #fulldomain | #fulldomain | ||||||
| dns_cx_rm() { | dns_cx_rm() { | ||||||
|   fulldomain=$1 |   fulldomain=$1 | ||||||
| 
 |   REST_API="$CX_Api" | ||||||
|  |   if _get_root "$fulldomain"; then | ||||||
|  |     record_id="" | ||||||
|  |     existing_records "$_domain" "$_sub_domain" | ||||||
|  |     if ! [ "$record_id" = "" ]; then | ||||||
|  |       _rest DELETE "record/$record_id/$_domain_id" "{}" | ||||||
|  |       _info "Deleted record ${fulldomain}" | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #usage:  root  sub | #usage:  root  sub | ||||||
| @ -69,12 +77,12 @@ 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 | ||||||
|   count=0 | 
 | ||||||
|   seg=$(printf "%s\n" "$response" | _egrep_o "{[^\{]*host\":\"$_sub_domain\"[^\}]*\}") |   seg=$(printf "%s\n" "$response" | _egrep_o '"record_id":[^{]*host":"'"$_sub_domain"'"[^}]*\}') | ||||||
|   _debug seg "$seg" |   _debug seg "$seg" | ||||||
|   if [ -z "$seg" ]; then |   if [ -z "$seg" ]; then | ||||||
|     return 0 |     return 0 | ||||||
| @ -82,7 +90,7 @@ existing_records() { | |||||||
| 
 | 
 | ||||||
|   if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then |   if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then | ||||||
|     count=1 |     count=1 | ||||||
|     record_id=$(printf "%s\n" "$seg" | _egrep_o "\"record_id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") |     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 | ||||||
|   fi |   fi | ||||||
| @ -123,7 +131,7 @@ update_record() { | |||||||
|   return 1 |   return 1 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| #_acme-challenge.www.domain.com | #_acme-challenge.www.domain.com | ||||||
| #returns | #returns | ||||||
| # _sub_domain=_acme-challenge.www | # _sub_domain=_acme-challenge.www | ||||||
| @ -147,9 +155,9 @@ _get_root() { | |||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     if _contains "$response" "$h."; then |     if _contains "$response" "$h."; then | ||||||
|       seg=$(printf "%s" "$response" | _egrep_o "\{[^\{]*\"$h\.\"[^\}]*\}") |       seg=$(printf "%s\n" "$response" | _egrep_o '"id":[^{]*"'"$h"'."[^}]*}') | ||||||
|       _debug seg "$seg" |       _debug seg "$seg" | ||||||
|       _domain_id=$(printf "%s" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") |       _domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") | ||||||
|       _debug _domain_id "$_domain_id" |       _debug _domain_id "$_domain_id" | ||||||
|       if [ "$_domain_id" ]; then |       if [ "$_domain_id" ]; then | ||||||
|         _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) |         _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) | ||||||
| @ -170,7 +178,7 @@ _get_root() { | |||||||
| _rest() { | _rest() { | ||||||
|   m=$1 |   m=$1 | ||||||
|   ep="$2" |   ep="$2" | ||||||
|   _debug "$ep" |   _debug ep "$ep" | ||||||
|   url="$REST_API/$ep" |   url="$REST_API/$ep" | ||||||
|   _debug url "$url" |   _debug url "$url" | ||||||
| 
 | 
 | ||||||
| @ -185,10 +193,10 @@ _rest() { | |||||||
|   hmac=$(printf "%s" "$sec" | _digest md5 hex) |   hmac=$(printf "%s" "$sec" | _digest md5 hex) | ||||||
|   _debug hmac "$hmac" |   _debug hmac "$hmac" | ||||||
| 
 | 
 | ||||||
|   _H1="API-KEY: $CX_Key" |   export _H1="API-KEY: $CX_Key" | ||||||
|   _H2="API-REQUEST-DATE: $cdate" |   export _H2="API-REQUEST-DATE: $cdate" | ||||||
|   _H3="API-HMAC: $hmac" |   export _H3="API-HMAC: $hmac" | ||||||
|   _H4="Content-Type: application/json" |   export _H4="Content-Type: application/json" | ||||||
| 
 | 
 | ||||||
|   if [ "$data" ]; then |   if [ "$data" ]; then | ||||||
|     response="$(_post "$data" "$url" "" "$m")" |     response="$(_post "$data" "$url" "" "$m")" | ||||||
| @ -201,8 +209,7 @@ _rest() { | |||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|   _debug2 response "$response" |   _debug2 response "$response" | ||||||
|   if ! _contains "$response" '"message":"success"'; then | 
 | ||||||
|     return 1 |   _contains "$response" '"code":1' | ||||||
|   fi | 
 | ||||||
|   return 0 |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										328
									
								
								dnsapi/dns_cyon.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										328
									
								
								dnsapi/dns_cyon.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,328 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | ######## | ||||||
|  | # Custom cyon.ch DNS API for use with [acme.sh](https://github.com/Neilpang/acme.sh) | ||||||
|  | # | ||||||
|  | # Usage: acme.sh --issue --dns dns_cyon -d www.domain.com | ||||||
|  | # | ||||||
|  | # Dependencies: | ||||||
|  | # ------------- | ||||||
|  | # - oathtool (When using 2 Factor Authentication) | ||||||
|  | # | ||||||
|  | # Issues: | ||||||
|  | # ------- | ||||||
|  | # Any issues / questions / suggestions can be posted here: | ||||||
|  | # https://github.com/noplanman/cyon-api/issues | ||||||
|  | # | ||||||
|  | # Author: Armando Lüscher <armando@noplanman.ch> | ||||||
|  | ######## | ||||||
|  | 
 | ||||||
|  | dns_cyon_add() { | ||||||
|  |   _cyon_load_credentials \ | ||||||
|  |     && _cyon_load_parameters "$@" \ | ||||||
|  |     && _cyon_print_header "add" \ | ||||||
|  |     && _cyon_login \ | ||||||
|  |     && _cyon_change_domain_env \ | ||||||
|  |     && _cyon_add_txt \ | ||||||
|  |     && _cyon_logout | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | dns_cyon_rm() { | ||||||
|  |   _cyon_load_credentials \ | ||||||
|  |     && _cyon_load_parameters "$@" \ | ||||||
|  |     && _cyon_print_header "delete" \ | ||||||
|  |     && _cyon_login \ | ||||||
|  |     && _cyon_change_domain_env \ | ||||||
|  |     && _cyon_delete_txt \ | ||||||
|  |     && _cyon_logout | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ######################### | ||||||
|  | ### PRIVATE FUNCTIONS ### | ||||||
|  | ######################### | ||||||
|  | 
 | ||||||
|  | _cyon_load_credentials() { | ||||||
|  |   # Convert loaded password to/from base64 as needed. | ||||||
|  |   if [ "${CY_Password_B64}" ]; then | ||||||
|  |     CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64 "multiline")" | ||||||
|  |   elif [ "${CY_Password}" ]; then | ||||||
|  |     CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then | ||||||
|  |     # Dummy entries to satisfy script checker. | ||||||
|  |     CY_Username="" | ||||||
|  |     CY_Password="" | ||||||
|  |     CY_OTP_Secret="" | ||||||
|  | 
 | ||||||
|  |     _err "" | ||||||
|  |     _err "You haven't set your cyon.ch login credentials yet." | ||||||
|  |     _err "Please set the required cyon environment variables." | ||||||
|  |     _err "" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   # Save the login credentials to the account.conf file. | ||||||
|  |   _debug "Save credentials to account.conf" | ||||||
|  |   _saveaccountconf CY_Username "${CY_Username}" | ||||||
|  |   _saveaccountconf CY_Password_B64 "$CY_Password_B64" | ||||||
|  |   if [ ! -z "${CY_OTP_Secret}" ]; then | ||||||
|  |     _saveaccountconf CY_OTP_Secret "$CY_OTP_Secret" | ||||||
|  |   else | ||||||
|  |     _clearaccountconf CY_OTP_Secret | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_is_idn() { | ||||||
|  |   _idn_temp="$(printf "%s" "${1}" | tr -d "0-9a-zA-Z.,-_")" | ||||||
|  |   _idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")" | ||||||
|  |   [ "$_idn_temp" ] || [ "$_idn_temp2" ] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_load_parameters() { | ||||||
|  |   # Read the required parameters to add the TXT entry. | ||||||
|  |   # shellcheck disable=SC2018,SC2019 | ||||||
|  |   fulldomain="$(printf "%s" "${1}" | tr "A-Z" "a-z")" | ||||||
|  |   fulldomain_idn="${fulldomain}" | ||||||
|  | 
 | ||||||
|  |   # Special case for IDNs, as cyon needs a domain environment change, | ||||||
|  |   # which uses the "pretty" instead of the punycode version. | ||||||
|  |   if _cyon_is_idn "${fulldomain}"; then | ||||||
|  |     if ! _exists idn; then | ||||||
|  |       _err "Please install idn to process IDN names." | ||||||
|  |       _err "" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     fulldomain="$(idn -u "${fulldomain}")" | ||||||
|  |     fulldomain_idn="$(idn -a "${fulldomain}")" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug fulldomain "${fulldomain}" | ||||||
|  |   _debug fulldomain_idn "${fulldomain_idn}" | ||||||
|  | 
 | ||||||
|  |   txtvalue="${2}" | ||||||
|  |   _debug txtvalue "${txtvalue}" | ||||||
|  | 
 | ||||||
|  |   # This header is required for curl calls. | ||||||
|  |   _H1="X-Requested-With: XMLHttpRequest" | ||||||
|  |   export _H1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_print_header() { | ||||||
|  |   if [ "${1}" = "add" ]; then | ||||||
|  |     _info "" | ||||||
|  |     _info "+---------------------------------------------+" | ||||||
|  |     _info "| Adding DNS TXT entry to your cyon.ch domain |" | ||||||
|  |     _info "+---------------------------------------------+" | ||||||
|  |     _info "" | ||||||
|  |     _info "  * Full Domain: ${fulldomain}" | ||||||
|  |     _info "  * TXT Value:   ${txtvalue}" | ||||||
|  |     _info "" | ||||||
|  |   elif [ "${1}" = "delete" ]; then | ||||||
|  |     _info "" | ||||||
|  |     _info "+-------------------------------------------------+" | ||||||
|  |     _info "| Deleting DNS TXT entry from your cyon.ch domain |" | ||||||
|  |     _info "+-------------------------------------------------+" | ||||||
|  |     _info "" | ||||||
|  |     _info "  * Full Domain: ${fulldomain}" | ||||||
|  |     _info "" | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_get_cookie_header() { | ||||||
|  |   printf "Cookie: %s" "$(grep "cyon=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'cyon=[^;]*;' | tr -d ';')" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_login() { | ||||||
|  |   _info "  - Logging in..." | ||||||
|  | 
 | ||||||
|  |   username_encoded="$(printf "%s" "${CY_Username}" | _url_encode)" | ||||||
|  |   password_encoded="$(printf "%s" "${CY_Password}" | _url_encode)" | ||||||
|  | 
 | ||||||
|  |   login_url="https://my.cyon.ch/auth/index/dologin-async" | ||||||
|  |   login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")" | ||||||
|  | 
 | ||||||
|  |   login_response="$(_post "$login_data" "$login_url")" | ||||||
|  |   _debug login_response "${login_response}" | ||||||
|  | 
 | ||||||
|  |   # Bail if login fails. | ||||||
|  |   if [ "$(printf "%s" "${login_response}" | _cyon_get_response_success)" != "success" ]; then | ||||||
|  |     _err "    $(printf "%s" "${login_response}" | _cyon_get_response_message)" | ||||||
|  |     _err "" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "    success" | ||||||
|  | 
 | ||||||
|  |   # NECESSARY!! Load the main page after login, to get the new cookie. | ||||||
|  |   _H2="$(_cyon_get_cookie_header)" | ||||||
|  |   export _H2 | ||||||
|  | 
 | ||||||
|  |   _get "https://my.cyon.ch/" >/dev/null | ||||||
|  | 
 | ||||||
|  |   # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. | ||||||
|  | 
 | ||||||
|  |   # 2FA authentication with OTP? | ||||||
|  |   if [ ! -z "${CY_OTP_Secret}" ]; then | ||||||
|  |     _info "  - Authorising with OTP code..." | ||||||
|  | 
 | ||||||
|  |     if ! _exists oathtool; then | ||||||
|  |       _err "Please install oathtool to use 2 Factor Authentication." | ||||||
|  |       _err "" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     # Get OTP code with the defined secret. | ||||||
|  |     otp_code="$(oathtool --base32 --totp "${CY_OTP_Secret}" 2>/dev/null)" | ||||||
|  | 
 | ||||||
|  |     login_otp_url="https://my.cyon.ch/auth/multi-factor/domultifactorauth-async" | ||||||
|  |     login_otp_data="totpcode=${otp_code}&pathname=%2F&rememberme=0" | ||||||
|  | 
 | ||||||
|  |     login_otp_response="$(_post "$login_otp_data" "$login_otp_url")" | ||||||
|  |     _debug login_otp_response "${login_otp_response}" | ||||||
|  | 
 | ||||||
|  |     # Bail if OTP authentication fails. | ||||||
|  |     if [ "$(printf "%s" "${login_otp_response}" | _cyon_get_response_success)" != "success" ]; then | ||||||
|  |       _err "    $(printf "%s" "${login_otp_response}" | _cyon_get_response_message)" | ||||||
|  |       _err "" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     _info "    success" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_logout() { | ||||||
|  |   _info "  - Logging out..." | ||||||
|  | 
 | ||||||
|  |   _get "https://my.cyon.ch/auth/index/dologout" >/dev/null | ||||||
|  | 
 | ||||||
|  |   _info "    success" | ||||||
|  |   _info "" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_change_domain_env() { | ||||||
|  |   _info "  - Changing domain environment..." | ||||||
|  | 
 | ||||||
|  |   # Get the "example.com" part of the full domain name. | ||||||
|  |   domain_env="$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/')" | ||||||
|  |   _debug "Changing domain environment to ${domain_env}" | ||||||
|  | 
 | ||||||
|  |   gloo_item_key="$(_get "https://my.cyon.ch/domain/" | tr '\n' ' ' | sed -E -e "s/.*data-domain=\"${domain_env}\"[^<]*data-itemkey=\"([^\"]*).*/\1/")" | ||||||
|  |   _debug gloo_item_key "${gloo_item_key}" | ||||||
|  | 
 | ||||||
|  |   domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/${gloo_item_key}" | ||||||
|  | 
 | ||||||
|  |   domain_env_response="$(_get "${domain_env_url}")" | ||||||
|  |   _debug domain_env_response "${domain_env_response}" | ||||||
|  | 
 | ||||||
|  |   if ! _cyon_check_if_2fa_missed "${domain_env_response}"; then return 1; fi | ||||||
|  | 
 | ||||||
|  |   domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)" | ||||||
|  | 
 | ||||||
|  |   # Bail if domain environment change fails. | ||||||
|  |   if [ "${domain_env_success}" != "true" ]; then | ||||||
|  |     _err "    $(printf "%s" "${domain_env_response}" | _cyon_get_response_message)" | ||||||
|  |     _err "" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "    success" | ||||||
|  |   _info "" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_add_txt() { | ||||||
|  |   _info "  - Adding DNS TXT entry..." | ||||||
|  | 
 | ||||||
|  |   add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async" | ||||||
|  |   add_txt_data="zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}" | ||||||
|  | 
 | ||||||
|  |   add_txt_response="$(_post "$add_txt_data" "$add_txt_url")" | ||||||
|  |   _debug add_txt_response "${add_txt_response}" | ||||||
|  | 
 | ||||||
|  |   if ! _cyon_check_if_2fa_missed "${add_txt_response}"; then return 1; fi | ||||||
|  | 
 | ||||||
|  |   add_txt_message="$(printf "%s" "${add_txt_response}" | _cyon_get_response_message)" | ||||||
|  |   add_txt_status="$(printf "%s" "${add_txt_response}" | _cyon_get_response_status)" | ||||||
|  | 
 | ||||||
|  |   # Bail if adding TXT entry fails. | ||||||
|  |   if [ "${add_txt_status}" != "true" ]; then | ||||||
|  |     _err "    ${add_txt_message}" | ||||||
|  |     _err "" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "    success (TXT|${fulldomain_idn}.|${txtvalue})" | ||||||
|  |   _info "" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_delete_txt() { | ||||||
|  |   _info "  - Deleting DNS TXT entry..." | ||||||
|  | 
 | ||||||
|  |   list_txt_url="https://my.cyon.ch/domain/dnseditor/list-async" | ||||||
|  | 
 | ||||||
|  |   list_txt_response="$(_get "${list_txt_url}" | sed -e 's/data-hash/\\ndata-hash/g')" | ||||||
|  |   _debug list_txt_response "${list_txt_response}" | ||||||
|  | 
 | ||||||
|  |   if ! _cyon_check_if_2fa_missed "${list_txt_response}"; then return 1; fi | ||||||
|  | 
 | ||||||
|  |   # Find and delete all acme challenge entries for the $fulldomain. | ||||||
|  |   _dns_entries="$(printf "%b\n" "${list_txt_response}" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p')" | ||||||
|  | 
 | ||||||
|  |   printf "%s" "${_dns_entries}" | while read -r _hash _identifier; do | ||||||
|  |     dns_type="$(printf "%s" "$_identifier" | cut -d'|' -f1)" | ||||||
|  |     dns_domain="$(printf "%s" "$_identifier" | cut -d'|' -f2)" | ||||||
|  | 
 | ||||||
|  |     if [ "${dns_type}" != "TXT" ] || [ "${dns_domain}" != "${fulldomain_idn}." ]; then | ||||||
|  |       continue | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     hash_encoded="$(printf "%s" "${_hash}" | _url_encode)" | ||||||
|  |     identifier_encoded="$(printf "%s" "${_identifier}" | _url_encode)" | ||||||
|  | 
 | ||||||
|  |     delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async" | ||||||
|  |     delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")" | ||||||
|  | 
 | ||||||
|  |     delete_txt_response="$(_post "$delete_txt_data" "$delete_txt_url")" | ||||||
|  |     _debug delete_txt_response "${delete_txt_response}" | ||||||
|  | 
 | ||||||
|  |     if ! _cyon_check_if_2fa_missed "${delete_txt_response}"; then return 1; fi | ||||||
|  | 
 | ||||||
|  |     delete_txt_message="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_message)" | ||||||
|  |     delete_txt_status="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_status)" | ||||||
|  | 
 | ||||||
|  |     # Skip if deleting TXT entry fails. | ||||||
|  |     if [ "${delete_txt_status}" != "true" ]; then | ||||||
|  |       _err "    ${delete_txt_message} (${_identifier})" | ||||||
|  |     else | ||||||
|  |       _info "    success (${_identifier})" | ||||||
|  |     fi | ||||||
|  |   done | ||||||
|  | 
 | ||||||
|  |   _info "    done" | ||||||
|  |   _info "" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_get_response_message() { | ||||||
|  |   _egrep_o '"message":"[^"]*"' | cut -d : -f 2 | tr -d '"' | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_get_response_status() { | ||||||
|  |   _egrep_o '"status":\w*' | cut -d : -f 2 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_get_response_success() { | ||||||
|  |   _egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"' | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _cyon_check_if_2fa_missed() { | ||||||
|  |   # Did we miss the 2FA? | ||||||
|  |   if test "${1#*multi_factor_form}" != "${1}"; then | ||||||
|  |     _err "    Missed OTP authentication!" | ||||||
|  |     _err "" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | } | ||||||
							
								
								
									
										205
									
								
								dnsapi/dns_dgon.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										205
									
								
								dnsapi/dns_dgon.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,205 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | ## Will be called by acme.sh to add the txt record to your api system. | ||||||
|  | ## returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | ## Author: thewer <github at thewer.com> | ||||||
|  | ## GitHub: https://github.com/gitwer/acme.sh | ||||||
|  | 
 | ||||||
|  | ## | ||||||
|  | ## Environment Variables Required: | ||||||
|  | ## | ||||||
|  | ## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc" | ||||||
|  | ## | ||||||
|  | 
 | ||||||
|  | #####################  Public functions  ##################### | ||||||
|  | 
 | ||||||
|  | ## Create the text record for validation. | ||||||
|  | ## Usage: fulldomain txtvalue | ||||||
|  | ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs" | ||||||
|  | dns_dgon_add() { | ||||||
|  |   fulldomain="$(echo "$1" | _lower_case)" | ||||||
|  |   txtvalue=$2 | ||||||
|  |   _info "Using digitalocean dns validation - add record" | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  |   _debug txtvalue "$txtvalue" | ||||||
|  | 
 | ||||||
|  |   ## save the env vars (key and domain split location) for later automated use | ||||||
|  |   _saveaccountconf DO_API_KEY "$DO_API_KEY" | ||||||
|  | 
 | ||||||
|  |   ## split the domain for DO API | ||||||
|  |   if ! _get_base_domain "$fulldomain"; then | ||||||
|  |     _err "domain not found in your account for addition" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug _sub_domain "$_sub_domain" | ||||||
|  |   _debug _domain "$_domain" | ||||||
|  | 
 | ||||||
|  |   ## Set the header with our post type and key auth key | ||||||
|  |   export _H1="Content-Type: application/json" | ||||||
|  |   export _H2="Authorization: Bearer $DO_API_KEY" | ||||||
|  |   PURL='https://api.digitalocean.com/v2/domains/'$_domain'/records' | ||||||
|  |   PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'"}' | ||||||
|  | 
 | ||||||
|  |   _debug PURL "$PURL" | ||||||
|  |   _debug PBODY "$PBODY" | ||||||
|  | 
 | ||||||
|  |   ## the create request - post | ||||||
|  |   ## args: BODY, URL, [need64, httpmethod] | ||||||
|  |   response="$(_post "$PBODY" "$PURL")" | ||||||
|  | 
 | ||||||
|  |   ## check response | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error in response: $response" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  | 
 | ||||||
|  |   ## finished correctly | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ## Remove the txt record after validation. | ||||||
|  | ## Usage: fulldomain txtvalue | ||||||
|  | ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs" | ||||||
|  | dns_dgon_rm() { | ||||||
|  |   fulldomain="$(echo "$1" | _lower_case)" | ||||||
|  |   txtvalue=$2 | ||||||
|  |   _info "Using digitalocean dns validation - remove record" | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  |   _debug txtvalue "$txtvalue" | ||||||
|  | 
 | ||||||
|  |   ## split the domain for DO API | ||||||
|  |   if ! _get_base_domain "$fulldomain"; then | ||||||
|  |     _err "domain not found in your account for removal" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug _sub_domain "$_sub_domain" | ||||||
|  |   _debug _domain "$_domain" | ||||||
|  | 
 | ||||||
|  |   ## Set the header with our post type and key auth key | ||||||
|  |   export _H1="Content-Type: application/json" | ||||||
|  |   export _H2="Authorization: Bearer $DO_API_KEY" | ||||||
|  |   ## get URL for the list of domains | ||||||
|  |   ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}} | ||||||
|  |   GURL="https://api.digitalocean.com/v2/domains/$_domain/records" | ||||||
|  | 
 | ||||||
|  |   ## while we dont have a record ID we keep going | ||||||
|  |   while [ -z "$record" ]; do | ||||||
|  |     ## 1) get the URL | ||||||
|  |     ## the create request - get | ||||||
|  |     ## args: URL, [onlyheader, timeout] | ||||||
|  |     domain_list="$(_get "$GURL")" | ||||||
|  |     ## 2) find record | ||||||
|  |     ## check for what we are looing for: "type":"A","name":"$_sub_domain" | ||||||
|  |     record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*\d+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")" | ||||||
|  |     ## 3) check record and get next page | ||||||
|  |     if [ -z "$record" ]; then | ||||||
|  |       ## find the next page if we dont have a match | ||||||
|  |       nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=\d+")" | ||||||
|  |       if [ -z "$nextpage" ]; then | ||||||
|  |         _err "no record and no nextpage in digital ocean DNS removal" | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |       _debug2 nextpage "$nextpage" | ||||||
|  |       GURL="$nextpage" | ||||||
|  |     fi | ||||||
|  |     ## we break out of the loop when we have a record | ||||||
|  |   done | ||||||
|  | 
 | ||||||
|  |   ## we found the record | ||||||
|  |   rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*\d+" | _egrep_o "\d+")" | ||||||
|  |   _debug rec_id "$rec_id" | ||||||
|  | 
 | ||||||
|  |   ## delete the record | ||||||
|  |   ## delete URL for removing the one we dont want | ||||||
|  |   DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id" | ||||||
|  | 
 | ||||||
|  |   ## the create request - delete | ||||||
|  |   ## args: BODY, URL, [need64, httpmethod] | ||||||
|  |   response="$(_post "" "$DURL" "" "DELETE")" | ||||||
|  | 
 | ||||||
|  |   ## check response (sort of) | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error in remove response: $response" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  | 
 | ||||||
|  |   ## finished correctly | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #####################  Private functions below  ##################### | ||||||
|  | 
 | ||||||
|  | ## Split the domain provided into the "bade domain" and the "start prefix". | ||||||
|  | ## This function searches for the longest subdomain in your account | ||||||
|  | ## for the full domain given and splits it into the base domain (zone) | ||||||
|  | ## and the prefix/record to be added/removed | ||||||
|  | ## USAGE: fulldomain | ||||||
|  | ## EG: "_acme-challenge.two.three.four.domain.com" | ||||||
|  | ## returns | ||||||
|  | ## _sub_domain="_acme-challenge.two" | ||||||
|  | ## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists | ||||||
|  | ## if only "domain.com" exists it will return | ||||||
|  | ## _sub_domain="_acme-challenge.two.three.four" | ||||||
|  | ## _domain="domain.com" | ||||||
|  | _get_base_domain() { | ||||||
|  |   # args | ||||||
|  |   fulldomain="$(echo "$1" | tr '[:upper:]' '[:lower:]')" | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  | 
 | ||||||
|  |   # domain max legal length = 253 | ||||||
|  |   MAX_DOM=255 | ||||||
|  | 
 | ||||||
|  |   ## get a list of domains for the account to check thru | ||||||
|  |   ## Set the headers | ||||||
|  |   export _H1="Content-Type: application/json" | ||||||
|  |   export _H2="Authorization: Bearer $DO_API_KEY" | ||||||
|  |   _debug DO_API_KEY "$DO_API_KEY" | ||||||
|  |   ## get URL for the list of domains | ||||||
|  |   ## havent seen this request paginated, tested with 18 domains (more requires manual requests with DO) | ||||||
|  |   DOMURL="https://api.digitalocean.com/v2/domains" | ||||||
|  | 
 | ||||||
|  |   ## get the domain list (DO gives basically a full XFER!) | ||||||
|  |   domain_list="$(_get "$DOMURL")" | ||||||
|  | 
 | ||||||
|  |   ## check response | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error in domain_list response: $domain_list" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 domain_list "$domain_list" | ||||||
|  | 
 | ||||||
|  |   ## for each shortening of our $fulldomain, check if it exists in the $domain_list | ||||||
|  |   ## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge" | ||||||
|  |   i=2 | ||||||
|  |   while [ $i -gt 0 ]; do | ||||||
|  |     ## get next longest domain | ||||||
|  |     _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM") | ||||||
|  |     ## check we got something back from our cut (or are we at the end) | ||||||
|  |     if [ -z "$_domain" ]; then | ||||||
|  |       ## we got to the end of the domain - invalid domain | ||||||
|  |       _err "domain not found in DigitalOcean account" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     ## we got part of a domain back - grep it out | ||||||
|  |     found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")" | ||||||
|  |     ## check if it exists | ||||||
|  |     if [ ! -z "$found" ]; then | ||||||
|  |       ## exists - exit loop returning the parts | ||||||
|  |       sub_point=$(_math $i - 1) | ||||||
|  |       _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point") | ||||||
|  |       _debug _domain "$_domain" | ||||||
|  |       _debug _sub_domain "$_sub_domain" | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |     ## increment cut point $i | ||||||
|  |     i=$(_math $i + 1) | ||||||
|  |   done | ||||||
|  | 
 | ||||||
|  |   ## we went through the entire domain zone list and dint find one that matched | ||||||
|  |   ## doesnt look like we can add in the record | ||||||
|  |   _err "domain not found in DigitalOcean account, but we should never get here" | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
							
								
								
									
										215
									
								
								dnsapi/dns_dnsimple.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								dnsapi/dns_dnsimple.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,215 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | # DNSimple domain api | ||||||
|  | # https://github.com/pho3nixf1re/acme.sh/issues | ||||||
|  | # | ||||||
|  | # This is your oauth token which can be acquired on the account page. Please | ||||||
|  | # note that this must be an _account_ token and not a _user_ token. | ||||||
|  | # https://dnsimple.com/a/<your account id>/account/access_tokens | ||||||
|  | # DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||||
|  | 
 | ||||||
|  | DNSimple_API="https://api.dnsimple.com/v2" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | # Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_dnsimple_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if [ -z "$DNSimple_OAUTH_TOKEN" ]; then | ||||||
|  |     DNSimple_OAUTH_TOKEN="" | ||||||
|  |     _err "You have not set the dnsimple oauth token yet." | ||||||
|  |     _err "Please visit https://dnsimple.com/user to generate it." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   # save the oauth token for later | ||||||
|  |   _saveaccountconf DNSimple_OAUTH_TOKEN "$DNSimple_OAUTH_TOKEN" | ||||||
|  | 
 | ||||||
|  |   if ! _get_account_id; then | ||||||
|  |     _err "failed to retrive account id" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "invalid domain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _get_records "$_account_id" "$_domain" "$_sub_domain" | ||||||
|  | 
 | ||||||
|  |   if [ "$_records_count" = "0" ]; then | ||||||
|  |     _info "Adding record" | ||||||
|  |     if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then | ||||||
|  |       if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then | ||||||
|  |         _info "Added" | ||||||
|  |         return 0 | ||||||
|  |       else | ||||||
|  |         _err "Unexpected response while adding text record." | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |     fi | ||||||
|  |     _err "Add txt record error." | ||||||
|  |   else | ||||||
|  |     _info "Updating record" | ||||||
|  |     _extract_record_id "$_records" "$_sub_domain" | ||||||
|  | 
 | ||||||
|  |     if _dnsimple_rest \ | ||||||
|  |       PATCH \ | ||||||
|  |       "$_account_id/zones/$_domain/records/$_record_id" \ | ||||||
|  |       "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then | ||||||
|  | 
 | ||||||
|  |       _info "Updated!" | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     _err "Update error" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # fulldomain | ||||||
|  | dns_dnsimple_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  | 
 | ||||||
|  |   if ! _get_account_id; then | ||||||
|  |     _err "failed to retrive account id" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "invalid domain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _get_records "$_account_id" "$_domain" "$_sub_domain" | ||||||
|  |   _extract_record_id "$_records" "$_sub_domain" | ||||||
|  | 
 | ||||||
|  |   if [ "$_record_id" ]; then | ||||||
|  | 
 | ||||||
|  |     if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id"; then | ||||||
|  |       _info "removed record" "$_record_id" | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _err "failed to remove record" "$_record_id" | ||||||
|  |   return 1 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions bellow ################################## | ||||||
|  | # _acme-challenge.www.domain.com | ||||||
|  | # returns | ||||||
|  | #   _sub_domain=_acme-challenge.www | ||||||
|  | #   _domain=domain.com | ||||||
|  | _get_root() { | ||||||
|  |   domain=$1 | ||||||
|  |   i=2 | ||||||
|  |   previous=1 | ||||||
|  |   while true; do | ||||||
|  |     h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||||
|  |     if [ -z "$h" ]; then | ||||||
|  |       # not valid | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     if ! _dnsimple_rest GET "$_account_id/zones/$h"; then | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     if _contains "$response" 'not found'; then | ||||||
|  |       _debug "$h not found" | ||||||
|  |     else | ||||||
|  |       _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$previous) | ||||||
|  |       _domain="$h" | ||||||
|  | 
 | ||||||
|  |       _debug _domain "$_domain" | ||||||
|  |       _debug _sub_domain "$_sub_domain" | ||||||
|  | 
 | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     previous="$i" | ||||||
|  |     i=$(_math "$i" + 1) | ||||||
|  |   done | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # returns _account_id | ||||||
|  | _get_account_id() { | ||||||
|  |   _debug "retrive account id" | ||||||
|  |   if ! _dnsimple_rest GET "whoami"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if _contains "$response" "\"account\":null"; then | ||||||
|  |     _err "no account associated with this token" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if _contains "$response" "timeout"; then | ||||||
|  |     _err "timeout retrieving account id" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _account_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"email\":" | cut -d: -f2 | cut -d, -f1) | ||||||
|  |   _debug _account_id "$_account_id" | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # returns | ||||||
|  | #   _records | ||||||
|  | #   _records_count | ||||||
|  | _get_records() { | ||||||
|  |   account_id=$1 | ||||||
|  |   domain=$2 | ||||||
|  |   sub_domain=$3 | ||||||
|  | 
 | ||||||
|  |   _debug "fetching txt records" | ||||||
|  |   _dnsimple_rest GET "$account_id/zones/$domain/records?per_page=100" | ||||||
|  | 
 | ||||||
|  |   if ! _contains "$response" "\"id\":"; then | ||||||
|  |     _err "failed to retrieve records" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _records_count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$sub_domain\"" | wc -l | _egrep_o "[0-9]+") | ||||||
|  |   _records=$response | ||||||
|  |   _debug _records_count "$_records_count" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # returns _record_id | ||||||
|  | _extract_record_id() { | ||||||
|  |   _record_id=$(printf "%s" "$_records" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1) | ||||||
|  |   _debug "_record_id" "$_record_id" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # returns response | ||||||
|  | _dnsimple_rest() { | ||||||
|  |   method=$1 | ||||||
|  |   path="$2" | ||||||
|  |   data="$3" | ||||||
|  |   request_url="$DNSimple_API/$path" | ||||||
|  |   _debug "$path" | ||||||
|  | 
 | ||||||
|  |   export _H1="Accept: application/json" | ||||||
|  |   export _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" | ||||||
|  | 
 | ||||||
|  |   if [ "$data" ] || [ "$method" = "DELETE" ]; then | ||||||
|  |     _H1="Content-Type: application/json" | ||||||
|  |     _debug data "$data" | ||||||
|  |     response="$(_post "$data" "$request_url" "" "$method")" | ||||||
|  |   else | ||||||
|  |     response="$(_get "$request_url" "" "" "$method")" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error $request_url" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
							
								
								
									
										148
									
								
								dnsapi/dns_do.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										148
									
								
								dnsapi/dns_do.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,148 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | # DNS API for Domain-Offensive / Resellerinterface / Domainrobot | ||||||
|  | 
 | ||||||
|  | # Report bugs at https://github.com/seidler2547/acme.sh/issues | ||||||
|  | 
 | ||||||
|  | # set these environment variables to match your customer ID and password: | ||||||
|  | # DO_PID="KD-1234567" | ||||||
|  | # DO_PW="cdfkjl3n2" | ||||||
|  | 
 | ||||||
|  | DO_URL="https://soap.resellerinterface.de/" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_do_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  |   if _dns_do_authenticate; then | ||||||
|  |     _info "Adding TXT record to ${_domain} as ${fulldomain}" | ||||||
|  |     _dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300 | ||||||
|  |     if _contains "${response}" '>success<'; then | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |     _err "Could not create resource record, check logs" | ||||||
|  |   fi | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #fulldomain | ||||||
|  | dns_do_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   if _dns_do_authenticate; then | ||||||
|  |     if _dns_do_list_rrs; then | ||||||
|  |       _dns_do_had_error=0 | ||||||
|  |       for _rrid in ${_rr_list}; do | ||||||
|  |         _info "Deleting resource record $_rrid for $_domain" | ||||||
|  |         _dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}" | ||||||
|  |         if ! _contains "${response}" '>success<'; then | ||||||
|  |           _dns_do_had_error=1 | ||||||
|  |           _err "Could not delete resource record for ${_domain}, id ${_rrid}" | ||||||
|  |         fi | ||||||
|  |       done | ||||||
|  |       return $_dns_do_had_error | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | _dns_do_authenticate() { | ||||||
|  |   _info "Authenticating as ${DO_PID}" | ||||||
|  |   _dns_do_soap authPartner partner "${DO_PID}" password "${DO_PW}" | ||||||
|  |   if _contains "${response}" '>success<'; then | ||||||
|  |     _get_root "$fulldomain" | ||||||
|  |     _debug "_domain $_domain" | ||||||
|  |     return 0 | ||||||
|  |   else | ||||||
|  |     _err "Authentication failed, are DO_PID and DO_PW set correctly?" | ||||||
|  |   fi | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _dns_do_list_rrs() { | ||||||
|  |   _dns_do_soap getRRList origin "${_domain}" | ||||||
|  |   if ! _contains "${response}" 'SOAP-ENC:Array'; then | ||||||
|  |     _err "getRRList origin ${_domain} failed" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _rr_list="$(echo "${response}" \ | ||||||
|  |     | tr -d "\n\r\t" \ | ||||||
|  |     | sed -e 's/<item xsi:type="ns2:Map">/\n/g' \ | ||||||
|  |     | grep ">$(_regexcape "$fulldomain")</value>" \ | ||||||
|  |     | sed -e 's/<\/item>/\n/g' \ | ||||||
|  |     | grep '>id</key><value' \ | ||||||
|  |     | _egrep_o '>[0-9]{1,16}<' \ | ||||||
|  |     | tr -d '><')" | ||||||
|  |   [ "${_rr_list}" ] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _dns_do_soap() { | ||||||
|  |   func="$1" | ||||||
|  |   shift | ||||||
|  |   # put the parameters to xml | ||||||
|  |   body="<tns:${func} xmlns:tns=\"${DO_URL}\">" | ||||||
|  |   while [ "$1" ]; do | ||||||
|  |     _k="$1" | ||||||
|  |     shift | ||||||
|  |     _v="$1" | ||||||
|  |     shift | ||||||
|  |     body="$body<$_k>$_v</$_k>" | ||||||
|  |   done | ||||||
|  |   body="$body</tns:${func}>" | ||||||
|  |   _debug2 "SOAP request ${body}" | ||||||
|  | 
 | ||||||
|  |   # build SOAP XML | ||||||
|  |   _xml='<?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> | ||||||
|  |   <env:Body>'"$body"'</env:Body> | ||||||
|  | </env:Envelope>' | ||||||
|  | 
 | ||||||
|  |   # set SOAP headers | ||||||
|  |   export _H1="SOAPAction: ${DO_URL}#${func}" | ||||||
|  | 
 | ||||||
|  |   if ! response="$(_post "${_xml}" "${DO_URL}")"; then | ||||||
|  |     _err "Error <$1>" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 "SOAP response $response" | ||||||
|  | 
 | ||||||
|  |   # retrieve cookie header | ||||||
|  |   _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" | ||||||
|  |   export _H2 | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _get_root() { | ||||||
|  |   domain=$1 | ||||||
|  |   i=1 | ||||||
|  | 
 | ||||||
|  |   _dns_do_soap getDomainList | ||||||
|  |   _all_domains="$(echo "${response}" \ | ||||||
|  |     | tr -d "\n\r\t " \ | ||||||
|  |     | _egrep_o 'domain</key><value[^>]+>[^<]+' \ | ||||||
|  |     | sed -e 's/^domain<\/key><value[^>]*>//g')" | ||||||
|  | 
 | ||||||
|  |   while true; do | ||||||
|  |     h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||||
|  |     if [ -z "$h" ]; then | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     if _contains "${_all_domains}" "^$(_regexcape "$h")\$"; then | ||||||
|  |       _domain="$h" | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     i=$(_math $i + 1) | ||||||
|  |   done | ||||||
|  |   _debug "$domain not found" | ||||||
|  | 
 | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _regexcape() { | ||||||
|  |   echo "$1" | sed -e 's/\([]\.$*^[]\)/\\\1/g' | ||||||
|  | } | ||||||
| @ -6,9 +6,8 @@ | |||||||
| # | # | ||||||
| #DP_Key="sADDsdasdgdsf" | #DP_Key="sADDsdasdgdsf" | ||||||
| 
 | 
 | ||||||
| DP_Api="https://dnsapi.cn" | REST_API="https://dnsapi.cn" | ||||||
| 
 | 
 | ||||||
| #REST_API |  | ||||||
| ########  Public functions ##################### | ########  Public functions ##################### | ||||||
| 
 | 
 | ||||||
| #Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | #Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
| @ -24,8 +23,6 @@ dns_dp_add() { | |||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   REST_API="$DP_Api" |  | ||||||
| 
 |  | ||||||
|   #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 DP_Id "$DP_Id" | ||||||
|   _saveaccountconf DP_Key "$DP_Key" |   _saveaccountconf DP_Key "$DP_Key" | ||||||
| @ -50,9 +47,39 @@ dns_dp_add() { | |||||||
|   fi |   fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #fulldomain | #fulldomain txtvalue | ||||||
| dns_dp_rm() { | dns_dp_rm() { | ||||||
|   fulldomain=$1 |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  |   _debug "First detect the root zone" | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "invalid domain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then | ||||||
|  |     _err "Record.Lis error." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if _contains "$response" 'No records'; then | ||||||
|  |     _info "Don't need to remove." | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'"$txtvalue"'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \") | ||||||
|  |   _debug record_id "$record_id" | ||||||
|  |   if [ -z "$record_id" ]; then | ||||||
|  |     _err "Can not get record id." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _rest POST "Record.Remove" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then | ||||||
|  |     _err "Record.Remove error." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _contains "$response" "Action completed successful" | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -75,8 +102,9 @@ existing_records() { | |||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   if _contains "$response" "Action completed successful"; then |   if _contains "$response" "Action completed successful"; then | ||||||
|     count=$(printf "%s" "$response" | grep '<type>TXT</type>' | wc -l) |     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) |     record_id=$(printf "%s" "$response" | grep '^<id>' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) | ||||||
|  |     _debug record_id "$record_id" | ||||||
|     return 0 |     return 0 | ||||||
|   else |   else | ||||||
|     _err "get existing records error." |     _err "get existing records error." | ||||||
| @ -130,7 +158,7 @@ update_record() { | |||||||
|   return 1 #error |   return 1 #error | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| #_acme-challenge.www.domain.com | #_acme-challenge.www.domain.com | ||||||
| #returns | #returns | ||||||
| # _sub_domain=_acme-challenge.www | # _sub_domain=_acme-challenge.www | ||||||
| @ -171,7 +199,7 @@ _get_root() { | |||||||
| 
 | 
 | ||||||
| #Usage: method  URI  data | #Usage: method  URI  data | ||||||
| _rest() { | _rest() { | ||||||
|   m=$1 |   m="$1" | ||||||
|   ep="$2" |   ep="$2" | ||||||
|   data="$3" |   data="$3" | ||||||
|   _debug "$ep" |   _debug "$ep" | ||||||
| @ -179,11 +207,11 @@ _rest() { | |||||||
| 
 | 
 | ||||||
|   _debug url "$url" |   _debug url "$url" | ||||||
| 
 | 
 | ||||||
|   if [ "$data" ]; then |   if [ "$m" = "GET" ]; then | ||||||
|     _debug2 data "$data" |     response="$(_get "$url" | tr -d '\r')" | ||||||
|     response="$(_post "$data" "$url")" |  | ||||||
|   else |   else | ||||||
|     response="$(_get "$url")" |     _debug2 data "$data" | ||||||
|  |     response="$(_post "$data" "$url" | tr -d '\r')" | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   if [ "$?" != "0" ]; then |   if [ "$?" != "0" ]; then | ||||||
|  | |||||||
							
								
								
									
										128
									
								
								dnsapi/dns_duckdns.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										128
									
								
								dnsapi/dns_duckdns.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,128 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Created by RaidenII, to use DuckDNS's API to add/remove text records | ||||||
|  | #06/27/2017 | ||||||
|  | 
 | ||||||
|  | # Pass credentials before "acme.sh --issue --dns dns_duckdns ..." | ||||||
|  | # -- | ||||||
|  | # export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" | ||||||
|  | # -- | ||||||
|  | # | ||||||
|  | # Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure may need to be used with acme.sh | ||||||
|  | 
 | ||||||
|  | DuckDNS_API="https://www.duckdns.org/update" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: dns_duckdns_add _acme-challenge.domain.duckdns.org "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_duckdns_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}" | ||||||
|  |   if [ -z "$DuckDNS_Token" ]; then | ||||||
|  |     _err "You must export variable: DuckDNS_Token" | ||||||
|  |     _err "The token for your DuckDNS account is necessary." | ||||||
|  |     _err "You can look it up in your DuckDNS account." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   # Now save the credentials. | ||||||
|  |   _saveaccountconf_mutable DuckDNS_Token "$DuckDNS_Token" | ||||||
|  | 
 | ||||||
|  |   # Unfortunately, DuckDNS does not seems to support lookup domain through API | ||||||
|  |   # So I assume your credentials (which are your domain and token) are correct | ||||||
|  |   # If something goes wrong, we will get a KO response from DuckDNS | ||||||
|  | 
 | ||||||
|  |   if ! _duckdns_get_domain; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   # Now add the TXT record to DuckDNS | ||||||
|  |   _info "Trying to add TXT record" | ||||||
|  |   if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=$txtvalue"; then | ||||||
|  |     if [ "$response" = "OK" ]; then | ||||||
|  |       _info "TXT record has been successfully added to your DuckDNS domain." | ||||||
|  |       _info "Note that all subdomains under this domain uses the same TXT record." | ||||||
|  |       return 0 | ||||||
|  |     else | ||||||
|  |       _err "Errors happened during adding the TXT record, response=$response" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   else | ||||||
|  |     _err "Errors happened during adding the TXT record." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: fulldomain txtvalue | ||||||
|  | #Remove the txt record after validation. | ||||||
|  | dns_duckdns_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}" | ||||||
|  |   if [ -z "$DuckDNS_Token" ]; then | ||||||
|  |     _err "You must export variable: DuckDNS_Token" | ||||||
|  |     _err "The token for your DuckDNS account is necessary." | ||||||
|  |     _err "You can look it up in your DuckDNS account." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _duckdns_get_domain; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   # Now remove the TXT record from DuckDNS | ||||||
|  |   _info "Trying to remove TXT record" | ||||||
|  |   if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=&clear=true"; then | ||||||
|  |     if [ "$response" = "OK" ]; then | ||||||
|  |       _info "TXT record has been successfully removed from your DuckDNS domain." | ||||||
|  |       return 0 | ||||||
|  |     else | ||||||
|  |       _err "Errors happened during removing the TXT record, response=$response" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   else | ||||||
|  |     _err "Errors happened during removing the TXT record." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | 
 | ||||||
|  | #fulldomain=_acme-challenge.domain.duckdns.org | ||||||
|  | #returns | ||||||
|  | # _duckdns_domain=domain | ||||||
|  | _duckdns_get_domain() { | ||||||
|  | 
 | ||||||
|  |   # We'll extract the domain/username from full domain | ||||||
|  |   _duckdns_domain="$(printf "%s" "$fulldomain" | _lower_case | _egrep_o '[.][^.][^.]*[.]duckdns.org' | cut -d . -f 2)" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$_duckdns_domain" ]; then | ||||||
|  |     _err "Error extracting the domain." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: method URI | ||||||
|  | _duckdns_rest() { | ||||||
|  |   method=$1 | ||||||
|  |   param="$2" | ||||||
|  |   _debug param "$param" | ||||||
|  |   url="$DuckDNS_API?$param" | ||||||
|  |   _debug url "$url" | ||||||
|  | 
 | ||||||
|  |   # DuckDNS uses GET to update domain info | ||||||
|  |   if [ "$method" = "GET" ]; then | ||||||
|  |     response="$(_get "$url")" | ||||||
|  |   else | ||||||
|  |     _err "Unsupported method" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
							
								
								
									
										339
									
								
								dnsapi/dns_dyn.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								dnsapi/dns_dyn.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,339 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | # | ||||||
|  | # Dyn.com Domain API | ||||||
|  | # | ||||||
|  | # Author: Gerd Naschenweng | ||||||
|  | # https://github.com/magicdude4eva | ||||||
|  | # | ||||||
|  | # Dyn Managed DNS API | ||||||
|  | # https://help.dyn.com/dns-api-knowledge-base/ | ||||||
|  | # | ||||||
|  | # It is recommended to add a "Dyn Managed DNS" user specific for API access. | ||||||
|  | # The "Zones & Records Permissions" required by this script are: | ||||||
|  | # -- | ||||||
|  | # RecordAdd | ||||||
|  | # RecordUpdate | ||||||
|  | # RecordDelete | ||||||
|  | # RecordGet | ||||||
|  | # ZoneGet | ||||||
|  | # ZoneAddNode | ||||||
|  | # ZoneRemoveNode | ||||||
|  | # ZonePublish | ||||||
|  | # -- | ||||||
|  | # | ||||||
|  | # Pass credentials before "acme.sh --issue --dns dns_dyn ..." | ||||||
|  | # -- | ||||||
|  | # export DYN_Customer="customer" | ||||||
|  | # export DYN_Username="apiuser" | ||||||
|  | # export DYN_Password="secret" | ||||||
|  | # -- | ||||||
|  | 
 | ||||||
|  | DYN_API="https://api.dynect.net/REST" | ||||||
|  | 
 | ||||||
|  | #REST_API | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: add  _acme-challenge.www.domain.com   "Challenge-code" | ||||||
|  | dns_dyn_add() { | ||||||
|  |   fulldomain="$1" | ||||||
|  |   txtvalue="$2" | ||||||
|  | 
 | ||||||
|  |   DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" | ||||||
|  |   DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" | ||||||
|  |   DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" | ||||||
|  |   if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then | ||||||
|  |     DYN_Customer="" | ||||||
|  |     DYN_Username="" | ||||||
|  |     DYN_Password="" | ||||||
|  |     _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   #save the config variables to the account conf file. | ||||||
|  |   _saveaccountconf_mutable DYN_Customer "$DYN_Customer" | ||||||
|  |   _saveaccountconf_mutable DYN_Username "$DYN_Username" | ||||||
|  |   _saveaccountconf_mutable DYN_Password "$DYN_Password" | ||||||
|  | 
 | ||||||
|  |   if ! _dyn_get_authtoken; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ -z "$_dyn_authtoken" ]; then | ||||||
|  |     _dyn_end_session | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _dyn_get_zone; then | ||||||
|  |     _dyn_end_session | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _dyn_add_record; then | ||||||
|  |     _dyn_end_session | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _dyn_publish_zone; then | ||||||
|  |     _dyn_end_session | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _dyn_end_session | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: fulldomain txtvalue | ||||||
|  | #Remove the txt record after validation. | ||||||
|  | dns_dyn_rm() { | ||||||
|  |   fulldomain="$1" | ||||||
|  |   txtvalue="$2" | ||||||
|  | 
 | ||||||
|  |   DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" | ||||||
|  |   DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" | ||||||
|  |   DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" | ||||||
|  |   if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then | ||||||
|  |     DYN_Customer="" | ||||||
|  |     DYN_Username="" | ||||||
|  |     DYN_Password="" | ||||||
|  |     _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _dyn_get_authtoken; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ -z "$_dyn_authtoken" ]; then | ||||||
|  |     _dyn_end_session | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _dyn_get_zone; then | ||||||
|  |     _dyn_end_session | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _dyn_get_record_id; then | ||||||
|  |     _dyn_end_session | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ -z "$_dyn_record_id" ]; then | ||||||
|  |     _dyn_end_session | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _dyn_rm_record; then | ||||||
|  |     _dyn_end_session | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _dyn_publish_zone; then | ||||||
|  |     _dyn_end_session | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _dyn_end_session | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | 
 | ||||||
|  | #get Auth-Token | ||||||
|  | _dyn_get_authtoken() { | ||||||
|  | 
 | ||||||
|  |   _info "Start Dyn API Session" | ||||||
|  | 
 | ||||||
|  |   data="{\"customer_name\":\"$DYN_Customer\", \"user_name\":\"$DYN_Username\", \"password\":\"$DYN_Password\"}" | ||||||
|  |   dyn_url="$DYN_API/Session/" | ||||||
|  |   method="POST" | ||||||
|  | 
 | ||||||
|  |   _debug data "$data" | ||||||
|  |   _debug dyn_url "$dyn_url" | ||||||
|  | 
 | ||||||
|  |   export _H1="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |   response="$(_post "$data" "$dyn_url" "" "$method")" | ||||||
|  |   sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" | ||||||
|  | 
 | ||||||
|  |   _debug response "$response" | ||||||
|  |   _debug sessionstatus "$sessionstatus" | ||||||
|  | 
 | ||||||
|  |   if [ "$sessionstatus" = "success" ]; then | ||||||
|  |     _dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')" | ||||||
|  |     _info "Token received" | ||||||
|  |     _debug _dyn_authtoken "$_dyn_authtoken" | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _dyn_authtoken="" | ||||||
|  |   _err "get token failed" | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #fulldomain=_acme-challenge.www.domain.com | ||||||
|  | #returns | ||||||
|  | # _dyn_zone=domain.com | ||||||
|  | _dyn_get_zone() { | ||||||
|  |   i=2 | ||||||
|  |   while true; do | ||||||
|  |     domain="$(printf "%s" "$fulldomain" | cut -d . -f "$i-100")" | ||||||
|  |     if [ -z "$domain" ]; then | ||||||
|  |       break | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     dyn_url="$DYN_API/Zone/$domain/" | ||||||
|  | 
 | ||||||
|  |     export _H1="Auth-Token: $_dyn_authtoken" | ||||||
|  |     export _H2="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |     response="$(_get "$dyn_url" "" "")" | ||||||
|  |     sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" | ||||||
|  | 
 | ||||||
|  |     _debug dyn_url "$dyn_url" | ||||||
|  |     _debug response "$response" | ||||||
|  |     _debug sessionstatus "$sessionstatus" | ||||||
|  | 
 | ||||||
|  |     if [ "$sessionstatus" = "success" ]; then | ||||||
|  |       _dyn_zone="$domain" | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |     i=$(_math "$i" + 1) | ||||||
|  |   done | ||||||
|  | 
 | ||||||
|  |   _dyn_zone="" | ||||||
|  |   _err "get zone failed" | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #add TXT record | ||||||
|  | _dyn_add_record() { | ||||||
|  | 
 | ||||||
|  |   _info "Adding TXT record" | ||||||
|  | 
 | ||||||
|  |   data="{\"rdata\":{\"txtdata\":\"$txtvalue\"},\"ttl\":\"300\"}" | ||||||
|  |   dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" | ||||||
|  |   method="POST" | ||||||
|  | 
 | ||||||
|  |   export _H1="Auth-Token: $_dyn_authtoken" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |   response="$(_post "$data" "$dyn_url" "" "$method")" | ||||||
|  |   sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" | ||||||
|  | 
 | ||||||
|  |   _debug response "$response" | ||||||
|  |   _debug sessionstatus "$sessionstatus" | ||||||
|  | 
 | ||||||
|  |   if [ "$sessionstatus" = "success" ]; then | ||||||
|  |     _info "TXT Record successfully added" | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _err "add TXT record failed" | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #publish the zone | ||||||
|  | _dyn_publish_zone() { | ||||||
|  | 
 | ||||||
|  |   _info "Publishing zone" | ||||||
|  | 
 | ||||||
|  |   data="{\"publish\":\"true\"}" | ||||||
|  |   dyn_url="$DYN_API/Zone/$_dyn_zone/" | ||||||
|  |   method="PUT" | ||||||
|  | 
 | ||||||
|  |   export _H1="Auth-Token: $_dyn_authtoken" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |   response="$(_post "$data" "$dyn_url" "" "$method")" | ||||||
|  |   sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" | ||||||
|  | 
 | ||||||
|  |   _debug response "$response" | ||||||
|  |   _debug sessionstatus "$sessionstatus" | ||||||
|  | 
 | ||||||
|  |   if [ "$sessionstatus" = "success" ]; then | ||||||
|  |     _info "Zone published" | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _err "publish zone failed" | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #get record_id of TXT record so we can delete the record | ||||||
|  | _dyn_get_record_id() { | ||||||
|  | 
 | ||||||
|  |   _info "Getting record_id of TXT record" | ||||||
|  | 
 | ||||||
|  |   dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" | ||||||
|  | 
 | ||||||
|  |   export _H1="Auth-Token: $_dyn_authtoken" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |   response="$(_get "$dyn_url" "" "")" | ||||||
|  |   sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" | ||||||
|  | 
 | ||||||
|  |   _debug response "$response" | ||||||
|  |   _debug sessionstatus "$sessionstatus" | ||||||
|  | 
 | ||||||
|  |   if [ "$sessionstatus" = "success" ]; then | ||||||
|  |     _dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | _head_n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")" | ||||||
|  |     _debug _dyn_record_id "$_dyn_record_id" | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _dyn_record_id="" | ||||||
|  |   _err "getting record_id failed" | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #delete TXT record | ||||||
|  | _dyn_rm_record() { | ||||||
|  | 
 | ||||||
|  |   _info "Deleting TXT record" | ||||||
|  | 
 | ||||||
|  |   dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/$_dyn_record_id/" | ||||||
|  |   method="DELETE" | ||||||
|  | 
 | ||||||
|  |   _debug dyn_url "$dyn_url" | ||||||
|  | 
 | ||||||
|  |   export _H1="Auth-Token: $_dyn_authtoken" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |   response="$(_post "" "$dyn_url" "" "$method")" | ||||||
|  |   sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" | ||||||
|  | 
 | ||||||
|  |   _debug response "$response" | ||||||
|  |   _debug sessionstatus "$sessionstatus" | ||||||
|  | 
 | ||||||
|  |   if [ "$sessionstatus" = "success" ]; then | ||||||
|  |     _info "TXT record successfully deleted" | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _err "delete TXT record failed" | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #logout | ||||||
|  | _dyn_end_session() { | ||||||
|  | 
 | ||||||
|  |   _info "End Dyn API Session" | ||||||
|  | 
 | ||||||
|  |   dyn_url="$DYN_API/Session/" | ||||||
|  |   method="DELETE" | ||||||
|  | 
 | ||||||
|  |   _debug dyn_url "$dyn_url" | ||||||
|  | 
 | ||||||
|  |   export _H1="Auth-Token: $_dyn_authtoken" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |   response="$(_post "" "$dyn_url" "" "$method")" | ||||||
|  | 
 | ||||||
|  |   _debug response "$response" | ||||||
|  | 
 | ||||||
|  |   _dyn_authtoken="" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
							
								
								
									
										228
									
								
								dnsapi/dns_dynu.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								dnsapi/dns_dynu.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,228 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Client ID | ||||||
|  | #Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" | ||||||
|  | # | ||||||
|  | #Secret | ||||||
|  | #Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9" | ||||||
|  | # | ||||||
|  | #Token | ||||||
|  | Dynu_Token="" | ||||||
|  | # | ||||||
|  | #Endpoint | ||||||
|  | Dynu_EndPoint="https://api.dynu.com/v1" | ||||||
|  | # | ||||||
|  | #Author: Dynu Systems, Inc. | ||||||
|  | #Report Bugs here: https://github.com/shar0119/acme.sh | ||||||
|  | # | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_dynu_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then | ||||||
|  |     Dynu_ClientId="" | ||||||
|  |     Dynu_Secret="" | ||||||
|  |     _err "Dynu client id and secret is not specified." | ||||||
|  |     _err "Please create you API client id and secret and try again." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   #save the client id and secret to the account conf file. | ||||||
|  |   _saveaccountconf Dynu_ClientId "$Dynu_ClientId" | ||||||
|  |   _saveaccountconf Dynu_Secret "$Dynu_Secret" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$Dynu_Token" ]; then | ||||||
|  |     _info "Getting Dynu token." | ||||||
|  |     if ! _dynu_authentication; then | ||||||
|  |       _err "Can not get token." | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug "Detect root zone" | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "Invalid domain." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug _node "$_node" | ||||||
|  |   _debug _domain_name "$_domain_name" | ||||||
|  | 
 | ||||||
|  |   _info "Creating TXT record." | ||||||
|  |   if ! _dynu_rest POST "dns/record/add" "{\"domain_name\":\"$_domain_name\",\"node_name\":\"$_node\",\"record_type\":\"TXT\",\"text_data\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _contains "$response" "text_data"; then | ||||||
|  |     _err "Could not add TXT record." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_dynu_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then | ||||||
|  |     Dynu_ClientId="" | ||||||
|  |     Dynu_Secret="" | ||||||
|  |     _err "Dynu client id and secret is not specified." | ||||||
|  |     _err "Please create you API client id and secret and try again." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   #save the client id and secret to the account conf file. | ||||||
|  |   _saveaccountconf Dynu_ClientId "$Dynu_ClientId" | ||||||
|  |   _saveaccountconf Dynu_Secret "$Dynu_Secret" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$Dynu_Token" ]; then | ||||||
|  |     _info "Getting Dynu token." | ||||||
|  |     if ! _dynu_authentication; then | ||||||
|  |       _err "Can not get token." | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug "Detect root zone." | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "Invalid domain." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug _node "$_node" | ||||||
|  |   _debug _domain_name "$_domain_name" | ||||||
|  | 
 | ||||||
|  |   _info "Checking for TXT record." | ||||||
|  |   if ! _get_recordid "$fulldomain" "$txtvalue"; then | ||||||
|  |     _err "Could not get TXT record id." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$_dns_record_id" = "" ]; then | ||||||
|  |     _err "TXT record not found." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Removing TXT record." | ||||||
|  |   if ! _delete_txt_record "$_dns_record_id"; then | ||||||
|  |     _err "Could not remove TXT record $_dns_record_id." | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ########  Private functions below ################################## | ||||||
|  | #_acme-challenge.www.domain.com | ||||||
|  | #returns | ||||||
|  | # _node=_acme-challenge.www | ||||||
|  | # _domain_name=domain.com | ||||||
|  | _get_root() { | ||||||
|  |   domain=$1 | ||||||
|  |   i=2 | ||||||
|  |   p=1 | ||||||
|  |   while true; do | ||||||
|  |     h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||||
|  |     _debug h "$h" | ||||||
|  |     if [ -z "$h" ]; then | ||||||
|  |       #not valid | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     if ! _dynu_rest GET "dns/get/$h"; then | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     if _contains "$response" "\"name\":\"$h\"" >/dev/null; then | ||||||
|  |       _domain_name=$h | ||||||
|  |       _node=$(printf "%s" "$domain" | cut -d . -f 1-$p) | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |     p=$i | ||||||
|  |     i=$(_math "$i" + 1) | ||||||
|  |   done | ||||||
|  |   return 1 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _get_recordid() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if ! _dynu_rest GET "dns/record/get?hostname=$fulldomain&rrtype=TXT"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _contains "$response" "$txtvalue"; then | ||||||
|  |     _dns_record_id=0 | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | _egrep_o ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2) | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _delete_txt_record() { | ||||||
|  |   _dns_record_id=$1 | ||||||
|  | 
 | ||||||
|  |   if ! _dynu_rest GET "dns/record/delete/$_dns_record_id"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _contains "$response" "true"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _dynu_rest() { | ||||||
|  |   m=$1 | ||||||
|  |   ep="$2" | ||||||
|  |   data="$3" | ||||||
|  |   _debug "$ep" | ||||||
|  | 
 | ||||||
|  |   export _H1="Authorization: Bearer $Dynu_Token" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |   if [ "$data" ]; then | ||||||
|  |     _debug data "$data" | ||||||
|  |     response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")" | ||||||
|  |   else | ||||||
|  |     _info "Getting $Dynu_EndPoint/$ep" | ||||||
|  |     response="$(_get "$Dynu_EndPoint/$ep")" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error $ep" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _dynu_authentication() { | ||||||
|  |   realm="$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" | ||||||
|  | 
 | ||||||
|  |   export _H1="Authorization: Basic $realm" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |   response="$(_get "$Dynu_EndPoint/oauth2/token")" | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "Authentication failed." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   if _contains "$response" "accessToken"; then | ||||||
|  |     Dynu_Token=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 2 | cut -d : -f 2 | cut -d '"' -f 2) | ||||||
|  |   fi | ||||||
|  |   if _contains "$Dynu_Token" "null"; then | ||||||
|  |     Dynu_Token="" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
							
								
								
									
										362
									
								
								dnsapi/dns_freedns.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										362
									
								
								dnsapi/dns_freedns.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,362 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #This file name is "dns_freedns.sh" | ||||||
|  | #So, here must be a method dns_freedns_add() | ||||||
|  | #Which will be called by acme.sh to add the txt record to your api system. | ||||||
|  | #returns 0 means success, otherwise error. | ||||||
|  | # | ||||||
|  | #Author: David Kerr | ||||||
|  | #Report Bugs here: https://github.com/dkerr64/acme.sh | ||||||
|  | # | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | # Export FreeDNS userid and password in following variables... | ||||||
|  | #  FREEDNS_User=username | ||||||
|  | #  FREEDNS_Password=password | ||||||
|  | # login cookie is saved in acme account config file so userid / pw | ||||||
|  | # need to be set only when changed. | ||||||
|  | 
 | ||||||
|  | #Usage: dns_freedns_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_freedns_add() { | ||||||
|  |   fulldomain="$1" | ||||||
|  |   txtvalue="$2" | ||||||
|  | 
 | ||||||
|  |   _info "Add TXT record using FreeDNS" | ||||||
|  |   _debug "fulldomain: $fulldomain" | ||||||
|  |   _debug "txtvalue: $txtvalue" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$FREEDNS_User" ] || [ -z "$FREEDNS_Password" ]; then | ||||||
|  |     FREEDNS_User="" | ||||||
|  |     FREEDNS_Password="" | ||||||
|  |     if [ -z "$FREEDNS_COOKIE" ]; then | ||||||
|  |       _err "You did not specify the FreeDNS username and password yet." | ||||||
|  |       _err "Please export as FREEDNS_User / FREEDNS_Password and try again." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     using_cached_cookies="true" | ||||||
|  |   else | ||||||
|  |     FREEDNS_COOKIE="$(_freedns_login "$FREEDNS_User" "$FREEDNS_Password")" | ||||||
|  |     if [ -z "$FREEDNS_COOKIE" ]; then | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     using_cached_cookies="false" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug "FreeDNS login cookies: $FREEDNS_COOKIE (cached = $using_cached_cookies)" | ||||||
|  | 
 | ||||||
|  |   _saveaccountconf FREEDNS_COOKIE "$FREEDNS_COOKIE" | ||||||
|  | 
 | ||||||
|  |   # split our full domain name into two parts... | ||||||
|  |   i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" | ||||||
|  |   i="$(_math "$i" - 1)" | ||||||
|  |   top_domain="$(echo "$fulldomain" | cut -d. -f "$i"-100)" | ||||||
|  |   i="$(_math "$i" - 1)" | ||||||
|  |   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 | ||||||
|  |   # returns a page regarding becoming a premium member.  This usually | ||||||
|  |   # happens after a period of inactivity.  Immediately trying again | ||||||
|  |   # returns the correct subdomain page.  So, we will try twice to | ||||||
|  |   # load the page and obtain our domain ID | ||||||
|  |   attempts=2 | ||||||
|  |   while [ "$attempts" -gt "0" ]; do | ||||||
|  |     attempts="$(_math "$attempts" - 1)" | ||||||
|  |     htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" | ||||||
|  |     if [ "$?" != "0" ]; then | ||||||
|  |       if [ "$using_cached_cookies" = "true" ]; then | ||||||
|  |         _err "Has your FreeDNS username and password changed?  If so..." | ||||||
|  |         _err "Please export as FREEDNS_User / FREEDNS_Password and try again." | ||||||
|  |       fi | ||||||
|  |       return 1 | ||||||
|  |     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" | ||||||
|  | 
 | ||||||
|  |     # 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. | ||||||
|  |     # So all we should be left with is CSV of table of subdomains we are | ||||||
|  |     # interested in. | ||||||
|  | 
 | ||||||
|  |     # Now we have to read through this table and extract the data we need | ||||||
|  |     lines="$(echo "$subdomain_csv" | wc -l)" | ||||||
|  |     i=0 | ||||||
|  |     found=0 | ||||||
|  |     while [ "$i" -lt "$lines" ]; do | ||||||
|  |       i="$(_math "$i" + 1)" | ||||||
|  |       line="$(echo "$subdomain_csv" | sed -n "${i}p")" | ||||||
|  |       _debug2 line "$line" | ||||||
|  |       if [ $found = 0 ] && _contains "$line" "<td>$top_domain</td>"; then | ||||||
|  |         # this line will contain DNSdomainid for the top_domain | ||||||
|  |         DNSdomainid="$(echo "$line" | _egrep_o "edit_domain_id *= *.*>" | cut -d = -f 2 | cut -d '>' -f 1)" | ||||||
|  |         _debug2 DNSdomainid "$DNSdomainid" | ||||||
|  |         found=1 | ||||||
|  |       else | ||||||
|  |         # lines contain DNS records for all subdomains | ||||||
|  |         DNSname="$(echo "$line" | _egrep_o 'edit.php.*</a>' | cut -d '>' -f 2 | cut -d '<' -f 1)" | ||||||
|  |         _debug2 DNSname "$DNSname" | ||||||
|  |         DNStype="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '4p' | cut -d '>' -f 2 | cut -d '<' -f 1)" | ||||||
|  |         _debug2 DNStype "$DNStype" | ||||||
|  |         if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then | ||||||
|  |           DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)" | ||||||
|  |           # Now get current value for the TXT record.  This method may | ||||||
|  |           # not produce accurate results as the value field is truncated | ||||||
|  |           # on this webpage. To get full value we would need to load | ||||||
|  |           # another page. However we don't really need this so long as | ||||||
|  |           # there is only one TXT record for the acme challenge subdomain. | ||||||
|  |           DNSvalue="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '5p' | cut -d '>' -f 2 | cut -d '<' -f 1)" | ||||||
|  |           _debug2 DNSvalue "$DNSvalue" | ||||||
|  |           if [ $found != 0 ]; then | ||||||
|  |             break | ||||||
|  |             # we are breaking out of the loop at the first match of DNS name | ||||||
|  |             # and DNS type (if we are past finding the domainid). This assumes | ||||||
|  |             # that there is only ever one TXT record for the LetsEncrypt/acme | ||||||
|  |             # challenge subdomain.  This seems to be a reasonable assumption | ||||||
|  |             # as the acme client deletes the TXT record on successful validation. | ||||||
|  |           fi | ||||||
|  |         else | ||||||
|  |           DNSname="" | ||||||
|  |           DNStype="" | ||||||
|  |         fi | ||||||
|  |       fi | ||||||
|  |     done | ||||||
|  | 
 | ||||||
|  |     _debug "DNSname: $DNSname DNStype: $DNStype DNSdomainid: $DNSdomainid DNSdataid: $DNSdataid" | ||||||
|  |     _debug "DNSvalue: $DNSvalue" | ||||||
|  | 
 | ||||||
|  |     if [ -z "$DNSdomainid" ]; then | ||||||
|  |       # If domain ID is empty then something went wrong (top level | ||||||
|  |       # domain not found at FreeDNS). | ||||||
|  |       if [ "$attempts" = "0" ]; then | ||||||
|  |         # exhausted maximum retry attempts | ||||||
|  |         _debug "$htmlpage" | ||||||
|  |         _debug "$subdomain_csv" | ||||||
|  |         _err "Domain $top_domain not found at FreeDNS" | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |     else | ||||||
|  |       # break out of the 'retry' loop... we have found our domain ID | ||||||
|  |       break | ||||||
|  |     fi | ||||||
|  |     _info "Domain $top_domain not found at FreeDNS" | ||||||
|  |     _info "Retry loading subdomain page ($attempts attempts remaining)" | ||||||
|  |   done | ||||||
|  | 
 | ||||||
|  |   if [ -z "$DNSdataid" ]; then | ||||||
|  |     # If data ID is empty then specific subdomain does not exist yet, need | ||||||
|  |     # to create it this should always be the case as the acme client | ||||||
|  |     # deletes the entry after domain is validated. | ||||||
|  |     _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" | ||||||
|  |     return $? | ||||||
|  |   else | ||||||
|  |     if [ "$txtvalue" = "$DNSvalue" ]; then | ||||||
|  |       # if value in TXT record matches value requested then DNS record | ||||||
|  |       # does not need to be updated. But... | ||||||
|  |       # Testing value match fails.  Website is truncating the value field. | ||||||
|  |       # So for now we will always go down the else path.  Though in theory | ||||||
|  |       # should never come here anyway as the acme client deletes | ||||||
|  |       # the TXT record on successful validation, so we should not even | ||||||
|  |       # have found a TXT record !! | ||||||
|  |       _info "No update necessary for $fulldomain at FreeDNS" | ||||||
|  |       return 0 | ||||||
|  |     else | ||||||
|  |       # Delete the old TXT record (with the wrong value) | ||||||
|  |       if _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"; then | ||||||
|  |         # And add in new TXT record with the value provided | ||||||
|  |         _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" | ||||||
|  |       fi | ||||||
|  |       return $? | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: fulldomain txtvalue | ||||||
|  | #Remove the txt record after validation. | ||||||
|  | dns_freedns_rm() { | ||||||
|  |   fulldomain="$1" | ||||||
|  |   txtvalue="$2" | ||||||
|  | 
 | ||||||
|  |   _info "Delete TXT record using FreeDNS" | ||||||
|  |   _debug "fulldomain: $fulldomain" | ||||||
|  |   _debug "txtvalue: $txtvalue" | ||||||
|  | 
 | ||||||
|  |   # Need to read cookie from conf file again in case new value set | ||||||
|  |   # during login to FreeDNS when TXT record was created. | ||||||
|  |   # acme.sh does not have a _readaccountconf() function | ||||||
|  |   FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")" | ||||||
|  |   _debug "FreeDNS login cookies: $FREEDNS_COOKIE" | ||||||
|  | 
 | ||||||
|  |   # Sometimes FreeDNS does not return the subdomain page but rather | ||||||
|  |   # returns a page regarding becoming a premium member.  This usually | ||||||
|  |   # happens after a period of inactivity.  Immediately trying again | ||||||
|  |   # returns the correct subdomain page.  So, we will try twice to | ||||||
|  |   # load the page and obtain our TXT record. | ||||||
|  |   attempts=2 | ||||||
|  |   while [ "$attempts" -gt "0" ]; do | ||||||
|  |     attempts="$(_math "$attempts" - 1)" | ||||||
|  | 
 | ||||||
|  |     htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" | ||||||
|  |     if [ "$?" != "0" ]; then | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '<form .*</form>' | sed 's/<tr>/@<tr>/g' | tr '@' '\n' | grep edit.php | grep "$fulldomain")" | ||||||
|  |     _debug2 subdomain_csv "$subdomain_csv" | ||||||
|  | 
 | ||||||
|  |     # 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. | ||||||
|  |     # So all we should be left with is CSV of table of subdomains we are | ||||||
|  |     # interested in. | ||||||
|  | 
 | ||||||
|  |     # Now we have to read through this table and extract the data we need | ||||||
|  |     lines="$(echo "$subdomain_csv" | wc -l)" | ||||||
|  |     i=0 | ||||||
|  |     found=0 | ||||||
|  |     while [ "$i" -lt "$lines" ]; do | ||||||
|  |       i="$(_math "$i" + 1)" | ||||||
|  |       line="$(echo "$subdomain_csv" | sed -n "${i}p")" | ||||||
|  |       _debug2 line "$line" | ||||||
|  |       DNSname="$(echo "$line" | _egrep_o 'edit.php.*</a>' | cut -d '>' -f 2 | cut -d '<' -f 1)" | ||||||
|  |       _debug2 DNSname "$DNSname" | ||||||
|  |       DNStype="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '4p' | cut -d '>' -f 2 | cut -d '<' -f 1)" | ||||||
|  |       _debug2 DNStype "$DNStype" | ||||||
|  |       if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then | ||||||
|  |         DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)" | ||||||
|  |         _debug2 DNSdataid "$DNSdataid" | ||||||
|  |         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 | ||||||
|  |         # Testing value match fails.  Website is truncating the value | ||||||
|  |         # field. So for now we will assume that there is only one TXT | ||||||
|  |         # field for the sub domain and just delete it. Currently this | ||||||
|  |         # is a safe assumption. | ||||||
|  |         _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" | ||||||
|  |         return $? | ||||||
|  |         #     fi | ||||||
|  |       fi | ||||||
|  |     done | ||||||
|  |   done | ||||||
|  | 
 | ||||||
|  |   # If we get this far we did not find a match (after two attempts) | ||||||
|  |   # Not necessarily an error, but log anyway. | ||||||
|  |   _debug2 "$subdomain_csv" | ||||||
|  |   _info "Cannot delete TXT record for $fulldomain/$txtvalue. Does not exist at FreeDNS" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | 
 | ||||||
|  | # usage: _freedns_login username password | ||||||
|  | # print string "cookie=value" etc. | ||||||
|  | # returns 0 success | ||||||
|  | _freedns_login() { | ||||||
|  |   export _H1="Accept-Language:en-US" | ||||||
|  |   username="$1" | ||||||
|  |   password="$2" | ||||||
|  |   url="https://freedns.afraid.org/zc.php?step=2" | ||||||
|  | 
 | ||||||
|  |   _debug "Login to FreeDNS as user $username" | ||||||
|  | 
 | ||||||
|  |   htmlpage="$(_post "username=$(printf '%s' "$username" | _url_encode)&password=$(printf '%s' "$password" | _url_encode)&submit=Login&action=auth" "$url")" | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "FreeDNS login failed for user $username bad RC from _post" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   cookies="$(grep -i '^Set-Cookie.*dns_cookie.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" | ||||||
|  | 
 | ||||||
|  |   # if cookies is not empty then logon successful | ||||||
|  |   if [ -z "$cookies" ]; then | ||||||
|  |     _debug "$htmlpage" | ||||||
|  |     _err "FreeDNS login failed for user $username. Check $HTTP_HEADER file" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   printf "%s" "$cookies" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # usage _freedns_retrieve_subdomain_page login_cookies | ||||||
|  | # echo page retrieved (html) | ||||||
|  | # returns 0 success | ||||||
|  | _freedns_retrieve_subdomain_page() { | ||||||
|  |   export _H1="Cookie:$1" | ||||||
|  |   export _H2="Accept-Language:en-US" | ||||||
|  |   url="https://freedns.afraid.org/subdomain/" | ||||||
|  | 
 | ||||||
|  |   _debug "Retrieve subdomain page from FreeDNS" | ||||||
|  | 
 | ||||||
|  |   htmlpage="$(_get "$url")" | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "FreeDNS retrieve subdomains failed bad RC from _get" | ||||||
|  |     return 1 | ||||||
|  |   elif [ -z "$htmlpage" ]; then | ||||||
|  |     _err "FreeDNS returned empty subdomain page" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug2 "$htmlpage" | ||||||
|  | 
 | ||||||
|  |   printf "%s" "$htmlpage" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # usage _freedns_add_txt_record login_cookies domain_id subdomain value | ||||||
|  | # returns 0 success | ||||||
|  | _freedns_add_txt_record() { | ||||||
|  |   export _H1="Cookie:$1" | ||||||
|  |   export _H2="Accept-Language:en-US" | ||||||
|  |   domain_id="$2" | ||||||
|  |   subdomain="$3" | ||||||
|  |   value="$(printf '%s' "$4" | _url_encode)" | ||||||
|  |   url="http://freedns.afraid.org/subdomain/save.php?step=2" | ||||||
|  | 
 | ||||||
|  |   htmlpage="$(_post "type=TXT&domain_id=$domain_id&subdomain=$subdomain&address=%22$value%22&send=Save%21" "$url")" | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "FreeDNS failed to add TXT record for $subdomain bad RC from _post" | ||||||
|  |     return 1 | ||||||
|  |   elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then | ||||||
|  |     _debug "$htmlpage" | ||||||
|  |     _err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file" | ||||||
|  |     return 1 | ||||||
|  |   elif _contains "$htmlpage" "security code was incorrect"; then | ||||||
|  |     _debug "$htmlpage" | ||||||
|  |     _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested security code" | ||||||
|  |     _err "Note that you cannot use automatic DNS validation for FreeDNS public domains" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug2 "$htmlpage" | ||||||
|  |   _info "Added acme challenge TXT record for $fulldomain at FreeDNS" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # usage _freedns_delete_txt_record login_cookies data_id | ||||||
|  | # returns 0 success | ||||||
|  | _freedns_delete_txt_record() { | ||||||
|  |   export _H1="Cookie:$1" | ||||||
|  |   export _H2="Accept-Language:en-US" | ||||||
|  |   data_id="$2" | ||||||
|  |   url="https://freedns.afraid.org/subdomain/delete2.php" | ||||||
|  | 
 | ||||||
|  |   htmlheader="$(_get "$url?data_id%5B%5D=$data_id&submit=delete+selected" "onlyheader")" | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "FreeDNS failed to delete TXT record for $data_id bad RC from _get" | ||||||
|  |     return 1 | ||||||
|  |   elif ! _contains "$htmlheader" "200 OK"; then | ||||||
|  |     _debug "$htmlheader" | ||||||
|  |     _err "FreeDNS failed to delete TXT record $data_id" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Deleted acme challenge TXT record for $fulldomain at FreeDNS" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
							
								
								
									
										123
									
								
								dnsapi/dns_gandi_livedns.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										123
									
								
								dnsapi/dns_gandi_livedns.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,123 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | # Gandi LiveDNS v5 API | ||||||
|  | # http://doc.livedns.gandi.net/ | ||||||
|  | # currently under beta | ||||||
|  | # | ||||||
|  | # Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable | ||||||
|  | # | ||||||
|  | #Author: Frédéric Crozat <fcrozat@suse.com> | ||||||
|  | #Report Bugs here: https://github.com/fcrozat/acme.sh | ||||||
|  | # | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | GANDI_LIVEDNS_API="https://dns.api.gandi.net/api/v5" | ||||||
|  | 
 | ||||||
|  | #Usage: dns_gandi_livedns_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_gandi_livedns_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if [ -z "$GANDI_LIVEDNS_KEY" ]; then | ||||||
|  |     _err "No API key specified for Gandi LiveDNS." | ||||||
|  |     _err "Create your key and export it as GANDI_LIVEDNS_KEY" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY" | ||||||
|  | 
 | ||||||
|  |   _debug "First detect the root zone" | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "invalid domain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  |   _debug txtvalue "$txtvalue" | ||||||
|  |   _debug domain "$_domain" | ||||||
|  |   _debug sub_domain "$_sub_domain" | ||||||
|  | 
 | ||||||
|  |   _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \ | ||||||
|  |     && _contains "$response" '{"message": "DNS Record Created"}' \ | ||||||
|  |     && _info "Add $(__green "success")" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: fulldomain txtvalue | ||||||
|  | #Remove the txt record after validation. | ||||||
|  | dns_gandi_livedns_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   _debug "First detect the root zone" | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "invalid domain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  |   _debug domain "$_domain" | ||||||
|  |   _debug sub_domain "$_sub_domain" | ||||||
|  | 
 | ||||||
|  |   _gandi_livedns_rest DELETE "domains/$_domain/records/$_sub_domain/TXT" "" | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | #_acme-challenge.www.domain.com | ||||||
|  | #returns | ||||||
|  | # _sub_domain=_acme-challenge.www | ||||||
|  | # _domain=domain.com | ||||||
|  | _get_root() { | ||||||
|  |   domain=$1 | ||||||
|  |   i=2 | ||||||
|  |   p=1 | ||||||
|  |   while true; do | ||||||
|  |     h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||||
|  |     _debug h "$h" | ||||||
|  |     if [ -z "$h" ]; then | ||||||
|  |       #not valid | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     if ! _gandi_livedns_rest GET "domains/$h"; then | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     if _contains "$response" '"code": 401'; then | ||||||
|  |       _err "$response" | ||||||
|  |       return 1 | ||||||
|  |     elif _contains "$response" '"code": 404'; then | ||||||
|  |       _debug "$h not found" | ||||||
|  |     else | ||||||
|  |       _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) | ||||||
|  |       _domain="$h" | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |     p="$i" | ||||||
|  |     i=$(_math "$i" + 1) | ||||||
|  |   done | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _gandi_livedns_rest() { | ||||||
|  |   m=$1 | ||||||
|  |   ep="$2" | ||||||
|  |   data="$3" | ||||||
|  |   _debug "$ep" | ||||||
|  | 
 | ||||||
|  |   export _H1="Content-Type: application/json" | ||||||
|  |   export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY" | ||||||
|  | 
 | ||||||
|  |   if [ "$m" = "GET" ]; then | ||||||
|  |     response="$(_get "$GANDI_LIVEDNS_API/$ep")" | ||||||
|  |   else | ||||||
|  |     _debug data "$data" | ||||||
|  |     response="$(_post "$data" "$GANDI_LIVEDNS_API/$ep" "" "$m")" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error $ep" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
| @ -40,7 +40,7 @@ dns_gd_add() { | |||||||
|   if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then |   if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then | ||||||
|     if [ "$response" = "{}" ]; then |     if [ "$response" = "{}" ]; then | ||||||
|       _info "Added, sleeping 10 seconds" |       _info "Added, sleeping 10 seconds" | ||||||
|       sleep 10 |       _sleep 10 | ||||||
|       #todo: check if the record takes effect |       #todo: check if the record takes effect | ||||||
|       return 0 |       return 0 | ||||||
|     else |     else | ||||||
| @ -59,7 +59,7 @@ dns_gd_rm() { | |||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| #_acme-challenge.www.domain.com | #_acme-challenge.www.domain.com | ||||||
| #returns | #returns | ||||||
| # _sub_domain=_acme-challenge.www | # _sub_domain=_acme-challenge.www | ||||||
| @ -98,8 +98,8 @@ _gd_rest() { | |||||||
|   data="$3" |   data="$3" | ||||||
|   _debug "$ep" |   _debug "$ep" | ||||||
| 
 | 
 | ||||||
|   _H1="Authorization: sso-key $GD_Key:$GD_Secret" |   export _H1="Authorization: sso-key $GD_Key:$GD_Secret" | ||||||
|   _H2="Content-Type: application/json" |   export _H2="Content-Type: application/json" | ||||||
| 
 | 
 | ||||||
|   if [ "$data" ]; then |   if [ "$data" ]; then | ||||||
|     _debug data "$data" |     _debug data "$data" | ||||||
|  | |||||||
							
								
								
									
										175
									
								
								dnsapi/dns_he.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										175
									
								
								dnsapi/dns_he.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,175 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | ######################################################################## | ||||||
|  | # Hurricane Electric hook script for acme.sh | ||||||
|  | # | ||||||
|  | # Environment variables: | ||||||
|  | # | ||||||
|  | #  - $HE_Username  (your dns.he.net username) | ||||||
|  | #  - $HE_Password  (your dns.he.net password) | ||||||
|  | # | ||||||
|  | # Author: Ondrej Simek <me@ondrejsimek.com> | ||||||
|  | # Git repo: https://github.com/angel333/acme.sh | ||||||
|  | 
 | ||||||
|  | #-- dns_he_add() - Add TXT record -------------------------------------- | ||||||
|  | # Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..." | ||||||
|  | 
 | ||||||
|  | dns_he_add() { | ||||||
|  |   _full_domain=$1 | ||||||
|  |   _txt_value=$2 | ||||||
|  |   _info "Using DNS-01 Hurricane Electric hook" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then | ||||||
|  |     HE_Username= | ||||||
|  |     HE_Password= | ||||||
|  |     _err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _saveaccountconf HE_Username "$HE_Username" | ||||||
|  |   _saveaccountconf HE_Password "$HE_Password" | ||||||
|  | 
 | ||||||
|  |   # Fills in the $_zone_id | ||||||
|  |   _find_zone "$_full_domain" || return 1 | ||||||
|  |   _debug "Zone id \"$_zone_id\" will be used." | ||||||
|  | 
 | ||||||
|  |   body="email=${HE_Username}&pass=${HE_Password}" | ||||||
|  |   body="$body&account=" | ||||||
|  |   body="$body&menu=edit_zone" | ||||||
|  |   body="$body&Type=TXT" | ||||||
|  |   body="$body&hosted_dns_zoneid=$_zone_id" | ||||||
|  |   body="$body&hosted_dns_recordid=" | ||||||
|  |   body="$body&hosted_dns_editzone=1" | ||||||
|  |   body="$body&Priority=" | ||||||
|  |   body="$body&Name=$_full_domain" | ||||||
|  |   body="$body&Content=$_txt_value" | ||||||
|  |   body="$body&TTL=300" | ||||||
|  |   body="$body&hosted_dns_editrecord=Submit" | ||||||
|  |   response="$(_post "$body" "https://dns.he.net/")" | ||||||
|  |   exit_code="$?" | ||||||
|  |   if [ "$exit_code" -eq 0 ]; then | ||||||
|  |     _info "TXT record added successfully." | ||||||
|  |   else | ||||||
|  |     _err "Couldn't add the TXT record." | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return "$exit_code" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #-- dns_he_rm() - Remove TXT record ------------------------------------ | ||||||
|  | # Usage: dns_he_rm _acme-challenge.subdomain.domain.com "XyZ123..." | ||||||
|  | 
 | ||||||
|  | dns_he_rm() { | ||||||
|  |   _full_domain=$1 | ||||||
|  |   _txt_value=$2 | ||||||
|  |   _info "Cleaning up after DNS-01 Hurricane Electric hook" | ||||||
|  | 
 | ||||||
|  |   # fills in the $_zone_id | ||||||
|  |   _find_zone "$_full_domain" || return 1 | ||||||
|  |   _debug "Zone id \"$_zone_id\" will be used." | ||||||
|  | 
 | ||||||
|  |   # Find the record id to clean | ||||||
|  |   body="email=${HE_Username}&pass=${HE_Password}" | ||||||
|  |   body="$body&hosted_dns_zoneid=$_zone_id" | ||||||
|  |   body="$body&menu=edit_zone" | ||||||
|  |   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). | ||||||
|  | 
 | ||||||
|  |   # Remove the record | ||||||
|  |   body="email=${HE_Username}&pass=${HE_Password}" | ||||||
|  |   body="$body&menu=edit_zone" | ||||||
|  |   body="$body&hosted_dns_zoneid=$_zone_id" | ||||||
|  |   body="$body&hosted_dns_recordid=$_record_id" | ||||||
|  |   body="$body&hosted_dns_editzone=1" | ||||||
|  |   body="$body&hosted_dns_delrecord=1" | ||||||
|  |   body="$body&hosted_dns_delconfirm=delete" | ||||||
|  |   _post "$body" "https://dns.he.net/" \ | ||||||
|  |     | grep '<div id="dns_status" onClick="hideThis(this);">Successfully removed record.</div>' \ | ||||||
|  |       >/dev/null | ||||||
|  |   exit_code="$?" | ||||||
|  |   if [ "$exit_code" -eq 0 ]; then | ||||||
|  |     _info "Record removed successfully." | ||||||
|  |   else | ||||||
|  |     _err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand." | ||||||
|  |     return "$exit_code" | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ########################## 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() { | ||||||
|  | 
 | ||||||
|  |   _domain="$1" | ||||||
|  | 
 | ||||||
|  |   body="email=${HE_Username}&pass=${HE_Password}" | ||||||
|  |   _matches=$(_post "$body" "https://dns.he.net/" \ | ||||||
|  |     | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" | ||||||
|  |   ) | ||||||
|  |   # Zone names and zone IDs are in same order | ||||||
|  |   _zone_ids=$(echo "$_matches" | cut -d '"' -f 5) | ||||||
|  |   _zone_names=$(echo "$_matches" | cut -d '"' -f 3) | ||||||
|  |   _debug2 "These are the zones on this HE account:" | ||||||
|  |   _debug2 "$_zone_names" | ||||||
|  |   _debug2 "And these are their respective IDs:" | ||||||
|  |   _debug2 "$_zone_ids" | ||||||
|  | 
 | ||||||
|  |   # Walk through all possible zone names | ||||||
|  |   _strip_counter=1 | ||||||
|  |   while true; do | ||||||
|  |     _attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-) | ||||||
|  | 
 | ||||||
|  |     # All possible zone names have been tried | ||||||
|  |     if [ -z "$_attempted_zone" ]; then | ||||||
|  |       _err "No zone for domain \"$_domain\" found." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     _debug "Looking for zone \"${_attempted_zone}\"" | ||||||
|  | 
 | ||||||
|  |     # Take care of "." and only match whole lines. Note that grep -F | ||||||
|  |     # 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 | ||||||
|  |       _zone_id=$(echo "$_zone_ids" | sed "${line_num}q;d") | ||||||
|  |       _debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"." | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     _debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less specific zone." | ||||||
|  |     _strip_counter=$(_math "$_strip_counter" + 1) | ||||||
|  |   done | ||||||
|  | } | ||||||
|  | # vim: et:ts=2:sw=2: | ||||||
							
								
								
									
										102
									
								
								dnsapi/dns_infoblox.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								dnsapi/dns_infoblox.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,102 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | ## Infoblox API integration by Jason Keller and Elijah Tenai | ||||||
|  | ## | ||||||
|  | ## Report any bugs via https://github.com/jasonkeller/acme.sh | ||||||
|  | 
 | ||||||
|  | dns_infoblox_add() { | ||||||
|  | 
 | ||||||
|  |   ## Nothing to see here, just some housekeeping | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  |   baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View" | ||||||
|  | 
 | ||||||
|  |   _info "Using Infoblox API" | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  |   _debug txtvalue "$txtvalue" | ||||||
|  | 
 | ||||||
|  |   ## Check for the credentials | ||||||
|  |   if [ -z "$Infoblox_Creds" ] || [ -z "$Infoblox_Server" ]; then | ||||||
|  |     Infoblox_Creds="" | ||||||
|  |     Infoblox_Server="" | ||||||
|  |     _err "You didn't specify the credentials, server or infoblox view yet (Infoblox_Creds, Infoblox_Server and Infoblox_View)." | ||||||
|  |     _err "Please set them via EXPORT ([username:password], [ip or hostname]) and try again." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ -z "$Infoblox_View" ]; then | ||||||
|  |     Infoblox_View="default" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   ## Save the credentials to the account file | ||||||
|  |   _saveaccountconf Infoblox_Creds "$Infoblox_Creds" | ||||||
|  |   _saveaccountconf Infoblox_Server "$Infoblox_Server" | ||||||
|  |   _saveaccountconf Infoblox_View "$Infoblox_View" | ||||||
|  | 
 | ||||||
|  |   ## Base64 encode the credentials | ||||||
|  |   Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) | ||||||
|  | 
 | ||||||
|  |   ## Construct the HTTP Authorization header | ||||||
|  |   export _H1="Accept-Language:en-US" | ||||||
|  |   export _H2="Authorization: Basic $Infoblox_CredsEncoded" | ||||||
|  | 
 | ||||||
|  |   ## Add the challenge record to the Infoblox grid member | ||||||
|  |   result="$(_post "" "$baseurlnObject" "" "POST")" | ||||||
|  | 
 | ||||||
|  |   ## Let's see if we get something intelligible back from the unit | ||||||
|  |   if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then | ||||||
|  |     _info "Successfully created the txt record" | ||||||
|  |     return 0 | ||||||
|  |   else | ||||||
|  |     _err "Error encountered during record addition" | ||||||
|  |     _err "$result" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | dns_infoblox_rm() { | ||||||
|  | 
 | ||||||
|  |   ## Nothing to see here, just some housekeeping | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   _info "Using Infoblox API" | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  |   _debug txtvalue "$txtvalue" | ||||||
|  | 
 | ||||||
|  |   ## Base64 encode the credentials | ||||||
|  |   Infoblox_CredsEncoded="$(printf "%b" "$Infoblox_Creds" | _base64)" | ||||||
|  | 
 | ||||||
|  |   ## Construct the HTTP Authorization header | ||||||
|  |   export _H1="Accept-Language:en-US" | ||||||
|  |   export _H2="Authorization: Basic $Infoblox_CredsEncoded" | ||||||
|  | 
 | ||||||
|  |   ## Does the record exist?  Let's check. | ||||||
|  |   baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty" | ||||||
|  |   result="$(_get "$baseurlnObject")" | ||||||
|  | 
 | ||||||
|  |   ## Let's see if we get something intelligible back from the grid | ||||||
|  |   if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then | ||||||
|  |     ## Extract the object reference | ||||||
|  |     objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" | ||||||
|  |     objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" | ||||||
|  |     ## Delete them! All the stale records! | ||||||
|  |     rmResult="$(_post "" "$objRmUrl" "" "DELETE")" | ||||||
|  |     ## Let's see if that worked | ||||||
|  |     if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then | ||||||
|  |       _info "Successfully deleted $objRef" | ||||||
|  |       return 0 | ||||||
|  |     else | ||||||
|  |       _err "Error occurred during txt record delete" | ||||||
|  |       _err "$rmResult" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   else | ||||||
|  |     _err "Record to delete didn't match an existing record" | ||||||
|  |     _err "$result" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
							
								
								
									
										355
									
								
								dnsapi/dns_inwx.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										355
									
								
								dnsapi/dns_inwx.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,355 @@ | |||||||
|  | #!/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" | ||||||
|  |   _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 ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then | ||||||
|  |     _err "Error could net get txt records" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! printf "%s" "$response" | grep "count" >/dev/null; then | ||||||
|  |     _info "Adding record" | ||||||
|  |     _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue" | ||||||
|  |   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 "Updating record" | ||||||
|  |     _inwx_update_record "$_record_id" "$txtvalue" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #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 ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; 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 | ||||||
|  | } | ||||||
| @ -30,7 +30,7 @@ dns_ispconfig_rm() { | |||||||
|   _ISPC_credentials && _ISPC_login && _ISPC_rmTxt |   _ISPC_credentials && _ISPC_login && _ISPC_rmTxt | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| 
 | 
 | ||||||
| _ISPC_credentials() { | _ISPC_credentials() { | ||||||
|   if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then |   if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then | ||||||
| @ -46,7 +46,7 @@ _ISPC_credentials() { | |||||||
|     _saveaccountconf ISPC_Api "${ISPC_Api}" |     _saveaccountconf ISPC_Api "${ISPC_Api}" | ||||||
|     _saveaccountconf ISPC_Api_Insecure "${ISPC_Api_Insecure}" |     _saveaccountconf ISPC_Api_Insecure "${ISPC_Api_Insecure}" | ||||||
|     # Set whether curl should use secure or insecure mode |     # Set whether curl should use secure or insecure mode | ||||||
|     HTTPS_INSECURE="${ISPC_Api_Insecure}" |     export HTTPS_INSECURE="${ISPC_Api_Insecure}" | ||||||
|   fi |   fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										95
									
								
								dnsapi/dns_knot.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								dnsapi/dns_knot.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: dns_knot_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_knot_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  |   _checkKey || return 1 | ||||||
|  |   [ -n "${KNOT_SERVER}" ] || KNOT_SERVER="localhost" | ||||||
|  |   # save the dns server and key to the account.conf file. | ||||||
|  |   _saveaccountconf KNOT_SERVER "${KNOT_SERVER}" | ||||||
|  |   _saveaccountconf KNOT_KEY "${KNOT_KEY}" | ||||||
|  | 
 | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "Domain does not exist." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Adding ${fulldomain}. 60 TXT \"${txtvalue}\"" | ||||||
|  | 
 | ||||||
|  |   knsupdate -y "${KNOT_KEY}" <<EOF | ||||||
|  | server ${KNOT_SERVER} | ||||||
|  | zone ${_domain}. | ||||||
|  | update add ${fulldomain}. 60 TXT "${txtvalue}" | ||||||
|  | send | ||||||
|  | quit | ||||||
|  | EOF | ||||||
|  | 
 | ||||||
|  |   if [ $? -ne 0 ]; then | ||||||
|  |     _err "Error updating domain." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Domain TXT record successfully added." | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: dns_knot_rm   _acme-challenge.www.domain.com | ||||||
|  | dns_knot_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   _checkKey || return 1 | ||||||
|  |   [ -n "${KNOT_SERVER}" ] || KNOT_SERVER="localhost" | ||||||
|  | 
 | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "Domain does not exist." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Removing ${fulldomain}. TXT" | ||||||
|  | 
 | ||||||
|  |   knsupdate -y "${KNOT_KEY}" <<EOF | ||||||
|  | server ${KNOT_SERVER} | ||||||
|  | zone ${_domain}. | ||||||
|  | update del ${fulldomain}. TXT | ||||||
|  | send | ||||||
|  | quit | ||||||
|  | EOF | ||||||
|  | 
 | ||||||
|  |   if [ $? -ne 0 ]; then | ||||||
|  |     _err "error updating domain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Domain TXT record successfully deleted." | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | # _acme-challenge.www.domain.com | ||||||
|  | # returns | ||||||
|  | # _domain=domain.com | ||||||
|  | _get_root() { | ||||||
|  |   domain=$1 | ||||||
|  |   i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" | ||||||
|  |   i=$(_math "$i" - 1) | ||||||
|  | 
 | ||||||
|  |   while true; do | ||||||
|  |     h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) | ||||||
|  |     if [ -z "$h" ]; then | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _domain="$h" | ||||||
|  |     return 0 | ||||||
|  |   done | ||||||
|  |   _debug "$domain not found" | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _checkKey() { | ||||||
|  |   if [ -z "${KNOT_KEY}" ]; then | ||||||
|  |     _err "You must specify a TSIG key to authenticate the request." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | } | ||||||
| @ -2,7 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| # dns api wrapper of lexicon for acme.sh | # dns api wrapper of lexicon for acme.sh | ||||||
| 
 | 
 | ||||||
| lexicon_url="https://github.com/AnalogJ/lexicon" | # https://github.com/AnalogJ/lexicon | ||||||
| lexicon_cmd="lexicon" | lexicon_cmd="lexicon" | ||||||
| 
 | 
 | ||||||
| wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api" | wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api" | ||||||
| @ -30,33 +30,38 @@ dns_lexicon_add() { | |||||||
|   _savedomainconf PROVIDER "$PROVIDER" |   _savedomainconf PROVIDER "$PROVIDER" | ||||||
|   export PROVIDER |   export PROVIDER | ||||||
| 
 | 
 | ||||||
|   Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr '[a-z]' '[A-Z]') |   # e.g. busybox-ash does not know [:upper:] | ||||||
|  |   # shellcheck disable=SC2018,SC2019 | ||||||
|  |   Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z') | ||||||
|   Lx_name_v=$(eval echo \$"$Lx_name") |   Lx_name_v=$(eval echo \$"$Lx_name") | ||||||
|   _debug "$Lx_name" "$Lx_name_v" |   _secure_debug "$Lx_name" "$Lx_name_v" | ||||||
|   if [ "$Lx_name_v" ]; then |   if [ "$Lx_name_v" ]; then | ||||||
|     _saveaccountconf "$Lx_name" "$Lx_name_v" |     _saveaccountconf "$Lx_name" "$Lx_name_v" | ||||||
|     eval export "$Lx_name" |     eval export "$Lx_name" | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr '[a-z]' '[A-Z]') |   # shellcheck disable=SC2018,SC2019 | ||||||
|  |   Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z') | ||||||
|   Lx_token_v=$(eval echo \$"$Lx_token") |   Lx_token_v=$(eval echo \$"$Lx_token") | ||||||
|   _debug "$Lx_token" "$Lx_token_v" |   _secure_debug "$Lx_token" "$Lx_token_v" | ||||||
|   if [ "$Lx_token_v" ]; then |   if [ "$Lx_token_v" ]; then | ||||||
|     _saveaccountconf "$Lx_token" "$Lx_token_v" |     _saveaccountconf "$Lx_token" "$Lx_token_v" | ||||||
|     eval export "$Lx_token" |     eval export "$Lx_token" | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr '[a-z]' '[A-Z]') |   # shellcheck disable=SC2018,SC2019 | ||||||
|  |   Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z') | ||||||
|   Lx_password_v=$(eval echo \$"$Lx_password") |   Lx_password_v=$(eval echo \$"$Lx_password") | ||||||
|   _debug "$Lx_password" "$Lx_password_v" |   _secure_debug "$Lx_password" "$Lx_password_v" | ||||||
|   if [ "$Lx_password_v" ]; then |   if [ "$Lx_password_v" ]; then | ||||||
|     _saveaccountconf "$Lx_password" "$Lx_password_v" |     _saveaccountconf "$Lx_password" "$Lx_password_v" | ||||||
|     eval export "$Lx_password" |     eval export "$Lx_password" | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr '[a-z]' '[A-Z]') |   # shellcheck disable=SC2018,SC2019 | ||||||
|  |   Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z') | ||||||
|   Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") |   Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") | ||||||
|   _debug "$Lx_domaintoken" "$Lx_domaintoken_v" |   _secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v" | ||||||
|   if [ "$Lx_domaintoken_v" ]; then |   if [ "$Lx_domaintoken_v" ]; then | ||||||
|     eval export "$Lx_domaintoken" |     eval export "$Lx_domaintoken" | ||||||
|     _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v" |     _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v" | ||||||
|  | |||||||
							
								
								
									
										183
									
								
								dnsapi/dns_linode.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										183
									
								
								dnsapi/dns_linode.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,183 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Author: Philipp Grosswiler <philipp.grosswiler@swiss-design.net> | ||||||
|  | 
 | ||||||
|  | LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action=" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: dns_linode_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_linode_add() { | ||||||
|  |   fulldomain="${1}" | ||||||
|  |   txtvalue="${2}" | ||||||
|  | 
 | ||||||
|  |   if ! _Linode_API; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Using Linode" | ||||||
|  |   _debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'" | ||||||
|  | 
 | ||||||
|  |   _debug "First detect the root zone" | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "Domain does not exist." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug _domain_id "$_domain_id" | ||||||
|  |   _debug _sub_domain "$_sub_domain" | ||||||
|  |   _debug _domain "$_domain" | ||||||
|  | 
 | ||||||
|  |   _parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue" | ||||||
|  | 
 | ||||||
|  |   if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then | ||||||
|  |     _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) | ||||||
|  |     _debug _resource_id "$_resource_id" | ||||||
|  | 
 | ||||||
|  |     if [ -z "$_resource_id" ]; then | ||||||
|  |       _err "Error adding the domain resource." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     _info "Domain resource successfully added." | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: dns_linode_rm   _acme-challenge.www.domain.com | ||||||
|  | dns_linode_rm() { | ||||||
|  |   fulldomain="${1}" | ||||||
|  | 
 | ||||||
|  |   if ! _Linode_API; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Using Linode" | ||||||
|  |   _debug "Calling: dns_linode_rm() '${fulldomain}'" | ||||||
|  | 
 | ||||||
|  |   _debug "First detect the root zone" | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "Domain does not exist." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug _domain_id "$_domain_id" | ||||||
|  |   _debug _sub_domain "$_sub_domain" | ||||||
|  |   _debug _domain "$_domain" | ||||||
|  | 
 | ||||||
|  |   _parameters="&DomainID=$_domain_id" | ||||||
|  | 
 | ||||||
|  |   if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then | ||||||
|  |     response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" | ||||||
|  | 
 | ||||||
|  |     resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" | ||||||
|  |     if [ "$resource" ]; then | ||||||
|  |       _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) | ||||||
|  |       if [ "$_resource_id" ]; then | ||||||
|  |         _debug _resource_id "$_resource_id" | ||||||
|  | 
 | ||||||
|  |         _parameters="&DomainID=$_domain_id&ResourceID=$_resource_id" | ||||||
|  | 
 | ||||||
|  |         if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then | ||||||
|  |           _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) | ||||||
|  |           _debug _resource_id "$_resource_id" | ||||||
|  | 
 | ||||||
|  |           if [ -z "$_resource_id" ]; then | ||||||
|  |             _err "Error deleting the domain resource." | ||||||
|  |             return 1 | ||||||
|  |           fi | ||||||
|  | 
 | ||||||
|  |           _info "Domain resource successfully deleted." | ||||||
|  |           return 0 | ||||||
|  |         fi | ||||||
|  |       fi | ||||||
|  | 
 | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | 
 | ||||||
|  | _Linode_API() { | ||||||
|  |   if [ -z "$LINODE_API_KEY" ]; then | ||||||
|  |     LINODE_API_KEY="" | ||||||
|  | 
 | ||||||
|  |     _err "You didn't specify the Linode API key yet." | ||||||
|  |     _err "Please create your key and try again." | ||||||
|  | 
 | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _saveaccountconf LINODE_API_KEY "$LINODE_API_KEY" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | #_acme-challenge.www.domain.com | ||||||
|  | #returns | ||||||
|  | # _sub_domain=_acme-challenge.www | ||||||
|  | # _domain=domain.com | ||||||
|  | # _domain_id=12345 | ||||||
|  | _get_root() { | ||||||
|  |   domain=$1 | ||||||
|  |   i=2 | ||||||
|  |   p=1 | ||||||
|  | 
 | ||||||
|  |   if _rest GET "domain.list"; then | ||||||
|  |     response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" | ||||||
|  |     while true; do | ||||||
|  |       h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||||
|  |       _debug h "$h" | ||||||
|  |       if [ -z "$h" ]; then | ||||||
|  |         #not valid | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  | 
 | ||||||
|  |       hostedzone="$(echo "$response" | _egrep_o "{.*\"DOMAIN\":\s*\"$h\".*}")" | ||||||
|  |       if [ "$hostedzone" ]; then | ||||||
|  |         _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) | ||||||
|  |         if [ "$_domain_id" ]; then | ||||||
|  |           _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) | ||||||
|  |           _domain=$h | ||||||
|  |           return 0 | ||||||
|  |         fi | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |       p=$i | ||||||
|  |       i=$(_math "$i" + 1) | ||||||
|  |     done | ||||||
|  |   fi | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #method method action data | ||||||
|  | _rest() { | ||||||
|  |   mtd="$1" | ||||||
|  |   ep="$2" | ||||||
|  |   data="$3" | ||||||
|  | 
 | ||||||
|  |   _debug mtd "$mtd" | ||||||
|  |   _debug ep "$ep" | ||||||
|  | 
 | ||||||
|  |   export _H1="Accept: application/json" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |   if [ "$mtd" != "GET" ]; then | ||||||
|  |     # both POST and DELETE. | ||||||
|  |     _debug data "$data" | ||||||
|  |     response="$(_post "$data" "$LINODE_API_URL$ep" "" "$mtd")" | ||||||
|  |   else | ||||||
|  |     response="$(_get "$LINODE_API_URL$ep$data")" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error $ep" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
| @ -46,12 +46,12 @@ dns_lua_add() { | |||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l) |   count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ") | ||||||
|   _debug count "$count" |   _debug count "$count" | ||||||
|   if [ "$count" = "0" ]; then |   if [ "$count" = "0" ]; then | ||||||
|     _info "Adding record" |     _info "Adding record" | ||||||
|     if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then |     if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then | ||||||
|       if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then |       if _contains "$response" "$fulldomain"; then | ||||||
|         _info "Added" |         _info "Added" | ||||||
|         #todo: check if the record takes effect |         #todo: check if the record takes effect | ||||||
|         return 0 |         return 0 | ||||||
| @ -63,11 +63,11 @@ dns_lua_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 "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | cut -d: -f2 | cut -d, -f1) |     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" |     _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}" |     _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" ]; then |     if [ "$?" = "0" ] && _contains "$response" "updated_at"; then | ||||||
|       _info "Updated!" |       _info "Updated!" | ||||||
|       #todo: check if the record takes effect |       #todo: check if the record takes effect | ||||||
|       return 0 |       return 0 | ||||||
| @ -81,10 +81,39 @@ dns_lua_add() { | |||||||
| #fulldomain | #fulldomain | ||||||
| dns_lua_rm() { | dns_lua_rm() { | ||||||
|   fulldomain=$1 |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  |   _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" | ||||||
|  |   _LUA_rest GET "zones/${_domain_id}/records" | ||||||
|  | 
 | ||||||
|  |   count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ") | ||||||
|  |   _debug count "$count" | ||||||
|  |   if [ "$count" = "0" ]; then | ||||||
|  |     _info "Don't need to remove." | ||||||
|  |   else | ||||||
|  |     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" | ||||||
|  |     if [ -z "$record_id" ]; then | ||||||
|  |       _err "Can not get record id to remove." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     if ! _LUA_rest DELETE "/zones/$_domain_id/records/$record_id"; then | ||||||
|  |       _err "Delete record error." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _contains "$response" "$record_id" | ||||||
|  |   fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| #_acme-challenge.www.domain.com | #_acme-challenge.www.domain.com | ||||||
| #returns | #returns | ||||||
| # _sub_domain=_acme-challenge.www | # _sub_domain=_acme-challenge.www | ||||||
| @ -99,6 +128,7 @@ _get_root() { | |||||||
|   fi |   fi | ||||||
|   while true; do |   while true; do | ||||||
|     h=$(printf "%s" "$domain" | cut -d . -f $i-100) |     h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||||
|  |     _debug h "$h" | ||||||
|     if [ -z "$h" ]; then |     if [ -z "$h" ]; then | ||||||
|       #not valid |       #not valid | ||||||
|       return 1 |       return 1 | ||||||
| @ -106,6 +136,7 @@ _get_root() { | |||||||
| 
 | 
 | ||||||
|     if _contains "$response" "\"name\":\"$h\""; then |     if _contains "$response" "\"name\":\"$h\""; then | ||||||
|       _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1) |       _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1) | ||||||
|  |       _debug _domain_id "$_domain_id" | ||||||
|       if [ "$_domain_id" ]; then |       if [ "$_domain_id" ]; then | ||||||
|         _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) |         _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) | ||||||
|         _domain="$h" |         _domain="$h" | ||||||
| @ -125,9 +156,9 @@ _LUA_rest() { | |||||||
|   data="$3" |   data="$3" | ||||||
|   _debug "$ep" |   _debug "$ep" | ||||||
| 
 | 
 | ||||||
|   _H1="Accept: application/json" |   export _H1="Accept: application/json" | ||||||
|   _H2="Authorization: Basic $LUA_auth" |   export _H2="Authorization: Basic $LUA_auth" | ||||||
|   if [ "$data" ]; then |   if [ "$m" != "GET" ]; then | ||||||
|     _debug data "$data" |     _debug data "$data" | ||||||
|     response="$(_post "$data" "$LUA_Api/$ep" "" "$m")" |     response="$(_post "$data" "$LUA_Api/$ep" "" "$m")" | ||||||
|   else |   else | ||||||
|  | |||||||
							
								
								
									
										43
									
								
								dnsapi/dns_me.sh
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										43
									
								
								dnsapi/dns_me.sh
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -78,10 +78,39 @@ dns_me_add() { | |||||||
| #fulldomain | #fulldomain | ||||||
| dns_me_rm() { | dns_me_rm() { | ||||||
|   fulldomain=$1 |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  |   _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" | ||||||
|  |   _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" | ||||||
|  | 
 | ||||||
|  |   count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) | ||||||
|  |   _debug count "$count" | ||||||
|  |   if [ "$count" = "0" ]; then | ||||||
|  |     _info "Don't need to remove." | ||||||
|  |   else | ||||||
|  |     record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1) | ||||||
|  |     _debug "record_id" "$record_id" | ||||||
|  |     if [ -z "$record_id" ]; then | ||||||
|  |       _err "Can not get record id to remove." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     if ! _me_rest DELETE "$_domain_id/records/$record_id"; then | ||||||
|  |       _err "Delete record error." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _contains "$response" '' | ||||||
|  |   fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| #_acme-challenge.www.domain.com | #_acme-challenge.www.domain.com | ||||||
| #returns | #returns | ||||||
| # _sub_domain=_acme-challenge.www | # _sub_domain=_acme-challenge.www | ||||||
| @ -103,7 +132,7 @@ _get_root() { | |||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     if _contains "$response" "\"name\":\"$h\""; then |     if _contains "$response" "\"name\":\"$h\""; then | ||||||
|       _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | head -n 1 | cut -d : -f 2) |       _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | head -n 1 | cut -d : -f 2 | tr -d '}') | ||||||
|       if [ "$_domain_id" ]; then |       if [ "$_domain_id" ]; then | ||||||
|         _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) |         _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) | ||||||
|         _domain="$h" |         _domain="$h" | ||||||
| @ -124,13 +153,13 @@ _me_rest() { | |||||||
|   _debug "$ep" |   _debug "$ep" | ||||||
| 
 | 
 | ||||||
|   cdate=$(date -u +"%a, %d %b %Y %T %Z") |   cdate=$(date -u +"%a, %d %b %Y %T %Z") | ||||||
|   hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(_hex "$ME_Secret")" hex) |   hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | tr -d " ")" hex) | ||||||
| 
 | 
 | ||||||
|   _H1="x-dnsme-apiKey: $ME_Key" |   export _H1="x-dnsme-apiKey: $ME_Key" | ||||||
|   _H2="x-dnsme-requestDate: $cdate" |   export _H2="x-dnsme-requestDate: $cdate" | ||||||
|   _H3="x-dnsme-hmac: $hmac" |   export _H3="x-dnsme-hmac: $hmac" | ||||||
| 
 | 
 | ||||||
|   if [ "$data" ]; then |   if [ "$m" != "GET" ]; then | ||||||
|     _debug data "$data" |     _debug data "$data" | ||||||
|     response="$(_post "$data" "$ME_Api/$ep" "" "$m")" |     response="$(_post "$data" "$ME_Api/$ep" "" "$m")" | ||||||
|   else |   else | ||||||
|  | |||||||
| @ -5,48 +5,31 @@ | |||||||
| #So, here must be a method   dns_myapi_add() | #So, here must be a method   dns_myapi_add() | ||||||
| #Which will be called by acme.sh to add the txt record to your api system. | #Which will be called by acme.sh to add the txt record to your api system. | ||||||
| #returns 0 means success, otherwise error. | #returns 0 means success, otherwise error. | ||||||
| 
 | # | ||||||
|  | #Author: Neilpang | ||||||
|  | #Report Bugs here: https://github.com/Neilpang/acme.sh | ||||||
|  | # | ||||||
| ########  Public functions ##################### | ########  Public functions ##################### | ||||||
| 
 | 
 | ||||||
| #Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | #Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
| dns_myapi_add() { | dns_myapi_add() { | ||||||
|   fulldomain=$1 |   fulldomain=$1 | ||||||
|   txtvalue=$2 |   txtvalue=$2 | ||||||
|  |   _info "Using myapi" | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  |   _debug txtvalue "$txtvalue" | ||||||
|   _err "Not implemented!" |   _err "Not implemented!" | ||||||
|   return 1 |   return 1 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #fulldomain | #Usage: fulldomain txtvalue | ||||||
|  | #Remove the txt record after validation. | ||||||
| dns_myapi_rm() { | dns_myapi_rm() { | ||||||
|   fulldomain=$1 |   fulldomain=$1 | ||||||
| 
 |   txtvalue=$2 | ||||||
|  |   _info "Using myapi" | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  |   _debug txtvalue "$txtvalue" | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| _info() { |  | ||||||
|   if [ -z "$2" ]; then |  | ||||||
|     echo "[$(date)] $1" |  | ||||||
|   else |  | ||||||
|     echo "[$(date)] $1='$2'" |  | ||||||
|   fi |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| _err() { |  | ||||||
|   _info "$@" >&2 |  | ||||||
|   return 1 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| _debug() { |  | ||||||
|   if [ -z "$DEBUG" ]; then |  | ||||||
|     return |  | ||||||
|   fi |  | ||||||
|   _err "$@" |  | ||||||
|   return 0 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| _debug2() { |  | ||||||
|   if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then |  | ||||||
|     _debug "$@" |  | ||||||
|   fi |  | ||||||
|   return |  | ||||||
| } |  | ||||||
|  | |||||||
							
								
								
									
										193
									
								
								dnsapi/dns_namecom.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										193
									
								
								dnsapi/dns_namecom.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,193 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Author: RaidneII | ||||||
|  | #Created 06/28/2017 | ||||||
|  | #Utilize name.com API to finish dns-01 verifications. | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | Namecom_API="https://api.name.com/api" | ||||||
|  | 
 | ||||||
|  | #Usage: dns_namecom_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_namecom_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   # First we need name.com credentials. | ||||||
|  |   if [ -z "$Namecom_Username" ]; then | ||||||
|  |     Namecom_Username="" | ||||||
|  |     _err "Username for name.com is missing." | ||||||
|  |     _err "Please specify that in your environment variable." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ -z "$Namecom_Token" ]; then | ||||||
|  |     Namecom_Token="" | ||||||
|  |     _err "API token for name.com is missing." | ||||||
|  |     _err "Please specify that in your environment variable." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   # Save them in configuration. | ||||||
|  |   _saveaccountconf Namecom_Username "$Namecom_Username" | ||||||
|  |   _saveaccountconf Namecom_Token "$Namecom_Token" | ||||||
|  | 
 | ||||||
|  |   # Login in using API | ||||||
|  |   if ! _namecom_login; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   # Find domain in domain list. | ||||||
|  |   if ! _namecom_get_root "$fulldomain"; then | ||||||
|  |     _err "Unable to find domain specified." | ||||||
|  |     _namecom_logout | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   # Add TXT record. | ||||||
|  |   _namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}" | ||||||
|  |   if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then | ||||||
|  |     retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") | ||||||
|  |     if [ "$retcode" ]; then | ||||||
|  |       _info "Successfully added TXT record, ready for validation." | ||||||
|  |       _namecom_logout | ||||||
|  |       return 0 | ||||||
|  |     else | ||||||
|  |       _err "Unable to add the DNS record." | ||||||
|  |       _namecom_logout | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: fulldomain txtvalue | ||||||
|  | #Remove the txt record after validation. | ||||||
|  | dns_namecom_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if ! _namecom_login; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   # Find domain in domain list. | ||||||
|  |   if ! _namecom_get_root "$fulldomain"; then | ||||||
|  |     _err "Unable to find domain specified." | ||||||
|  |     _namecom_logout | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   # Get the record id. | ||||||
|  |   if _namecom_rest GET "dns/list/$_domain"; then | ||||||
|  |     retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") | ||||||
|  |     if [ "$retcode" ]; then | ||||||
|  |       _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d \" -f 4) | ||||||
|  |       _debug record_id "$_record_id" | ||||||
|  |       _info "Successfully retrieved the record id for ACME challenge." | ||||||
|  |     else | ||||||
|  |       _err "Unable to retrieve the record id." | ||||||
|  |       _namecom_logout | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   # Remove the DNS record using record id. | ||||||
|  |   _namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}" | ||||||
|  |   if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then | ||||||
|  |     retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") | ||||||
|  |     if [ "$retcode" ]; then | ||||||
|  |       _info "Successfully removed the TXT record." | ||||||
|  |       _namecom_logout | ||||||
|  |       return 0 | ||||||
|  |     else | ||||||
|  |       _err "Unable to remove the DNS record." | ||||||
|  |       _namecom_logout | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | _namecom_rest() { | ||||||
|  |   method=$1 | ||||||
|  |   param=$2 | ||||||
|  |   data=$3 | ||||||
|  | 
 | ||||||
|  |   export _H1="Content-Type: application/json" | ||||||
|  |   export _H2="Api-Session-Token: $sessionkey" | ||||||
|  |   if [ "$method" != "GET" ]; then | ||||||
|  |     response="$(_post "$data" "$Namecom_API/$param" "" "$method")" | ||||||
|  |   else | ||||||
|  |     response="$(_get "$Namecom_API/$param")" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error $param" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _namecom_login() { | ||||||
|  |   namecom_login_json="{\"username\":\"$Namecom_Username\",\"api_token\":\"$Namecom_Token\"}" | ||||||
|  | 
 | ||||||
|  |   if _namecom_rest POST "login" "$namecom_login_json"; then | ||||||
|  |     retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") | ||||||
|  |     if [ "$retcode" ]; then | ||||||
|  |       _info "Successfully logged in. Fetching session token..." | ||||||
|  |       sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4) | ||||||
|  |       if [ ! -z "$sessionkey" ]; then | ||||||
|  |         _debug sessionkey "$sessionkey" | ||||||
|  |         _info "Session key obtained." | ||||||
|  |       else | ||||||
|  |         _err "Unable to get session key." | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |     else | ||||||
|  |       _err "Logging in failed." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _namecom_logout() { | ||||||
|  |   if _namecom_rest GET "logout"; then | ||||||
|  |     retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") | ||||||
|  |     if [ "$retcode" ]; then | ||||||
|  |       _info "Successfully logged out." | ||||||
|  |     else | ||||||
|  |       _err "Error logging out." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _namecom_get_root() { | ||||||
|  |   domain=$1 | ||||||
|  |   i=2 | ||||||
|  |   p=1 | ||||||
|  | 
 | ||||||
|  |   if ! _namecom_rest GET "domain/list"; 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 | ||||||
|  | } | ||||||
							
								
								
									
										158
									
								
								dnsapi/dns_nsone.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								dnsapi/dns_nsone.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,158 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | # bug reports to dev@1e.ca | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | #NS1_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | NS1_Api="https://api.nsone.net/v1" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_nsone_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if [ -z "$NS1_Key" ]; then | ||||||
|  |     NS1_Key="" | ||||||
|  |     _err "You didn't specify nsone dns api key yet." | ||||||
|  |     _err "Please create you key and try again." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   #save the api key and email to the account conf file. | ||||||
|  |   _saveaccountconf NS1_Key "$NS1_Key" | ||||||
|  | 
 | ||||||
|  |   _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" | ||||||
|  |   _nsone_rest GET "zones/${_domain}" | ||||||
|  | 
 | ||||||
|  |   if ! _contains "$response" "\"records\":"; then | ||||||
|  |     _err "Error" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") | ||||||
|  |   _debug count "$count" | ||||||
|  |   if [ "$count" = "0" ]; then | ||||||
|  |     _info "Adding record" | ||||||
|  | 
 | ||||||
|  |     if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; 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 "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\",\"id\":\"[^,]*\"" | _head_n 1 | cut -d: -f7 | cut -d, -f1) | ||||||
|  |     _debug "record_id" "$record_id" | ||||||
|  | 
 | ||||||
|  |     _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}" | ||||||
|  |     if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then | ||||||
|  |       _info "Updated!" | ||||||
|  |       #todo: check if the record takes effect | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |     _err "Update error" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #fulldomain | ||||||
|  | dns_nsone_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  |   _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" | ||||||
|  |   _nsone_rest GET "zones/${_domain}/$fulldomain/TXT" | ||||||
|  | 
 | ||||||
|  |   count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",.*\"type\":\"TXT\"" | wc -l | tr -d " ") | ||||||
|  |   _debug count "$count" | ||||||
|  |   if [ "$count" = "0" ]; then | ||||||
|  |     _info "Don't need to remove." | ||||||
|  |   else | ||||||
|  |     if ! _nsone_rest DELETE "zones/${_domain}/$fulldomain/TXT"; then | ||||||
|  |       _err "Delete record error." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _contains "$response" "" | ||||||
|  |   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 | ||||||
|  |   if ! _nsone_rest GET "zones"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   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" "\"zone\":\"$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 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _nsone_rest() { | ||||||
|  |   m=$1 | ||||||
|  |   ep="$2" | ||||||
|  |   data="$3" | ||||||
|  |   _debug "$ep" | ||||||
|  | 
 | ||||||
|  |   export _H1="Accept: application/json" | ||||||
|  |   export _H2="X-NSONE-Key: $NS1_Key" | ||||||
|  |   if [ "$m" != "GET" ]; then | ||||||
|  |     _debug data "$data" | ||||||
|  |     response="$(_post "$data" "$NS1_Api/$ep" "" "$m")" | ||||||
|  |   else | ||||||
|  |     response="$(_get "$NS1_Api/$ep")" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error $ep" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
| @ -44,7 +44,7 @@ EOF | |||||||
|   return 0 |   return 0 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| 
 | 
 | ||||||
| _checkKeyFile() { | _checkKeyFile() { | ||||||
|   if [ -z "${NSUPDATE_KEY}" ]; then |   if [ -z "${NSUPDATE_KEY}" ]; then | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| #!/usr/bin/env sh | #!/usr/bin/env sh | ||||||
| 
 | 
 | ||||||
| #Applcation Key | #Application Key | ||||||
| #OVH_AK="sdfsdfsdfljlbjkljlkjsdfoiwje" | #OVH_AK="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||||
| # | # | ||||||
| #Application Secret | #Application Secret | ||||||
| @ -119,7 +119,7 @@ dns_ovh_add() { | |||||||
| 
 | 
 | ||||||
|   _info "Checking authentication" |   _info "Checking authentication" | ||||||
| 
 | 
 | ||||||
|   response="$(_ovh_rest GET "domain/")" |   response="$(_ovh_rest GET "domain")" | ||||||
|   if _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." | ||||||
| @ -182,7 +182,7 @@ dns_ovh_rm() { | |||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| 
 | 
 | ||||||
| _ovh_authentication() { | _ovh_authentication() { | ||||||
| 
 | 
 | ||||||
| @ -191,7 +191,7 @@ _ovh_authentication() { | |||||||
|   _H3="" |   _H3="" | ||||||
|   _H4="" |   _H4="" | ||||||
| 
 | 
 | ||||||
|   _ovhdata='{"accessRules": [{"method": "GET","path": "/*"},{"method": "POST","path": "/*"},{"method": "PUT","path": "/*"},{"method": "DELETE","path": "/*"}],"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/*"}],"redirection":"'$ovh_success'"}' | ||||||
| 
 | 
 | ||||||
|   response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" |   response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" | ||||||
|   _debug3 response "$response" |   _debug3 response "$response" | ||||||
| @ -207,7 +207,7 @@ _ovh_authentication() { | |||||||
|     _err "Unable to get consumerKey" |     _err "Unable to get consumerKey" | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|   _debug consumerKey "$consumerKey" |   _secure_debug consumerKey "$consumerKey" | ||||||
| 
 | 
 | ||||||
|   OVH_CK="$consumerKey" |   OVH_CK="$consumerKey" | ||||||
|   _saveaccountconf OVH_CK "$OVH_CK" |   _saveaccountconf OVH_CK "$OVH_CK" | ||||||
| @ -238,7 +238,7 @@ _get_root() { | |||||||
|       return 1 |       return 1 | ||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     if ! _contains "$response" "This service does not exist" >/dev/null; then |     if ! _contains "$response" "This service does not exist" >/dev/null && ! _contains "$response" "NOT_GRANTED_CALL" >/dev/null; then | ||||||
|       _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) |       _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) | ||||||
|       _domain="$h" |       _domain="$h" | ||||||
|       return 0 |       return 0 | ||||||
| @ -269,16 +269,16 @@ _ovh_rest() { | |||||||
|   _ovh_t="$(_ovh_timestamp)" |   _ovh_t="$(_ovh_timestamp)" | ||||||
|   _debug2 _ovh_t "$_ovh_t" |   _debug2 _ovh_t "$_ovh_t" | ||||||
|   _ovh_p="$OVH_AS+$OVH_CK+$m+$_ovh_url+$data+$_ovh_t" |   _ovh_p="$OVH_AS+$OVH_CK+$m+$_ovh_url+$data+$_ovh_t" | ||||||
|   _debug _ovh_p "$_ovh_p" |   _secure_debug _ovh_p "$_ovh_p" | ||||||
|   _ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)" |   _ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)" | ||||||
|   _debug2 _ovh_hex "$_ovh_hex" |   _debug2 _ovh_hex "$_ovh_hex" | ||||||
| 
 | 
 | ||||||
|   _H1="X-Ovh-Application: $OVH_AK" |   export _H1="X-Ovh-Application: $OVH_AK" | ||||||
|   _H2="X-Ovh-Signature: \$1\$$_ovh_hex" |   export _H2="X-Ovh-Signature: \$1\$$_ovh_hex" | ||||||
|   _debug2 _H2 "$_H2" |   _debug2 _H2 "$_H2" | ||||||
|   _H3="X-Ovh-Timestamp: $_ovh_t" |   export _H3="X-Ovh-Timestamp: $_ovh_t" | ||||||
|   _H4="X-Ovh-Consumer: $OVH_CK" |   export _H4="X-Ovh-Consumer: $OVH_CK" | ||||||
|   _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" ]; then | ||||||
|     _debug data "$data" |     _debug data "$data" | ||||||
|     response="$(_post "$data" "$_ovh_url" "" "$m")" |     response="$(_post "$data" "$_ovh_url" "" "$m")" | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| #!/usr/bin/env sh | #!/usr/bin/env sh | ||||||
| 
 | 
 | ||||||
| #PowerDNS Emdedded API | #PowerDNS Embedded API | ||||||
| #https://doc.powerdns.com/md/httpapi/api_spec/ | #https://doc.powerdns.com/md/httpapi/api_spec/ | ||||||
| # | # | ||||||
| #PDNS_Url="http://ns.example.com:8081" | #PDNS_Url="http://ns.example.com:8081" | ||||||
| @ -130,7 +130,7 @@ notify_slaves() { | |||||||
|   return 0 |   return 0 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions bellow ################################## | ####################  Private functions below ################################## | ||||||
| #_acme-challenge.www.domain.com | #_acme-challenge.www.domain.com | ||||||
| #returns | #returns | ||||||
| # _domain=domain.com | # _domain=domain.com | ||||||
| @ -165,7 +165,7 @@ _pdns_rest() { | |||||||
|   ep=$2 |   ep=$2 | ||||||
|   data=$3 |   data=$3 | ||||||
| 
 | 
 | ||||||
|   _H1="X-API-Key: $PDNS_Token" |   export _H1="X-API-Key: $PDNS_Token" | ||||||
| 
 | 
 | ||||||
|   if [ ! "$method" = "GET" ]; then |   if [ ! "$method" = "GET" ]; then | ||||||
|     _debug data "$data" |     _debug data "$data" | ||||||
|  | |||||||
							
								
								
									
										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 | ||||||
|  | } | ||||||
							
								
								
									
										149
									
								
								dnsapi/dns_vscale.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										149
									
								
								dnsapi/dns_vscale.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,149 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #This is the vscale.io api wrapper for acme.sh | ||||||
|  | # | ||||||
|  | #Author: Alex Loban | ||||||
|  | #Report Bugs here: https://github.com/LAV45/acme.sh | ||||||
|  | 
 | ||||||
|  | #VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||||
|  | VSCALE_API_URL="https://api.vscale.io/v1" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_vscale_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if [ -z "$VSCALE_API_KEY" ]; then | ||||||
|  |     VSCALE_API_KEY="" | ||||||
|  |     _err "You didn't specify the VSCALE api key yet." | ||||||
|  |     _err "Please create you key and try again." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _saveaccountconf VSCALE_API_KEY "$VSCALE_API_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" | ||||||
|  | 
 | ||||||
|  |   _vscale_tmpl_json="{\"type\":\"TXT\",\"name\":\"$_sub_domain.$_domain\",\"content\":\"$txtvalue\"}" | ||||||
|  | 
 | ||||||
|  |   if _vscale_rest POST "domains/$_domain_id/records/" "$_vscale_tmpl_json"; then | ||||||
|  |     response=$(printf "%s\n" "$response" | _egrep_o "{\"error\": \".+\"" | cut -d : -f 2) | ||||||
|  |     if [ -z "$response" ]; then | ||||||
|  |       _info "txt record updated success." | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #fulldomain txtvalue | ||||||
|  | dns_vscale_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   _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" | ||||||
|  |   _vscale_rest GET "domains/$_domain_id/records/" | ||||||
|  | 
 | ||||||
|  |   if [ -n "$response" ]; then | ||||||
|  |     record_id=$(printf "%s\n" "$response" | _egrep_o "\"TXT\", \"id\": [0-9]+, \"name\": \"$_sub_domain.$_domain\"" | cut -d : -f 2 | tr -d ", \"name\"") | ||||||
|  |     _debug record_id "$record_id" | ||||||
|  |     if [ -z "$record_id" ]; then | ||||||
|  |       _err "Can not get record id to remove." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     if _vscale_rest DELETE "domains/$_domain_id/records/$record_id" && [ -z "$response" ]; then | ||||||
|  |       _info "txt record deleted success." | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |     _debug response "$response" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | #_acme-challenge.www.domain.com | ||||||
|  | #returns | ||||||
|  | # _sub_domain=_acme-challenge.www | ||||||
|  | # _domain=domain.com | ||||||
|  | # _domain_id=12345 | ||||||
|  | _get_root() { | ||||||
|  |   domain=$1 | ||||||
|  |   i=2 | ||||||
|  |   p=1 | ||||||
|  | 
 | ||||||
|  |   if _vscale_rest GET "domains/"; then | ||||||
|  |     response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" | ||||||
|  |     while true; do | ||||||
|  |       h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||||
|  |       _debug h "$h" | ||||||
|  |       if [ -z "$h" ]; then | ||||||
|  |         #not valid | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  | 
 | ||||||
|  |       hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")" | ||||||
|  |       if [ "$hostedzone" ]; then | ||||||
|  |         _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) | ||||||
|  |         if [ "$_domain_id" ]; then | ||||||
|  |           _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) | ||||||
|  |           _domain=$h | ||||||
|  |           return 0 | ||||||
|  |         fi | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |       p=$i | ||||||
|  |       i=$(_math "$i" + 1) | ||||||
|  |     done | ||||||
|  |   fi | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #method uri qstr data | ||||||
|  | _vscale_rest() { | ||||||
|  |   mtd="$1" | ||||||
|  |   ep="$2" | ||||||
|  |   data="$3" | ||||||
|  | 
 | ||||||
|  |   _debug mtd "$mtd" | ||||||
|  |   _debug ep "$ep" | ||||||
|  | 
 | ||||||
|  |   export _H1="Accept: application/json" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  |   export _H3="X-Token: ${VSCALE_API_KEY}" | ||||||
|  | 
 | ||||||
|  |   if [ "$mtd" != "GET" ]; then | ||||||
|  |     # both POST and DELETE. | ||||||
|  |     _debug data "$data" | ||||||
|  |     response="$(_post "$data" "$VSCALE_API_URL/$ep" "" "$mtd")" | ||||||
|  |   else | ||||||
|  |     response="$(_get "$VSCALE_API_URL/$ep")" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error $ep" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
							
								
								
									
										107
									
								
								dnsapi/dns_yandex.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										107
									
								
								dnsapi/dns_yandex.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,107 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | # Author: non7top@gmail.com | ||||||
|  | # 07 Jul 2017 | ||||||
|  | # report bugs at https://github.com/non7top/acme.sh | ||||||
|  | 
 | ||||||
|  | # Values to export: | ||||||
|  | # export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_yandex_add() { | ||||||
|  |   fulldomain="${1}" | ||||||
|  |   txtvalue="${2}" | ||||||
|  |   _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" | ||||||
|  |   _PDD_credentials || return 1 | ||||||
|  |   export _H1="PddToken: $PDD_Token" | ||||||
|  | 
 | ||||||
|  |   curDomain=$(_PDD_get_domain "$fulldomain") | ||||||
|  |   _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}" | ||||||
|  |   curUri="https://pddimp.yandex.ru/api2/admin/dns/add" | ||||||
|  |   curResult="$(_post "${curData}" "${curUri}")" | ||||||
|  |   _debug "Result: $curResult" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: dns_myapi_rm   _acme-challenge.www.domain.com | ||||||
|  | dns_yandex_rm() { | ||||||
|  |   fulldomain="${1}" | ||||||
|  |   _debug "Calling: dns_yandex_rm() '${fulldomain}'" | ||||||
|  |   _PDD_credentials || return 1 | ||||||
|  |   export _H1="PddToken: $PDD_Token" | ||||||
|  |   record_id=$(pdd_get_record_id "${fulldomain}") | ||||||
|  |   _debug "Result: $record_id" | ||||||
|  | 
 | ||||||
|  |   curDomain=$(_PDD_get_domain "$fulldomain") | ||||||
|  |   _debug "Found suitable domain in pdd: $curDomain" | ||||||
|  |   curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" | ||||||
|  | 
 | ||||||
|  |   curUri="https://pddimp.yandex.ru/api2/admin/dns/del" | ||||||
|  |   curData="domain=${curDomain}&record_id=${record_id}" | ||||||
|  |   curResult="$(_post "${curData}" "${curUri}")" | ||||||
|  |   _debug "Result: $curResult" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | 
 | ||||||
|  | _PDD_get_domain() { | ||||||
|  |   fulldomain="${1}" | ||||||
|  |   __page=1 | ||||||
|  |   __last=0 | ||||||
|  |   while [ $__last -eq 0 ]; do | ||||||
|  |     uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" | ||||||
|  |     res1=$(_get "$uri1" | _normalizeJson) | ||||||
|  |     #_debug "$res1" | ||||||
|  |     __found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p') | ||||||
|  |     _debug "found: $__found results on page" | ||||||
|  |     if [ "$__found" -lt 20 ]; then | ||||||
|  |       _debug "last page: $__page" | ||||||
|  |       __last=1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     __all_domains="$__all_domains $(echo "$res1" | sed -e "s@,@\n@g" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')" | ||||||
|  | 
 | ||||||
|  |     __page=$(_math $__page + 1) | ||||||
|  |   done | ||||||
|  | 
 | ||||||
|  |   k=2 | ||||||
|  |   while [ $k -lt 10 ]; do | ||||||
|  |     __t=$(echo "$fulldomain" | cut -d . -f $k-100) | ||||||
|  |     _debug "finding zone for domain $__t" | ||||||
|  |     for d in $__all_domains; do | ||||||
|  |       if [ "$d" = "$__t" ]; then | ||||||
|  |         echo "$__t" | ||||||
|  |         return | ||||||
|  |       fi | ||||||
|  |     done | ||||||
|  |     k=$(_math $k + 1) | ||||||
|  |   done | ||||||
|  |   _err "No suitable domain found in your account" | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _PDD_credentials() { | ||||||
|  |   if [ -z "${PDD_Token}" ]; then | ||||||
|  |     PDD_Token="" | ||||||
|  |     _err "You need to export PDD_Token=xxxxxxxxxxxxxxxxx" | ||||||
|  |     _err "You can get it at https://pddimp.yandex.ru/api2/admin/get_token" | ||||||
|  |     return 1 | ||||||
|  |   else | ||||||
|  |     _saveaccountconf PDD_Token "${PDD_Token}" | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pdd_get_record_id() { | ||||||
|  |   fulldomain="${1}" | ||||||
|  | 
 | ||||||
|  |   curDomain=$(_PDD_get_domain "$fulldomain") | ||||||
|  |   _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}" | ||||||
|  |   curResult="$(_get "${curUri}" | _normalizeJson)" | ||||||
|  |   _debug "Result: $curResult" | ||||||
|  |   echo "$curResult" | _egrep_o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user