Browse Source

Merge remote-tracking branch 'upstream/master'

pull/2873/head
wurzelpanzer 6 years ago
parent
commit
2c9ba1d04e
  1. 4
      .github/ISSUE_TEMPLATE.md
  2. 2
      .github/PULL_REQUEST_TEMPLATE.md
  3. 28
      .github/auto-comment.yml
  4. 2
      .travis.yml
  5. 99
      README.md
  6. 173
      acme.sh
  7. 2
      deploy/README.md
  8. 2
      deploy/docker.sh
  9. 52
      deploy/haproxy.sh
  10. 139
      deploy/panos.sh
  11. 32
      deploy/qiniu.sh
  12. 26
      deploy/routeros.sh
  13. 155
      deploy/synology_dsm.sh
  14. 2
      dnsapi/README.md
  15. 254
      dnsapi/dns_1984hosting.sh
  16. 21
      dnsapi/dns_aws.sh
  17. 2
      dnsapi/dns_azure.sh
  18. 28
      dnsapi/dns_cf.sh
  19. 197
      dnsapi/dns_clouddns.sh
  20. 141
      dnsapi/dns_constellix.sh
  21. 2
      dnsapi/dns_cyon.sh
  22. 2
      dnsapi/dns_ddnss.sh
  23. 14
      dnsapi/dns_dp.sh
  24. 121
      dnsapi/dns_dynv6.sh
  25. 2
      dnsapi/dns_freedns.sh
  26. 2
      dnsapi/dns_gcloud.sh
  27. 5
      dnsapi/dns_inwx.sh
  28. 129
      dnsapi/dns_joker.sh
  29. 168
      dnsapi/dns_kas.sh
  30. 12
      dnsapi/dns_lexicon.sh
  31. 10
      dnsapi/dns_linode_v4.sh
  32. 2
      dnsapi/dns_me.sh
  33. 2
      dnsapi/dns_miab.sh
  34. 159
      dnsapi/dns_misaka.sh
  35. 4
      dnsapi/dns_myapi.sh
  36. 94
      dnsapi/dns_nic.sh
  37. 88
      dnsapi/dns_nm.sh
  38. 2
      dnsapi/dns_openprovider.sh
  39. 273
      dnsapi/dns_opnsense.sh
  40. 4
      dnsapi/dns_ovh.sh
  41. 2
      dnsapi/dns_pleskxml.sh
  42. 2
      dnsapi/dns_rackspace.sh
  43. 2
      dnsapi/dns_servercow.sh
  44. 2
      dnsapi/dns_unoeuro.sh
  45. 126
      dnsapi/dns_yandex.sh
  46. 4
      dnsapi/dns_zone.sh
  47. 64
      notify/cqhttp.sh

4
.github/ISSUE_TEMPLATE.md

@ -2,7 +2,7 @@
我很忙, 每天可能只有 几秒钟 时间看你的 issue, 如果不按照我的要求写 issue, 你可能不会得到任何回复, 石沉大海.
请确保已经更新到最新的代码, 然后贴上来 `--debug 2` 的调试输出. 没有调试信息. 我做不了什么.
如何调试 https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh
如何调试 https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
If it is a bug report:
- make sure you are able to repro it on the latest released version.
@ -10,7 +10,7 @@ You can install the latest version by: `acme.sh --upgrade`
- Search the existing issues.
- 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/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh).
-->

2
.github/PULL_REQUEST_TEMPLATE.md

@ -3,7 +3,7 @@
Please send to `dev` branch instead.
Any PR to `master` branch will NOT be merged.
2. For dns api support, read this guide first: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
2. For dns api support, read this guide first: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
You will NOT get any review without passing this guide. You also need to fix the CI errors.
-->

28
.github/auto-comment.yml

@ -0,0 +1,28 @@
# Comment to a new issue.
issuesOpened: >
If this is a bug report, please upgrade to the latest code and try again:
如果有 bug, 请先更新到最新版试试:
```sh
acme.sh --upgrade
```
please also provide the log with `--debug 2`.
see: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
pullRequestOpened: >
First, never send a PR to `master` branch, it will never be accepted. Please send to the `dev` branch instead.
If this is a PR to support new DNS API or new notification API, please read this guide first:
https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
Please check the guide items one by one.
Then add your usage here:
https://github.com/acmesh-official/acme.sh/wiki/dnsapi

2
.travis.yml

@ -28,7 +28,7 @@ script:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi
- cd ..
- git clone --depth 1 https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest
- git clone --depth 1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./rundocker.sh testplat ubuntu:latest ; fi
- if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi

99
README.md

