diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 53112c6f..c9c1b555 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.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).
-->
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 3bd170b7..4f7ceb47 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.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.
-->
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 1264803e..155ec64b 100644
--- a/.travis.yml
+++ b/.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
diff --git a/README.md b/README.md
index d5012d68..d1c793d4 100644
--- a/README.md
+++ b/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)
[![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,41 @@ 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
+|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-latest.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/base-archlinux.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-linux-docker.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
-For all build statuses, check our [weekly build project](https://github.com/Neilpang/acmetest):
+For all build statuses, check our [weekly build project](https://github.com/acmesh-official/acmetest):
-https://github.com/Neilpang/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 +85,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 +111,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 +180,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 +226,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 +238,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
@@ -259,7 +259,7 @@ acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com
You will need to configure your website config files to use the cert by yourself.
We don't want to mess your apache server, don't worry.**
-More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
+More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert
# 7. Use Nginx mode
@@ -283,7 +283,7 @@ acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com
You will need to configure your website config files to use the cert by yourself.
We don't want to mess your nginx server, don't worry.**
-More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
+More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert
# 8. Automatic DNS API integration
@@ -293,11 +293,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 +430,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 +456,7 @@ TODO:
### Code Contributors
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
-
+
### Financial Contributors
@@ -487,7 +487,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 +495,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)
diff --git a/acme.sh b/acme.sh
index 07838b29..c9cd0d1c 100755
--- a/acme.sh
+++ b/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"
@@ -126,19 +126,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."
@@ -2019,7 +2019,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 +2040,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
}
@@ -2413,7 +2415,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"
@@ -3445,7 +3447,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."
@@ -3819,9 +3821,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 +4006,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"
@@ -4115,45 +4119,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,7 +4535,7 @@ $_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"
@@ -5568,7 +5586,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,7 +6216,7 @@ 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.
@@ -6207,8 +6225,8 @@ Parameters:
--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.
- --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 +6240,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 +6317,8 @@ _installOnline() {
chmod +x $PROJECT_ENTRY
if ./$PROJECT_ENTRY install "$_nocron" "" "$_noprofile"; then
_info "Install success!"
+ _initpath
+ _saveaccountconf "UPGRADE_HASH" "$(_getMasterHash)"
fi
cd ..
@@ -6308,9 +6328,19 @@ _installOnline() {
)
}
+_getMasterHash() {
+ _b="$BRANCH"
+ if [ -z "$_b" ]; then
+ _b="master"
+ fi
+ _hash_url="https://api.github.com/repos/acmesh-official/$PROJECT_NAME/git/refs/heads/$_b"
+ _get $_hash_url | tr -d "\r\n" | tr '{},' '\n' | grep '"sha":' | cut -d '"' -f 4
+}
+
upgrade() {
if (
_initpath
+ [ -z "$FORCE" ] && [ "$(_getMasterHash)" = "$(_readaccountconf "UPGRADE_HASH")" ] && _info "Already uptodate!" && exit 0
export LE_WORKING_DIR
cd "$LE_WORKING_DIR"
_installOnline "nocron" "noprofile"
diff --git a/deploy/README.md b/deploy/README.md
index fc633ad7..e3f239fa 100644
--- a/deploy/README.md
+++ b/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
diff --git a/deploy/docker.sh b/deploy/docker.sh
index 05333b3f..06d79855 100755
--- a/deploy/docker.sh
+++ b/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"
diff --git a/deploy/routeros.sh b/deploy/routeros.sh
index 70fe70a3..2f349999 100644
--- a/deploy/routeros.sh
+++ b/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
diff --git a/dnsapi/README.md b/dnsapi/README.md
index 08fff5bf..e81f7916 100644
--- a/dnsapi/README.md
+++ b/dnsapi/README.md
@@ -2,4 +2,5 @@
DNS api usage:
-https://github.com/Neilpang/acme.sh/wiki/dnsapi
+https://github.com/acmesh-official/acme.sh/wiki/dnsapi
+
diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh
index 6db87666..0503d0f2 100755
--- a/dnsapi/dns_aws.sh
+++ b/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 #####################
diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh
index 8b52dee7..bf7cf2bf 100644
--- a/dnsapi/dns_azure.sh
+++ b/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 #####################
diff --git a/dnsapi/dns_clouddns.sh b/dnsapi/dns_clouddns.sh
new file mode 100755
index 00000000..31ae4ee9
--- /dev/null
+++ b/dnsapi/dns_clouddns.sh
@@ -0,0 +1,197 @@
+#!/usr/bin/env sh
+
+# Author: Radek Sprta
+
+#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
+}
diff --git a/dnsapi/dns_constellix.sh b/dnsapi/dns_constellix.sh
new file mode 100644
index 00000000..c47ede44
--- /dev/null
+++ b/dnsapi/dns_constellix.sh
@@ -0,0 +1,141 @@
+#!/usr/bin/env sh
+
+# Author: Wout Decre
+
+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"; then
+ return 1
+ 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 '}')
+ 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
+}
diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh
index d7ad712c..8db3011d 100644
--- a/dnsapi/dns_cyon.sh
+++ b/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
#
diff --git a/dnsapi/dns_ddnss.sh b/dnsapi/dns_ddnss.sh
index 903b9619..53781d0d 100644
--- a/dnsapi/dns_ddnss.sh
+++ b/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 #####################
diff --git a/dnsapi/dns_dynv6.sh b/dnsapi/dns_dynv6.sh
new file mode 100644
index 00000000..cf39282b
--- /dev/null
+++ b/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
+}
diff --git a/dnsapi/dns_easydns.sh b/dnsapi/dns_easydns.sh
new file mode 100644
index 00000000..ca8faab2
--- /dev/null
+++ b/dnsapi/dns_easydns.sh
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+#######################################################
+#
+# easyDNS REST API for acme.sh by Neilpang based on dns_cf.sh
+#
+# Please note: # API is currently beta and subject to constant change
+# http://sandbox.rest.easydns.net:3000/
+#
+# Author: wurzelpanzer [wurzelpanzer@maximolider.net]
+# Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/2647
+#
+#################### Public functions #################
+
+#EASYDNS_Key="xxxxxxxxxxxxxxxxxxxxxxxx"
+#EASYDNS_Token="xxxxxxxxxxxxxxxxxxxxxxxx"
+EASYDNS_Api="https://rest.easydns.net"
+
+#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+dns_easydns_add() {
+ fulldomain=$1
+ txtvalue=$2
+
+ EASYDNS_Token="${EASYDNS_Token:-$(_readaccountconf_mutable EASYDNS_Token)}"
+ EASYDNS_Key="${EASYDNS_Key:-$(_readaccountconf_mutable EASYDNS_Key)}"
+
+ if [ -z "$EASYDNS_Token" ] || [ -z "$EASYDNS_Key" ]; then
+ _err "You didn't specify an easydns.net token or api key. Please sign up at http://docs.sandbox.rest.easydns.net/beta_signup.php"
+ return 1
+ else
+ _saveaccountconf_mutable EASYDNS_Token "$EASYDNS_Token"
+ _saveaccountconf_mutable EASYDNS_Key "$EASYDNS_Key"
+ fi
+
+ _debug "First detect the root zone"
+ if ! _get_root "$fulldomain"; then
+ _err "invalid domain"
+ return 1
+ fi
+ _debug _sub_domain "$_sub_domain"
+ _debug _domain "$_domain"
+
+ _debug "Getting txt records"
+ _EASYDNS_rest GET "zones/records/all/${_domain}/search/${_sub_domain}"
+
+ if ! printf "%s" "$response" | grep \"status\":200 >/dev/null; then
+ _err "Error"
+ return 1
+ fi
+
+ _info "Adding record"
+ if _EASYDNS_rest PUT "zones/records/add/$_domain/TXT" "{\"host\":\"$_sub_domain\",\"rdata\":\"$txtvalue\"}"; then
+ if _contains "$response" "\"status\":201"; then
+ _info "Added, OK"
+ return 0
+ elif _contains "$response" "Record already exists"; then
+ _info "Already exists, OK"
+ return 0
+ else
+ _err "Add txt record error."
+ return 1
+ fi
+ fi
+ _err "Add txt record error."
+ return 1
+
+}
+
+dns_easydns_rm() {
+ fulldomain=$1
+ txtvalue=$2
+
+ EASYDNS_Token="${EASYDNS_Token:-$(_readaccountconf_mutable EASYDNS_Token)}"
+ EASYDNS_Key="${EASYDNS_Key:-$(_readaccountconf_mutable EASYDNS_Key)}"
+
+ _debug "First detect the root zone"
+ if ! _get_root "$fulldomain"; then
+ _err "invalid domain"
+ return 1
+ fi
+ _debug _sub_domain "$_sub_domain"
+ _debug _domain "$_domain"
+
+ _debug "Getting txt records"
+ _EASYDNS_rest GET "zones/records/all/${_domain}/search/${_sub_domain}"
+
+ if ! printf "%s" "$response" | grep \"status\":200 >/dev/null; then
+ _err "Error"
+ return 1
+ fi
+
+ count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
+ _debug count "$count"
+ if [ "$count" = "0" ]; then
+ _info "Don't need to remove."
+ else
+ record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1)
+ _debug "record_id" "$record_id"
+ if [ -z "$record_id" ]; then
+ _err "Can not get record id to remove."
+ return 1
+ fi
+ if ! _EASYDNS_rest DELETE "zones/records/$_domain/$record_id"; then
+ _err "Delete record error."
+ return 1
+ fi
+ _contains "$response" "\"status\":200"
+ fi
+
+}
+
+#################### Private functions below ##################################
+#_acme-challenge.www.domain.com
+#returns
+# _sub_domain=_acme-challenge.www
+# _domain=domain.com
+_get_root() {
+ domain=$1
+ i=1
+ p=1
+ while true; do
+ h=$(printf "%s" "$domain" | cut -d . -f $i-100)
+ _debug h "$h"
+ if [ -z "$h" ]; then
+ #not valid
+ return 1
+ fi
+
+ if ! _EASYDNS_rest GET "zones/records/all/$h"; then
+ return 1
+ fi
+
+ if _contains "$response" "\"status\":200"; 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
+}
+
+_EASYDNS_rest() {
+ m=$1
+ ep="$2"
+ data="$3"
+ _debug "$ep"
+
+ basicauth=$(printf "%s" "$EASYDNS_Token":"$EASYDNS_Key" | _base64)
+
+ export _H1="accept: application/json"
+ if [ "$basicauth" ]; then
+ export _H2="Authorization: Basic $basicauth"
+ fi
+
+ if [ "$m" != "GET" ]; then
+ export _H3="Content-Type: application/json"
+ _debug data "$data"
+ response="$(_post "$data" "$EASYDNS_Api/$ep" "" "$m")"
+ else
+ response="$(_get "$EASYDNS_Api/$ep")"
+ fi
+
+ if [ "$?" != "0" ]; then
+ _err "error $ep"
+ return 1
+ fi
+ _debug2 response "$response"
+ return 0
+}
diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh
index 6a0b58ac..4a58931f 100755
--- a/dnsapi/dns_freedns.sh
+++ b/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 #####################
diff --git a/dnsapi/dns_gcloud.sh b/dnsapi/dns_gcloud.sh
index ebbeecf2..6365b338 100755
--- a/dnsapi/dns_gcloud.sh
+++ b/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)
diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh
index f6f54464..516b6eff 100755
--- a/dnsapi/dns_lexicon.sh
+++ b/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 #####################
diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh
index 23ff6cee..7e697704 100644
--- a/dnsapi/dns_miab.sh
+++ b/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 #####################
diff --git a/dnsapi/dns_misaka.sh b/dnsapi/dns_misaka.sh
new file mode 100755
index 00000000..eed4170e
--- /dev/null
+++ b/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
+}
diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh
index 2451d193..7f3c5a86 100755
--- a/dnsapi/dns_myapi.sh
+++ b/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() {
diff --git a/dnsapi/dns_nic.sh b/dnsapi/dns_nic.sh
index e3b39b0c..5052ee10 100644
--- a/dnsapi/dns_nic.sh
+++ b/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"
diff --git a/dnsapi/dns_openprovider.sh b/dnsapi/dns_openprovider.sh
index 1b1b760e..ad1e5838 100755
--- a/dnsapi/dns_openprovider.sh
+++ b/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"
diff --git a/dnsapi/dns_opnsense.sh b/dnsapi/dns_opnsense.sh
new file mode 100755
index 00000000..b2a3746f
--- /dev/null
+++ b/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
+}
diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh
index 65567efd..7c18d009 100755
--- a/dnsapi/dns_ovh.sh
+++ b/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"
diff --git a/dnsapi/dns_pleskxml.sh b/dnsapi/dns_pleskxml.sh
index c5d9e544..fe18bef4 100644
--- a/dnsapi/dns_pleskxml.sh
+++ b/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
diff --git a/dnsapi/dns_rackspace.sh b/dnsapi/dns_rackspace.sh
index 3939fd81..159671f9 100644
--- a/dnsapi/dns_rackspace.sh
+++ b/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"
diff --git a/dnsapi/dns_servercow.sh b/dnsapi/dns_servercow.sh
index be4e59da..e73d85b0 100755
--- a/dnsapi/dns_servercow.sh
+++ b/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
diff --git a/dnsapi/dns_zone.sh b/dnsapi/dns_zone.sh
index 847e32cd..176fc494 100755
--- a/dnsapi/dns_zone.sh
+++ b/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