@ -1,4 +1,4 @@
# An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)
# An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/acmesh-official/acme.sh.svg?branch=master)](https://travis-ci.org/acmesh-official/acme.sh)
<a href="https://opencollective.com/acmesh" alt="Financial Contributors on Open Collective"><img src="https://opencollective.com/acmesh/all/badge.svg?label=financial+contributors" /></a> [![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
- An ACME protocol client written purely in Shell (Unix shell) language.
@ -17,14 +17,14 @@
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/acmesh-official/acme.sh/wiki
For Docker Fans: [acme.sh :two_hearts: Docker ](https://github.com/Neilpang/acme.sh/wiki/Run-acme.sh-in-docker)
For Docker Fans: [acme.sh :two_hearts: Docker ](https://github.com/acmesh-official/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/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E)
# Who:
- [FreeBSD.org](https://blog.crashed.org/letsencrypt-in-freebsd-org/)
@ -40,41 +40,42 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
- [CentOS Web Panel](http://centos-webpanel.com/)
- [lnmp.org](https://lnmp.org/)
- [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials)
- [more...](https://github.com/acmesh-official/acme.sh/wiki/Blogs-and-tutorials)
# Tested OS
| NO | Status| Platform|
|----|-------|---------|
|1|[![](https://neilpang.github.io/acmetest/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Ubuntu
|2|[![](https://neilpang.github.io/acmetest/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Debian
|3|[![](https://neilpang.github.io/acmetest/status/centos-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|CentOS
|4|[![](https://neilpang.github.io/acmetest/status/windows-cygwin.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Windows (cygwin with curl, openssl and crontab included)
|5|[![](https://neilpang.github.io/acmetest/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|FreeBSD
|6|[![](https://neilpang.github.io/acmetest/status/pfsense.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|pfsense
|7|[![](https://neilpang.github.io/acmetest/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|openSUSE
|8|[![](https://neilpang.github.io/acmetest/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Alpine Linux (with curl)
|9|[![](https://neilpang.github.io/acmetest/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Archlinux
|10|[![](https://neilpang.github.io/acmetest/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|fedora
|11|[![](https://neilpang.github.io/acmetest/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Kali Linux
|12|[![](https://neilpang.github.io/acmetest/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Oracle Linux
|13|[![](https://neilpang.github.io/acmetest/status/proxmox.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh
|14|-----| Cloud Linux https://github.com/Neilpang/le/issues/111
|15|[![](https://neilpang.github.io/acmetest/status/openbsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|OpenBSD
|16|[![](https://neilpang.github.io/acmetest/status/mageia.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Mageia
|17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT)
|18|[![](https://neilpang.github.io/acmetest/status/solaris.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris
|19|[![](https://neilpang.github.io/acmetest/status/gentoo-stage3-amd64.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux
|20|[![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)|Mac OSX
For all build statuses, check our [weekly build project](https://github.com/Neilpang/acmetest):
https://github.com/Neilpang/acmetest
|1|[![](https://acmesh-official.github.io/acmetest/status/ubuntu-latest.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Ubuntu
|2|[![](https://acmesh-official.github.io/acmetest/status/debian-latest.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Debian
|3|[![](https://acmesh-official.github.io/acmetest/status/centos-latest.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|CentOS
|4|[![](https://acmesh-official.github.io/acmetest/status/windows-cygwin.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Windows (cygwin with curl, openssl and crontab included)
|5|[![](https://acmesh-official.github.io/acmetest/status/freebsd.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|FreeBSD
|6|[![](https://acmesh-official.github.io/acmetest/status/pfsense.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|pfsense
|7|[![](https://acmesh-official.github.io/acmetest/status/opensuse-leap.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|openSUSE
|8|[![](https://acmesh-official.github.io/acmetest/status/alpine-latest.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Alpine Linux (with curl)
|9|[![](https://acmesh-official.github.io/acmetest/status/archlinux-latest.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Archlinux
|10|[![](https://acmesh-official.github.io/acmetest/status/fedora-latest.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|fedora
|11|[![](https://acmesh-official.github.io/acmetest/status/kalilinux-kali.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Kali Linux
|12|[![](https://acmesh-official.github.io/acmetest/status/oraclelinux-latest.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Oracle Linux
|13|[![](https://acmesh-official.github.io/acmetest/status/proxmox.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh
|14|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111
|15|[![](https://acmesh-official.github.io/acmetest/status/openbsd.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|OpenBSD
|16|[![](https://acmesh-official.github.io/acmetest/status/mageia.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Mageia
|17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
|18|[![](https://acmesh-official.github.io/acmetest/status/solaris.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|SunOS/Solaris
|19|[![](https://acmesh-official.github.io/acmetest/status/gentoo-stage3-amd64.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Gentoo Linux
|20|[![Build Status](https://travis-ci.org/acmesh-official/acme.sh.svg?branch=master)](https://travis-ci.org/acmesh-official/acme.sh)|Mac OSX
|21|[![](https://acmesh-official.github.io/acmetest/status/clearlinux-latest.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)|ClearLinux
For all build statuses, check our [weekly build project](https://github.com/acmesh-official/acmetest):
https://github.com/acmesh-official/acmetest
# Supported CA
- Letsencrypt.org CA(default)
- [BuyPass.com CA](https://github.com/Neilpang/acme.sh/wiki/BuyPass.com-CA)
- [BuyPass.com CA](https://github.com/acmesh-official/acme.sh/wiki/BuyPass.com-CA)
- [Pebble strict Mode](https://github.com/letsencrypt/pebble)
# Supported modes
@ -85,15 +86,15 @@ https://github.com/Neilpang/acmetest
- Apache mode
- Nginx mode
- DNS mode
- [DNS alias mode](https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode)
- [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode)
- [DNS alias mode](https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode)
- [Stateless mode](https://github.com/acmesh-official/acme.sh/wiki/Stateless-Mode)
# 1. How to install
### 1. Install online
Check this project: https://github.com/Neilpang/get.acme.sh
Check this project: https://github.com/acmesh-official/get.acme.sh
```bash
curl https://get.acme.sh | sh
@ -111,14 +112,14 @@ wget -O - https://get.acme.sh | sh
Clone this project and launch installation:
```bash
git clone https://github.com/Neilpang/acme.sh.git
git clone https://github.com/acmesh-official/acme.sh.git
cd ./acme.sh
./acme.sh --install
```
You `don't have to be root` then, although `it is recommended`.
Advanced Installation: https://github.com/Neilpang/acme.sh/wiki/How-to-install
Advanced Installation: https://github.com/acmesh-official/acme.sh/wiki/How-to-install
The installer will perform 3 actions:
@ -180,7 +181,7 @@ The certs will be placed in `~/.acme.sh/example.com/`
The certs will be renewed automatically every **60** days.
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert
# 3. Install the cert to Apache/Nginx etc.
@ -226,7 +227,7 @@ Port `80` (TCP) **MUST** be free to listen on, otherwise you will be prompted to
acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com
```
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert
# 5. Use Standalone ssl server to issue cert
@ -238,7 +239,7 @@ Port `443` (TCP) **MUST** be free to listen on, otherwise you will be prompted t
acme.sh --issue --alpn -d example.com -d www.example.com -d cp.example.com
```
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert
# 6. Use Apache mode
@ -257,9 +258,9 @@ acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com
**This apache mode is only to issue the cert, it will not change your apache config files.
You will need to configure your website config files to use the cert by yourself.
We don't want to mess your apache server, don't worry.**
We don't want to mess with your apache server, don't worry.**
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert
# 7. Use Nginx mode
@ -281,9 +282,9 @@ acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com
**This nginx mode is only to issue the cert, it will not change your nginx config files.
You will need to configure your website config files to use the cert by yourself.
We don't want to mess your nginx server, don't worry.**
We don't want to mess with your nginx server, don't worry.**
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert
# 8. Automatic DNS API integration
@ -293,11 +294,11 @@ You don't have to do anything manually!
### Currently acme.sh supports most of the dns providers:
https://github.com/Neilpang/acme.sh/wiki/dnsapi
https://github.com/acmesh-official/acme.sh/wiki/dnsapi
# 9. Use DNS manual mode:
See: https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode first.
See: https://github.com/acmesh-official/acme.sh/wiki/dns-manual-mode first.
If your dns provider doesn't support any api access, you can add the txt record by your hand.
@ -430,12 +431,12 @@ acme.sh --upgrade --auto-upgrade 0
# 15. Issue a cert from an existing CSR
https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR
https://github.com/acmesh-official/acme.sh/wiki/Issue-a-cert-from-existing-CSR
# 16. Send notifications in cronjob
https://github.com/Neilpang/acme.sh/wiki/notify
https://github.com/acmesh-official/acme.sh/wiki/notify
# 17. Under the Hood
@ -456,7 +457,7 @@ TODO:
### Code Contributors
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="https://github.com/Neilpang/acme.sh/graphs/contributors"><img src="https://opencollective.com/acmesh/contributors.svg?width=890&button=false" /></a>
<a href="https://github.com/acmesh-official/acme.sh/graphs/contributors"><img src="https://opencollective.com/acmesh/contributors.svg?width=890&button=false" /></a>
### Financial Contributors
@ -487,7 +488,7 @@ License is GPLv3
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/acmesh-official/acme.sh/issues) and [pull requests](https://github.com/acmesh-official/acme.sh/pulls) are welcome.
# 20. Donate
@ -495,4 +496,4 @@ Your donation makes **acme.sh** better:
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/acmesh-official/acme.sh/wiki/Donate-list)

173
acme.sh

@ -1,12 +1,12 @@
#!/usr/bin/env sh
VER=2.8.4
VER=2.8.6
PROJECT_NAME="acme.sh"
PROJECT_ENTRY="acme.sh"
PROJECT="https://github.com/Neilpang/$PROJECT_NAME"
PROJECT="https://github.com/acmesh-official/$PROJECT_NAME"
DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME"
@ -48,8 +48,6 @@ LOCAL_ANY_ADDRESS="0.0.0.0"
DEFAULT_RENEW=60
DEFAULT_DNS_SLEEP=120
NO_VALUE="no"
W_DNS="dns"
@ -126,19 +124,19 @@ NOTIFY_MODE_CERT=1
NOTIFY_MODE_DEFAULT=$NOTIFY_MODE_BULK
_DEBUG_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh"
_DEBUG_WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh"
_PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations"
_PREPARE_LINK="https://github.com/acmesh-official/acme.sh/wiki/Install-preparations"
_STATELESS_WIKI="https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode"
_STATELESS_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Stateless-Mode"
_DNS_ALIAS_WIKI="https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode"
_DNS_ALIAS_WIKI="https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode"
_DNS_MANUAL_WIKI="https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode"
_DNS_MANUAL_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dns-manual-mode"
_NOTIFY_WIKI="https://github.com/Neilpang/acme.sh/wiki/notify"
_NOTIFY_WIKI="https://github.com/acmesh-official/acme.sh/wiki/notify"
_SUDO_WIKI="https://github.com/Neilpang/acme.sh/wiki/sudo"
_SUDO_WIKI="https://github.com/acmesh-official/acme.sh/wiki/sudo"
_DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead."
@ -207,7 +205,7 @@ _dlg_versions() {
echo "socat:"
if _exists "socat"; then
socat -h 2>&1
socat -V 2>&1
else
_debug "socat doesn't exists."
fi
@ -848,6 +846,14 @@ _json_encode() {
echo "$_j_str" | _hex_dump | _lower_case | sed 's/0a/5c 6e/g' | tr -d ' ' | _h2b | tr -d "\r\n"
}
#from: http:\/\/ to http://
_json_decode() {
_j_str="$(sed 's#\\/#/#g')"
_debug3 "_json_decode"
_debug3 "_j_str" "$_j_str"
echo "$_j_str"
}
#options file
_sed_i() {
options="$1"
@ -2019,7 +2025,7 @@ _send_signed_request() {
_debug code "$code"
_debug2 original "$response"
if echo "$responseHeaders" | grep -i "Content-Type: application/json" >/dev/null 2>&1; then
if echo "$responseHeaders" | grep -i "Content-Type: *application/json" >/dev/null 2>&1; then
response="$(echo "$response" | _normalizeJson)"
fi
_debug2 response "$response"
@ -2040,8 +2046,10 @@ _send_signed_request() {
continue
fi
fi
break
return 0
done
_info "Giving up sending to CA server after $MAX_REQUEST_RETRY_TIMES retries."
return 1
}
@ -2164,7 +2172,7 @@ _getdeployconf() {
return 0 # do nothing
fi
_saved=$(_readdomainconf "SAVED_$_rac_key")
eval "export $_rac_key=$_saved"
eval "export $_rac_key=\"$_saved\""
}
#_saveaccountconf key value base64encode
@ -2413,7 +2421,7 @@ __initHome() {
if [ -z "$ACCOUNT_CONF_PATH" ]; then
ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH"
fi
_debug3 ACCOUNT_CONF_PATH "$ACCOUNT_CONF_PATH"
DEFAULT_LOG_FILE="$LE_CONFIG_HOME/$PROJECT_NAME.log"
DEFAULT_CA_HOME="$LE_CONFIG_HOME/ca"
@ -3417,13 +3425,13 @@ _regAccount() {
if [ "$ACME_VERSION" = "2" ]; then
regjson='{"termsOfServiceAgreed": true}'
if [ "$ACCOUNT_EMAIL" ]; then
regjson='{"contact": ["mailto: '$ACCOUNT_EMAIL'"], "termsOfServiceAgreed": true}'
regjson='{"contact": ["mailto:'$ACCOUNT_EMAIL'"], "termsOfServiceAgreed": true}'
fi
else
_reg_res="$ACME_NEW_ACCOUNT_RES"
regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
if [ "$ACCOUNT_EMAIL" ]; then
regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
regjson='{"resource": "'$_reg_res'", "contact": ["mailto:'$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
fi
fi
@ -3445,7 +3453,7 @@ _regAccount() {
fi
_debug2 responseHeaders "$responseHeaders"
_accUri="$(echo "$responseHeaders" | grep -i "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
_accUri="$(echo "$responseHeaders" | grep -i "^Location:" | _head_n 1 | cut -d ':' -f 2- | tr -d "\r\n ")"
_debug "_accUri" "$_accUri"
if [ -z "$_accUri" ]; then
_err "Can not find account id url."
@ -3503,7 +3511,7 @@ updateaccount() {
if [ "$ACME_VERSION" = "2" ]; then
if [ "$ACCOUNT_EMAIL" ]; then
updjson='{"contact": ["mailto: '$ACCOUNT_EMAIL'"]}'
updjson='{"contact": ["mailto:'$ACCOUNT_EMAIL'"]}'
fi
else
# ACMEv1: Updates happen the same way a registration is done.
@ -3516,6 +3524,7 @@ updateaccount() {
_send_signed_request "$_accUri" "$updjson"
if [ "$code" = '200' ]; then
echo "$response" >"$ACCOUNT_JSON_PATH"
_info "account update success for $_accUri."
else
_info "Error. The account was not updated."
@ -3819,9 +3828,11 @@ _check_dns_entries() {
_sleep 10
else
_info "All success, let's return"
break
return 0
fi
done
_info "Timed out waiting for DNS."
return 1
}
@ -4002,7 +4013,7 @@ issue() {
_on_issue_err "$_post_hook"
return 1
fi
Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n " | cut -d ":" -f 2-)"
_debug Le_LinkOrder "$Le_LinkOrder"
Le_OrderFinalize="$(echo "$response" | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)"
_debug Le_OrderFinalize "$Le_OrderFinalize"
@ -4016,7 +4027,7 @@ issue() {
#for dns manual mode
_savedomainconf "Le_OrderFinalize" "$Le_OrderFinalize"
_authorizations_seg="$(echo "$response" | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')"
_authorizations_seg="$(echo "$response" | _json_decode | _egrep_o '"authorizations" *: *\[[^\[]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')"
_debug2 _authorizations_seg "$_authorizations_seg"
if [ -z "$_authorizations_seg" ]; then
_err "_authorizations_seg not found."
@ -4082,7 +4093,7 @@ $_authorizations_map"
if [ "$ACME_VERSION" = "2" ]; then
_idn_d="$(_idn "$d")"
_candindates="$(echo "$_authorizations_map" | grep "^$_idn_d,")"
_candindates="$(echo "$_authorizations_map" | grep -i "^$_idn_d,")"
_debug2 _candindates "$_candindates"
if [ "$(echo "$_candindates" | wc -l)" -gt 1 ]; then
for _can in $_candindates; do
@ -4115,45 +4126,59 @@ $_authorizations_map"
entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
_debug entry "$entry"
keyauthorization=""
if [ -z "$entry" ]; then
_err "Error, can not get domain token entry $d"
_supported_vtypes="$(echo "$response" | _egrep_o "\"challenges\":\[[^]]*]" | tr '{' "\n" | grep type | cut -d '"' -f 4 | tr "\n" ' ')"
if [ "$_supported_vtypes" ]; then
_err "The supported validation types are: $_supported_vtypes, but you specified: $vtype"
if ! _startswith "$d" '*.'; then
_debug "Not a wildcard domain, lets check whether the validation is already valid."
if echo "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
_debug "$d is already valid."
keyauthorization="$STATE_VERIFIED"
_debug keyauthorization "$keyauthorization"
fi
fi
if [ -z "$keyauthorization" ]; then
_err "Error, can not get domain token entry $d for $vtype"
_supported_vtypes="$(echo "$response" | _egrep_o "\"challenges\":\[[^]]*]" | tr '{' "\n" | grep type | cut -d '"' -f 4 | tr "\n" ' ')"
if [ "$_supported_vtypes" ]; then
_err "The supported validation types are: $_supported_vtypes, but you specified: $vtype"
fi
_clearup
_on_issue_err "$_post_hook"
return 1
fi
_clearup
_on_issue_err "$_post_hook"
return 1
fi
token="$(echo "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
_debug token "$token"
if [ -z "$token" ]; then
_err "Error, can not get domain token $entry"
_clearup
_on_issue_err "$_post_hook"
return 1
fi
if [ "$ACME_VERSION" = "2" ]; then
uri="$(echo "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)"
else
uri="$(echo "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)"
fi
_debug uri "$uri"
if [ -z "$keyauthorization" ]; then
token="$(echo "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
_debug token "$token"
if [ -z "$uri" ]; then
_err "Error, can not get domain uri. $entry"
_clearup
_on_issue_err "$_post_hook"
return 1
fi
keyauthorization="$token.$thumbprint"
_debug keyauthorization "$keyauthorization"
if [ -z "$token" ]; then
_err "Error, can not get domain token $entry"
_clearup
_on_issue_err "$_post_hook"
return 1
fi
if [ "$ACME_VERSION" = "2" ]; then
uri="$(echo "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)"
else
uri="$(echo "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)"
fi
_debug uri "$uri"
if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
_debug "$d is already verified."
keyauthorization="$STATE_VERIFIED"
if [ -z "$uri" ]; then
_err "Error, can not get domain uri. $entry"
_clearup
_on_issue_err "$_post_hook"
return 1
fi
keyauthorization="$token.$thumbprint"
_debug keyauthorization "$keyauthorization"
if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
_debug "$d is already verified."
keyauthorization="$STATE_VERIFIED"
_debug keyauthorization "$keyauthorization"
fi
fi
dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot"
@ -4517,13 +4542,13 @@ $_authorizations_map"
return 1
fi
if [ -z "$Le_LinkOrder" ]; then
Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n" | cut -d ":" -f 2-)"
fi
_savedomainconf "Le_LinkOrder" "$Le_LinkOrder"
_link_cert_retry=0
_MAX_CERT_RETRY=5
_MAX_CERT_RETRY=30
while [ "$_link_cert_retry" -lt "$_MAX_CERT_RETRY" ]; do
if _contains "$response" "\"status\":\"valid\""; then
_debug "Order status is valid."
@ -5568,7 +5593,7 @@ _deactivate() {
return 1
fi
authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ':' -f 2- | tr -d "\r\n")"
_debug "authzUri" "$authzUri"
if [ "$code" ] && [ ! "$code" = '201' ]; then
_err "new-authz error: $response"
@ -6198,17 +6223,17 @@ Parameters:
--force, -f Used to force to install or force to renew a cert immediately.
--staging, --test Use staging server, just for test.
--debug Output debug info.
--output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure.
--output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for security.
--webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
--standalone Use standalone mode.
--alpn Use standalone alpn mode.
--stateless Use stateless mode, see: $_STATELESS_WIKI
--apache Use apache mode.
--dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
--dnssleep [$DEFAULT_DNS_SLEEP] The time in seconds to wait for all the txt records to take effect in dns api mode. Default $DEFAULT_DNS_SLEEP seconds.
--dnssleep 300 The time in seconds to wait for all the txt records to take effect in dns api mode. It's not necessary to use this by default, $PROJECT_NAME polls dns status automatically.
--keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384.
--accountkeylength, -ak [2048] Specifies the account key length.
--keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384, ec-521.
--accountkeylength, -ak [2048] Specifies the account key length: 2048, 3072, 4096
--log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here.
--log-level 1|2 Specifies the log level, default is 1.
--syslog [0|3|6|7] Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug.
@ -6222,7 +6247,7 @@ Parameters:
--reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server.
--server SERVER ACME Directory Resource URI. (default: https://acme-v01.api.letsencrypt.org/directory)
--server SERVER ACME Directory Resource URI. (default: $DEFAULT_CA)
--accountconf Specifies a customized account config file.
--home Specifies the home dir for $PROJECT_NAME.
--cert-home Specifies the home dir to save all the certs, only valid for '--install' command.
@ -6299,6 +6324,8 @@ _installOnline() {
chmod +x $PROJECT_ENTRY
if ./$PROJECT_ENTRY install "$_nocron" "" "$_noprofile"; then
_info "Install success!"
_initpath
_saveaccountconf "UPGRADE_HASH" "$(_getUpgradeHash)"
fi
cd ..
@ -6308,9 +6335,27 @@ _installOnline() {
)
}
_getRepoHash() {
_hash_path=$1
shift
_hash_url="https://api.github.com/repos/acmesh-official/$PROJECT_NAME/git/refs/$_hash_path"
_get $_hash_url | tr -d "\r\n" | tr '{},' '\n' | grep '"sha":' | cut -d '"' -f 4
}
_getUpgradeHash() {
_b="$BRANCH"
if [ -z "$_b" ]; then
_b="master"
fi
_hash=$(_getRepoHash "heads/$_b")
if [ -z "$_hash" ]; then _hash=$(_getRepoHash "tags/$_b"); fi
echo $_hash
}
upgrade() {
if (
_initpath
[ -z "$FORCE" ] && [ "$(_getUpgradeHash)" = "$(_readaccountconf "UPGRADE_HASH")" ] && _info "Already uptodate!" && exit 0
export LE_WORKING_DIR
cd "$LE_WORKING_DIR"
_installOnline "nocron" "noprofile"

2
deploy/README.md

@ -2,5 +2,5 @@
deploy hook usage:
https://github.com/Neilpang/acme.sh/wiki/deployhooks
https://github.com/acmesh-official/acme.sh/wiki/deployhooks

2
deploy/docker.sh

@ -8,7 +8,7 @@
#DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/path/to/fullchain.pem"
#DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="service nginx force-reload"
_DEPLOY_DOCKER_WIKI="https://github.com/Neilpang/acme.sh/wiki/deploy-to-docker-containers"
_DEPLOY_DOCKER_WIKI="https://github.com/acmesh-official/acme.sh/wiki/deploy-to-docker-containers"
_DOCKER_HOST_DEFAULT="/var/run/docker.sock"

52
deploy/haproxy.sh

@ -208,33 +208,37 @@ haproxy_deploy() {
_issuerdn=$(openssl x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
_debug _issuerdn "${_issuerdn}"
_info "Requesting OCSP response"
# Request the OCSP response from the issuer and store it
# If the issuer is a CA cert then our command line has "-CAfile" added
if [ "${_subjectdn}" = "${_issuerdn}" ]; then
# If the issuer is a CA cert then our command line has "-CAfile" added
openssl ocsp \
-issuer "${_issuer}" \
-cert "${_pem}" \
-url "${_ocsp_url}" \
-header Host "${_ocsp_host}" \
-respout "${_ocsp}" \
-verify_other "${_issuer}" \
-no_nonce \
-CAfile "${_issuer}" \
| grep -q "${_pem}: good"
_ret=$?
_cafile_argument="-CAfile \"${_issuer}\""
else
_cafile_argument=""
fi
_debug _cafile_argument "${_cafile_argument}"
# if OpenSSL/LibreSSL is v1.1 or above, the format for the -header option has changed
_openssl_version=$(openssl version | cut -d' ' -f2)
_debug _openssl_version "${_openssl_version}"
_openssl_major=$(echo "${_openssl_version}" | cut -d '.' -f1)
_openssl_minor=$(echo "${_openssl_version}" | cut -d '.' -f2)
if [ "${_openssl_major}" -eq "1" ] && [ "${_openssl_minor}" -ge "1" ] || [ "${_openssl_major}" -ge "2" ]; then
_header_sep="="
else
# Issuer is not a root CA so no "-CAfile" option
openssl ocsp \
-issuer "${_issuer}" \
-cert "${_pem}" \
-url "${_ocsp_url}" \
-header Host "${_ocsp_host}" \
-respout "${_ocsp}" \
-verify_other "${_issuer}" \
-no_nonce \
| grep -q "${_pem}: good"
_ret=$?
_header_sep=" "
fi
# Request the OCSP response from the issuer and store it
_openssl_ocsp_cmd="openssl ocsp \
-issuer \"${_issuer}\" \
-cert \"${_pem}\" \
-url \"${_ocsp_url}\" \
-header Host${_header_sep}\"${_ocsp_host}\" \
-respout \"${_ocsp}\" \
-verify_other \"${_issuer}\" \
-no_nonce \
${_cafile_argument} \
| grep -q \"${_pem}: good\""
_debug _openssl_ocsp_cmd "${_openssl_ocsp_cmd}"
eval "${_openssl_ocsp_cmd}"
_ret=$?
else
# Non fatal: No issuer file was present so no OCSP stapling file created
_err "OCSP stapling in use but no .issuer file was present"

139
deploy/panos.sh

@ -0,0 +1,139 @@
#!/usr/bin/env sh
# Script to deploy certificates to Palo Alto Networks PANOS via API
# Note PANOS API KEY and IP address needs to be set prior to running.
# The following variables exported from environment will be used.
# If not set then values previously saved in domain.conf file are used.
#
# Firewall admin with superuser and IP address is required.
#
# export PANOS_USER="" # required
# export PANOS_PASS="" # required
# export PANOS_HOST="" # required
# This function is to parse the XML
parse_response() {
type=$2
if [ "$type" = 'keygen' ]; then
status=$(echo "$1" | sed 's/^.*\(['\'']\)\([a-z]*\)'\''.*/\2/g')
if [ "$status" = "success" ]; then
panos_key=$(echo "$1" | sed 's/^.*\(<key>\)\(.*\)<\/key>.*/\2/g')
_panos_key=$panos_key
else
message="PAN-OS Key could not be set."
fi
else
status=$(echo "$1" | sed 's/^.*"\([a-z]*\)".*/\1/g')
message=$(echo "$1" | sed 's/^.*<result>\(.*\)<\/result.*/\1/g')
fi
return 0
}
deployer() {
content=""
type=$1 # Types are keygen, cert, key, commit
_debug "**** Deploying $type *****"
panos_url="https://$_panos_host/api/"
if [ "$type" = 'keygen' ]; then
_H1="Content-Type: application/x-www-form-urlencoded"
content="type=keygen&user=$_panos_user&password=$_panos_pass"
# content="$content${nl}--$delim${nl}Content-Disposition: form-data; type=\"keygen\"; user=\"$_panos_user\"; password=\"$_panos_pass\"${nl}Content-Type: application/octet-stream${nl}${nl}"
fi
if [ "$type" = 'cert' ] || [ "$type" = 'key' ]; then
#Generate DEIM
delim="-----MultipartDelimiter$(date "+%s%N")"
nl="\015\012"
#Set Header
export _H1="Content-Type: multipart/form-data; boundary=$delim"
if [ "$type" = 'cert' ]; then
panos_url="${panos_url}?type=import"
content="--$delim${nl}Content-Disposition: form-data; name=\"category\"\r\n\r\ncertificate"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"certificate-name\"\r\n\r\n$_cdomain"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")"
fi
if [ "$type" = 'key' ]; then
panos_url="${panos_url}?type=import"
content="--$delim${nl}Content-Disposition: form-data; name=\"category\"\r\n\r\nprivate-key"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"certificate-name\"\r\n\r\n$_cdomain"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"passphrase\"\r\n\r\n123456"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
fi
#Close multipart
content="$content${nl}--$delim--${nl}${nl}"
#Convert CRLF
content=$(printf %b "$content")
fi
if [ "$type" = 'commit' ]; then
export _H1="Content-Type: application/x-www-form-urlencoded"
cmd=$(printf "%s" "<commit><partial><$_panos_user></$_panos_user></partial></commit>" | _url_encode)
content="type=commit&key=$_panos_key&cmd=$cmd"
fi
response=$(_post "$content" "$panos_url" "" "POST")
parse_response "$response" "$type"
# Saving response to variables
response_status=$status
#DEBUG
_debug response_status "$response_status"
if [ "$response_status" = "success" ]; then
_debug "Successfully deployed $type"
return 0
else
_err "Deploy of type $type failed. Try deploying with --debug to troubleshoot."
_debug "$message"
return 1
fi
}
# This is the main function that will call the other functions to deploy everything.
panos_deploy() {
_cdomain="$1"
_ckey="$2"
_cfullchain="$5"
# PANOS ENV VAR check
if [ -z "$PANOS_USER" ] || [ -z "$PANOS_PASS" ] || [ -z "$PANOS_HOST" ]; then
_debug "No ENV variables found lets check for saved variables"
_getdeployconf PANOS_USER
_getdeployconf PANOS_PASS
_getdeployconf PANOS_HOST
_panos_user=$PANOS_USER
_panos_pass=$PANOS_PASS
_panos_host=$PANOS_HOST
if [ -z "$_panos_user" ] && [ -z "$_panos_pass" ] && [ -z "$_panos_host" ]; then
_err "No host, user and pass found.. If this is the first time deploying please set PANOS_HOST, PANOS_USER and PANOS_PASS in environment variables. Delete them after you have succesfully deployed certs."
return 1
else
_debug "Using saved env variables."
fi
else
_debug "Detected ENV variables to be saved to the deploy conf."
# Encrypt and save user
_savedeployconf PANOS_USER "$PANOS_USER" 1
_savedeployconf PANOS_PASS "$PANOS_PASS" 1
_savedeployconf PANOS_HOST "$PANOS_HOST" 1
_panos_user="$PANOS_USER"
_panos_pass="$PANOS_PASS"
_panos_host="$PANOS_HOST"
fi
_debug "Let's use username and pass to generate token."
if [ -z "$_panos_user" ] || [ -z "$_panos_pass" ] || [ -z "$_panos_host" ]; then
_err "Please pass username and password and host as env variables PANOS_USER, PANOS_PASS and PANOS_HOST"
return 1
else
_debug "Getting PANOS KEY"
deployer keygen
if [ -z "$_panos_key" ]; then
_err "Missing apikey."
return 1
else
deployer cert
deployer key
deployer commit
fi
fi
}

32
deploy/qiniu.sh

@ -6,6 +6,8 @@
# export QINIU_AK="QINIUACCESSKEY"
# export QINIU_SK="QINIUSECRETKEY"
# export QINIU_CDN_DOMAIN="cdn.example.com"
# If you have more than one domain, just
# export QINIU_CDN_DOMAIN="cdn1.example.com cdn2.example.com"
QINIU_API_BASE="https://api.qiniu.com"
@ -67,21 +69,23 @@ qiniu_deploy() {
_debug certId "$_certId"
## update domain ssl config
update_path="/domain/$QINIU_CDN_DOMAIN/httpsconf"
update_body="{\"certid\":$_certId,\"forceHttps\":false}"
update_access_token="$(_make_access_token "$update_path")"
_debug update_access_token "$update_access_token"
export _H1="Authorization: QBox $update_access_token"
update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline")
if _contains "$update_response" "error"; then
_err "Error in updating domain httpsconf:"
_err "$update_response"
return 1
fi
_debug update_response "$update_response"
_info "Certificate successfully deployed"
for domain in $QINIU_CDN_DOMAIN; do
update_path="/domain/$domain/httpsconf"
update_access_token="$(_make_access_token "$update_path")"
_debug update_access_token "$update_access_token"
export _H1="Authorization: QBox $update_access_token"
update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline")
if _contains "$update_response" "error"; then
_err "Error in updating domain $domain httpsconf:"
_err "$update_response"
return 1
fi
_debug update_response "$update_response"
_info "Domain $domain certificate has been deployed successfully"
done
return 0
}

26
deploy/routeros.sh

@ -85,19 +85,19 @@ routeros_deploy() {
scp "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key"
_info "Trying to push cert '$_cfullchain' to router"
scp "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer"
DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=ftp,read,write,password,sensitive
source=\"## generated by routeros deploy script in acme.sh
\n/certificate remove [ find name=$_cdomain.cer_0 ]
\n/certificate remove [ find name=$_cdomain.cer_1 ]
\ndelay 1
\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\"
\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\"
\ndelay 1
\n/file remove $_cdomain.cer
\n/file remove $_cdomain.key
\ndelay 2
\n/ip service set www-ssl certificate=$_cdomain.cer_0
\n$ROUTER_OS_ADDITIONAL_SERVICES
DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=ftp,read,write,password,sensitive \
source=\"## generated by routeros deploy script in acme.sh;\
\n/certificate remove [ find name=$_cdomain.cer_0 ];\
\n/certificate remove [ find name=$_cdomain.cer_1 ];\
\ndelay 1;\
\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\";\
\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\";\
\ndelay 1;\
\n/file remove $_cdomain.cer;\
\n/file remove $_cdomain.key;\
\ndelay 2;\
\n/ip service set www-ssl certificate=$_cdomain.cer_0;\
\n$ROUTER_OS_ADDITIONAL_SERVICES;\
\n\"
"
# shellcheck disable=SC2029

155
deploy/synology_dsm.sh

@ -0,0 +1,155 @@
#!/usr/bin/env sh
# Here is a script to deploy cert to Synology DSM
#
# it requires the jq and curl are in the $PATH and the following
# environment variables must be set:
#
# SYNO_Username - Synology Username to login (must be an administrator)
# SYNO_Password - Synology Password to login
# SYNO_Certificate - Certificate description to target for replacement
#
# The following environmental variables may be set if you don't like their
# default values:
#
# SYNO_Scheme - defaults to http
# SYNO_Hostname - defaults to localhost
# SYNO_Port - defaults to 5000
# SYNO_DID - device ID to skip OTP - defaults to empty
#
#returns 0 means success, otherwise error.
######## Public functions #####################
_syno_get_cookie_data() {
grep "\W$1=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o "$1=[^;]*;" | tr -d ';'
}
#domain keyfile certfile cafile fullchain
synology_dsm_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_debug _cdomain "$_cdomain"
# Get Username and Password, but don't save until we successfully authenticate
_getdeployconf SYNO_Username
_getdeployconf SYNO_Password
_getdeployconf SYNO_Create
_getdeployconf SYNO_DID
if [ -z "$SYNO_Username" ] || [ -z "$SYNO_Password" ]; then
SYNO_Username=""
SYNO_Password=""
_err "SYNO_Username & SYNO_Password must be set"
return 1
fi
_debug2 SYNO_Username "$SYNO_Username"
_secure_debug2 SYNO_Password "$SYNO_Password"
# Optional scheme, hostname, and port for Synology DSM
_getdeployconf SYNO_Scheme
_getdeployconf SYNO_Hostname
_getdeployconf SYNO_Port
# default vaules for scheme, hostname, and port
# defaulting to localhost and http because it's localhost...
[ -n "${SYNO_Scheme}" ] || SYNO_Scheme="http"
[ -n "${SYNO_Hostname}" ] || SYNO_Hostname="localhost"
[ -n "${SYNO_Port}" ] || SYNO_Port="5000"
_savedeployconf SYNO_Scheme "$SYNO_Scheme"
_savedeployconf SYNO_Hostname "$SYNO_Hostname"
_savedeployconf SYNO_Port "$SYNO_Port"
_debug2 SYNO_Scheme "$SYNO_Scheme"
_debug2 SYNO_Hostname "$SYNO_Hostname"
_debug2 SYNO_Port "$SYNO_Port"
# Get the certificate description, but don't save it until we verfiy it's real
_getdeployconf SYNO_Certificate
if [ -z "${SYNO_Certificate:?}" ]; then
_err "SYNO_Certificate needs to be defined (with the Certificate description name)"
return 1
fi
_debug SYNO_Certificate "$SYNO_Certificate"
_base_url="$SYNO_Scheme://$SYNO_Hostname:$SYNO_Port"
_debug _base_url "$_base_url"
# Login, get the token from JSON and session id from cookie
_info "Logging into $SYNO_Hostname:$SYNO_Port"
response=$(_get "$_base_url/webman/login.cgi?username=$SYNO_Username&passwd=$SYNO_Password&enable_syno_token=yes&device_id=$SYNO_DID")
token=$(echo "$response" | grep "SynoToken" | sed -n 's/.*"SynoToken" *: *"\([^"]*\).*/\1/p')
_debug3 response "$response"
if [ -z "$token" ]; then
_err "Unable to authenticate to $SYNO_Hostname:$SYNO_Port using $SYNO_Scheme."
_err "Check your username and password."
return 1
fi
_H1="Cookie: $(_syno_get_cookie_data "id"); $(_syno_get_cookie_data "smid")"
_H2="X-SYNO-TOKEN: $token"
export _H1
export _H2
_debug2 H1 "${_H1}"
_debug2 H2 "${_H2}"
# Now that we know the username and password are good, save them
_savedeployconf SYNO_Username "$SYNO_Username"
_savedeployconf SYNO_Password "$SYNO_Password"
_savedeployconf SYNO_DID "$SYNO_DID"
_debug token "$token"
_info "Getting certificates in Synology DSM"
response=$(_post "api=SYNO.Core.Certificate.CRT&method=list&version=1" "$_base_url/webapi/entry.cgi")
_debug3 response "$response"
id=$(echo "$response" | sed -n "s/.*\"desc\":\"$SYNO_Certificate\",\"id\":\"\([^\"]*\).*/\1/p")
_debug2 id "$id"
if [ -z "$id" ] && [ -z "${SYNO_Create:?}" ]; then
_err "Unable to find certificate: $SYNO_Certificate and \$SYNO_Create is not set"
return 1
fi
# we've verified this certificate description is a thing, so save it
_savedeployconf SYNO_Certificate "$SYNO_Certificate"
default=false
if echo "$response" | sed -n "s/.*\"desc\":\"$SYNO_Certificate\",\([^{]*\).*/\1/p" | grep -- 'is_default":true' >/dev/null; then
default=true
fi
_debug2 default "$default"
_info "Generate form POST request"
nl="\015\012"
delim="--------------------------$(_utc_date | tr -d -- '-: ')"
content="--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")\012"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_ccert")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ccert")\012"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"inter_cert\"; filename=\"$(basename "$_cca")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cca")\012"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"id\"${nl}${nl}$id"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"desc\"${nl}${nl}${SYNO_Certificate}"
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"as_default\"${nl}${nl}${default}"
content="$content${nl}--$delim--${nl}"
content="$(printf "%b_" "$content")"
content="${content%_}" # protect trailing \n
_info "Upload certificate to the Synology DSM"
response=$(_post "$content" "$_base_url/webapi/entry.cgi?api=SYNO.Core.Certificate&method=import&version=1&SynoToken=$token" "" "POST" "multipart/form-data; boundary=${delim}")
_debug3 response "$response"
if ! echo "$response" | grep '"error":' >/dev/null; then
if echo "$response" | grep '"restart_httpd":true' >/dev/null; then
_info "http services were restarted"
else
_info "http services were NOT restarted"
fi
return 0
else
_err "Unable to update certificate, error code $response"
return 1
fi
}

2
dnsapi/README.md

@ -2,5 +2,5 @@
DNS api usage:
https://github.com/Neilpang/acme.sh/wiki/dnsapi
https://github.com/acmesh-official/acme.sh/wiki/dnsapi

254
dnsapi/dns_1984hosting.sh

@ -0,0 +1,254 @@
#!/usr/bin/env sh
#This file name is "dns_1984hosting.sh"
#So, here must be a method dns_1984hosting_add()
#Which will be called by acme.sh to add the txt record to your api system.
#returns 0 means success, otherwise error.
#
#Author: Adrian Fedoreanu
#Report Bugs here: https://github.com/acmesh-official/acme.sh
# or here... https://github.com/acmesh-official/acme.sh/issues/2851
#
######## Public functions #####################
# Export 1984HOSTING username and password in following variables
#
# One984HOSTING_Username=username
# One984HOSTING_Password=password
#
# sessionid cookie is saved in ~/.acme.sh/account.conf
# username/password need to be set only when changed.
#Usage: dns_1984hosting_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_1984hosting_add() {
fulldomain=$1
txtvalue=$2
_info "Add TXT record using 1984Hosting"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
if ! _1984hosting_login; then
_err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file"
return 1
fi
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain" "$fulldomain"
return 1
fi
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_1984hosting_add_txt_record "$_domain" "$_sub_domain" "$txtvalue"
return $?
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_1984hosting_rm() {
fulldomain=$1
txtvalue=$2
_info "Delete TXT record using 1984Hosting"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
if ! _1984hosting_login; then
_err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file"
return 1
fi
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain" "$fulldomain"
return 1
fi
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_1984hosting_delete_txt_record "$_domain" "$_sub_domain"
return $?
}
#################### Private functions below ##################################
# usage _1984hosting_add_txt_record domain subdomain value
# returns 0 success
_1984hosting_add_txt_record() {
_debug "Add TXT record $1 with value '$3'"
domain="$1"
subdomain="$2"
value="$(printf '%s' "$3" | _url_encode)"
url="https://management.1984hosting.com/domains/entry/"
postdata="entry=new"
postdata="$postdata&type=TXT"
postdata="$postdata&ttl=3600"
postdata="$postdata&zone=$domain"
postdata="$postdata&host=$subdomain"
postdata="$postdata&rdata=%22$value%22"
_debug2 postdata "$postdata"
_authpost "$postdata" "$url"
response="$(echo "$_response" | _normalizeJson)"
_debug2 response "$response"
if _contains "$response" '"haserrors": true'; then
_err "1984Hosting failed to add TXT record for $subdomain bad RC from _post"
return 1
elif _contains "$response" "<html>"; then
_err "1984Hosting failed to add TXT record for $subdomain. Check $HTTP_HEADER file"
return 1
elif [ "$response" = '{"auth": false, "ok": false}' ]; then
_err "1984Hosting failed to add TXT record for $subdomain. Invalid or expired cookie"
return 1
fi
_info "Added acme challenge TXT record for $fulldomain at 1984Hosting"
return 0
}
# usage _1984hosting_delete_txt_record entry_id
# returns 0 success
_1984hosting_delete_txt_record() {
_debug "Delete $fulldomain TXT record"
domain="$1"
subdomain="$2"
url="https://management.1984hosting.com/domains"
_htmlget "$url" "$domain"
_debug2 _response "$_response"
zone_id="$(echo "$_response" | _egrep_o 'zone\/[0-9]+')"
_debug2 zone_id "$zone_id"
if [ -z "$zone_id" ]; then
_err "Error getting zone_id for $1"
return 1
fi
_htmlget "$url/$zone_id" "$subdomain"
_debug2 _response "$_response"
entry_id="$(echo "$_response" | _egrep_o 'entry_[0-9]+' | sed 's/entry_//')"
_debug2 entry_id "$entry_id"
if [ -z "$entry_id" ]; then
_err "Error getting TXT entry_id for $1"
return 1
fi
_authpost "entry=$entry_id" "$url/delentry/"
response="$(echo "$_response" | _normalizeJson)"
_debug2 response "$response"
if ! _contains "$response" '"ok": true'; then
_err "1984Hosting failed to delete TXT record for $entry_id bad RC from _post"
return 1
fi
_info "Deleted acme challenge TXT record for $fulldomain at 1984Hosting"
return 0
}
# usage: _1984hosting_login username password
# returns 0 success
_1984hosting_login() {
if ! _check_credentials; then return 1; fi
if _check_cookie; then
_debug "Already logged in"
return 0
fi
_debug "Login to 1984Hosting as user $One984HOSTING_Username"
username=$(printf '%s' "$One984HOSTING_Username" | _url_encode)
password=$(printf '%s' "$One984HOSTING_Password" | _url_encode)
url="https://management.1984hosting.com/accounts/checkuserauth/"
response="$(_post "username=$username&password=$password&otpkey=" "$url")"
response="$(echo "$response" | _normalizeJson)"
_debug2 response "$response"
if [ "$response" = '{"loggedin": true, "ok": true}' ]; then
One984HOSTING_COOKIE="$(grep '^Set-Cookie:' "$HTTP_HEADER" | _tail_n 1 | _egrep_o 'sessionid=[^;]*;' | tr -d ';')"
export One984HOSTING_COOKIE
_saveaccountconf_mutable One984HOSTING_COOKIE "$One984HOSTING_COOKIE"
return 0
fi
return 1
}
_check_credentials() {
if [ -z "$One984HOSTING_Username" ] || [ -z "$One984HOSTING_Password" ]; then
One984HOSTING_Username=""
One984HOSTING_Password=""
_err "You haven't specified 1984Hosting username or password yet."
_err "Please export as One984HOSTING_Username / One984HOSTING_Password and try again."
return 1
fi
return 0
}
_check_cookie() {
One984HOSTING_COOKIE="${One984HOSTING_COOKIE:-$(_readaccountconf_mutable One984HOSTING_COOKIE)}"
if [ -z "$One984HOSTING_COOKIE" ]; then
_debug "No cached cookie found"
return 1
fi
_authget "https://management.1984hosting.com/accounts/loginstatus/"
response="$(echo "$_response" | _normalizeJson)"
if [ "$_response" = '{"ok": true}' ]; then
_debug "Cached cookie still valid"
return 0
fi
_debug "Cached cookie no longer valid"
One984HOSTING_COOKIE=""
_saveaccountconf_mutable One984HOSTING_COOKIE "$One984HOSTING_COOKIE"
return 1
}
#_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)
if [ -z "$h" ]; then
#not valid
return 1
fi
_authget "https://management.1984hosting.com/domains/soacheck/?zone=$h&nameserver=ns0.1984.is."
if _contains "$_response" "serial"; 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
}
# add extra headers to request
_authget() {
export _H1="Cookie: $One984HOSTING_COOKIE"
_response=$(_get "$1")
}
# truncate huge HTML response
# echo: Argument list too long
_htmlget() {
export _H1="Cookie: $One984HOSTING_COOKIE"
_response=$(_get "$1" | grep "$2" | _head_n 1)
}
# add extra headers to request
_authpost() {
export _H1="Cookie: $One984HOSTING_COOKIE"
_response=$(_post "$1" "$2")
}

21
dnsapi/dns_aws.sh

@ -12,7 +12,7 @@
AWS_HOST="route53.amazonaws.com"
AWS_URL="https://$AWS_HOST"
AWS_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-use-Amazon-Route53-API"
AWS_WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Amazon-Route53-API"
######## Public functions #####################
@ -23,6 +23,7 @@ dns_aws_add() {
AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}"
AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}"
AWS_DNS_SLOWRATE="${AWS_DNS_SLOWRATE:-$(_readaccountconf_mutable AWS_DNS_SLOWRATE)}"
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
_use_container_role || _use_instance_role
@ -40,6 +41,7 @@ dns_aws_add() {
if [ -z "$_using_role" ]; then
_saveaccountconf_mutable AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID"
_saveaccountconf_mutable AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY"
_saveaccountconf_mutable AWS_DNS_SLOWRATE "$AWS_DNS_SLOWRATE"
fi
_debug "First detect the root zone"
@ -77,7 +79,13 @@ dns_aws_add() {
if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
_info "TXT record updated successfully."
_sleep 1
if [ -n "$AWS_DNS_SLOWRATE" ]; then
_info "Slow rate activated: sleeping for $AWS_DNS_SLOWRATE seconds"
_sleep "$AWS_DNS_SLOWRATE"
else
_sleep 1
fi
return 0
fi
_sleep 1
@ -91,6 +99,7 @@ dns_aws_rm() {
AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}"
AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}"
AWS_DNS_SLOWRATE="${AWS_DNS_SLOWRATE:-$(_readaccountconf_mutable AWS_DNS_SLOWRATE)}"
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
_use_container_role || _use_instance_role
@ -125,7 +134,13 @@ dns_aws_rm() {
if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
_info "TXT record deleted successfully."
_sleep 1
if [ -n "$AWS_DNS_SLOWRATE" ]; then
_info "Slow rate activated: sleeping for $AWS_DNS_SLOWRATE seconds"
_sleep "$AWS_DNS_SLOWRATE"
else
_sleep 1
fi
return 0
fi
_sleep 1

2
dnsapi/dns_azure.sh

@ -1,6 +1,6 @@
#!/usr/bin/env sh
WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-use-Azure-DNS"
WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS"
######## Public functions #####################

28
dnsapi/dns_cf.sh

@ -7,6 +7,7 @@
#CF_Token="xxxx"
#CF_Account_ID="xxxx"
#CF_Zone_ID="xxxx"
CF_Api="https://api.cloudflare.com/client/v4"
@ -19,12 +20,14 @@ dns_cf_add() {
CF_Token="${CF_Token:-$(_readaccountconf_mutable CF_Token)}"
CF_Account_ID="${CF_Account_ID:-$(_readaccountconf_mutable CF_Account_ID)}"
CF_Zone_ID="${CF_Zone_ID:-$(_readaccountconf_mutable CF_Zone_ID)}"
CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}"
CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
if [ "$CF_Token" ]; then
_saveaccountconf_mutable CF_Token "$CF_Token"
_saveaccountconf_mutable CF_Account_ID "$CF_Account_ID"
_saveaccountconf_mutable CF_Zone_ID "$CF_Zone_ID"
else
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
CF_Key=""
@ -91,6 +94,7 @@ dns_cf_rm() {
CF_Token="${CF_Token:-$(_readaccountconf_mutable CF_Token)}"
CF_Account_ID="${CF_Account_ID:-$(_readaccountconf_mutable CF_Account_ID)}"
CF_Zone_ID="${CF_Zone_ID:-$(_readaccountconf_mutable CF_Zone_ID)}"
CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}"
CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
@ -107,7 +111,7 @@ dns_cf_rm() {
_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"
_err "Error: $response"
return 1
fi
@ -141,6 +145,28 @@ _get_root() {
domain=$1
i=1
p=1
# Use Zone ID directly if provided
if [ "$CF_Zone_ID" ]; then
if ! _cf_rest GET "zones/$CF_Zone_ID"; then
return 1
else
if _contains "$response" '"success":true'; then
_domain=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1)
if [ "$_domain" ]; then
_cutlength=$((${#domain} - ${#_domain} - 1))
_sub_domain=$(printf "%s" "$domain" | cut -c "1-$_cutlength")
_domain_id=$CF_Zone_ID
return 0
else
return 1
fi
else
return 1
fi
fi
fi
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"

197
dnsapi/dns_clouddns.sh

@ -0,0 +1,197 @@
#!/usr/bin/env sh
# Author: Radek Sprta <sprta@vshosting.cz>
#CLOUDDNS_EMAIL=XXXXX
#CLOUDDNS_PASSWORD="YYYYYYYYY"
#CLOUDDNS_CLIENT_ID=XXXXX
CLOUDDNS_API='https://admin.vshosting.cloud/clouddns'
CLOUDDNS_LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login'
######## Public functions #####################
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_clouddns_add() {
fulldomain=$1
txtvalue=$2
_debug "fulldomain" "$fulldomain"
CLOUDDNS_CLIENT_ID="${CLOUDDNS_CLIENT_ID:-$(_readaccountconf_mutable CLOUDDNS_CLIENT_ID)}"
CLOUDDNS_EMAIL="${CLOUDDNS_EMAIL:-$(_readaccountconf_mutable CLOUDDNS_EMAIL)}"
CLOUDDNS_PASSWORD="${CLOUDDNS_PASSWORD:-$(_readaccountconf_mutable CLOUDDNS_PASSWORD)}"
if [ -z "$CLOUDDNS_PASSWORD" ] || [ -z "$CLOUDDNS_EMAIL" ] || [ -z "$CLOUDDNS_CLIENT_ID" ]; then
CLOUDDNS_CLIENT_ID=""
CLOUDDNS_EMAIL=""
CLOUDDNS_PASSWORD=""
_err "You didn't specify a CloudDNS password, email and client ID yet."
return 1
fi
if ! _contains "$CLOUDDNS_EMAIL" "@"; then
_err "It seems that the CLOUDDNS_EMAIL=$CLOUDDNS_EMAIL is not a valid email address."
_err "Please check and retry."
return 1
fi
# Save CloudDNS client id, email and password to config file
_saveaccountconf_mutable CLOUDDNS_CLIENT_ID "$CLOUDDNS_CLIENT_ID"
_saveaccountconf_mutable CLOUDDNS_EMAIL "$CLOUDDNS_EMAIL"
_saveaccountconf_mutable CLOUDDNS_PASSWORD "$CLOUDDNS_PASSWORD"
_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"
# Add TXT record
data="{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"value\":\"$txtvalue\",\"domainId\":\"$_domain_id\"}"
if _clouddns_api POST "record-txt" "$data"; then
if _contains "$response" "$txtvalue"; then
_info "Added, OK"
elif _contains "$response" '"code":4136'; then
_info "Already exists, OK"
else
_err "Add TXT record error."
return 1
fi
fi
_debug "Publishing record changes"
_clouddns_api PUT "domain/$_domain_id/publish" "{\"soaTtl\":300}"
}
# Usage: rm _acme-challenge.www.domain.com
dns_clouddns_rm() {
fulldomain=$1
_debug "fulldomain" "$fulldomain"
CLOUDDNS_CLIENT_ID="${CLOUDDNS_CLIENT_ID:-$(_readaccountconf_mutable CLOUDDNS_CLIENT_ID)}"
CLOUDDNS_EMAIL="${CLOUDDNS_EMAIL:-$(_readaccountconf_mutable CLOUDDNS_EMAIL)}"
CLOUDDNS_PASSWORD="${CLOUDDNS_PASSWORD:-$(_readaccountconf_mutable CLOUDDNS_PASSWORD)}"
_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"
# Get record ID
_clouddns_api GET "domain/$_domain_id"
if _contains "$response" "lastDomainRecordList"; then
re="\"lastDomainRecordList\".*\"id\":\"([^\"}]*)\"[^}]*\"name\":\"$fulldomain.\","
_last_domains=$(echo "$response" | _egrep_o "$re")
re2="\"id\":\"([^\"}]*)\"[^}]*\"name\":\"$fulldomain.\","
_record_id=$(echo "$_last_domains" | _egrep_o "$re2" | _head_n 1 | cut -d : -f 2 | cut -d , -f 1 | tr -d "\"")
_debug _record_id "$_record_id"
else
_err "Could not retrieve record ID"
return 1
fi
_info "Removing record"
if _clouddns_api DELETE "record/$_record_id"; then
if _contains "$response" "\"error\":"; then
_err "Could not remove record"
return 1
fi
fi
_debug "Publishing record changes"
_clouddns_api PUT "domain/$_domain_id/publish" "{\"soaTtl\":300}"
}
#################### Private functions below ##################################
# Usage: _get_root _acme-challenge.www.domain.com
# Returns:
# _sub_domain=_acme-challenge.www
# _domain=domain.com
# _domain_id=sdjkglgdfewsdfg
_get_root() {
domain=$1
# Get domain root
data="{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$CLOUDDNS_CLIENT_ID\"}]}"
_clouddns_api "POST" "domain/search" "$data"
domain_slice="$domain"
while [ -z "$domain_root" ]; do
if _contains "$response" "\"domainName\":\"$domain_slice\.\""; then
domain_root="$domain_slice"
_debug domain_root "$domain_root"
fi
domain_slice="$(echo "$domain_slice" | cut -d . -f 2-)"
done
# Get domain id
data="{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$CLOUDDNS_CLIENT_ID\"}, \
{\"name\": \"domainName\", \"operator\": \"eq\", \"value\": \"$domain_root.\"}]}"
_clouddns_api "POST" "domain/search" "$data"
if _contains "$response" "\"id\":\""; then
re='domainType\":\"[^\"]*\",\"id\":\"([^\"]*)\",' # Match domain id
_domain_id=$(echo "$response" | _egrep_o "$re" | _head_n 1 | cut -d : -f 3 | tr -d "\",")
if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | sed "s/.$domain_root//")
_domain="$domain_root"
return 0
fi
_err 'Domain name not found on your CloudDNS account'
return 1
fi
return 1
}
# Usage: _clouddns_api GET domain/search '{"data": "value"}'
# Returns:
# response='{"message": "api response"}'
_clouddns_api() {
method=$1
endpoint="$2"
data="$3"
_debug endpoint "$endpoint"
if [ -z "$CLOUDDNS_TOKEN" ]; then
_clouddns_login
fi
_debug CLOUDDNS_TOKEN "$CLOUDDNS_TOKEN"
export _H1="Content-Type: application/json"
export _H2="Authorization: Bearer $CLOUDDNS_TOKEN"
if [ "$method" != "GET" ]; then
_debug data "$data"
response="$(_post "$data" "$CLOUDDNS_API/$endpoint" "" "$method" | tr -d '\t\r\n ')"
else
response="$(_get "$CLOUDDNS_API/$endpoint" | tr -d '\t\r\n ')"
fi
# shellcheck disable=SC2181
if [ "$?" != "0" ]; then
_err "Error $endpoint"
return 1
fi
_debug2 response "$response"
return 0
}
# Returns:
# CLOUDDNS_TOKEN=dslfje2rj23l
_clouddns_login() {
login_data="{\"email\": \"$CLOUDDNS_EMAIL\", \"password\": \"$CLOUDDNS_PASSWORD\"}"
response="$(_post "$login_data" "$CLOUDDNS_LOGIN_API" "" "POST" "Content-Type: application/json")"
if _contains "$response" "\"accessToken\":\""; then
CLOUDDNS_TOKEN=$(echo "$response" | _egrep_o "\"accessToken\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
export CLOUDDNS_TOKEN
else
echo 'Could not get CloudDNS access token; check your credentials'
return 1
fi
return 0
}

141
dnsapi/dns_constellix.sh

@ -0,0 +1,141 @@
#!/usr/bin/env sh
# Author: Wout Decre <wout@canodus.be>
CONSTELLIX_Api="https://api.dns.constellix.com/v1"
#CONSTELLIX_Key="XXX"
#CONSTELLIX_Secret="XXX"
######## Public functions #####################
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record
dns_constellix_add() {
fulldomain=$1
txtvalue=$2
CONSTELLIX_Key="${CONSTELLIX_Key:-$(_readaccountconf_mutable CONSTELLIX_Key)}"
CONSTELLIX_Secret="${CONSTELLIX_Secret:-$(_readaccountconf_mutable CONSTELLIX_Secret)}"
if [ -z "$CONSTELLIX_Key" ] || [ -z "$CONSTELLIX_Secret" ]; then
_err "You did not specify the Contellix API key and secret yet."
return 1
fi
_saveaccountconf_mutable CONSTELLIX_Key "$CONSTELLIX_Key"
_saveaccountconf_mutable CONSTELLIX_Secret "$CONSTELLIX_Secret"
if ! _get_root "$fulldomain"; then
_err "Invalid domain"
return 1
fi
_info "Adding TXT record"
if _constellix_rest POST "domains/${_domain_id}/records" "[{\"type\":\"txt\",\"add\":true,\"set\":{\"name\":\"${_sub_domain}\",\"ttl\":120,\"roundRobin\":[{\"value\":\"${txtvalue}\"}]}}]"; then
if printf -- "%s" "$response" | grep "{\"success\":\"1 record(s) added, 0 record(s) updated, 0 record(s) deleted\"}" >/dev/null; then
_info "Added"
return 0
else
_err "Error adding TXT record"
return 1
fi
fi
}
# Usage: fulldomain txtvalue
# Used to remove the txt record after validation
dns_constellix_rm() {
fulldomain=$1
txtvalue=$2
CONSTELLIX_Key="${CONSTELLIX_Key:-$(_readaccountconf_mutable CONSTELLIX_Key)}"
CONSTELLIX_Secret="${CONSTELLIX_Secret:-$(_readaccountconf_mutable CONSTELLIX_Secret)}"
if [ -z "$CONSTELLIX_Key" ] || [ -z "$CONSTELLIX_Secret" ]; then
_err "You did not specify the Contellix API key and secret yet."
return 1
fi
if ! _get_root "$fulldomain"; then
_err "Invalid domain"
return 1
fi
_info "Removing TXT record"
if _constellix_rest POST "domains/${_domain_id}/records" "[{\"type\":\"txt\",\"delete\":true,\"filter\":{\"field\":\"name\",\"op\":\"eq\",\"value\":\"${_sub_domain}\"}}]"; then
if printf -- "%s" "$response" | grep "{\"success\":\"0 record(s) added, 0 record(s) updated, 1 record(s) deleted\"}" >/dev/null; then
_info "Removed"
return 0
else
_err "Error removing TXT record"
return 1
fi
fi
}
#################### Private functions below ##################################
_get_root() {
domain=$1
i=2
p=1
_debug "Detecting root zone"
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
if [ -z "$h" ]; then
return 1
fi
if ! _constellix_rest GET "domains/search?exact=$h"; then
return 1
fi
if _contains "$response" "\"name\":\"$h\""; then
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]+" | cut -d ':' -f 2)
if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d '.' -f 1-$p)
_domain="$h"
_debug _domain_id "$_domain_id"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
return 0
fi
return 1
fi
p=$i
i=$(_math "$i" + 1)
done
return 1
}
_constellix_rest() {
m=$1
ep="$2"
data="$3"
_debug "$ep"
rdate=$(date +"%s")"000"
hmac=$(printf "%s" "$rdate" | _hmac sha1 "$(printf "%s" "$CONSTELLIX_Secret" | _hex_dump | tr -d ' ')" | _base64)
export _H1="x-cnsdns-apiKey: $CONSTELLIX_Key"
export _H2="x-cnsdns-requestDate: $rdate"
export _H3="x-cnsdns-hmac: $hmac"
export _H4="Accept: application/json"
export _H5="Content-Type: application/json"
if [ "$m" != "GET" ]; then
_debug data "$data"
response="$(_post "$data" "$CONSTELLIX_Api/$ep" "" "$m")"
else
response="$(_get "$CONSTELLIX_Api/$ep")"
fi
if [ "$?" != "0" ]; then
_err "Error $ep"
return 1
fi
_debug response "$response"
return 0
}

2
dnsapi/dns_cyon.sh

@ -1,7 +1,7 @@
#!/usr/bin/env sh
########
# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/Neilpang/acme.sh)
# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/acmesh-official/acme.sh)
#
# Usage: acme.sh --issue --dns dns_cyon -d www.domain.com
#

2
dnsapi/dns_ddnss.sh

@ -12,7 +12,7 @@
# --
#
DDNSS_DNS_API="https://ddnss.de/upd.php"
DDNSS_DNS_API="https://ip4.ddnss.de/upd.php"
######## Public functions #####################

14
dnsapi/dns_dp.sh

@ -53,7 +53,7 @@ dns_dp_rm() {
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
if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&format=json&lang=en&domain_id=$_domain_id&sub_domain=$_sub_domain"; then
_err "Record.Lis error."
return 1
fi
@ -70,12 +70,12 @@ dns_dp_rm() {
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
if ! _rest POST "Record.Remove" "login_token=$DP_Id,$DP_Key&format=json&lang=en&domain_id=$_domain_id&record_id=$record_id"; then
_err "Record.Remove error."
return 1
fi
_contains "$response" "Action completed successful"
_contains "$response" "successful"
}
@ -89,11 +89,11 @@ add_record() {
_info "Adding record"
if ! _rest POST "Record.Create" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认"; then
if ! _rest POST "Record.Create" "login_token=$DP_Id,$DP_Key&format=json&lang=en&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认"; then
return 1
fi
_contains "$response" "Action completed successful" || _contains "$response" "Domain record already exists"
_contains "$response" "successful" || _contains "$response" "Domain record already exists"
}
#################### Private functions below ##################################
@ -113,11 +113,11 @@ _get_root() {
return 1
fi
if ! _rest POST "Domain.Info" "login_token=$DP_Id,$DP_Key&format=json&domain=$h"; then
if ! _rest POST "Domain.Info" "login_token=$DP_Id,$DP_Key&format=json&lang=en&domain=$h"; then
return 1
fi
if _contains "$response" "Action completed successful"; then
if _contains "$response" "successful"; then
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
_debug _domain_id "$_domain_id"
if [ "$_domain_id" ]; then

121
dnsapi/dns_dynv6.sh

@ -0,0 +1,121 @@
#!/usr/bin/env sh
#Author StefanAbl
#Usage specify a private keyfile to use with dynv6 'export KEY="path/to/keyfile"'
#if no keyfile is specified, you will be asked if you want to create one in /home/$USER/.ssh/dynv6 and /home/$USER/.ssh/dynv6.pub
######## Public functions #####################
# Please Read this guide first: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_dynv6_add() {
fulldomain=$1
txtvalue=$2
_info "Using dynv6 api"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
_get_keyfile
_info "using keyfile $dynv6_keyfile"
_get_domain "$fulldomain"
_your_hosts="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts)"
if ! _contains "$_your_hosts" "$_host"; then
_debug "The host is $_host and the record $_record"
_debug "Dynv6 returned $_your_hosts"
_err "The host $_host does not exists on your dynv6 account"
return 1
fi
_debug "found host on your account"
returnval="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts \""$_host"\" records set \""$_record"\" txt data \""$txtvalue"\")"
_debug "Dynv6 returend this after record was added: $returnval"
if _contains "$returnval" "created"; then
return 0
elif _contains "$returnval" "updated"; then
return 0
else
_err "Something went wrong! it does not seem like the record was added succesfully"
return 1
fi
return 1
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_dynv6_rm() {
fulldomain=$1
txtvalue=$2
_info "Using dynv6 api"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
_get_keyfile
_info "using keyfile $dynv6_keyfile"
_get_domain "$fulldomain"
_your_hosts="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts)"
if ! _contains "$_your_hosts" "$_host"; then
_debug "The host is $_host and the record $_record"
_debug "Dynv6 returned $_your_hosts"
_err "The host $_host does not exists on your dynv6 account"
return 1
fi
_debug "found host on your account"
_info "$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts "\"$_host\"" records del "\"$_record\"" txt)"
return 0
}
#################### Private functions below ##################################
#Usage: No Input required
#returns
#dynv6_keyfile the path to the new keyfile that has been generated
_generate_new_key() {
dynv6_keyfile="$(eval echo ~"$USER")/.ssh/dynv6"
_info "Path to key file used: $dynv6_keyfile"
if [ ! -f "$dynv6_keyfile" ] && [ ! -f "$dynv6_keyfile.pub" ]; then
_debug "generating key in $dynv6_keyfile and $dynv6_keyfile.pub"
ssh-keygen -f "$dynv6_keyfile" -t ssh-ed25519 -N ''
else
_err "There is already a file in $dynv6_keyfile or $dynv6_keyfile.pub"
return 1
fi
}
#Usage: _acme-challenge.www.example.dynv6.net
#returns
#_host= example.dynv6.net
#_record=_acme-challenge.www
#aborts if not a valid domain
_get_domain() {
_full_domain="$1"
_debug "getting domain for $_full_domain"
if ! _contains "$_full_domain" 'dynv6.net' && ! _contains "$_full_domain" 'dns.army' && ! _contains "$_full_domain" 'dns.navy'; then
_err "The hosts does not seem to be a dynv6 host"
return 1
fi
_record="${_full_domain%.*}"
_record="${_record%.*}"
_record="${_record%.*}"
_debug "The record we are ging to use is $_record"
_host="$_full_domain"
while [ "$(echo "$_host" | grep -o '\.' | wc -l)" != "2" ]; do
_host="${_host#*.}"
done
_debug "And the host is $_host"
return 0
}
# Usage: No input required
#returns
#dynv6_keyfile path to the key that will be used
_get_keyfile() {
_debug "get keyfile method called"
dynv6_keyfile="${dynv6_keyfile:-$(_readaccountconf_mutable dynv6_keyfile)}"
_debug Your key is "$dynv6_keyfile"
if [ -z "$dynv6_keyfile" ]; then
if [ -z "$KEY" ]; then
_err "You did not specify a key to use with dynv6"
_info "Creating new dynv6 api key to add to dynv6.com"
_generate_new_key
_info "Please add this key to dynv6.com $(cat "$dynv6_keyfile.pub")"
_info "Hit Enter to contiue"
read -r _
#save the credentials to the account conf file.
else
dynv6_keyfile="$KEY"
fi
_saveaccountconf_mutable dynv6_keyfile "$dynv6_keyfile"
fi
}

2
dnsapi/dns_freedns.sh

@ -7,7 +7,7 @@
#
#Author: David Kerr
#Report Bugs here: https://github.com/dkerr64/acme.sh
#or here... https://github.com/Neilpang/acme.sh/issues/2305
#or here... https://github.com/acmesh-official/acme.sh/issues/2305
#
######## Public functions #####################

2
dnsapi/dns_gcloud.sh

@ -131,7 +131,7 @@ _dns_gcloud_find_zone() {
filter="$filter$part. "
part="$(echo "$part" | sed 's/[^.]*\.*//')"
done
filter="$filter)"
filter="$filter) AND visibility=public"
_debug filter "$filter"
# List domains and find the zone with the deepest sub-domain (in case of some levels of delegation)

5
dnsapi/dns_inwx.sh

@ -55,6 +55,7 @@ dns_inwx_rm() {
INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}"
INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}"
INWX_Shared_Secret="${INWX_Shared_Secret:-$(_readaccountconf_mutable INWX_Shared_Secret)}"
if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then
INWX_User=""
INWX_Password=""
@ -63,10 +64,6 @@ dns_inwx_rm() {
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"

129
dnsapi/dns_joker.sh

@ -0,0 +1,129 @@
#!/usr/bin/env sh
# Joker.com API for acme.sh
#
# This script adds the necessary TXT record to a domain in Joker.com.
#
# You must activate Dynamic DNS in Joker.com DNS configuration first.
# Username and password below refer to Dynamic DNS authentication,
# not your Joker.com login credentials.
# See: https://joker.com/faq/content/11/427/en/what-is-dynamic-dns-dyndns.html
#
# NOTE: This script does not support wildcard certificates, because
# Joker.com API does not support adding two TXT records with the same
# subdomain. Adding the second record will overwrite the first one.
# See: https://joker.com/faq/content/6/496/en/let_s-encrypt-support.html
# "... this request will replace all TXT records for the specified
# label by the provided content"
#
# Author: aattww (https://github.com/aattww/)
#
# Report bugs to https://github.com/acmesh-official/acme.sh/issues/2840
#
# JOKER_USERNAME="xxxx"
# JOKER_PASSWORD="xxxx"
JOKER_API="https://svc.joker.com/nic/replace"
######## Public functions #####################
#Usage: dns_joker_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_joker_add() {
fulldomain=$1
txtvalue=$2
JOKER_USERNAME="${JOKER_USERNAME:-$(_readaccountconf_mutable JOKER_USERNAME)}"
JOKER_PASSWORD="${JOKER_PASSWORD:-$(_readaccountconf_mutable JOKER_PASSWORD)}"
if [ -z "$JOKER_USERNAME" ] || [ -z "$JOKER_PASSWORD" ]; then
_err "No Joker.com username and password specified."
return 1
fi
_saveaccountconf_mutable JOKER_USERNAME "$JOKER_USERNAME"
_saveaccountconf_mutable JOKER_PASSWORD "$JOKER_PASSWORD"
if ! _get_root "$fulldomain"; then
_err "Invalid domain"
return 1
fi
_info "Adding TXT record"
if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$_domain&label=$_sub_domain&type=TXT&value=$txtvalue"; then
if _startswith "$response" "OK"; then
_info "Added, OK"
return 0
fi
fi
_err "Error adding TXT record."
return 1
}
#fulldomain txtvalue
dns_joker_rm() {
fulldomain=$1
txtvalue=$2
JOKER_USERNAME="${JOKER_USERNAME:-$(_readaccountconf_mutable JOKER_USERNAME)}"
JOKER_PASSWORD="${JOKER_PASSWORD:-$(_readaccountconf_mutable JOKER_PASSWORD)}"
if ! _get_root "$fulldomain"; then
_err "Invalid domain"
return 1
fi
_info "Removing TXT record"
# TXT record is removed by setting its value to empty.
if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$_domain&label=$_sub_domain&type=TXT&value="; then
if _startswith "$response" "OK"; then
_info "Removed, OK"
return 0
fi
fi
_err "Error removing TXT record."
return 1
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
_get_root() {
fulldomain=$1
i=1
while true; do
h=$(printf "%s" "$fulldomain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
return 1
fi
# Try to remove a test record. With correct root domain, username and password this will return "OK: ..." regardless
# of record in question existing or not.
if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$h&label=jokerTXTUpdateTest&type=TXT&value="; then
if _startswith "$response" "OK"; then
_sub_domain="$(echo "$fulldomain" | sed "s/\\.$h\$//")"
_domain=$h
return 0
fi
fi
i=$(_math "$i" + 1)
done
_debug "Root domain not found"
return 1
}
_joker_rest() {
data="$1"
_debug data "$data"
if ! response="$(_post "$data" "$JOKER_API" "" "POST")"; then
_err "Error POSTing"
return 1
fi
_debug response "$response"
return 0
}

168
dnsapi/dns_kas.sh

@ -0,0 +1,168 @@
#!/usr/bin/env sh
########################################################################
# All-inkl Kasserver hook script for acme.sh
#
# Environment variables:
#
# - $KAS_Login (Kasserver API login name)
# - $KAS_Authtype (Kasserver API auth type. Default: sha1)
# - $KAS_Authdata (Kasserver API auth data.)
#
# Author: Martin Kammerlander, Phlegx Systems OG <martin.kammerlander@phlegx.com>
# Updated by: Marc-Oliver Lange <git@die-lang.es>
# Credits: Inspired by dns_he.sh. Thanks a lot man!
# Git repo: https://github.com/phlegx/acme.sh
# TODO: Better Error handling
########################################################################
KAS_Api="https://kasapi.kasserver.com/dokumentation/formular.php"
######## Public functions #####################
dns_kas_add() {
_fulldomain=$1
_txtvalue=$2
_info "Using DNS-01 All-inkl/Kasserver hook"
_info "Adding $_fulldomain DNS TXT entry on All-inkl/Kasserver"
_info "Check and Save Props"
_check_and_save
_info "Checking Zone and Record_Name"
_get_zone_and_record_name "$_fulldomain"
_info "Getting Record ID"
_get_record_id
_info "Creating TXT DNS record"
params="?kas_login=$KAS_Login"
params="$params&kas_auth_type=$KAS_Authtype"
params="$params&kas_auth_data=$KAS_Authdata"
params="$params&var1=record_name"
params="$params&wert1=$_record_name"
params="$params&var2=record_type"
params="$params&wert2=TXT"
params="$params&var3=record_data"
params="$params&wert3=$_txtvalue"
params="$params&var4=record_aux"
params="$params&wert4=0"
params="$params&kas_action=add_dns_settings"
params="$params&var5=zone_host"
params="$params&wert5=$_zone"
_debug2 "Wait for 10 seconds by default before calling KAS API."
_sleep 10
response="$(_get "$KAS_Api$params")"
_debug2 "response" "$response"
if ! _contains "$response" "TRUE"; then
_err "An unkown error occurred, please check manually."
return 1
fi
return 0
}
dns_kas_rm() {
_fulldomain=$1
_txtvalue=$2
_info "Using DNS-01 All-inkl/Kasserver hook"
_info "Cleaning up after All-inkl/Kasserver hook"
_info "Removing $_fulldomain DNS TXT entry on All-inkl/Kasserver"
_info "Check and Save Props"
_check_and_save
_info "Checking Zone and Record_Name"
_get_zone_and_record_name "$_fulldomain"
_info "Getting Record ID"
_get_record_id
# If there is a record_id, delete the entry
if [ -n "$_record_id" ]; then
params="?kas_login=$KAS_Login"
params="$params&kas_auth_type=$KAS_Authtype"
params="$params&kas_auth_data=$KAS_Authdata"
params="$params&kas_action=delete_dns_settings"
for i in $_record_id; do
params2="$params&var1=record_id"
params2="$params2&wert1=$i"
_debug2 "Wait for 10 seconds by default before calling KAS API."
_sleep 10
response="$(_get "$KAS_Api$params2")"
_debug2 "response" "$response"
if ! _contains "$response" "TRUE"; then
_err "Either the txt record is not found or another error occurred, please check manually."
return 1
fi
done
else # Cannot delete or unkown error
_err "No record_id found that can be deleted. Please check manually."
return 1
fi
return 0
}
########################## PRIVATE FUNCTIONS ###########################
# Checks for the ENV variables and saves them
_check_and_save() {
KAS_Login="${KAS_Login:-$(_readaccountconf_mutable KAS_Login)}"
KAS_Authtype="${KAS_Authtype:-$(_readaccountconf_mutable KAS_Authtype)}"
KAS_Authdata="${KAS_Authdata:-$(_readaccountconf_mutable KAS_Authdata)}"
if [ -z "$KAS_Login" ] || [ -z "$KAS_Authtype" ] || [ -z "$KAS_Authdata" ]; then
KAS_Login=
KAS_Authtype=
KAS_Authdata=
_err "No auth details provided. Please set user credentials using the \$KAS_Login, \$KAS_Authtype, and \$KAS_Authdata environment variables."
return 1
fi
_saveaccountconf_mutable KAS_Login "$KAS_Login"
_saveaccountconf_mutable KAS_Authtype "$KAS_Authtype"
_saveaccountconf_mutable KAS_Authdata "$KAS_Authdata"
return 0
}
# Gets back the base domain/zone and record name.
# See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
_get_zone_and_record_name() {
params="?kas_login=$KAS_Login"
params="?kas_login=$KAS_Login"
params="$params&kas_auth_type=$KAS_Authtype"
params="$params&kas_auth_data=$KAS_Authdata"
params="$params&kas_action=get_domains"
_debug2 "Wait for 10 seconds by default before calling KAS API."
_sleep 10
response="$(_get "$KAS_Api$params")"
_debug2 "response" "$response"
_zonen="$(echo "$response" | tr -d "\n\r" | tr -d " " | tr '[]' '<>' | sed "s/=>Array/\n=> Array/g" | tr ' ' '\n' | grep "domain_name" | tr '<' '\n' | grep "domain_name" | sed "s/domain_name>=>//g")"
_domain="$1"
_temp_domain="$(echo "$1" | sed 's/\.$//')"
_rootzone="$_domain"
for i in $_zonen; do
l1=${#_rootzone}
l2=${#i}
if _endswith "$_domain" "$i" && [ "$l1" -ge "$l2" ]; then
_rootzone="$i"
fi
done
_zone="${_rootzone}."
_temp_record_name="$(echo "$_temp_domain" | sed "s/$_rootzone//g")"
_record_name="$(echo "$_temp_record_name" | sed 's/\.$//')"
_debug2 "Zone:" "$_zone"
_debug2 "Domain:" "$_domain"
_debug2 "Record_Name:" "$_record_name"
return 0
}
# Retrieve the DNS record ID
_get_record_id() {
params="?kas_login=$KAS_Login"
params="$params&kas_auth_type=$KAS_Authtype"
params="$params&kas_auth_data=$KAS_Authdata"
params="$params&kas_action=get_dns_settings"
params="$params&var1=zone_host"
params="$params&wert1=$_zone"
_debug2 "Wait for 10 seconds by default before calling KAS API."
_sleep 10
response="$(_get "$KAS_Api$params")"
_debug2 "response" "$response"
_record_id="$(echo "$response" | tr -d "\n\r" | tr -d " " | tr '[]' '<>' | sed "s/=>Array/\n=> Array/g" | tr ' ' '\n' | grep "=>$_record_name<" | grep '>TXT<' | tr '<' '\n' | grep record_id | sed "s/record_id>=>//g")"
_debug2 _record_id "$_record_id"
return 0
}

12
dnsapi/dns_lexicon.sh

@ -5,7 +5,7 @@
# https://github.com/AnalogJ/lexicon
lexicon_cmd="lexicon"
wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api"
wiki="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-lexicon-dns-api"
_lexicon_init() {
if ! _exists "$lexicon_cmd"; then
@ -63,6 +63,16 @@ _lexicon_init() {
_saveaccountconf_mutable "$Lx_domaintoken" "$Lx_domaintoken_v"
eval export "$Lx_domaintoken"
fi
# shellcheck disable=SC2018,SC2019
Lx_api_key=$(echo LEXICON_"${PROVIDER}"_API_KEY | tr 'a-z' 'A-Z')
eval "$Lx_api_key=\${$Lx_api_key:-$(_readaccountconf_mutable "$Lx_api_key")}"
Lx_api_key_v=$(eval echo \$"$Lx_api_key")
_secure_debug "$Lx_api_key" "$Lx_api_key_v"
if [ "$Lx_api_key_v" ]; then
_saveaccountconf_mutable "$Lx_api_key" "$Lx_api_key_v"
eval export "$Lx_api_key"
fi
}
######## Public functions #####################

10
dnsapi/dns_linode_v4.sh

@ -36,7 +36,7 @@ dns_linode_v4_add() {
}"
if _rest POST "/$_domain_id/records" "$_payload" && [ -n "$response" ]; then
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"id\": *[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
_debug _resource_id "$_resource_id"
if [ -z "$_resource_id" ]; then
@ -74,9 +74,9 @@ dns_linode_v4_rm() {
if _rest GET "/$_domain_id/records" && [ -n "$response" ]; then
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
resource="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$_sub_domain\".*}")"
resource="$(echo "$response" | _egrep_o "\{.*\"name\": *\"$_sub_domain\".*}")"
if [ "$resource" ]; then
_resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
_resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"id\": *[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
if [ "$_resource_id" ]; then
_debug _resource_id "$_resource_id"
@ -139,9 +139,9 @@ _get_root() {
return 1
fi
hostedzone="$(echo "$response" | _egrep_o "{.*\"domain\":\s*\"$h\".*}")"
hostedzone="$(echo "$response" | _egrep_o "\{.*\"domain\": *\"$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 \ )
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\": *[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

2
dnsapi/dns_me.sh

@ -114,7 +114,7 @@ _get_root() {
fi
if _contains "$response" "\"name\":\"$h\""; 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" | sed 's/^{//; s/}$//; s/{.*}//' | sed -r 's/^.*"id":([0-9]+).*$/\1/')
if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain="$h"

2
dnsapi/dns_miab.sh

@ -10,7 +10,7 @@
# used to communicate with the MailinaBox Custom DNS API
# Report Bugs here:
# https://github.com/billgertz/MIAB_dns_api (for dns_miab.sh)
# https://github.com/Neilpang/acme.sh (for acme.sh)
# https://github.com/acmesh-official/acme.sh (for acme.sh)
#
######## Public functions #####################

159
dnsapi/dns_misaka.sh

@ -0,0 +1,159 @@
#!/usr/bin/env sh
# bug reports to support+acmesh@misaka.io
# based on dns_nsone.sh by dev@1e.ca
#
#Misaka_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
#
Misaka_Api="https://dnsapi.misaka.io/dns"
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_misaka_add() {
fulldomain=$1
txtvalue=$2
if [ -z "$Misaka_Key" ]; then
Misaka_Key=""
_err "You didn't specify misaka.io 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 Misaka_Key "$Misaka_Key"
_debug "checking root zone [$fulldomain]"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_debug "Getting txt records"
_misaka_rest GET "zones/${_domain}/recordsets?search=${_sub_domain}"
if ! _contains "$response" "\"results\":"; then
_err "Error"
return 1
fi
count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$_sub_domain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ")
_debug count "$count"
if [ "$count" = "0" ]; then
_info "Adding record"
if _misaka_rest PUT "zones/${_domain}/recordsets/${_sub_domain}/TXT" "{\"records\":[{\"value\":\"\\\"$txtvalue\\\"\"}],\"filters\":[],\"ttl\":1}"; then
_debug response "$response"
if _contains "$response" "$_sub_domain"; then
_info "Added"
return 0
else
_err "Add txt record error."
return 1
fi
fi
_err "Add txt record error."
else
_info "Updating record"
_misaka_rest POST "zones/${_domain}/recordsets/${_sub_domain}/TXT?append=true" "{\"records\": [{\"value\": \"\\\"$txtvalue\\\"\"}],\"ttl\":1}"
if [ "$?" = "0" ] && _contains "$response" "$_sub_domain"; then
_info "Updated!"
#todo: check if the record takes effect
return 0
fi
_err "Update error"
return 1
fi
}
#fulldomain
dns_misaka_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"
_misaka_rest GET "zones/${_domain}/recordsets?search=${_sub_domain}"
count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$_sub_domain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ")
_debug count "$count"
if [ "$count" = "0" ]; then
_info "Don't need to remove."
else
if ! _misaka_rest DELETE "zones/${_domain}/recordsets/${_sub_domain}/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 ! _misaka_rest GET "zones?limit=1000"; 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" "\"name\":\"$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
}
_misaka_rest() {
m=$1
ep="$2"
data="$3"
_debug "$ep"
export _H1="Content-Type: application/json"
export _H2="User-Agent: acme.sh/$VER misaka-dns-acmesh/20191213"
export _H3="Authorization: Token $Misaka_Key"
if [ "$m" != "GET" ]; then
_debug data "$data"
response="$(_post "$data" "$Misaka_Api/$ep" "" "$m")"
else
response="$(_get "$Misaka_Api/$ep")"
fi
if [ "$?" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
return 0
}

4
dnsapi/dns_myapi.sh

@ -7,11 +7,11 @@
#returns 0 means success, otherwise error.
#
#Author: Neilpang
#Report Bugs here: https://github.com/Neilpang/acme.sh
#Report Bugs here: https://github.com/acmesh-official/acme.sh
#
######## Public functions #####################
# Please Read this guide first: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
# Please Read this guide first: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_myapi_add() {

94
dnsapi/dns_nic.sh

@ -1,10 +1,9 @@
#!/usr/bin/env sh
#
#NIC_Token="sdfsdfsdfljlbjkljlkjsdfoiwjedfglgkdlfgkfgldfkg"
#
#NIC_ClientID='0dc0xxxxxxxxxxxxxxxxxxxxxxxxce88'
#NIC_ClientSecret='3LTtxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxnuW8'
#NIC_Username="000000/NIC-D"
#NIC_Password="xxxxxxx"
NIC_Api="https://api.nic.ru"
@ -13,22 +12,7 @@ dns_nic_add() {
fulldomain="${1}"
txtvalue="${2}"
NIC_Token="${NIC_Token:-$(_readaccountconf_mutable NIC_Token)}"
NIC_Username="${NIC_Username:-$(_readaccountconf_mutable NIC_Username)}"
NIC_Password="${NIC_Password:-$(_readaccountconf_mutable NIC_Password)}"
if [ -z "$NIC_Token" ] || [ -z "$NIC_Username" ] || [ -z "$NIC_Password" ]; then
NIC_Token=""
NIC_Username=""
NIC_Password=""
_err "You must export variables: NIC_Token, NIC_Username and NIC_Password"
return 1
fi
_saveaccountconf_mutable NIC_Customer "$NIC_Token"
_saveaccountconf_mutable NIC_Username "$NIC_Username"
_saveaccountconf_mutable NIC_Password "$NIC_Password"
if ! _nic_get_authtoken "$NIC_Username" "$NIC_Password" "$NIC_Token"; then
if ! _nic_get_authtoken save; then
_err "get NIC auth token failed"
return 1
fi
@ -59,18 +43,7 @@ dns_nic_rm() {
fulldomain="${1}"
txtvalue="${2}"
NIC_Token="${NIC_Token:-$(_readaccountconf_mutable NIC_Token)}"
NIC_Username="${NIC_Username:-$(_readaccountconf_mutable NIC_Username)}"
NIC_Password="${NIC_Password:-$(_readaccountconf_mutable NIC_Password)}"
if [ -z "$NIC_Token" ] || [ -z "$NIC_Username" ] || [ -z "$NIC_Password" ]; then
NIC_Token=""
NIC_Username=""
NIC_Password=""
_err "You must export variables: NIC_Token, NIC_Username and NIC_Password"
return 1
fi
if ! _nic_get_authtoken "$NIC_Username" "$NIC_Password" "$NIC_Token"; then
if ! _nic_get_authtoken; then
_err "get NIC auth token failed"
return 1
fi
@ -103,17 +76,64 @@ dns_nic_rm() {
#################### Private functions below ##################################
#_nic_get_auth_elements [need2save]
_nic_get_auth_elements() {
_need2save=$1
NIC_ClientID="${NIC_ClientID:-$(_readaccountconf_mutable NIC_ClientID)}"
NIC_ClientSecret="${NIC_ClientSecret:-$(_readaccountconf_mutable NIC_ClientSecret)}"
NIC_Username="${NIC_Username:-$(_readaccountconf_mutable NIC_Username)}"
NIC_Password="${NIC_Password:-$(_readaccountconf_mutable NIC_Password)}"
## for backward compatibility
if [ -z "$NIC_ClientID" ] || [ -z "$NIC_ClientSecret" ]; then
NIC_Token="${NIC_Token:-$(_readaccountconf_mutable NIC_Token)}"
_debug NIC_Token "$NIC_Token"
if [ -n "$NIC_Token" ]; then
_two_values="$(echo "${NIC_Token}" | _dbase64)"
_debug _two_values "$_two_values"
NIC_ClientID=$(echo "$_two_values" | cut -d':' -f1)
NIC_ClientSecret=$(echo "$_two_values" | cut -d':' -f2-)
_debug restored_NIC_ClientID "$NIC_ClientID"
_debug restored_NIC_ClientSecret "$NIC_ClientSecret"
fi
fi
if [ -z "$NIC_ClientID" ] || [ -z "$NIC_ClientSecret" ] || [ -z "$NIC_Username" ] || [ -z "$NIC_Password" ]; then
NIC_ClientID=""
NIC_ClientSecret=""
NIC_Username=""
NIC_Password=""
_err "You must export variables: NIC_ClientID, NIC_ClientSecret, NIC_Username and NIC_Password"
return 1
fi
if [ "$_need2save" ]; then
_saveaccountconf_mutable NIC_ClientID "$NIC_ClientID"
_saveaccountconf_mutable NIC_ClientSecret "$NIC_ClientSecret"
_saveaccountconf_mutable NIC_Username "$NIC_Username"
_saveaccountconf_mutable NIC_Password "$NIC_Password"
fi
NIC_BasicAuth=$(printf "%s:%s" "${NIC_ClientID}" "${NIC_ClientSecret}" | _base64)
_debug NIC_BasicAuth "$NIC_BasicAuth"
}
#_nic_get_authtoken [need2save]
_nic_get_authtoken() {
username="$1"
password="$2"
token="$3"
_need2save=$1
if ! _nic_get_auth_elements "$_need2save"; then
return 1
fi
_info "Getting NIC auth token"
export _H1="Authorization: Basic $token"
export _H1="Authorization: Basic ${NIC_BasicAuth}"
export _H2="Content-Type: application/x-www-form-urlencoded"
res=$(_post "grant_type=password&username=$username&password=$password&scope=%28GET%7CPUT%7CPOST%7CDELETE%29%3A%2Fdns-master%2F.%2B" "$NIC_Api/oauth/token" "" "POST")
res=$(_post "grant_type=password&username=${NIC_Username}&password=${NIC_Password}&scope=%28GET%7CPUT%7CPOST%7CDELETE%29%3A%2Fdns-master%2F.%2B" "$NIC_Api/oauth/token" "" "POST")
if _contains "$res" "access_token"; then
_auth_token=$(printf "%s" "$res" | cut -d , -f2 | tr -d "\"" | sed "s/access_token://")
_info "Token received"
@ -146,7 +166,7 @@ _get_root() {
if _contains "$_all_domains" "^$h$"; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain=$h
_service=$(printf "%s" "$response" | grep "$_domain" | sed -r "s/.*service=\"(.*)\".*$/\1/")
_service=$(printf "%s" "$response" | grep "idn-name=\"$_domain\"" | sed -r "s/.*service=\"(.*)\".*$/\1/")
return 0
fi
p="$i"

88
dnsapi/dns_nm.sh

@ -0,0 +1,88 @@
#!/usr/bin/env sh
########################################################################
# https://namemaster.de hook script for acme.sh
#
# Environment variables:
#
# - $NM_user (your namemaster.de API username)
# - $NM_sha256 (your namemaster.de API password_as_sha256hash)
#
# Author: Thilo Gass <thilo.gass@gmail.com>
# Git repo: https://github.com/ThiloGa/acme.sh
#-- dns_nm_add() - Add TXT record --------------------------------------
# Usage: dns_nm_add _acme-challenge.subdomain.domain.com "XyZ123..."
namemaster_api="https://namemaster.de/api/api.php"
dns_nm_add() {
fulldomain=$1
txt_value=$2
_info "Using DNS-01 namemaster hook"
NM_user="${NM_user:-$(_readaccountconf_mutable NM_user)}"
NM_sha256="${NM_sha256:-$(_readaccountconf_mutable NM_sha256)}"
if [ -z "$NM_user" ] || [ -z "$NM_sha256" ]; then
NM_user=""
NM_sha256=""
_err "No auth details provided. Please set user credentials using the \$NM_user and \$NM_sha256 environment variables."
return 1
fi
#save the api user and sha256 password to the account conf file.
_debug "Save user and hash"
_saveaccountconf_mutable NM_user "$NM_user"
_saveaccountconf_mutable NM_sha256 "$NM_sha256"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain" "$fulldomain"
return 1
fi
_info "die Zone lautet:" "$zone"
get="$namemaster_api?User=$NM_user&Password=$NM_sha256&Antwort=csv&Typ=ACME&zone=$zone&hostname=$fulldomain&TXT=$txt_value&Action=Auto&Lifetime=3600"
if ! erg="$(_get "$get")"; then
_err "error Adding $fulldomain TXT: $txt_value"
return 1
fi
if _contains "$erg" "Success"; then
_info "Success, TXT Added, OK"
else
_err "error Adding $fulldomain TXT: $txt_value erg: $erg"
return 1
fi
_debug "ok Auto $fulldomain TXT: $txt_value erg: $erg"
return 0
}
dns_nm_rm() {
fulldomain=$1
txtvalue=$2
_info "TXT enrty in $fulldomain is deleted automatically"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
}
_get_root() {
domain=$1
get="$namemaster_api?User=$NM_user&Password=$NM_sha256&Typ=acme&hostname=$domain&Action=getzone&antwort=csv"
if ! zone="$(_get "$get")"; then
_err "error getting Zone"
return 1
else
if _contains "$zone" "hostname not found"; then
return 1
fi
fi
}

2
dnsapi/dns_openprovider.sh

@ -3,7 +3,7 @@
# This is the OpenProvider API wrapper for acme.sh
#
# Author: Sylvia van Os
# Report Bugs here: https://github.com/Neilpang/acme.sh/issues/2104
# Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/2104
#
# export OPENPROVIDER_USER="username"
# export OPENPROVIDER_PASSWORDHASH="hashed_password"

273
dnsapi/dns_opnsense.sh

@ -0,0 +1,273 @@
#!/usr/bin/env sh
#OPNsense Bind API
#https://docs.opnsense.org/development/api.html
#
#OPNs_Host="opnsense.example.com"
#OPNs_Port="443"
# optional, defaults to 443 if unset
#OPNs_Key="qocfU9RSbt8vTIBcnW8bPqCrpfAHMDvj5OzadE7Str+rbjyCyk7u6yMrSCHtBXabgDDXx/dY0POUp7ZA"
#OPNs_Token="pZEQ+3ce8dDlfBBdg3N8EpqpF5I1MhFqdxX06le6Gl8YzyQvYCfCzNaFX9O9+IOSyAs7X71fwdRiZ+Lv"
#OPNs_Api_Insecure=0
# optional, defaults to 0 if unset
# Set 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1)
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000"
#fulldomain
#txtvalue
OPNs_DefaultPort=443
OPNs_DefaultApi_Insecure=0
dns_opnsense_add() {
fulldomain=$1
txtvalue=$2
_opns_check_auth || return 1
if ! set_record "$fulldomain" "$txtvalue"; then
return 1
fi
return 0
}
#fulldomain
dns_opnsense_rm() {
fulldomain=$1
txtvalue=$2
_opns_check_auth || return 1
if ! rm_record "$fulldomain" "$txtvalue"; then
return 1
fi
return 0
}
set_record() {
fulldomain=$1
new_challenge=$2
_info "Adding record $fulldomain with challenge: $new_challenge"
_debug "Detect root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _domain "$_domain"
_debug _host "$_host"
_debug _domainid "$_domainid"
_return_str=""
_record_string=""
_build_record_string "$_domainid" "$_host" "$new_challenge"
_uuid=""
if _existingchallenge "$_domain" "$_host" "$new_challenge"; then
# Update
if _opns_rest "POST" "/record/setRecord/${_uuid}" "$_record_string"; then
_return_str="$response"
else
return 1
fi
else
#create
if _opns_rest "POST" "/record/addRecord" "$_record_string"; then
_return_str="$response"
else
return 1
fi
fi
if echo "$_return_str" | _egrep_o "\"result\":\"saved\"" >/dev/null; then
_opns_rest "POST" "/service/reconfigure" "{}"
_debug "Record created"
else
_err "Error creating record $_record_string"
return 1
fi
return 0
}
rm_record() {
fulldomain=$1
new_challenge="$2"
_info "Remove record $fulldomain with challenge: $new_challenge"
_debug "Detect root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _domain "$_domain"
_debug _host "$_host"
_debug _domainid "$_domainid"
_uuid=""
if _existingchallenge "$_domain" "$_host" "$new_challenge"; then
# Delete
if _opns_rest "POST" "/record/delRecord/${_uuid}" "\{\}"; then
if echo "$_return_str" | _egrep_o "\"result\":\"deleted\"" >/dev/null; then
_opns_rest "POST" "/service/reconfigure" "{}"
_debug "Record deleted"
else
_err "Error deleting record $_host from domain $fulldomain"
return 1
fi
else
_err "Error deleting record $_host from domain $fulldomain"
return 1
fi
else
_info "Record not found, nothing to remove"
fi
return 0
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _domainid=domid
#_domain=domain.com
_get_root() {
domain=$1
i=2
p=1
if _opns_rest "GET" "/domain/get"; then
_domain_response="$response"
else
return 1
fi
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
if [ -z "$h" ]; then
#not valid
return 1
fi
_debug h "$h"
id=$(echo "$_domain_response" | _egrep_o "\"[^\"]*\":{\"enabled\":\"1\",\"type\":{\"master\":{\"value\":\"master\",\"selected\":1},\"slave\":{\"value\":\"slave\",\"selected\":0}},\"masterip\":\"[^\"]*\",\"domainname\":\"${h}\"" | cut -d ':' -f 1 | cut -d '"' -f 2)
if [ -n "$id" ]; then
_debug id "$id"
_host=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain="${h}"
_domainid="${id}"
return 0
fi
p=$i
i=$(_math $i + 1)
done
_debug "$domain not found"
return 1
}
_opns_rest() {
method=$1
ep=$2
data=$3
#Percent encode user and token
key=$(echo "$OPNs_Key" | tr -d "\n\r" | _url_encode)
token=$(echo "$OPNs_Token" | tr -d "\n\r" | _url_encode)
opnsense_url="https://${key}:${token}@${OPNs_Host}:${OPNs_Port:-$OPNs_DefaultPort}/api/bind${ep}"
export _H1="Content-Type: application/json"
_debug2 "Try to call api: https://${OPNs_Host}:${OPNs_Port:-$OPNs_DefaultPort}/api/bind${ep}"
if [ ! "$method" = "GET" ]; then
_debug data "$data"
export _H1="Content-Type: application/json"
response="$(_post "$data" "$opnsense_url" "" "$method")"
else
export _H1=""
response="$(_get "$opnsense_url")"
fi
if [ "$?" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
return 0
}
_build_record_string() {
_record_string="{\"record\":{\"enabled\":\"1\",\"domain\":\"$1\",\"name\":\"$2\",\"type\":\"TXT\",\"value\":\"$3\"}}"
}
_existingchallenge() {
if _opns_rest "GET" "/record/searchRecord"; then
_record_response="$response"
else
return 1
fi
_uuid=""
_uuid=$(echo "$_record_response" | _egrep_o "\"uuid\":\"[^\"]*\",\"enabled\":\"[01]\",\"domain\":\"$1\",\"name\":\"$2\",\"type\":\"TXT\",\"value\":\"$3\"" | cut -d ':' -f 2 | cut -d '"' -f 2)
if [ -n "$_uuid" ]; then
_debug uuid "$_uuid"
return 0
fi
_debug "${2}.$1{1} record not found"
return 1
}
_opns_check_auth() {
OPNs_Host="${OPNs_Host:-$(_readaccountconf_mutable OPNs_Host)}"
OPNs_Port="${OPNs_Port:-$(_readaccountconf_mutable OPNs_Port)}"
OPNs_Key="${OPNs_Key:-$(_readaccountconf_mutable OPNs_Key)}"
OPNs_Token="${OPNs_Token:-$(_readaccountconf_mutable OPNs_Token)}"
OPNs_Api_Insecure="${OPNs_Api_Insecure:-$(_readaccountconf_mutable OPNs_Api_Insecure)}"
if [ -z "$OPNs_Host" ]; then
_err "You don't specify OPNsense address."
return 1
else
_saveaccountconf_mutable OPNs_Host "$OPNs_Host"
fi
if ! printf '%s' "$OPNs_Port" | grep '^[0-9]*$' >/dev/null; then
_err 'OPNs_Port specified but not numeric value'
return 1
elif [ -z "$OPNs_Port" ]; then
_info "OPNSense port not specified. Defaulting to using port $OPNs_DefaultPort"
else
_saveaccountconf_mutable OPNs_Port "$OPNs_Port"
fi
if ! printf '%s' "$OPNs_Api_Insecure" | grep '^[01]$' >/dev/null; then
_err 'OPNs_Api_Insecure specified but not 0/1 value'
return 1
elif [ -n "$OPNs_Api_Insecure" ]; then
_saveaccountconf_mutable OPNs_Api_Insecure "$OPNs_Api_Insecure"
fi
export HTTPS_INSECURE="${OPNs_Api_Insecure:-$OPNs_DefaultApi_Insecure}"
if [ -z "$OPNs_Key" ]; then
_err "you have not specified your OPNsense api key id."
_err "Please set OPNs_Key and try again."
return 1
else
_saveaccountconf_mutable OPNs_Key "$OPNs_Key"
fi
if [ -z "$OPNs_Token" ]; then
_err "you have not specified your OPNsense token."
_err "Please create OPNs_Token and try again."
return 1
else
_saveaccountconf_mutable OPNs_Token "$OPNs_Token"
fi
if ! _opns_rest "GET" "/general/get"; then
_err "Call to OPNsense API interface failed. Unable to access OPNsense API."
return 1
fi
return 0
}

4
dnsapi/dns_ovh.sh

@ -32,9 +32,9 @@ SYS_CA='https://ca.api.soyoustart.com/1.0'
#'runabove-ca'
RAV_CA='https://api.runabove.com/1.0'
wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api"
wiki="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-OVH-domain-api"
ovh_success="https://github.com/Neilpang/acme.sh/wiki/OVH-Success"
ovh_success="https://github.com/acmesh-official/acme.sh/wiki/OVH-Success"
_ovh_get_api() {
_ogaep="$1"

2
dnsapi/dns_pleskxml.sh

@ -2,7 +2,7 @@
## Name: dns_pleskxml.sh
## Created by Stilez.
## Also uses some code from PR#1832 by @romanlum (https://github.com/Neilpang/acme.sh/pull/1832/files)
## Also uses some code from PR#1832 by @romanlum (https://github.com/acmesh-official/acme.sh/pull/1832/files)
## This DNS-01 method uses the Plesk XML API described at:
## https://docs.plesk.com/en-US/12.5/api-rpc/about-xml-api.28709

2
dnsapi/dns_rackspace.sh

@ -9,7 +9,7 @@ RACKSPACE_Endpoint="https://dns.api.rackspacecloud.com/v1.0"
# 20190213 - The name & id fields swapped in the API response; fix sed
# 20190101 - Duplicating file for new pull request to dev branch
# Original - tcocca:rackspace_dnsapi https://github.com/Neilpang/acme.sh/pull/1297
# Original - tcocca:rackspace_dnsapi https://github.com/acmesh-official/acme.sh/pull/1297
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"

2
dnsapi/dns_servercow.sh

@ -1,7 +1,7 @@
#!/usr/bin/env sh
##########
# Custom servercow.de DNS API v1 for use with [acme.sh](https://github.com/Neilpang/acme.sh)
# Custom servercow.de DNS API v1 for use with [acme.sh](https://github.com/acmesh-official/acme.sh)
#
# Usage:
# export SERVERCOW_API_Username=username

2
dnsapi/dns_unoeuro.sh

@ -52,7 +52,7 @@ dns_unoeuro_add() {
fi
_info "Adding record"
if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then
if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120,\"priority\":0}"; then
if _contains "$response" "\"status\": 200" >/dev/null; then
_info "Added, OK"
return 0

126
dnsapi/dns_yandex.sh

@ -6,6 +6,9 @@
# Values to export:
# export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# Sometimes cloudflare / google doesn't pick new dns records fast enough.
# You can add --dnssleep XX to params as workaround.
######## Public functions #####################
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
@ -13,97 +16,106 @@ dns_yandex_add() {
fulldomain="${1}"
txtvalue="${2}"
_debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'"
_PDD_credentials || return 1
export _H1="PddToken: $PDD_Token"
_PDD_get_domain "$fulldomain" || return 1
_debug "Found suitable domain in pdd: $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"
_PDD_get_domain || return 1
_debug "Found suitable domain: $domain"
_PDD_get_record_ids || return 1
_debug "Record_ids: $record_ids"
if [ ! -z "$record_ids" ]; then
_info "All existing $subdomain records from $domain will be removed at the very end."
fi
data="domain=${domain}&type=TXT&subdomain=${subdomain}&ttl=300&content=${txtvalue}"
uri="https://pddimp.yandex.ru/api2/admin/dns/add"
result="$(_post "${data}" "${uri}" | _normalizeJson)"
_debug "Result: $result"
if ! _contains "$result" '"success":"ok"'; then
if _contains "$result" '"success":"error"' && _contains "$result" '"error":"record_exists"'; then
_info "Record already exists."
else
_err "Can't add $subdomain to $domain."
return 1
fi
fi
}
#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"
_PDD_get_domain "$fulldomain" || return 1
_debug "Found suitable domain in pdd: $curDomain"
_debug "Found suitable domain: $domain"
record_id=$(pdd_get_record_id "${fulldomain}")
_debug "Result: $record_id"
_PDD_get_record_ids "${domain}" "${subdomain}" || return 1
_debug "Record_ids: $record_ids"
for rec_i in $record_id; do
curUri="https://pddimp.yandex.ru/api2/admin/dns/del"
curData="domain=${curDomain}&record_id=${rec_i}"
curResult="$(_post "${curData}" "${curUri}")"
_debug "Result: $curResult"
for record_id in $record_ids; do
data="domain=${domain}&record_id=${record_id}"
uri="https://pddimp.yandex.ru/api2/admin/dns/del"
result="$(_post "${data}" "${uri}" | _normalizeJson)"
_debug "Result: $result"
if ! _contains "$result" '"success":"ok"'; then
_info "Can't remove $subdomain from $domain."
fi
done
}
#################### 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)"
_debug2 "res1" "$res1"
__found="$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p')"
_debug "found: $__found results on page"
if [ "0$__found" -lt 20 ]; then
_debug "last page: $__page"
__last=1
subdomain_start=1
while true; do
domain_start=$(_math $subdomain_start + 1)
domain=$(echo "$fulldomain" | cut -d . -f "$domain_start"-)
subdomain=$(echo "$fulldomain" | cut -d . -f -"$subdomain_start")
_debug "Checking domain $domain"
if [ -z "$domain" ]; then
return 1
fi
__all_domains="$__all_domains $(echo "$res1" | tr "," "\n" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')"
uri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=$domain"
result="$(_get "${uri}" | _normalizeJson)"
_debug "Result: $result"
__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
p=$(_math $k - 1)
curSubdomain="$(echo "$fulldomain" | cut -d . -f "1-$p")"
curDomain="$__t"
return 0
fi
done
k=$(_math $k + 1)
if _contains "$result" '"success":"ok"'; then
return 0
fi
subdomain_start=$(_math $subdomain_start + 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"
_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
export _H1="PddToken: $PDD_Token"
}
pdd_get_record_id() {
fulldomain="${1}"
_PDD_get_record_ids() {
_debug "Check existing records for $subdomain"
uri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${domain}"
result="$(_get "${uri}" | _normalizeJson)"
_debug "Result: $result"
_PDD_get_domain "$fulldomain"
_debug "Found suitable domain in pdd: $curDomain"
if ! _contains "$result" '"success":"ok"'; then
return 1
fi
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'
record_ids=$(echo "$result" | _egrep_o "{[^{]*\"subdomain\":\"${subdomain}\"[^}]*}" | sed -n -e 's#.*"record_id": \([0-9]*\).*#\1#p')
}

4
dnsapi/dns_zone.sh

@ -136,10 +136,10 @@ _get_root() {
if [ -z "$h" ]; then
return 1
fi
if ! _zone_rest GET "dns/$h/a"; then
if ! _zone_rest GET "dns/$h"; then
return 1
fi
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
if _contains "$response" "\"identificator\":\"$h\"" >/dev/null; then
_domain=$h
return 0
fi

64
notify/cqhttp.sh

@ -0,0 +1,64 @@
#!/usr/bin/env sh
#Support for CQHTTP api. Push notification on CoolQ
#CQHTTP_TOKEN="" Recommended to be not empty, QQ application token
#CQHTTP_USER="" Required, QQ receiver ID
#CQHTTP_APIROOT="" Required, CQHTTP Server URL (without slash suffix)
#CQHTTP_CUSTOM_MSGHEAD="" Optional, custom message header
CQHTTP_APIPATH="/send_private_msg"
cqhttp_send() {
_subject="$1"
_content="$2"
_statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
_debug "_statusCode" "$_statusCode"
CQHTTP_TOKEN="${CQHTTP_TOKEN:-$(_readaccountconf_mutable CQHTTP_TOKEN)}"
if [ -z "$CQHTTP_TOKEN" ]; then
CQHTTP_TOKEN=""
_info "You didn't specify a CQHTTP application token yet, which is unsafe. Assuming it to be empty."
else
_saveaccountconf_mutable CQHTTP_TOKEN "$CQHTTP_TOKEN"
fi
CQHTTP_USER="${CQHTTP_USER:-$(_readaccountconf_mutable CQHTTP_USER)}"
if [ -z "$CQHTTP_USER" ]; then
CQHTTP_USER=""
_err "You didn't specify a QQ user yet."
return 1
fi
_saveaccountconf_mutable CQHTTP_USER "$CQHTTP_USER"
CQHTTP_APIROOT="${CQHTTP_APIROOT:-$(_readaccountconf_mutable CQHTTP_APIROOT)}"
if [ -z "$CQHTTP_APIROOT" ]; then
CQHTTP_APIROOT=""
_err "You didn't specify the API root yet."
return 1
fi
_saveaccountconf_mutable CQHTTP_APIROOT "$CQHTTP_APIROOT"
CQHTTP_CUSTOM_MSGHEAD="${CQHTTP_CUSTOM_MSGHEAD:-$(_readaccountconf_mutable CQHTTP_CUSTOM_MSGHEAD)}"
if [ -z "$CQHTTP_CUSTOM_MSGHEAD" ]; then
CQHTTP_CUSTOM_MSGHEAD="A message from acme.sh:"
else
_saveaccountconf_mutable CQHTTP_CUSTOM_MSGHEAD "$CQHTTP_CUSTOM_MSGHEAD"
fi
_access_token="$(printf "%s" "$CQHTTP_TOKEN" | _url_encode)"
_user_id="$(printf "%s" "$CQHTTP_USER" | _url_encode)"
_message="$(printf "$CQHTTP_CUSTOM_MSGHEAD %s\\n%s" "$_subject" "$_content" | _url_encode)"
_finalUrl="$CQHTTP_APIROOT$CQHTTP_APIPATH?access_token=$_access_token&user_id=$_user_id&message=$_message"
response="$(_get "$_finalUrl")"
if [ "$?" = "0" ] && _contains "$response" "\"retcode\":0,\"status\":\"ok\""; then
_info "QQ send success."
return 0
fi
_err "QQ send error."
_debug "URL" "$_finalUrl"
_debug "Response" "$response"
return 1
}
Loading…
Cancel
Save