From 52351d7dc8f0cccf3139e16ea56e5f1d001e6deb Mon Sep 17 00:00:00 2001 From: martgras Date: Tue, 13 Mar 2018 12:43:07 +0100 Subject: [PATCH 001/280] avoid side effects in _printargs A possible fix for https://github.com/Neilpang/acme.sh/issues/1356 --- acme.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/acme.sh b/acme.sh index 2a3138c..d3dea32 100755 --- a/acme.sh +++ b/acme.sh @@ -139,6 +139,7 @@ __red() { } _printargs() { + local _exitstatus="$?" if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then printf -- "%s" "[$(date)] " fi @@ -148,6 +149,8 @@ _printargs() { printf -- "%s" "$1='$2'" fi printf "\n" + # return the saved exit status + return "$_exitstatus" } _dlg_versions() { From 65a7d56957dd9fa9ffd7b341dd1ad4c3368ab2c9 Mon Sep 17 00:00:00 2001 From: martgras Date: Wed, 14 Mar 2018 09:52:58 +0100 Subject: [PATCH 002/280] remove local keyword --- acme.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d3dea32..88605b2 100755 --- a/acme.sh +++ b/acme.sh @@ -139,7 +139,7 @@ __red() { } _printargs() { - local _exitstatus="$?" + _exitstatus="$?" if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then printf -- "%s" "[$(date)] " fi @@ -186,6 +186,7 @@ _dlg_versions() { #class _syslog() { + _exitstatus="$?" if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" = "$SYSLOG_LEVEL_NONE" ]; then return fi @@ -199,6 +200,7 @@ _syslog() { fi fi $__logger_i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1 + return "$_exitstatus" } _log() { From cac3b3ea354a41fe047c9b07ffe77dd586d97b4f Mon Sep 17 00:00:00 2001 From: Ivar Larsson Date: Wed, 14 Mar 2018 12:32:02 -0400 Subject: [PATCH 003/280] add dns_loopia --- dnsapi/dns_loopia.sh | 227 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 dnsapi/dns_loopia.sh diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh new file mode 100644 index 0000000..7845db4 --- /dev/null +++ b/dnsapi/dns_loopia.sh @@ -0,0 +1,227 @@ +#!/usr/bin/env sh + +# +#LOOPIA_User="username" +# +#LOOPIA_Password="password" + +LOOPIA_Api="https://api.loopia.se/RPCSERV" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_loopia_add() { + fulldomain=$1 + txtvalue=$2 + + LOOPIA_User="${LOOPIA_User:-$(_readaccountconf_mutable LOOPIA_User)}" + LOOPIA_Password="${LOOPIA_Password:-$(_readaccountconf_mutable LOOPIA_Password)}" + if [ -z "$LOOPIA_User" ] || [ -z "$LOOPIA_Password" ]; then + LOOPIA_User="" + LOOPIA_Password="" + _err "You don't specify loopia user and password yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable LOOPIA_User "$LOOPIA_User" + _saveaccountconf_mutable LOOPIA_Password "$LOOPIA_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + + _loopia_add_record "$_domain" "$_sub_domain" + _loopia_update_record "$_domain" "$_sub_domain" "$txtvalue" + +} + +dns_loopia_rm() { + fulldomain=$1 + txtvalue=$2 + + LOOPIA_User="${LOOPIA_User:-$(_readaccountconf_mutable LOOPIA_User)}" + LOOPIA_Password="${LOOPIA_Password:-$(_readaccountconf_mutable LOOPIA_Password)}" + if [ -z "$LOOPIA_User" ] || [ -z "$LOOPIA_Password" ]; then + LOOPIA_User="" + LOOPIA_Password="" + _err "You don't specify LOOPIA user and password yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable LOOPIA_User "$LOOPIA_User" + _saveaccountconf_mutable LOOPIA_Password "$LOOPIA_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + xml_content=$(printf ' + + removeSubdomain + + + %s + + + %s + + + %s + + + %s + + + ' $LOOPIA_User $LOOPIA_Password "$_domain" "$_sub_domain") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + + if ! _contains "$response" "OK"; then + _err "Error could not get txt records" + return 1 + fi +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + _debug "get root" + + domain=$1 + i=2 + p=1 + + xml_content=$(printf ' + + getDomains + + + %s + + + %s + + + ' $LOOPIA_User $LOOPIA_Password) + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "$h"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 + +} + +_loopia_update_record() { + domain=$1 + sub_domain=$2 + txtval=$3 + + xml_content=$(printf ' + + updateZoneRecord + + + %s + + + %s + + + %s + + + %s + + + + + type + TXT + + + priority + 0 + + + ttl + 60 + + + rdata + %s + + + record_id + 0 + + + + + ' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain" "$txtval") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "OK" >/dev/null; then + _err "Error" + return 1 + fi + return 0 +} + +_loopia_add_record() { + domain=$1 + sub_domain=$2 + + xml_content=$(printf ' + + addSubdomain + + + %s + + + %s + + + %s + + + %s + + + ' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "OK" >/dev/null; then + _err "Error" + return 1 + fi + return 0 +} From 7a46293f7a54240a82dda4d0bb34106415944f33 Mon Sep 17 00:00:00 2001 From: Ivar Larsson Date: Thu, 15 Mar 2018 10:55:31 -0400 Subject: [PATCH 004/280] loopia documentation --- README.md | 1 + dnsapi/README.md | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/README.md b/README.md index 5471c57..20b306e 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,7 @@ You don't have to do anything manually! 1. zonomi.com DNS API 1. DreamHost.com API 1. DirectAdmin API +1. Loopia API And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 8b4a835..e2e9172 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -784,6 +784,28 @@ acme.sh --issue --dns dns_da -d example.com -d www.example.com The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 42. Use Loopia API +User must provide login credentials to the Loopia API. +The user needs the following permissions: + +- addSubdomain +- updateZoneRecord +- getDomains +- removeSubdomain + +Set the login credentials: +``` +export LOOPIA_User="user@loopiaapi" +export LOOPIA_Password="password" +``` + +And to issue a cert: +``` +acme.sh --issue --dns dns_loopia -d example.com -d *.example.com +``` + +The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API From 413f071861c6205fa5a9d783e50a56e35776be8b Mon Sep 17 00:00:00 2001 From: Ivar Larsson Date: Sun, 18 Mar 2018 10:00:10 -0400 Subject: [PATCH 005/280] use echo --- dnsapi/dns_loopia.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh index 7845db4..55b4f94 100644 --- a/dnsapi/dns_loopia.sh +++ b/dnsapi/dns_loopia.sh @@ -119,7 +119,7 @@ _get_root() { response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(echo "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then #not valid return 1 @@ -187,7 +187,7 @@ _loopia_update_record() { response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" - if ! printf "%s" "$response" | grep "OK" >/dev/null; then + if ! echo "$response" | grep "OK" >/dev/null; then _err "Error" return 1 fi @@ -219,7 +219,7 @@ _loopia_add_record() { response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" - if ! printf "%s" "$response" | grep "OK" >/dev/null; then + if ! echo "$response" | grep "OK" >/dev/null; then _err "Error" return 1 fi From ae329385316511db8a4f377f3c630b2ba31e01d7 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 19 Mar 2018 12:17:47 -0300 Subject: [PATCH 006/280] added dnsapi/dns_kinghost.sh --- dnsapi/dns_kinghost.sh | 110 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 dnsapi/dns_kinghost.sh diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh new file mode 100644 index 0000000..3697e4a --- /dev/null +++ b/dnsapi/dns_kinghost.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env sh + +#KINGHOST_username="xxxx@sss.com" +#KINGHOST_Password="sdfsdfsdfljlbjkljlkjsdfoiwje" + +KING_Api="https://api.kinghost.net/acme" + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_kinghost_add() { + fulldomain=$1 + txtvalue=$2 + + KINGHOST_username="${KINGHOST_username:-$(_readaccountconf_mutable KINGHOST_username)}" + KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" + if [ -z "$KINGHOST_username" ] || [ -z "$KINGHOST_Password" ]; then + KINGHOST_username="" + KINGHOST_Password="" + _err "You don't specify KingHost api password and email yet." + _err "Please create you key and try again." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable KINGHOST_username "$KINGHOST_username" + _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" + + _debug "Getting txt records" + _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + #This API call returns "status":"ok" if dns record does not exists + #We are creating a new txt record here, so we expect the "ok" status + if ! printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + _kinghost_rest POST "dns" "name=$fulldomain&content=$txtvalue" + if ! printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0; +} + +# Usage: fulldomain txtvalue +# Used to remove the txt record after validation +dns_kinghost_rm() { + fulldomain=$1 + txtvalue=$2 + + KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" + KINGHOST_username="${KINGHOST_username:-$(_readaccountconf_mutable KINGHOST_username)}" + if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_username" ]; then + KINGHOST_Password="" + KINGHOST_username="" + _err "You don't specify KingHost api key and email yet." + _err "Please create you key and try again." + return 1 + fi + + _debug "Getting txt records" + _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + #This API call returns "status":"ok" if dns record does not exists + #We are removing a txt record here, so the record must exists + if printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" + if ! printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0; +} + + +#################### Private functions below ################################## +_kinghost_rest() { + method=$1 + uri="$2" + data="$3" + _debug "$uri" + + export _H1="X-Auth-Email: $KINGHOST_username" + export _H2="X-Auth-Key: $KINGHOST_Password" + + if [ "$method" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$KING_Api/$uri.json" "" "$method")" + else + response="$(_get "$KING_Api/$uri.json?$data")" + fi + + if [ "$?" != "0" ]; then + _err "error $uri" + return 1 + fi + _debug2 response "$response" + return 0 +} From 2ff6f4d3cfe9494f552fdd0fd72e418a75ece7e5 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 19 Mar 2018 12:26:54 -0300 Subject: [PATCH 007/280] updated docs for dns_kinghost api usage --- README.md | 1 + dnsapi/README.md | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/README.md b/README.md index 5471c57..0faea3e 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,7 @@ You don't have to do anything manually! 1. zonomi.com DNS API 1. DreamHost.com API 1. DirectAdmin API +1. KingHost (https://www.kinghost.com.br/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 8b4a835..caae7cf 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -784,6 +784,17 @@ acme.sh --issue --dns dns_da -d example.com -d www.example.com The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 42. Use KingHost DNS API + +API access must be enabled at https://painel.kinghost.com.br/painel.api.php + +``` +export KINGHOST_username="yourusername" +export KINGHOST_Password="yourpassword" +acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com +``` + +The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. # Use custom API From 48bdfa23771393bfe62d858aacb1110ed1eb5639 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 19 Mar 2018 13:49:58 -0300 Subject: [PATCH 008/280] added doc header to dns_kinghost.sh --- dnsapi/dns_kinghost.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index 3697e4a..5d3a493 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -1,7 +1,16 @@ #!/usr/bin/env sh -#KINGHOST_username="xxxx@sss.com" -#KINGHOST_Password="sdfsdfsdfljlbjkljlkjsdfoiwje" +############################################################ +# KingHost API support # +# http://api.kinghost.net/doc/ # +# # +# Author: Felipe Keller Braz # +# Report Bugs here: https://github.com/kinghost/acme.sh # +# # +# Values to export: # +# export KINGHOST_username="email@provider.com" # +# export KINGHOST_Password="xxxxxxxxxx" # +############################################################ KING_Api="https://api.kinghost.net/acme" @@ -83,7 +92,6 @@ dns_kinghost_rm() { return 0; } - #################### Private functions below ################################## _kinghost_rest() { method=$1 From 6787c81abe86a8339d917069f74e2601b4f878ff Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Tue, 20 Mar 2018 09:58:10 -0300 Subject: [PATCH 009/280] renamed KINGHOST_username => KINGHOST_Username --- dnsapi/dns_kinghost.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index 5d3a493..fc436bb 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -8,7 +8,7 @@ # Report Bugs here: https://github.com/kinghost/acme.sh # # # # Values to export: # -# export KINGHOST_username="email@provider.com" # +# export KINGHOST_Username="email@provider.com" # # export KINGHOST_Password="xxxxxxxxxx" # ############################################################ @@ -20,10 +20,10 @@ dns_kinghost_add() { fulldomain=$1 txtvalue=$2 - KINGHOST_username="${KINGHOST_username:-$(_readaccountconf_mutable KINGHOST_username)}" + KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" - if [ -z "$KINGHOST_username" ] || [ -z "$KINGHOST_Password" ]; then - KINGHOST_username="" + if [ -z "$KINGHOST_Username" ] || [ -z "$KINGHOST_Password" ]; then + KINGHOST_Username="" KINGHOST_Password="" _err "You don't specify KingHost api password and email yet." _err "Please create you key and try again." @@ -31,7 +31,7 @@ dns_kinghost_add() { fi #save the credentials to the account conf file. - _saveaccountconf_mutable KINGHOST_username "$KINGHOST_username" + _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" _debug "Getting txt records" @@ -62,10 +62,10 @@ dns_kinghost_rm() { txtvalue=$2 KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" - KINGHOST_username="${KINGHOST_username:-$(_readaccountconf_mutable KINGHOST_username)}" - if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_username" ]; then + KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" + if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then KINGHOST_Password="" - KINGHOST_username="" + KINGHOST_Username="" _err "You don't specify KingHost api key and email yet." _err "Please create you key and try again." return 1 @@ -99,7 +99,7 @@ _kinghost_rest() { data="$3" _debug "$uri" - export _H1="X-Auth-Email: $KINGHOST_username" + export _H1="X-Auth-Email: $KINGHOST_Username" export _H2="X-Auth-Key: $KINGHOST_Password" if [ "$method" != "GET" ]; then From aa9975ad0d03d08a7cd7beaad60b4ff29adc3277 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Tue, 20 Mar 2018 10:08:52 -0300 Subject: [PATCH 010/280] dns_kinghost.sh :: changed printf to echo --- dnsapi/dns_kinghost.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index fc436bb..2dc57cb 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -39,14 +39,14 @@ dns_kinghost_add() { #This API call returns "status":"ok" if dns record does not exists #We are creating a new txt record here, so we expect the "ok" status - if ! printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then _err "Error" _err "$response" return 1 fi _kinghost_rest POST "dns" "name=$fulldomain&content=$txtvalue" - if ! printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then _err "Error" _err "$response" return 1 @@ -76,14 +76,14 @@ dns_kinghost_rm() { #This API call returns "status":"ok" if dns record does not exists #We are removing a txt record here, so the record must exists - if printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + if echo "$response" | grep '"status":"ok"' >/dev/null; then _err "Error" _err "$response" return 1 fi _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" - if ! printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then _err "Error" _err "$response" return 1 From 46ac97a3ff455b6c16b9fabfc4b42f331d9cc7ef Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 21 Mar 2018 20:57:48 +0800 Subject: [PATCH 011/280] update doc --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8a12d9f..6a26835 100644 --- a/README.md +++ b/README.md @@ -331,6 +331,8 @@ For more details: [How to use DNS API](dnsapi) # 8. Use DNS manual mode: +See: https://github.com/Neilpang/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. ```bash From 5f9b0675e2065e73c1bafafd13c833cbfcdc2c55 Mon Sep 17 00:00:00 2001 From: Ivar Larsson Date: Wed, 21 Mar 2018 11:18:26 -0400 Subject: [PATCH 012/280] loopia -> loopia.se --- README.md | 2 +- dnsapi/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 20b306e..c6ea993 100644 --- a/README.md +++ b/README.md @@ -313,7 +313,7 @@ You don't have to do anything manually! 1. zonomi.com DNS API 1. DreamHost.com API 1. DirectAdmin API -1. Loopia API +1. Loopia.se API And: diff --git a/dnsapi/README.md b/dnsapi/README.md index e2e9172..fe4a701 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -784,7 +784,7 @@ acme.sh --issue --dns dns_da -d example.com -d www.example.com The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 42. Use Loopia API +## 42. Use Loopia.se API User must provide login credentials to the Loopia API. The user needs the following permissions: From 8995d3434faec3779c2caf580e9d5f713381f2cf Mon Sep 17 00:00:00 2001 From: Ivar Larsson Date: Wed, 21 Mar 2018 11:19:22 -0400 Subject: [PATCH 013/280] _contains instead of echo --- dnsapi/dns_loopia.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh index 55b4f94..5d76118 100644 --- a/dnsapi/dns_loopia.sh +++ b/dnsapi/dns_loopia.sh @@ -187,7 +187,7 @@ _loopia_update_record() { response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" - if ! echo "$response" | grep "OK" >/dev/null; then + if ! _contains "$response" "OK"; then _err "Error" return 1 fi @@ -219,7 +219,7 @@ _loopia_add_record() { response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" - if ! echo "$response" | grep "OK" >/dev/null; then + if ! _contains "$response" "OK"; then _err "Error" return 1 fi From af5ff2bb93acaa14c29e7ef5291b682a341edca4 Mon Sep 17 00:00:00 2001 From: Nils Sandmann Date: Wed, 21 Mar 2018 16:43:42 +0100 Subject: [PATCH 014/280] Modified DNSAPI for PowerDNS to support wildcard certificates --- dnsapi/dns_pdns.sh | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 3d99e10..40b344c 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -88,9 +88,20 @@ set_record() { _info "Adding record" root=$1 full=$2 - txtvalue=$3 + new_challenge=$3 - if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then + _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones/$root" + _existing_challenges=($(echo "$response" | _normalizeJson | grep -Po "\"name\":\"$fulldomain\K.*?}]" | grep -Po 'content\":\"\\"\K[^\\]*')) + _record_string="" + _build_record_string $new_challenge + + for i in "${_existing_challenges[@]}" + do + _record_string+=", " + _build_record_string $i + done + + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}"; then _err "Set txt record error." return 1 fi @@ -185,3 +196,7 @@ _pdns_rest() { return 0 } + +_build_record_string() { + _record_string+="{\"content\": \"\\\"$1\\\"\", \"disabled\": false}" +} From 893917a25dac51a5e0354f8122c5043060ecd573 Mon Sep 17 00:00:00 2001 From: Nils Sandmann Date: Thu, 22 Mar 2018 11:13:46 +0100 Subject: [PATCH 015/280] Fix travis errors --- dnsapi/dns_pdns.sh | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 40b344c..594f9b2 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -91,14 +91,12 @@ set_record() { new_challenge=$3 _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones/$root" - _existing_challenges=($(echo "$response" | _normalizeJson | grep -Po "\"name\":\"$fulldomain\K.*?}]" | grep -Po 'content\":\"\\"\K[^\\]*')) _record_string="" - _build_record_string $new_challenge - - for i in "${_existing_challenges[@]}" - do - _record_string+=", " - _build_record_string $i + _build_record_string "$new_challenge" + _existing_challenges=$(echo "$response" | _normalizeJson | grep -Po "\"name\":\"$fulldomain\\K.*?}]" | grep -Po 'content\":\"\\"\K[^\\]*') + for oldchallenge in $_existing_challenges; do + _record_string="${_record_string}, " + _build_record_string "$oldchallenge" done if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}"; then @@ -106,10 +104,6 @@ set_record() { return 1 fi - if ! notify_slaves "$root"; then - return 1 - fi - return 0 } @@ -198,5 +192,5 @@ _pdns_rest() { } _build_record_string() { - _record_string+="{\"content\": \"\\\"$1\\\"\", \"disabled\": false}" + _record_string="${_record_string}{\"content\": \"\\\"$1\\\"\", \"disabled\": false}" } From fbd8ab47eab3b62515978e17bac8609336c32cd5 Mon Sep 17 00:00:00 2001 From: pyriand3r Date: Thu, 22 Mar 2018 11:23:16 +0100 Subject: [PATCH 016/280] only reseller can use do.de's reseller interface --- dnsapi/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 8b4a835..504a8b5 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -325,6 +325,8 @@ The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.s ## 17. Use Domain-Offensive/Resellerinterface/Domainrobot API +ATTENTION: You need to be a registered Reseller to be able to use the ResellerInterface. As a normal user you can not use this method. + You will need your login credentials (Partner ID+Password) to the Resellerinterface, and export them before you run `acme.sh`: ``` export DO_PID="KD-1234567" From 6b15cf3f722632bf183a2a2c081652dba531738b Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 22 Mar 2018 13:45:43 -0400 Subject: [PATCH 017/280] Remove template text --- deploy/keychain.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/deploy/keychain.sh b/deploy/keychain.sh index a99ed46..d86b4d0 100644 --- a/deploy/keychain.sh +++ b/deploy/keychain.sh @@ -1,11 +1,5 @@ #!/usr/bin/env sh -#Here is a sample custom api script. -#This file name is "myapi.sh" -#So, here must be a method myapi_deploy() -#Which will be called by acme.sh to deploy the cert -#returns 0 means success, otherwise error. - ######## Public functions ##################### #domain keyfile certfile cafile fullchain From ba9e7fbf64b907c4bd53864b6a938b885201e346 Mon Sep 17 00:00:00 2001 From: James Gibson Date: Thu, 22 Mar 2018 22:46:21 -0600 Subject: [PATCH 018/280] Clarified the language around the Name.com steps Name.com has simplified the process to obtain API tokens, this clarifies the language around requesting a key. --- dnsapi/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 8b4a835..ffd61dc 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -525,8 +525,9 @@ For issues, please report to https://github.com/raidenii/acme.sh/issues. ## 28. Use Name.com API -You'll need to fill out the form at https://www.name.com/reseller/apply to apply -for API username and token. +Create your API token here: https://www.name.com/account/settings/api + +Note: `Namecom_Username` should be your Name.com username and not the token name. If you accidentally run the script with the token name as the username see `~/.acme.sh/account.conf` to fix the issue ``` export Namecom_Username="testuser" From aad309ee4f41da300daf61ac303d4eb6fd3d6bca Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 24 Mar 2018 00:06:39 +0800 Subject: [PATCH 019/280] fix https://github.com/Neilpang/acme.sh/issues/1430 --- acme.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index c1298c4..da8e60c 100755 --- a/acme.sh +++ b/acme.sh @@ -1806,6 +1806,7 @@ _send_signed_request() { MAX_REQUEST_RETRY_TIMES=5 _request_retry_times=0 while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do + _request_retry_times=$(_math "$_request_retry_times" + 1) _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then _headers="" @@ -1836,7 +1837,11 @@ _send_signed_request() { fi nonce="$_CACHED_NONCE" _debug2 nonce "$nonce" - + if [ -z "$nonce" ]; then + _info "Could not get nonce, let's try again." + _sleep 2 + continue + fi if [ "$ACME_VERSION" = "2" ]; then if [ "$url" = "$ACME_NEW_ACCOUNT" ] || [ "$url" = "$ACME_REVOKE_CERT" ]; then protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' @@ -1894,7 +1899,6 @@ _send_signed_request() { if _contains "$_body" "JWS has invalid anti-replay nonce"; then _info "It seems the CA server is busy now, let's wait and retry." - _request_retry_times=$(_math "$_request_retry_times" + 1) _sleep 5 continue fi From 9c88971bc14314f061f17e71b292027586d0b63e Mon Sep 17 00:00:00 2001 From: James Gibson Date: Thu, 22 Mar 2018 23:09:38 -0600 Subject: [PATCH 020/280] Use internal base64 util instead of PATH bin/ --- dnsapi/dns_namecom.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index b712fa9..254952d 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -123,7 +123,7 @@ _namecom_login() { # Auth string # Name.com API v4 uses http basic auth to authenticate # need to convert the token for http auth - _namecom_auth=$(printf "%s:%s" "$Namecom_Username" "$Namecom_Token" | base64) + _namecom_auth=$(printf "%s:%s" "$Namecom_Username" "$Namecom_Token" | _base64) if _namecom_rest GET "hello"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"username\"\:\"$Namecom_Username\"") From a3f7ff90e300379c1acfbe5788d855a9584b82ae Mon Sep 17 00:00:00 2001 From: Nils Sandmann Date: Sat, 24 Mar 2018 18:46:04 +0100 Subject: [PATCH 021/280] Used e_grep_o instead grep -Po, dns_pdns_rm() now deletes only entry with matching txt value --- dnsapi/dns_pdns.sh | 58 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 594f9b2..8f07e8c 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -69,15 +69,21 @@ dns_pdns_add() { #fulldomain dns_pdns_rm() { fulldomain=$1 + txtvalue=$2 + + if [ -z "$PDNS_Ttl" ]; then + PDNS_Ttl="$DEFAULT_PDNS_TTL" + fi _debug "Detect root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi + _debug _domain "$_domain" - if ! rm_record "$_domain" "$fulldomain"; then + if ! rm_record "$_domain" "$fulldomain" "$txtvalue"; then return 1 fi @@ -90,12 +96,10 @@ set_record() { full=$2 new_challenge=$3 - _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones/$root" _record_string="" _build_record_string "$new_challenge" - _existing_challenges=$(echo "$response" | _normalizeJson | grep -Po "\"name\":\"$fulldomain\\K.*?}]" | grep -Po 'content\":\"\\"\K[^\\]*') + _list_existingchallenges for oldchallenge in $_existing_challenges; do - _record_string="${_record_string}, " _build_record_string "$oldchallenge" done @@ -104,6 +108,10 @@ set_record() { return 1 fi + if ! notify_slaves "$root"; then + return 1 + fi + return 0 } @@ -111,14 +119,37 @@ rm_record() { _info "Remove record" root=$1 full=$2 + txtvalue=$3 - if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then - _err "Delete txt record error." - return 1 - fi + #Enumerate existing acme challenges + _list_existingchallenges - if ! notify_slaves "$root"; then - return 1 + if _contains "$_existing_challenges" "$txtvalue"; then + #Delete all challenges (PowerDNS API does not allow to delete content) + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then + _err "Delete txt record error." + return 1 + fi + _record_string="" + #If the only existing challenge was the challenge to delete: nothing to do + if ! [ "$_existing_challenges" = "$txtvalue" ]; then + for oldchallenge in $_existing_challenges; do + #Build up the challenges to re-add, ommitting the one what should be deleted + if ! [ "$oldchallenge" = "$txtvalue" ]; then + _build_record_string "$oldchallenge" + fi + done + #Recreate the existing challenges + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}"; then + _err "Set txt record error." + return 1 + fi + fi + if ! notify_slaves "$root"; then + return 1 + fi + else + _info "Record not found, nothing to remove" fi return 0 @@ -192,5 +223,10 @@ _pdns_rest() { } _build_record_string() { - _record_string="${_record_string}{\"content\": \"\\\"$1\\\"\", \"disabled\": false}" + _record_string="${_record_string:+${_record_string}, }{\"content\": \"\\\"${1}\\\"\", \"disabled\": false}" +} + +_list_existingchallenges() { + _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones/$root" + _existing_challenges=$(echo "$response" | _normalizeJson | _egrep_o "\"name\":\"${fulldomain}[^]]*}" | _egrep_o 'content\":\"\\"[^\\]*' | sed -n 's/^content":"\\"//p') } From 5b355c6ca7d3b8c690d70567f08a6e347a7a5e47 Mon Sep 17 00:00:00 2001 From: Austin Drummond Date: Sat, 24 Mar 2018 18:57:22 -0400 Subject: [PATCH 022/280] Fixed Dreamhost ENV var name in dnsapi/README.md --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 8b4a835..c03e383 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -750,7 +750,7 @@ DNS API keys may be created at https://panel.dreamhost.com/?tree=home.api. Ensure the created key has add and remove privelages. ``` -export DH_API_Key="" +export DH_API_KEY="" acme.sh --issue --dns dns_dreamhost -d example.com -d www.example.com ``` From fe843bc466b3d3267ac0b1866bf3e3365663c505 Mon Sep 17 00:00:00 2001 From: martgras Date: Sun, 25 Mar 2018 14:32:51 +0200 Subject: [PATCH 023/280] dns_he - proposed fix for #1438 if you have more than one zone of a domain (e.g. example.com and subdomain.example.com) _find_zone fails. This fix removes partials matches. --- dnsapi/dns_he.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index f42d56a..d196fbe 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -143,7 +143,7 @@ _find_zone() { _debug "Looking for zone \"${_attempted_zone}\"" - line_num="$(echo "$_zone_names" | grep -n "$_attempted_zone" | cut -d : -f 1)" + line_num="$(echo "$_zone_names" | grep -n "^$_attempted_zone" | cut -d : -f 1)" if [ "$line_num" ]; then _zone_id=$(echo "$_zone_ids" | sed -n "${line_num}p") From 7588fc0989dcfb5f99da70a3ad70621b54cef533 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 26 Mar 2018 09:32:41 +0200 Subject: [PATCH 024/280] Fixes DNSimple for Wildcard certificates --- dnsapi/dns_dnsimple.sh | 55 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index 0bfe2b9..0a5b79b 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -39,7 +39,7 @@ dns_dnsimple_add() { _get_records "$_account_id" "$_domain" "$_sub_domain" - if [ "$_records_count" = "0" ]; then +# if [ "$_records_count" = "0" ]; then _info "Adding record" if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then @@ -51,22 +51,22 @@ dns_dnsimple_add() { fi fi _err "Add txt record error." - else - _info "Updating record" - _extract_record_id "$_records" "$_sub_domain" - - if _dnsimple_rest \ - PATCH \ - "$_account_id/zones/$_domain/records/$_record_id" \ - "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - - _info "Updated!" - return 0 - fi - - _err "Update error" - return 1 - fi +# else +# _info "Updating record" +# _extract_record_id "$_records" "$_sub_domain" + +# if _dnsimple_rest \ +# PATCH \ +# "$_account_id/zones/$_domain/records/$_record_id" \ +# "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then + +# _info "Updated!" +# return 0 +# fi + +# _err "Update error" +# return 1 +# fi } # fulldomain @@ -84,19 +84,20 @@ dns_dnsimple_rm() { fi _get_records "$_account_id" "$_domain" "$_sub_domain" - _extract_record_id "$_records" "$_sub_domain" + _extract_record_id "$_records" "$_sub_domain" if [ "$_record_id" ]; then - - if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id"; then - _info "removed record" "$_record_id" - return 0 - fi + echo "$_record_id" | while read -r item + do + if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$item"; then + _info "removed record" "$item" + return 0 + else + _err "failed to remove record" "$item" + return 1 + fi + done fi - - _err "failed to remove record" "$_record_id" - return 1 - } #################### Private functions bellow ################################## From 30283282d2f99afcfd39c45e4b3cdbaa0fef4035 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 26 Mar 2018 09:40:33 +0200 Subject: [PATCH 025/280] Fixing code style according to Travis --- dnsapi/dns_dnsimple.sh | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index 0a5b79b..0dd3918 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -39,34 +39,17 @@ dns_dnsimple_add() { _get_records "$_account_id" "$_domain" "$_sub_domain" -# if [ "$_records_count" = "0" ]; then - _info "Adding record" - if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then - _info "Added" - return 0 - else - _err "Unexpected response while adding text record." - return 1 - fi + _info "Adding record" + if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then + _info "Added" + return 0 + else + _err "Unexpected response while adding text record." + return 1 fi - _err "Add txt record error." -# else -# _info "Updating record" -# _extract_record_id "$_records" "$_sub_domain" - -# if _dnsimple_rest \ -# PATCH \ -# "$_account_id/zones/$_domain/records/$_record_id" \ -# "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - -# _info "Updated!" -# return 0 -# fi - -# _err "Update error" -# return 1 -# fi + fi + _err "Add txt record error." } # fulldomain @@ -87,8 +70,7 @@ dns_dnsimple_rm() { _extract_record_id "$_records" "$_sub_domain" if [ "$_record_id" ]; then - echo "$_record_id" | while read -r item - do + echo "$_record_id" | while read -r item; do if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$item"; then _info "removed record" "$item" return 0 From 4d2a0697edfbded749df960e0cbb8a770794bcfc Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 10:49:34 -0300 Subject: [PATCH 026/280] fix identation dnsapi/dns_kinghost.sh --- .gitignore | 2 + dnsapi/dns_kinghost.sh | 136 ++++++++++++++++++++--------------------- 2 files changed, 70 insertions(+), 68 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a13ea46 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +ae.sh diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index 2dc57cb..ddf9f89 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -17,79 +17,79 @@ KING_Api="https://api.kinghost.net/acme" # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" # Used to add txt record dns_kinghost_add() { - fulldomain=$1 - txtvalue=$2 - - KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" - KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" - if [ -z "$KINGHOST_Username" ] || [ -z "$KINGHOST_Password" ]; then - KINGHOST_Username="" - KINGHOST_Password="" - _err "You don't specify KingHost api password and email yet." - _err "Please create you key and try again." - return 1 - fi - - #save the credentials to the account conf file. - _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" - _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" - - _debug "Getting txt records" - _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" - - #This API call returns "status":"ok" if dns record does not exists - #We are creating a new txt record here, so we expect the "ok" status - if ! echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - _kinghost_rest POST "dns" "name=$fulldomain&content=$txtvalue" - if ! echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - return 0; + fulldomain=$1 + txtvalue=$2 + + KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" + KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" + if [ -z "$KINGHOST_Username" ] || [ -z "$KINGHOST_Password" ]; then + KINGHOST_Username="" + KINGHOST_Password="" + _err "You don't specify KingHost api password and email yet." + _err "Please create you key and try again." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" + _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" + + _debug "Getting txt records" + _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + #This API call returns "status":"ok" if dns record does not exists + #We are creating a new txt record here, so we expect the "ok" status + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + _kinghost_rest POST "dns" "name=$fulldomain&content=$txtvalue" + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0; } # Usage: fulldomain txtvalue # Used to remove the txt record after validation dns_kinghost_rm() { - fulldomain=$1 - txtvalue=$2 - - KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" - KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" - if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then - KINGHOST_Password="" - KINGHOST_Username="" - _err "You don't specify KingHost api key and email yet." - _err "Please create you key and try again." - return 1 - fi - - _debug "Getting txt records" - _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" - - #This API call returns "status":"ok" if dns record does not exists - #We are removing a txt record here, so the record must exists - if echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" - if ! echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - return 0; + fulldomain=$1 + txtvalue=$2 + + KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" + KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" + if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then + KINGHOST_Password="" + KINGHOST_Username="" + _err "You don't specify KingHost api key and email yet." + _err "Please create you key and try again." + return 1 + fi + + _debug "Getting txt records" + _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + #This API call returns "status":"ok" if dns record does not exists + #We are removing a txt record here, so the record must exists + if echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0; } #################### Private functions below ################################## From 7efa54666559b797d38a676f3d8ac9d1a7e61b09 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 10:58:22 -0300 Subject: [PATCH 027/280] removed local .gitignore file --- .gitignore | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index a13ea46..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea -ae.sh From e8fd373e6c68a7044a90b82690b917c1b9ce530e Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 10:58:56 -0300 Subject: [PATCH 028/280] removed blank space at ending of dnsapi/dns_kinghost.sh --- dnsapi/dns_kinghost.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index ddf9f89..d3a8fb3 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -115,4 +115,4 @@ _kinghost_rest() { fi _debug2 response "$response" return 0 -} +} \ No newline at end of file From 86ef6e6987d6f8413f0f9184d008a6a5ea7e62b5 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 11:21:12 -0300 Subject: [PATCH 029/280] fixes on dnsapi/dns_kinghost.sh and dnsapi/README.md --- dnsapi/README.md | 2 +- dnsapi/dns_kinghost.sh | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index f99671e..e459094 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -792,7 +792,7 @@ The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` an API access must be enabled at https://painel.kinghost.com.br/painel.api.php ``` -export KINGHOST_username="yourusername" +export KINGHOST_Username="yourusername" export KINGHOST_Password="yourpassword" acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com ``` diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index d3a8fb3..7c0d159 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -31,8 +31,8 @@ dns_kinghost_add() { fi #save the credentials to the account conf file. - _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" - _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" + _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" + _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" _debug "Getting txt records" _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" @@ -52,7 +52,7 @@ dns_kinghost_add() { return 1 fi - return 0; + return 0 } # Usage: fulldomain txtvalue @@ -63,7 +63,7 @@ dns_kinghost_rm() { KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" - if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then + if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then KINGHOST_Password="" KINGHOST_Username="" _err "You don't specify KingHost api key and email yet." @@ -89,7 +89,7 @@ dns_kinghost_rm() { return 1 fi - return 0; + return 0 } #################### Private functions below ################################## @@ -115,4 +115,4 @@ _kinghost_rest() { fi _debug2 response "$response" return 0 -} \ No newline at end of file +} From f8fb0e67b458821a913e981111b26196001e3a61 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 12:17:10 -0300 Subject: [PATCH 030/280] fix dnsapi/dns_kinghost.sh with shfmt utility --- dnsapi/dns_kinghost.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index 7c0d159..2ac8e6d 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -31,8 +31,8 @@ dns_kinghost_add() { fi #save the credentials to the account conf file. - _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" - _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" + _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" + _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" _debug "Getting txt records" _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" From 9e3c931b34a438c78e03ab69206722330ec28297 Mon Sep 17 00:00:00 2001 From: martgras Date: Sun, 25 Mar 2018 17:47:56 +0200 Subject: [PATCH 031/280] dns_azure add support for validation record at domain apex Prevent the issue described in #1442 Fix [SC1117] Backslash is literal in "\[". --- dnsapi/dns_azure.sh | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index e0d9516..c6893a0 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -76,10 +76,10 @@ dns_azure_add() { values="{\"value\":[\"$txtvalue\"]}" timestamp="$(_time)" if [ "$_code" = "200" ]; then - vlist="$(echo "$response" | _egrep_o "\"value\"\s*:\s*\[\s*\"[^\"]*\"\s*]" | cut -d : -f 2 | tr -d "[]\"")" + vlist="$(echo "$response" | _egrep_o "\"value\"\\s*:\\s*\\[\\s*\"[^\"]*\"\\s*]" | cut -d : -f 2 | tr -d "[]\"")" _debug "existing TXT found" _debug "$vlist" - existingts="$(echo "$response" | _egrep_o "\"acmetscheck\"\s*:\s*\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d "\"")" + existingts="$(echo "$response" | _egrep_o "\"acmetscheck\"\\s*:\\s*\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d "\"")" if [ -z "$existingts" ]; then # the record was not created by acme.sh. Copy the exisiting entires existingts=$timestamp @@ -172,7 +172,7 @@ dns_azure_rm() { _azure_rest GET "$acmeRecordURI" "" "$accesstoken" timestamp="$(_time)" if [ "$_code" = "200" ]; then - vlist="$(echo "$response" | _egrep_o "\"value\"\s*:\s*\[\s*\"[^\"]*\"\s*]" | cut -d : -f 2 | tr -d "[]\"" | grep -v "$txtvalue")" + vlist="$(echo "$response" | _egrep_o "\"value\"\\s*:\\s*\\[\\s*\"[^\"]*\"\\s*]" | cut -d : -f 2 | tr -d "[]\"" | grep -v "$txtvalue")" values="" comma="" for v in $vlist; do @@ -230,7 +230,7 @@ _azure_rest() { fi _ret="$?" _secure_debug2 "response $response" - _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" _debug "http response code $_code" if [ "$_code" = "401" ]; then # we have an invalid access token set to expired @@ -308,7 +308,7 @@ _get_root() { domain=$1 subscriptionId=$2 accesstoken=$3 - i=2 + i=1 p=1 ## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list @@ -328,9 +328,14 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\"" >/dev/null; then - _domain_id=$(echo "$response" | _egrep_o "\{\"id\":\"[^\"]*$h\"" | head -n 1 | cut -d : -f 2 | tr -d \") + _domain_id=$(echo "$response" | _egrep_o "\\{\"id\":\"[^\"]*$h\"" | head -n 1 | cut -d : -f 2 | tr -d \") if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + if [ "$i" = 1 ]; then + #create the record at the domain apex (@) if only the domain name was provided as --domain-alias + _sub_domain="@" + else + _sub_domain=$(echo "$domain" | cut -d . -f 1-$p) + fi _domain=$h return 0 fi From 37bc099d393f661bce904097be027e4ccef87a9a Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 14:27:21 -0300 Subject: [PATCH 032/280] removed redundant api call --- dnsapi/dns_infraws.sh | 102 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 dnsapi/dns_infraws.sh diff --git a/dnsapi/dns_infraws.sh b/dnsapi/dns_infraws.sh new file mode 100644 index 0000000..30abcbf --- /dev/null +++ b/dnsapi/dns_infraws.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env sh + +############################################################ +# Plugin para criação automática da entrada de DNS txt # +# Uso com o sistema acme.sh # +# # +# Author: Felipe Keller Braz # +# Report Bugs here: infra_interno@kinghost.com.br # +# # +# Values to export: # +# export INFRAWS_Hash="PASSWORD" # +############################################################ + +INFRAWS_Api="http://infra-ws.kinghost.net/serverbackend/acme" + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_infraws_add() { + fulldomain=$1 + txtvalue=$2 + + INFRAWS_Hash="${INFRAWS_Hash:-$(_readaccountconf_mutable INFRAWS_Hash)}" + + if [ -z "$INFRAWS_Hash" ]; then + INFRAWS_Hash="" + _err "You don't specify KingHost api password and email yet." + _err "Please create you key and try again." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable INFRAWS_Hash "$INFRAWS_Hash" + + _debug "Getting txt records" + infraws_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + #This API call returns "status":"ok" if dns record does not exists + #We are creating a new txt record here, so we expect the "ok" status + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + infraws_rest POST "dns" "name=$fulldomain&content=$txtvalue" + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0 +} + +# Usage: fulldomain txtvalue +# Used to remove the txt record after validation +dns_infraws_rm() { + fulldomain=$1 + txtvalue=$2 + + INFRAWS_Hash="${INFRAWS_Hash:-$(_readaccountconf_mutable INFRAWS_Hash)}" + if [ -z "$INFRAWS_Hash" ]; then + INFRAWS_Hash="" + _err "You don't specify KingHost api key and email yet." + _err "Please create you key and try again." + return 1 + fi + + _debug "Getting txt records" + infraws_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + infraws_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0 +} + +#################### Private functions below ################################## +infraws_rest() { + method=$1 + uri="$2" + data="$3" + _debug "$uri" + + if [ "$method" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$INFRAWS_Api/hash/$INFRAWS_Hash/" "" "$method")" + else + response="$(_get "$INFRAWS_Api/hash/$INFRAWS_Hash/?$data")" + fi + + if [ "$?" != "0" ]; then + _err "error $uri" + return 1 + fi + _debug2 response "$response" + return 0 +} From 2d1d512d0f968f0bdbca36aafdd043ec427a7bed Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 14:28:52 -0300 Subject: [PATCH 033/280] removed redundant api call --- dnsapi/dns_kinghost.sh | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index 2ac8e6d..898ab28 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -71,17 +71,6 @@ dns_kinghost_rm() { return 1 fi - _debug "Getting txt records" - _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" - - #This API call returns "status":"ok" if dns record does not exists - #We are removing a txt record here, so the record must exists - if echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" if ! echo "$response" | grep '"status":"ok"' >/dev/null; then _err "Error" From 914808b867dd57c485edaab9a43358ac0716d41a Mon Sep 17 00:00:00 2001 From: Habetdin Date: Tue, 27 Mar 2018 06:16:39 +0300 Subject: [PATCH 034/280] Adding Zilore API support --- dnsapi/dns_zilore.sh | 139 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 dnsapi/dns_zilore.sh diff --git a/dnsapi/dns_zilore.sh b/dnsapi/dns_zilore.sh new file mode 100644 index 0000000..4365004 --- /dev/null +++ b/dnsapi/dns_zilore.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env sh + +Zilore_API="https://api.zilore.com/dns/v1" +# Zilore_Key="YOUR-ZILORE-API-KEY" + +######## Public functions ##################### + +dns_zilore_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Using Zilore" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + Zilore_Key="${Zilore_Key:-$(_readaccountconf_mutable Zilore_Key)}" + if [ -z "$Zilore_Key" ]; then + Zilore_Key="" + _err "Please define Zilore API key" + return 1 + fi + _saveaccountconf_mutable Zilore_Key "$Zilore_Key" + + if ! _get_root "$fulldomain"; then + _err "Unable to determine root domain" + return 1 + else + _debug _domain "$_domain" + fi + + if _zilore_rest POST "domains/$_domain/records?record_type=TXT&record_ttl=600&record_name=$fulldomain&record_value=\"$txtvalue\""; then + if _contains "$response" '"added"' >/dev/null; then + _info "Added TXT record, waiting for validation" + return 0 + else + _debug response "$response" + _err "Error while adding DNS records" + return 1 + fi + fi + + return 1 +} + +dns_zilore_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Using Zilore" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + Zilore_Key="${Zilore_Key:-$(_readaccountconf_mutable Zilore_Key)}" + if [ -z "$Zilore_Key" ]; then + Zilore_Key="" + _err "Please define Zilore API key" + return 1 + fi + _saveaccountconf_mutable Zilore_Key "$Zilore_Key" + + if ! _get_root "$fulldomain"; then + _err "Unable to determine root domain" + return 1 + else + _debug _domain "$_domain" + fi + + _debug "Getting TXT records" + _zilore_rest GET "domains/${_domain}/records?search_text=$txtvalue&search_record_type=TXT" + _debug response "$response" + + if ! _contains "$response" '"ok"' >/dev/null; then + _err "Error while getting records list" + return 1 + else + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[^\"]+\"" | cut -d : -f 2 | tr -d \" | head -n 1) + if [ -z "$_record_id" ]; then + _err "Cannot determine _record_id" + return 1 + else + _debug _record_id "$_record_id" + fi + if ! _zilore_rest DELETE "domains/${_domain}/records?record_id=$_record_id"; then + _err "Error while deleting chosen record" + return 1 + fi + _contains "$response" '"ok"' + fi +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + i=2 + 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 ! _zilore_rest GET "domains?search_text=$h"; then + return 1 + fi + + if _contains "$response" "\"$h\"" >/dev/null; then + _domain=$h + return 0 + else + _debug "$h not found" + fi + i=$(_math "$i" + 1) + done + return 1 +} + +_zilore_rest() { + method=$1 + param=$2 + data=$3 + + export _H1="X-Auth-Key: $Zilore_Key" + + if [ "$method" != "GET" ]; then + response="$(_post "$data" "$Zilore_API/$param" "" "$method")" + else + response="$(_get "$Zilore_API/$param")" + fi + + if [ "$?" != "0" ]; then + _err "error $param" + return 1 + fi + + _debug2 response "$response" + return 0 +} From 6b0333e919e5d7eee10f7a0c3156b44bd81d7fcb Mon Sep 17 00:00:00 2001 From: Habetdin Date: Tue, 27 Mar 2018 06:21:10 +0300 Subject: [PATCH 035/280] Update README #1 --- dnsapi/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index f3edfb6..9df2d01 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -787,6 +787,20 @@ acme.sh --issue --dns dns_da -d example.com -d www.example.com The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 42. Use Zilore API to automatically issue cert + +First you need to login to your Zilore account to get your API key. + +``` +export Zilore_Key="5dcad3a2-36cb-50e8-cb92-000002f9" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_zilore -d example.com -d www.example.com +``` + +The `Zilore_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. # Use custom API From 882e1db1d61d129fa5354a7eeb4d70c77049fff0 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Tue, 27 Mar 2018 06:23:15 +0300 Subject: [PATCH 036/280] Update README #2 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6a26835..8d43729 100644 --- a/README.md +++ b/README.md @@ -315,6 +315,7 @@ You don't have to do anything manually! 1. zonomi.com DNS API 1. DreamHost.com API 1. DirectAdmin API +1. Zilore API And: From fde971fe81b5c64d724c1453a74d4023b3f13fb1 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Tue, 27 Mar 2018 06:31:25 +0300 Subject: [PATCH 037/280] Fix formatting --- dnsapi/dns_zilore.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_zilore.sh b/dnsapi/dns_zilore.sh index 4365004..6969944 100644 --- a/dnsapi/dns_zilore.sh +++ b/dnsapi/dns_zilore.sh @@ -106,7 +106,7 @@ _get_root() { fi if _contains "$response" "\"$h\"" >/dev/null; then - _domain=$h + _domain=$h return 0 else _debug "$h not found" From 986f61ac92bcb38b95d7eaff3612d8fb1ec6a5eb Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Wed, 28 Mar 2018 10:18:43 -0300 Subject: [PATCH 038/280] deleted wrog file --- dnsapi/dns_infraws.sh | 102 ------------------------------------------ 1 file changed, 102 deletions(-) delete mode 100644 dnsapi/dns_infraws.sh diff --git a/dnsapi/dns_infraws.sh b/dnsapi/dns_infraws.sh deleted file mode 100644 index 30abcbf..0000000 --- a/dnsapi/dns_infraws.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env sh - -############################################################ -# Plugin para criação automática da entrada de DNS txt # -# Uso com o sistema acme.sh # -# # -# Author: Felipe Keller Braz # -# Report Bugs here: infra_interno@kinghost.com.br # -# # -# Values to export: # -# export INFRAWS_Hash="PASSWORD" # -############################################################ - -INFRAWS_Api="http://infra-ws.kinghost.net/serverbackend/acme" - -# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -# Used to add txt record -dns_infraws_add() { - fulldomain=$1 - txtvalue=$2 - - INFRAWS_Hash="${INFRAWS_Hash:-$(_readaccountconf_mutable INFRAWS_Hash)}" - - if [ -z "$INFRAWS_Hash" ]; then - INFRAWS_Hash="" - _err "You don't specify KingHost api password and email yet." - _err "Please create you key and try again." - return 1 - fi - - #save the credentials to the account conf file. - _saveaccountconf_mutable INFRAWS_Hash "$INFRAWS_Hash" - - _debug "Getting txt records" - infraws_rest GET "dns" "name=$fulldomain&content=$txtvalue" - - #This API call returns "status":"ok" if dns record does not exists - #We are creating a new txt record here, so we expect the "ok" status - if ! echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - infraws_rest POST "dns" "name=$fulldomain&content=$txtvalue" - if ! echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - return 0 -} - -# Usage: fulldomain txtvalue -# Used to remove the txt record after validation -dns_infraws_rm() { - fulldomain=$1 - txtvalue=$2 - - INFRAWS_Hash="${INFRAWS_Hash:-$(_readaccountconf_mutable INFRAWS_Hash)}" - if [ -z "$INFRAWS_Hash" ]; then - INFRAWS_Hash="" - _err "You don't specify KingHost api key and email yet." - _err "Please create you key and try again." - return 1 - fi - - _debug "Getting txt records" - infraws_rest GET "dns" "name=$fulldomain&content=$txtvalue" - - infraws_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" - if ! echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - return 0 -} - -#################### Private functions below ################################## -infraws_rest() { - method=$1 - uri="$2" - data="$3" - _debug "$uri" - - if [ "$method" != "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$INFRAWS_Api/hash/$INFRAWS_Hash/" "" "$method")" - else - response="$(_get "$INFRAWS_Api/hash/$INFRAWS_Hash/?$data")" - fi - - if [ "$?" != "0" ]; then - _err "error $uri" - return 1 - fi - _debug2 response "$response" - return 0 -} From b14ef537e13096d5565d71243b9c7f7976efa76f Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:14:45 +0300 Subject: [PATCH 039/280] head => _head_n --- dnsapi/dns_zilore.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_zilore.sh b/dnsapi/dns_zilore.sh index 6969944..4211102 100644 --- a/dnsapi/dns_zilore.sh +++ b/dnsapi/dns_zilore.sh @@ -73,7 +73,7 @@ dns_zilore_rm() { _err "Error while getting records list" return 1 else - _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[^\"]+\"" | cut -d : -f 2 | tr -d \" | head -n 1) + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[^\"]+\"" | cut -d : -f 2 | tr -d \" | _head_n 1) if [ -z "$_record_id" ]; then _err "Cannot determine _record_id" return 1 From b4f4c28871debcc627d1fc5225fbb34d0a1451e1 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:17:22 +0300 Subject: [PATCH 040/280] Update README.md --- dnsapi/README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 9df2d01..1029526 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -787,7 +787,19 @@ acme.sh --issue --dns dns_da -d example.com -d www.example.com The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 42. Use Zilore API to automatically issue cert +## 42. Use KingHost DNS API + +API access must be enabled at https://painel.kinghost.com.br/painel.api.php + +``` +export KINGHOST_Username="yourusername" +export KINGHOST_Password="yourpassword" +acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com +``` + +The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +## 43. Use Zilore DNS API First you need to login to your Zilore account to get your API key. From 2bc38b206364d6b00e72cd217ddc933f2b1dbd4e Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:22:33 +0300 Subject: [PATCH 041/280] Revert "Update README.md" This reverts commit b4f4c28871debcc627d1fc5225fbb34d0a1451e1. --- dnsapi/README.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 1029526..9df2d01 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -787,19 +787,7 @@ acme.sh --issue --dns dns_da -d example.com -d www.example.com The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 42. Use KingHost DNS API - -API access must be enabled at https://painel.kinghost.com.br/painel.api.php - -``` -export KINGHOST_Username="yourusername" -export KINGHOST_Password="yourpassword" -acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com -``` - -The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 43. Use Zilore DNS API +## 42. Use Zilore API to automatically issue cert First you need to login to your Zilore account to get your API key. From ce9f77afed08f5a1136d903d87a434329a1d44e5 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:22:36 +0300 Subject: [PATCH 042/280] Revert "Update README #2" This reverts commit 882e1db1d61d129fa5354a7eeb4d70c77049fff0. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 8d43729..6a26835 100644 --- a/README.md +++ b/README.md @@ -315,7 +315,6 @@ You don't have to do anything manually! 1. zonomi.com DNS API 1. DreamHost.com API 1. DirectAdmin API -1. Zilore API And: From e32c2b84ee941fbefd74ddc735c14dd5533e5579 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:22:38 +0300 Subject: [PATCH 043/280] Revert "Update README #1" This reverts commit 6b0333e919e5d7eee10f7a0c3156b44bd81d7fcb. --- dnsapi/README.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 9df2d01..f3edfb6 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -787,20 +787,6 @@ acme.sh --issue --dns dns_da -d example.com -d www.example.com The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 42. Use Zilore API to automatically issue cert - -First you need to login to your Zilore account to get your API key. - -``` -export Zilore_Key="5dcad3a2-36cb-50e8-cb92-000002f9" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_zilore -d example.com -d www.example.com -``` - -The `Zilore_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. # Use custom API From ce9c22742503efed89dfa4300c7d72739fe9aaf9 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:25:52 +0300 Subject: [PATCH 044/280] Update README.md --- dnsapi/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index e459094..1029526 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -799,6 +799,21 @@ acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 43. Use Zilore DNS API + +First you need to login to your Zilore account to get your API key. + +``` +export Zilore_Key="5dcad3a2-36cb-50e8-cb92-000002f9" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_zilore -d example.com -d www.example.com +``` + +The `Zilore_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. From 8f5ee989baa03579a98c9434762bd2376263136b Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:26:34 +0300 Subject: [PATCH 045/280] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4c46c92..b5d5aff 100644 --- a/README.md +++ b/README.md @@ -316,6 +316,7 @@ You don't have to do anything manually! 1. DreamHost.com API 1. DirectAdmin API 1. KingHost (https://www.kinghost.com.br/) +1. Zilore (https://zilore.com) And: From 87a8dda95525eddcbac441d8944a94e63401d48d Mon Sep 17 00:00:00 2001 From: Bob Belnap Date: Wed, 28 Mar 2018 12:40:31 -0400 Subject: [PATCH 046/280] add chain cert --- deploy/vault_cli.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/vault_cli.sh b/deploy/vault_cli.sh index 02617c5..79c25aa 100644 --- a/deploy/vault_cli.sh +++ b/deploy/vault_cli.sh @@ -51,6 +51,7 @@ vault_cli_deploy() { $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1 $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1 + $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1 $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1 } From 696d9c6bd38a0424cbadd8985947fd14a38c4a66 Mon Sep 17 00:00:00 2001 From: Ivar Larsson Date: Wed, 28 Mar 2018 17:15:31 -0400 Subject: [PATCH 047/280] remove merge chars --- dnsapi/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 58ebecb..af0542d 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -821,8 +821,6 @@ acme.sh --issue --dns dns_loopia -d example.com -d *.example.com The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -======= - # Use custom API If your API is not supported yet, you can write your own DNS API. From 98e15f658ef14c68c040766e4bb8c979ae5703a7 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Thu, 29 Mar 2018 04:31:46 +0300 Subject: [PATCH 048/280] Update Zilore API description --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 1029526..ba1c045 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -801,7 +801,7 @@ The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/acc ## 43. Use Zilore DNS API -First you need to login to your Zilore account to get your API key. +First, get your API key at https://my.zilore.com/account/api ``` export Zilore_Key="5dcad3a2-36cb-50e8-cb92-000002f9" @@ -809,7 +809,7 @@ export Zilore_Key="5dcad3a2-36cb-50e8-cb92-000002f9" Ok, let's issue a cert now: ``` -acme.sh --issue --dns dns_zilore -d example.com -d www.example.com +acme.sh --issue --dns dns_zilore -d example.com -d *.example.com ``` The `Zilore_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. From 09304c33c12277e85bf4229b0e0ec883beb182f6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 29 Mar 2018 21:51:33 +0800 Subject: [PATCH 049/280] start 2.7.9 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index da8e60c..a5e4b39 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.8 +VER=2.7.9 PROJECT_NAME="acme.sh" From 499f745732863a210c66ee242f3ee26c142fc185 Mon Sep 17 00:00:00 2001 From: pandiloko <1jasotel@gmail.com> Date: Sun, 1 Apr 2018 14:41:35 +0200 Subject: [PATCH 050/280] False case in variable name for dreamhost api --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index ba1c045..045ed0e 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -753,7 +753,7 @@ DNS API keys may be created at https://panel.dreamhost.com/?tree=home.api. Ensure the created key has add and remove privelages. ``` -export DH_API_Key="" +export DH_API_KEY="" acme.sh --issue --dns dns_dreamhost -d example.com -d www.example.com ``` From 792f3775ce464f4f7a9066bfe8e28ca33a394a55 Mon Sep 17 00:00:00 2001 From: martgras <25747549+martgras@users.noreply.github.com> Date: Mon, 2 Apr 2018 18:26:50 +0200 Subject: [PATCH 051/280] Fixes dns_he Issue #1476 username / password has to be urlencoded --- dnsapi/dns_he.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index d196fbe..da4a1b8 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -33,8 +33,9 @@ dns_he_add() { # Fills in the $_zone_id _find_zone "$_full_domain" || return 1 _debug "Zone id \"$_zone_id\" will be used." - - body="email=${HE_Username}&pass=${HE_Password}" + username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)" + body="email=${username_encoded}&pass=${password_encoded}" body="$body&account=" body="$body&menu=edit_zone" body="$body&Type=TXT" @@ -71,7 +72,9 @@ dns_he_rm() { _debug "Zone id \"$_zone_id\" will be used." # Find the record id to clean - body="email=${HE_Username}&pass=${HE_Password}" + username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)" + body="email=${username_encoded}&pass=${password_encoded}" body="$body&hosted_dns_zoneid=$_zone_id" body="$body&menu=edit_zone" body="$body&hosted_dns_editzone=" @@ -112,9 +115,15 @@ dns_he_rm() { _find_zone() { _domain="$1" - body="email=${HE_Username}&pass=${HE_Password}" + username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)" + body="email=${username_encoded}&pass=${password_encoded}" response="$(_post "$body" "https://dns.he.net/")" _debug2 response "$response" + if _contains "$response" '>Incorrect<'; then + _err "Unable to login to dns.he.net please check username and password" + return 1 + fi _table="$(echo "$response" | tr -d "#" | sed "s/ Date: Fri, 16 Mar 2018 11:20:18 +0100 Subject: [PATCH 052/280] add acme-dns plugin --- README.md | 1 + dnsapi/README.md | 16 +++++++++++++ dnsapi/dns_acmedns.sh | 55 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 dnsapi/dns_acmedns.sh diff --git a/README.md b/README.md index 44b9660..52f7997 100644 --- a/README.md +++ b/README.md @@ -318,6 +318,7 @@ You don't have to do anything manually! 1. KingHost (https://www.kinghost.com.br/) 1. Zilore (https://zilore.com) 1. Loopia.se API +1. acme-dns (https://github.com/joohoi/acme-dns) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index bc1919d..b8bdbbb 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -835,6 +835,22 @@ acme.sh --issue --dns dns_loopia -d example.com -d *.example.com ``` The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 45. Use ACME DNS API + +ACME DNS is a limited DNS server with RESTful HTTP API to handle ACME DNS challenges easily and securely. +https://github.com/joohoi/acme-dns + +``` +export ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update" +export ACMEDNS_USERNAME="" +export ACMEDNS_PASSWORD="" +export ACMEDNS_SUBDOMAIN="" + +acme.sh --issue --dns dns_acmedns -d example.com -d www.example.com +``` + +The credentials will be saved in `~/.acme.sh/account.conf` and will +be reused when needed. # Use custom API diff --git a/dnsapi/dns_acmedns.sh b/dnsapi/dns_acmedns.sh new file mode 100644 index 0000000..9b3efa4 --- /dev/null +++ b/dnsapi/dns_acmedns.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env sh +# +#Author: Wolfgang Ebner +#Report Bugs here: https://github.com/webner/acme.sh +# +######## Public functions ##################### + +#Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_acmedns_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using acme-dns" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ACMEDNS_UPDATE_URL="${ACMEDNS_UPDATE_URL:-$(_readaccountconf_mutable ACMEDNS_UPDATE_URL)}" + ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readaccountconf_mutable ACMEDNS_USERNAME)}" + ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readaccountconf_mutable ACMEDNS_PASSWORD)}" + ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readaccountconf_mutable ACMEDNS_SUBDOMAIN)}" + + if [ "$ACMEDNS_UPDATE_URL" = "" ]; then + ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update" + fi + + _saveaccountconf_mutable ACMEDNS_UPDATE_URL "$ACMEDNS_UPDATE_URL" + _saveaccountconf_mutable ACMEDNS_USERNAME "$ACMEDNS_USERNAME" + _saveaccountconf_mutable ACMEDNS_PASSWORD "$ACMEDNS_PASSWORD" + _saveaccountconf_mutable ACMEDNS_SUBDOMAIN "$ACMEDNS_SUBDOMAIN" + + export _H1="X-Api-User: $ACMEDNS_USERNAME" + export _H2="X-Api-Key: $ACMEDNS_PASSWORD" + data="{\"subdomain\":\"$ACMEDNS_SUBDOMAIN\", \"txt\": \"$txtvalue\"}" + + _debug data "$data" + response="$(_post "$data" "$ACMEDNS_UPDATE_URL" "" "POST")" + _debug response "$response" + + if ! echo "$response" | grep "\"$txtvalue\"" >/dev/null; then + _err "invalid response of acme-dns" + return 1 + fi + +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_acmedns_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using acme-dns" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" +} + +#################### Private functions below ################################## From ed817c81defb98efdbde427089c6a081990b98ce Mon Sep 17 00:00:00 2001 From: AlexeyStolyarov Date: Thu, 5 Apr 2018 14:18:53 +0500 Subject: [PATCH 053/280] #issue with nsupdate on Ubuntu 14.04.1 LTS on Ubuntu 14.04.1 LTS if nsupdate runs without port number given it treated argument following server name as port number. and throws error: ``` port 'update' is not numeric syntax error ``` --- dnsapi/dns_nsupdate.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 7acb2ef..ad77502 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -8,12 +8,14 @@ dns_nsupdate_add() { txtvalue=$2 _checkKeyFile || return 1 [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" + [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 # save the dns server and key to the account conf file. - _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}" + _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER} " + _saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT} " _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" nsupdate -k "${NSUPDATE_KEY}" < Date: Thu, 5 Apr 2018 14:45:15 +0500 Subject: [PATCH 054/280] Update dns_nsupdate.sh --- dnsapi/dns_nsupdate.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index ad77502..db653b6 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -15,7 +15,7 @@ dns_nsupdate_add() { _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" nsupdate -k "${NSUPDATE_KEY}" < Date: Thu, 5 Apr 2018 14:50:55 +0500 Subject: [PATCH 055/280] Update dns_nsupdate.sh --- dnsapi/dns_nsupdate.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index db653b6..555f4d2 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -10,8 +10,8 @@ dns_nsupdate_add() { [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 # save the dns server and key to the account conf file. - _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER} " - _saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT} " + _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}" + _saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}" _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" nsupdate -k "${NSUPDATE_KEY}" < Date: Mon, 9 Apr 2018 00:10:27 +0200 Subject: [PATCH 056/280] Add Support for inwx mobile tan --- dnsapi/README.md | 8 ++++++++ dnsapi/dns_inwx.sh | 50 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index b8bdbbb..a90b3f7 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -641,6 +641,14 @@ acme.sh --issue --dns dns_inwx -d example.com -d www.example.com The `INWX_User` and `INWX_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +If your account is secured by mobile tan you have also defined the shared secret. + +``` +export INWX_Shared_Secret="shared secret" +``` + +You may need to re-enable the mobile tan to gain the shared secret. + ## 34. User Servercow API v1 Create a new user from the servercow control center. Don't forget to activate **DNS API** for this user. diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index 5dfba7d..cd5af91 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -4,6 +4,10 @@ #INWX_User="username" # #INWX_Password="password" +# +# Dependencies: +# ------------- +# - oathtool (When using 2 Factor Authentication) INWX_Api="https://api.domrobot.com/xmlrpc/" @@ -16,6 +20,7 @@ dns_inwx_add() { 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="" @@ -27,6 +32,7 @@ dns_inwx_add() { #save the api key and email to the account conf file. _saveaccountconf_mutable INWX_User "$INWX_User" _saveaccountconf_mutable INWX_Password "$INWX_Password" + _saveaccountconf_mutable INWX_Shared_Secret "$INWX_Shared_Secret" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -148,8 +154,46 @@ _inwx_login() { ' $INWX_User $INWX_Password) response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + _H1=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')") + export _H1 - printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')" + #https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71 + if _contains "$response" "tfa"; then + if [ -z "$INWX_Shared_Secret" ]; then + _err "Mobile TAN detected." + _err "Please define a shared secret." + return 1 + fi + + if ! _exists oathtool; then + _err "Please install oathtool to use 2 Factor Authentication." + _err "" + return 1 + fi + + tan="$(oathtool --base32 --totp "${INWX_Shared_Secret}" 2>/dev/null)" + + xml_content=$(printf ' + + account.unlock + + + + + + tan + + %s + + + + + + + ' "$tan") + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + fi } @@ -161,8 +205,8 @@ _get_root() { i=2 p=1 - _H1=$(_inwx_login) - export _H1 + _inwx_login + xml_content=' nameserver.list From 98a7e72f0aa581cb8f3a2a7f7734d728d571b1a7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 13 Apr 2018 21:28:13 +0800 Subject: [PATCH 057/280] fix https://github.com/Neilpang/acme.sh/issues/1512#issuecomment-381121303 --- dnsapi/dns_gd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 5fb1b17..ad1a286 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -59,7 +59,7 @@ dns_gd_add() { _info "Adding record" if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then - if [ "$response" = "{}" ]; then + if [ "$response" = "{}" ] || [ "$response" = "null" ]; then _info "Added, sleeping 10 seconds" _sleep 10 #todo: check if the record takes effect From f8526f027cac5facbebe237252e5110a838ec3aa Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 20 Apr 2018 14:05:09 +0800 Subject: [PATCH 058/280] fix https://github.com/Neilpang/acme.sh/issues/1539 --- dnsapi/dns_gd.sh | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index ad1a286..97902df 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -59,19 +59,13 @@ dns_gd_add() { _info "Adding record" if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then - if [ "$response" = "{}" ] || [ "$response" = "null" ]; then - _info "Added, sleeping 10 seconds" - _sleep 10 - #todo: check if the record takes effect - return 0 - else - _err "Add txt record error." - _err "$response" - return 1 - fi + _info "Added, sleeping 10 seconds" + _sleep 10 + #todo: check if the record takes effect + return 0 fi _err "Add txt record error." - + return 1 } #fulldomain From e36fbd6af5c56b4672077694e7db9adebcb49d25 Mon Sep 17 00:00:00 2001 From: Grant Millar Date: Fri, 20 Apr 2018 09:41:07 +0100 Subject: [PATCH 059/280] Fix DNSimple when zone has > 100 records The _get_records function currently returns the first 100 records. As our TXT is added most recently, if you have > 100 records it will not be returned. I've changed the function to sort by ID DESC, so it will always return the latest 100 records. --- dnsapi/dns_dnsimple.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index 0dd3918..b2cba58 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -152,7 +152,7 @@ _get_records() { sub_domain=$3 _debug "fetching txt records" - _dnsimple_rest GET "$account_id/zones/$domain/records?per_page=100" + _dnsimple_rest GET "$account_id/zones/$domain/records?per_page=100&sort=id:desc" if ! _contains "$response" "\"id\":"; then _err "failed to retrieve records" From 8a5c4979ad96d3547c318e98b8633b1c77804c1e Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 20 Apr 2018 23:22:25 +0800 Subject: [PATCH 060/280] fix shellcheck --- .travis.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index b6b5742..5d0e4db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,12 +13,6 @@ env: global: - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64 -addons: - apt: - sources: - - debian-sid # Grab shellcheck from the Debian repo (o_O) - packages: - - shellcheck install: - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then @@ -40,7 +34,6 @@ script: - 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 - matrix: fast_finish: true From f0a87da3759026176b5aa42dfcbe1c063974de70 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 20 Apr 2018 23:32:42 +0800 Subject: [PATCH 061/280] fix shfmt --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5d0e4db..04de193 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,9 +23,7 @@ install: script: - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - command -V openssl && openssl version - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then chmod +x ~/shfmt ; fi - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt && chmod +x ~/shfmt && ~/shfmt -l -w -i 2 . ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi From ce8dca7afe06c96cb0e1321bd552ef31c7c6003f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 21 Apr 2018 13:15:17 +0800 Subject: [PATCH 062/280] move renewhook after installcert fix https://github.com/Neilpang/acme.sh/issues/1547 --- acme.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index a5e4b39..5fdac38 100755 --- a/acme.sh +++ b/acme.sh @@ -4287,20 +4287,21 @@ $_authorizations_map" Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400) _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" - if ! _on_issue_success "$_post_hook" "$_renew_hook"; then - _err "Call hook error." - return 1 - fi - if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then _savedomainconf "Le_RealCertPath" "$_real_cert" _savedomainconf "Le_RealCACertPath" "$_real_ca" _savedomainconf "Le_RealKeyPath" "$_real_key" _savedomainconf "Le_ReloadCmd" "$_reload_cmd" _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" - _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd" + if ! _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"; then + return 1 + fi fi + if ! _on_issue_success "$_post_hook" "$_renew_hook"; then + _err "Call hook error." + return 1 + fi } #domain [isEcc] From 66686de4e4afc555260538c28b943777d79d019d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 21 Apr 2018 13:21:56 +0800 Subject: [PATCH 063/280] add --branch --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 5fdac38..e7a30d9 100755 --- a/acme.sh +++ b/acme.sh @@ -5515,6 +5515,7 @@ Parameters: --openssl-bin Specifies a custom openssl bin location. --use-wget Force to use wget, if you have both curl and wget installed. --yes-I-know-dns-manual-mode-enough-go-ahead-please Force to use dns manual mode: $_DNS_MANUAL_WIKI + --branch, -b Only valid for '--upgrade' command, specifies the branch name to upgrade to. " } @@ -6059,6 +6060,10 @@ _process() { _use_wget="1" ACME_USE_WGET="1" ;; + --branch | -b) + export BRANCH="$2" + shift + ;; *) _err "Unknown parameter : $1" return 1 From 8259e82787befd82a52d1458d4f0a3a15afac5ec Mon Sep 17 00:00:00 2001 From: Oleg Rakovitch Date: Mon, 23 Apr 2018 18:34:15 +0300 Subject: [PATCH 064/280] Add missing package to docker image Issue #1552 --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index b286673..5a64c72 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,7 @@ FROM alpine:3.6 RUN apk update -f \ && apk --no-cache add -f \ openssl \ + coreutils \ curl \ socat \ && rm -rf /var/cache/apk/* From 676402d918cb064999d05d33289e9f41fb3fe48a Mon Sep 17 00:00:00 2001 From: Kordian Bruck Date: Thu, 26 Apr 2018 11:40:17 +0200 Subject: [PATCH 065/280] Increase serial when adding txt records --- dnsapi/dns_ispconfig.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh index 1e500ad..c8f7eed 100755 --- a/dnsapi/dns_ispconfig.sh +++ b/dnsapi/dns_ispconfig.sh @@ -128,7 +128,7 @@ _ISPC_addTxt() { curSerial="$(date +%s)" curStamp="$(date +'%F %T')" params="\"server_id\":\"${server_id}\",\"zone\":\"${zone}\",\"name\":\"${fulldomain}.\",\"type\":\"txt\",\"data\":\"${txtvalue}\",\"aux\":\"0\",\"ttl\":\"3600\",\"active\":\"y\",\"stamp\":\"${curStamp}\",\"serial\":\"${curSerial}\"" - curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}}}" + curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}},\"update_serial\":true}}" curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_add")" _debug "Calling _ISPC_addTxt: '${curData}' '${ISPC_Api}?dns_txt_add'" _debug "Result of _ISPC_addTxt: '$curResult'" From e32b3aac22a64aa2357860f9cdf8697d268af811 Mon Sep 17 00:00:00 2001 From: Steffen Busch Date: Thu, 26 Apr 2018 21:02:37 +0200 Subject: [PATCH 066/280] Added --force-color to enforce the use of ANSI Color. Issue #1557 --- acme.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index e7a30d9..5e794a5 100755 --- a/acme.sh +++ b/acme.sh @@ -124,21 +124,21 @@ if [ -t 1 ]; then fi __green() { - if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then printf '\033[1;31;32m' fi printf -- "%b" "$1" - if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then printf '\033[0m' fi } __red() { - if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then printf '\033[1;31;40m' fi printf -- "%b" "$1" - if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then printf '\033[0m' fi } @@ -5501,6 +5501,7 @@ Parameters: --ca-path Specifies directory containing CA certificates in PEM format, used by wget or curl. --nocron Only valid for '--install' command, which means: do not install the default cron job. In this case, the certs will not be renewed automatically. --no-color Do not output color text. + --force-color Force output of color text. Useful for non-interactive use with the aha tool for HTML E-Mails. --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' --csr Specifies the input csr. --pre-hook Command to be run before obtaining any certificates. @@ -5966,6 +5967,9 @@ _process() { --no-color) export ACME_NO_COLOR=1 ;; + --force-color) + export ACME_FORCE_COLOR=1 + ;; --ecc) _ecc="isEcc" ;; From 4e05062def15d4b99dcc6e26457ebebe853e977f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Bli=C5=BE=C3=ADk?= Date: Mon, 30 Apr 2018 15:09:07 +0200 Subject: [PATCH 067/280] add tele3-dns plugin --- README.md | 1 + dnsapi/README.md | 12 ++++++++ dnsapi/dns_tele3.sh | 70 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 dnsapi/dns_tele3.sh diff --git a/README.md b/README.md index 52f7997..f395e49 100644 --- a/README.md +++ b/README.md @@ -319,6 +319,7 @@ You don't have to do anything manually! 1. Zilore (https://zilore.com) 1. Loopia.se API 1. acme-dns (https://github.com/joohoi/acme-dns) +1. TELE3 (https://www.tele3.cz) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index a90b3f7..ef61a24 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -859,7 +859,19 @@ acme.sh --issue --dns dns_acmedns -d example.com -d www.example.com The credentials will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 46. Use TELE3 API +First you need to login to your TELE3 account to set your API-KEY. +https://www.tele3.cz/system-acme-api.html + +``` +export TELE3_Key="MS2I4uPPaI..." +export TELE3_Secret="kjhOIHGJKHg" + +acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com +``` + +The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed. # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_tele3.sh b/dnsapi/dns_tele3.sh new file mode 100644 index 0000000..3dced48 --- /dev/null +++ b/dnsapi/dns_tele3.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env sh +# +# tele3.cz DNS API +# +# Author: Roman Blizik +# Report Bugs here: https://github.com/par-pa/acme.sh +# +# -- +# export TELE3_Key="MS2I4uPPaI..." +# export TELE3_Secret="kjhOIHGJKHg" +# -- + +TELE3_API="https://www.tele3.cz/acme/" + +######## Public functions ##################### + +dns_tele3_add() { + _info "Using TELE3 DNS" + data="\"ope\":\"add\", \"domain\":\"$1\", \"value\":\"$2\"" + if ! _tele3_call; then + _err "Publish zone failed" + return 1 + fi + + _info "Zone published" +} + +dns_tele3_rm() { + _info "Using TELE3 DNS" + data="\"ope\":\"rm\", \"domain\":\"$1\", \"value\":\"$2\"" + if ! _tele3_call; then + _err "delete TXT record failed" + return 1 + fi + + _info "TXT record successfully deleted" +} + +#################### Private functions below ################################## + +_tele3_init() { + TELE3_Key="${TELE3_Key:-$(_readaccountconf_mutable TELE3_Key)}" + TELE3_Secret="${TELE3_Secret:-$(_readaccountconf_mutable TELE3_Secret)}" + if [ -z "$TELE3_Key" ] || [ -z "$TELE3_Secret" ]; then + TELE3_Key="" + TELE3_Secret="" + _err "You must export variables: TELE3_Key and TELE3_Secret" + return 1 + fi + + #save the config variables to the account conf file. + _saveaccountconf_mutable TELE3_Key "$TELE3_Key" + _saveaccountconf_mutable TELE3_Secret "$TELE3_Secret" +} + +_tele3_call() { + _tele3_init + data="{\"key\":\"$TELE3_Key\", \"secret\":\"$TELE3_Secret\", $data}" + + _debug data "$data" + + response="$(_post "$data" "$TELE3_API" "" "POST")" + _debug response "$response" + + if [ "$response" != "success" ]; then + _err "$response" + return 1 + fi +} + From 70b56eb527400f645e78004c56fd4154b9b2df1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Bli=C5=BE=C3=ADk?= Date: Wed, 2 May 2018 11:13:10 +0200 Subject: [PATCH 068/280] remove whitespace --- dnsapi/dns_tele3.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_tele3.sh b/dnsapi/dns_tele3.sh index 3dced48..76c9091 100644 --- a/dnsapi/dns_tele3.sh +++ b/dnsapi/dns_tele3.sh @@ -67,4 +67,3 @@ _tele3_call() { return 1 fi } - From 03a1386902fc38ce042c04e7af11c1fa629b6c58 Mon Sep 17 00:00:00 2001 From: Kordian Bruck Date: Wed, 2 May 2018 23:01:52 +0200 Subject: [PATCH 069/280] Update serial also when deleting the token --- dnsapi/dns_ispconfig.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh index c8f7eed..2d8d6b0 100755 --- a/dnsapi/dns_ispconfig.sh +++ b/dnsapi/dns_ispconfig.sh @@ -128,7 +128,7 @@ _ISPC_addTxt() { curSerial="$(date +%s)" curStamp="$(date +'%F %T')" params="\"server_id\":\"${server_id}\",\"zone\":\"${zone}\",\"name\":\"${fulldomain}.\",\"type\":\"txt\",\"data\":\"${txtvalue}\",\"aux\":\"0\",\"ttl\":\"3600\",\"active\":\"y\",\"stamp\":\"${curStamp}\",\"serial\":\"${curSerial}\"" - curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}},\"update_serial\":true}}" + curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}},\"update_serial\":true}" curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_add")" _debug "Calling _ISPC_addTxt: '${curData}' '${ISPC_Api}?dns_txt_add'" _debug "Result of _ISPC_addTxt: '$curResult'" @@ -160,7 +160,7 @@ _ISPC_rmTxt() { *) unset IFS _info "Retrieved Record ID." - curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\"}" + curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\",\"update_serial\":true}" curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")" _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_delete'" _debug "Result of _ISPC_rmTxt: '$curResult'" From 360dc140ea101a319973afeaead4cdb2a016f027 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Thu, 3 May 2018 01:28:56 -0500 Subject: [PATCH 070/280] implement basic haproxy deploy HAProxy requires the certificate chain and key to be concatenated and placed somewhere (can be anywhere). This script expects a single environment variable with the path where the concatenated PEM file should be written --- deploy/haproxy.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 34efbb1..7eb23e2 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -20,7 +20,16 @@ haproxy_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _err "deploy cert to haproxy server, Not implemented yet" - return 1 + # combine the key and fullchain into a single pem and install + _savedomainconf DEPLOY_HAPROXY_PEM_PATH "$DEPLOY_HAPROXY_PEM_PATH" + + _pem_full_path="$DEPLOY_HAPROXY_PEM_PATH/$_cdomain.pem" + _info "Full path to PEM $_pem_full_path" + + cat "$_cfullchain" "$_ckey" > "$_pem_full_path" + chmod 600 "$_pem_full_path" + + _info "Certificate successfully deployed" + return 0 } From 1eae73105a04e296e5c3d3524ccb2ab929196cd1 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Thu, 3 May 2018 01:33:06 -0500 Subject: [PATCH 071/280] add docs for HAProxy deployment --- deploy/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index 0b820df..8fb6595 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -255,3 +255,17 @@ acme.sh --deploy -d fritzbox.example.com --deploy-hook fritzbox ```sh acme.sh --deploy -d ftp.example.com --deploy-hook strongswan ``` + +## 10. Deploy the cert to HAProxy + +You must specify the path where you want the concatenated key and certificate chain written. +```sh +export DEPLOY_HAPROXY_PEM_PATH=/etc/haproxy +``` + +You can then deploy the certificate as follows +```sh +acme.sh --deploy -d haproxy.example.com --deploy-hook haproxy +``` + +The path for the PEM file will be stored with the domain configuration and will be available when renewing, so that deploy will happen automatically when renewed. From 7573e560b63d009963711ef5df61d41837466a03 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Thu, 3 May 2018 10:06:05 -0500 Subject: [PATCH 072/280] Add conditional check to ensure path is provided --- deploy/haproxy.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 7eb23e2..c263ab7 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -23,7 +23,13 @@ haproxy_deploy() { # combine the key and fullchain into a single pem and install _savedomainconf DEPLOY_HAPROXY_PEM_PATH "$DEPLOY_HAPROXY_PEM_PATH" - _pem_full_path="$DEPLOY_HAPROXY_PEM_PATH/$_cdomain.pem" + _pem_path="${DEPLOY_HAPROXY_PEM_PATH}" + if [ -z "$_pem_path" ]; then + _err "Path to save PEM file not found. Please define DEPLOY_HAPROXY_PEM_PATH." + return 1 + fi + + _pem_full_path="$_pem_path/$_cdomain.pem" _info "Full path to PEM $_pem_full_path" cat "$_cfullchain" "$_ckey" > "$_pem_full_path" From ec73aeba169cb2650491931db6fed4e62033ab2e Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Thu, 3 May 2018 12:17:26 -0500 Subject: [PATCH 073/280] remove whitespace --- deploy/haproxy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index c263ab7..d5cab9f 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -32,7 +32,7 @@ haproxy_deploy() { _pem_full_path="$_pem_path/$_cdomain.pem" _info "Full path to PEM $_pem_full_path" - cat "$_cfullchain" "$_ckey" > "$_pem_full_path" + cat "$_cfullchain" "$_ckey" >"$_pem_full_path" chmod 600 "$_pem_full_path" _info "Certificate successfully deployed" From 5f593994c785f74732ef3728d68d86b56713eca4 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Thu, 3 May 2018 12:25:11 -0500 Subject: [PATCH 074/280] remove more whitespace (trying to get TravisCI working) --- deploy/haproxy.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index d5cab9f..77f9c94 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -28,7 +28,6 @@ haproxy_deploy() { _err "Path to save PEM file not found. Please define DEPLOY_HAPROXY_PEM_PATH." return 1 fi - _pem_full_path="$_pem_path/$_cdomain.pem" _info "Full path to PEM $_pem_full_path" From 681e3785efdbe84b25f9f40f647694bb4fb0f262 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 4 May 2018 22:23:56 +0800 Subject: [PATCH 075/280] add dns alias mode --- dnsapi/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index a90b3f7..aa8ae6b 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1,5 +1,9 @@ # How to use DNS API +If your dns provider doesn't provide api access, you can use our dns alias mode: + +https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode + ## 1. Use CloudFlare domain API to automatically issue cert First you need to login to your CloudFlare account to get your API key. From e9e999542d62ef30f417f84254264051060068a6 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Fri, 4 May 2018 10:14:31 -0500 Subject: [PATCH 076/280] add reload --- deploy/haproxy.sh | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 77f9c94..0b89b7a 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -20,9 +20,18 @@ haproxy_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - # combine the key and fullchain into a single pem and install + # handle reload preference + DEFAULT_HAPROXY_RELOAD="/usr/sbin/service haproxy restart" + if [[ -z "${DEPLOY_HAPROXY_RELOAD}" ]]; then + _reload="${DEFAULT_HAPROXY_RELOAD}" + _cleardomainconf DEPLOY_HAPROXY_RELOAD + else + _reload="${DEPLOY_HAPROXY_RELOAD}" + _savedomainconf DEPLOY_HAPROXY_RELOAD "$DEPLOY_HAPROXY_RELOAD" + fi _savedomainconf DEPLOY_HAPROXY_PEM_PATH "$DEPLOY_HAPROXY_PEM_PATH" + # work out the path where the PEM file should go _pem_path="${DEPLOY_HAPROXY_PEM_PATH}" if [ -z "$_pem_path" ]; then _err "Path to save PEM file not found. Please define DEPLOY_HAPROXY_PEM_PATH." @@ -31,10 +40,19 @@ haproxy_deploy() { _pem_full_path="$_pem_path/$_cdomain.pem" _info "Full path to PEM $_pem_full_path" + # combine the key and fullchain into a single pem and install cat "$_cfullchain" "$_ckey" >"$_pem_full_path" chmod 600 "$_pem_full_path" - _info "Certificate successfully deployed" - return 0 + + # restart HAProxy + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" + return 0 + else + _err "Reload error" + return 1 + fi } From afe5cb588d97ba723680c181ec5c1bd69892cd2c Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Fri, 4 May 2018 10:25:54 -0500 Subject: [PATCH 077/280] update for POSIX compliance --- deploy/haproxy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 0b89b7a..5c1a40e 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -22,7 +22,7 @@ haproxy_deploy() { # handle reload preference DEFAULT_HAPROXY_RELOAD="/usr/sbin/service haproxy restart" - if [[ -z "${DEPLOY_HAPROXY_RELOAD}" ]]; then + if [ -z "${DEPLOY_HAPROXY_RELOAD}" ]; then _reload="${DEFAULT_HAPROXY_RELOAD}" _cleardomainconf DEPLOY_HAPROXY_RELOAD else From c9818ea2c46183ba8db09a21fe6308f93a159028 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Fri, 4 May 2018 13:03:27 -0500 Subject: [PATCH 078/280] add documentation for reload command --- deploy/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index 8fb6595..181989d 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -263,6 +263,12 @@ You must specify the path where you want the concatenated key and certificate ch export DEPLOY_HAPROXY_PEM_PATH=/etc/haproxy ``` +You may optionally define the command to reload HAProxy. The value shown below will be used as the default if you don't set this environment variable. + +```sh +export DEPLOY_HAPROXY_RELOAD="/usr/sbin/service haproxy restart" +``` + You can then deploy the certificate as follows ```sh acme.sh --deploy -d haproxy.example.com --deploy-hook haproxy From e9782c3219722e590f84f2aa3d6cc056564a141e Mon Sep 17 00:00:00 2001 From: linux-insideDE <39219399+linux-insideDE@users.noreply.github.com> Date: Tue, 15 May 2018 13:18:50 +0200 Subject: [PATCH 079/280] Create dns_netcup.sh --- dnsapi/dns_netcup.sh | 146 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 dnsapi/dns_netcup.sh diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh new file mode 100644 index 0000000..7a8002a --- /dev/null +++ b/dnsapi/dns_netcup.sh @@ -0,0 +1,146 @@ +#!/usr/bin/env sh + +#Requirments: jq +#developed by linux-insideDE + +NC_Apikey="${NC_Apikey:-$(_readaccountconf_mutable NC_Apikey)}" +NC_Apipw="${NC_Apipw:-$(_readaccountconf_mutable NC_Apipw)}" +NC_CID="${NC_CID:-$(_readaccountconf_mutable NC_CID)}" +end="https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON" +client="" + +dns_netcup_add() { + login + if [ "$NC_Apikey" = "" ] || [ "$NC_Apipw" = "" ] || [ "$NC_CID" = "" ]; then + _err "No Credentials given" + return 1 + fi + _saveaccountconf_mutable NC_Apikey "$NC_Apikey" + _saveaccountconf_mutable NC_Apipw "$NC_Apipw" + _saveaccountconf_mutable NC_CID "$NC_CID" + fulldomain=$1 + txtvalue=$2 + tld="" + domain="" + exit=0 + i=20 + while [ "$i" -gt 0 ]; + do + tmp=$(echo "$fulldomain" | cut -d'.' -f$i) + if [ "$tmp" != "" ]; then + if [ "$tld" = "" ]; then + tld=$tmp + else + domain=$tmp + exit=$i + break; + fi + fi + i=$((i - 1)) + done + inc="" + i=1 + while [ "$i" -lt "$exit" ]; + do + if [ "$((exit-1))" = "$i" ]; then + inc="$inc$i" + break; + else + if [ "$inc" = "" ]; then + inc="$i," + else + inc="$inc$i," + fi + fi + i=$((i + 1)) + done + + tmp=$(echo "$fulldomain" | cut -d'.' -f$inc) + msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain.$tld\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"\", \"hostname\": \"$tmp\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"false\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") + _debug "$msg" + if [ "$(echo "$msg" | jq -r .status)" != "success" ]; then + _err "$msg" + return 1 + fi + logout +} + +dns_netcup_rm() { + login + fulldomain=$1 + txtvalue=$2 + tld="" + domain="" + exit=0 + i=20 + while [ "$i" -gt 0 ]; + do + tmp=$(echo "$fulldomain" | cut -d'.' -f$i) + if [ "$tmp" != "" ]; then + if [ "$tld" = "" ]; then + tld=$tmp + else + domain=$tmp + exit=$i + break; + fi + fi + i=$((i - 1)) + done + inc="" + i=1 + while [ "$i" -lt "$exit" ]; + do + if [ "$((exit-1))" = "$i" ]; then + inc="$inc$i" + break; + else + if [ "$inc" = "" ]; then + inc="$i," + else + inc="$inc$i," + fi + fi + i=$((i + 1)) + done + tmp=$(echo "$fulldomain" | cut -d'.' -f$inc) + doma="$domain.$tld" + rec=$(getRecords "$doma") + ids=$(echo "$rec" | jq -r ".[]|select(.destination==\"$txtvalue\")|.id") + msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$doma\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"$ids\", \"hostname\": \"$tmp\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"TRUE\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") + _debug "$msg" + if [ "$(echo "$msg" | jq -r .status)" != "success" ]; then + _err "$msg" + return 1 + fi + logout +} + +login() { + tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") + sid=$(echo "$tmp" | jq -r .responsedata.apisessionid) + _debug "$tmp" + if [ "$(echo "$tmp" | jq -r .status)" != "success" ]; then + _err "$tmp" + return 1 + fi +} +logout() { + tmp=$(_post "{\"action\": \"logout\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") + _debug "$tmp" + if [ "$(echo "$tmp" | jq -r .status)" != "success" ]; then + _err "$tmp" + return 1 + fi +} +getRecords() { + tmp2=$(_post "{\"action\": \"infoDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\", \"domainname\": \"$1\"}}" "$end" "" "POST") + xxd=$(echo "$tmp2" | jq -r ".responsedata.dnsrecords" | tr '[' ' ' | tr ']' ' ') + xcd=$(echo "$xxd" | sed 's/}\s{/},{/g') + echo "[ $xcd ]" + _debug "$tmp2" + if [ "$(echo "$tmp2" | jq -r .status)" != "success" ]; then + _err "$tmp2" + return 1 + fi +} From 3cd5b9ca2ed24ce74d5f81ef300879e7c24a0bff Mon Sep 17 00:00:00 2001 From: linux-insideDE <39219399+linux-insideDE@users.noreply.github.com> Date: Tue, 15 May 2018 13:21:25 +0200 Subject: [PATCH 080/280] added netcup dns api --- dnsapi/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index ef6c9d0..ed16536 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -876,6 +876,22 @@ acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com ``` The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed. +## 47. Use netcup DNS API to automatically issue cert + +First you need to login to your CCP account to get your API Key and API Password. +This script requires ``jq`` +``` +export NC_Apikey="" +export NC_Apipw="" +export NC_CID="" +``` + +Now, let's issue a cert: +``` +acme.sh --issue --dns dns_netcup -d example.com -d www.example.com +``` + +The `NC_Apikey`,`NC_Apipw` and `NC_CID` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. # Use custom API If your API is not supported yet, you can write your own DNS API. From f3a622d1a747f2460ea3ec231e14461e8a15049c Mon Sep 17 00:00:00 2001 From: linux-insideDE <39219399+linux-insideDE@users.noreply.github.com> Date: Tue, 15 May 2018 13:22:55 +0200 Subject: [PATCH 081/280] added netcup dns api --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f395e49..18b878d 100644 --- a/README.md +++ b/README.md @@ -320,6 +320,7 @@ You don't have to do anything manually! 1. Loopia.se API 1. acme-dns (https://github.com/joohoi/acme-dns) 1. TELE3 (https://www.tele3.cz) +1. netcup DNS API (https://www.netcup.de) And: From 6a4aad1aa8287c3362b566d7216ea92416f2e7d9 Mon Sep 17 00:00:00 2001 From: linux-insideDE <39219399+linux-insideDE@users.noreply.github.com> Date: Tue, 15 May 2018 14:38:29 +0200 Subject: [PATCH 082/280] replaced increment/decrement with _math function --- dnsapi/dns_netcup.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh index 7a8002a..2e31e13 100644 --- a/dnsapi/dns_netcup.sh +++ b/dnsapi/dns_netcup.sh @@ -36,7 +36,7 @@ dns_netcup_add() { break; fi fi - i=$((i - 1)) + i=$(_math "$i" - 1) done inc="" i=1 @@ -52,7 +52,7 @@ dns_netcup_add() { inc="$inc$i," fi fi - i=$((i + 1)) + i=$(_math "$i" + 1) done tmp=$(echo "$fulldomain" | cut -d'.' -f$inc) @@ -85,7 +85,7 @@ dns_netcup_rm() { break; fi fi - i=$((i - 1)) + i=$(_math "$i" - 1) done inc="" i=1 @@ -101,7 +101,7 @@ dns_netcup_rm() { inc="$inc$i," fi fi - i=$((i + 1)) + i=$(_math "$i" + 1) done tmp=$(echo "$fulldomain" | cut -d'.' -f$inc) doma="$domain.$tld" From ca1d62bec07ef4233383d9652a6a8ce6f2e509b5 Mon Sep 17 00:00:00 2001 From: linux-insideDE <39219399+linux-insideDE@users.noreply.github.com> Date: Tue, 15 May 2018 16:21:57 +0200 Subject: [PATCH 083/280] removed jq dependencies --- dnsapi/dns_netcup.sh | 47 ++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh index 2e31e13..7e52dd9 100644 --- a/dnsapi/dns_netcup.sh +++ b/dnsapi/dns_netcup.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -#Requirments: jq + #developed by linux-insideDE NC_Apikey="${NC_Apikey:-$(_readaccountconf_mutable NC_Apikey)}" @@ -58,7 +58,7 @@ dns_netcup_add() { tmp=$(echo "$fulldomain" | cut -d'.' -f$inc) msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain.$tld\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"\", \"hostname\": \"$tmp\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"false\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") _debug "$msg" - if [ "$(echo "$msg" | jq -r .status)" != "success" ]; then + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then _err "$msg" return 1 fi @@ -106,10 +106,29 @@ dns_netcup_rm() { tmp=$(echo "$fulldomain" | cut -d'.' -f$inc) doma="$domain.$tld" rec=$(getRecords "$doma") - ids=$(echo "$rec" | jq -r ".[]|select(.destination==\"$txtvalue\")|.id") + + ida=0000 + idv=0001 + ids=0000000000 + i=1 + while [ "$i" -ne 0 ]; + do + specrec=$(_getfield "$rec" "$i" ";") + idv="$ida" + ida=$(_getfield "$specrec" "1" "," | sed 's/\"id\":\"//g' | sed 's/\"//g') + txtv=$(_getfield "$specrec" "5" "," | sed 's/\"destination\":\"//g' | sed 's/\"//g') + i=$(_math "$i" + 1) + if [ "$txtvalue" = "$txtv" ]; then + i=0 + ids="$ida" + fi + if [ "$ida" = "$idv" ]; then + i=0 + fi + done msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$doma\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"$ids\", \"hostname\": \"$tmp\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"TRUE\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") _debug "$msg" - if [ "$(echo "$msg" | jq -r .status)" != "success" ]; then + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then _err "$msg" return 1 fi @@ -117,30 +136,28 @@ dns_netcup_rm() { } login() { - tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") - sid=$(echo "$tmp" | jq -r .responsedata.apisessionid) + tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") + sid=$(_getfield "$tmp" "8" | sed s/\"responsedata\":\{\"apisessionid\":\"//g | sed 's/\"\}\}//g') _debug "$tmp" - if [ "$(echo "$tmp" | jq -r .status)" != "success" ]; then - _err "$tmp" + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" return 1 fi } logout() { tmp=$(_post "{\"action\": \"logout\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") _debug "$tmp" - if [ "$(echo "$tmp" | jq -r .status)" != "success" ]; then - _err "$tmp" + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" return 1 fi } getRecords() { tmp2=$(_post "{\"action\": \"infoDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\", \"domainname\": \"$1\"}}" "$end" "" "POST") - xxd=$(echo "$tmp2" | jq -r ".responsedata.dnsrecords" | tr '[' ' ' | tr ']' ' ') - xcd=$(echo "$xxd" | sed 's/}\s{/},{/g') - echo "[ $xcd ]" + echo $(echo "$tmp2" | sed 's/\[//g' | sed 's/\]//g' | sed 's/{\"serverrequestid\".*\"dnsrecords\"://g' | sed 's/},{/};{/g' | sed 's/{//g' | sed 's/}//g') _debug "$tmp2" - if [ "$(echo "$tmp2" | jq -r .status)" != "success" ]; then - _err "$tmp2" + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" return 1 fi } From ed2ba6bc3aa88fa1d9ba8761ea4b92c3939441c4 Mon Sep 17 00:00:00 2001 From: linux-insideDE <39219399+linux-insideDE@users.noreply.github.com> Date: Tue, 15 May 2018 16:22:40 +0200 Subject: [PATCH 084/280] removed jq dependencies --- dnsapi/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index ed16536..cc2f476 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -879,7 +879,6 @@ The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will ## 47. Use netcup DNS API to automatically issue cert First you need to login to your CCP account to get your API Key and API Password. -This script requires ``jq`` ``` export NC_Apikey="" export NC_Apipw="" From 4715a1a5e0d6a1a6c0c2d462cba0f01a37389d88 Mon Sep 17 00:00:00 2001 From: linux-insideDE <39219399+linux-insideDE@users.noreply.github.com> Date: Wed, 16 May 2018 22:07:44 +0200 Subject: [PATCH 085/280] satisfy shellcheck --- dnsapi/dns_netcup.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh index 7e52dd9..755d22b 100644 --- a/dnsapi/dns_netcup.sh +++ b/dnsapi/dns_netcup.sh @@ -1,6 +1,4 @@ #!/usr/bin/env sh - - #developed by linux-insideDE NC_Apikey="${NC_Apikey:-$(_readaccountconf_mutable NC_Apikey)}" @@ -154,7 +152,8 @@ logout() { } getRecords() { tmp2=$(_post "{\"action\": \"infoDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\", \"domainname\": \"$1\"}}" "$end" "" "POST") - echo $(echo "$tmp2" | sed 's/\[//g' | sed 's/\]//g' | sed 's/{\"serverrequestid\".*\"dnsrecords\"://g' | sed 's/},{/};{/g' | sed 's/{//g' | sed 's/}//g') + out=$(echo "$tmp2" | sed 's/\[//g' | sed 's/\]//g' | sed 's/{\"serverrequestid\".*\"dnsrecords\"://g' | sed 's/},{/};{/g' | sed 's/{//g' | sed 's/}//g') + echo "$out" _debug "$tmp2" if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then _err "$msg" From 48e8022095a9bd993ed0633066fd7a65d51a0bd8 Mon Sep 17 00:00:00 2001 From: linux-insideDE <39219399+linux-insideDE@users.noreply.github.com> Date: Tue, 29 May 2018 16:23:28 +0200 Subject: [PATCH 086/280] improved handling for third level domains --- dnsapi/dns_netcup.sh | 131 +++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 81 deletions(-) diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh index 755d22b..00edb5b 100644 --- a/dnsapi/dns_netcup.sh +++ b/dnsapi/dns_netcup.sh @@ -18,48 +18,33 @@ dns_netcup_add() { _saveaccountconf_mutable NC_CID "$NC_CID" fulldomain=$1 txtvalue=$2 - tld="" domain="" - exit=0 - i=20 - while [ "$i" -gt 0 ]; - do - tmp=$(echo "$fulldomain" | cut -d'.' -f$i) - if [ "$tmp" != "" ]; then - if [ "$tld" = "" ]; then - tld=$tmp - else - domain=$tmp - exit=$i - break; - fi - fi - i=$(_math "$i" - 1) - done - inc="" - i=1 - while [ "$i" -lt "$exit" ]; + exit=$(echo "$fulldomain" | tr -dc '.' | wc -c) + exit=$(_math "$exit" + 1) + i=$exit + + while [ "$exit" -gt 0 ] do - if [ "$((exit-1))" = "$i" ]; then - inc="$inc$i" - break; + tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") + if [ "$(_math "$i" - "$exit")" -eq 0 ]; then + domain="$tmp" else - if [ "$inc" = "" ]; then - inc="$i," - else - inc="$inc$i," - fi - fi - i=$(_math "$i" + 1) + domain="$tmp.$domain" + fi + if [ "$(_math "$i" - "$exit")" -ge 1 ]; then + msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"false\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") + _debug "$msg" + if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" + return 1 + else + break; + fi + fi + fi + exit=$(_math "$exit" - 1) done - - tmp=$(echo "$fulldomain" | cut -d'.' -f$inc) - msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain.$tld\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"\", \"hostname\": \"$tmp\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"false\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") - _debug "$msg" - if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then - _err "$msg" - return 1 - fi logout } @@ -67,43 +52,36 @@ dns_netcup_rm() { login fulldomain=$1 txtvalue=$2 - tld="" + domain="" - exit=0 - i=20 - while [ "$i" -gt 0 ]; - do - tmp=$(echo "$fulldomain" | cut -d'.' -f$i) - if [ "$tmp" != "" ]; then - if [ "$tld" = "" ]; then - tld=$tmp - else - domain=$tmp - exit=$i - break; - fi - fi - i=$(_math "$i" - 1) - done - inc="" - i=1 - while [ "$i" -lt "$exit" ]; + exit=$(echo "$fulldomain" | tr -dc '.' | wc -c) + exit=$(_math "$exit" + 1) + i=$exit + rec="" + + while [ "$exit" -gt 0 ] do - if [ "$((exit-1))" = "$i" ]; then - inc="$inc$i" - break; + tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") + if [ "$(_math "$i" - "$exit")" -eq 0 ]; then + domain="$tmp" else - if [ "$inc" = "" ]; then - inc="$i," - else - inc="$inc$i," + domain="$tmp.$domain" + fi + if [ "$(_math "$i" - "$exit")" -ge 1 ]; then + msg=$(_post "{\"action\": \"infoDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\", \"domainname\": \"$domain\"}}" "$end" "" "POST") + rec=$(echo "$msg" | sed 's/\[//g' | sed 's/\]//g' | sed 's/{\"serverrequestid\".*\"dnsrecords\"://g' | sed 's/},{/};{/g' | sed 's/{//g' | sed 's/}//g') + _debug "$msg" + if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" + return 1 + else + break; + fi fi fi - i=$(_math "$i" + 1) + exit=$(_math "$exit" - 1) done - tmp=$(echo "$fulldomain" | cut -d'.' -f$inc) - doma="$domain.$tld" - rec=$(getRecords "$doma") ida=0000 idv=0001 @@ -123,8 +101,9 @@ dns_netcup_rm() { if [ "$ida" = "$idv" ]; then i=0 fi - done - msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$doma\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"$ids\", \"hostname\": \"$tmp\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"TRUE\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") + done + + msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"$ids\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"TRUE\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") _debug "$msg" if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then _err "$msg" @@ -150,13 +129,3 @@ logout() { return 1 fi } -getRecords() { - tmp2=$(_post "{\"action\": \"infoDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\", \"domainname\": \"$1\"}}" "$end" "" "POST") - out=$(echo "$tmp2" | sed 's/\[//g' | sed 's/\]//g' | sed 's/{\"serverrequestid\".*\"dnsrecords\"://g' | sed 's/},{/};{/g' | sed 's/{//g' | sed 's/}//g') - echo "$out" - _debug "$tmp2" - if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then - _err "$msg" - return 1 - fi -} From 206be3c1619a699af3e53636935e64f51493cd2f Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 29 May 2018 22:38:52 +0800 Subject: [PATCH 087/280] fix https://github.com/Neilpang/acme.sh/issues/1633 --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 5e794a5..713170b 100755 --- a/acme.sh +++ b/acme.sh @@ -4676,19 +4676,19 @@ _installcert() { if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then cp "$_real_cert" "$_backup_path/cert.bak" fi - cat "$CERT_PATH" >"$_real_cert" + cat "$CERT_PATH" >"$_real_cert" || return 1 fi if [ "$_real_ca" ]; then _info "Installing CA to:$_real_ca" if [ "$_real_ca" = "$_real_cert" ]; then echo "" >>"$_real_ca" - cat "$CA_CERT_PATH" >>"$_real_ca" + cat "$CA_CERT_PATH" >>"$_real_ca" || return 1 else if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then cp "$_real_ca" "$_backup_path/ca.bak" fi - cat "$CA_CERT_PATH" >"$_real_ca" + cat "$CA_CERT_PATH" >"$_real_ca" || return 1 fi fi @@ -4698,9 +4698,9 @@ _installcert() { cp "$_real_key" "$_backup_path/key.bak" fi if [ -f "$_real_key" ]; then - cat "$CERT_KEY_PATH" >"$_real_key" + cat "$CERT_KEY_PATH" >"$_real_key" || return 1 else - cat "$CERT_KEY_PATH" >"$_real_key" + cat "$CERT_KEY_PATH" >"$_real_key" || return 1 chmod 600 "$_real_key" fi fi @@ -4710,7 +4710,7 @@ _installcert() { if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then cp "$_real_fullchain" "$_backup_path/fullchain.bak" fi - cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" + cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" || return 1 fi if [ "$_reload_cmd" ]; then From c7b904501c7ecc3054cee92937733d45647e3690 Mon Sep 17 00:00:00 2001 From: linux-insideDE <39219399+linux-insideDE@users.noreply.github.com> Date: Tue, 29 May 2018 16:56:07 +0200 Subject: [PATCH 088/280] make shfmt happy --- dnsapi/dns_netcup.sh | 52 ++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh index 00edb5b..59e9270 100644 --- a/dnsapi/dns_netcup.sh +++ b/dnsapi/dns_netcup.sh @@ -13,18 +13,18 @@ dns_netcup_add() { _err "No Credentials given" return 1 fi - _saveaccountconf_mutable NC_Apikey "$NC_Apikey" - _saveaccountconf_mutable NC_Apipw "$NC_Apipw" - _saveaccountconf_mutable NC_CID "$NC_CID" + _saveaccountconf_mutable NC_Apikey "$NC_Apikey" + _saveaccountconf_mutable NC_Apipw "$NC_Apipw" + _saveaccountconf_mutable NC_CID "$NC_CID" fulldomain=$1 txtvalue=$2 domain="" exit=$(echo "$fulldomain" | tr -dc '.' | wc -c) exit=$(_math "$exit" + 1) i=$exit - - while [ "$exit" -gt 0 ] - do + + while + [ "$exit" -gt 0 ]; do tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") if [ "$(_math "$i" - "$exit")" -eq 0 ]; then domain="$tmp" @@ -34,13 +34,13 @@ dns_netcup_add() { if [ "$(_math "$i" - "$exit")" -ge 1 ]; then msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"false\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") _debug "$msg" - if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then + if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then _err "$msg" return 1 else - break; - fi + break + fi fi fi exit=$(_math "$exit" - 1) @@ -52,57 +52,57 @@ dns_netcup_rm() { login fulldomain=$1 txtvalue=$2 - + domain="" exit=$(echo "$fulldomain" | tr -dc '.' | wc -c) exit=$(_math "$exit" + 1) i=$exit rec="" - - while [ "$exit" -gt 0 ] - do + + while + [ "$exit" -gt 0 ]; do tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") if [ "$(_math "$i" - "$exit")" -eq 0 ]; then domain="$tmp" else domain="$tmp.$domain" fi - if [ "$(_math "$i" - "$exit")" -ge 1 ]; then + if [ "$(_math "$i" - "$exit")" -ge 1 ]; then msg=$(_post "{\"action\": \"infoDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\", \"domainname\": \"$domain\"}}" "$end" "" "POST") rec=$(echo "$msg" | sed 's/\[//g' | sed 's/\]//g' | sed 's/{\"serverrequestid\".*\"dnsrecords\"://g' | sed 's/},{/};{/g' | sed 's/{//g' | sed 's/}//g') - _debug "$msg" - if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then + _debug "$msg" + if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then _err "$msg" return 1 else - break; - fi + break + fi fi fi exit=$(_math "$exit" - 1) done - + ida=0000 idv=0001 - ids=0000000000 + ids=0000000000 i=1 - while [ "$i" -ne 0 ]; - do + while + [ "$i" -ne 0 ]; do specrec=$(_getfield "$rec" "$i" ";") idv="$ida" ida=$(_getfield "$specrec" "1" "," | sed 's/\"id\":\"//g' | sed 's/\"//g') - txtv=$(_getfield "$specrec" "5" "," | sed 's/\"destination\":\"//g' | sed 's/\"//g') + txtv=$(_getfield "$specrec" "5" "," | sed 's/\"destination\":\"//g' | sed 's/\"//g') i=$(_math "$i" + 1) if [ "$txtvalue" = "$txtv" ]; then i=0 ids="$ida" - fi + fi if [ "$ida" = "$idv" ]; then i=0 fi done - + msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"$ids\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"TRUE\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") _debug "$msg" if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then @@ -113,7 +113,7 @@ dns_netcup_rm() { } login() { - tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") + tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") sid=$(_getfield "$tmp" "8" | sed s/\"responsedata\":\{\"apisessionid\":\"//g | sed 's/\"\}\}//g') _debug "$tmp" if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then From 69b780ee321c15dd5e8348766389a140277d9871 Mon Sep 17 00:00:00 2001 From: linux-insideDE <39219399+linux-insideDE@users.noreply.github.com> Date: Tue, 29 May 2018 17:24:53 +0200 Subject: [PATCH 089/280] Update dns_netcup.sh --- dnsapi/dns_netcup.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh index 59e9270..573550e 100644 --- a/dnsapi/dns_netcup.sh +++ b/dnsapi/dns_netcup.sh @@ -102,7 +102,6 @@ dns_netcup_rm() { i=0 fi done - msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"$ids\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"TRUE\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") _debug "$msg" if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then From f90a2ae1959ea359412a0b570de99e083babed65 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 12 Jun 2018 21:19:27 +0800 Subject: [PATCH 090/280] check UNABLE_TO_AUTHENTICATE --- dnsapi/dns_gd.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 97902df..7cf4738 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -168,5 +168,9 @@ _gd_rest() { return 1 fi _debug2 response "$response" + if _contains "$response" "UNABLE_TO_AUTHENTICATE"; then + _err "It seems that your api key or secret is not correct." + return 1 + fi return 0 } From d987d61ea96da50a2efd733724b7f6b49c8da7df Mon Sep 17 00:00:00 2001 From: Santeri Kannisto Date: Thu, 28 Jun 2018 09:38:14 +0200 Subject: [PATCH 091/280] Issue #1328 bug fix v3 Eliminated php dependency with a private function for urlencode using sed. Php had failed on godaddy due to multiple php instances and naturally cron using the one without the necessary -r option. Compared to previous PR the sed code is now POSIX and should work on all environments. --- deploy/cpanel_uapi.sh | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/deploy/cpanel_uapi.sh b/deploy/cpanel_uapi.sh index 4563b9c..053a0c9 100644 --- a/deploy/cpanel_uapi.sh +++ b/deploy/cpanel_uapi.sh @@ -2,8 +2,12 @@ # Here is the script to deploy the cert to your cpanel using the cpanel API. # Uses command line uapi. --user option is needed only if run as root. # Returns 0 when success. -# Written by Santeri Kannisto -# Public domain, 2017 +# +# Please note that I am no longer using Github. If you want to report an issue +# or contact me, visit https://forum.webseodesigners.com/web-design-seo-and-hosting-f16/ +# +# Written by Santeri Kannisto +# Public domain, 2017-2018 #export DEPLOY_CPANEL_USER=myusername @@ -28,15 +32,9 @@ cpanel_uapi_deploy() { _err "The command uapi is not found." return 1 fi - if ! _exists php; then - _err "The command php is not found." - return 1 - fi # read cert and key files and urlencode both - _certstr=$(cat "$_ccert") - _keystr=$(cat "$_ckey") - _cert=$(php -r "echo urlencode(\"$_certstr\");") - _key=$(php -r "echo urlencode(\"$_keystr\");") + _cert=$(cat "$_ccert" | _url_encode) + _key=$(cat "$_ckey" | _url_encode) _debug _cert "$_cert" _debug _key "$_key" From 05dea7b22ac15c6748e79f4beed02c22b39b3784 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 28 Jun 2018 20:34:29 +0800 Subject: [PATCH 092/280] fix warning --- deploy/cpanel_uapi.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/cpanel_uapi.sh b/deploy/cpanel_uapi.sh index 053a0c9..01cb94e 100644 --- a/deploy/cpanel_uapi.sh +++ b/deploy/cpanel_uapi.sh @@ -33,8 +33,8 @@ cpanel_uapi_deploy() { return 1 fi # read cert and key files and urlencode both - _cert=$(cat "$_ccert" | _url_encode) - _key=$(cat "$_ckey" | _url_encode) + _cert=$(_url_encode < "$_ccert") + _key=$(_url_encode < "$_ckey") _debug _cert "$_cert" _debug _key "$_key" From 9c545059ae43396c49b35c1870496ec58406b495 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 28 Jun 2018 22:21:22 +0800 Subject: [PATCH 093/280] fix warning --- deploy/cpanel_uapi.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/cpanel_uapi.sh b/deploy/cpanel_uapi.sh index 01cb94e..44844f7 100644 --- a/deploy/cpanel_uapi.sh +++ b/deploy/cpanel_uapi.sh @@ -33,8 +33,8 @@ cpanel_uapi_deploy() { return 1 fi # read cert and key files and urlencode both - _cert=$(_url_encode < "$_ccert") - _key=$(_url_encode < "$_ckey") + _cert=$(_url_encode <"$_ccert") + _key=$(_url_encode <"$_ckey") _debug _cert "$_cert" _debug _key "$_key" From 26c669e42da5e87c8d616e6c20c53e26e94d2c21 Mon Sep 17 00:00:00 2001 From: Will Date: Sun, 1 Jul 2018 18:53:47 -0400 Subject: [PATCH 094/280] Update README.md - HTTPS For centminmod.com Link Update README.md - HTTPS For centminmod.com Link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f395e49..cb2c8cb 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [webfaction](https://community.webfaction.com/questions/19988/using-letsencrypt) - [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty) - [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709) -- [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html) +- [Centminmod](https://centminmod.com/letsencrypt-acmetool-https.html) - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) - [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient) From 28e4bcf67f82c9aa6e88224aa528cb629eff5743 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 8 Jul 2018 16:04:18 +0200 Subject: [PATCH 095/280] initial version with Euserv.eu DNS API Support --- dnsapi/dns_euserv.sh | 358 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 dnsapi/dns_euserv.sh diff --git a/dnsapi/dns_euserv.sh b/dnsapi/dns_euserv.sh new file mode 100644 index 0000000..1a58df5 --- /dev/null +++ b/dnsapi/dns_euserv.sh @@ -0,0 +1,358 @@ +#!/usr/bin/env sh + +#This is the euserv.eu api wrapper for acme.sh +# +#Author: Michael Brueckner +#Report Bugs: https://www.github.com/initit/acme.sh or mbr@initit.de + +# +#EUSERV_Username="username" +# +#EUSERV_Password="password" +# +# Dependencies: +# ------------- +# - none - + +EUSERV_Api="https://api.euserv.net" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_euserv_add() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + EUSERV_Username="${EUSERV_Username:-$(_readaccountconf_mutable EUSERV_Username)}" + EUSERV_Password="${EUSERV_Password:-$(_readaccountconf_mutable EUSERV_Password)}" + if [ -z "$EUSERV_Username" ] || [ -z "$EUSERV_Password" ]; then + EUSERV_Username="" + EUSERV_Password="" + _err "You don't specify euserv user and password yet." + _err "Please create your key and try again." + return 1 + fi + + #save the user and email to the account conf file. + _saveaccountconf_mutable EUSERV_Username "$EUSERV_Username" + _saveaccountconf_mutable EUSERV_Password "$EUSERV_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue" + +} + +#fulldomain txtvalue +dns_euserv_rm() { + + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + EUSERV_Username="${EUSERV_Username:-$(_readaccountconf_mutable EUSERV_Username)}" + EUSERV_Password="${EUSERV_Password:-$(_readaccountconf_mutable EUSERV_Password)}" + if [ -z "$EUSERV_Username" ] || [ -z "$EUSERV_Password" ]; then + EUSERV_Username="" + EUSERV_Password="" + _err "You don't specify euserv user and password yet." + _err "Please create your key and try again." + return 1 + fi + + #save the user and email to the account conf file. + _saveaccountconf_mutable EUSERV_Username "$EUSERV_Username" + _saveaccountconf_mutable EUSERV_Password "$EUSERV_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug "_sub_domain" "$_sub_domain" + _debug "_domain" "$_domain" + + _debug "Getting txt records" + + xml_content=$(printf ' + + domain.dns_get_active_records + + + + + + login + + %s + + + + password + + %s + + + + domain_id + + %s + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error could not get txt records" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + +# _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1 ) +# _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/' ) + + if ! printf "%s" "$response" | grep '>dns_record_content<.*>'"$txtvalue"'<' >/dev/null; then + _info "Do not need to delete record" + else + # find block where txtvalue is in. the record_id is allways prior this line! + _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1 ) + # record_id is the last entry with a number, identified by the postfix of + _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/' ) + _info "Deleting record" + _euserv_delete_record "$_record_id" + fi + +} + +#################### Private functions below ################################## + +_euserv_get_domain_orders() { +# returns: _euserv_domain_orders + + _debug "get domain_orders" + + xml_content=$(printf ' + + domain.get_domain_orders + + + + + + login + %s + + + password + %s + + + + + + ' "$EUSERV_Username" "$EUSERV_Password") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error could not get domain orders" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + + _euserv_domain_orders="$response" + return 0 +} + +_euserv_get_domain_id() { +# returns: _euserv_domain_id + domain=$1 + _debug "get domain_id" + + _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1 ) + _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/' ) + + if [ -z "$_euserv_domain_id" ] ; then + _err "Could not find domain_id for domain $domain" + _debug "_euserv_domain_orders" "$_euserv_domain_orders" + return 1 + fi + return 0 + +} + +_get_root() { + domain=$1 + _debug "get root" + + # Just to read the domain_orders once + + domain=$1 + i=2 + p=1 + _euserv_get_domain_orders + response="$_euserv_domain_orders" + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "$h"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + if ! _euserv_get_domain_id "$_domain"; then + _err "invalid domain" + return 1 + fi + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 + +} + +# TODO +_euserv_delete_record() { + record_id=$1 + xml_content=$(printf ' + + domain.dns_delete_record + + + + + + login + + %s + + + + password + + %s + + + + dns_record_id + + %s + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$record_id") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error deleting record" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + + return 0 + +} + +_euserv_add_record() { + domain=$1 + sub_domain=$2 + txtval=$3 + + xml_content=$(printf ' + + domain.dns_create_record + + + + + + login + + %s + + + + password + + %s + + + domain_id + + %s + + + + dns_record_subdomain + + %s + + + + dns_record_type + + TXT + + + + dns_record_value + + %s + + + + dns_record_ttl + + 300 + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id" "$sub_domain" "$txtval" ) + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error could not create record" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi +# _dns_record_id="$(echo "$response" | _egrep_o "[\s\S]dns_record_id<\/name>[\s]*?[\s]*?(\K\d*)")" +# _debug "_dns_record_id" "$_dns_record_id" + return 0 +} From 94f91ae6878f8652cc947a98aa7b78dd42334c0c Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 8 Jul 2018 16:04:18 +0200 Subject: [PATCH 096/280] initial version with Euserv.eu DNS API Support - added dnsapi/dns_euserv.sh - modified dnsapi/README.md --- dnsapi/README.md | 25 ++- dnsapi/dns_euserv.sh | 358 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 382 insertions(+), 1 deletion(-) create mode 100644 dnsapi/dns_euserv.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index ef6c9d0..9f60764 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -876,6 +876,29 @@ acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com ``` The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed. +## 47. euserv.eu API to automatically issue cert + +First you need to login to your euserv.eu account to activate your API Administration (API Verwaltung). +[https://support.euserv.com](https://support.euserv.com) + +Once you've activate, login to your API Admin Interface and create an Account. +Please specify the scope (active groups: domain) and assign the allowed IPs. + +Be aware to use the `--insecure` flag, cause euserv.eu is still using self-signed certificates! + +``` +export EUSERV_Username="99999.user123" +export EUSERV_Password="Asbe54gHde" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_euserv -d example.com -d *.example.com --insecure +``` + +The `EUSERV_Username` and `EUSERV_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +Please report any issues to https://github.com/initit/acme.sh or to # Use custom API If your API is not supported yet, you can write your own DNS API. @@ -896,4 +919,4 @@ See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide # Use lexicon DNS API -https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api +https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api \ No newline at end of file diff --git a/dnsapi/dns_euserv.sh b/dnsapi/dns_euserv.sh new file mode 100644 index 0000000..1a58df5 --- /dev/null +++ b/dnsapi/dns_euserv.sh @@ -0,0 +1,358 @@ +#!/usr/bin/env sh + +#This is the euserv.eu api wrapper for acme.sh +# +#Author: Michael Brueckner +#Report Bugs: https://www.github.com/initit/acme.sh or mbr@initit.de + +# +#EUSERV_Username="username" +# +#EUSERV_Password="password" +# +# Dependencies: +# ------------- +# - none - + +EUSERV_Api="https://api.euserv.net" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_euserv_add() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + EUSERV_Username="${EUSERV_Username:-$(_readaccountconf_mutable EUSERV_Username)}" + EUSERV_Password="${EUSERV_Password:-$(_readaccountconf_mutable EUSERV_Password)}" + if [ -z "$EUSERV_Username" ] || [ -z "$EUSERV_Password" ]; then + EUSERV_Username="" + EUSERV_Password="" + _err "You don't specify euserv user and password yet." + _err "Please create your key and try again." + return 1 + fi + + #save the user and email to the account conf file. + _saveaccountconf_mutable EUSERV_Username "$EUSERV_Username" + _saveaccountconf_mutable EUSERV_Password "$EUSERV_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue" + +} + +#fulldomain txtvalue +dns_euserv_rm() { + + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + EUSERV_Username="${EUSERV_Username:-$(_readaccountconf_mutable EUSERV_Username)}" + EUSERV_Password="${EUSERV_Password:-$(_readaccountconf_mutable EUSERV_Password)}" + if [ -z "$EUSERV_Username" ] || [ -z "$EUSERV_Password" ]; then + EUSERV_Username="" + EUSERV_Password="" + _err "You don't specify euserv user and password yet." + _err "Please create your key and try again." + return 1 + fi + + #save the user and email to the account conf file. + _saveaccountconf_mutable EUSERV_Username "$EUSERV_Username" + _saveaccountconf_mutable EUSERV_Password "$EUSERV_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug "_sub_domain" "$_sub_domain" + _debug "_domain" "$_domain" + + _debug "Getting txt records" + + xml_content=$(printf ' + + domain.dns_get_active_records + + + + + + login + + %s + + + + password + + %s + + + + domain_id + + %s + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error could not get txt records" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + +# _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1 ) +# _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/' ) + + if ! printf "%s" "$response" | grep '>dns_record_content<.*>'"$txtvalue"'<' >/dev/null; then + _info "Do not need to delete record" + else + # find block where txtvalue is in. the record_id is allways prior this line! + _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1 ) + # record_id is the last entry with a number, identified by the postfix of + _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/' ) + _info "Deleting record" + _euserv_delete_record "$_record_id" + fi + +} + +#################### Private functions below ################################## + +_euserv_get_domain_orders() { +# returns: _euserv_domain_orders + + _debug "get domain_orders" + + xml_content=$(printf ' + + domain.get_domain_orders + + + + + + login + %s + + + password + %s + + + + + + ' "$EUSERV_Username" "$EUSERV_Password") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error could not get domain orders" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + + _euserv_domain_orders="$response" + return 0 +} + +_euserv_get_domain_id() { +# returns: _euserv_domain_id + domain=$1 + _debug "get domain_id" + + _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1 ) + _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/' ) + + if [ -z "$_euserv_domain_id" ] ; then + _err "Could not find domain_id for domain $domain" + _debug "_euserv_domain_orders" "$_euserv_domain_orders" + return 1 + fi + return 0 + +} + +_get_root() { + domain=$1 + _debug "get root" + + # Just to read the domain_orders once + + domain=$1 + i=2 + p=1 + _euserv_get_domain_orders + response="$_euserv_domain_orders" + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "$h"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + if ! _euserv_get_domain_id "$_domain"; then + _err "invalid domain" + return 1 + fi + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 + +} + +# TODO +_euserv_delete_record() { + record_id=$1 + xml_content=$(printf ' + + domain.dns_delete_record + + + + + + login + + %s + + + + password + + %s + + + + dns_record_id + + %s + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$record_id") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error deleting record" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + + return 0 + +} + +_euserv_add_record() { + domain=$1 + sub_domain=$2 + txtval=$3 + + xml_content=$(printf ' + + domain.dns_create_record + + + + + + login + + %s + + + + password + + %s + + + domain_id + + %s + + + + dns_record_subdomain + + %s + + + + dns_record_type + + TXT + + + + dns_record_value + + %s + + + + dns_record_ttl + + 300 + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id" "$sub_domain" "$txtval" ) + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error could not create record" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi +# _dns_record_id="$(echo "$response" | _egrep_o "[\s\S]dns_record_id<\/name>[\s]*?[\s]*?(\K\d*)")" +# _debug "_dns_record_id" "$_dns_record_id" + return 0 +} From d99968ee6d39c759909c8742592c349a00f336fd Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 8 Jul 2018 16:25:35 +0200 Subject: [PATCH 097/280] Modified dnsapi/README.md --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 9f60764..49f2625 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -878,10 +878,10 @@ acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed. ## 47. euserv.eu API to automatically issue cert -First you need to login to your euserv.eu account to activate your API Administration (API Verwaltung). +First you need to login to your euserv.eu account and activate your API Administration (API Verwaltung). [https://support.euserv.com](https://support.euserv.com) -Once you've activate, login to your API Admin Interface and create an Account. +Once you've activate, login to your API Admin Interface and create an API account. Please specify the scope (active groups: domain) and assign the allowed IPs. Be aware to use the `--insecure` flag, cause euserv.eu is still using self-signed certificates! From 616b0b6baa0eb08670ac0876f6b74a7627076629 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 8 Jul 2018 22:50:52 +0200 Subject: [PATCH 098/280] fixed shfmt related errors in dns_euserv.sh and modified README.md --- README.md | 1 + dnsapi/README.md | 6 +- dnsapi/dns_euserv.sh | 142 +++++++++++++++++++++---------------------- 3 files changed, 74 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index f395e49..bda7252 100644 --- a/README.md +++ b/README.md @@ -320,6 +320,7 @@ You don't have to do anything manually! 1. Loopia.se API 1. acme-dns (https://github.com/joohoi/acme-dns) 1. TELE3 (https://www.tele3.cz) +1. EUSERV.EU (https://www.euserv.eu) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 49f2625..1f394f9 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -876,7 +876,7 @@ acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com ``` The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed. -## 47. euserv.eu API to automatically issue cert +## 47. Use Euserv.eu API First you need to login to your euserv.eu account and activate your API Administration (API Verwaltung). [https://support.euserv.com](https://support.euserv.com) @@ -884,14 +884,12 @@ First you need to login to your euserv.eu account and activate your API Administ Once you've activate, login to your API Admin Interface and create an API account. Please specify the scope (active groups: domain) and assign the allowed IPs. -Be aware to use the `--insecure` flag, cause euserv.eu is still using self-signed certificates! - ``` export EUSERV_Username="99999.user123" export EUSERV_Password="Asbe54gHde" ``` -Ok, let's issue a cert now: +Ok, let's issue a cert now: (Be aware to use the `--insecure` flag, cause euserv.eu is still using self-signed certificates!) ``` acme.sh --issue --dns dns_euserv -d example.com -d *.example.com --insecure ``` diff --git a/dnsapi/dns_euserv.sh b/dnsapi/dns_euserv.sh index 1a58df5..cb1e0a4 100644 --- a/dnsapi/dns_euserv.sh +++ b/dnsapi/dns_euserv.sh @@ -42,11 +42,12 @@ dns_euserv_add() { _err "invalid domain" return 1 fi - _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - + _debug "_sub_domain" "$_sub_domain" + _debug "_domain" "$_domain" _info "Adding record" - _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue" + if ! _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue"; then + return 1 + fi } @@ -114,24 +115,20 @@ dns_euserv_rm() { export _H1="Content-Type: text/xml" response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" - ok="$(printf '%s' "$response" | grep "status100")" - if [ -z "$ok" ]; then - _err "Error could not get txt records" + if ! _contains "$response" "status100"; then + _err "Error could not get txt records" _debug "xml_content" "$xml_content" _debug "response" "$response" return 1 fi -# _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1 ) -# _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/' ) - if ! printf "%s" "$response" | grep '>dns_record_content<.*>'"$txtvalue"'<' >/dev/null; then _info "Do not need to delete record" else - # find block where txtvalue is in. the record_id is allways prior this line! - _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1 ) - # record_id is the last entry with a number, identified by the postfix of - _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/' ) + # find XML block where txtvalue is in. The record_id is allways prior this line! + _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1 ) + # record_id is the last Tag with a number before the row _endLine, identified by + _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/' ) _info "Deleting record" _euserv_delete_record "$_record_id" fi @@ -140,11 +137,52 @@ dns_euserv_rm() { #################### Private functions below ################################## +_get_root() { + domain=$1 + _debug "get root" + + # Just to read the domain_orders once + + domain=$1 + i=2 + p=1 + + if ! _euserv_get_domain_orders; then + return 1 + fi + + # Get saved response with domain_orders + response="$_euserv_domain_orders" + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "$h"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + if ! _euserv_get_domain_id "$_domain"; then + _err "invalid domain" + return 1 + fi + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + _euserv_get_domain_orders() { -# returns: _euserv_domain_orders + # returns: _euserv_domain_orders _debug "get domain_orders" - + xml_content=$(printf ' domain.get_domain_orders @@ -165,76 +203,41 @@ _euserv_get_domain_orders() { ' "$EUSERV_Username" "$EUSERV_Password") - + export _H1="Content-Type: text/xml" response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" - - ok="$(printf '%s' "$response" | grep "status100")" - if [ -z "$ok" ]; then + + if ! _contains "$response" "status100"; then _err "Error could not get domain orders" _debug "xml_content" "$xml_content" _debug "response" "$response" return 1 fi - + + # save response to reduce API calls _euserv_domain_orders="$response" return 0 } _euserv_get_domain_id() { -# returns: _euserv_domain_id + # returns: _euserv_domain_id domain=$1 _debug "get domain_id" - _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1 ) - _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/' ) + # find line where the domain name is within the $response + _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1) + # next occurency of domain_id after the domain_name is the correct one + _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/') - if [ -z "$_euserv_domain_id" ] ; then + if [ -z "$_euserv_domain_id" ]; then _err "Could not find domain_id for domain $domain" _debug "_euserv_domain_orders" "$_euserv_domain_orders" return 1 fi - return 0 - -} - -_get_root() { - domain=$1 - _debug "get root" - - # Just to read the domain_orders once - - domain=$1 - i=2 - p=1 - _euserv_get_domain_orders - response="$_euserv_domain_orders" - - while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - _debug h "$h" - if [ -z "$h" ]; then - #not valid - return 1 - fi - - if _contains "$response" "$h"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _domain="$h" - if ! _euserv_get_domain_id "$_domain"; then - _err "invalid domain" - return 1 - fi - return 0 - fi - p=$i - i=$(_math "$i" + 1) - done - return 1 + return 0 } -# TODO _euserv_delete_record() { record_id=$1 xml_content=$(printf ' @@ -271,14 +274,13 @@ _euserv_delete_record() { export _H1="Content-Type: text/xml" response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" - ok="$(printf '%s' "$response" | grep "status100")" - if [ -z "$ok" ]; then + if ! _contains "$response" "status100"; then _err "Error deleting record" _debug "xml_content" "$xml_content" _debug "response" "$response" return 1 fi - + return 0 } @@ -340,19 +342,17 @@ _euserv_add_record() { - ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id" "$sub_domain" "$txtval" ) + ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id" "$sub_domain" "$txtval") export _H1="Content-Type: text/xml" response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" - ok="$(printf '%s' "$response" | grep "status100")" - if [ -z "$ok" ]; then + if ! _contains "$response" "status100"; then _err "Error could not create record" _debug "xml_content" "$xml_content" _debug "response" "$response" return 1 fi -# _dns_record_id="$(echo "$response" | _egrep_o "[\s\S]dns_record_id<\/name>[\s]*?[\s]*?(\K\d*)")" -# _debug "_dns_record_id" "$_dns_record_id" + return 0 } From 261cc448f78729ec52992b9a010e7eb32daca0e1 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 8 Jul 2018 23:00:26 +0200 Subject: [PATCH 099/280] fixed shfmt related errors in dns_euserv.sh and modified README.md --- dnsapi/dns_euserv.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_euserv.sh b/dnsapi/dns_euserv.sh index cb1e0a4..44120a3 100644 --- a/dnsapi/dns_euserv.sh +++ b/dnsapi/dns_euserv.sh @@ -43,10 +43,10 @@ dns_euserv_add() { return 1 fi _debug "_sub_domain" "$_sub_domain" - _debug "_domain" "$_domain" + _debug "_domain" "$_domain" _info "Adding record" - if ! _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue"; then - return 1 + if ! _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue"; then + return 1 fi } @@ -80,7 +80,7 @@ dns_euserv_rm() { _debug "_domain" "$_domain" _debug "Getting txt records" - + xml_content=$(printf ' domain.dns_get_active_records @@ -111,7 +111,7 @@ dns_euserv_rm() { ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id") - + export _H1="Content-Type: text/xml" response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" @@ -126,9 +126,9 @@ dns_euserv_rm() { _info "Do not need to delete record" else # find XML block where txtvalue is in. The record_id is allways prior this line! - _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1 ) + _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1) # record_id is the last Tag with a number before the row _endLine, identified by - _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/' ) + _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/') _info "Deleting record" _euserv_delete_record "$_record_id" fi @@ -168,7 +168,7 @@ _get_root() { if ! _euserv_get_domain_id "$_domain"; then _err "invalid domain" return 1 - fi + fi return 0 fi p=$i @@ -343,7 +343,7 @@ _euserv_add_record() { ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id" "$sub_domain" "$txtval") - + export _H1="Content-Type: text/xml" response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" From 2945b230e4dd4c03de5c48f1f65ca07fe45045fd Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 9 Jul 2018 22:54:34 +0200 Subject: [PATCH 100/280] replaced tail/head with _tail_n/_head_n and printf with echo --- dnsapi/dns_euserv.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_euserv.sh b/dnsapi/dns_euserv.sh index 44120a3..3810156 100644 --- a/dnsapi/dns_euserv.sh +++ b/dnsapi/dns_euserv.sh @@ -122,13 +122,13 @@ dns_euserv_rm() { return 1 fi - if ! printf "%s" "$response" | grep '>dns_record_content<.*>'"$txtvalue"'<' >/dev/null; then + if ! echo "$response" | grep '>dns_record_content<.*>'"$txtvalue"'<' >/dev/null; then _info "Do not need to delete record" else # find XML block where txtvalue is in. The record_id is allways prior this line! - _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1) + _endLine=$(echo "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1) # record_id is the last Tag with a number before the row _endLine, identified by - _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/') + _record_id=$(echo "$response" | sed -n '1,'"$_endLine"'p' | grep '' | _tail_n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/') _info "Deleting record" _euserv_delete_record "$_record_id" fi @@ -155,7 +155,7 @@ _get_root() { response="$_euserv_domain_orders" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(echo "$domain" | cut -d . -f $i-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -163,7 +163,7 @@ _get_root() { fi if _contains "$response" "$h"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(echo "$domain" | cut -d . -f 1-$p) _domain="$h" if ! _euserv_get_domain_id "$_domain"; then _err "invalid domain" @@ -225,9 +225,9 @@ _euserv_get_domain_id() { _debug "get domain_id" # find line where the domain name is within the $response - _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1) + _startLine=$(echo "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1) # next occurency of domain_id after the domain_name is the correct one - _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/') + _euserv_domain_id=$(echo "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | _head_n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/') if [ -z "$_euserv_domain_id" ]; then _err "Could not find domain_id for domain $domain" From 9cecd525e20cec8500e33629690fefd8182006d8 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 18 Jul 2018 00:26:21 +0800 Subject: [PATCH 101/280] fix JWS has an invalid anti-replay nonce https://github.com/Neilpang/acme.sh/issues/1630 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 713170b..c23942f 100755 --- a/acme.sh +++ b/acme.sh @@ -1607,7 +1607,7 @@ _inithttp() { } -# body url [needbase64] [POST|PUT] [ContentType] +# body url [needbase64] [POST|PUT|DELETE] [ContentType] _post() { body="$1" _post_url="$2" @@ -1897,7 +1897,7 @@ _send_signed_request() { _debug3 _body "$_body" fi - if _contains "$_body" "JWS has invalid anti-replay nonce"; then + if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then _info "It seems the CA server is busy now, let's wait and retry." _sleep 5 continue From b9b703238670f646c6e7f20637715a74b93f52c1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 18 Jul 2018 00:33:07 +0800 Subject: [PATCH 102/280] lets start v2.8.0 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index c23942f..8fd321b 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.9 +VER=2.8.0 PROJECT_NAME="acme.sh" From 411b342a2758c4a2e75b519453fcd8be3730f78d Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 18 Jul 2018 22:00:09 +0800 Subject: [PATCH 103/280] request a new nonce for invalid anti-replay nonce error --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index 8fd321b..43b3f63 100755 --- a/acme.sh +++ b/acme.sh @@ -1899,6 +1899,7 @@ _send_signed_request() { if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then _info "It seems the CA server is busy now, let's wait and retry." + _CACHED_NONCE="" _sleep 5 continue fi From 8d230dd798f2b25cfa37761ebc20591f57ebad1c Mon Sep 17 00:00:00 2001 From: Old?ich Jedli?ka Date: Tue, 24 Jul 2018 15:39:48 +0200 Subject: [PATCH 104/280] Added dns_lexicon_rm command. Remove created TXT record when finished. Works with lexicon version 2.3.0 and later. --- dnsapi/dns_lexicon.sh | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index c09f16f..9c0f986 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -7,15 +7,7 @@ lexicon_cmd="lexicon" wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api" -######## Public functions ##################### - -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_lexicon_add() { - fulldomain=$1 - txtvalue=$2 - - domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999) - +_initLexicon() { if ! _exists "$lexicon_cmd"; then _err "Please install $lexicon_cmd first: $wiki" return 1 @@ -66,13 +58,36 @@ dns_lexicon_add() { eval export "$Lx_domaintoken" _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v" fi +} + +######## Public functions ##################### + +#Usage: dns_lexicon_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_lexicon_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _initLexicon; then + return 1 + fi + + domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999) $lexicon_cmd "$PROVIDER" create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" } -#fulldomain +#Usage: dns_lexicon_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_lexicon_rm() { fulldomain=$1 + txtvalue=$2 + + if ! _initLexicon; then + return 1 + fi + + domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999) + + $lexicon_cmd "$PROVIDER" delete "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" } From 0366e8758cb908eb1224fd346b06d3973611799b Mon Sep 17 00:00:00 2001 From: Old?ich Jedli?ka Date: Tue, 24 Jul 2018 22:14:39 +0200 Subject: [PATCH 105/280] Added reading of stored config. --- dnsapi/dns_lexicon.sh | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index 9c0f986..4ec1631 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -7,12 +7,13 @@ lexicon_cmd="lexicon" wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api" -_initLexicon() { +_lexicon_init() { if ! _exists "$lexicon_cmd"; then _err "Please install $lexicon_cmd first: $wiki" return 1 fi + PROVIDER="${PROVIDER:-$(_readdomainconf PROVIDER)}" if [ -z "$PROVIDER" ]; then PROVIDER="" _err "Please define env PROVIDER first: $wiki" @@ -25,38 +26,42 @@ _initLexicon() { # e.g. busybox-ash does not know [:upper:] # shellcheck disable=SC2018,SC2019 Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z') + eval $Lx_name="\${$Lx_name:-$(_readaccountconf_mutable $Lx_name)}" Lx_name_v=$(eval echo \$"$Lx_name") _secure_debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then - _saveaccountconf "$Lx_name" "$Lx_name_v" + _saveaccountconf_mutable "$Lx_name" "$Lx_name_v" eval export "$Lx_name" fi # shellcheck disable=SC2018,SC2019 Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z') + eval $Lx_token="\${$Lx_token:-$(_readaccountconf_mutable $Lx_token)}" Lx_token_v=$(eval echo \$"$Lx_token") _secure_debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then - _saveaccountconf "$Lx_token" "$Lx_token_v" + _saveaccountconf_mutable "$Lx_token" "$Lx_token_v" eval export "$Lx_token" fi # shellcheck disable=SC2018,SC2019 Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z') + eval $Lx_password="\${$Lx_password:-$(_readaccountconf_mutable $Lx_password)}" Lx_password_v=$(eval echo \$"$Lx_password") _secure_debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then - _saveaccountconf "$Lx_password" "$Lx_password_v" + _saveaccountconf_mutable "$Lx_password" "$Lx_password_v" eval export "$Lx_password" fi # shellcheck disable=SC2018,SC2019 Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z') + eval $Lx_domaintoken="\${$Lx_domaintoken:-$(_readaccountconf_mutable $Lx_domaintoken)}" Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") _secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then + _saveaccountconf_mutable "$Lx_domaintoken" "$Lx_domaintoken_v" eval export "$Lx_domaintoken" - _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v" fi } @@ -67,7 +72,7 @@ dns_lexicon_add() { fulldomain=$1 txtvalue=$2 - if ! _initLexicon; then + if ! _lexicon_init; then return 1 fi @@ -82,7 +87,7 @@ dns_lexicon_rm() { fulldomain=$1 txtvalue=$2 - if ! _initLexicon; then + if ! _lexicon_init; then return 1 fi From cb11580981bf67058257da90a165a441558f0ac1 Mon Sep 17 00:00:00 2001 From: Jesse Miller Date: Tue, 24 Jul 2018 22:32:38 -0500 Subject: [PATCH 106/280] BSD fix _time2str() date -u -d@"12345" does not produce an error on *BSD and outputs the current date in UTC, which is not the expected output from _time2str() Fix, reorder _time2str() to attempt BSD style date first, which errors on Linux, so cascade style OS detection works correctly. --- acme.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 43b3f63..69584cc 100755 --- a/acme.sh +++ b/acme.sh @@ -1374,17 +1374,17 @@ _url_replace() { } _time2str() { - #Linux - if date -u -d@"$1" 2>/dev/null; then + #BSD + if date -u -r "$1" 2>/dev/null; then return fi - #BSD - if date -u -r "$1" 2>/dev/null; then + #Linux + if date -u -d@"$1" 2>/dev/null; then return fi - #Soaris + #Solaris if _exists adb; then _t_s_a=$(echo "0t${1}=Y" | adb) echo "$_t_s_a" From 436940285594dd9397161d5ca16f6e3973b4312c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Old=C5=99ich=20Jedli=C4=8Dka?= Date: Wed, 25 Jul 2018 10:40:57 +0200 Subject: [PATCH 107/280] Cleaned-up shellcheck warnings. --- dnsapi/dns_lexicon.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index 4ec1631..ab180fb 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -26,7 +26,7 @@ _lexicon_init() { # e.g. busybox-ash does not know [:upper:] # shellcheck disable=SC2018,SC2019 Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z') - eval $Lx_name="\${$Lx_name:-$(_readaccountconf_mutable $Lx_name)}" + eval "$Lx_name=\${$Lx_name:-$(_readaccountconf_mutable "$Lx_name")}" Lx_name_v=$(eval echo \$"$Lx_name") _secure_debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then @@ -36,7 +36,7 @@ _lexicon_init() { # shellcheck disable=SC2018,SC2019 Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z') - eval $Lx_token="\${$Lx_token:-$(_readaccountconf_mutable $Lx_token)}" + eval "$Lx_token=\${$Lx_token:-$(_readaccountconf_mutable "$Lx_token")}" Lx_token_v=$(eval echo \$"$Lx_token") _secure_debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then @@ -46,7 +46,7 @@ _lexicon_init() { # shellcheck disable=SC2018,SC2019 Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z') - eval $Lx_password="\${$Lx_password:-$(_readaccountconf_mutable $Lx_password)}" + eval "$Lx_password=\${$Lx_password:-$(_readaccountconf_mutable "$Lx_password")}" Lx_password_v=$(eval echo \$"$Lx_password") _secure_debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then @@ -56,7 +56,7 @@ _lexicon_init() { # shellcheck disable=SC2018,SC2019 Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z') - eval $Lx_domaintoken="\${$Lx_domaintoken:-$(_readaccountconf_mutable $Lx_domaintoken)}" + eval "$Lx_domaintoken=\${$Lx_domaintoken:-$(_readaccountconf_mutable "$Lx_domaintoken")}" Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") _secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then From cc2d59468d69ed40527113d99f0aee275a72885d Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 26 Jul 2018 21:57:22 +0800 Subject: [PATCH 108/280] use json content type for both v1 and v2 --- acme.sh | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 69584cc..bd0c390 100755 --- a/acme.sh +++ b/acme.sh @@ -1795,11 +1795,8 @@ _send_signed_request() { return 1 fi - if [ "$ACME_VERSION" = "2" ]; then - __request_conent_type="$CONTENT_TYPE_JSON" - else - __request_conent_type="" - fi + __request_conent_type="$CONTENT_TYPE_JSON" + payload64=$(printf "%s" "$payload" | _base64 | _url_replace) _debug3 payload64 "$payload64" From d3c9d0b331b2c49327e5a4c6d3d54839e69aecd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Thu, 26 Jul 2018 19:59:15 +0200 Subject: [PATCH 109/280] Fix inwx account without Mobile TAN --- dnsapi/dns_inwx.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index cd5af91..f4590cf 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -158,7 +158,8 @@ _inwx_login() { export _H1 #https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71 - if _contains "$response" "tfa"; then + if _contains "$response" "code1000" \ + && _contains "$response" "tfaGOOGLE-AUTH"; then if [ -z "$INWX_Shared_Secret" ]; then _err "Mobile TAN detected." _err "Please define a shared secret." From 709a3fb06fceaa2f26655b5b1b64aabe51f22446 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 28 Jul 2018 22:02:03 +0800 Subject: [PATCH 110/280] add more retry for badnonce error --- acme.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index bd0c390..32219d9 100755 --- a/acme.sh +++ b/acme.sh @@ -1800,7 +1800,8 @@ _send_signed_request() { payload64=$(printf "%s" "$payload" | _base64 | _url_replace) _debug3 payload64 "$payload64" - MAX_REQUEST_RETRY_TIMES=5 + MAX_REQUEST_RETRY_TIMES=20 + _sleep_retry_sec=1 _request_retry_times=0 while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _request_retry_times=$(_math "$_request_retry_times" + 1) @@ -1895,9 +1896,9 @@ _send_signed_request() { fi if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then - _info "It seems the CA server is busy now, let's wait and retry." + _info "It seems the CA server is busy now, let's wait and retry. Sleeping $_sleep_retry_sec seconds." _CACHED_NONCE="" - _sleep 5 + _sleep $_sleep_retry_sec continue fi break From 86276ad17b50227b9b9d7f2d72abd7cdf22f19a8 Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Wed, 1 Aug 2018 16:37:08 +0200 Subject: [PATCH 111/280] added hosting.de DNS Plugin * can be used with API of hosting.de * can also be used with ICANN registrar http.net * needs just API key and endpoint * support wildcard certificates --- dnsapi/dns_hostingde.sh | 110 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 dnsapi/dns_hostingde.sh diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh new file mode 100644 index 0000000..a6abc42 --- /dev/null +++ b/dnsapi/dns_hostingde.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env sh + +# hosting.de API + +# Values to export: +# export HOSTINGDE_ENDPOINT='https://secure.hosting.de' +# export HOSTINGDE_APIKEY='xxxxx' + + +######## Public functions ##################### + +dns_hostingde_add() { + fulldomain="${1}" + txtvalue="${2}" + _debug "Calling: _hostingde_addRecord() '${fulldomain}' '${txtvalue}'" + _hostingde_apiKey && _hostingde_getZoneConfig && _hostingde_addRecord +} + +dns_hostingde_rm() { + fulldomain="${1}" + txtvalue="${2}" + _debug "Calling: _hostingde_removeRecord() '${fulldomain}' '${txtvalue}'" + _hostingde_apiKey && _hostingde_getZoneConfig && _hostingde_removeRecord +} + +#################### own Private functions below ################################## + +_hostingde_apiKey() { + HOSTINGDE_APIKEY="${HOSTINGDE_APIKEY:-$(_readaccountconf_mutable HOSTINGDE_APIKEY)}" + if [ -z "$HOSTINGDE_APIKEY" ] || [ -z "$HOSTINGDE_ENDPOINT" ]; then + HOSTINGDE_APIKEY="" + HOSTINGDE_ENDPOINT="" + _err "You haven't specified hosting.de API key or endpoint yet." + _err "Please create your key and try again." + return 1 + fi + + _saveaccountconf_mutable HOSTINGDE_APIKEY "$HOSTINGDE_APIKEY" + _saveaccountconf_mutable HOSTINGDE_ENDPOINT "$HOSTINGDE_ENDPOINT" +} + +_hostingde_getZoneConfig() { + _info "Getting ZoneConfig" + curZone="${fulldomain#*.}" + returnCode=1 + while _contains "${curZone}" "\\."; do + curData="{\"filter\":{\"field\":\"zoneName\",\"value\":\"${curZone}\"},\"limit\":1,\"authToken\":\"${HOSTINGDE_APIKEY}\"}" + curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneConfigsFind")" + _debug "Calling zoneConfigsFind: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneConfigsFind'" + _debug "Result of zoneConfigsFind: '$curResult'" + if _contains "${curResult}" '"status": "error"'; then + if _contains "${curResult}" '"code": 10109'; then + _err "The API-Key is invalid or could not be found" + else + _err "UNKNOWN API ERROR" + fi + returnCode=1 + break; + fi + if _contains "${curResult}" '"totalEntries": 1'; then + _info "Retrieved zone data." + _debug "Zone data: '${curResult}'" + + # read ZoneConfigId for later update + zoneConfigId=$(echo "${curResult}" | _egrep_o '"id":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + _debug "zoneConfigId '${zoneConfigId}'" + returnCode=0 + break + fi + curZone="${curZone#*.}" + done + if [ $returnCode -ne 0 ]; then + _info "ZoneEnd reached, Zone ${curZone} not found in hosting.de API" + fi + return $returnCode +} + +_hostingde_addRecord() { + _info "Adding record to zone" + curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\"},\"recordsToAdd\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\",\"ttl\":3600}]}" + curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")" + _debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'" + _debug "Result of zoneUpdate: '$curResult'" + if _contains "${curResult}" '"status": "error"'; then + if _contains "${curResult}" '"code": 10109'; then + _err "The API-Key is invalid or could not be found" + else + _err "UNKNOWN API ERROR" + fi + return 1 + fi + return 0 +} + +_hostingde_removeRecord() { + _info "Removing record from zone" + curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\"},\"recordsToDelete\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\"}]}" + curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")" + _debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'" + _debug "Result of zoneUpdate: '$curResult'" + if _contains "${curResult}" '"status": "error"'; then + if _contains "${curResult}" '"code": 10109'; then + _err "The API-Key is invalid or could not be found" + else + _err "UNKNOWN API ERROR" + fi + return 1 + fi + return 0 +} From 5494e88e08f22400ed7fabc3c9f445eca85334e5 Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Wed, 1 Aug 2018 17:00:22 +0200 Subject: [PATCH 112/280] making shfmt happy --- dnsapi/dns_hostingde.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index a6abc42..39bcfb6 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -6,7 +6,6 @@ # export HOSTINGDE_ENDPOINT='https://secure.hosting.de' # export HOSTINGDE_APIKEY='xxxxx' - ######## Public functions ##################### dns_hostingde_add() { @@ -55,7 +54,7 @@ _hostingde_getZoneConfig() { _err "UNKNOWN API ERROR" fi returnCode=1 - break; + break fi if _contains "${curResult}" '"totalEntries": 1'; then _info "Retrieved zone data." @@ -70,7 +69,7 @@ _hostingde_getZoneConfig() { curZone="${curZone#*.}" done if [ $returnCode -ne 0 ]; then - _info "ZoneEnd reached, Zone ${curZone} not found in hosting.de API" + _info "ZoneEnd reached, Zone ${curZone} not found in hosting.de API" fi return $returnCode } From 63134fafece3f9ffb5092b2d897e38366072d64d Mon Sep 17 00:00:00 2001 From: little-fat Date: Thu, 2 Aug 2018 20:57:27 +0800 Subject: [PATCH 113/280] Fix key leakage in SSH deploy log --- deploy/ssh.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deploy/ssh.sh b/deploy/ssh.sh index a68da35..9cb0af9 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -11,7 +11,7 @@ # # Only a username is required. All others are optional. # -# The following examples are for QNAP NAS running QTS 4.2 +# The following examples are for QNAP NAS running QTS 4.2 # export DEPLOY_SSH_CMD="" # defaults to ssh # export DEPLOY_SSH_USER="admin" # required # export DEPLOY_SSH_SERVER="qnap" # defaults to domain name @@ -101,7 +101,7 @@ ssh_deploy() { fi # CERTFILE is optional. - # If provided then private key will be copied or appended to provided filename. + # If provided then certificate will be copied or appended to provided filename. if [ -n "$DEPLOY_SSH_CERTFILE" ]; then Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE" _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile" @@ -190,7 +190,7 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d _info "Backup directories erased after 180 days." fi - _debug "Remote commands to execute: $_cmdstr" + _secure_debug "Remote commands to execute: " "$_cmdstr" _info "Submitting sequence of commands to remote server by ssh" # quotations in bash cmd below intended. Squash travis spellcheck error # shellcheck disable=SC2029 From 4162975f9f2db76fbc5fcfbdaa3bea5f0df6e9cc Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Thu, 2 Aug 2018 15:43:40 +0200 Subject: [PATCH 114/280] added hosting.de API to README's --- README.md | 1 + dnsapi/README.md | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/README.md b/README.md index c8bebc6..614476a 100644 --- a/README.md +++ b/README.md @@ -321,6 +321,7 @@ You don't have to do anything manually! 1. acme-dns (https://github.com/joohoi/acme-dns) 1. TELE3 (https://www.tele3.cz) 1. EUSERV.EU (https://www.euserv.eu) +1. hosting.de (https://www.hosting.de) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 1f394f9..bce0ffe 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -897,6 +897,29 @@ acme.sh --issue --dns dns_euserv -d example.com -d *.example.com --insecure The `EUSERV_Username` and `EUSERV_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. Please report any issues to https://github.com/initit/acme.sh or to +## 48. Use hosting.de API + +Create an API key in your hosting.de account here: https://secure.hosting.de + +The key needs the following rights: +- DNS_ZONES_EDIT +- DNS_ZONES_LIST + +Set your API Key and endpoint: + +``` +export HOSTINGDE_APIKEY="xxx" +export HOSTINGDE_ENDPOINT="https://secure.hosting.de" +``` + +The plugin can also be used for the http.net API. http.net customers have to set endpoint to https://partner.http.net. + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_hostingde -d example.com -d *.example.com +``` + +The hosting.de API key and endpoint will be saved in `~/.acme.sh/account.conf` and will be reused when needed. # Use custom API If your API is not supported yet, you can write your own DNS API. From ed95509a4f938737957c641a9c5257bda55a1540 Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Thu, 2 Aug 2018 15:47:02 +0200 Subject: [PATCH 115/280] hosting.de API keys can contain special chars, so using simple quotes --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index bce0ffe..01192b1 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -908,8 +908,8 @@ The key needs the following rights: Set your API Key and endpoint: ``` -export HOSTINGDE_APIKEY="xxx" -export HOSTINGDE_ENDPOINT="https://secure.hosting.de" +export HOSTINGDE_APIKEY='xxx' +export HOSTINGDE_ENDPOINT='https://secure.hosting.de' ``` The plugin can also be used for the http.net API. http.net customers have to set endpoint to https://partner.http.net. From 4fbd21da5788ce48874b483aaa57700a4520ea7f Mon Sep 17 00:00:00 2001 From: Gunnar Liljas Date: Tue, 7 Aug 2018 13:35:08 +0200 Subject: [PATCH 116/280] Spelling --- dnsapi/dns_aws.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 8ce7c34..2ad3c81 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -29,7 +29,7 @@ dns_aws_add() { if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then AWS_ACCESS_KEY_ID="" AWS_SECRET_ACCESS_KEY="" - _err "You don't specify aws route53 api key id and and api key secret yet." + _err "You haven't specifed the aws route53 api key id and and api key secret yet." _err "Please create your key and try again. see $(__green $AWS_WIKI)" return 1 fi @@ -62,7 +62,7 @@ dns_aws_add() { fi if [ "$_resource_record" ] && _contains "$response" "$txtvalue"; then - _info "The txt record already exists, skip" + _info "The TXT record already exists. Skipping." return 0 fi @@ -71,7 +71,7 @@ dns_aws_add() { _aws_tmpl_xml="UPSERT$fulldomainTXT300$_resource_record\"$txtvalue\"" if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then - _info "txt record updated success." + _info "TXT record updated successfully." return 0 fi @@ -99,7 +99,7 @@ dns_aws_rm() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _info "Geting existing records for $fulldomain" + _info "Getting existing records for $fulldomain" if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then return 1 fi @@ -108,14 +108,14 @@ dns_aws_rm() { _resource_record="$(echo "$response" | sed 's//"/g' | tr '"' "\n" | grep "$fulldomain." | _egrep_o "" | sed "s///" | sed "s###")" _debug "_resource_record" "$_resource_record" else - _debug "no records exists, skip" + _debug "no records exist, skip" return 0 fi _aws_tmpl_xml="DELETE$_resource_record$fulldomain.TXT300" if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then - _info "txt record deleted success." + _info "TXT record deleted successfully." return 0 fi @@ -163,7 +163,7 @@ _get_root() { _domain=$h return 0 fi - _err "Can not find domain id: $h" + _err "Can't find domain with id: $h" return 1 fi fi From 22cd408efbcbacb866987b866cdadc5c49f870e1 Mon Sep 17 00:00:00 2001 From: Hitoshi Date: Sun, 12 Aug 2018 18:15:20 +0800 Subject: [PATCH 117/280] add dns api support for dnspod.com --- README.md | 1 + dnsapi/README.md | 19 +++++- dnsapi/dns_dpi.sh | 161 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 1 deletion(-) create mode 100755 dnsapi/dns_dpi.sh diff --git a/README.md b/README.md index c8bebc6..e7c292c 100644 --- a/README.md +++ b/README.md @@ -321,6 +321,7 @@ You don't have to do anything manually! 1. acme-dns (https://github.com/joohoi/acme-dns) 1. TELE3 (https://www.tele3.cz) 1. EUSERV.EU (https://www.euserv.eu) +1. DNSPod.com API (https://www.dnspod.com) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 1f394f9..3fa0ab3 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -897,6 +897,23 @@ acme.sh --issue --dns dns_euserv -d example.com -d *.example.com --insecure The `EUSERV_Username` and `EUSERV_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. Please report any issues to https://github.com/initit/acme.sh or to + +## 48. Use DNSPod.com domain API to automatically issue cert + +First you need to get your API Key and ID by this [get-the-user-token](https://www.dnspod.com/docs/info.html#get-the-user-token). + +``` +export DPI_Id="1234" +export DPI_Key="sADDsdasdgdsf" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_dpi -d example.com -d www.example.com +``` + +The `DPI_Id` and `DPI_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. @@ -917,4 +934,4 @@ See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide # Use lexicon DNS API -https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api \ No newline at end of file +https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api diff --git a/dnsapi/dns_dpi.sh b/dnsapi/dns_dpi.sh new file mode 100755 index 0000000..831150a --- /dev/null +++ b/dnsapi/dns_dpi.sh @@ -0,0 +1,161 @@ +#!/usr/bin/env sh + +# Dnspod.com Domain api +# +#DPI_Id="1234" +# +#DPI_Key="sADDsdasdgdsf" + +REST_API="https://api.dnspod.com" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dpi_add() { + fulldomain=$1 + txtvalue=$2 + + DPI_Id="${DPI_Id:-$(_readaccountconf_mutable DPI_Id)}" + DPI_Key="${DPI_Key:-$(_readaccountconf_mutable DPI_Key)}" + if [ -z "$DPI_Id" ] || [ -z "$DPI_Key" ]; then + DPI_Id="" + DPI_Key="" + _err "You don't specify dnspod api key and key id yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable DPI_Id "$DPI_Id" + _saveaccountconf_mutable DPI_Key "$DPI_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + add_record "$_domain" "$_sub_domain" "$txtvalue" + +} + +#fulldomain txtvalue +dns_dpi_rm() { + fulldomain=$1 + txtvalue=$2 + + DPI_Id="${DPI_Id:-$(_readaccountconf_mutable DPI_Id)}" + DPI_Key="${DPI_Key:-$(_readaccountconf_mutable DPI_Key)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + if ! _rest POST "Record.List" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then + _err "Record.Lis error." + return 1 + fi + + if _contains "$response" 'No records'; then + _info "Don't need to remove." + return 0 + fi + + record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'"$txtvalue"'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \") + _debug record_id "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id." + return 1 + fi + + if ! _rest POST "Record.Remove" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then + _err "Record.Remove error." + return 1 + fi + + _contains "$response" "Action completed successful" + +} + +#add the txt record. +#usage: root sub txtvalue +add_record() { + root=$1 + sub=$2 + txtvalue=$3 + fulldomain="$sub.$root" + + _info "Adding record" + + if ! _rest POST "Record.Create" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=default"; then + return 1 + fi + + _contains "$response" "Action completed successful" || _contains "$response" "Domain record already exists" +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _rest POST "Domain.Info" "user_token=$DPI_Id,$DPI_Key&format=json&domain=$h"; then + return 1 + fi + + if _contains "$response" "Action completed successful"; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") + _debug _domain_id "$_domain_id" + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _debug _sub_domain "$_sub_domain" + _domain="$h" + _debug _domain "$_domain" + return 0 + fi + return 1 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +#Usage: method URI data +_rest() { + m="$1" + ep="$2" + data="$3" + _debug "$ep" + url="$REST_API/$ep" + + _debug url "$url" + + if [ "$m" = "GET" ]; then + response="$(_get "$url" | tr -d '\r')" + else + _debug2 data "$data" + response="$(_post "$data" "$url" | tr -d '\r')" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From 7aeb113c62dee96e259229028ed349828d982dac Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 14 Aug 2018 09:53:13 +0200 Subject: [PATCH 118/280] createDomainKey: fix exitcode for creating new key when running acme.sh headless (without terminal) to create a new key createDomainKey returns a non-zero exit-code. explicitly returning zero avoids this. --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index 32219d9..6eee183 100755 --- a/acme.sh +++ b/acme.sh @@ -1327,6 +1327,7 @@ createDomainKey() { if _createkey "$_cdl" "$CERT_KEY_PATH"; then _savedomainconf Le_Keylength "$_cdl" _info "The domain key is here: $(__green $CERT_KEY_PATH)" + return 0 fi else if [ "$IS_RENEW" ]; then From 0a3ac1f5c3f1ac55ad210344a02ad79a4a9abd50 Mon Sep 17 00:00:00 2001 From: Janos Lenart Date: Fri, 25 May 2018 18:56:07 +0100 Subject: [PATCH 119/280] Added support for Google Cloud DNS API (dns_gcloud) --- README.md | 1 + dnsapi/README.md | 21 ++++++ dnsapi/dns_gcloud.sh | 167 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100755 dnsapi/dns_gcloud.sh diff --git a/README.md b/README.md index c8bebc6..07fbc84 100644 --- a/README.md +++ b/README.md @@ -274,6 +274,7 @@ You don't have to do anything manually! ### Currently acme.sh supports: +1. Google Cloud DNS API 1. CloudFlare.com API 1. DNSPod.cn API 1. CloudXNS.com API diff --git a/dnsapi/README.md b/dnsapi/README.md index 1f394f9..b5fff91 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -4,6 +4,27 @@ If your dns provider doesn't provide api access, you can use our dns alias mode: https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode +## 1. Use Google Cloud DNS API to automatically issue cert + +First you need to authenticate to gcloud. + +``` +gcloud init +``` + +**The `dns_gcloud` script uses the active gcloud configuration and credentials.** +There is no logic inside `dns_gcloud` to override the project and other settings. +If needed, create additional [gcloud configurations](https://cloud.google.com/sdk/gcloud/reference/topic/configurations). +You can change the configuration being used without *activating* it; simply set the `CLOUDSDK_ACTIVE_CONFIG_NAME` environment variable. + +To issue a certificate you can: +``` +export CLOUDSDK_ACTIVE_CONFIG_NAME=default # see the note above +acme.sh --issue --dns dns_gcloud -d example.com -d '*.example.com' +``` + +`dns_gcloud` also supports [DNS alias mode](https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode). + ## 1. Use CloudFlare domain API to automatically issue cert First you need to login to your CloudFlare account to get your API key. diff --git a/dnsapi/dns_gcloud.sh b/dnsapi/dns_gcloud.sh new file mode 100755 index 0000000..5fbd2b6 --- /dev/null +++ b/dnsapi/dns_gcloud.sh @@ -0,0 +1,167 @@ +#!/usr/bin/env sh + +# Author: Janos Lenart + +######## Public functions ##################### + +# Usage: dns_gcloud_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_gcloud_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using gcloud" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _dns_gcloud_find_zone || return $? + + # Add an extra RR + _dns_gcloud_start_tr || return $? + _dns_gcloud_get_rrdatas || return $? + echo "$rrdatas" | _dns_gcloud_remove_rrs || return $? + echo -e "$rrdatas\n\"$txtvalue\"" | grep -v '^$' | _dns_gcloud_add_rrs || return $? + _dns_gcloud_execute_tr || return $? + + _info "$fulldomain record added" +} + +# Usage: dns_gcloud_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Remove the txt record after validation. +dns_gcloud_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using gcloud" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _dns_gcloud_find_zone || return $? + + # Remove one RR + _dns_gcloud_start_tr || return $? + _dns_gcloud_get_rrdatas || return $? + echo "$rrdatas" | _dns_gcloud_remove_rrs || return $? + echo "$rrdatas" | fgrep -v "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $? + _dns_gcloud_execute_tr || return $? + + _info "$fulldomain record added" +} + +#################### Private functions below ################################## + +_dns_gcloud_start_tr() { + if ! trd=`mktemp -d`; then + _err "_dns_gcloud_start_tr: failed to create temporary directory" + return 1 + fi + tr="$trd/tr.yaml" + _debug tr "$tr" + + if ! gcloud dns record-sets transaction start \ + --transaction-file="$tr" \ + --zone="$managedZone"; then + rm -r "$trd" + _err "_dns_gcloud_start_tr: failed to execute transaction" + return 1 + fi +} + +_dns_gcloud_execute_tr() { + if ! gcloud dns record-sets transaction execute \ + --transaction-file="$tr" \ + --zone="$managedZone"; then + _debug tr "`cat \"$tr\"`" + rm -r "$trd" + _err "_dns_gcloud_execute_tr: failed to execute transaction" + return 1 + fi + rm -r "$trd" + + for i in `seq 1 120`; do + if gcloud dns record-sets changes list \ + --zone=lenart \ + --filter='status != done' \ + | grep -q '.*'; then + _info "_dns_gcloud_execute_tr: waiting for transaction to be comitted ..." + sleep 5 + else + return 0 + fi + done + + _err "_dns_gcloud_execute_tr: transaction is still pending after 10 minutes" + rm -r "$trd" + return 1 +} + +_dns_gcloud_remove_rrs() { + if ! xargs --no-run-if-empty gcloud dns record-sets transaction remove \ + --name="$fulldomain." \ + --ttl="$ttl" \ + --type=TXT \ + --zone="$managedZone" \ + --transaction-file="$tr"; then + _debug tr "`cat \"$tr\"`" + rm -r "$trd" + _err "_dns_gcloud_remove_rrs: failed to remove RRs" + return 1 + fi +} + +_dns_gcloud_add_rrs() { + ttl=60 + if ! xargs --no-run-if-empty gcloud dns record-sets transaction add \ + --name="$fulldomain." \ + --ttl="$ttl" \ + --type=TXT \ + --zone="$managedZone" \ + --transaction-file="$tr"; then + _debug tr "`cat \"$tr\"`" + rm -r "$trd" + _err "_dns_gcloud_add_rrs: failed to add RRs" + return 1 + fi +} + +_dns_gcloud_find_zone() { + # Prepare a filter that matches zones that are suiteable for this entry. + # For example, _acme-challenge.something.domain.com might need to go into something.domain.com or domain.com; + # this function finds the longest postfix that has a managed zone. + part="$fulldomain" + filter="dnsName=( " + while [ "$part" != "" ]; do + filter="$filter$part. " + part="`echo \"$part\" | sed 's/[^.]*\.*//'`" + done + filter="$filter)" + _debug filter "$filter" + + # List domains and find the longest match (in case of some levels of delegation) + if ! match=$(gcloud dns managed-zones list \ + --format="value(name, dnsName)" \ + --filter="$filter" \ + | while read dnsName name; do + echo -e "${#dnsName}\t$dnsName\t$name" + done \ + | sort -n -r | head -n1 | cut -f2,3 | grep '.*'); then + _err "_dns_gcloud_find_zone: Can't find a matching managed zone! Perhaps wrong project or gcloud credentials?" + return 1 + fi + + dnsName=$(echo "$match" | cut -f2) + _debug dnsName "$dnsName" + managedZone=$(echo "$match" | cut -f1) + _debug managedZone "$managedZone" +} + +_dns_gcloud_get_rrdatas() { + if ! rrdatas=$(gcloud dns record-sets list \ + --zone="$managedZone" \ + --name="$fulldomain." \ + --type=TXT \ + --format="value(ttl,rrdatas)"); then + _err "_dns_gcloud_get_rrdatas: Failed to list record-sets" + rm -r "$trd" + return 1 + fi + ttl=$(echo "$rrdatas" | cut -f1) + rrdatas=$(echo "$rrdatas" | cut -f2 | sed 's/","/"\n"/g') +} From 167758003c3f04f2b849f4e330490b2c40e24251 Mon Sep 17 00:00:00 2001 From: Janos Lenart Date: Fri, 25 May 2018 19:22:40 +0100 Subject: [PATCH 120/280] Fixed shfmt (dns_gcloud) --- dnsapi/dns_gcloud.sh | 74 ++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/dnsapi/dns_gcloud.sh b/dnsapi/dns_gcloud.sh index 5fbd2b6..9246618 100755 --- a/dnsapi/dns_gcloud.sh +++ b/dnsapi/dns_gcloud.sh @@ -18,7 +18,7 @@ dns_gcloud_add() { _dns_gcloud_start_tr || return $? _dns_gcloud_get_rrdatas || return $? echo "$rrdatas" | _dns_gcloud_remove_rrs || return $? - echo -e "$rrdatas\n\"$txtvalue\"" | grep -v '^$' | _dns_gcloud_add_rrs || return $? + printf "%s\n%s\n" "$rrdatas" "\"$txtvalue\"" | grep -v '^$' | _dns_gcloud_add_rrs || return $? _dns_gcloud_execute_tr || return $? _info "$fulldomain record added" @@ -39,7 +39,7 @@ dns_gcloud_rm() { _dns_gcloud_start_tr || return $? _dns_gcloud_get_rrdatas || return $? echo "$rrdatas" | _dns_gcloud_remove_rrs || return $? - echo "$rrdatas" | fgrep -v "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $? + echo "$rrdatas" | grep -F -v "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $? _dns_gcloud_execute_tr || return $? _info "$fulldomain record added" @@ -48,7 +48,7 @@ dns_gcloud_rm() { #################### Private functions below ################################## _dns_gcloud_start_tr() { - if ! trd=`mktemp -d`; then + if ! trd=$(mktemp -d); then _err "_dns_gcloud_start_tr: failed to create temporary directory" return 1 fi @@ -56,8 +56,8 @@ _dns_gcloud_start_tr() { _debug tr "$tr" if ! gcloud dns record-sets transaction start \ - --transaction-file="$tr" \ - --zone="$managedZone"; then + --transaction-file="$tr" \ + --zone="$managedZone"; then rm -r "$trd" _err "_dns_gcloud_start_tr: failed to execute transaction" return 1 @@ -66,22 +66,22 @@ _dns_gcloud_start_tr() { _dns_gcloud_execute_tr() { if ! gcloud dns record-sets transaction execute \ - --transaction-file="$tr" \ - --zone="$managedZone"; then - _debug tr "`cat \"$tr\"`" + --transaction-file="$tr" \ + --zone="$managedZone"; then + _debug tr "$(cat "$tr")" rm -r "$trd" _err "_dns_gcloud_execute_tr: failed to execute transaction" return 1 fi rm -r "$trd" - for i in `seq 1 120`; do + for i in $(seq 1 120); do if gcloud dns record-sets changes list \ - --zone=lenart \ - --filter='status != done' \ - | grep -q '.*'; then - _info "_dns_gcloud_execute_tr: waiting for transaction to be comitted ..." - sleep 5 + --zone=lenart \ + --filter='status != done' \ + | grep -q '^.*'; then + _info "_dns_gcloud_execute_tr: waiting for transaction to be comitted ($i/120)..." + sleep 5 else return 0 fi @@ -94,12 +94,12 @@ _dns_gcloud_execute_tr() { _dns_gcloud_remove_rrs() { if ! xargs --no-run-if-empty gcloud dns record-sets transaction remove \ - --name="$fulldomain." \ - --ttl="$ttl" \ - --type=TXT \ - --zone="$managedZone" \ - --transaction-file="$tr"; then - _debug tr "`cat \"$tr\"`" + --name="$fulldomain." \ + --ttl="$ttl" \ + --type=TXT \ + --zone="$managedZone" \ + --transaction-file="$tr"; then + _debug tr "$(cat "$tr")" rm -r "$trd" _err "_dns_gcloud_remove_rrs: failed to remove RRs" return 1 @@ -109,12 +109,12 @@ _dns_gcloud_remove_rrs() { _dns_gcloud_add_rrs() { ttl=60 if ! xargs --no-run-if-empty gcloud dns record-sets transaction add \ - --name="$fulldomain." \ - --ttl="$ttl" \ - --type=TXT \ - --zone="$managedZone" \ - --transaction-file="$tr"; then - _debug tr "`cat \"$tr\"`" + --name="$fulldomain." \ + --ttl="$ttl" \ + --type=TXT \ + --zone="$managedZone" \ + --transaction-file="$tr"; then + _debug tr "$(cat "$tr")" rm -r "$trd" _err "_dns_gcloud_add_rrs: failed to add RRs" return 1 @@ -129,19 +129,19 @@ _dns_gcloud_find_zone() { filter="dnsName=( " while [ "$part" != "" ]; do filter="$filter$part. " - part="`echo \"$part\" | sed 's/[^.]*\.*//'`" + part="$(echo "$part" | sed 's/[^.]*\.*//')" done filter="$filter)" _debug filter "$filter" # List domains and find the longest match (in case of some levels of delegation) if ! match=$(gcloud dns managed-zones list \ - --format="value(name, dnsName)" \ - --filter="$filter" \ - | while read dnsName name; do - echo -e "${#dnsName}\t$dnsName\t$name" - done \ - | sort -n -r | head -n1 | cut -f2,3 | grep '.*'); then + --format="value(name, dnsName)" \ + --filter="$filter" \ + | while read -r dnsName name; do + printf "%s\t%s\t%s\n" "${#dnsName}" "$dnsName" "$name" + done \ + | sort -n -r | head -n1 | cut -f2,3 | grep '^.*'); then _err "_dns_gcloud_find_zone: Can't find a matching managed zone! Perhaps wrong project or gcloud credentials?" return 1 fi @@ -154,10 +154,10 @@ _dns_gcloud_find_zone() { _dns_gcloud_get_rrdatas() { if ! rrdatas=$(gcloud dns record-sets list \ - --zone="$managedZone" \ - --name="$fulldomain." \ - --type=TXT \ - --format="value(ttl,rrdatas)"); then + --zone="$managedZone" \ + --name="$fulldomain." \ + --type=TXT \ + --format="value(ttl,rrdatas)"); then _err "_dns_gcloud_get_rrdatas: Failed to list record-sets" rm -r "$trd" return 1 From 1d4dec551068bd5b5fefc2f2b9258204305dc37c Mon Sep 17 00:00:00 2001 From: Janos Lenart Date: Sat, 26 May 2018 12:48:55 +0100 Subject: [PATCH 121/280] Moved dns_gcloud to 47. --- README.md | 2 +- dnsapi/README.md | 46 ++++++++++++++++++++++++---------------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 07fbc84..cf29d76 100644 --- a/README.md +++ b/README.md @@ -274,7 +274,6 @@ You don't have to do anything manually! ### Currently acme.sh supports: -1. Google Cloud DNS API 1. CloudFlare.com API 1. DNSPod.cn API 1. CloudXNS.com API @@ -322,6 +321,7 @@ You don't have to do anything manually! 1. acme-dns (https://github.com/joohoi/acme-dns) 1. TELE3 (https://www.tele3.cz) 1. EUSERV.EU (https://www.euserv.eu) +1. Google Cloud DNS API And: diff --git a/dnsapi/README.md b/dnsapi/README.md index b5fff91..31c99e8 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -4,27 +4,6 @@ If your dns provider doesn't provide api access, you can use our dns alias mode: https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode -## 1. Use Google Cloud DNS API to automatically issue cert - -First you need to authenticate to gcloud. - -``` -gcloud init -``` - -**The `dns_gcloud` script uses the active gcloud configuration and credentials.** -There is no logic inside `dns_gcloud` to override the project and other settings. -If needed, create additional [gcloud configurations](https://cloud.google.com/sdk/gcloud/reference/topic/configurations). -You can change the configuration being used without *activating* it; simply set the `CLOUDSDK_ACTIVE_CONFIG_NAME` environment variable. - -To issue a certificate you can: -``` -export CLOUDSDK_ACTIVE_CONFIG_NAME=default # see the note above -acme.sh --issue --dns dns_gcloud -d example.com -d '*.example.com' -``` - -`dns_gcloud` also supports [DNS alias mode](https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode). - ## 1. Use CloudFlare domain API to automatically issue cert First you need to login to your CloudFlare account to get your API key. @@ -897,6 +876,7 @@ acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com ``` The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed. +<<<<<<< HEAD ## 47. Use Euserv.eu API First you need to login to your euserv.eu account and activate your API Administration (API Verwaltung). @@ -918,6 +898,28 @@ acme.sh --issue --dns dns_euserv -d example.com -d *.example.com --insecure The `EUSERV_Username` and `EUSERV_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. Please report any issues to https://github.com/initit/acme.sh or to + +## 48. Use Google Cloud DNS API to automatically issue cert + +First you need to authenticate to gcloud. + +``` +gcloud init +``` + +**The `dns_gcloud` script uses the active gcloud configuration and credentials.** +There is no logic inside `dns_gcloud` to override the project and other settings. +If needed, create additional [gcloud configurations](https://cloud.google.com/sdk/gcloud/reference/topic/configurations). +You can change the configuration being used without *activating* it; simply set the `CLOUDSDK_ACTIVE_CONFIG_NAME` environment variable. + +To issue a certificate you can: +``` +export CLOUDSDK_ACTIVE_CONFIG_NAME=default # see the note above +acme.sh --issue --dns dns_gcloud -d example.com -d '*.example.com' +``` + +`dns_gcloud` also supports [DNS alias mode](https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode). + # Use custom API If your API is not supported yet, you can write your own DNS API. @@ -938,4 +940,4 @@ See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide # Use lexicon DNS API -https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api \ No newline at end of file +https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api From 441f8f3ce83e10bbf69a30a4d25c821d65e174b1 Mon Sep 17 00:00:00 2001 From: Janos Lenart Date: Wed, 15 Aug 2018 12:01:43 +0100 Subject: [PATCH 122/280] Replied to PR comments --- dnsapi/dns_gcloud.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_gcloud.sh b/dnsapi/dns_gcloud.sh index 9246618..99fbf41 100755 --- a/dnsapi/dns_gcloud.sh +++ b/dnsapi/dns_gcloud.sh @@ -77,7 +77,7 @@ _dns_gcloud_execute_tr() { for i in $(seq 1 120); do if gcloud dns record-sets changes list \ - --zone=lenart \ + --zone="$managedZone" \ --filter='status != done' \ | grep -q '^.*'; then _info "_dns_gcloud_execute_tr: waiting for transaction to be comitted ($i/120)..." @@ -141,7 +141,7 @@ _dns_gcloud_find_zone() { | while read -r dnsName name; do printf "%s\t%s\t%s\n" "${#dnsName}" "$dnsName" "$name" done \ - | sort -n -r | head -n1 | cut -f2,3 | grep '^.*'); then + | sort -n -r | _head_n 1 | cut -f2,3 | grep '^.*'); then _err "_dns_gcloud_find_zone: Can't find a matching managed zone! Perhaps wrong project or gcloud credentials?" return 1 fi From 9e96a9317235ce3c775a048db2a78ec6f418fe2c Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Wed, 15 Aug 2018 18:36:24 +0200 Subject: [PATCH 123/280] Updated README with Gitlab help --- deploy/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index 181989d..5c03ce6 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -275,3 +275,24 @@ acme.sh --deploy -d haproxy.example.com --deploy-hook haproxy ``` The path for the PEM file will be stored with the domain configuration and will be available when renewing, so that deploy will happen automatically when renewed. + +## 11. Deploy your cert to Gitlab pages + +You must define the API key and the informations for the project and Gitlab page you are updating the certificate for. + +```sh +# The token can be created in your user settings under "Access Tokens" +export GITLAB_TOKEN="xxxxxxxxxxx" + +# The project ID is displayed on the home page of the project +export GITLAB_PROJECT_ID=12345678 + +# The domain must match the one defined for the Gitlab page, without "https://" +export GITLAB_DOMAIN="www.mydomain.com" +``` + +You can then deploy the certificate as follows + +```sh +acme.sh --deploy -d www.mydomain.com --deploy-hook gitlab +``` \ No newline at end of file From d06eea53ef08c68340fb48590779f48df98716f7 Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Wed, 15 Aug 2018 18:36:34 +0200 Subject: [PATCH 124/280] Add deploy plugin for Gitlab pages --- deploy/gitlab.sh | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 deploy/gitlab.sh diff --git a/deploy/gitlab.sh b/deploy/gitlab.sh new file mode 100644 index 0000000..5bc53e8 --- /dev/null +++ b/deploy/gitlab.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env sh + +# Script to deploy certificate to a Gitlab hosted page + +# The following variables exported from environment will be used. +# If not set then values previously saved in domain.conf file are used. + +# All the variables are required + +# export GITLAB_TOKEN="xxxxxxx" +# export GITLAB_PROJECT_ID=012345 +# export GITLAB_DOMAIN="mydomain.com" + +gitlab_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if [ -z "$GITLAB_TOKEN" ]; then + if [ -z "$Le_Deploy_gitlab_token" ]; then + _err "GITLAB_TOKEN not defined." + return 1 + fi + else + Le_Deploy_gitlab_token="$GITLAB_TOKEN" + _savedomainconf Le_Deploy_gitlab_token "$Le_Deploy_gitlab_token" + fi + + if [ -z "$GITLAB_PROJECT_ID" ]; then + if [ -z "$Le_Deploy_gitlab_project_id" ]; then + _err "GITLAB_PROJECT_ID not defined." + return 1 + fi + else + Le_Deploy_gitlab_project_id="$GITLAB_PROJECT_ID" + _savedomainconf Le_Deploy_gitlab_project_id "$Le_Deploy_gitlab_project_id" + fi + + if [ -z "$GITLAB_DOMAIN" ]; then + if [ -z "$Le_Deploy_gitlab_domain" ]; then + _err "GITLAB_DOMAIN not defined." + return 1 + fi + else + Le_Deploy_gitlab_domain="$GITLAB_DOMAIN" + _savedomainconf Le_Deploy_gitlab_domain "$Le_Deploy_gitlab_domain" + fi + + curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain > /dev/null && exit 0 + + # Exit curl status code if curl didn't work + exit $? +} From 0575eb671a8506d69eb81946d45e385732c6e8a7 Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Wed, 15 Aug 2018 18:44:24 +0200 Subject: [PATCH 125/280] Fix double quote around URL --- deploy/gitlab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/gitlab.sh b/deploy/gitlab.sh index 5bc53e8..9502da7 100644 --- a/deploy/gitlab.sh +++ b/deploy/gitlab.sh @@ -54,7 +54,7 @@ gitlab_deploy() { _savedomainconf Le_Deploy_gitlab_domain "$Le_Deploy_gitlab_domain" fi - curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain > /dev/null && exit 0 + curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" "https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" > /dev/null && exit 0 # Exit curl status code if curl didn't work exit $? From 6d8292cdd8fe98a5f3d61072f1d8a53f8ceb2768 Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Wed, 15 Aug 2018 19:00:08 +0200 Subject: [PATCH 126/280] Syntax fix --- deploy/gitlab.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/gitlab.sh b/deploy/gitlab.sh index 9502da7..6c1d0f4 100644 --- a/deploy/gitlab.sh +++ b/deploy/gitlab.sh @@ -32,7 +32,7 @@ gitlab_deploy() { else Le_Deploy_gitlab_token="$GITLAB_TOKEN" _savedomainconf Le_Deploy_gitlab_token "$Le_Deploy_gitlab_token" - fi + fi if [ -z "$GITLAB_PROJECT_ID" ]; then if [ -z "$Le_Deploy_gitlab_project_id" ]; then @@ -42,7 +42,7 @@ gitlab_deploy() { else Le_Deploy_gitlab_project_id="$GITLAB_PROJECT_ID" _savedomainconf Le_Deploy_gitlab_project_id "$Le_Deploy_gitlab_project_id" - fi + fi if [ -z "$GITLAB_DOMAIN" ]; then if [ -z "$Le_Deploy_gitlab_domain" ]; then @@ -52,9 +52,9 @@ gitlab_deploy() { else Le_Deploy_gitlab_domain="$GITLAB_DOMAIN" _savedomainconf Le_Deploy_gitlab_domain "$Le_Deploy_gitlab_domain" - fi + fi - curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" "https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" > /dev/null && exit 0 + curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" "https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" >/dev/null && exit 0 # Exit curl status code if curl didn't work exit $? From 75dd0a770f060eccb13f7ec449a6cc1cf1fba006 Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Wed, 15 Aug 2018 19:10:31 +0200 Subject: [PATCH 127/280] Fix Syntax --- deploy/gitlab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/gitlab.sh b/deploy/gitlab.sh index 6c1d0f4..174b226 100644 --- a/deploy/gitlab.sh +++ b/deploy/gitlab.sh @@ -54,7 +54,7 @@ gitlab_deploy() { _savedomainconf Le_Deploy_gitlab_domain "$Le_Deploy_gitlab_domain" fi - curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" "https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" >/dev/null && exit 0 + curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" "https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" >/dev/null && exit 0 # Exit curl status code if curl didn't work exit $? From b401dbbf65f9f671f3c4e66bd4aa75c8abbdf133 Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Wed, 15 Aug 2018 19:17:24 +0200 Subject: [PATCH 128/280] Fix Syntax --- deploy/gitlab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/gitlab.sh b/deploy/gitlab.sh index 174b226..e0222be 100644 --- a/deploy/gitlab.sh +++ b/deploy/gitlab.sh @@ -55,7 +55,7 @@ gitlab_deploy() { fi curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" "https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" >/dev/null && exit 0 - + # Exit curl status code if curl didn't work exit $? } From 8113548920c4b3fdeee4ecdc3959d40d48410fd7 Mon Sep 17 00:00:00 2001 From: Aarup Date: Tue, 21 Aug 2018 11:44:36 +0200 Subject: [PATCH 129/280] Update dns api to support v2 wildcard cert #1261 --- dnsapi/dns_unoeuro.sh | 62 ++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index a3803a2..8be1542 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -50,35 +50,18 @@ dns_unoeuro_add() { _err "Error" return 1 fi + _info "Adding record" - if ! _contains "$response" "$_sub_domain" >/dev/null; then - _info "Adding record" - - if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then - if _contains "$response" "\"status\": 200" >/dev/null; then - _info "Added, OK" - return 0 - else - _err "Add txt record error." - return 1 - fi - fi - _err "Add txt record error." - else - _info "Updating record" - record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$(_math "$record_line_number" - 1) - record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") - _debug "record_id" "$record_id" - - _uno_rest PUT "my/products/$h/dns/records/$record_id" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}" + if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then if _contains "$response" "\"status\": 200" >/dev/null; then - _info "Updated, OK" + _info "Added, OK" return 0 + else + _err "Add txt record error." + return 1 fi - _err "Update error" - return 1 fi + _err "Add txt record error." } #fulldomain txtvalue @@ -122,23 +105,24 @@ dns_unoeuro_rm() { if ! _contains "$response" "$_sub_domain"; then _info "Don't need to remove." else - record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$(_math "$record_line_number" - 1) - record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") - _debug "record_id" "$record_id" - - if [ -z "$record_id" ]; then - _err "Can not get record id to remove." - return 1 - fi + for record_line_number in $(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1); do + record_line_number=$(_math "$record_line_number" - 1) + _debug "record_line_number" "$record_line_number" + record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") + _debug "record_id" "$record_id" + + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi - if ! _uno_rest DELETE "my/products/$h/dns/records/$record_id"; then - _err "Delete record error." - return 1 - fi - _contains "$response" "\"status\": 200" + if ! _uno_rest DELETE "my/products/$h/dns/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "\"status\": 200" + done fi - } #################### Private functions below ################################## From b23718f3ad8b7a5defc0fd67bbcf20f1ec9d1613 Mon Sep 17 00:00:00 2001 From: Jens Reimann Date: Tue, 21 Aug 2018 11:01:47 +0200 Subject: [PATCH 130/280] Add support for additional Lexicon options --- dnsapi/dns_lexicon.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index ab180fb..f6f5446 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -78,7 +78,11 @@ dns_lexicon_add() { domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999) - $lexicon_cmd "$PROVIDER" create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" + _secure_debug LEXICON_OPTS "$LEXICON_OPTS" + _savedomainconf LEXICON_OPTS "$LEXICON_OPTS" + + # shellcheck disable=SC2086 + $lexicon_cmd "$PROVIDER" $LEXICON_OPTS create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" } @@ -93,6 +97,7 @@ dns_lexicon_rm() { domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999) - $lexicon_cmd "$PROVIDER" delete "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" + # shellcheck disable=SC2086 + $lexicon_cmd "$PROVIDER" $LEXICON_OPTS delete "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" } From 8b6986ba18367103d1efe32fed9961ccae40ac3a Mon Sep 17 00:00:00 2001 From: Aarup Date: Tue, 21 Aug 2018 12:32:30 +0200 Subject: [PATCH 131/280] Fix file formatting --- dnsapi/dns_unoeuro.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index 8be1542..9132f13 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -61,7 +61,6 @@ dns_unoeuro_add() { return 1 fi fi - _err "Add txt record error." } #fulldomain txtvalue @@ -121,7 +120,7 @@ dns_unoeuro_rm() { return 1 fi _contains "$response" "\"status\": 200" - done + done fi } From c205777542ea8acf4ca9f36e5a55dc22c76b9515 Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Tue, 21 Aug 2018 16:18:00 +0200 Subject: [PATCH 132/280] Better integration with acme.sh utils --- deploy/gitlab.sh | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/deploy/gitlab.sh b/deploy/gitlab.sh index e0222be..a95983a 100644 --- a/deploy/gitlab.sh +++ b/deploy/gitlab.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/usr/bin/env sh -x # Script to deploy certificate to a Gitlab hosted page @@ -54,8 +54,29 @@ gitlab_deploy() { _savedomainconf Le_Deploy_gitlab_domain "$Le_Deploy_gitlab_domain" fi - curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" "https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" >/dev/null && exit 0 + #curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" "https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" >/dev/null && exit 0 + + string_fullchain=$( _url_encode < $_cfullchain ) + string_key=$( _url_encode < $_ckey ) + + body="certificate=$string_fullchain&key=$string_key" + + export _H1="PRIVATE-TOKEN: $Le_Deploy_gitlab_token" - # Exit curl status code if curl didn't work - exit $? + gitlab_url="https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" + + _response=$( _post "$body" "$gitlab_url" 0 PUT | _dbase64 "multiline" ) + + error_response="error" + + if test "${_response#*$error_response}" != "$_response"; then + _err "Error in deploying certificate:" + _err "$_response" + return 1 + fi + + _debug response "$_response" + _info "Certificate successfully deployed" + + return 0 } From f1b0dd7836021db95470cc1d2269182edf35d0e1 Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Tue, 21 Aug 2018 16:22:08 +0200 Subject: [PATCH 133/280] Fix Syntax --- deploy/gitlab.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/deploy/gitlab.sh b/deploy/gitlab.sh index a95983a..1ec617b 100644 --- a/deploy/gitlab.sh +++ b/deploy/gitlab.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh -x +#!/usr/bin/env sh # Script to deploy certificate to a Gitlab hosted page @@ -56,19 +56,19 @@ gitlab_deploy() { #curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" "https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" >/dev/null && exit 0 - string_fullchain=$( _url_encode < $_cfullchain ) - string_key=$( _url_encode < $_ckey ) + string_fullchain=$(_url_encode < $_cfullchain) + string_key=$(_url_encode < $_ckey) body="certificate=$string_fullchain&key=$string_key" - + export _H1="PRIVATE-TOKEN: $Le_Deploy_gitlab_token" gitlab_url="https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" - - _response=$( _post "$body" "$gitlab_url" 0 PUT | _dbase64 "multiline" ) + + _response=$(_post "$body" "$gitlab_url" 0 PUT | _dbase64 "multiline") error_response="error" - + if test "${_response#*$error_response}" != "$_response"; then _err "Error in deploying certificate:" _err "$_response" From 5a326b82bdb8569cb6c7980a5fcca85ec2791048 Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Tue, 21 Aug 2018 16:24:57 +0200 Subject: [PATCH 134/280] Fix Syntax --- deploy/gitlab.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/gitlab.sh b/deploy/gitlab.sh index 1ec617b..0d41ab2 100644 --- a/deploy/gitlab.sh +++ b/deploy/gitlab.sh @@ -56,8 +56,8 @@ gitlab_deploy() { #curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" "https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" >/dev/null && exit 0 - string_fullchain=$(_url_encode < $_cfullchain) - string_key=$(_url_encode < $_ckey) + string_fullchain=$(_url_encode <$_cfullchain) + string_key=$(_url_encode <$_ckey) body="certificate=$string_fullchain&key=$string_key" From bbf2a15f27acbce9f9a375f13a592b0ecb14e468 Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Tue, 21 Aug 2018 16:30:33 +0200 Subject: [PATCH 135/280] Fix Syntax --- deploy/gitlab.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/deploy/gitlab.sh b/deploy/gitlab.sh index 0d41ab2..ece31c9 100644 --- a/deploy/gitlab.sh +++ b/deploy/gitlab.sh @@ -54,8 +54,6 @@ gitlab_deploy() { _savedomainconf Le_Deploy_gitlab_domain "$Le_Deploy_gitlab_domain" fi - #curl -s --fail --request PUT --header "PRIVATE-TOKEN: $Le_Deploy_gitlab_token" --form "certificate=@$_cfullchain" --form "key=@$_ckey" "https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" >/dev/null && exit 0 - string_fullchain=$(_url_encode <$_cfullchain) string_key=$(_url_encode <$_ckey) From e3c7fc8077aeb84c386da549dac035de855cab6c Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Tue, 21 Aug 2018 16:35:39 +0200 Subject: [PATCH 136/280] Fix Syntax --- deploy/gitlab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/gitlab.sh b/deploy/gitlab.sh index ece31c9..66bb4eb 100644 --- a/deploy/gitlab.sh +++ b/deploy/gitlab.sh @@ -56,7 +56,7 @@ gitlab_deploy() { string_fullchain=$(_url_encode <$_cfullchain) string_key=$(_url_encode <$_ckey) - + body="certificate=$string_fullchain&key=$string_key" export _H1="PRIVATE-TOKEN: $Le_Deploy_gitlab_token" From 8d6443b25da55693d4ff716b6ce76e849ae17c4d Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Tue, 21 Aug 2018 16:41:45 +0200 Subject: [PATCH 137/280] Fix Syntax --- deploy/gitlab.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/gitlab.sh b/deploy/gitlab.sh index 66bb4eb..ba2d312 100644 --- a/deploy/gitlab.sh +++ b/deploy/gitlab.sh @@ -54,8 +54,8 @@ gitlab_deploy() { _savedomainconf Le_Deploy_gitlab_domain "$Le_Deploy_gitlab_domain" fi - string_fullchain=$(_url_encode <$_cfullchain) - string_key=$(_url_encode <$_ckey) + string_fullchain=$(_url_encode <"$_cfullchain") + string_key=$(_url_encode <"$_ckey") body="certificate=$string_fullchain&key=$string_key" From 840b3a34cba3602e49a14dded23e2664a31fc277 Mon Sep 17 00:00:00 2001 From: linux-insideDE <39219399+linux-insideDE@users.noreply.github.com> Date: Tue, 21 Aug 2018 21:47:40 +0200 Subject: [PATCH 138/280] changed some chars --- dnsapi/dns_netcup.sh | 214 +++++++++++++++++++++---------------------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh index 573550e..2dfbdab 100644 --- a/dnsapi/dns_netcup.sh +++ b/dnsapi/dns_netcup.sh @@ -8,123 +8,123 @@ end="https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON" client="" dns_netcup_add() { - login - if [ "$NC_Apikey" = "" ] || [ "$NC_Apipw" = "" ] || [ "$NC_CID" = "" ]; then - _err "No Credentials given" - return 1 - fi - _saveaccountconf_mutable NC_Apikey "$NC_Apikey" - _saveaccountconf_mutable NC_Apipw "$NC_Apipw" - _saveaccountconf_mutable NC_CID "$NC_CID" - fulldomain=$1 - txtvalue=$2 - domain="" - exit=$(echo "$fulldomain" | tr -dc '.' | wc -c) - exit=$(_math "$exit" + 1) - i=$exit + login + if [ "$NC_Apikey" = "" ] || [ "$NC_Apipw" = "" ] || [ "$NC_CID" = "" ]; then + _err "No Credentials given" + return 1 + fi + _saveaccountconf_mutable NC_Apikey "$NC_Apikey" + _saveaccountconf_mutable NC_Apipw "$NC_Apipw" + _saveaccountconf_mutable NC_CID "$NC_CID" + fulldomain=$1 + txtvalue=$2 + domain="" + exit=$(echo "$fulldomain" | tr -dc '.' | wc -c) + exit=$(_math "$exit" + 1) + i=$exit - while - [ "$exit" -gt 0 ]; do - tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") - if [ "$(_math "$i" - "$exit")" -eq 0 ]; then - domain="$tmp" - else - domain="$tmp.$domain" - fi - if [ "$(_math "$i" - "$exit")" -ge 1 ]; then - msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"false\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") - _debug "$msg" - if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then - if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then - _err "$msg" - return 1 - else - break - fi - fi - fi - exit=$(_math "$exit" - 1) - done - logout + while + [ "$exit" -gt 0 ]; do + tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") + if [ "$(_math "$i" - "$exit")" -eq 0 ]; then + domain="$tmp" + else + domain="$tmp.$domain" + fi + if [ "$(_math "$i" - "$exit")" -ge 1 ]; then + msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"false\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") + _debug "$msg" + if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" + return 1 + else + break + fi + fi + fi + exit=$(_math "$exit" - 1) + done + logout } dns_netcup_rm() { - login - fulldomain=$1 - txtvalue=$2 + login + fulldomain=$1 + txtvalue=$2 - domain="" - exit=$(echo "$fulldomain" | tr -dc '.' | wc -c) - exit=$(_math "$exit" + 1) - i=$exit - rec="" + domain="" + exit=$(echo "$fulldomain" | tr -dc '.' | wc -c) + exit=$(_math "$exit" + 1) + i=$exit + rec="" - while - [ "$exit" -gt 0 ]; do - tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") - if [ "$(_math "$i" - "$exit")" -eq 0 ]; then - domain="$tmp" - else - domain="$tmp.$domain" - fi - if [ "$(_math "$i" - "$exit")" -ge 1 ]; then - msg=$(_post "{\"action\": \"infoDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\", \"domainname\": \"$domain\"}}" "$end" "" "POST") - rec=$(echo "$msg" | sed 's/\[//g' | sed 's/\]//g' | sed 's/{\"serverrequestid\".*\"dnsrecords\"://g' | sed 's/},{/};{/g' | sed 's/{//g' | sed 's/}//g') - _debug "$msg" - if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then - if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then - _err "$msg" - return 1 - else - break - fi - fi - fi - exit=$(_math "$exit" - 1) - done + while + [ "$exit" -gt 0 ]; do + tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") + if [ "$(_math "$i" - "$exit")" -eq 0 ]; then + domain="$tmp" + else + domain="$tmp.$domain" + fi + if [ "$(_math "$i" - "$exit")" -ge 1 ]; then + msg=$(_post "{\"action\": \"infoDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\", \"domainname\": \"$domain\"}}" "$end" "" "POST") + rec=$(echo "$msg" | sed 's/\[//g' | sed 's/\]//g' | sed 's/{\"serverrequestid\".*\"dnsrecords\"://g' | sed 's/},{/};{/g' | sed 's/{//g' | sed 's/}//g') + _debug "$msg" + if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" + return 1 + else + break + fi + fi + fi + exit=$(_math "$exit" - 1) + done - ida=0000 - idv=0001 - ids=0000000000 - i=1 - while - [ "$i" -ne 0 ]; do - specrec=$(_getfield "$rec" "$i" ";") - idv="$ida" - ida=$(_getfield "$specrec" "1" "," | sed 's/\"id\":\"//g' | sed 's/\"//g') - txtv=$(_getfield "$specrec" "5" "," | sed 's/\"destination\":\"//g' | sed 's/\"//g') - i=$(_math "$i" + 1) - if [ "$txtvalue" = "$txtv" ]; then - i=0 - ids="$ida" - fi - if [ "$ida" = "$idv" ]; then - i=0 - fi - done - msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"$ids\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"TRUE\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") - _debug "$msg" - if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then - _err "$msg" - return 1 - fi - logout + ida=0000 + idv=0001 + ids=0000000000 + i=1 + while + [ "$i" -ne 0 ]; do + specrec=$(_getfield "$rec" "$i" ";") + idv="$ida" + ida=$(_getfield "$specrec" "1" "," | sed 's/\"id\":\"//g' | sed 's/\"//g') + txtv=$(_getfield "$specrec" "5" "," | sed 's/\"destination\":\"//g' | sed 's/\"//g') + i=$(_math "$i" + 1) + if [ "$txtvalue" = "$txtv" ]; then + i=0 + ids="$ida" + fi + if [ "$ida" = "$idv" ]; then + i=0 + fi + done + msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"$ids\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"TRUE\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") + _debug "$msg" + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" + return 1 + fi + logout } login() { - tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") - sid=$(_getfield "$tmp" "8" | sed s/\"responsedata\":\{\"apisessionid\":\"//g | sed 's/\"\}\}//g') - _debug "$tmp" - if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then - _err "$msg" - return 1 - fi + tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") + sid=$(_getfield "$tmp" "8" | sed s/\"responsedata\":\{\"apisessionid\":\"//g | sed 's/\"\}\}//g') + _debug "$tmp" + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" + return 1 + fi } logout() { - tmp=$(_post "{\"action\": \"logout\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") - _debug "$tmp" - if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then - _err "$msg" - return 1 - fi + tmp=$(_post "{\"action\": \"logout\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") + _debug "$tmp" + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" + return 1 + fi } From 4fffb3c8161358b1bdf9e570bedba4fb3c010803 Mon Sep 17 00:00:00 2001 From: linux-insideDE <39219399+linux-insideDE@users.noreply.github.com> Date: Tue, 21 Aug 2018 21:55:44 +0200 Subject: [PATCH 139/280] make shfmt happy --- dnsapi/dns_netcup.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh index 2dfbdab..2273eb7 100644 --- a/dnsapi/dns_netcup.sh +++ b/dnsapi/dns_netcup.sh @@ -24,7 +24,8 @@ dns_netcup_add() { i=$exit while - [ "$exit" -gt 0 ]; do + [ "$exit" -gt 0 ] + do tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") if [ "$(_math "$i" - "$exit")" -eq 0 ]; then domain="$tmp" @@ -60,7 +61,8 @@ dns_netcup_rm() { rec="" while - [ "$exit" -gt 0 ]; do + [ "$exit" -gt 0 ] + do tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") if [ "$(_math "$i" - "$exit")" -eq 0 ]; then domain="$tmp" @@ -88,7 +90,8 @@ dns_netcup_rm() { ids=0000000000 i=1 while - [ "$i" -ne 0 ]; do + [ "$i" -ne 0 ] + do specrec=$(_getfield "$rec" "$i" ";") idv="$ida" ida=$(_getfield "$specrec" "1" "," | sed 's/\"id\":\"//g' | sed 's/\"//g') From 2e74df2583cf2a28a74251a8f0c25d5e55d1a170 Mon Sep 17 00:00:00 2001 From: KUDO Takashi Date: Mon, 30 Jul 2018 19:41:11 +0900 Subject: [PATCH 140/280] Add support ConoHa DNS API --- README.md | 1 + dnsapi/README.md | 19 +++- dnsapi/dns_conoha.sh | 255 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+), 1 deletion(-) create mode 100755 dnsapi/dns_conoha.sh diff --git a/README.md b/README.md index ada8273..d247707 100644 --- a/README.md +++ b/README.md @@ -323,6 +323,7 @@ You don't have to do anything manually! 1. EUSERV.EU (https://www.euserv.eu) 1. DNSPod.com API (https://www.dnspod.com) 1. Google Cloud DNS API +1. ConoHa (https://www.conoha.jp) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 8322679..15c5026 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -876,7 +876,6 @@ acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com ``` The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed. -<<<<<<< HEAD ## 47. Use Euserv.eu API First you need to login to your euserv.eu account and activate your API Administration (API Verwaltung). @@ -936,6 +935,24 @@ acme.sh --issue --dns dns_gcloud -d example.com -d '*.example.com' `dns_gcloud` also supports [DNS alias mode](https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode). +## 50. Use ConoHa API + +First you need to login to your ConoHa account to get your API credentials. + +``` +export CONOHA_Username="xxxxxx" +export CONOHA_Password="xxxxxx" +export CONOHA_TenantId="xxxxxx" +export CONOHA_IdentityServiceApi="https://identity.xxxx.conoha.io/v2.0" +``` + +To issue a cert: +``` +acme.sh --issue --dns dns_conoha -d example.com -d www.example.com +``` + +The `CONOHA_Username`, `CONOHA_Password`, `CONOHA_TenantId` and `CONOHA_IdentityServiceApi` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + ======= # Use custom API diff --git a/dnsapi/dns_conoha.sh b/dnsapi/dns_conoha.sh new file mode 100755 index 0000000..f9e4ac1 --- /dev/null +++ b/dnsapi/dns_conoha.sh @@ -0,0 +1,255 @@ +#!/usr/bin/env sh + +CONOHA_DNS_EP_PREFIX_REGEXP="https://dns-service\." + +######## Public functions ##################### + +#Usage: dns_conoha_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_conoha_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using conoha" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _debug "Check uesrname and password" + CONOHA_Username="${CONOHA_Username:-$(_readaccountconf_mutable CONOHA_Username)}" + CONOHA_Password="${CONOHA_Password:-$(_readaccountconf_mutable CONOHA_Password)}" + CONOHA_TenantId="${CONOHA_TenantId:-$(_readaccountconf_mutable CONOHA_TenantId)}" + CONOHA_IdentityServiceApi="${CONOHA_IdentityServiceApi:-$(_readaccountconf_mutable CONOHA_IdentityServiceApi)}" + if [ -z "$CONOHA_Username" ] || [ -z "$CONOHA_Password" ] || [ -z "$CONOHA_TenantId" ] || [ -z "$CONOHA_IdentityServiceApi" ]; then + CONOHA_Username="" + CONOHA_Password="" + CONOHA_TenantId="" + CONOHA_IdentityServiceApi="" + _err "You didn't specify a conoha api username and password yet." + _err "Please create the user and try again." + return 1 + fi + + _saveaccountconf_mutable CONOHA_Username "$CONOHA_Username" + _saveaccountconf_mutable CONOHA_Password "$CONOHA_Password" + _saveaccountconf_mutable CONOHA_TenantId "$CONOHA_TenantId" + _saveaccountconf_mutable CONOHA_IdentityServiceApi "$CONOHA_IdentityServiceApi" + + if set -- $(_conoha_get_accesstoken "$CONOHA_IdentityServiceApi/tokens" "$CONOHA_Username" "$CONOHA_Password" "$CONOHA_TenantId"); then + accesstoken=$1 + CONOHA_Api=$2 + else + return 1 + fi + #return 1 #XXX + + _debug "First detect the root zone" + if ! _get_root "$fulldomain" "$CONOHA_Api" "$accesstoken"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + #return 1 #XXX + + _info "Adding record" + body="{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"data\":\"$txtvalue\",\"ttl\":60}" + if _conoha_rest POST "$CONOHA_Api/v1/domains/$_domain_id/records" "$body" "$accesstoken"; then + if _contains "$response" '"data":"'"$txtvalue"'"'; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + + _err "Add txt record error." + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_conoha_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using conoha" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _debug "Check uesrname and password" + CONOHA_Username="${CONOHA_Username:-$(_readaccountconf_mutable CONOHA_Username)}" + CONOHA_Password="${CONOHA_Password:-$(_readaccountconf_mutable CONOHA_Password)}" + CONOHA_TenantId="${CONOHA_TenantId:-$(_readaccountconf_mutable CONOHA_TenantId)}" + CONOHA_IdentityServiceApi="${CONOHA_IdentityServiceApi:-$(_readaccountconf_mutable CONOHA_IdentityServiceApi)}" + if [ -z "$CONOHA_Username" ] || [ -z "$CONOHA_Password" ] || [ -z "$CONOHA_TenantId" ] || [ -z "$CONOHA_IdentityServiceApi" ]; then + CONOHA_Username="" + CONOHA_Password="" + CONOHA_TenantId="" + CONOHA_IdentityServiceApi="" + _err "You didn't specify a conoha api username and password yet." + _err "Please create the user and try again." + return 1 + fi + + _saveaccountconf_mutable CONOHA_Username "$CONOHA_Username" + _saveaccountconf_mutable CONOHA_Password "$CONOHA_Password" + _saveaccountconf_mutable CONOHA_TenantId "$CONOHA_TenantId" + _saveaccountconf_mutable CONOHA_IdentityServiceApi "$CONOHA_IdentityServiceApi" + + if set -- $(_conoha_get_accesstoken "$CONOHA_IdentityServiceApi/tokens" "$CONOHA_Username" "$CONOHA_Password" "$CONOHA_TenantId"); then + accesstoken=$1 + CONOHA_Api=$2 + else + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain" "$CONOHA_Api" "$accesstoken"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + if ! _conoha_rest GET "$CONOHA_Api/v1/domains/$_domain_id/records" "" "$accesstoken"; then + _err "Error" + return 1 + fi + + record_id=$(printf "%s" "$response" | _egrep_o '{[^}]*}' | + grep '"type":"TXT"' | grep "\"data\":\"$txtvalue\"" | _egrep_o "\"id\":\"[^\"]*\"" | + _head_n 1 | cut -d : -f 2 | tr -d \") + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + _debug record_id "$record_id" + + _info "Removing the txt record" + if ! _conoha_rest DELETE "$CONOHA_Api/v1/domains/$_domain_id/records/$record_id" "" "$accesstoken"; then + _err "Delete record error." + return 1 + fi + + return 0 +} + +#################### Private functions below ################################## + +_conoha_rest() { + m="$1" + ep="$2" + data="$3" + accesstoken="$4" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + if [ -n "$accesstoken" ]; then + export _H3="X-Auth-Token: $accesstoken" + fi + + _debug "$ep" + if [ "$m" != "GET" ]; then + _secure_debug2 data "$data" + response="$(_post "$data" "$ep" "" "$m")" + else + response="$(_get "$ep")" + fi + _ret="$?" + _secure_debug2 response "$response" + if [ "$_ret" != "0" ]; then + _err "error $ep" + return 1 + fi + + response="$(printf "%s" "$response" | _normalizeJson)" + return 0 +} + +_conoha_get_accesstoken() { + ep="$1" + username="$2" + password="$3" + tenantId="$4" + + accesstoken="$(_readaccountconf_mutable conoha_accesstoken)" + expires="$(_readaccountconf_mutable conoha_tokenvalidto)" + CONOHA_Api="$(_readaccountconf_mutable conoha_dns_ep)" + + # can we reuse the access token? + if [ -n "$accesstoken" ] && [ -n "$expires" ] && [ -n "$CONOHA_Api" ]; then + utc_date="$(_utc_date | sed "s/ /T/")" + if expr "$utc_date" "<" "$expires" >/dev/null; then + # access token is still valid - reuse it + _debug "reusing access token" + printf "%s\n%s" "$accesstoken" "$CONOHA_Api" + return 0 + else + _debug "access token expired" + fi + fi + _debug "getting new access token" + + body="$(printf '{"auth":{"passwordCredentials":{"username":"%s","password":"%s"},"tenantId":"%s"}}' "$username" "$password" "$tenantId")" + if ! _conoha_rest POST "$ep" "$body" ""; then + _err error "$response" + return 1 + fi + accesstoken=$(printf "%s" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") + expires=$(printf "%s" "$response" | _egrep_o "\"expires\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2-4 | tr -d \" | tr -d Z) #expect UTC + if [ -z "$accesstoken" ] || [ -z "$expires" ]; then + _err "no acccess token received. Check your Conoha settings see $WIKI" + return 1 + fi + _saveaccountconf_mutable conoha_accesstoken "$accesstoken" + _saveaccountconf_mutable conoha_tokenvalidto "$expires" + + CONOHA_Api=$(printf "%s" "$response" | _egrep_o 'publicURL":"'"$CONOHA_DNS_EP_PREFIX_REGEXP"'[^"]*"' | _head_n 1 | cut -d : -f 2-3 | tr -d \") + if [ -z "$CONOHA_Api" ]; then + _err "failed to get conoha dns endpoint url" + return 1 + fi + _saveaccountconf_mutable conoha_dns_ep "$CONOHA_Api" + + printf "%s\n%s" "$accesstoken" "$CONOHA_Api" + return 0 +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain="$1" + ep="$2" + accesstoken="$3" + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100). + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _conoha_rest GET "$ep/v1/domains?name=$h" "" "$accesstoken"; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} From 72a7f932c65c4fd2c889fd3220081bb2b005cf34 Mon Sep 17 00:00:00 2001 From: KUDO Takashi Date: Mon, 30 Jul 2018 22:03:14 +0900 Subject: [PATCH 141/280] fix indent --- dnsapi/dns_conoha.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_conoha.sh b/dnsapi/dns_conoha.sh index f9e4ac1..c573d17 100755 --- a/dnsapi/dns_conoha.sh +++ b/dnsapi/dns_conoha.sh @@ -117,9 +117,9 @@ dns_conoha_rm() { return 1 fi - record_id=$(printf "%s" "$response" | _egrep_o '{[^}]*}' | - grep '"type":"TXT"' | grep "\"data\":\"$txtvalue\"" | _egrep_o "\"id\":\"[^\"]*\"" | - _head_n 1 | cut -d : -f 2 | tr -d \") + record_id=$(printf "%s" "$response" | _egrep_o '{[^}]*}' \ + | grep '"type":"TXT"' | grep "\"data\":\"$txtvalue\"" | _egrep_o "\"id\":\"[^\"]*\"" \ + | _head_n 1 | cut -d : -f 2 | tr -d \") if [ -z "$record_id" ]; then _err "Can not get record id to remove." return 1 @@ -147,7 +147,7 @@ _conoha_rest() { export _H2="Content-Type: application/json" if [ -n "$accesstoken" ]; then export _H3="X-Auth-Token: $accesstoken" - fi + fi _debug "$ep" if [ "$m" != "GET" ]; then From a35d27166941762aa819da21f6c7452b6e2dd178 Mon Sep 17 00:00:00 2001 From: KUDO Takashi Date: Mon, 30 Jul 2018 22:15:57 +0900 Subject: [PATCH 142/280] cleanup --- dnsapi/dns_conoha.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dnsapi/dns_conoha.sh b/dnsapi/dns_conoha.sh index c573d17..694665b 100755 --- a/dnsapi/dns_conoha.sh +++ b/dnsapi/dns_conoha.sh @@ -38,7 +38,6 @@ dns_conoha_add() { else return 1 fi - #return 1 #XXX _debug "First detect the root zone" if ! _get_root "$fulldomain" "$CONOHA_Api" "$accesstoken"; then @@ -48,7 +47,6 @@ dns_conoha_add() { _debug _domain_id "$_domain_id" _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - #return 1 #XXX _info "Adding record" body="{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"data\":\"$txtvalue\",\"ttl\":60}" @@ -176,7 +174,7 @@ _conoha_get_accesstoken() { accesstoken="$(_readaccountconf_mutable conoha_accesstoken)" expires="$(_readaccountconf_mutable conoha_tokenvalidto)" CONOHA_Api="$(_readaccountconf_mutable conoha_dns_ep)" - + # can we reuse the access token? if [ -n "$accesstoken" ] && [ -n "$expires" ] && [ -n "$CONOHA_Api" ]; then utc_date="$(_utc_date | sed "s/ /T/")" From 73d04b976ee638479e9dff65da43450a17a7858b Mon Sep 17 00:00:00 2001 From: KUDO Takashi Date: Mon, 30 Jul 2018 22:50:47 +0900 Subject: [PATCH 143/280] avoid "SC2046: Quote this to prevent word splitting." Travis CI error. --- dnsapi/dns_conoha.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_conoha.sh b/dnsapi/dns_conoha.sh index 694665b..d3bee13 100755 --- a/dnsapi/dns_conoha.sh +++ b/dnsapi/dns_conoha.sh @@ -32,9 +32,9 @@ dns_conoha_add() { _saveaccountconf_mutable CONOHA_TenantId "$CONOHA_TenantId" _saveaccountconf_mutable CONOHA_IdentityServiceApi "$CONOHA_IdentityServiceApi" - if set -- $(_conoha_get_accesstoken "$CONOHA_IdentityServiceApi/tokens" "$CONOHA_Username" "$CONOHA_Password" "$CONOHA_TenantId"); then - accesstoken=$1 - CONOHA_Api=$2 + if token="$(_conoha_get_accesstoken "$CONOHA_IdentityServiceApi/tokens" "$CONOHA_Username" "$CONOHA_Password" "$CONOHA_TenantId")"; then + accesstoken="$(printf "%s" "$token" | sed -n 1p)" + CONOHA_Api="$(printf "%s" "$token" | sed -n 2p)" else return 1 fi @@ -93,9 +93,9 @@ dns_conoha_rm() { _saveaccountconf_mutable CONOHA_TenantId "$CONOHA_TenantId" _saveaccountconf_mutable CONOHA_IdentityServiceApi "$CONOHA_IdentityServiceApi" - if set -- $(_conoha_get_accesstoken "$CONOHA_IdentityServiceApi/tokens" "$CONOHA_Username" "$CONOHA_Password" "$CONOHA_TenantId"); then - accesstoken=$1 - CONOHA_Api=$2 + if token="$(_conoha_get_accesstoken "$CONOHA_IdentityServiceApi/tokens" "$CONOHA_Username" "$CONOHA_Password" "$CONOHA_TenantId")"; then + accesstoken="$(printf "%s" "$token" | sed -n 1p)" + CONOHA_Api="$(printf "%s" "$token" | sed -n 2p)" else return 1 fi @@ -181,7 +181,7 @@ _conoha_get_accesstoken() { if expr "$utc_date" "<" "$expires" >/dev/null; then # access token is still valid - reuse it _debug "reusing access token" - printf "%s\n%s" "$accesstoken" "$CONOHA_Api" + printf "%s\n%s\n" "$accesstoken" "$CONOHA_Api" return 0 else _debug "access token expired" @@ -210,7 +210,7 @@ _conoha_get_accesstoken() { fi _saveaccountconf_mutable conoha_dns_ep "$CONOHA_Api" - printf "%s\n%s" "$accesstoken" "$CONOHA_Api" + printf "%s\n%s\n" "$accesstoken" "$CONOHA_Api" return 0 } From 68a290c34752c2aa0b913332467b7a5f2c001111 Mon Sep 17 00:00:00 2001 From: Yann Bizeul Date: Wed, 22 Aug 2018 19:08:33 +0200 Subject: [PATCH 144/280] revert dns_inwx.sh to dev --- dnsapi/dns_inwx.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index f4590cf..cd5af91 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -158,8 +158,7 @@ _inwx_login() { export _H1 #https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71 - if _contains "$response" "code1000" \ - && _contains "$response" "tfaGOOGLE-AUTH"; then + if _contains "$response" "tfa"; then if [ -z "$INWX_Shared_Secret" ]; then _err "Mobile TAN detected." _err "Please define a shared secret." From 1756bbff84e204bef1edaa953d2ffb0c04c9008b Mon Sep 17 00:00:00 2001 From: Herman Sletteng Date: Tue, 15 May 2018 11:31:43 +0200 Subject: [PATCH 145/280] DNS plugin for Danish service gratisdns.dk Currently only supports primary domains. My use case does not involve secondary domains so I'm not sure how it behaves, and cannot test it. Might be as simple as turning all "primary"-references into a variable that's either "primary" or "secondary", and make an extra check for this in _get_domain... Cookie handling heavily inspired by freedns plugin, including caching the cookie in the config file, so we can rm without re-authenticating --- README.md | 1 + dnsapi/README.md | 20 ++++++ dnsapi/dns_gdnsdk.sh | 168 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100755 dnsapi/dns_gdnsdk.sh diff --git a/README.md b/README.md index 0ba5eeb..904a478 100644 --- a/README.md +++ b/README.md @@ -325,6 +325,7 @@ You don't have to do anything manually! 1. Google Cloud DNS API 1. ConoHa (https://www.conoha.jp) 1. netcup DNS API (https://www.netcup.de) +1. GratisDNS.dk (https://gratisdns.dk) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 47862d6..891417f 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -970,6 +970,26 @@ acme.sh --issue --dns dns_netcup -d example.com -d www.example.com The `NC_Apikey`,`NC_Apipw` and `NC_CID` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 52. Use GratisDNS.dk + +GratisDNS.dk (https://gratisdns.dj/) does not provide an API to update DNS records (other than IPv4 and IPv6 +dynamic DNS addresses). The acme.sh plugin therefore retrieves and updates domain TXT records by logging +into the GratisDNS website to read the HTML and posting updates as HTTP. The plugin needs to know your +userid and password for the GratisDNS website. + +```sh +export GDNSDK_Username="..." +export GDNSDK_Password="..." +``` +The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + + +Now you can issue a certificate. + +```sh +acme.sh --issue --dns dns_gdnsdk -d example.com -d *.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_gdnsdk.sh b/dnsapi/dns_gdnsdk.sh new file mode 100755 index 0000000..05a4c9f --- /dev/null +++ b/dnsapi/dns_gdnsdk.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env sh +#Author: Herman Sletteng +#Report Bugs here: https://github.com/loial/acme.sh +# +# +# Note, gratisdns requires a login first, so the script needs to handle +# temporary cookies. Since acme.sh _get/_post currently don't directly support +# cookies, I've defined wrapper functions _myget/_mypost to set the headers + +GDNSDK_API="https://admin.gratisdns.com" +######## Public functions ##################### +#Usage: dns_gdnsdk_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_gdnsdk_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using gratisdns.dk" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + if ! _gratisdns_login; then + _err "Login failed!" + return 1 + fi + #finding domain zone + if ! _get_domain; then + _err "No matching root domain for $fulldomain found" + return 1 + fi + # adding entry + _info "Adding the entry" + _mypost "action=dns_primary_record_added_txt&user_domain=$_domain&name=$fulldomain&txtdata=$txtvalue&ttl=1" + if _successful_update; then return 0; fi + _err "Couldn't create entry!" + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_gdnsdk_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using gratisdns.dk" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + if ! _gratisdns_login; then + _err "Login failed!" + return 1 + fi + if ! _get_domain; then + _err "No matching root domain for $fulldomain found" + return 1 + fi + _findentry "$fulldomain" "$txtvalue" + if [ -z "$_id" ]; then + _info "Entry doesn't exist, nothing to delete" + return 0 + fi + _debug "Deleting record..." + _mypost "action=dns_primary_delete_txt&user_domain=$_domain&id=$_id" + # removing entry + + if _successful_update; then return 0; fi + _err "Couldn't delete entry!" + return 1 +} + +#################### Private functions below ################################## + +_checkcredentials() { + GDNSDK_Username="${GDNSDK_Username:-$(_readaccountconf_mutable GDNSDK_Username)}" + GDNSDK_Password="${GDNSDK_Password:-$(_readaccountconf_mutable GDNSDK_Password)}" + + if [ -z "$GDNSDK_Username" ] || [ -z "$GDNSDK_Password" ]; then + GDNSDK_Username="" + GDNSDK_Password="" + _err "You haven't specified gratisdns.dk username and password yet." + _err "Please add credentials and try again." + return 1 + fi + #save the credentials to the account conf file. + _saveaccountconf_mutable GDNSDK_Username "$GDNSDK_Username" + _saveaccountconf_mutable GDNSDK_Password "$GDNSDK_Password" + return 0 +} + +_checkcookie() { + GDNSDK_Cookie="${GDNSDK_Cookie:-$(_readaccountconf_mutable GDNSDK_Cookie)}" + if [ -z "$GDNSDK_Cookie" ]; then + _debug "No cached cookie found" + return 1 + fi + _myget "action=" + if (echo "$_result" | grep -q "logmeout"); then + _debug "Cached cookie still valid" + return 0 + fi + _debug "Cached cookie no longer valid" + GDNSDK_Cookie="" + _saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie" + return 1 +} + +_gratisdns_login() { + if ! _checkcredentials; then return 1; fi + + if _checkcookie; then + _debug "Already logged in" + return 0 + fi + _debug "Logging into GratisDNS with user $GDNSDK_Username" + + if ! _mypost "login=$GDNSDK_Username&password=$GDNSDK_Password&action=logmein"; then + _err "GratisDNS login failed for user $GDNSDK_Username bad RC from _post" + return 1 + fi + + GDNSDK_Cookie="$(grep -A 15 '302 Found' "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]*' | _head_n 1 | cut -d ' ' -f2)" + + if [ -z "$GDNSDK_Cookie" ]; then + _err "GratisDNS login failed for user $GDNSDK_Username. Check $HTTP_HEADER file" + return 1 + fi + export GDNSDK_Cookie + _saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie" + return 0 +} + +_myget() { + #Adds cookie to request + export _H1="Cookie: $GDNSDK_Cookie" + _result=$(_get "$GDNSDK_API?$1") +} +_mypost() { + #Adds cookie to request + export _H1="Cookie: $GDNSDK_Cookie" + _result=$(_post "$1" "$GDNSDK_API") +} + +_get_domain() { + _myget 'action=dns_primarydns' + _domains=$(echo "$_result" | grep -o -P ' domain="\K([[:alnum:].-_]+)') + if [ -z "$_domains" ]; then + _err "Primary domain list not found!" + return 1 + fi + for _domain in $_domains; do + if (_endswith "$fulldomain" "$_domain"); then + _debug "Root domain: $_domain" + return 0 + fi + done + return 1 +} + +_successful_update() { + if (echo "$_result" | grep -q 'table-success'); then return 0; fi + return 1 +} + +_findentry() { + #returns id of dns entry, if it exists + _myget "action=dns_primary_changeDNSsetup&user_domain=$_domain" + _id=$(echo "$_result" | grep -o -P "$1\s*\s*\s*[^?]*[^&]*&id=[^&]*" | sed 's/^.*=//') if [ -n "$_id" ]; then _debug "Entry found with _id=$_id" return 0 From 12c900ea7d4f4da4de856611f5955bad23e8db25 Mon Sep 17 00:00:00 2001 From: Herman Sletteng Date: Wed, 29 Aug 2018 00:44:34 +0200 Subject: [PATCH 147/280] Gratisdns.dk: Fix typo in url, also added note recommending --dnssleep 300 --- dnsapi/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 891417f..c8207b9 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -972,7 +972,7 @@ The `NC_Apikey`,`NC_Apipw` and `NC_CID` will be saved in `~/.acme.sh/account.con ## 52. Use GratisDNS.dk -GratisDNS.dk (https://gratisdns.dj/) does not provide an API to update DNS records (other than IPv4 and IPv6 +GratisDNS.dk (https://gratisdns.dk/) does not provide an API to update DNS records (other than IPv4 and IPv6 dynamic DNS addresses). The acme.sh plugin therefore retrieves and updates domain TXT records by logging into the GratisDNS website to read the HTML and posting updates as HTTP. The plugin needs to know your userid and password for the GratisDNS website. @@ -986,8 +986,11 @@ The username and password will be saved in `~/.acme.sh/account.conf` and will be Now you can issue a certificate. +Note: It usually takes a few minutes (usually 3-4 minutes) before the changes propagates to gratisdns.dk nameservers (ns3.gratisdns.dk often are slow), +and in rare cases I have seen over 5 minutes before google DNS catches it. Therefor a DNS sleep of at least 300 seconds are recommended- + ```sh -acme.sh --issue --dns dns_gdnsdk -d example.com -d *.example.com +acme.sh --issue --dns dns_gdnsdk --dnssleep 300 -d example.com -d *.example.com ``` # Use custom API From 0d03309c2f17bd5ed8e73a1425c956b4cc422a24 Mon Sep 17 00:00:00 2001 From: LLeny Date: Sun, 2 Sep 2018 21:25:44 +0800 Subject: [PATCH 148/280] Namecheap initial --- dnsapi/dns_namecheap.sh | 233 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100755 dnsapi/dns_namecheap.sh diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh new file mode 100755 index 0000000..67aa3ac --- /dev/null +++ b/dnsapi/dns_namecheap.sh @@ -0,0 +1,233 @@ +#!/usr/bin/env sh + +# Namecheap API +# https://www.namecheap.com/support/api/intro.aspx +# +# Requires Namecheap API key set in NAMECHEAP_API_KEY and NAMECHEAP_USERNAME set as environment variable +# +######## Public functions ##################### + +NAMECHEAP_API="https://api.sandbox.namecheap.com/xml.response" + +#Usage: dns_namecheap_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_namecheap_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _namecheap_check_config; then + _err "$error" + return 1 + fi + + _namecheap_set_publicip + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + + _set_namecheap_TXT "$_domain" "$_sub_domain" "$txtvalue" +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_namecheap_rm() { + fulldomain=$1 + txtvalue=$2 + + _namecheap_set_publicip + + if ! _namecheap_check_config; then + _err "$error" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + + _del_namecheap_TXT "$_domain" "$_sub_domain" "$txtvalue" + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + + if ! _namecheap_post "namecheap.domains.getList"; then + _err "$error" + return 1 + fi + + i=2 + p=1 + + while true; do + + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _contains "$response" "$h"; then + _debug "$h not found" + else + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +_namecheap_set_publicip() { + _publicip="$(_get https://ifconfig.co/ip)" +} + +_namecheap_post() { + command=$1 + data="ApiUser=${NAMECHEAP_USERNAME}&ApiKey=${NAMECHEAP_API_KEY}&ClientIp=${_publicip}&UserName=${NAMECHEAP_USERNAME}&Command=${command}" + + response="$(_post "$data" "$NAMECHEAP_API" "" "POST")" + _debug2 response "$response" + + if _contains "$response" "Status=\"ERROR\"" >/dev/null; then + error=$(echo "$response" | _egrep_o ">.*<\\/Error>" | cut -d '<' -f 1 | tr -d '>') + _err "error $error" + return 1 + fi + + return 0 +} + + +_namecheap_parse_host() { + _host=$1 + +#HostID UniqueID of the host records +#Name The domain or subdomain for which host record is set +#Type The type of host record that is set +#Address The value that is set for the host record (IP address for A record, URL for URL redirects, etc.) +#MXPref MXPreference number +#TTL TTL value for the host record + + _debug _host "$_host" + + _hostid=$(echo "$_host" | _egrep_o 'HostId=".*"' | cut -d '"' -f 2) + _hostname=$(echo "$_host" | _egrep_o 'Name=".*"' | cut -d '"' -f 2) + _hosttype=$(echo "$_host" | _egrep_o 'Type=".*"' | cut -d '"' -f 2) + _hostaddress=$(echo "$_host" | _egrep_o 'Address=".*"' | cut -d '"' -f 2) + _hostmxpref=$(echo "$_host" | _egrep_o 'MXPref=".*"' | cut -d '"' -f 2) + _hostttl=$(echo "$_host" | _egrep_o 'TTL=".*"' | cut -d '"' -f 2) + + _debug hostid "$_hostid" + _debug hostname "$_hostname" + _debug hosttype "$_hosttype" + _debug hostaddress "$_hostaddress" + _debug hostmxpref "$_hostmxpref" + _debug hostttl "$_hostttl" + +} + +_namecheap_check_config() { + + if [ -z "$NAMECHEAP_API_KEY" ]; then + _err "No API key specified for Namecheap API." + _err "Create your key and export it as NAMECHEAP_API_KEY" + return 1 + fi + + if [ -z "$NAMECHEAP_USERNAME" ]; then + _err "No username key specified for Namecheap API." + _err "Create your key and export it as NAMECHEAP_USERNAME" + return 1 + fi + + _saveaccountconf NAMECHEAP_API_KEY "$NAMECHEAP_API_KEY" + _saveaccountconf NAMECHEAP_USERNAME "$NAMECHEAP_USERNAME" + + return 0 +} + +_set_namecheap_TXT() { + subdomain=$2 + txt=$3 + tld=$(echo "$1" | cut -d '.' -f 2) + sld=$(echo "$1" | cut -d '.' -f 1) + request="namecheap.domains.dns.getHosts&SLD=$sld&TLD=$tld" + + if ! _namecheap_post "$request"; then + _err "$error" + return 1 + fi + + hosts=$(echo "$response" | _egrep_o '') + _debug hosts "$hosts" + + if [ -z "$hosts" ]; then + _error "Hosts not found" + return 1 + fi + + i=0 + found=0 + + while read host; do + + if _contains "$host" " Date: Wed, 5 Sep 2018 21:29:42 +0800 Subject: [PATCH 149/280] WIP --- dnsapi/dns_namecheap.sh | 78 +++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index 67aa3ac..89aeddd 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -19,7 +19,9 @@ dns_namecheap_add() { return 1 fi - _namecheap_set_publicip + if ! _namecheap_set_publicip; then + return 1 + fi _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -40,8 +42,10 @@ dns_namecheap_add() { dns_namecheap_rm() { fulldomain=$1 txtvalue=$2 - - _namecheap_set_publicip + + if ! _namecheap_set_publicip; then + return 1 + fi if ! _namecheap_check_config; then _err "$error" @@ -102,7 +106,35 @@ _get_root() { } _namecheap_set_publicip() { - _publicip="$(_get https://ifconfig.co/ip)" + + if [ -z "$NAMECHEAP_SOURCEIP" ]; then + _err "No Source IP specified for Namecheap API." + _err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP" + return 1 + else + _saveaccountconf NAMECHEAP_SOURCEIP "$NAMECHEAP_SOURCEIP" + _debug sourceip "$NAMECHEAP_SOURCEIP" + + ip=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}') + addr=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '(http|https)://.*') + + _debug2 ip "$ip" + _debug2 addr "$addr" + + if [ -n "$ip" ]; then + _publicip="$ip" + elif [ -n "$addr" ]; then + _publicip=$(_get "$addr") + else + _err "No Source IP specified for Namecheap API." + _err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP" + return 1 + fi + fi + + _debug publicip "$_publicip" + + return 0 } _namecheap_post() { @@ -124,14 +156,6 @@ _namecheap_post() { _namecheap_parse_host() { _host=$1 - -#HostID UniqueID of the host records -#Name The domain or subdomain for which host record is set -#Type The type of host record that is set -#Address The value that is set for the host record (IP address for A record, URL for URL redirects, etc.) -#MXPref MXPreference number -#TTL TTL value for the host record - _debug _host "$_host" _hostid=$(echo "$_host" | _egrep_o 'HostId=".*"' | cut -d '"' -f 2) @@ -190,38 +214,35 @@ _set_namecheap_TXT() { return 1 fi - i=0 + _namecheap_reset_hostList found=0 - while read host; do + while read -r host; do if _contains "$host" " Date: Fri, 7 Sep 2018 20:52:10 +0800 Subject: [PATCH 150/280] Usage --- dnsapi/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 891417f..48b0489 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -990,6 +990,27 @@ Now you can issue a certificate. acme.sh --issue --dns dns_gdnsdk -d example.com -d *.example.com ``` +## 53. Use Namecheap + +You will need your namecheap username, API KEY (https://www.namecheap.com/support/api/intro.aspx) and your external IP address (or an URL to get it), this IP will need to be whitelisted at Namecheap. +Due to Namecheap's AP limitation all the records of your domain will be read and re applied, make sure to have a backup of your records you could apply if any issue would arise. + +```sh +export NAMECHEAP_USERNAME="..." +export NAMECHEAP_API_KEY="..." +export NAMECHEAP_SOURCEIP="..." +``` + +NAMECHEAP_SOURCEIP can either be an IP address (e.g. 145.34.23.54) or an URL to provide it (e.g. https://ifconfig.co/ip). + +The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +Now you can issue a certificate. + +```sh +acme.sh --issue --dns dns_namecheap -d example.com -d *.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. From dc0dd6588c7172892e87c91af57efda1fffad447 Mon Sep 17 00:00:00 2001 From: LLeny Date: Fri, 7 Sep 2018 20:52:34 +0800 Subject: [PATCH 151/280] Support list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 904a478..b9a5cc5 100644 --- a/README.md +++ b/README.md @@ -326,6 +326,7 @@ You don't have to do anything manually! 1. ConoHa (https://www.conoha.jp) 1. netcup DNS API (https://www.netcup.de) 1. GratisDNS.dk (https://gratisdns.dk) +1. Namecheap API (https://www.namecheap.com/) And: From 8868783476809bf647fbd0c9efbba866306fe660 Mon Sep 17 00:00:00 2001 From: LLeny Date: Fri, 7 Sep 2018 20:52:49 +0800 Subject: [PATCH 152/280] Staging --- dnsapi/dns_namecheap.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index 89aeddd..73ed865 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -7,7 +7,11 @@ # ######## Public functions ##################### -NAMECHEAP_API="https://api.sandbox.namecheap.com/xml.response" +if [ "$STAGE" -eq 1 ]; then + NAMECHEAP_API="https://api.sandbox.namecheap.com/xml.response" +else + NAMECHEAP_API="https://api.namecheap.com/xml.response" +fi #Usage: dns_namecheap_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_namecheap_add() { From b859dd660c5b6c718fd71c595d3a1c1eb1e8bedd Mon Sep 17 00:00:00 2001 From: LLeny Date: Fri, 7 Sep 2018 20:53:21 +0800 Subject: [PATCH 153/280] dns_rm support --- dnsapi/dns_namecheap.sh | 80 +++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 19 deletions(-) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index 73ed865..0bf49e5 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -129,7 +129,7 @@ _namecheap_set_publicip() { _publicip="$ip" elif [ -n "$addr" ]; then _publicip=$(_get "$addr") - else + else _err "No Source IP specified for Namecheap API." _err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP" return 1 @@ -162,12 +162,12 @@ _namecheap_parse_host() { _host=$1 _debug _host "$_host" - _hostid=$(echo "$_host" | _egrep_o 'HostId=".*"' | cut -d '"' -f 2) - _hostname=$(echo "$_host" | _egrep_o 'Name=".*"' | cut -d '"' -f 2) - _hosttype=$(echo "$_host" | _egrep_o 'Type=".*"' | cut -d '"' -f 2) - _hostaddress=$(echo "$_host" | _egrep_o 'Address=".*"' | cut -d '"' -f 2) - _hostmxpref=$(echo "$_host" | _egrep_o 'MXPref=".*"' | cut -d '"' -f 2) - _hostttl=$(echo "$_host" | _egrep_o 'TTL=".*"' | cut -d '"' -f 2) + _hostid=$(echo "$_host" | _egrep_o '\sHostId="[^"]*' | cut -d '"' -f 2) + _hostname=$(echo "$_host" | _egrep_o '\sName="[^"]*' | cut -d '"' -f 2) + _hosttype=$(echo "$_host" | _egrep_o '\sType="[^"]*' | cut -d '"' -f 2) + _hostaddress=$(echo "$_host" | _egrep_o '\sAddress="[^"]*' | cut -d '"' -f 2) + _hostmxpref=$(echo "$_host" | _egrep_o '\sMXPref="[^"]*' | cut -d '"' -f 2) + _hostttl=$(echo "$_host" | _egrep_o '\sTTL="[^"]*' | cut -d '"' -f 2) _debug hostid "$_hostid" _debug hostname "$_hostname" @@ -210,7 +210,7 @@ _set_namecheap_TXT() { return 1 fi - hosts=$(echo "$response" | _egrep_o '') + hosts=$(echo "$response" | _egrep_o ']*') _debug hosts "$hosts" if [ -z "$hosts" ]; then @@ -219,29 +219,72 @@ _set_namecheap_TXT() { fi _namecheap_reset_hostList - found=0 while read -r host; do - if _contains "$host" "]*') + _debug hosts "$hosts" + + if [ -z "$hosts" ]; then + _error "Hosts not found" + return 1 + fi + + _namecheap_reset_hostList + + found=0 - if [ "$_hosttype" = "TXT" ] && [ "$_hostname" = "$subdomain" ]; then - _namecheap_add_host "$_hostname" "$_hosttype" "$txt" "$_hostmxpref" "$_hostttl" - found=1 + while read -r host; do + if _contains "$host" " Date: Sat, 8 Sep 2018 07:05:44 +0800 Subject: [PATCH 154/280] README fixes --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 48b0489..1421cc2 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -993,7 +993,7 @@ acme.sh --issue --dns dns_gdnsdk -d example.com -d *.example.com ## 53. Use Namecheap You will need your namecheap username, API KEY (https://www.namecheap.com/support/api/intro.aspx) and your external IP address (or an URL to get it), this IP will need to be whitelisted at Namecheap. -Due to Namecheap's AP limitation all the records of your domain will be read and re applied, make sure to have a backup of your records you could apply if any issue would arise. +Due to Namecheap's API limitation all the records of your domain will be read and re applied, make sure to have a backup of your records you could apply if any issue would arise. ```sh export NAMECHEAP_USERNAME="..." @@ -1001,7 +1001,7 @@ export NAMECHEAP_API_KEY="..." export NAMECHEAP_SOURCEIP="..." ``` -NAMECHEAP_SOURCEIP can either be an IP address (e.g. 145.34.23.54) or an URL to provide it (e.g. https://ifconfig.co/ip). +NAMECHEAP_SOURCEIP can either be an IP address or an URL to provide it (e.g. https://ifconfig.co/ip). The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed. From 30ee00ff50fca9345110c69c0cd4b9827f96f65d Mon Sep 17 00:00:00 2001 From: LLeny Date: Sat, 8 Sep 2018 07:06:16 +0800 Subject: [PATCH 155/280] RM TXT check --- dnsapi/dns_namecheap.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index 0bf49e5..9cf6fb1 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -270,8 +270,7 @@ _del_namecheap_TXT() { while read -r host; do if _contains "$host" " Date: Sat, 8 Sep 2018 07:06:35 +0800 Subject: [PATCH 156/280] NC API warning --- dnsapi/dns_namecheap.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index 9cf6fb1..a368608 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -3,8 +3,9 @@ # Namecheap API # https://www.namecheap.com/support/api/intro.aspx # -# Requires Namecheap API key set in NAMECHEAP_API_KEY and NAMECHEAP_USERNAME set as environment variable -# +# Requires Namecheap API key set in NAMECHEAP_API_KEY, NAMECHEAP_SOURCEIP and NAMECHEAP_USERNAME set as environment variable +# Due to Namecheap's API limitation all the records of your domain will be read and re applied, make sure to have a backup of your records you could apply if any issue would arise. + ######## Public functions ##################### if [ "$STAGE" -eq 1 ]; then From 697e694de692b04531db2bc7e309c1afbe5e2616 Mon Sep 17 00:00:00 2001 From: LLeny Date: Sat, 8 Sep 2018 07:28:56 +0800 Subject: [PATCH 157/280] Indentation --- dnsapi/dns_namecheap.sh | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index a368608..9ace134 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -20,12 +20,12 @@ dns_namecheap_add() { txtvalue=$2 if ! _namecheap_check_config; then - _err "$error" - return 1 + _err "$error" + return 1 fi if ! _namecheap_set_publicip; then - return 1 + return 1 fi _debug "First detect the root zone" @@ -49,12 +49,12 @@ dns_namecheap_rm() { txtvalue=$2 if ! _namecheap_set_publicip; then - return 1 + return 1 fi if ! _namecheap_check_config; then - _err "$error" - return 1 + _err "$error" + return 1 fi _debug "First detect the root zone" @@ -81,8 +81,8 @@ _get_root() { domain=$1 if ! _namecheap_post "namecheap.domains.getList"; then - _err "$error" - return 1 + _err "$error" + return 1 fi i=2 @@ -117,7 +117,7 @@ _namecheap_set_publicip() { _err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP" return 1 else - _saveaccountconf NAMECHEAP_SOURCEIP "$NAMECHEAP_SOURCEIP" + _saveaccountconf NAMECHEAP_SOURCEIP "$NAMECHEAP_SOURCEIP" _debug sourceip "$NAMECHEAP_SOURCEIP" ip=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}') @@ -207,16 +207,16 @@ _set_namecheap_TXT() { request="namecheap.domains.dns.getHosts&SLD=$sld&TLD=$tld" if ! _namecheap_post "$request"; then - _err "$error" - return 1 + _err "$error" + return 1 fi hosts=$(echo "$response" | _egrep_o ']*') _debug hosts "$hosts" if [ -z "$hosts" ]; then - _error "Hosts not found" - return 1 + _error "Hosts not found" + return 1 fi _namecheap_reset_hostList @@ -237,8 +237,8 @@ EOT request="namecheap.domains.dns.setHosts&SLD=${sld}&TLD=${tld}${_hostrequest}" if ! _namecheap_post "$request"; then - _err "$error" - return 1 + _err "$error" + return 1 fi return 0 @@ -252,16 +252,16 @@ _del_namecheap_TXT() { request="namecheap.domains.dns.getHosts&SLD=$sld&TLD=$tld" if ! _namecheap_post "$request"; then - _err "$error" - return 1 + _err "$error" + return 1 fi hosts=$(echo "$response" | _egrep_o ']*') _debug hosts "$hosts" if [ -z "$hosts" ]; then - _error "Hosts not found" - return 1 + _error "Hosts not found" + return 1 fi _namecheap_reset_hostList @@ -271,9 +271,9 @@ _del_namecheap_TXT() { while read -r host; do if _contains "$host" " Date: Sat, 8 Sep 2018 08:06:35 +0800 Subject: [PATCH 158/280] shfmt --- dnsapi/dns_namecheap.sh | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index 9ace134..7089c2d 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -47,7 +47,7 @@ dns_namecheap_add() { dns_namecheap_rm() { fulldomain=$1 txtvalue=$2 - + if ! _namecheap_set_publicip; then return 1 fi @@ -69,7 +69,6 @@ dns_namecheap_rm() { _debug sub_domain "$_sub_domain" _del_namecheap_TXT "$_domain" "$_sub_domain" "$txtvalue" - } #################### Private functions below ################################## @@ -89,7 +88,7 @@ _get_root() { p=1 while true; do - + h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" if [ -z "$h" ]; then @@ -111,7 +110,7 @@ _get_root() { } _namecheap_set_publicip() { - + if [ -z "$NAMECHEAP_SOURCEIP" ]; then _err "No Source IP specified for Namecheap API." _err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP" @@ -119,13 +118,13 @@ _namecheap_set_publicip() { else _saveaccountconf NAMECHEAP_SOURCEIP "$NAMECHEAP_SOURCEIP" _debug sourceip "$NAMECHEAP_SOURCEIP" - + ip=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}') addr=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '(http|https)://.*') - + _debug2 ip "$ip" _debug2 addr "$addr" - + if [ -n "$ip" ]; then _publicip="$ip" elif [ -n "$addr" ]; then @@ -136,16 +135,16 @@ _namecheap_set_publicip() { return 1 fi fi - + _debug publicip "$_publicip" - + return 0 } _namecheap_post() { command=$1 data="ApiUser=${NAMECHEAP_USERNAME}&ApiKey=${NAMECHEAP_API_KEY}&ClientIp=${_publicip}&UserName=${NAMECHEAP_USERNAME}&Command=${command}" - + response="$(_post "$data" "$NAMECHEAP_API" "" "POST")" _debug2 response "$response" @@ -158,7 +157,6 @@ _namecheap_post() { return 0 } - _namecheap_parse_host() { _host=$1 _debug _host "$_host" @@ -176,7 +174,6 @@ _namecheap_parse_host() { _debug hostaddress "$_hostaddress" _debug hostmxpref "$_hostmxpref" _debug hostttl "$_hostttl" - } _namecheap_check_config() { @@ -273,7 +270,7 @@ _del_namecheap_TXT() { _namecheap_parse_host "$host" if [ "$_hosttype" = "TXT" ] && [ "$_hostname" = "$subdomain" ] && [ "$_hostaddress" = "$txt" ]; then _debug "TXT entry found" - found=1 + found=1 else _namecheap_add_host "$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl" fi From 80b40c02b453538191f66d6d44aefbf7aed4b850 Mon Sep 17 00:00:00 2001 From: Christian Brandel Date: Mon, 10 Sep 2018 01:24:20 +0200 Subject: [PATCH 159/280] use perl instead of iconv, if iconv is not available --- deploy/fritzbox.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index 943b198..21ea6cf 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -28,8 +28,10 @@ fritzbox_deploy() { _debug _cfullchain "$_cfullchain" if ! _exists iconv; then - _err "iconv not found" - return 1 + if ! _exists perl; then + _err "iconv or perl not found" + return 1 + fi fi _fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}" @@ -61,7 +63,11 @@ fritzbox_deploy() { _info "Log in to the FRITZ!Box" _fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" - _fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" + if _exists iconv; then + _fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" + else + _fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | md5sum | awk '{print $1}')" + fi _fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then From 5b7cac100220f4d6354d400d655c2e87d9023999 Mon Sep 17 00:00:00 2001 From: Tom Blauwendraat Date: Wed, 12 Sep 2018 05:34:56 +0200 Subject: [PATCH 160/280] [FIX] Delete all occurrences of TXT key, dont fail if there is more than one, [FIX] Respect pagination on domain listing, before only the first page was loaded --- dnsapi/dns_dgon.sh | 153 ++++++++++++++++++++++++++------------------- 1 file changed, 89 insertions(+), 64 deletions(-) diff --git a/dnsapi/dns_dgon.sh b/dnsapi/dns_dgon.sh index 5d38ef7..e92c780 100755 --- a/dnsapi/dns_dgon.sh +++ b/dnsapi/dns_dgon.sh @@ -104,47 +104,59 @@ dns_dgon_rm() { ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}} GURL="https://api.digitalocean.com/v2/domains/$_domain/records" - ## while we dont have a record ID we keep going - while [ -z "$record" ]; do + ## Get all the matching records + while [ true ]; do ## 1) get the URL ## the create request - get ## args: URL, [onlyheader, timeout] domain_list="$(_get "$GURL")" - ## 2) find record - ## check for what we are looing for: "type":"A","name":"$_sub_domain" - record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[0-9]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")" - ## 3) check record and get next page - if [ -z "$record" ]; then - ## find the next page if we dont have a match - nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")" - if [ -z "$nextpage" ]; then - _err "no record and no nextpage in digital ocean DNS removal" - return 1 - fi - _debug2 nextpage "$nextpage" - GURL="$nextpage" + + ## check response + if [ "$?" != "0" ]; then + _err "error in domain_list response: $domain_list" + return 1 fi - ## we break out of the loop when we have a record - done + _debug2 domain_list "$domain_list" - ## we found the record - rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")" - _debug rec_id "$rec_id" + ## 2) find records + ## check for what we are looking for: "type":"A","name":"$_sub_domain" + record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[0-9]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")" - ## delete the record - ## delete URL for removing the one we dont want - DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id" + if [ ! -z "$record" ]; then + + ## we found records + rec_ids="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")" + _debug rec_ids "$rec_ids" + if [ ! -z "$rec_ids" ]; then + echo "$rec_ids" | while IFS= read -r rec_id ; do + ## delete the record + ## delete URL for removing the one we dont want + DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id" + + ## the create request - delete + ## args: BODY, URL, [need64, httpmethod] + response="$(_post "" "$DURL" "" "DELETE")" + + ## check response (sort of) + if [ "$?" != "0" ]; then + _err "error in remove response: $response" + return 1 + fi + _debug2 response "$response" + + done + fi + fi - ## the create request - delete - ## args: BODY, URL, [need64, httpmethod] - response="$(_post "" "$DURL" "" "DELETE")" + ## 3) find the next page + nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")" + if [ -z "$nextpage" ]; then + break + fi + _debug2 nextpage "$nextpage" + GURL="$nextpage" - ## check response (sort of) - if [ "$?" != "0" ]; then - _err "error in remove response: $response" - return 1 - fi - _debug2 response "$response" + done ## finished correctly return 0 @@ -178,44 +190,57 @@ _get_base_domain() { export _H2="Authorization: Bearer $DO_API_KEY" _debug DO_API_KEY "$DO_API_KEY" ## get URL for the list of domains - ## havent seen this request paginated, tested with 18 domains (more requires manual requests with DO) + ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}} DOMURL="https://api.digitalocean.com/v2/domains" - ## get the domain list (DO gives basically a full XFER!) - domain_list="$(_get "$DOMURL")" + ## while we dont have a matching domain we keep going + while [ -z "$found" ]; do + ## get the domain list (current page) + domain_list="$(_get "$DOMURL")" - ## check response - if [ "$?" != "0" ]; then - _err "error in domain_list response: $domain_list" - return 1 - fi - _debug2 domain_list "$domain_list" - - ## for each shortening of our $fulldomain, check if it exists in the $domain_list - ## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge" - i=2 - while [ $i -gt 0 ]; do - ## get next longest domain - _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM") - ## check we got something back from our cut (or are we at the end) - if [ -z "$_domain" ]; then - ## we got to the end of the domain - invalid domain - _err "domain not found in DigitalOcean account" + ## check response + if [ "$?" != "0" ]; then + _err "error in domain_list response: $domain_list" return 1 fi - ## we got part of a domain back - grep it out - found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")" - ## check if it exists - if [ ! -z "$found" ]; then - ## exists - exit loop returning the parts - sub_point=$(_math $i - 1) - _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point") - _debug _domain "$_domain" - _debug _sub_domain "$_sub_domain" - return 0 + _debug2 domain_list "$domain_list" + + ## for each shortening of our $fulldomain, check if it exists in the $domain_list + ## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge" + i=2 + while [ $i -gt 0 ]; do + ## get next longest domain + _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM") + ## check we got something back from our cut (or are we at the end) + if [ -z "$_domain" ]; then + break + fi + ## we got part of a domain back - grep it out + found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")" + ## check if it exists + if [ ! -z "$found" ]; then + ## exists - exit loop returning the parts + sub_point=$(_math $i - 1) + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point") + _debug _domain "$_domain" + _debug _sub_domain "$_sub_domain" + return 0 + fi + ## increment cut point $i + i=$(_math $i + 1) + done + + if [ -z "$found" ]; then + ## find the next page if we dont have a match + nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")" + if [ -z "$nextpage" ]; then + _err "no record and no nextpage in digital ocean DNS removal" + return 1 + fi + _debug2 nextpage "$nextpage" + DOMURL="$nextpage" fi - ## increment cut point $i - i=$(_math $i + 1) + done ## we went through the entire domain zone list and dint find one that matched From 4a18c45e4f34bcc05ecc3891af9ac72f5df2b68f Mon Sep 17 00:00:00 2001 From: Tom Blauwendraat Date: Wed, 12 Sep 2018 05:46:51 +0200 Subject: [PATCH 161/280] fixup! [FIX] Delete all occurrences of TXT key, dont fail if there is more than one, [FIX] Respect pagination on domain listing, before only the first page was loaded --- dnsapi/dns_dgon.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_dgon.sh b/dnsapi/dns_dgon.sh index e92c780..24e1a9f 100755 --- a/dnsapi/dns_dgon.sh +++ b/dnsapi/dns_dgon.sh @@ -105,7 +105,7 @@ dns_dgon_rm() { GURL="https://api.digitalocean.com/v2/domains/$_domain/records" ## Get all the matching records - while [ true ]; do + while true; do ## 1) get the URL ## the create request - get ## args: URL, [onlyheader, timeout] @@ -128,7 +128,7 @@ dns_dgon_rm() { rec_ids="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")" _debug rec_ids "$rec_ids" if [ ! -z "$rec_ids" ]; then - echo "$rec_ids" | while IFS= read -r rec_id ; do + echo "$rec_ids" | while IFS= read -r rec_id; do ## delete the record ## delete URL for removing the one we dont want DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id" From 332263073222754fa6fe5066b1a38e06d831276b Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 25 Sep 2018 23:42:04 +0800 Subject: [PATCH 162/280] minor, debug msg --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 32219d9..db2953e 100755 --- a/acme.sh +++ b/acme.sh @@ -1809,14 +1809,14 @@ _send_signed_request() { if [ -z "$_CACHED_NONCE" ]; then _headers="" if [ "$ACME_NEW_NONCE" ]; then - _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" + _debug2 "Get nonce with HEAD. ACME_NEW_NONCE" "$ACME_NEW_NONCE" nonceurl="$ACME_NEW_NONCE" if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then _headers="$(cat "$HTTP_HEADER")" fi fi if [ -z "$_headers" ]; then - _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" + _debug2 "Get nonce with GET. ACME_DIRECTORY" "$ACME_DIRECTORY" nonceurl="$ACME_DIRECTORY" _headers="$(_get "$nonceurl" "onlyheader")" fi From 4c1f70af4b27781a3f5055328f704a268fb8a5d4 Mon Sep 17 00:00:00 2001 From: evoadmin Date: Tue, 2 Oct 2018 10:43:25 +0300 Subject: [PATCH 163/280] Update dns_he.sh If you have a password with special char it will fail at Remove record --- dnsapi/dns_he.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index da4a1b8..df00c74 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -92,7 +92,9 @@ dns_he_rm() { return 1 fi # Remove the record - body="email=${HE_Username}&pass=${HE_Password}" + username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)" + body="email=${username_encoded}&pass=${password_encoded}" body="$body&menu=edit_zone" body="$body&hosted_dns_zoneid=$_zone_id" body="$body&hosted_dns_recordid=$_record_id" From 9f6f721a133a30ea135d33ea004d30ffbac31de8 Mon Sep 17 00:00:00 2001 From: Ephen Date: Mon, 15 Oct 2018 17:11:25 +0800 Subject: [PATCH 164/280] cloudxns.net cloudxns.net is the main domain. --- dnsapi/dns_cx.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index f2d3ead..d07d8e0 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -# Cloudxns.com Domain api +# CloudXNS Domain api # #CX_Key="1234" # @@ -19,7 +19,7 @@ dns_cx_add() { if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then CX_Key="" CX_Secret="" - _err "You don't specify cloudxns.com api key or secret yet." + _err "You don't specify cloudxns.net api key or secret yet." _err "Please create you key and try again." return 1 fi From fd536d373ebd65eecf8ce8e2f760ef186e5ce74f Mon Sep 17 00:00:00 2001 From: Phil Ross Date: Thu, 18 Oct 2018 17:12:06 +0100 Subject: [PATCH 165/280] Skip aliases of already verified domains. When issuing a two-domain certificate using a different alias for each domain, if the first domain is already verified, verification for the second domain would be attempted (unsuccessfully) using the alias of the first domain. Increment the alias index when skipping verified domains so that the correct alias will be used for subsequent domains. --- acme.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/acme.sh b/acme.sh index ee23827..8ae6600 100755 --- a/acme.sh +++ b/acme.sh @@ -2925,6 +2925,7 @@ _clearupdns() { _debug txt "$txt" if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _debug "$d is already verified, skip $vtype." + _alias_index="$(_math "$_alias_index" + 1)" continue fi @@ -3775,6 +3776,7 @@ $_authorizations_map" _debug d "$d" if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _debug "$d is already verified, skip $vtype." + _alias_index="$(_math "$_alias_index" + 1)" continue fi From 26421684dc0c7c0cc79ea36f728d44de2fa382f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Thu, 26 Jul 2018 19:59:15 +0200 Subject: [PATCH 166/280] Fix inwx account without Mobile TAN --- dnsapi/dns_inwx.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index cd5af91..f4590cf 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -158,7 +158,8 @@ _inwx_login() { export _H1 #https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71 - if _contains "$response" "tfa"; then + if _contains "$response" "code1000" \ + && _contains "$response" "tfaGOOGLE-AUTH"; then if [ -z "$INWX_Shared_Secret" ]; then _err "Mobile TAN detected." _err "Please define a shared secret." From 46b3a9158c80ab5f1c76437ed1fb9fad2c13e96a Mon Sep 17 00:00:00 2001 From: LLeny <5269958+LLeny@users.noreply.github.com> Date: Sun, 21 Oct 2018 18:17:23 +0800 Subject: [PATCH 167/280] Fixes Neilpang/acme.sh#1888 --- dnsapi/dns_namecheap.sh | 64 +++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index 7089c2d..a6651be 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -199,9 +199,12 @@ _namecheap_check_config() { _set_namecheap_TXT() { subdomain=$2 txt=$3 - tld=$(echo "$1" | cut -d '.' -f 2) - sld=$(echo "$1" | cut -d '.' -f 1) - request="namecheap.domains.dns.getHosts&SLD=$sld&TLD=$tld" + + if ! _namecheap_set_tld_sld "$1"; then + return 1 + fi + + request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}" if ! _namecheap_post "$request"; then _err "$error" @@ -231,7 +234,7 @@ EOT _debug hostrequestfinal "$_hostrequest" - request="namecheap.domains.dns.setHosts&SLD=${sld}&TLD=${tld}${_hostrequest}" + request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}" if ! _namecheap_post "$request"; then _err "$error" @@ -244,9 +247,12 @@ EOT _del_namecheap_TXT() { subdomain=$2 txt=$3 - tld=$(echo "$1" | cut -d '.' -f 2) - sld=$(echo "$1" | cut -d '.' -f 1) - request="namecheap.domains.dns.getHosts&SLD=$sld&TLD=$tld" + + if ! _namecheap_set_tld_sld "$1"; then + return 1 + fi + + request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}" if ! _namecheap_post "$request"; then _err "$error" @@ -286,7 +292,7 @@ EOT _debug hostrequestfinal "$_hostrequest" - request="namecheap.domains.dns.setHosts&SLD=${sld}&TLD=${tld}${_hostrequest}" + request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}" if ! _namecheap_post "$request"; then _err "$error" @@ -306,3 +312,45 @@ _namecheap_add_host() { _hostindex=$(_math "$_hostindex" + 1) _hostrequest=$(printf '%s&HostName%d=%s&RecordType%d=%s&Address%d=%s&MXPref%d=%d&TTL%d=%d' "$_hostrequest" "$_hostindex" "$1" "$_hostindex" "$2" "$_hostindex" "$3" "$_hostindex" "$4" "$_hostindex" "$5") } + +_namecheap_set_tld_sld() { + domain=$1 + _tld="" + _sld="" + + i=2 + + while true; do + + _tld=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug tld "$_tld" + + if [ -z "$_tld" ]; then + _debug "invalid tld" + return 1 + fi + + j=$(_math "$i" - 1) + + _sld=$(printf "%s" "$domain" | cut -d . -f 1-"$j") + _debug sld "$_sld" + + if [ -z "$_sld" ]; then + _debug "invalid sld" + return 1 + fi + + request="namecheap.domains.dns.getHosts&SLD=$_sld&TLD=$_tld" + + if ! _namecheap_post "$request"; then + _debug "sld($_sld)/tld($_tld) not found" + else + _debug "sld($_sld)/tld($_tld) found" + return 0 + fi + + i=$(_math "$i" + 1) + + done + +} From a894b7cc9b374d5588b346a9afde1282b5d067d3 Mon Sep 17 00:00:00 2001 From: hebbet Date: Wed, 24 Oct 2018 16:33:02 +0200 Subject: [PATCH 168/280] add link to cloudflare profil for api key --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 2cecfa5..71ba53b 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -6,7 +6,7 @@ https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode ## 1. Use CloudFlare domain API to automatically issue cert -First you need to login to your CloudFlare account to get your API key. +First you need to login to your CloudFlare account to get your [API key](https://dash.cloudflare.com/profile). ``` export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" From 9672c6b885a100a9c83ce1651591271a5f3e2b2a Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 30 Oct 2018 22:14:49 +0800 Subject: [PATCH 169/280] fix https://github.com/Neilpang/acme.sh/issues/1905 --- acme.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index ee23827..b59332b 100755 --- a/acme.sh +++ b/acme.sh @@ -4602,7 +4602,8 @@ deploy() { _initpath "$_d" "$_isEcc" if [ ! -d "$DOMAIN_PATH" ]; then - _err "Domain is not valid:'$_d'" + _err "The domain '$_d' is not a cert name. You must use the cert name to specify the cert to install." + _err "Can not find path:'$DOMAIN_PATH'" return 1 fi @@ -4629,7 +4630,8 @@ installcert() { _initpath "$_main_domain" "$_isEcc" if [ ! -d "$DOMAIN_PATH" ]; then - _err "Domain is not valid:'$_main_domain'" + _err "The domain '$_main_domain' is not a cert name. You must use the cert name to specify the cert to install." + _err "Can not find path:'$DOMAIN_PATH'" return 1 fi From 7903fcb48c3b90bced87b187a05c538ec7c74fe8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 30 Oct 2018 22:50:44 +0800 Subject: [PATCH 170/280] fix typo --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index b59332b..7944d5d 100755 --- a/acme.sh +++ b/acme.sh @@ -5476,7 +5476,7 @@ Parameters: --log-level 1|2 Specifies the log level, default is 1. --syslog [0|3|6|7] Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug. - These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: + These parameters are to install the cert to nginx/apache or any other server after issue/renew a cert: --cert-file After issue/renew, the cert will be copied to this path. --key-file After issue/renew, the key will be copied to this path. From 12956679e73e615882fc556518fba00c2d07baf4 Mon Sep 17 00:00:00 2001 From: Joakim Lemb Date: Mon, 5 Nov 2018 14:52:26 +0100 Subject: [PATCH 171/280] Added top URI parameter --- dnsapi/dns_azure.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index c6893a0..ae8aa1c 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -316,7 +316,7 @@ _get_root() { ## (ZoneListResult with continuation token for the next page of results) ## Per https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#dns-limits you are limited to 100 Zone/subscriptions anyways ## - _azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?api-version=2017-09-01" "" "$accesstoken" + _azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?\$top=500&api-version=2017-09-01" "" "$accesstoken" # Find matching domain name is Json response while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) From 4b581f37203a8dea1c7c1ef5d25322fed49bb3e8 Mon Sep 17 00:00:00 2001 From: pavelaks Date: Sat, 10 Nov 2018 12:10:06 +0300 Subject: [PATCH 172/280] Update README.md Fix VSCALE example (add export before VSCALE_API_KEY) --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 2cecfa5..9413925 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -454,7 +454,7 @@ The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account. First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). ``` -VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" +export VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" ``` Ok, let's issue a cert now: From 552710ac2a2e5dcb85d31f3d3d4ed5c2a0dbd5ec Mon Sep 17 00:00:00 2001 From: nakermann1973 <35577878+nakermann1973@users.noreply.github.com> Date: Tue, 13 Nov 2018 10:15:38 +0100 Subject: [PATCH 173/280] Add missing bind-tools package The bind_tools package is required for dns_nsupdate to work --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 5a64c72..c1a2199 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,7 @@ RUN apk update -f \ && apk --no-cache add -f \ openssl \ coreutils \ + bind-tools \ curl \ socat \ && rm -rf /var/cache/apk/* From 5fee82ce39e70a301cece87185762f415489b258 Mon Sep 17 00:00:00 2001 From: Thomas Rohlik Date: Mon, 19 Nov 2018 16:09:32 +0100 Subject: [PATCH 174/280] Fix dot Very important commit :1st_place_medal: --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index ee23827..0930eff 100755 --- a/acme.sh +++ b/acme.sh @@ -5485,7 +5485,7 @@ Parameters: --server SERVER ACME Directory Resource URI. (default: https://acme-v01.api.letsencrypt.org/directory) --accountconf Specifies a customized account config file. - --home Specifies the home dir for $PROJECT_NAME . + --home Specifies the home dir for $PROJECT_NAME. --cert-home Specifies the home dir to save all the certs, only valid for '--install' command. --config-home Specifies the home dir to save all the configurations. --useragent Specifies the user agent string. it will be saved for future use too. From 137dc1eac0bdc6f664c7fbc3aae9b1cce4c58a85 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 23 Nov 2018 22:53:02 +0800 Subject: [PATCH 175/280] fix https://github.com/Neilpang/acme.sh/issues/1912 --- acme.sh | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index c7138c1..502b695 100755 --- a/acme.sh +++ b/acme.sh @@ -124,23 +124,19 @@ if [ -t 1 ]; then fi __green() { - if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then - printf '\033[1;31;32m' + if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then + printf '\033[1;31;32m%b\033[0m' "$1" + return fi printf -- "%b" "$1" - if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then - printf '\033[0m' - fi } __red() { - if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then - printf '\033[1;31;40m' + if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then + printf '\033[1;31;40m%b\033[0m' "$1" + return fi printf -- "%b" "$1" - if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then - printf '\033[0m' - fi } _printargs() { From a6f2110141011c950c6709b083331f0dd933de9b Mon Sep 17 00:00:00 2001 From: epgdatacapbon Date: Sat, 24 Nov 2018 01:58:46 +0900 Subject: [PATCH 176/280] Add DNS API support for MyDNS.JP --- dnsapi/README.md | 16 ++++ dnsapi/dns_mydnsjp.sh | 210 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 dnsapi/dns_mydnsjp.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index 2cecfa5..7362eb2 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1014,6 +1014,22 @@ Now you can issue a certificate. acme.sh --issue --dns dns_namecheap -d example.com -d *.example.com ``` +## 54. Use MyDNS.JP API + +First, register to MyDNS.JP and get MasterID and Password. + +``` +export MYDNSJP_MasterID=MasterID +export MYDNSJP_Password=Password +``` + +To issue a certificate: + +``` +acme.sh --issue --dns dns_mydnsjp -d example.com -d www.example.com +``` +The `MYDNSJP_MasterID` and `MYDNSJP_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_mydnsjp.sh b/dnsapi/dns_mydnsjp.sh new file mode 100644 index 0000000..d421329 --- /dev/null +++ b/dnsapi/dns_mydnsjp.sh @@ -0,0 +1,210 @@ +#!/usr/bin/env sh + +#Here is a api script for MyDNS.JP. +#This file name is "dns_mydnsjp.sh" +#So, here must be a method dns_mydnsjp_add() +#Which will be called by acme.sh to add the txt record to your api system. +#returns 0 means success, otherwise error. +# +#Author: epgdatacapbon +#Report Bugs here: https://github.com/epgdatacapbon/acme.sh +# +######## Public functions ##################### + +# Export MyDNS.JP MasterID and Password in following variables... +# MYDNSJP_MasterID=MasterID +# MYDNSJP_Password=Password + +MYDNSJP_API="http://www.mydns.jp" + +#Usage: dns_mydnsjp_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_mydnsjp_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Using mydnsjp" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + # Load the credentials from the account conf file + MYDNSJP_MasterID="${MYDNSJP_MasterID:-$(_readaccountconf_mutable MYDNSJP_MasterID)}" + MYDNSJP_Password="${MYDNSJP_Password:-$(_readaccountconf_mutable MYDNSJP_Password)}" + if [ -z "$MYDNSJP_MasterID" ] || [ -z "$MYDNSJP_Password" ]; then + MYDNSJP_MasterID="" + MYDNSJP_Password="" + _err "You don't specify mydnsjp api MasterID and Password yet." + _err "Please export as MYDNSJP_MasterID / MYDNSJP_Password and try again." + return 1 + fi + + # Save the credentials to the account conf file + _saveaccountconf_mutable MYDNSJP_MasterID "$MYDNSJP_MasterID" + _saveaccountconf_mutable MYDNSJP_Password "$MYDNSJP_Password" + + _debug "First detect the root zone." + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _mydnsjp_api "REGIST" "$_domain" "$txtvalue"; then + if printf -- "%s" "$response" | grep "OK." >/dev/null; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_mydnsjp_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Removing TXT record" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + # Load the credentials from the account conf file + MYDNSJP_MasterID="${MYDNSJP_MasterID:-$(_readaccountconf_mutable MYDNSJP_MasterID)}" + MYDNSJP_Password="${MYDNSJP_Password:-$(_readaccountconf_mutable MYDNSJP_Password)}" + if [ -z "$MYDNSJP_MasterID" ] || [ -z "$MYDNSJP_Password" ]; then + MYDNSJP_MasterID="" + MYDNSJP_Password="" + _err "You don't specify mydnsjp api MasterID and Password yet." + _err "Please export as MYDNSJP_MasterID / MYDNSJP_Password and try again." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _mydnsjp_api "DELETE" "$_domain" "$txtvalue"; then + if printf -- "%s" "$response" | grep "OK." >/dev/null; then + _info "Deleted, OK" + return 0 + else + _err "Delete txt record error." + return 1 + fi + fi + _err "Delete txt record error." + + return 1 +} + +#################### Private functions below ################################## +# _acme-challenge.www.domain.com +# returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + fulldomain=$1 + i=2 + p=1 + + # Get the root domain + _mydnsjp_retrieve_domain + if [ "$?" != "0" ]; then + # not valid + return 1 + fi + + while true; do + _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + + if [ -z "$_domain" ]; then + # not valid + return 1 + fi + + if [ "$_domain" = "$_root_domain" ]; then + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +# Retrieve the root domain +# returns 0 success +_mydnsjp_retrieve_domain() { + _debug "Login to MyDNS.JP" + + response="$(_post "masterid=$MYDNSJP_MasterID&masterpwd=$MYDNSJP_Password" "$MYDNSJP_API/?MENU=100")" + cookie="$(grep '^Set-Cookie:' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2)" + + # If cookies is not empty then logon successful + if [ -z "$cookie" ]; then + _err "Fail to get a cookie." + return 1 + fi + + _debug "Retrieve DOMAIN INFO page" + + export _H1="Cookie:${cookie}" + + response="$(_get "$MYDNSJP_API/?MENU=300")" + + if [ "$?" != "0" ]; then + _err "Fail to retrieve DOMAIN INFO." + return 1 + fi + + _root_domain=$(echo "$response" | grep "DNSINFO\[domainname\]" | sed 's/^.*value="\([^"]*\)".*/\1/') + + # Logout + response="$(_get "$MYDNSJP_API/?MENU=090")" + + _debug _root_domain "$_root_domain" + + if [ -z "$_root_domain" ]; then + _err "Fail to get the root domain." + return 1 + fi + + return 0 +} + +_mydnsjp_api() { + cmd=$1 + domain=$2 + txtvalue=$3 + + # Base64 encode the credentials + credentials=$(printf "%s:%s" "$MYDNSJP_MasterID" "$MYDNSJP_Password" | _base64) + + # Construct the HTTP Authorization header + export _H1="Content-Type: application/x-www-form-urlencoded" + export _H2="Authorization: Basic ${credentials}" + + response="$(_post "CERTBOT_DOMAIN=$domain&CERTBOT_VALIDATION=$txtvalue&EDIT_CMD=$cmd" "$MYDNSJP_API/directedit.html")" + + if [ "$?" != "0" ]; then + _err "error $domain" + return 1 + fi + + _debug2 response "$response" + + return 0 +} From 14ad5955b58a48720da0b70bb902900029f9b3f8 Mon Sep 17 00:00:00 2001 From: epgdatacapbon Date: Sat, 24 Nov 2018 01:58:46 +0900 Subject: [PATCH 177/280] Add DNS API support for MyDNS.JP --- dnsapi/README.md | 16 ++++ dnsapi/dns_mydnsjp.sh | 210 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 dnsapi/dns_mydnsjp.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index 02e8fd8..f126568 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1014,6 +1014,22 @@ Now you can issue a certificate. acme.sh --issue --dns dns_namecheap -d example.com -d *.example.com ``` +## 54. Use MyDNS.JP API + +First, register to MyDNS.JP and get MasterID and Password. + +``` +export MYDNSJP_MasterID=MasterID +export MYDNSJP_Password=Password +``` + +To issue a certificate: + +``` +acme.sh --issue --dns dns_mydnsjp -d example.com -d www.example.com +``` +The `MYDNSJP_MasterID` and `MYDNSJP_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_mydnsjp.sh b/dnsapi/dns_mydnsjp.sh new file mode 100644 index 0000000..d421329 --- /dev/null +++ b/dnsapi/dns_mydnsjp.sh @@ -0,0 +1,210 @@ +#!/usr/bin/env sh + +#Here is a api script for MyDNS.JP. +#This file name is "dns_mydnsjp.sh" +#So, here must be a method dns_mydnsjp_add() +#Which will be called by acme.sh to add the txt record to your api system. +#returns 0 means success, otherwise error. +# +#Author: epgdatacapbon +#Report Bugs here: https://github.com/epgdatacapbon/acme.sh +# +######## Public functions ##################### + +# Export MyDNS.JP MasterID and Password in following variables... +# MYDNSJP_MasterID=MasterID +# MYDNSJP_Password=Password + +MYDNSJP_API="http://www.mydns.jp" + +#Usage: dns_mydnsjp_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_mydnsjp_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Using mydnsjp" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + # Load the credentials from the account conf file + MYDNSJP_MasterID="${MYDNSJP_MasterID:-$(_readaccountconf_mutable MYDNSJP_MasterID)}" + MYDNSJP_Password="${MYDNSJP_Password:-$(_readaccountconf_mutable MYDNSJP_Password)}" + if [ -z "$MYDNSJP_MasterID" ] || [ -z "$MYDNSJP_Password" ]; then + MYDNSJP_MasterID="" + MYDNSJP_Password="" + _err "You don't specify mydnsjp api MasterID and Password yet." + _err "Please export as MYDNSJP_MasterID / MYDNSJP_Password and try again." + return 1 + fi + + # Save the credentials to the account conf file + _saveaccountconf_mutable MYDNSJP_MasterID "$MYDNSJP_MasterID" + _saveaccountconf_mutable MYDNSJP_Password "$MYDNSJP_Password" + + _debug "First detect the root zone." + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _mydnsjp_api "REGIST" "$_domain" "$txtvalue"; then + if printf -- "%s" "$response" | grep "OK." >/dev/null; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_mydnsjp_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Removing TXT record" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + # Load the credentials from the account conf file + MYDNSJP_MasterID="${MYDNSJP_MasterID:-$(_readaccountconf_mutable MYDNSJP_MasterID)}" + MYDNSJP_Password="${MYDNSJP_Password:-$(_readaccountconf_mutable MYDNSJP_Password)}" + if [ -z "$MYDNSJP_MasterID" ] || [ -z "$MYDNSJP_Password" ]; then + MYDNSJP_MasterID="" + MYDNSJP_Password="" + _err "You don't specify mydnsjp api MasterID and Password yet." + _err "Please export as MYDNSJP_MasterID / MYDNSJP_Password and try again." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _mydnsjp_api "DELETE" "$_domain" "$txtvalue"; then + if printf -- "%s" "$response" | grep "OK." >/dev/null; then + _info "Deleted, OK" + return 0 + else + _err "Delete txt record error." + return 1 + fi + fi + _err "Delete txt record error." + + return 1 +} + +#################### Private functions below ################################## +# _acme-challenge.www.domain.com +# returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + fulldomain=$1 + i=2 + p=1 + + # Get the root domain + _mydnsjp_retrieve_domain + if [ "$?" != "0" ]; then + # not valid + return 1 + fi + + while true; do + _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + + if [ -z "$_domain" ]; then + # not valid + return 1 + fi + + if [ "$_domain" = "$_root_domain" ]; then + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +# Retrieve the root domain +# returns 0 success +_mydnsjp_retrieve_domain() { + _debug "Login to MyDNS.JP" + + response="$(_post "masterid=$MYDNSJP_MasterID&masterpwd=$MYDNSJP_Password" "$MYDNSJP_API/?MENU=100")" + cookie="$(grep '^Set-Cookie:' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2)" + + # If cookies is not empty then logon successful + if [ -z "$cookie" ]; then + _err "Fail to get a cookie." + return 1 + fi + + _debug "Retrieve DOMAIN INFO page" + + export _H1="Cookie:${cookie}" + + response="$(_get "$MYDNSJP_API/?MENU=300")" + + if [ "$?" != "0" ]; then + _err "Fail to retrieve DOMAIN INFO." + return 1 + fi + + _root_domain=$(echo "$response" | grep "DNSINFO\[domainname\]" | sed 's/^.*value="\([^"]*\)".*/\1/') + + # Logout + response="$(_get "$MYDNSJP_API/?MENU=090")" + + _debug _root_domain "$_root_domain" + + if [ -z "$_root_domain" ]; then + _err "Fail to get the root domain." + return 1 + fi + + return 0 +} + +_mydnsjp_api() { + cmd=$1 + domain=$2 + txtvalue=$3 + + # Base64 encode the credentials + credentials=$(printf "%s:%s" "$MYDNSJP_MasterID" "$MYDNSJP_Password" | _base64) + + # Construct the HTTP Authorization header + export _H1="Content-Type: application/x-www-form-urlencoded" + export _H2="Authorization: Basic ${credentials}" + + response="$(_post "CERTBOT_DOMAIN=$domain&CERTBOT_VALIDATION=$txtvalue&EDIT_CMD=$cmd" "$MYDNSJP_API/directedit.html")" + + if [ "$?" != "0" ]; then + _err "error $domain" + return 1 + fi + + _debug2 response "$response" + + return 0 +} From d55c64c83891e06fef9301c3bbbad54b36de27b2 Mon Sep 17 00:00:00 2001 From: epgdatacapbon Date: Sat, 24 Nov 2018 14:07:50 +0900 Subject: [PATCH 178/280] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b9a5cc5..e0f601d 100644 --- a/README.md +++ b/README.md @@ -327,6 +327,7 @@ You don't have to do anything manually! 1. netcup DNS API (https://www.netcup.de) 1. GratisDNS.dk (https://gratisdns.dk) 1. Namecheap API (https://www.namecheap.com/) +1. MyDNS.JP API (https://www.mydns.jp/) And: From be5085f2052321f0fa1887bd7be7b3ca0de52aa2 Mon Sep 17 00:00:00 2001 From: epgdatacapbon Date: Sun, 25 Nov 2018 18:14:52 +0900 Subject: [PATCH 179/280] Increase security using https for MyDNS.JP API --- dnsapi/dns_mydnsjp.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 dnsapi/dns_mydnsjp.sh diff --git a/dnsapi/dns_mydnsjp.sh b/dnsapi/dns_mydnsjp.sh old mode 100644 new mode 100755 index d421329..aab2aab --- a/dnsapi/dns_mydnsjp.sh +++ b/dnsapi/dns_mydnsjp.sh @@ -15,7 +15,7 @@ # MYDNSJP_MasterID=MasterID # MYDNSJP_Password=Password -MYDNSJP_API="http://www.mydns.jp" +MYDNSJP_API="https://www.mydns.jp" #Usage: dns_mydnsjp_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_mydnsjp_add() { @@ -151,7 +151,7 @@ _mydnsjp_retrieve_domain() { _debug "Login to MyDNS.JP" response="$(_post "masterid=$MYDNSJP_MasterID&masterpwd=$MYDNSJP_Password" "$MYDNSJP_API/?MENU=100")" - cookie="$(grep '^Set-Cookie:' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2)" + cookie="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2)" # If cookies is not empty then logon successful if [ -z "$cookie" ]; then From 7917aa2a7c7012d2d0ee2e5d14924dbee801a3b5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Dec 2018 19:37:35 +0800 Subject: [PATCH 180/280] fix https://github.com/Neilpang/acme.sh/issues/1941 cache dns zones response --- dnsapi/dns_cf.sh | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 3595b9b..cbebb03 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -34,6 +34,9 @@ dns_cf_add() { _saveaccountconf_mutable CF_Key "$CF_Key" _saveaccountconf_mutable CF_Email "$CF_Email" + _DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '@.' '__')" + _cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" + _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" @@ -58,9 +61,12 @@ dns_cf_add() { # if [ "$count" = "0" ]; then _info "Adding record" if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then + if _contains "$response" "$fulldomain"; then _info "Added, OK" return 0 + elif _contains "$response" "The record already exists"; then + _info "Already exists, OK" + return 0 else _err "Add txt record error." return 1 @@ -99,11 +105,16 @@ dns_cf_rm() { return 1 fi + _DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '@.' '__')" + _debug "First detect the root zone" if ! _get_root "$fulldomain"; then + _cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" _err "invalid domain" return 1 fi + _cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" + _debug _domain_id "$_domain_id" _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" @@ -143,6 +154,21 @@ dns_cf_rm() { # _domain=domain.com # _domain_id=sdjkglgdfewsdfg _get_root() { + + _cf_zones="$(_readdomainconf $_DOMAIN_CF_ZONES_CACHE_NAME_)" + _debug2 "_cf_zones" "$_cf_zones" + if [ -z "$_cf_zones" ]; then + _debug "$_DOMAIN_CF_ZONES_CACHE_NAME_ is none, so get it." + if ! _cf_rest GET "zones"; then + return 1 + fi + _cf_zones="$response" + _savedomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" "$(echo "$_cf_zones" | _base64)" + else + _debug "$_DOMAIN_CF_ZONES_CACHE_NAME_ found" + _cf_zones="$(echo "$_cf_zones" | _dbase64)" + fi + domain=$1 i=2 p=1 @@ -154,12 +180,8 @@ _get_root() { return 1 fi - if ! _cf_rest GET "zones?name=$h"; then - return 1 - fi - - if _contains "$response" "\"name\":\"$h\"" >/dev/null; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") + if _contains "$_cf_zones" "\"name\":\"$h\"" >/dev/null; then + _domain_id=$(printf "%s\n" "$_cf_zones" | _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 From 9a27b389765ac6d7a256333e9e1f6fe3c4b92e08 Mon Sep 17 00:00:00 2001 From: "Aaron W. Swenson" Date: Sun, 2 Dec 2018 11:18:41 -0500 Subject: [PATCH 181/280] Update Linode API to v4 Linode API has made breaking changes that are resolved by this update. No user action is required. Additionally, related README.md entry updated to include new cloud manager interface. --- dnsapi/README.md | 13 +++++++++++-- dnsapi/dns_linode.sh | 39 ++++++++++++++++++++------------------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index bb0e89d..5642aa4 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -264,9 +264,18 @@ when needed. ## 14. Use Linode domain API First you need to login to your Linode account to get your API Key. -[https://manager.linode.com/profile/api](https://manager.linode.com/profile/api) -Then add an API key with label *ACME* and copy the new key. + * [Classic Manager](https://manager.linode.com/profile/api) + + Under "Add an API key", Give the new key a "Label" (we recommend *ACME*), + set the expiry to never, "Create API Key", and copy the new key into the `LINODE_API_KEY` command + below. + + * [Cloud Manager](https://cloud.linode.com/profile/tokens) + + Click on "Add a Personal Access Token". Give the new key a "Label" (we + recommend *ACME*), give it Read/Write access to "Domains". "Submit", and + copy the new key into the `LINODE_API_KEY` command below. ```sh export LINODE_API_KEY="..." diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index ead5b16..d03e6c4 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -2,7 +2,7 @@ #Author: Philipp Grosswiler -LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action=" +LINODE_API_URL="https://api.linode.com/v4/domains" ######## Public functions ##################### @@ -27,10 +27,14 @@ dns_linode_add() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue" + _payload="{ + \"type\": \"TXT\", + \"name\": \"$_sub_domain\", + \"target\": \"$txtvalue\" + }" - if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then - _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + if _rest POST "/$_domain_id/records" "$_payload" && [ -n "$response" ]; then + _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) _debug _resource_id "$_resource_id" if [ -z "$_resource_id" ]; then @@ -65,25 +69,21 @@ dns_linode_rm() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _parameters="&DomainID=$_domain_id" - - if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then + 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\":\s*\"$_sub_domain\".*}")" if [ "$resource" ]; then - _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) if [ "$_resource_id" ]; then _debug _resource_id "$_resource_id" - _parameters="&DomainID=$_domain_id&ResourceID=$_resource_id" - - if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then - _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) - _debug _resource_id "$_resource_id" + if _rest DELETE "/$_domain_id/records/$_resource_id" && [ -n "$response" ]; then + # On 200/OK, empty set is returned. Check for error, if any. + _error_response=$(printf "%s\n" "$response" | _egrep_o "\"errors\"" | cut -d : -f 2 | tr -d " " | _head_n 1) - if [ -z "$_resource_id" ]; then - _err "Error deleting the domain resource." + if [ -n "$_error_response" ]; then + _err "Error deleting the domain resource: $_error_response" return 1 fi @@ -127,7 +127,7 @@ _get_root() { i=2 p=1 - if _rest GET "domain.list"; then + if _rest GET; then response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) @@ -137,9 +137,9 @@ _get_root() { return 1 fi - hostedzone="$(echo "$response" | _egrep_o "{.*\"DOMAIN\":\s*\"$h\".*}")" + hostedzone="$(echo "$response" | _egrep_o "{.*\"domain\":\s*\"$h\".*}")" if [ "$hostedzone" ]; then - _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain=$h @@ -165,6 +165,7 @@ _rest() { export _H1="Accept: application/json" export _H2="Content-Type: application/json" + export _H3="Authorization: Bearer $LINODE_API_KEY" if [ "$mtd" != "GET" ]; then # both POST and DELETE. From 598becf6197d750615f9f62a881f4c383c2f35b2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 3 Dec 2018 20:31:20 +0800 Subject: [PATCH 182/280] minor, fix format --- dnsapi/dns_cf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index cbebb03..944956a 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -155,7 +155,7 @@ dns_cf_rm() { # _domain_id=sdjkglgdfewsdfg _get_root() { - _cf_zones="$(_readdomainconf $_DOMAIN_CF_ZONES_CACHE_NAME_)" + _cf_zones="$(_readdomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_")" _debug2 "_cf_zones" "$_cf_zones" if [ -z "$_cf_zones" ]; then _debug "$_DOMAIN_CF_ZONES_CACHE_NAME_ is none, so get it." From fb08b53f0b4c43db21bc33b804c031c9cc8ae975 Mon Sep 17 00:00:00 2001 From: Adrian Almenar Date: Mon, 3 Dec 2018 18:42:33 +0100 Subject: [PATCH 183/280] Add Neodigit.net DNS API --- README.md | 3 +- dnsapi/README.md | 13 +++ dnsapi/dns_neodigit.sh | 181 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 dnsapi/dns_neodigit.sh diff --git a/README.md b/README.md index c4ea5c6..6dcc8ea 100644 --- a/README.md +++ b/README.md @@ -329,8 +329,9 @@ You don't have to do anything manually! 1. Namecheap API (https://www.namecheap.com/) 1. MyDNS.JP API (https://www.mydns.jp/) 1. hosting.de (https://www.hosting.de) +1. Neodigit.net API (https://www.neodigit.net) -And: +And: **lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api (DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)** diff --git a/dnsapi/README.md b/dnsapi/README.md index bb0e89d..b5f4d2c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1054,6 +1054,19 @@ acme.sh --issue --dns dns_hostingde -d example.com -d *.example.com The hosting.de API key and endpoint will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 56. Use Neodigit.net API + +``` +export NEODIGIT_API_TOKEN="eXJxTkdUVUZmcHQ3QWJackQ4ZGlMejRDSklRYmo5VG5zcFFKK2thYnE0WnVnNnMy" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_neodigit -d example.com -d www.example.com +``` + +Neodigit API Token will be saved in `~/.acme.sh/account.conf` and will be used when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_neodigit.sh b/dnsapi/dns_neodigit.sh new file mode 100644 index 0000000..9835613 --- /dev/null +++ b/dnsapi/dns_neodigit.sh @@ -0,0 +1,181 @@ +#!/usr/bin/env sh + +# +# NEODIGIT_API_TOKEN="jasdfhklsjadhflnhsausdfas" + +# This is Neodigit.net api wrapper for acme.sh +# +# Author: Adrian Almenar +# Report Bugs here: https://github.com/tecnocratica/acme.sh +# +NEODIGIT_API_URL="https://api.neodigit.net/v1" +# +######## Public functions ##################### + +# Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_neodigit_add() { + fulldomain=$1 + txtvalue=$2 + + NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" + if [ -z "$NEODIGIT_API_TOKEN" ]; then + NEODIGIT_API_TOKEN="" + _err "You haven't specified a Token api key." + _err "Please create the key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable NEODIGIT_API_TOKEN "$NEODIGIT_API_TOKEN" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + + _debug "Getting txt records" + _neo_rest GET "dns/zones/${_domain_id}/records?type=TXT&name=$fulldomain" + + _debug _code "$_code" + + if [ "$_code" != "200" ]; then + _err "error retrieving data!" + return 1 + fi + + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + + _info "Adding record" + if _neo_rest POST "dns/zones/$_domain_id/records" "{\"record\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":60}}"; then + if printf -- "%s" "$response" | grep "$_sub_domain" >/dev/null; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + return 1 +} + +#fulldomain txtvalue +dns_neodigit_rm() { + fulldomain=$1 + txtvalue=$2 + + NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" + if [ -z "$NEODIGIT_API_TOKEN" ]; then + NEODIGIT_API_TOKEN="" + _err "You haven't specified a Token api key." + _err "Please create the key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable NEODIGIT_API_TOKEN "$NEODIGIT_API_TOKEN" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _neo_rest GET "dns/zones/${_domain_id}/records?type=TXT&name=$fulldomain&content=$txtvalue" + + if [ "$_code" != "200" ]; then + _err "error retrieving data!" + return 1 + fi + + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _neo_rest DELETE "dns/zones/$_domain_id/records/$record_id"; then + _err "Delete record error." + return 1 + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=dasfdsafsadg5ythd +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _neo_rest GET "dns/zones?name=$h"; then + return 1 + fi + + _debug p "$p" + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_neo_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="X-TCPanel-Token: $NEODIGIT_API_TOKEN" + export _H2="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$NEODIGIT_API_URL/$ep" "" "$m")" + else + response="$(_get "$NEODIGIT_API_URL/$ep")" + fi + + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From f4ad42bb842e410bd86500cf5bb936d8c3f1e989 Mon Sep 17 00:00:00 2001 From: Adrian Almenar Date: Tue, 4 Dec 2018 14:33:00 +0100 Subject: [PATCH 184/280] Changes requested on commit review --- dnsapi/dns_neodigit.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_neodigit.sh b/dnsapi/dns_neodigit.sh index 9835613..d87845a 100644 --- a/dnsapi/dns_neodigit.sh +++ b/dnsapi/dns_neodigit.sh @@ -17,7 +17,7 @@ dns_neodigit_add() { fulldomain=$1 txtvalue=$2 - NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" + NEODIGIT_API_TOKEN="$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" if [ -z "$NEODIGIT_API_TOKEN" ]; then NEODIGIT_API_TOKEN="" _err "You haven't specified a Token api key." @@ -73,7 +73,7 @@ dns_neodigit_rm() { fulldomain=$1 txtvalue=$2 - NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" + NEODIGIT_API_TOKEN="$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" if [ -z "$NEODIGIT_API_TOKEN" ]; then NEODIGIT_API_TOKEN="" _err "You haven't specified a Token api key." @@ -102,7 +102,7 @@ dns_neodigit_rm() { return 1 fi - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) + record_id=$(echo "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) _debug "record_id" "$record_id" if [ -z "$record_id" ]; then _err "Can not get record id to remove." @@ -140,7 +140,7 @@ _get_root() { _debug p "$p" if _contains "$response" "\"name\":\"$h\"" >/dev/null; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) + _domain_id=$(echo "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain=$h From 842f030355ee9013b6ba6861d347ef15a4e546e3 Mon Sep 17 00:00:00 2001 From: Adrian Almenar Date: Tue, 4 Dec 2018 14:36:28 +0100 Subject: [PATCH 185/280] Revert change --- dnsapi/dns_neodigit.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_neodigit.sh b/dnsapi/dns_neodigit.sh index d87845a..64ea878 100644 --- a/dnsapi/dns_neodigit.sh +++ b/dnsapi/dns_neodigit.sh @@ -17,7 +17,7 @@ dns_neodigit_add() { fulldomain=$1 txtvalue=$2 - NEODIGIT_API_TOKEN="$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" + NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" if [ -z "$NEODIGIT_API_TOKEN" ]; then NEODIGIT_API_TOKEN="" _err "You haven't specified a Token api key." @@ -73,7 +73,7 @@ dns_neodigit_rm() { fulldomain=$1 txtvalue=$2 - NEODIGIT_API_TOKEN="$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" + NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" if [ -z "$NEODIGIT_API_TOKEN" ]; then NEODIGIT_API_TOKEN="" _err "You haven't specified a Token api key." From 7ff525468f0fda2c29e3aea51e8cc425a1204acc Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Wed, 5 Dec 2018 03:01:50 +0800 Subject: [PATCH 186/280] Arch Linux package acme.sh is now in [community] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c4ea5c6..d806940 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709) - [Centminmod](https://centminmod.com/letsencrypt-acmetool-https.html) - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) -- [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) +- [archlinux](https://www.archlinux.org/packages/community/any/acme.sh) - [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient) - [CentOS Web Panel](http://centos-webpanel.com/) - [lnmp.org](https://lnmp.org/) From 9841063df9dd40120d32ed8185defaee9ef8a8e6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 6 Dec 2018 22:05:26 +0800 Subject: [PATCH 187/280] fix nginx mode --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 392079f..ff241e6 100755 --- a/acme.sh +++ b/acme.sh @@ -2839,7 +2839,7 @@ _isRealNginxConf() { _skip_ssl=1 for _listen_i in $(echo "$_seg_n" | tr "\t" ' ' | grep "^ *listen" | tr -d " "); do if [ "$_listen_i" ]; then - if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl[ |;]")" ]; then + if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl")" ]; then _debug2 "$_listen_i is ssl" else _debug2 "$_listen_i is plain text" From c84466b1319f5648b420b5670cf15d686df4646a Mon Sep 17 00:00:00 2001 From: Sergey Pashinin Date: Mon, 10 Dec 2018 16:55:21 +0300 Subject: [PATCH 188/280] Write certs in Vault for Fabio load balancer --- deploy/vault_cli.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/deploy/vault_cli.sh b/deploy/vault_cli.sh index 79c25aa..b93fdd5 100644 --- a/deploy/vault_cli.sh +++ b/deploy/vault_cli.sh @@ -49,9 +49,13 @@ vault_cli_deploy() { return 1 fi - $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1 - $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1 - $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1 - $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1 + if [ -n "$FABIO" ]; then + $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1 + else + $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1 + $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1 + $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1 + $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1 + fi } From 9f067d7f56eba9c1b301686d2a89419d9e993ea1 Mon Sep 17 00:00:00 2001 From: Sergey Pashinin Date: Mon, 10 Dec 2018 18:17:18 +0300 Subject: [PATCH 189/280] Deploy to Hashicorp Vault docs --- deploy/README.md | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index 5c03ce6..cec7d77 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -295,4 +295,40 @@ You can then deploy the certificate as follows ```sh acme.sh --deploy -d www.mydomain.com --deploy-hook gitlab -``` \ No newline at end of file +``` + +## 12. Deploy your cert to Hashicorp Vault + +```sh +export VAULT_PREFIX="acme" +``` + +You can then deploy the certificate as follows + +```sh +acme.sh --deploy -d www.mydomain.com --deploy-hook vault_cli +``` + +Your certs will be saved in Vault using this structure: + +```sh +vault write "${VAULT_PREFIX}/${domain}/cert.pem" value=@"..." +vault write "${VAULT_PREFIX}/${domain}/cert.key" value=@"..." +vault write "${VAULT_PREFIX}/${domain}/chain.pem" value=@"..." +vault write "${VAULT_PREFIX}/${domain}/fullchain.pem" value=@"..." +``` + +You might be using Fabio load balancer (which can get certs from +Vault). It needs a bit different structure of your certs in Vault. It +gets certs only from keys that were saved in `prefix/domain`, like this: + +```bash +vault write /www.domain.com cert=@cert.pem key=@key.pem +``` + +If you want to save certs in Vault this way just set "FABIO" env +variable to anything (ex: "1") before running `acme.sh`: + +```sh +export FABIO="1" +``` From a43545c6ea9f79df2acfa1bc10db8f44e803b197 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 11 Dec 2018 19:11:56 +0800 Subject: [PATCH 190/280] fix https://github.com/Neilpang/acme.sh/issues/1959 --- dnsapi/dns_cf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 944956a..f50ab49 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -181,7 +181,7 @@ _get_root() { fi if _contains "$_cf_zones" "\"name\":\"$h\"" >/dev/null; then - _domain_id=$(printf "%s\n" "$_cf_zones" | _egrep_o "\[.\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") + _domain_id=$(echo "$_cf_zones" | tr '{' "\n" | grep "\"name\":\"$h\"" | _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 From 5431d051685bc6c0d7cd1341dc5111892715ee19 Mon Sep 17 00:00:00 2001 From: "Daniel F. Dickinson" Date: Thu, 13 Dec 2018 01:22:44 -0500 Subject: [PATCH 191/280] dnsapi nsupdate: Add nsupdate debug option When debug is enabled, also use nsupdate's debug logging so that the user can see potential issues with the nsupdate transaction. Signed-off-by: Daniel F. Dickinson --- dnsapi/dns_nsupdate.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 555f4d2..609785e 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -14,7 +14,9 @@ dns_nsupdate_add() { _saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}" _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" - nsupdate -k "${NSUPDATE_KEY}" < Date: Thu, 13 Dec 2018 01:23:53 -0500 Subject: [PATCH 192/280] dnsapi: Add option to set zone for nsupdate Some DNS servers for which dns_nsupdate.sh is applicable (such as dyn.com's 'Standard DNS' TSIG update mechanism), require that the zone be set during the nsupdate transaction. Therefore we add a new environment variable NSUPDATE_ZONE which is used to set the zone for the DNS TSIG transaction. Signed-off-by: Daniel F. Dickinson --- dnsapi/README.md | 6 +++++- dnsapi/dns_nsupdate.sh | 23 +++++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index afe1f7f..30c1be5 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -146,13 +146,17 @@ Finally, make the DNS server and update Key available to `acme.sh` export NSUPDATE_SERVER="dns.example.com" export NSUPDATE_KEY="/path/to/your/nsupdate.key" ``` +and optionally (depending on DNS server) +``` +export NSUPDATE_ZONE="example.com" +``` Ok, let's issue a cert now: ``` acme.sh --issue --dns dns_nsupdate -d example.com -d www.example.com ``` -The `NSUPDATE_SERVER` and `NSUPDATE_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +The `NSUPDATE_SERVER`, `NSUPDATE_KEY`, and `NSUPDATE_ZONE` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. ## 8. Use LuaDNS domain API diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 609785e..8b479f9 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -13,14 +13,24 @@ dns_nsupdate_add() { _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}" _saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}" _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" + _saveaccountconf NSUPDATE_ZONE "${NSUPDATE_ZONE}" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d" [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D" - nsupdate -k "${NSUPDATE_KEY}" $nsdebug < Date: Sun, 16 Dec 2018 21:10:22 +0800 Subject: [PATCH 193/280] add more debug info https://github.com/Neilpang/acme.sh/issues/1932 --- acme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index ff241e6..5cfcb38 100755 --- a/acme.sh +++ b/acme.sh @@ -1516,7 +1516,8 @@ _calcjwk() { JWK_HEADERPLACE_PART1='{"nonce": "' JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"' else - _err "Only RSA or EC key is supported." + _err "Only RSA or EC key is supported. keyfile=$keyfile" + _debug2 "$(cat "$keyfile")" return 1 fi From 2b9ebd666280cc7832bce31d0b282df7f4d276d7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 17 Dec 2018 23:02:02 +0800 Subject: [PATCH 194/280] fix showcsr https://github.com/Neilpang/acme.sh/issues/1968 --- acme.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 5cfcb38..6264da0 100755 --- a/acme.sh +++ b/acme.sh @@ -1134,12 +1134,17 @@ _readSubjectAltNamesFromCSR() { if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then _debug "AltNames contains subject" - _dnsAltnames="$(printf "%s" "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")" + _excapedAlgnames="$(echo "$_dnsAltnames" | tr '*' '#')" + _debug _excapedAlgnames "$_excapedAlgnames" + _escapedSubject="$(echo "$_csrsubj" | tr '*' '#')" + _debug _escapedSubject "$_escapedSubject" + _dnsAltnames="$(echo "$_excapedAlgnames," | sed "s/DNS:$_escapedSubject,//g" | tr '#' '*' | sed "s/,\$//g")" + _debug _dnsAltnames "$_dnsAltnames" else _debug "AltNames doesn't contain subject" fi - printf "%s" "$_dnsAltnames" | sed "s/DNS://g" + echo "$_dnsAltnames" | sed "s/DNS://g" } #_csrfile From 08681f4a8b9ea066b00e5f890b47bfbfe3fb5b3e Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 18 Dec 2018 19:28:38 +0800 Subject: [PATCH 195/280] support tls-alpn-01 https://github.com/Neilpang/acme.sh/issues/1675#issuecomment-447857756 --- acme.sh | 50 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 6264da0..efd6446 100755 --- a/acme.sh +++ b/acme.sh @@ -37,6 +37,7 @@ VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" VTYPE_TLS="tls-sni-01" VTYPE_TLS2="tls-sni-02" +VTYPE_ALPN="tls-alpn-01" LOCAL_ANY_ADDRESS="0.0.0.0" @@ -48,6 +49,7 @@ NO_VALUE="no" W_TLS="tls" W_DNS="dns" +W_ALPN="alpn" DNS_ALIAS_PREFIX="=" MODE_STATELESS="stateless" @@ -1046,7 +1048,7 @@ _idn() { fi } -#_createcsr cn san_list keyfile csrfile conf +#_createcsr cn san_list keyfile csrfile conf acmeValidationv1 _createcsr() { _debug _createcsr domain="$1" @@ -1054,6 +1056,7 @@ _createcsr() { csrkey="$3" csr="$4" csrconf="$5" + acmeValidationv1="$6" _debug2 domain "$domain" _debug2 domainlist "$domainlist" _debug2 csrkey "$csrkey" @@ -1062,7 +1065,9 @@ _createcsr() { printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf" - if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then + if [ "$acmeValidationv1" ]; then + printf -- "\nsubjectAltName=DNS:$domainlist" >>"$csrconf" + elif [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then #single domain _info "Single domain" "$domain" printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf" @@ -1084,6 +1089,10 @@ _createcsr() { printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf" fi + if [ "$acmeValidationv1" ]; then + printf "\n1.3.6.1.5.5.7.1.30.1=critical,DER:04:20:${acmeValidationv1}" >> "${csrconf}" + fi + _csr_cn="$(_idn "$domain")" _debug2 _csr_cn "$_csr_cn" if _contains "$(uname -a)" "MINGW"; then @@ -2107,7 +2116,7 @@ _sleep() { fi } -# _starttlsserver san_a san_b port content _ncaddr +# _starttlsserver san_a san_b port content _ncaddr acmeValidationv1 _starttlsserver() { _info "Starting tls server." san_a="$1" @@ -2115,10 +2124,12 @@ _starttlsserver() { port="$3" content="$4" opaddr="$5" + acmeValidationv1="$6" _debug san_a "$san_a" _debug san_b "$san_b" _debug port "$port" + _debug acmeValidationv1 "$acmeValidationv1" #create key TLS_KEY if ! _createkey "2048" "$TLS_KEY"; then @@ -2131,7 +2142,7 @@ _starttlsserver() { if [ "$san_b" ]; then alt="$alt,$san_b" fi - if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF"; then + if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$acmeValidationv1"; then _err "Create tls validation csr error." return 1 fi @@ -2157,6 +2168,10 @@ _starttlsserver() { __S_OPENSSL="$__S_OPENSSL -6" fi + if [ "$acmeValidationv1" ]; then + __S_OPENSSL="$__S_OPENSSL -alpn acme-tls/1" + fi + _debug "$__S_OPENSSL" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then $__S_OPENSSL -tlsextdebug & @@ -3067,8 +3082,8 @@ _on_before_issue() { _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" fi _checkport="$Le_HTTPPort" - elif [ "$_currentRoot" = "$W_TLS" ]; then - _info "Standalone tls mode." + elif [ "$_currentRoot" = "$W_TLS" ] || [ "$_currentRoot" = "$W_ALPN" ]; then + _info "Standalone tls/alpn mode." if [ -z "$Le_TLSPort" ]; then Le_TLSPort=443 else @@ -3694,6 +3709,10 @@ $_authorizations_map" fi fi + if [ "$_currentRoot" = "$W_ALPN" ]; then + vtype="$VTYPE_ALPN" + fi + if [ "$ACME_VERSION" = "2" ]; then response="$(echo "$_authorizations_map" | grep "^$d," | sed "s/$d,//")" _debug2 "response" "$response" @@ -4007,6 +4026,16 @@ $_authorizations_map" _on_issue_err "$_post_hook" "$vlist" return 1 fi + elif [ "$vtype" = "$VTYPE_ALPN" ]; then + acmevalidationv1="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")" + _debug acmevalidationv1 "$acmevalidationv1" + if ! _starttlsserver "$d" "" "$Le_TLSPort" "$keyauthorization" "$_ncaddr" "$acmevalidationv1"; then + _err "Start tls server error." + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi fi if ! __trigger_validation "$uri" "$keyauthorization"; then @@ -5469,6 +5498,7 @@ Parameters: --output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure. --webroot, -w /path/to/webroot Specifies the web root folder for web root mode. --standalone Use standalone mode. + --alpn Use standalone alpn mode. --stateless Use stateless mode, see: $_STATELESS_WIKI --apache Use apache mode. --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. @@ -5823,6 +5853,14 @@ _process() { _webroot="$_webroot,$wvalue" fi ;; + --alpn) + wvalue="$W_ALPN" + if [ -z "$_webroot" ]; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; --stateless) wvalue="$MODE_STATELESS" if [ -z "$_webroot" ]; then From 79a0a66f1f2f547464bec4ee7ab876a664a2ed78 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 18 Dec 2018 20:18:18 +0800 Subject: [PATCH 196/280] support --tlsport --- acme.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/acme.sh b/acme.sh index efd6446..5ce97f8 100755 --- a/acme.sh +++ b/acme.sh @@ -5529,6 +5529,7 @@ Parameters: --accountkey Specifies the account key path, only valid for the '--install' command. --days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days. --httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer. + --tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer. --local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses. --listraw Only used for '--list' command, list the certs in raw format. --stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal. @@ -5985,6 +5986,11 @@ _process() { Le_HTTPPort="$_httpport" shift ;; + --tlsport) + _tlsport="$2" + Le_TLSPort="$_tlsport" + shift + ;; --listraw) _listraw="raw" ;; From f99ca918db8e4587ec1437c6815a32a8de49c42f Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 18 Dec 2018 20:33:33 +0800 Subject: [PATCH 197/280] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5ce97f8..acda4be 100755 --- a/acme.sh +++ b/acme.sh @@ -1090,7 +1090,7 @@ _createcsr() { fi if [ "$acmeValidationv1" ]; then - printf "\n1.3.6.1.5.5.7.1.30.1=critical,DER:04:20:${acmeValidationv1}" >> "${csrconf}" + printf "\n1.3.6.1.5.5.7.1.30.1=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}" fi _csr_cn="$(_idn "$domain")" From 67d3e8d04968e8beaaa463639cd5989edf5fd9b7 Mon Sep 17 00:00:00 2001 From: Ivru Date: Thu, 20 Dec 2018 16:07:05 +0100 Subject: [PATCH 198/280] Add Exoscape API support for DNSAPI --- README.md | 1 + dnsapi/README.md | 18 +++++ dnsapi/dns_exoscale.sh | 170 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100755 dnsapi/dns_exoscale.sh diff --git a/README.md b/README.md index 033711f..6a1cf3a 100644 --- a/README.md +++ b/README.md @@ -330,6 +330,7 @@ You don't have to do anything manually! 1. MyDNS.JP API (https://www.mydns.jp/) 1. hosting.de (https://www.hosting.de) 1. Neodigit.net API (https://www.neodigit.net) +1. Exoscale.com API (https://www.exoscale.com/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index afe1f7f..89cf397 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1076,6 +1076,24 @@ acme.sh --issue --dns dns_neodigit -d example.com -d www.example.com Neodigit API Token will be saved in `~/.acme.sh/account.conf` and will be used when needed. +## 57. Use Exoscale API + +Create an API key and secret key in the Exoscale account section + +Set your API and secret key: + +``` +export EXOSCALE_API_KEY='xxx' +export EXOSCALE_SECRET_KEY='xxx' +``` + +Now, let's issue a cert: +``` +acme.sh --issue --dns dns_netcup -d example.com -d www.example.com +``` + +The `EXOSCALE_API_KEY` and `EXOSCALE_SECRET_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_exoscale.sh b/dnsapi/dns_exoscale.sh new file mode 100755 index 0000000..f9ffff2 --- /dev/null +++ b/dnsapi/dns_exoscale.sh @@ -0,0 +1,170 @@ +#!/usr/bin/env sh + +EXOSCALE_API=https://api.exoscale.com/dns/v1 + + +######## Public functions ##################### + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_exoscale_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _checkAuth; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + if _exoscale_rest POST "domains/$_domain_id/records" "{\"record\":{\"name\":\"$_sub_domain\",\"record_type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":120}}" "$_domain_token"; then + if _contains "$response" "$txtvalue"; then + _info "Added, OK" + return 0 + fi + fi + _err "Add txt record error." + return 1 + +} + +# Usage: fulldomain txtvalue +# Used to remove the txt record after validation +dns_exoscale_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! _checkAuth; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _exoscale_rest GET "domains/${_domain_id}/records?type=TXT&name=$_sub_domain" "" "$_domain_token" + if _contains "$response" "\"name\":\"$_sub_domain\"" >/dev/null; then + _record_id=$(echo "$response" | tr '{' "\n" | grep "\"content\":\"$txtvalue\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \") + fi + + if [ -z "$_record_id" ] ; then + _err "Can not get record id to remove." + return 1 + fi + + _debug "Deleting record $_record_id" + + if ! _exoscale_rest DELETE "domains/$_domain_id/records/$_record_id" "" "$_domain_token"; then + _err "Delete record error." + return 1 + fi + + return 0 +} + + +#################### Private functions below ################################## + +_checkAuth() { + EXOSCALE_API_KEY="${EXOSCALE_API_KEY:-$(_readaccountconf_mutable EXOSCALE_API_KEY)}" + EXOSCALE_SECRET_KEY="${EXOSCALE_SECRET_KEY:-$(_readaccountconf_mutable EXOSCALE_SECRET_KEY)}" + + if [ -z "$EXOSCALE_API_KEY" ] || [ -z "$EXOSCALE_SECRET_KEY" ]; then + EXOSCALE_API_KEY="" + EXOSCALE_SECRET_KEY="" + _err "You don't specify Exoscale application key and application secret yet." + _err "Please create you key and try again." + return 1 + fi + + _saveaccountconf_mutable EXOSCALE_API_KEY "$EXOSCALE_API_KEY" + _saveaccountconf_mutable EXOSCALE_SECRET_KEY "$EXOSCALE_SECRET_KEY" + + return 0 +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +# _domain_token=sdjkglgdfewsdfg +_get_root() { + + if ! _exoscale_rest GET "domains"; then + return 1 + fi + + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _domain_id=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \") + _domain_token=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") + if [ "$_domain_token" ] && [ "$_domain_id" ] ; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +# returns response +_exoscale_rest() { + method=$1 + path="$2" + data="$3" + token="$4" + request_url="$EXOSCALE_API/$path" + _debug "$path" + + export _H1="Accept: application/json" + + if [ "$token" ]; then + export _H2="X-DNS-Domain-Token: $token" + else + export _H2="X-DNS-Token: $EXOSCALE_API_KEY:$EXOSCALE_SECRET_KEY" + fi + + if [ "$data" ] || [ "$method" = "DELETE" ]; then + _H3="Content-Type: application/json" + _debug data "$data" + response="$(_post "$data" "$request_url" "" "$method")" + else + response="$(_get "$request_url" "" "" "$method")" + fi + + if [ "$?" != "0" ]; then + _err "error $request_url" + return 1 + fi + _debug2 response "$response" + return 0 +} From eea9aaf9404d6f62c722e96c2d064bcab21347b4 Mon Sep 17 00:00:00 2001 From: Ivru Date: Thu, 20 Dec 2018 16:24:08 +0100 Subject: [PATCH 199/280] Fix typos --- dnsapi/dns_exoscale.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_exoscale.sh b/dnsapi/dns_exoscale.sh index f9ffff2..a837b79 100755 --- a/dnsapi/dns_exoscale.sh +++ b/dnsapi/dns_exoscale.sh @@ -61,7 +61,7 @@ dns_exoscale_rm() { _record_id=$(echo "$response" | tr '{' "\n" | grep "\"content\":\"$txtvalue\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \") fi - if [ -z "$_record_id" ] ; then + if [ -z "$_record_id" ]; then _err "Can not get record id to remove." return 1 fi @@ -123,7 +123,7 @@ _get_root() { if _contains "$response" "\"name\":\"$h\"" >/dev/null; then _domain_id=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \") _domain_token=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") - if [ "$_domain_token" ] && [ "$_domain_id" ] ; then + if [ "$_domain_token" ] && [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain=$h return 0 From 8e43b86f06d244ed6635054cb768c45e86f16bdd Mon Sep 17 00:00:00 2001 From: Ivru Date: Thu, 20 Dec 2018 16:30:02 +0100 Subject: [PATCH 200/280] Export header _H3 --- dnsapi/dns_exoscale.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_exoscale.sh b/dnsapi/dns_exoscale.sh index a837b79..bb433ec 100755 --- a/dnsapi/dns_exoscale.sh +++ b/dnsapi/dns_exoscale.sh @@ -154,7 +154,7 @@ _exoscale_rest() { fi if [ "$data" ] || [ "$method" = "DELETE" ]; then - _H3="Content-Type: application/json" + export _H3="Content-Type: application/json" _debug data "$data" response="$(_post "$data" "$request_url" "" "$method")" else From 405173a0b4176d8858f7d31aaf570a27cafb1a90 Mon Sep 17 00:00:00 2001 From: Ivru Date: Thu, 20 Dec 2018 16:37:11 +0100 Subject: [PATCH 201/280] Remove extraneous blank lines --- dnsapi/dns_exoscale.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/dnsapi/dns_exoscale.sh b/dnsapi/dns_exoscale.sh index bb433ec..ccf05fc 100755 --- a/dnsapi/dns_exoscale.sh +++ b/dnsapi/dns_exoscale.sh @@ -2,7 +2,6 @@ EXOSCALE_API=https://api.exoscale.com/dns/v1 - ######## Public functions ##################### # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" @@ -76,7 +75,6 @@ dns_exoscale_rm() { return 0 } - #################### Private functions below ################################## _checkAuth() { From 9a473640fb2341a5c9e56ffcb645200c1725392c Mon Sep 17 00:00:00 2001 From: "Aaron W. Swenson" Date: Thu, 20 Dec 2018 11:00:10 -0500 Subject: [PATCH 202/280] Revert "Update Linode API to v4" This reverts commit 9a27b389765ac6d7a256333e9e1f6fe3c4b92e08. Turns out, the Cloud Manager is not backward compatible, nor is the Classic Manager forward compatible. --- dnsapi/README.md | 13 ++----------- dnsapi/dns_linode.sh | 39 +++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 30c1be5..603bd72 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -268,18 +268,9 @@ when needed. ## 14. Use Linode domain API First you need to login to your Linode account to get your API Key. +[https://manager.linode.com/profile/api](https://manager.linode.com/profile/api) - * [Classic Manager](https://manager.linode.com/profile/api) - - Under "Add an API key", Give the new key a "Label" (we recommend *ACME*), - set the expiry to never, "Create API Key", and copy the new key into the `LINODE_API_KEY` command - below. - - * [Cloud Manager](https://cloud.linode.com/profile/tokens) - - Click on "Add a Personal Access Token". Give the new key a "Label" (we - recommend *ACME*), give it Read/Write access to "Domains". "Submit", and - copy the new key into the `LINODE_API_KEY` command below. +Then add an API key with label *ACME* and copy the new key. ```sh export LINODE_API_KEY="..." diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index d03e6c4..ead5b16 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -2,7 +2,7 @@ #Author: Philipp Grosswiler -LINODE_API_URL="https://api.linode.com/v4/domains" +LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action=" ######## Public functions ##################### @@ -27,14 +27,10 @@ dns_linode_add() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _payload="{ - \"type\": \"TXT\", - \"name\": \"$_sub_domain\", - \"target\": \"$txtvalue\" - }" + _parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue" - if _rest POST "/$_domain_id/records" "$_payload" && [ -n "$response" ]; then - _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then + _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) _debug _resource_id "$_resource_id" if [ -z "$_resource_id" ]; then @@ -69,21 +65,25 @@ dns_linode_rm() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - if _rest GET "/$_domain_id/records" && [ -n "$response" ]; then + _parameters="&DomainID=$_domain_id" + + if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" - resource="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$_sub_domain\".*}")" + resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" if [ "$resource" ]; then - _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) if [ "$_resource_id" ]; then _debug _resource_id "$_resource_id" - if _rest DELETE "/$_domain_id/records/$_resource_id" && [ -n "$response" ]; then - # On 200/OK, empty set is returned. Check for error, if any. - _error_response=$(printf "%s\n" "$response" | _egrep_o "\"errors\"" | cut -d : -f 2 | tr -d " " | _head_n 1) + _parameters="&DomainID=$_domain_id&ResourceID=$_resource_id" + + if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then + _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + _debug _resource_id "$_resource_id" - if [ -n "$_error_response" ]; then - _err "Error deleting the domain resource: $_error_response" + if [ -z "$_resource_id" ]; then + _err "Error deleting the domain resource." return 1 fi @@ -127,7 +127,7 @@ _get_root() { i=2 p=1 - if _rest GET; then + if _rest GET "domain.list"; then response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) @@ -137,9 +137,9 @@ _get_root() { return 1 fi - hostedzone="$(echo "$response" | _egrep_o "{.*\"domain\":\s*\"$h\".*}")" + hostedzone="$(echo "$response" | _egrep_o "{.*\"DOMAIN\":\s*\"$h\".*}")" if [ "$hostedzone" ]; then - _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain=$h @@ -165,7 +165,6 @@ _rest() { export _H1="Accept: application/json" export _H2="Content-Type: application/json" - export _H3="Authorization: Bearer $LINODE_API_KEY" if [ "$mtd" != "GET" ]; then # both POST and DELETE. From c8c1140f15d6c96d83bd3734fcc1604e0caa408e Mon Sep 17 00:00:00 2001 From: "Aaron W. Swenson" Date: Thu, 20 Dec 2018 11:01:34 -0500 Subject: [PATCH 203/280] Linode API v4 Redo The Cloud and Classic Manager work with different APIs, and so require a separate module, which we introduce here. The README has also been modified to state that the two are separate and incompatible, and provides instructions on using either. --- dnsapi/README.md | 46 +++++++++- dnsapi/dns_linode_v4.sh | 185 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+), 4 deletions(-) create mode 100755 dnsapi/dns_linode_v4.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index 603bd72..df6db11 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -267,16 +267,26 @@ when needed. ## 14. Use Linode domain API +The tokens created in the classic manager and cloud manager are incompatible +with one another. While the classic manager makes an all or nothing API, the +newer cloud manager interface promises to produce API keys with a finer +permission system. However, either way works just fine. + +### Classic Manager ### + +Classic Manager: https://manager.linode.com/profile/api + First you need to login to your Linode account to get your API Key. -[https://manager.linode.com/profile/api](https://manager.linode.com/profile/api) -Then add an API key with label *ACME* and copy the new key. +Then add an API key with label *ACME* and copy the new key into the following +command. ```sh export LINODE_API_KEY="..." ``` -Due to the reload time of any changes in the DNS records, we have to use the `dnssleep` option to wait at least 15 minutes for the changes to take effect. +Due to the reload time of any changes in the DNS records, we have to use the +`dnssleep` option to wait at least 15 minutes for the changes to take effect. Ok, let's issue a cert now: @@ -284,7 +294,35 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.com ``` -The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be +reused when needed. + +### Cloud Manager ### + +Cloud Manager: https://cloud.linode.com/profile/tokens + +First you need to login to your Linode account to get your API Key. + + 1. Click on "Add a Personal Access Token". + 2. Give the new key a "Label" (we recommend *ACME*) + 3. Give it Read/Write access to "Domains" + 4. "Submit" and copy the new key into the `LINODE_V4_API_KEY` command below. + +```sh +export LINODE_V4_API_KEY="..." +``` + +Due to the reload time of any changes in the DNS records, we have to use the +`dnssleep` option to wait at least 15 minutes for the changes to take effect. + +Ok, let's issue a cert now: + +```sh +acme.sh --issue --dns dns_linode_v4 --dnssleep 900 -d example.com -d www.example.com +``` + +The `LINODE_V4_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be +reused when needed. ## 15. Use FreeDNS diff --git a/dnsapi/dns_linode_v4.sh b/dnsapi/dns_linode_v4.sh new file mode 100755 index 0000000..dfa1a65 --- /dev/null +++ b/dnsapi/dns_linode_v4.sh @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +#Original Author: Philipp Grosswiler +#v4 Update Author: Aaron W. Swenson + +LINODE_V4_API_URL="https://api.linode.com/v4/domains" + +######## Public functions ##################### + +#Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_linode_add() { + fulldomain="${1}" + txtvalue="${2}" + + if ! _Linode_API; then + return 1 + fi + + _info "Using Linode" + _debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Domain does not exist." + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _payload="{ + \"type\": \"TXT\", + \"name\": \"$_sub_domain\", + \"target\": \"$txtvalue\" + }" + + if _rest POST "/$_domain_id/records" "$_payload" && [ -n "$response" ]; then + _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + _debug _resource_id "$_resource_id" + + if [ -z "$_resource_id" ]; then + _err "Error adding the domain resource." + return 1 + fi + + _info "Domain resource successfully added." + return 0 + fi + + return 1 +} + +#Usage: dns_linode_rm _acme-challenge.www.domain.com +dns_linode_rm() { + fulldomain="${1}" + + if ! _Linode_API; then + return 1 + fi + + _info "Using Linode" + _debug "Calling: dns_linode_rm() '${fulldomain}'" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Domain does not exist." + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _rest GET "/$_domain_id/records" && [ -n "$response" ]; then + response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" + + resource="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$_sub_domain\".*}")" + if [ "$resource" ]; then + _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "$_resource_id" ]; then + _debug _resource_id "$_resource_id" + + if _rest DELETE "/$_domain_id/records/$_resource_id" && [ -n "$response" ]; then + # On 200/OK, empty set is returned. Check for error, if any. + _error_response=$(printf "%s\n" "$response" | _egrep_o "\"errors\"" | cut -d : -f 2 | tr -d " " | _head_n 1) + + if [ -n "$_error_response" ]; then + _err "Error deleting the domain resource: $_error_response" + return 1 + fi + + _info "Domain resource successfully deleted." + return 0 + fi + fi + + return 1 + fi + + return 0 + fi + + return 1 +} + +#################### Private functions below ################################## + +_Linode_API() { + if [ -z "$LINODE_V4_API_KEY" ]; then + LINODE_V4_API_KEY="" + + _err "You didn't specify the Linode v4 API key yet." + _err "Please create your key and try again." + + return 1 + fi + + _saveaccountconf LINODE_V4_API_KEY "$LINODE_V4_API_KEY" +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=12345 +_get_root() { + domain=$1 + i=2 + p=1 + + if _rest GET; then + response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + hostedzone="$(echo "$response" | _egrep_o "{.*\"domain\":\s*\"$h\".*}")" + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + fi + return 1 +} + +#method method action data +_rest() { + mtd="$1" + ep="$2" + data="$3" + + _debug mtd "$mtd" + _debug ep "$ep" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + export _H3="Authorization: Bearer $LINODE_V4_API_KEY" + + if [ "$mtd" != "GET" ]; then + # both POST and DELETE. + _debug data "$data" + response="$(_post "$data" "$LINODE_V4_API_URL$ep" "" "$mtd")" + else + response="$(_get "$LINODE_V4_API_URL$ep$data")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From 2671af13cdfb592f56c5de1ffdbe438f79db72d8 Mon Sep 17 00:00:00 2001 From: Ketil Date: Thu, 27 Dec 2018 15:17:19 +0100 Subject: [PATCH 204/280] Bugfix for allowing '+' character in CloudFlare email --- dnsapi/dns_cf.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index f50ab49..021094d 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -34,7 +34,7 @@ dns_cf_add() { _saveaccountconf_mutable CF_Key "$CF_Key" _saveaccountconf_mutable CF_Email "$CF_Email" - _DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '@.' '__')" + _DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '+@.' '___')" _cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" _debug "First detect the root zone" @@ -105,7 +105,7 @@ dns_cf_rm() { return 1 fi - _DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '@.' '__')" + _DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '+@.' '___')" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then From 9756adb9336daf7fdfd63ce83dde75aa269708d8 Mon Sep 17 00:00:00 2001 From: Ketil Date: Thu, 27 Dec 2018 15:45:19 +0100 Subject: [PATCH 205/280] Fixed spelling of 'tigger' to 'Trigger'. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index acda4be..c80d8aa 100755 --- a/acme.sh +++ b/acme.sh @@ -3443,7 +3443,7 @@ __get_domain_new_authz() { #uri keyAuthorization __trigger_validation() { - _debug2 "tigger domain validation." + _debug2 "Trigger domain validation." _t_url="$1" _debug2 _t_url "$_t_url" _t_key_authz="$2" From 920cab6f1206abde5e8ced352bdd3908a2950534 Mon Sep 17 00:00:00 2001 From: Ketil Date: Thu, 27 Dec 2018 16:06:41 +0100 Subject: [PATCH 206/280] Added fixes to also use BuyPass Go ACME server --- acme.sh | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/acme.sh b/acme.sh index acda4be..aa2adc6 100755 --- a/acme.sh +++ b/acme.sh @@ -13,6 +13,8 @@ _SCRIPT_="$0" _SUB_FOLDERS="dnsapi deploy" +BUYPASS_CA="https://api.buypass.no/acme/directory" + LETSENCRYPT_CA_V1="https://acme-v01.api.letsencrypt.org/directory" LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory" @@ -1820,9 +1822,12 @@ _send_signed_request() { _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then _headers="" - if [ "$ACME_NEW_NONCE" ]; then - _debug2 "Get nonce with HEAD. ACME_NEW_NONCE" "$ACME_NEW_NONCE" + if [ "$ACME_NEW_NONCE" ] || [ "$BUYPASS" ]; then nonceurl="$ACME_NEW_NONCE" + if [ "$BUYPASS" ]; then + nonceurl=$url + fi + _debug2 "Get nonce with HEAD. ACME_NEW_NONCE" "$nonceurl" if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then _headers="$(cat "$HTTP_HEADER")" fi @@ -1875,7 +1880,7 @@ _send_signed_request() { sig="$(printf "%s" "$_sig_t" | _url_replace)" _debug3 sig "$sig" - if [ "$ACME_VERSION" = "2" ]; then + if [ "$ACME_VERSION" = "2" ] || [ "$BUYPASS" ]; then body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" else body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" @@ -2330,6 +2335,13 @@ _initAPI() { fi export ACME_AGREEMENT + BUYPASS=$(echo "$_api_server" | _egrep_o 'buypass') + if [ "$BUYPASS" ]; then + BUYPASS=1 + fi + export BUYPASS + _debug "BUYPASS" "$BUYPASS" + _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" @@ -3448,10 +3460,16 @@ __trigger_validation() { _debug2 _t_url "$_t_url" _t_key_authz="$2" _debug2 _t_key_authz "$_t_key_authz" + _t_vtype="$3" + _debug2 _t_vtype "$_t_vtype" if [ "$ACME_VERSION" = "2" ]; then _send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}" else - _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" + if [ "$BUYPASS" ]; then + _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"type\": \"$_t_vtype\", \"keyAuthorization\": \"$_t_key_authz\"}" + else + _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" + fi fi } @@ -4038,7 +4056,7 @@ $_authorizations_map" fi fi - if ! __trigger_validation "$uri" "$keyauthorization"; then + if ! __trigger_validation "$uri" "$keyauthorization" "$vtype"; then _err "$d:Can not get challenge: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup @@ -4047,14 +4065,18 @@ $_authorizations_map" fi if [ "$code" ] && [ "$code" != '202' ]; then - if [ "$ACME_VERSION" = "2" ] && [ "$code" = '200' ]; then + if [ "$BUYPASS" ] && [ "$code" = '200' ]; then _debug "trigger validation code: $code" else - _err "$d:Challenge error: $response" - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 + if [ "$ACME_VERSION" = "2" ] && [ "$code" = '200' ]; then + _debug "trigger validation code: $code" + else + _err "$d:Challenge error: $response" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi fi fi From 8bd12ed040c65fcc5b4919c1f81835c579da6314 Mon Sep 17 00:00:00 2001 From: Ketil Date: Fri, 28 Dec 2018 09:22:31 +0100 Subject: [PATCH 207/280] Rewrite to remove BuyPass spesific fixes and adapt ACME v1 --- acme.sh | 44 +++++++++++--------------------------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/acme.sh b/acme.sh index aa2adc6..0ec0851 100755 --- a/acme.sh +++ b/acme.sh @@ -1822,12 +1822,9 @@ _send_signed_request() { _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then _headers="" - if [ "$ACME_NEW_NONCE" ] || [ "$BUYPASS" ]; then + if [ "$ACME_NEW_NONCE" ]; then + _debug2 "Get nonce with HEAD. ACME_NEW_NONCE" "$ACME_NEW_NONCE" nonceurl="$ACME_NEW_NONCE" - if [ "$BUYPASS" ]; then - nonceurl=$url - fi - _debug2 "Get nonce with HEAD. ACME_NEW_NONCE" "$nonceurl" if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then _headers="$(cat "$HTTP_HEADER")" fi @@ -1880,11 +1877,7 @@ _send_signed_request() { sig="$(printf "%s" "$_sig_t" | _url_replace)" _debug3 sig "$sig" - if [ "$ACME_VERSION" = "2" ] || [ "$BUYPASS" ]; then - body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" - else - body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" - fi + body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" _debug3 body "$body" response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")" @@ -2335,13 +2328,6 @@ _initAPI() { fi export ACME_AGREEMENT - BUYPASS=$(echo "$_api_server" | _egrep_o 'buypass') - if [ "$BUYPASS" ]; then - BUYPASS=1 - fi - export BUYPASS - _debug "BUYPASS" "$BUYPASS" - _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" @@ -3455,7 +3441,7 @@ __get_domain_new_authz() { #uri keyAuthorization __trigger_validation() { - _debug2 "tigger domain validation." + _debug2 "Trigger domain validation." _t_url="$1" _debug2 _t_url "$_t_url" _t_key_authz="$2" @@ -3465,11 +3451,7 @@ __trigger_validation() { if [ "$ACME_VERSION" = "2" ]; then _send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}" else - if [ "$BUYPASS" ]; then - _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"type\": \"$_t_vtype\", \"keyAuthorization\": \"$_t_key_authz\"}" - else - _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" - fi + _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"type\": \"$_t_vtype\", \"keyAuthorization\": \"$_t_key_authz\"}" fi } @@ -4065,18 +4047,14 @@ $_authorizations_map" fi if [ "$code" ] && [ "$code" != '202' ]; then - if [ "$BUYPASS" ] && [ "$code" = '200' ]; then + if [ "$code" = '200' ]; then _debug "trigger validation code: $code" else - if [ "$ACME_VERSION" = "2" ] && [ "$code" = '200' ]; then - _debug "trigger validation code: $code" - else - _err "$d:Challenge error: $response" - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 - fi + _err "$d:Challenge error: $response" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 fi fi From 65a2f789dc415c518d16d5c50e9d0d28919eb5ff Mon Sep 17 00:00:00 2001 From: Ketil Date: Fri, 28 Dec 2018 13:26:20 +0100 Subject: [PATCH 208/280] Removing BUYPASS_CA variable --- acme.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/acme.sh b/acme.sh index 0ec0851..422383b 100755 --- a/acme.sh +++ b/acme.sh @@ -13,8 +13,6 @@ _SCRIPT_="$0" _SUB_FOLDERS="dnsapi deploy" -BUYPASS_CA="https://api.buypass.no/acme/directory" - LETSENCRYPT_CA_V1="https://acme-v01.api.letsencrypt.org/directory" LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory" From b32071ad049e3235adebd87f64b1899bbc3d21f2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 28 Dec 2018 22:12:54 +0800 Subject: [PATCH 209/280] remove unused code --- acme.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 422383b..dd71835 100755 --- a/acme.sh +++ b/acme.sh @@ -36,7 +36,6 @@ _OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" VTYPE_TLS="tls-sni-01" -VTYPE_TLS2="tls-sni-02" VTYPE_ALPN="tls-alpn-01" LOCAL_ANY_ADDRESS="0.0.0.0" @@ -3700,11 +3699,7 @@ $_authorizations_map" fi if [ "$_currentRoot" = "$W_TLS" ]; then - if [ "$ACME_VERSION" = "2" ]; then - vtype="$VTYPE_TLS2" - else - vtype="$VTYPE_TLS" - fi + vtype="$VTYPE_TLS" fi if [ "$_currentRoot" = "$W_ALPN" ]; then From 7ba9a5972dd904b1b5834e7ef1a6a3323d1e29aa Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 28 Dec 2018 22:45:40 +0800 Subject: [PATCH 210/280] revert fix for https://github.com/Neilpang/acme.sh/issues/1941 1. fix https://github.com/Neilpang/acme.sh/issues/1977 2. The cache is too long to as a line to save in the conf --- dnsapi/dns_cf.sh | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 021094d..202385f 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -34,9 +34,6 @@ dns_cf_add() { _saveaccountconf_mutable CF_Key "$CF_Key" _saveaccountconf_mutable CF_Email "$CF_Email" - _DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '+@.' '___')" - _cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" - _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" @@ -105,16 +102,11 @@ dns_cf_rm() { return 1 fi - _DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '+@.' '___')" - _debug "First detect the root zone" if ! _get_root "$fulldomain"; then - _cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" _err "invalid domain" return 1 fi - _cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" - _debug _domain_id "$_domain_id" _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" @@ -154,21 +146,6 @@ dns_cf_rm() { # _domain=domain.com # _domain_id=sdjkglgdfewsdfg _get_root() { - - _cf_zones="$(_readdomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_")" - _debug2 "_cf_zones" "$_cf_zones" - if [ -z "$_cf_zones" ]; then - _debug "$_DOMAIN_CF_ZONES_CACHE_NAME_ is none, so get it." - if ! _cf_rest GET "zones"; then - return 1 - fi - _cf_zones="$response" - _savedomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" "$(echo "$_cf_zones" | _base64)" - else - _debug "$_DOMAIN_CF_ZONES_CACHE_NAME_ found" - _cf_zones="$(echo "$_cf_zones" | _dbase64)" - fi - domain=$1 i=2 p=1 @@ -180,8 +157,12 @@ _get_root() { return 1 fi - if _contains "$_cf_zones" "\"name\":\"$h\"" >/dev/null; then - _domain_id=$(echo "$_cf_zones" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "^\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") + if ! _cf_rest GET "zones?name=$h"; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _domain_id=$(echo "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain=$h From ec67a1b2c12c4fa1bdb28feb870853652b7bbe07 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 28 Dec 2018 22:52:40 +0800 Subject: [PATCH 211/280] Do not limit the renew days to 60, it's just a default value. buypass support 180 days. --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index dd71835..aae16f0 100755 --- a/acme.sh +++ b/acme.sh @@ -40,7 +40,7 @@ VTYPE_ALPN="tls-alpn-01" LOCAL_ANY_ADDRESS="0.0.0.0" -MAX_RENEW=60 +DEFAULT_RENEW=60 DEFAULT_DNS_SLEEP=120 @@ -4267,8 +4267,8 @@ $_authorizations_map" Le_CertCreateTimeStr=$(date -u) _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr" - if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ]; then - Le_RenewalDays="$MAX_RENEW" + if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ]; then + Le_RenewalDays="$DEFAULT_RENEW" else _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" fi @@ -5520,7 +5520,7 @@ Parameters: --useragent Specifies the user agent string. it will be saved for future use too. --accountemail Specifies the account email, only valid for the '--install' and '--update-account' command. --accountkey Specifies the account key path, only valid for the '--install' command. - --days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days. + --days Specifies the days to renew the cert when using '--issue' command. The default value is $DEFAULT_RENEW days. --httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer. --tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer. --local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses. From c4094c68ee44cd9651fb1effe38ce4a1c97b1cee Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 28 Dec 2018 23:04:40 +0800 Subject: [PATCH 212/280] Support BuyPass.com CA --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 6a1cf3a..50d2cfb 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,10 @@ For all build statuses, check our [weekly build project](https://github.com/Neil https://github.com/Neilpang/acmetest +# Supported CA + +- Letsencrypt.org CA(default) +- [BuyPass.com CA](https://github.com/Neilpang/acme.sh/wiki/BuyPass.com-CA) # Supported modes From c9baca79109de3d55a6ced143b01e4ef7a07729a Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 28 Dec 2018 23:12:16 +0800 Subject: [PATCH 213/280] add tls-alpn mode --- README.md | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 50d2cfb..2d31c67 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ https://github.com/Neilpang/acmetest - Webroot mode - Standalone mode +- Standalone tls-alpn mode - Apache mode - Nginx mode - DNS mode @@ -225,8 +226,20 @@ acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert +# 5. Use Standalone ssl server to issue cert -# 5. Use Apache mode +**(requires you to be root/sudoer or have permission to listen on port 443 (TCP))** + +Port `443` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again. + +```bash +acme.sh --issue --alpn -d example.com -d www.example.com -d cp.example.com +``` + +More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert + + +# 6. Use Apache mode **(requires you to be root/sudoer, since it is required to interact with Apache server)** @@ -246,7 +259,7 @@ We don't want to mess your apache server, don't worry.** More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert -# 6. Use Nginx mode +# 7. Use Nginx mode **(requires you to be root/sudoer, since it is required to interact with Nginx server)** @@ -270,7 +283,7 @@ We don't want to mess your nginx server, don't worry.** More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert -# 7. Automatic DNS API integration +# 8. Automatic DNS API integration If your DNS provider supports API access, we can use that API to automatically issue the certs. @@ -348,7 +361,7 @@ If your DNS provider is not on the supported list above, you can write your own For more details: [How to use DNS API](dnsapi) -# 8. Use DNS manual mode: +# 9. Use DNS manual mode: See: https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode first. @@ -384,7 +397,7 @@ Ok, it's done. **Please use dns api mode instead.** -# 9. Issue ECC certificates +# 10. Issue ECC certificates `Let's Encrypt` can now issue **ECDSA** certificates. @@ -416,7 +429,7 @@ Valid values are: -# 10. Issue Wildcard certificates +# 11. Issue Wildcard certificates It's simple, just give a wildcard domain as the `-d` parameter. @@ -426,7 +439,7 @@ acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf -# 11. How to renew the certs +# 12. How to renew the certs No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days. @@ -443,7 +456,7 @@ acme.sh --renew -d example.com --force --ecc ``` -# 12. How to stop cert renewal +# 13. How to stop cert renewal To stop renewal of a cert, you can execute the following to remove the cert from the renewal list: @@ -456,7 +469,7 @@ The cert/key file is not removed from the disk. You can remove the respective directory (e.g. `~/.acme.sh/example.com`) by yourself. -# 13. How to upgrade `acme.sh` +# 14. How to upgrade `acme.sh` acme.sh is in constant development, so it's strongly recommended to use the latest code. @@ -481,25 +494,25 @@ acme.sh --upgrade --auto-upgrade 0 ``` -# 14. Issue a cert from an existing CSR +# 15. Issue a cert from an existing CSR https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR -# 15. Under the Hood +# 16. Under the Hood Speak ACME language using shell, directly to "Let's Encrypt". TODO: -# 16. Acknowledgments +# 17. Acknowledgments 1. Acme-tiny: https://github.com/diafygi/acme-tiny 2. ACME protocol: https://github.com/ietf-wg-acme/acme -# 17. License & Others +# 18. License & Others License is GPLv3 @@ -508,7 +521,7 @@ Please Star and Fork me. [Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome. -# 18. Donate +# 19. Donate Your donation makes **acme.sh** better: 1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/) From 29a5311ae0cb82799d404efb8dc1b4c3cc7ff14d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20R=C3=B6ttsches?= Date: Fri, 28 Dec 2018 00:45:51 +0200 Subject: [PATCH 214/280] [dnsapi] Support adding / removing multiple TXT values for Gandi Gandi supports setting multiple entries by setting multiple array items for the rrset_values field in their API. Modify the dns_gandi_livedns.sh script so that it checks for existing entries, appends new ones if needed, and removes existing ones individually. This enabled wildcard certificate support on Gandi. Fixes the dns_gandi_livedns part of #1261. Tested for creating a multidomain, multiple wild-card certificate on Gandi and using a test script executing only the dns_gandi_livedns_add and dns_gandi_livedns_rm functions. --- dnsapi/dns_gandi_livedns.sh | 62 ++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 5 deletions(-) mode change 100755 => 100644 dnsapi/dns_gandi_livedns.sh diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh old mode 100755 new mode 100644 index 7a21aba..cdda477 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -7,6 +7,7 @@ # Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable # #Author: Frédéric Crozat +# Dominik Röttsches #Report Bugs here: https://github.com/fcrozat/acme.sh # ######## Public functions ##################### @@ -36,9 +37,7 @@ dns_gandi_livedns_add() { _debug domain "$_domain" _debug sub_domain "$_sub_domain" - _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \ - && _contains "$response" '{"message": "DNS Record Created"}' \ - && _info "Add $(__green "success")" + _dns_gandi_append_record "$_domain" "$_sub_domain" "$txtvalue" } #Usage: fulldomain txtvalue @@ -56,9 +55,23 @@ dns_gandi_livedns_rm() { _debug fulldomain "$fulldomain" _debug domain "$_domain" _debug sub_domain "$_sub_domain" + _debug txtvalue "$txtvalue" - _gandi_livedns_rest DELETE "domains/$_domain/records/$_sub_domain/TXT" "" - + if ! _dns_gandi_existing_rrset_values "$_domain" "$_sub_domain"; then + return 1 + fi + _new_rrset_values=$(echo "$_rrset_values" | sed "s/...$txtvalue...//g") + # Cleanup dangling commata. + _new_rrset_values=$(echo "$_new_rrset_values" | sed "s/, ,/ ,/g") + _new_rrset_values=$(echo "$_new_rrset_values" | sed "s/, *\]/\]/g") + _new_rrset_values=$(echo "$_new_rrset_values" | sed "s/\[ *,/\[/g") + _debug "New rrset_values" "$_new_rrset_values" + + _gandi_livedns_rest PUT \ + "domains/$_domain/records/$_sub_domain/TXT" \ + "{\"rrset_ttl\": 300, \"rrset_values\": $_new_rrset_values}" \ + && _contains "$response" '{"message": "DNS Record Created"}' \ + && _info "Removing record $(__green "success")" } #################### Private functions below ################################## @@ -98,6 +111,45 @@ _get_root() { return 1 } +_dns_gandi_append_record() { + domain=$1 + sub_domain=$2 + txtvalue=$3 + + if _dns_gandi_existing_rrset_values "$domain" "$sub_domain"; then + _debug "Appending new value" + _rrset_values=$(echo "$_rrset_values" | sed "s/\"]/\",\"$txtvalue\"]/") + else + _debug "Creating new record" "$_rrset_values" + _rrset_values="[\"$txtvalue\"]" + fi + _debug new_rrset_values "$_rrset_values" + _gandi_livedns_rest PUT "domains/$_domain/records/$sub_domain/TXT" \ + "{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" \ + && _contains "$response" '{"message": "DNS Record Created"}' \ + && _info "Adding record $(__green "success")" +} + +_dns_gandi_existing_rrset_values() { + domain=$1 + sub_domain=$2 + if ! _gandi_livedns_rest GET "domains/$domain/records/$sub_domain"; then + return 1 + fi + if ! _contains "$response" '"rrset_type": "TXT"'; then + _debug "Does not have a _acme-challenge TXT record yet." + return 1 + fi + if _contains "$response" '"rrset_values": \[\]'; then + _debug "Empty rrset_values for TXT record, no previous TXT record." + return 1 + fi + _debug "Already has TXT record." + _rrset_values=$(echo "$response" | _egrep_o 'rrset_values.*\[.*\]' \ + | _egrep_o '\[".*\"]') + return 0 +} + _gandi_livedns_rest() { m=$1 ep="$2" From 68c5c366f4bc0ab421bd2004e40718b7561c984f Mon Sep 17 00:00:00 2001 From: Ben Edmunds Date: Sun, 30 Dec 2018 03:13:23 +0000 Subject: [PATCH 215/280] dnsapi update dynu for api v2 --- dnsapi/dns_dynu.sh | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 17a1cdb..506ef53 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -10,7 +10,7 @@ Dynu_Token="" # #Endpoint -Dynu_EndPoint="https://api.dynu.com/v1" +Dynu_EndPoint="https://api.dynu.com/v2" # #Author: Dynu Systems, Inc. #Report Bugs here: https://github.com/shar0119/acme.sh @@ -51,11 +51,11 @@ dns_dynu_add() { _debug _domain_name "$_domain_name" _info "Creating TXT record." - if ! _dynu_rest POST "dns/record/add" "{\"domain_name\":\"$_domain_name\",\"node_name\":\"$_node\",\"record_type\":\"TXT\",\"text_data\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then + if ! _dynu_rest POST "dns/$dnsId/record" "{\"domainId\":\"$dnsId\",\"nodeName\":\"$_node\",\"recordType\":\"TXT\",\"textData\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then return 1 fi - if ! _contains "$response" "text_data"; then + if ! _contains "$response" "200"; then _err "Could not add TXT record." return 1 fi @@ -132,11 +132,12 @@ _get_root() { return 1 fi - if ! _dynu_rest GET "dns/get/$h"; then + if ! _dynu_rest GET "dns/getroot/$h"; then return 1 fi - if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + if _contains "$response" "\"domainName\":\"$h\"" >/dev/null; then + dnsId=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 2 | cut -d : -f 2) _domain_name=$h _node=$(printf "%s" "$domain" | cut -d . -f 1-$p) return 0 @@ -152,7 +153,7 @@ _get_recordid() { fulldomain=$1 txtvalue=$2 - if ! _dynu_rest GET "dns/record/get?hostname=$fulldomain&rrtype=TXT"; then + if ! _dynu_rest GET "dns/$dnsId/record"; then return 1 fi @@ -161,19 +162,18 @@ _get_recordid() { return 0 fi - _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | _egrep_o ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2) - + _dns_record_id=$(printf "%s" "$response" | sed -e 's/[^{]*\({[^}]*}\)[^{]*/\1\n/g' | grep "\"textData\":\"$txtvalue\"" | sed -e 's/.*"id":\([^,]*\).*/\1/') return 0 } _delete_txt_record() { _dns_record_id=$1 - if ! _dynu_rest GET "dns/record/delete/$_dns_record_id"; then + if ! _dynu_rest DELETE "dns/$dnsId/record/$_dns_record_id"; then return 1 fi - if ! _contains "$response" "true"; then + if ! _contains "$response" "200"; then return 1 fi @@ -189,7 +189,7 @@ _dynu_rest() { export _H1="Authorization: Bearer $Dynu_Token" export _H2="Content-Type: application/json" - if [ "$data" ]; then + if [ "$data" ] || [ "$m" = "DELETE" ]; then _debug data "$data" response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")" else @@ -216,8 +216,8 @@ _dynu_authentication() { _err "Authentication failed." return 1 fi - if _contains "$response" "accessToken"; then - Dynu_Token=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 2 | cut -d : -f 2 | cut -d '"' -f 2) + if _contains "$response" "access_token"; then + Dynu_Token=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 1 | cut -d : -f 2 | cut -d '"' -f 2) fi if _contains "$Dynu_Token" "null"; then Dynu_Token="" From cd4f29135b8f66d5dc8a34833712ad90eceefe9f Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Wed, 2 Jan 2019 16:44:11 +0100 Subject: [PATCH 216/280] waiting for API zoneStatus active --- dnsapi/dns_hostingde.sh | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index 39bcfb6..317ebed 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -74,8 +74,26 @@ _hostingde_getZoneConfig() { return $returnCode } +_hostingde_getZoneStatus() { + _debug "Checking Zone status" + curData="{\"filter\":{\"field\":\"zoneConfigId\",\"value\":\"${zoneConfigId}\"},\"limit\":1,\"authToken\":\"${HOSTINGDE_APIKEY}\"}" + curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zonesFind")" + _debug "Calling zonesFind '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zonesFind'" + _debug "Result of zonesFind '$curResult'" + zoneStatus=$(echo "${curResult}" | grep -v success | _egrep_o '"status":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + _debug "zoneStatus '${zoneStatus}'" + return 0 +} + _hostingde_addRecord() { _info "Adding record to zone" + _hostingde_getZoneStatus + _debug "Result of zoneStatus: '${zoneStatus}'" + while [ "${zoneStatus}" != "active" ]; do + sleep 5 + _hostingde_getZoneStatus + _debug "Result of zoneStatus: '${zoneStatus}'" + done curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\"},\"recordsToAdd\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\",\"ttl\":3600}]}" curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")" _debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'" @@ -93,6 +111,13 @@ _hostingde_addRecord() { _hostingde_removeRecord() { _info "Removing record from zone" + _hostingde_getZoneStatus + _debug "Result of zoneStatus: '$zoneStatus'" + while [ "$zoneStatus" != "active" ]; do + sleep 5 + _hostingde_getZoneStatus + _debug "Result of zoneStatus: '$zoneStatus'" + done curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\"},\"recordsToDelete\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\"}]}" curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")" _debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'" From ecf7dded07144d81aba47addee52eae0c072dbd0 Mon Sep 17 00:00:00 2001 From: Ivru Date: Thu, 3 Jan 2019 08:39:51 +0100 Subject: [PATCH 217/280] Fix typo --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 201deee..9358eb4 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1122,7 +1122,7 @@ export EXOSCALE_SECRET_KEY='xxx' Now, let's issue a cert: ``` -acme.sh --issue --dns dns_netcup -d example.com -d www.example.com +acme.sh --issue --dns dns_exoscale -d example.com -d www.example.com ``` The `EXOSCALE_API_KEY` and `EXOSCALE_SECRET_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. From 089823785e1aa4b1cb4d3b4725bab2920a97ff02 Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Thu, 3 Jan 2019 10:32:59 +0100 Subject: [PATCH 218/280] Using _sleep() instead of sleep --- dnsapi/dns_hostingde.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index 317ebed..74a472d 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -90,7 +90,7 @@ _hostingde_addRecord() { _hostingde_getZoneStatus _debug "Result of zoneStatus: '${zoneStatus}'" while [ "${zoneStatus}" != "active" ]; do - sleep 5 + _sleep 5 _hostingde_getZoneStatus _debug "Result of zoneStatus: '${zoneStatus}'" done @@ -114,7 +114,7 @@ _hostingde_removeRecord() { _hostingde_getZoneStatus _debug "Result of zoneStatus: '$zoneStatus'" while [ "$zoneStatus" != "active" ]; do - sleep 5 + _sleep 5 _hostingde_getZoneStatus _debug "Result of zoneStatus: '$zoneStatus'" done From 40f0238bb79a14ed884a520b24cb5cbcdbd3aa08 Mon Sep 17 00:00:00 2001 From: Marton Szucs Date: Thu, 3 Jan 2019 11:32:43 +0100 Subject: [PATCH 219/280] fix dns_loopia wildcard certificate Checks if a subdomain already exists before creating one. The loopia API clears all records for a subdomain when adding it again. Adding TXT-records instead of updating the existing record when using the add method. Wildcard certificates require multiple TXT-records for the same subdomain. Now you can create wildcard certificates using: `acme.sh --issue -d example.com -d '*.example.com' --dns dns_loopia` Double quoting variables --- dnsapi/dns_loopia.sh | 77 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh index 5d76118..ece5ef8 100644 --- a/dnsapi/dns_loopia.sh +++ b/dnsapi/dns_loopia.sh @@ -38,8 +38,8 @@ dns_loopia_add() { _info "Adding record" - _loopia_add_record "$_domain" "$_sub_domain" - _loopia_update_record "$_domain" "$_sub_domain" "$txtvalue" + _loopia_add_sub_domain "$_domain" "$_sub_domain" + _loopia_add_record "$_domain" "$_sub_domain" "$txtvalue" } @@ -96,6 +96,37 @@ dns_loopia_rm() { #################### Private functions below ################################## +_loopia_get_records() { + domain=$1 + sub_domain=$2 + + xml_content=$(printf ' + + getZoneRecords + + + %s + + + %s + + + %s + + + %s + + + ' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + if ! _contains "$response" ""; then + _err "Error" + return 1 + fi + return 0 +} + _get_root() { domain=$1 _debug "get root" @@ -137,14 +168,14 @@ _get_root() { } -_loopia_update_record() { +_loopia_add_record() { domain=$1 sub_domain=$2 txtval=$3 xml_content=$(printf ' - updateZoneRecord + addZoneRecord %s @@ -176,10 +207,6 @@ _loopia_update_record() { rdata %s - - record_id - 0 - @@ -194,10 +221,42 @@ _loopia_update_record() { return 0 } -_loopia_add_record() { +_sub_domain_exists() { domain=$1 sub_domain=$2 + xml_content=$(printf ' + + getSubdomains + + + %s + + + %s + + + %s + + + ' $LOOPIA_User $LOOPIA_Password "$domain") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + + if _contains "$response" "$sub_domain"; then + return 0 + fi + return 1 +} + +_loopia_add_sub_domain() { + domain=$1 + sub_domain=$2 + + if _sub_domain_exists "$domain" "$sub_domain"; then + return 0 + fi + xml_content=$(printf ' addSubdomain From 68d9aad3a26eacb0d57d9c5fe66f59571bddab69 Mon Sep 17 00:00:00 2001 From: hebbet Date: Thu, 3 Jan 2019 14:19:55 +0100 Subject: [PATCH 220/280] add link to profile of Cloudflare follow-up for #1893 --- dnsapi/dns_cf.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 202385f..532199f 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -19,8 +19,8 @@ dns_cf_add() { if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then CF_Key="" CF_Email="" - _err "You didn't specify a cloudflare api key and email yet." - _err "Please create the key and try again." + _err "You didn't specify a Cloudflare api key and email yet." + _err "You can get yours from here https://dash.cloudflare.com/profile." return 1 fi @@ -97,8 +97,8 @@ dns_cf_rm() { if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then CF_Key="" CF_Email="" - _err "You didn't specify a cloudflare api key and email yet." - _err "Please create the key and try again." + _err "You didn't specify a Cloudflare api key and email yet." + _err "You can get yours from here https://dash.cloudflare.com/profile." return 1 fi From ad613e2437f0cb4cb476af6c61c5975cf1212db8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 4 Jan 2019 22:40:59 +0800 Subject: [PATCH 221/280] fix alpn oid. https://github.com/Neilpang/acme.sh/issues/2005 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index aae16f0..8b7fa70 100755 --- a/acme.sh +++ b/acme.sh @@ -1089,7 +1089,7 @@ _createcsr() { fi if [ "$acmeValidationv1" ]; then - printf "\n1.3.6.1.5.5.7.1.30.1=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}" + printf "\n1.3.6.1.5.5.7.1.31=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}" fi _csr_cn="$(_idn "$domain")" From 0483d841e385626e6dc45bc24c8d88a3d5277b62 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 6 Jan 2019 21:05:33 +0800 Subject: [PATCH 222/280] Support Post as Get (#2009) * Support POST as GET https://community.letsencrypt.org/t/acme-v2-scheduled-deprecation-of-unauthenticated-resource-gets/74380 * fix PAG, The newline '\n' in response is removed by _send_signed_request(), to keep it, we just use needbase64 * fix PAG, the cert is muti line * fix format * PAG is only for v2 --- acme.sh | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 8b7fa70..872529f 100755 --- a/acme.sh +++ b/acme.sh @@ -3651,7 +3651,7 @@ issue() { _authorizations_map="" for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' '); do _debug2 "_authz_url" "$_authz_url" - if ! response="$(_get "$_authz_url")"; then + if ! _send_signed_request "$_authz_url"; then _err "get to authz error." _err "_authorizations_seg" "$_authorizations_seg" _err "_authz_url" "$_authz_url" @@ -4069,7 +4069,11 @@ $_authorizations_map" _debug "sleep 2 secs to verify" sleep 2 _debug "checking" - response="$(_get "$uri")" + if [ "$ACME_VERSION" = "2" ]; then + _send_signed_request "$uri" + else + response="$(_get "$uri")" + fi if [ "$?" != "0" ]; then _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" @@ -4145,13 +4149,16 @@ $_authorizations_map" fi Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" - if ! _get "$Le_LinkCert" >"$CERT_PATH"; then + _tempSignedResponse="$response" + if ! _send_signed_request "$Le_LinkCert" "" "needbase64"; then _err "Sign failed, can not download cert:$Le_LinkCert." _err "$response" _on_issue_err "$_post_hook" return 1 fi + echo "$response" | _dbase64 "multiline" >"$CERT_PATH" + if [ "$(grep -- "$BEGIN_CERT" "$CERT_PATH" | wc -l)" -gt "1" ]; then _debug "Found cert chain" cat "$CERT_PATH" >"$CERT_FULLCHAIN_PATH" @@ -4161,6 +4168,7 @@ $_authorizations_map" _end_n="$(_math $_end_n + 1)" sed -n "${_end_n},9999p" "$CERT_FULLCHAIN_PATH" >"$CA_CERT_PATH" fi + response="$_tempSignedResponse" else if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed. $response" @@ -4231,7 +4239,8 @@ $_authorizations_map" while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do _debug _link_issuer_retry "$_link_issuer_retry" if [ "$ACME_VERSION" = "2" ]; then - if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then + if _send_signed_request "$Le_LinkIssuer"; then + echo "$response" >"$CA_CERT_PATH" break fi else @@ -4957,7 +4966,7 @@ _deactivate() { authzUri="$_authorizations_seg" _debug2 "authzUri" "$authzUri" - if ! response="$(_get "$authzUri")"; then + if ! _send_signed_request "$authzUri"; then _err "get to authz error." _err "_authorizations_seg" "$_authorizations_seg" _err "authzUri" "$authzUri" From 72ce37704bbaa04d71623c50b545ef1357e981b3 Mon Sep 17 00:00:00 2001 From: Mike Barnes Date: Tue, 8 Jan 2019 15:49:09 +1100 Subject: [PATCH 223/280] Native PointHQ support --- dnsapi/README.md | 19 ++++- dnsapi/dns_pointhq.sh | 164 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 dnsapi/dns_pointhq.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index 9358eb4..f1bf05e 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1,12 +1,12 @@ # How to use DNS API -If your dns provider doesn't provide api access, you can use our dns alias mode: +If your dns provider doesn't provide api access, you can use our dns alias mode: https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode ## 1. Use CloudFlare domain API to automatically issue cert -First you need to login to your CloudFlare account to get your [API key](https://dash.cloudflare.com/profile). +First you need to login to your CloudFlare account to get your [API key](https://dash.cloudflare.com/profile). ``` export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" @@ -891,7 +891,7 @@ acme.sh --issue --dns dns_loopia -d example.com -d *.example.com The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed. ## 45. Use ACME DNS API -ACME DNS is a limited DNS server with RESTful HTTP API to handle ACME DNS challenges easily and securely. +ACME DNS is a limited DNS server with RESTful HTTP API to handle ACME DNS challenges easily and securely. https://github.com/joohoi/acme-dns ``` @@ -1056,6 +1056,7 @@ Now you can issue a certificate. acme.sh --issue --dns dns_namecheap -d example.com -d *.example.com ``` +<<<<<<< HEAD ## 54. Use MyDNS.JP API First, register to MyDNS.JP and get MasterID and Password. @@ -1127,6 +1128,18 @@ acme.sh --issue --dns dns_exoscale -d example.com -d www.example.com The `EXOSCALE_API_KEY` and `EXOSCALE_SECRET_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 58. Using PointHQ API to issue certs + +Log into [PointHQ account management](https://app.pointhq.com/profile) and copy the API key from the page there. + +```export PointHQ_Key="apikeystringgoeshere" +exportPointHQ_Email="accountemail@yourdomain.com" +``` + +You can then issue certs by using: +```acme.sh --issue --dns dns_pointhq -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_pointhq.sh b/dnsapi/dns_pointhq.sh new file mode 100644 index 0000000..6231310 --- /dev/null +++ b/dnsapi/dns_pointhq.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env sh + +# +#PointHQ_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#PointHQ_Email="xxxx@sss.com" + +PointHQ_Api="https://api.pointhq.com" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_pointhq_add() { + fulldomain=$1 + txtvalue=$2 + + PointHQ_Key="${PointHQ_Key:-$(_readaccountconf_mutable PointHQ_Key)}" + PointHQ_Email="${PointHQ_Email:-$(_readaccountconf_mutable PointHQ_Email)}" + if [ -z "$PointHQ_Key" ] || [ -z "$PointHQ_Email" ]; then + PointHQ_Key="" + PointHQ_Email="" + _err "You didn't specify a PointHQ API key and email yet." + _err "Please create the key and try again." + return 1 + fi + + if ! _contains "$PointHQ_Email" "@"; then + _err "It seems that the PointHQ_Email=$PointHQ_Email is not a valid email address." + _err "Please check and retry." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable PointHQ_Key "$PointHQ_Key" + _saveaccountconf_mutable PointHQ_Email "$PointHQ_Email" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + if _pointhq_rest POST "zones/$_domain/records" "{\"zone_record\": {\"name\":\"$_sub_domain\",\"record_type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":3600}}"; then + if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + return 1 +} + +#fulldomain txtvalue +dns_pointhq_rm() { + fulldomain=$1 + txtvalue=$2 + + PointHQ_Key="${PointHQ_Key:-$(_readaccountconf_mutable PointHQ_Key)}" + PointHQ_Email="${PointHQ_Email:-$(_readaccountconf_mutable PointHQ_Email)}" + if [ -z "$PointHQ_Key" ] || [ -z "$PointHQ_Email" ]; then + PointHQ_Key="" + PointHQ_Email="" + _err "You didn't specify a PointHQ API key and email yet." + _err "Please create the key and try again." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _pointhq_rest GET "zones/${_domain}/records?record_type=TXT&name=$_sub_domain" + + if ! printf "%s" "$response" | grep "^\[" >/dev/null; then + _err "Error" + return 1 + fi + + if [ "$response" = "[]" ]; then + _info "No records to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | tr -d \" | head -n 1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _pointhq_rest DELETE "zones/$_domain/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" '"status":"OK"' + fi +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _pointhq_rest GET "zones"; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_pointhq_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + _pointhq_auth=$(printf "%s:%s" "$PointHQ_Email" "$PointHQ_Key" | _base64) + + export _H1="Authorization: Basic $_pointhq_auth" + export _H2="Content-Type: application/json" + export _H3="Accept: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$PointHQ_Api/$ep" "" "$m")" + else + response="$(_get "$PointHQ_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From cd3ef8fa5ac946975704d6bb910b2ddf07314377 Mon Sep 17 00:00:00 2001 From: Mike Barnes Date: Tue, 8 Jan 2019 15:53:53 +1100 Subject: [PATCH 224/280] Correct edits to README.md this time --- dnsapi/README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index f1bf05e..fc65748 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1,12 +1,12 @@ # How to use DNS API -If your dns provider doesn't provide api access, you can use our dns alias mode: +If your dns provider doesn't provide api access, you can use our dns alias mode: https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode ## 1. Use CloudFlare domain API to automatically issue cert -First you need to login to your CloudFlare account to get your [API key](https://dash.cloudflare.com/profile). +First you need to login to your CloudFlare account to get your [API key](https://dash.cloudflare.com/profile). ``` export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" @@ -891,7 +891,7 @@ acme.sh --issue --dns dns_loopia -d example.com -d *.example.com The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed. ## 45. Use ACME DNS API -ACME DNS is a limited DNS server with RESTful HTTP API to handle ACME DNS challenges easily and securely. +ACME DNS is a limited DNS server with RESTful HTTP API to handle ACME DNS challenges easily and securely. https://github.com/joohoi/acme-dns ``` @@ -1056,7 +1056,6 @@ Now you can issue a certificate. acme.sh --issue --dns dns_namecheap -d example.com -d *.example.com ``` -<<<<<<< HEAD ## 54. Use MyDNS.JP API First, register to MyDNS.JP and get MasterID and Password. From 3099c799b25b4eca5de668326b3be297eed12903 Mon Sep 17 00:00:00 2001 From: Mike Barnes Date: Wed, 9 Jan 2019 10:24:28 +1100 Subject: [PATCH 225/280] Added PointHQ to supported API list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2d31c67..41ffb69 100644 --- a/README.md +++ b/README.md @@ -348,6 +348,7 @@ You don't have to do anything manually! 1. hosting.de (https://www.hosting.de) 1. Neodigit.net API (https://www.neodigit.net) 1. Exoscale.com API (https://www.exoscale.com/) +1. PointDNS API (https://pointhq.com/) And: From dd068467def09b070dc2e7dcf158cf69d52c5d74 Mon Sep 17 00:00:00 2001 From: Fabio Kruger Date: Thu, 10 Jan 2019 19:33:25 +0100 Subject: [PATCH 226/280] 2020 Added a space to improve log readability --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 872529f..ff47286 100755 --- a/acme.sh +++ b/acme.sh @@ -3901,7 +3901,7 @@ $_authorizations_map" continue fi - _info "Verifying:$d" + _info "Verifying: $d" _debug "d" "$d" _debug "keyauthorization" "$keyauthorization" _debug "uri" "$uri" From e19809d5b510ebd466f1abfd9f8ec4feadae3d92 Mon Sep 17 00:00:00 2001 From: shonenada Date: Fri, 11 Jan 2019 18:17:38 +0800 Subject: [PATCH 227/280] Add deployment for qiniu cdn Upload certificate and privkey to Qiniu's CDN service with https://developer.qiniu.com/fusion/api/4248/certificate --- acme.sh | 2 +- deploy/qiniu.sh | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 deploy/qiniu.sh diff --git a/acme.sh b/acme.sh index 872529f..86b555a 100755 --- a/acme.sh +++ b/acme.sh @@ -1580,7 +1580,7 @@ _inithttp() { fi if [ -z "$_ACME_CURL" ] && _exists "curl"; then - _ACME_CURL="curl -L --silent --dump-header $HTTP_HEADER " + _ACME_CURL="curl -L --dump-header $HTTP_HEADER " if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then _CURL_DUMP="$(_mktemp)" _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh new file mode 100644 index 0000000..4fa66ee --- /dev/null +++ b/deploy/qiniu.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env sh + +# Script to create certificate to qiniu.com +# +# This deployment required following variables +# export QINIU_AK="QINIUACCESSKEY" +# export QINIU_SK="QINIUSECRETKEY" + +QINIU_API_BASE="https://api.qiniu.com" + +qiniu_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if [ -z "$QINIU_AK" ]; then + if [ -z "$Le_Deploy_Qiniu_AK" ]; then + _err "QINIU_AK is not defined." + return 1 + fi + else + Le_Deploy_Qiniu_AK="$QINIU_AK" + _savedomainconf Le_Deploy_Qiniu_AK "$Le_Deploy_Qiniu_AK" + fi + + if [ -z "$QINIU_SK" ]; then + if [ -z "$Le_Deploy_Qiniu_SK" ]; then + _err "QINIU_SK is not defined." + return 1 + fi + else + Le_Deploy_Qiniu_SK="$QINIU_SK" + _savedomainconf Le_Deploy_Qiniu_SK "$Le_Deploy_Qiniu_SK" + fi + + string_fullchain=$(awk '{printf "%s\\n", $0}' "$_cfullchain") + string_key=$(awk '{printf "%s\\n", $0}' "$_ckey") + + body="{\"name\":\"$_cdomain\",\"common_name\":\"$_cdomain\",\"ca\":\""$string_fullchain"\",\"pri\":\"$string_key\"}" + + create_ssl_url="$QINIU_API_BASE/sslcert" + + ACCESSTOKEN="$(_make_sslcreate_access_token)" + export _H1="Authorization: QBox $ACCESSTOKEN" + + _response=$(_post "$body" "$create_ssl_url" 0 "POST" "application/json" | _dbase64 "multiline") + + success_response="certID" + if test "${_response#*$success_response}" == "$_response"; then + _err "Error in deploying certificate:" + _err "$_response" + return 1 + fi + + _debug response "$_response" + _info "Certificate successfully deployed" + + return 0 +} + +_make_sslcreate_access_token() { + _data="/sslcert\\n" + _token="$(printf "$_data" | openssl sha1 -hmac $Le_Deploy_Qiniu_SK -binary | openssl base64 -e)" + echo "$Le_Deploy_Qiniu_AK:$_token" +} From 3bc6628227dcebc1b788ed0676d51b992ee202cc Mon Sep 17 00:00:00 2001 From: shonenada Date: Fri, 11 Jan 2019 19:19:07 +0800 Subject: [PATCH 228/280] Update Qiniu's domain settings after uploading certificate --- acme.sh | 2 +- deploy/qiniu.sh | 41 ++++++++++++++++++++++++++++++++--------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index 86b555a..872529f 100755 --- a/acme.sh +++ b/acme.sh @@ -1580,7 +1580,7 @@ _inithttp() { fi if [ -z "$_ACME_CURL" ] && _exists "curl"; then - _ACME_CURL="curl -L --dump-header $HTTP_HEADER " + _ACME_CURL="curl -L --silent --dump-header $HTTP_HEADER " if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then _CURL_DUMP="$(_mktemp)" _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index 4fa66ee..070b7f6 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -44,30 +44,53 @@ qiniu_deploy() { string_fullchain=$(awk '{printf "%s\\n", $0}' "$_cfullchain") string_key=$(awk '{printf "%s\\n", $0}' "$_ckey") - body="{\"name\":\"$_cdomain\",\"common_name\":\"$_cdomain\",\"ca\":\""$string_fullchain"\",\"pri\":\"$string_key\"}" + sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$_cdomain\",\"ca\":\""$string_fullchain"\",\"pri\":\"$string_key\"}" create_ssl_url="$QINIU_API_BASE/sslcert" - ACCESSTOKEN="$(_make_sslcreate_access_token)" - export _H1="Authorization: QBox $ACCESSTOKEN" + sslcert_access_token="$(_make_sslcreate_access_token "/sslcert\\n")" + _debug sslcert_access_token "$sslcert_access_token" + export _H1="Authorization: QBox $sslcert_access_token" - _response=$(_post "$body" "$create_ssl_url" 0 "POST" "application/json" | _dbase64 "multiline") + sslcert_response=$(_post "$sslcerl_body" "$create_ssl_url" 0 "POST" "application/json" | _dbase64 "multiline") success_response="certID" - if test "${_response#*$success_response}" == "$_response"; then - _err "Error in deploying certificate:" - _err "$_response" + if test "${sslcert_response#*$success_response}" == "$sslcert_response"; then + _err "Error in creating certificate:" + _err "$sslcert_response" return 1 fi - _debug response "$_response" + _debug sslcert_response "$sslcert_response" + _info "Certificate successfully uploaded, updating domain $_cdomain" + + _certId=$(printf "%s" $sslcert_response | sed -e "s/^.*certID\":\"//" -e "s/\"\}$//") + _debug certId "$_certId" + + update_path="/domain/$_cdomain/httpsconf" + update_url="$QINIU_API_BASE$update_path" + update_body="{\"certid\":\""$_certId"\",\"forceHttps\":true}" + + update_access_token="$(_make_sslcreate_access_token "$update_path\\n")" + _debug update_access_token "$update_access_token" + export _H1="Authorization: QBox $update_access_token" + update_response=$(_post "$update_body" "$update_url" 0 "PUT" "application/json" | _dbase64 "multiline") + + err_response="error" + if test "${update_response#*$err_response}" != "$update_response"; then + _err "Error in updating domain:" + _err "$update_response" + return 1 + fi + + _debug update_response "$update_response" _info "Certificate successfully deployed" return 0 } _make_sslcreate_access_token() { - _data="/sslcert\\n" + _data="$1" _token="$(printf "$_data" | openssl sha1 -hmac $Le_Deploy_Qiniu_SK -binary | openssl base64 -e)" echo "$Le_Deploy_Qiniu_AK:$_token" } From d2a60f3ca42aead53dedbb7afa841919ac75fc83 Mon Sep 17 00:00:00 2001 From: shonenada Date: Sat, 12 Jan 2019 15:54:42 +0800 Subject: [PATCH 229/280] lint code --- deploy/qiniu.sh | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index 070b7f6..4f578b2 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -41,18 +41,16 @@ qiniu_deploy() { _savedomainconf Le_Deploy_Qiniu_SK "$Le_Deploy_Qiniu_SK" fi + ## upload certificate string_fullchain=$(awk '{printf "%s\\n", $0}' "$_cfullchain") string_key=$(awk '{printf "%s\\n", $0}' "$_ckey") - sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$_cdomain\",\"ca\":\""$string_fullchain"\",\"pri\":\"$string_key\"}" - - create_ssl_url="$QINIU_API_BASE/sslcert" - - sslcert_access_token="$(_make_sslcreate_access_token "/sslcert\\n")" + sslcert_path="/sslcert" + sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$_cdomain\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}" + sslcert_access_token="$(_make_sslcreate_access_token "$sslcert_path")" _debug sslcert_access_token "$sslcert_access_token" export _H1="Authorization: QBox $sslcert_access_token" - - sslcert_response=$(_post "$sslcerl_body" "$create_ssl_url" 0 "POST" "application/json" | _dbase64 "multiline") + sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline") success_response="certID" if test "${sslcert_response#*$success_response}" == "$sslcert_response"; then @@ -64,21 +62,21 @@ qiniu_deploy() { _debug sslcert_response "$sslcert_response" _info "Certificate successfully uploaded, updating domain $_cdomain" - _certId=$(printf "%s" $sslcert_response | sed -e "s/^.*certID\":\"//" -e "s/\"\}$//") + ## extract certId + _certId=$(printf "%s" "$sslcert_response" | sed -e "s/^.*certID\":\"//" -e "s/\"\}$//") _debug certId "$_certId" + ## update domain ssl config update_path="/domain/$_cdomain/httpsconf" - update_url="$QINIU_API_BASE$update_path" - update_body="{\"certid\":\""$_certId"\",\"forceHttps\":true}" - - update_access_token="$(_make_sslcreate_access_token "$update_path\\n")" + update_body="{\"certid\":\"$_certId\",\"forceHttps\":true}" + update_access_token="$(_make_sslcreate_access_token "$update_path")" _debug update_access_token "$update_access_token" export _H1="Authorization: QBox $update_access_token" - update_response=$(_post "$update_body" "$update_url" 0 "PUT" "application/json" | _dbase64 "multiline") + update_response=$(_post "$update_body" "$QINIU_API_BASE$update_body" 0 "PUT" "application/json" | _dbase64 "multiline") err_response="error" if test "${update_response#*$err_response}" != "$update_response"; then - _err "Error in updating domain:" + _err "Error in updating domain httpsconf:" _err "$update_response" return 1 fi @@ -90,7 +88,7 @@ qiniu_deploy() { } _make_sslcreate_access_token() { - _data="$1" - _token="$(printf "$_data" | openssl sha1 -hmac $Le_Deploy_Qiniu_SK -binary | openssl base64 -e)" + _data="$1\\n" + _token="$(printf "%s" "$_data" | openssl sha1 -hmac "$Le_Deploy_Qiniu_SK" -binary | openssl base64 -e)" echo "$Le_Deploy_Qiniu_AK:$_token" } From 4ec39ab707069e8fe87eccffc289dc0432afcc53 Mon Sep 17 00:00:00 2001 From: shonenada Date: Sat, 12 Jan 2019 19:58:57 +0800 Subject: [PATCH 230/280] replace with functions defined in acme.sh --- deploy/qiniu.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index 4f578b2..c2306c5 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -72,7 +72,7 @@ qiniu_deploy() { update_access_token="$(_make_sslcreate_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_body" 0 "PUT" "application/json" | _dbase64 "multiline") + update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline") err_response="error" if test "${update_response#*$err_response}" != "$update_response"; then @@ -88,7 +88,6 @@ qiniu_deploy() { } _make_sslcreate_access_token() { - _data="$1\\n" - _token="$(printf "%s" "$_data" | openssl sha1 -hmac "$Le_Deploy_Qiniu_SK" -binary | openssl base64 -e)" + _token="$(printf "%s\\n" "$1" | _hmac "sha1" "$(printf "%s" "$Le_Deploy_Qiniu_SK" | _hex_dump | tr -d " ")" | _base64)" echo "$Le_Deploy_Qiniu_AK:$_token" } From 82b11da4caf356f418e12ca5c5fd047bbe21d37e Mon Sep 17 00:00:00 2001 From: shonenada Date: Sat, 12 Jan 2019 21:07:22 +0800 Subject: [PATCH 231/280] replace `awk` with `sed` and `tr` --- deploy/qiniu.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index c2306c5..559e59c 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -42,8 +42,8 @@ qiniu_deploy() { fi ## upload certificate - string_fullchain=$(awk '{printf "%s\\n", $0}' "$_cfullchain") - string_key=$(awk '{printf "%s\\n", $0}' "$_ckey") + string_fullchain=$(sed 's/$/\\n/' "$_cfullchain" | tr -d '\n') + string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n') sslcert_path="/sslcert" sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$_cdomain\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}" @@ -63,12 +63,12 @@ qiniu_deploy() { _info "Certificate successfully uploaded, updating domain $_cdomain" ## extract certId - _certId=$(printf "%s" "$sslcert_response" | sed -e "s/^.*certID\":\"//" -e "s/\"\}$//") + _certId="$(printf "%s" "$sslcert_response" | _normalizeJson | _egrep_o "certID\":\s*\"[^\"]*\"" | cut -d : -f 2)" _debug certId "$_certId" ## update domain ssl config update_path="/domain/$_cdomain/httpsconf" - update_body="{\"certid\":\"$_certId\",\"forceHttps\":true}" + update_body="{\"certid\":$_certId,\"forceHttps\":true}" update_access_token="$(_make_sslcreate_access_token "$update_path")" _debug update_access_token "$update_access_token" export _H1="Authorization: QBox $update_access_token" From 0cd6afde6f586a3791952f07a3fe99c5f7e45ed3 Mon Sep 17 00:00:00 2001 From: shonenada Date: Sat, 12 Jan 2019 21:15:16 +0800 Subject: [PATCH 232/280] Add guidance to deploying cert to qiniu.com --- deploy/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index cec7d77..68c1a27 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -332,3 +332,19 @@ variable to anything (ex: "1") before running `acme.sh`: ```sh export FABIO="1" ``` + +## 13. Deploy your certificate to Qiniu.com + +You should create AccessKey/SecretKey pair in https://portal.qiniu.com/user/key before deploying +your certificate. + +```sh +$ export QINIU_AK="foo" +$ export QINIU_SK="bar" +``` + +then you can deploy certificate by following command: + +```sh +$ acme.sh --deploy -d example.com --deploy-hook qiniu +``` From 96efc8c7f025b6b862c9502abf44434fcd6b0693 Mon Sep 17 00:00:00 2001 From: shonenada Date: Sat, 12 Jan 2019 23:11:19 +0800 Subject: [PATCH 233/280] lint codes --- deploy/qiniu.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index 559e59c..e0be60f 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -52,8 +52,7 @@ qiniu_deploy() { export _H1="Authorization: QBox $sslcert_access_token" sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline") - success_response="certID" - if test "${sslcert_response#*$success_response}" == "$sslcert_response"; then + if ! _contains "$sslcert_response" "certID"; then _err "Error in creating certificate:" _err "$sslcert_response" return 1 @@ -63,7 +62,7 @@ qiniu_deploy() { _info "Certificate successfully uploaded, updating domain $_cdomain" ## extract certId - _certId="$(printf "%s" "$sslcert_response" | _normalizeJson | _egrep_o "certID\":\s*\"[^\"]*\"" | cut -d : -f 2)" + _certId="$(printf "%s" "$sslcert_response" | _normalizeJson | _egrep_o "certID\": *\"[^\"]*\"" | cut -d : -f 2)" _debug certId "$_certId" ## update domain ssl config @@ -74,8 +73,7 @@ qiniu_deploy() { export _H1="Authorization: QBox $update_access_token" update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline") - err_response="error" - if test "${update_response#*$err_response}" != "$update_response"; then + if _contains "$update_response" "error"; then _err "Error in updating domain httpsconf:" _err "$update_response" return 1 @@ -88,6 +86,6 @@ qiniu_deploy() { } _make_sslcreate_access_token() { - _token="$(printf "%s\\n" "$1" | _hmac "sha1" "$(printf "%s" "$Le_Deploy_Qiniu_SK" | _hex_dump | tr -d " ")" | _base64)" + _token="$(printf "%s\n" "$1" | _hmac "sha1" "$(printf "%s" "$Le_Deploy_Qiniu_SK" | _hex_dump | tr -d " ")" | _base64)" echo "$Le_Deploy_Qiniu_AK:$_token" } From 3c6b707353007d476e758932dfca1e7125e534b1 Mon Sep 17 00:00:00 2001 From: shonenada Date: Sun, 13 Jan 2019 12:23:15 +0800 Subject: [PATCH 234/280] add `QINIU_CDN_DOMAIN` for wildcard certificate --- deploy/README.md | 14 ++++++++++++-- deploy/qiniu.sh | 6 ++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 68c1a27..fa2d718 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -335,8 +335,9 @@ export FABIO="1" ## 13. Deploy your certificate to Qiniu.com -You should create AccessKey/SecretKey pair in https://portal.qiniu.com/user/key before deploying -your certificate. +You should create AccessKey/SecretKey pair in https://portal.qiniu.com/user/key +before deploying your certificate, and please ensure you have enabled HTTPS for +your domain name. You can enable it in https://portal.qiniu.com/cdn/domain. ```sh $ export QINIU_AK="foo" @@ -348,3 +349,12 @@ then you can deploy certificate by following command: ```sh $ acme.sh --deploy -d example.com --deploy-hook qiniu ``` + +(Optional), If you are using wildcard certificate, +you may need export `QINIU_CDN_DOMAIN` to specify which domain +you want to update: + +```sh +$ export QINIU_CDN_DOMAIN="cdn.example.com" +$ acme.sh --deploy -d example.com --deploy-hook qiniu +``` diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index e0be60f..dac1866 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -5,6 +5,7 @@ # This deployment required following variables # export QINIU_AK="QINIUACCESSKEY" # export QINIU_SK="QINIUSECRETKEY" +# export QINIU_CDN_DOMAIN="cdn.example.com" QINIU_API_BASE="https://api.qiniu.com" @@ -14,6 +15,7 @@ qiniu_deploy() { _ccert="$3" _cca="$4" _cfullchain="$5" + _cdndomain="${QINIU_CDN_DOMAIN:-$_cdomain}" _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" @@ -46,7 +48,7 @@ qiniu_deploy() { string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n') sslcert_path="/sslcert" - sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$_cdomain\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}" + sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$_cdndomain\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}" sslcert_access_token="$(_make_sslcreate_access_token "$sslcert_path")" _debug sslcert_access_token "$sslcert_access_token" export _H1="Authorization: QBox $sslcert_access_token" @@ -66,7 +68,7 @@ qiniu_deploy() { _debug certId "$_certId" ## update domain ssl config - update_path="/domain/$_cdomain/httpsconf" + update_path="/domain/$_cdndomain/httpsconf" update_body="{\"certid\":$_certId,\"forceHttps\":true}" update_access_token="$(_make_sslcreate_access_token "$update_path")" _debug update_access_token "$update_access_token" From 4c1fa9c2422143b164448b6e7c327bb293f808a8 Mon Sep 17 00:00:00 2001 From: shonenada Date: Mon, 14 Jan 2019 22:19:00 +0800 Subject: [PATCH 235/280] save CDN Domain with `_savedomainconf` --- deploy/qiniu.sh | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index dac1866..a97dfbb 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -15,7 +15,6 @@ qiniu_deploy() { _ccert="$3" _cca="$4" _cfullchain="$5" - _cdndomain="${QINIU_CDN_DOMAIN:-$_cdomain}" _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" @@ -43,13 +42,20 @@ qiniu_deploy() { _savedomainconf Le_Deploy_Qiniu_SK "$Le_Deploy_Qiniu_SK" fi + Le_Deploy_Qiniu_Cdn_Domain="${QINIU_CDN_DOMAIN:-$(_readdomainconf Le_Deploy_Qiniu_Cdn_Domain)}" + if [ -z "$Le_Deploy_Qiniu_Cdn_Domain" ]; then + Le_Deploy_Qiniu_Cdn_Domain="$_cdomain" + fi + + _savedomainconf Le_Deploy_Qiniu_Cdn_Domain "$Le_Deploy_Qiniu_Cdn_Domain" + ## upload certificate string_fullchain=$(sed 's/$/\\n/' "$_cfullchain" | tr -d '\n') string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n') sslcert_path="/sslcert" - sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$_cdndomain\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}" - sslcert_access_token="$(_make_sslcreate_access_token "$sslcert_path")" + sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$Le_Deploy_Qiniu_Cdn_Domain\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}" + sslcert_access_token="$(_make_access_token "$sslcert_path")" _debug sslcert_access_token "$sslcert_access_token" export _H1="Authorization: QBox $sslcert_access_token" sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline") @@ -68,9 +74,9 @@ qiniu_deploy() { _debug certId "$_certId" ## update domain ssl config - update_path="/domain/$_cdndomain/httpsconf" - update_body="{\"certid\":$_certId,\"forceHttps\":true}" - update_access_token="$(_make_sslcreate_access_token "$update_path")" + update_path="/domain/$Le_Deploy_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") @@ -87,7 +93,7 @@ qiniu_deploy() { return 0 } -_make_sslcreate_access_token() { +_make_access_token() { _token="$(printf "%s\n" "$1" | _hmac "sha1" "$(printf "%s" "$Le_Deploy_Qiniu_SK" | _hex_dump | tr -d " ")" | _base64)" echo "$Le_Deploy_Qiniu_AK:$_token" } From 10ba2cd312fb346a9af32a808ddbfa1d55b83879 Mon Sep 17 00:00:00 2001 From: jim-p Date: Thu, 10 Jan 2019 16:06:46 -0500 Subject: [PATCH 236/280] Use a literal space instead of an escaped space. Fixes #2022 --- dnsapi/dns_namecheap.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index a6651be..2f401bd 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -161,12 +161,12 @@ _namecheap_parse_host() { _host=$1 _debug _host "$_host" - _hostid=$(echo "$_host" | _egrep_o '\sHostId="[^"]*' | cut -d '"' -f 2) - _hostname=$(echo "$_host" | _egrep_o '\sName="[^"]*' | cut -d '"' -f 2) - _hosttype=$(echo "$_host" | _egrep_o '\sType="[^"]*' | cut -d '"' -f 2) - _hostaddress=$(echo "$_host" | _egrep_o '\sAddress="[^"]*' | cut -d '"' -f 2) - _hostmxpref=$(echo "$_host" | _egrep_o '\sMXPref="[^"]*' | cut -d '"' -f 2) - _hostttl=$(echo "$_host" | _egrep_o '\sTTL="[^"]*' | cut -d '"' -f 2) + _hostid=$(echo "$_host" | _egrep_o ' HostId="[^"]*' | cut -d '"' -f 2) + _hostname=$(echo "$_host" | _egrep_o ' Name="[^"]*' | cut -d '"' -f 2) + _hosttype=$(echo "$_host" | _egrep_o ' Type="[^"]*' | cut -d '"' -f 2) + _hostaddress=$(echo "$_host" | _egrep_o ' Address="[^"]*' | cut -d '"' -f 2) + _hostmxpref=$(echo "$_host" | _egrep_o ' MXPref="[^"]*' | cut -d '"' -f 2) + _hostttl=$(echo "$_host" | _egrep_o ' TTL="[^"]*' | cut -d '"' -f 2) _debug hostid "$_hostid" _debug hostname "$_hostname" From afdb9a63ffa4540dd8d3097492b8940b21b50907 Mon Sep 17 00:00:00 2001 From: shonenada Date: Sat, 19 Jan 2019 23:58:55 +0800 Subject: [PATCH 237/280] chore: replece `Le_Deploy_Qiniu_*` with `QINIU_*` --- deploy/qiniu.sh | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index a97dfbb..aadda53 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -23,38 +23,31 @@ qiniu_deploy() { _debug _cfullchain "$_cfullchain" if [ -z "$QINIU_AK" ]; then - if [ -z "$Le_Deploy_Qiniu_AK" ]; then - _err "QINIU_AK is not defined." - return 1 - fi + _err "QINIU_AK is not defined." + return 1 else - Le_Deploy_Qiniu_AK="$QINIU_AK" - _savedomainconf Le_Deploy_Qiniu_AK "$Le_Deploy_Qiniu_AK" + _savedomainconf QINIU_AK "$QINIU_AK" fi if [ -z "$QINIU_SK" ]; then - if [ -z "$Le_Deploy_Qiniu_SK" ]; then - _err "QINIU_SK is not defined." - return 1 - fi + _err "QINIU_SK is not defined." + return 1 else - Le_Deploy_Qiniu_SK="$QINIU_SK" - _savedomainconf Le_Deploy_Qiniu_SK "$Le_Deploy_Qiniu_SK" + _savedomainconf QINIU_SK "$QINIU_SK" fi - Le_Deploy_Qiniu_Cdn_Domain="${QINIU_CDN_DOMAIN:-$(_readdomainconf Le_Deploy_Qiniu_Cdn_Domain)}" - if [ -z "$Le_Deploy_Qiniu_Cdn_Domain" ]; then - Le_Deploy_Qiniu_Cdn_Domain="$_cdomain" + if [ -z "$QINIU_CDN_DOMAIN" ]; then + QINIU_CDN_DOMAIN="$_cdomain" fi - _savedomainconf Le_Deploy_Qiniu_Cdn_Domain "$Le_Deploy_Qiniu_Cdn_Domain" + _savedomainconf QINIU_CDN_DOMAIN "$QINIU_CDN_DOMAIN" ## upload certificate string_fullchain=$(sed 's/$/\\n/' "$_cfullchain" | tr -d '\n') string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n') sslcert_path="/sslcert" - sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$Le_Deploy_Qiniu_Cdn_Domain\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}" + sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$QINIU_CDN_DOMAIN\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}" sslcert_access_token="$(_make_access_token "$sslcert_path")" _debug sslcert_access_token "$sslcert_access_token" export _H1="Authorization: QBox $sslcert_access_token" @@ -74,7 +67,7 @@ qiniu_deploy() { _debug certId "$_certId" ## update domain ssl config - update_path="/domain/$Le_Deploy_Qiniu_Cdn_Domain/httpsconf" + 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" @@ -94,6 +87,6 @@ qiniu_deploy() { } _make_access_token() { - _token="$(printf "%s\n" "$1" | _hmac "sha1" "$(printf "%s" "$Le_Deploy_Qiniu_SK" | _hex_dump | tr -d " ")" | _base64)" - echo "$Le_Deploy_Qiniu_AK:$_token" + _token="$(printf "%s\n" "$1" | _hmac "sha1" "$(printf "%s" "$QINIU_SK" | _hex_dump | tr -d " ")" | _base64)" + echo "$QINIU_AK:$_token" } From dd6fa4af0075248585202eab93ac89f51b652c0e Mon Sep 17 00:00:00 2001 From: shonenada Date: Sun, 20 Jan 2019 23:58:10 +0800 Subject: [PATCH 238/280] Save `QINIU_CDN_DOMAIN` only when defined --- deploy/qiniu.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index aadda53..8410caa 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -36,12 +36,12 @@ qiniu_deploy() { _savedomainconf QINIU_SK "$QINIU_SK" fi - if [ -z "$QINIU_CDN_DOMAIN" ]; then - QINIU_CDN_DOMAIN="$_cdomain" + if [ "$QINIU_CDN_DOMAIN" ]; then + _savedomainconf QINIU_CDN_DOMAIN "$QINIU_CDN_DOMAIN" + else + QINIU_CDN_DOMAIN="$_cdomain" fi - _savedomainconf QINIU_CDN_DOMAIN "$QINIU_CDN_DOMAIN" - ## upload certificate string_fullchain=$(sed 's/$/\\n/' "$_cfullchain" | tr -d '\n') string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n') From e8eec2cb41b34bf52fff36647a4861bec23fa653 Mon Sep 17 00:00:00 2001 From: shonenada Date: Mon, 21 Jan 2019 00:08:23 +0800 Subject: [PATCH 239/280] add chinese readme --- deploy/README.md | 2 ++ deploy/README_zh.md | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 deploy/README_zh.md diff --git a/deploy/README.md b/deploy/README.md index fa2d718..a9e28e9 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -335,6 +335,8 @@ export FABIO="1" ## 13. Deploy your certificate to Qiniu.com +[中文文档](https://github.com/Neilpang/acme.sh/blob/master/deploy/README_zh.md#13-%E9%83%A8%E7%BD%B2%E5%88%B0%E4%B8%83%E7%89%9B%E5%9F%9F%E5%90%8D%E8%AF%81%E4%B9%A6%E6%9C%8D%E5%8A%A1) + You should create AccessKey/SecretKey pair in https://portal.qiniu.com/user/key before deploying your certificate, and please ensure you have enabled HTTPS for your domain name. You can enable it in https://portal.qiniu.com/cdn/domain. diff --git a/deploy/README_zh.md b/deploy/README_zh.md new file mode 100644 index 0000000..4132dce --- /dev/null +++ b/deploy/README_zh.md @@ -0,0 +1,24 @@ +# Deploy 使用文档 + +## 13. 部署到七牛域名证书服务 + +使用 acme.sh 部署到七牛之前,需要确保部署的域名已打开 HTTPS 功能,您可以访问[融合 CDN - 域名管理](https://portal.qiniu.com/cdn/domain) 设置。 +另外还需要先导出 AK/SK 环境变量,您可以访问[密钥管理](https://portal.qiniu.com/user/key) 获得。 + +```sh +$ export QINIU_AK="foo" +$ export QINIU_SK="bar" +``` + +完成准备工作之后,您就可以通过下面的命令开始部署 SSL 证书到七牛上: + +```sh +$ acme.sh --deploy -d example.com --deploy-hook qiniu +``` + +假如您部署的证书为泛域名证书,您还需要设置 `QINIU_CDN_DOMAIN` 变量,指定实际需要部署的域名: + +```sh +$ export QINIU_CDN_DOMAIN="cdn.example.com" +$ acme.sh --deploy -d example.com --deploy-hook qiniu +``` From c445e70cffe326219b8d597867ba28ae85523ba1 Mon Sep 17 00:00:00 2001 From: shonenada Date: Mon, 21 Jan 2019 14:33:15 +0800 Subject: [PATCH 240/280] fix indent --- deploy/qiniu.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index 8410caa..158b8db 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -37,9 +37,9 @@ qiniu_deploy() { fi if [ "$QINIU_CDN_DOMAIN" ]; then - _savedomainconf QINIU_CDN_DOMAIN "$QINIU_CDN_DOMAIN" + _savedomainconf QINIU_CDN_DOMAIN "$QINIU_CDN_DOMAIN" else - QINIU_CDN_DOMAIN="$_cdomain" + QINIU_CDN_DOMAIN="$_cdomain" fi ## upload certificate From a4a53e1355503efa8a550f954f59cc3a2b763935 Mon Sep 17 00:00:00 2001 From: shonenada Date: Mon, 21 Jan 2019 17:31:21 +0800 Subject: [PATCH 241/280] Move docs into README.md from README_zh.md --- deploy/README.md | 23 ++++++++++++++++++++++- deploy/README_zh.md | 24 ------------------------ 2 files changed, 22 insertions(+), 25 deletions(-) delete mode 100644 deploy/README_zh.md diff --git a/deploy/README.md b/deploy/README.md index a9e28e9..091e9fe 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -335,7 +335,28 @@ export FABIO="1" ## 13. Deploy your certificate to Qiniu.com -[中文文档](https://github.com/Neilpang/acme.sh/blob/master/deploy/README_zh.md#13-%E9%83%A8%E7%BD%B2%E5%88%B0%E4%B8%83%E7%89%9B%E5%9F%9F%E5%90%8D%E8%AF%81%E4%B9%A6%E6%9C%8D%E5%8A%A1) +使用 acme.sh 部署到七牛之前,需要确保部署的域名已打开 HTTPS 功能,您可以访问[融合 CDN - 域名管理](https://portal.qiniu.com/cdn/domain) 设置。 +另外还需要先导出 AK/SK 环境变量,您可以访问[密钥管理](https://portal.qiniu.com/user/key) 获得。 + +```sh +$ export QINIU_AK="foo" +$ export QINIU_SK="bar" +``` + +完成准备工作之后,您就可以通过下面的命令开始部署 SSL 证书到七牛上: + +```sh +$ acme.sh --deploy -d example.com --deploy-hook qiniu +``` + +假如您部署的证书为泛域名证书,您还需要设置 `QINIU_CDN_DOMAIN` 变量,指定实际需要部署的域名: + +```sh +$ export QINIU_CDN_DOMAIN="cdn.example.com" +$ acme.sh --deploy -d example.com --deploy-hook qiniu +``` + +### English version You should create AccessKey/SecretKey pair in https://portal.qiniu.com/user/key before deploying your certificate, and please ensure you have enabled HTTPS for diff --git a/deploy/README_zh.md b/deploy/README_zh.md deleted file mode 100644 index 4132dce..0000000 --- a/deploy/README_zh.md +++ /dev/null @@ -1,24 +0,0 @@ -# Deploy 使用文档 - -## 13. 部署到七牛域名证书服务 - -使用 acme.sh 部署到七牛之前,需要确保部署的域名已打开 HTTPS 功能,您可以访问[融合 CDN - 域名管理](https://portal.qiniu.com/cdn/domain) 设置。 -另外还需要先导出 AK/SK 环境变量,您可以访问[密钥管理](https://portal.qiniu.com/user/key) 获得。 - -```sh -$ export QINIU_AK="foo" -$ export QINIU_SK="bar" -``` - -完成准备工作之后,您就可以通过下面的命令开始部署 SSL 证书到七牛上: - -```sh -$ acme.sh --deploy -d example.com --deploy-hook qiniu -``` - -假如您部署的证书为泛域名证书,您还需要设置 `QINIU_CDN_DOMAIN` 变量,指定实际需要部署的域名: - -```sh -$ export QINIU_CDN_DOMAIN="cdn.example.com" -$ acme.sh --deploy -d example.com --deploy-hook qiniu -``` From 56d70e4ea74d2c1274326ec0ac9c93657d9b4e94 Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Mon, 21 Jan 2019 15:02:09 +0100 Subject: [PATCH 242/280] Update to latest API Changes --- dnsapi/dns_hostingde.sh | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index 74a472d..7c18511 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -59,9 +59,22 @@ _hostingde_getZoneConfig() { if _contains "${curResult}" '"totalEntries": 1'; then _info "Retrieved zone data." _debug "Zone data: '${curResult}'" - - # read ZoneConfigId for later update zoneConfigId=$(echo "${curResult}" | _egrep_o '"id":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + zoneConfigName=$(echo "${curResult}" | _egrep_o '"name":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + zoneConfigType=$(echo "${curResult}" | grep -v "FindZoneConfigsResult" | _egrep_o '"type":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + zoneConfigExpire=$(echo "${curResult}" | _egrep_o '"expire":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1) + zoneConfigNegativeTtl=$(echo "${curResult}" | _egrep_o '"negativeTtl":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1) + zoneConfigRefresh=$(echo "${curResult}" | _egrep_o '"refresh":.*' | cut -d ':' -f 2 | cut -d '"' -f 2| cut -d ',' -f 1) + zoneConfigRetry=$(echo "${curResult}" | _egrep_o '"retry":.*' | cut -d ':' -f 2 | cut -d '"' -f 2| cut -d ',' -f 1) + zoneConfigTtl=$(echo "${curResult}" | _egrep_o '"ttl":.*' | cut -d ':' -f 2 | cut -d '"' -f 2| cut -d ',' -f 1) + zoneConfigDnsServerGroupId=$(echo "${curResult}" | _egrep_o '"dnsServerGroupId":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + zoneConfigEmailAddress=$(echo "${curResult}" | _egrep_o '"emailAddress":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + zoneConfigDnsSecMode=$(echo "${curResult}" | _egrep_o '"dnsSecMode":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + if [ $zoneConfigType != "NATIVE" ]; then + _err "Zone is not native" + returnCode=1 + break + fi _debug "zoneConfigId '${zoneConfigId}'" returnCode=0 break @@ -94,7 +107,7 @@ _hostingde_addRecord() { _hostingde_getZoneStatus _debug "Result of zoneStatus: '${zoneStatus}'" done - curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\"},\"recordsToAdd\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\",\"ttl\":3600}]}" + curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\",\"name\":\"${zoneConfigName}\",\"type\":\"${zoneConfigType}\",\"dnsServerGroupId\":\"${zoneConfigDnsServerGroupId}\",\"dnsSecMode\":\"${zoneConfigDnsSecMode}\",\"emailAddress\":\"${zoneConfigEmailAddress}\",\"soaValues\":{\"expire\":${zoneConfigExpire},\"negativeTtl\":${zoneConfigNegativeTtl},\"refresh\":${zoneConfigRefresh},\"retry\":${zoneConfigRetry},\"ttl\":${zoneConfigTtl}}},\"recordsToAdd\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\",\"ttl\":3600}]}" curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")" _debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'" _debug "Result of zoneUpdate: '$curResult'" @@ -118,7 +131,7 @@ _hostingde_removeRecord() { _hostingde_getZoneStatus _debug "Result of zoneStatus: '$zoneStatus'" done - curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\"},\"recordsToDelete\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\"}]}" + curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\",\"name\":\"${zoneConfigName}\",\"type\":\"${zoneConfigType}\",\"dnsServerGroupId\":\"${zoneConfigDnsServerGroupId}\",\"dnsSecMode\":\"${zoneConfigDnsSecMode}\",\"emailAddress\":\"${zoneConfigEmailAddress}\",\"soaValues\":{\"expire\":${zoneConfigExpire},\"negativeTtl\":${zoneConfigNegativeTtl},\"refresh\":${zoneConfigRefresh},\"retry\":${zoneConfigRetry},\"ttl\":${zoneConfigTtl}}},\"recordsToDelete\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\"}]}" curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")" _debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'" _debug "Result of zoneUpdate: '$curResult'" From b15c1ffedcd1d627e6339396179e7691ca83938e Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 21 Jan 2019 22:09:13 +0800 Subject: [PATCH 243/280] clean TXT records when error happens. https://github.com/Neilpang/acme.sh/issues/2037 --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index ff47286..697a14a 100755 --- a/acme.sh +++ b/acme.sh @@ -2921,7 +2921,10 @@ _clearup() { _clearupdns() { _debug "_clearupdns" - if [ "$dnsadded" != 1 ] || [ -z "$vlist" ]; then + _debug "dnsadded" "$dnsadded" + _debug "vlist" "$vlist" + #dnsadded is "0" or "1" means dns-01 method was used for at least one domain + if [ -z "$dnsadded" ] || [ -z "$vlist" ]; then _debug "skip dns." return fi From 545f23551f09082799f02a159ed6ade2aa4eb36f Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 21 Jan 2019 22:25:23 +0800 Subject: [PATCH 244/280] trigger validation before cleanup fix https://github.com/Neilpang/acme.sh/issues/2037 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 697a14a..d651c4f 100755 --- a/acme.sh +++ b/acme.sh @@ -3857,8 +3857,8 @@ $_authorizations_map" ) if [ "$?" != "0" ]; then - _clearup _on_issue_err "$_post_hook" "$vlist" + _clearup return 1 fi dnsadded='1' @@ -3869,8 +3869,8 @@ $_authorizations_map" _savedomainconf "Le_Vlist" "$vlist" _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and re-run with --renew." - _clearup _on_issue_err "$_post_hook" + _clearup return 1 fi From 2dc50e66330c291fafee95d1b8d7183e413df647 Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Mon, 21 Jan 2019 15:45:32 +0100 Subject: [PATCH 245/280] making shfmt happy --- dnsapi/dns_hostingde.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index 7c18511..7f29d62 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -64,9 +64,9 @@ _hostingde_getZoneConfig() { zoneConfigType=$(echo "${curResult}" | grep -v "FindZoneConfigsResult" | _egrep_o '"type":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) zoneConfigExpire=$(echo "${curResult}" | _egrep_o '"expire":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1) zoneConfigNegativeTtl=$(echo "${curResult}" | _egrep_o '"negativeTtl":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1) - zoneConfigRefresh=$(echo "${curResult}" | _egrep_o '"refresh":.*' | cut -d ':' -f 2 | cut -d '"' -f 2| cut -d ',' -f 1) - zoneConfigRetry=$(echo "${curResult}" | _egrep_o '"retry":.*' | cut -d ':' -f 2 | cut -d '"' -f 2| cut -d ',' -f 1) - zoneConfigTtl=$(echo "${curResult}" | _egrep_o '"ttl":.*' | cut -d ':' -f 2 | cut -d '"' -f 2| cut -d ',' -f 1) + zoneConfigRefresh=$(echo "${curResult}" | _egrep_o '"refresh":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1) + zoneConfigRetry=$(echo "${curResult}" | _egrep_o '"retry":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1) + zoneConfigTtl=$(echo "${curResult}" | _egrep_o '"ttl":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1) zoneConfigDnsServerGroupId=$(echo "${curResult}" | _egrep_o '"dnsServerGroupId":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) zoneConfigEmailAddress=$(echo "${curResult}" | _egrep_o '"emailAddress":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) zoneConfigDnsSecMode=$(echo "${curResult}" | _egrep_o '"dnsSecMode":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) From b0775f7a580ac534ad2443cd9308fab5b339749f Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Mon, 21 Jan 2019 16:32:45 +0100 Subject: [PATCH 246/280] making shftm really happy --- dnsapi/dns_hostingde.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index 7f29d62..b61acb7 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -70,7 +70,7 @@ _hostingde_getZoneConfig() { zoneConfigDnsServerGroupId=$(echo "${curResult}" | _egrep_o '"dnsServerGroupId":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) zoneConfigEmailAddress=$(echo "${curResult}" | _egrep_o '"emailAddress":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) zoneConfigDnsSecMode=$(echo "${curResult}" | _egrep_o '"dnsSecMode":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) - if [ $zoneConfigType != "NATIVE" ]; then + if [ "${zoneConfigType}" != "NATIVE" ]; then _err "Zone is not native" returnCode=1 break From 572adbaad2c8531870753c18c2b313c70faa9a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20P=C3=A1la?= Date: Mon, 31 Dec 2018 20:05:08 +0100 Subject: [PATCH 247/280] Add support for Active24.cz --- README.md | 1 + dnsapi/README.md | 18 ++++++ dnsapi/dns_active24.sh | 141 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100755 dnsapi/dns_active24.sh diff --git a/README.md b/README.md index 41ffb69..70abcc6 100644 --- a/README.md +++ b/README.md @@ -349,6 +349,7 @@ You don't have to do anything manually! 1. Neodigit.net API (https://www.neodigit.net) 1. Exoscale.com API (https://www.exoscale.com/) 1. PointDNS API (https://pointhq.com/) +1. Active24.cz API (https://www.active24.cz/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index fc65748..0a9c492 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1139,6 +1139,24 @@ You can then issue certs by using: ```acme.sh --issue --dns dns_pointhq -d example.com -d www.example.com ``` +## 59. Use Active24 API + +Create an API token in the Active24 account section, documentation on https://faq.active24.com/cz/790131-REST-API-rozhran%C3%AD. + +Set your API token: + +``` +export ACTIVE24_Token='xxx' +``` + +Now, let's issue a cert, set `dnssleep` for propagation new DNS record: +``` +acme.sh --issue --dns dns_active24 -d example.com -d www.example.com --dnssleep 1000 +``` + +The `ACTIVE24_Token` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_active24.sh b/dnsapi/dns_active24.sh new file mode 100755 index 0000000..90ffaf6 --- /dev/null +++ b/dnsapi/dns_active24.sh @@ -0,0 +1,141 @@ +#!/usr/bin/env sh + +#ACTIVE24_Token="sdfsdfsdfljlbjkljlkjsdfoiwje" + +ACTIVE24_Api="https://api.active24.com" + +######## Public functions ##################### + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_active24_add() { + fulldomain=$1 + txtvalue=$2 + + _active24_init + + _info "Adding txt record" + if _active24_rest POST "dns/$_domain/txt/v1" "{\"name\":\"$_sub_domain\",\"text\":\"$txtvalue\",\"ttl\":0}"; then + if _contains "$response" "errors"; then + _err "Add txt record error." + return 1 + else + _info "Added, OK" + return 0 + fi + fi + _err "Add txt record error." + return 1 +} + +# Usage: fulldomain txtvalue +# Used to remove the txt record after validation +dns_active24_rm() { + fulldomain=$1 + txtvalue=$2 + + _active24_init + + _debug "Getting txt records" + _active24_rest GET "dns/$_domain/records/v1" + + if _contains "$response" "errors"; then + _err "Error" + return 1 + fi + + hash_ids=$(echo "$response" | _egrep_o "[^{]+${txtvalue}[^}]+" | _egrep_o "hashId\":\"[^\"]+" | cut -c10-) + + for hash_id in $hash_ids; do + _debug "Removing hash_id" "$hash_id" + if _active24_rest DELETE "dns/$_domain/$hash_id/v1" ""; then + if _contains "$response" "errors"; then + _err "Unable to remove txt record." + return 1 + else + _info "Removed txt record." + return 0 + fi + fi + done + + _err "No txt records found." + return 1 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + + if ! _active24_rest GET "dns/domains/v1"; then + return 1 + fi + + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug "h" "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"$h\"" >/dev/null; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_active24_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Authorization: Bearer $ACTIVE24_Token" + + if [ "$m" != "GET" ]; then + _debug "data" "$data" + response="$(_post "$data" "$ACTIVE24_Api/$ep" "" "$m" "application/json")" + else + response="$(_get "$ACTIVE24_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + +_active24_init() { + ACTIVE24_Token="${ACTIVE24_Token:-$(_readaccountconf_mutable ACTIVE24_Token)}" + if [ -z "$ACTIVE24_Token" ]; then + ACTIVE24_Token="" + _err "You didn't specify a Active24 api token yet." + _err "Please create the token and try again." + return 1 + fi + + _saveaccountconf_mutable ACTIVE24_Token "ACTIVE24_Token" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" +} From 127532c226149b991814bd696b1362b079fa8c2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20M=C3=A4del?= Date: Thu, 24 Jan 2019 16:53:03 +0100 Subject: [PATCH 248/280] Added dns_doapi.sh --- dnsapi/dns_doapi.sh | 59 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100755 dnsapi/dns_doapi.sh diff --git a/dnsapi/dns_doapi.sh b/dnsapi/dns_doapi.sh new file mode 100755 index 0000000..f3d56b6 --- /dev/null +++ b/dnsapi/dns_doapi.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env sh + +# Official Let's Encrypt API for do.de / Domain-Offensive +# +# This is different from the dns_do adapter, because dns_do is only usable for enterprise customers +# This API is also available to private customers/individuals +# +# Provide the required LetsEncrypt token like this: +# DO_LETOKEN="FmD408PdqT1E269gUK57" + +DO_API="https://www.do.de/api/letsencrypt" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_doapi_add() { + fulldomain=$1 + txtvalue=$2 + + DO_LETOKEN="${DO_LETOKEN:-$(_readaccountconf_mutable DO_LETOKEN)}" + if [ -z "$DO_LETOKEN" ]; then + DO_LETOKEN="" + _err "You didn't configure a do.de API token yet." + _err "Please set DO_LETOKEN and try again." + return 1 + fi + _saveaccountconf_mutable DO_LETOKEN "$DO_LETOKEN" + + _info "Adding TXT record to ${_domain} as ${fulldomain}" + response="$(_get "$DO_API?token=$DO_LETOKEN&domain=${fulldomain}&value=${txtvalue}")" + if _contains "${response}" 'success'; then + return 0 + fi + _err "Could not create resource record, check logs" + _err $response + return 1 +} + +dns_doapi_rm() { + fulldomain=$1 + + DO_LETOKEN="${DO_LETOKEN:-$(_readaccountconf_mutable DO_LETOKEN)}" + if [ -z "$DO_LETOKEN" ]; then + DO_LETOKEN="" + _err "You didn't configure a do.de API token yet." + _err "Please set DO_LETOKEN and try again." + return 1 + fi + _saveaccountconf_mutable DO_LETOKEN "$DO_LETOKEN" + + _info "Deleting resource record $fulldomain" + response="$(_get "$DO_API?token=$DO_LETOKEN&domain=${fulldomain}&action=delete")" + if _contains "${response}" 'success'; then + return 0 + fi + _err "Could not delete resource record, check logs" + _err $response + return 1 +} From ddf77f10e95e6daf22b99a7e5986912d58ff4b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20M=C3=A4del?= Date: Thu, 24 Jan 2019 16:59:36 +0100 Subject: [PATCH 249/280] Cleaned up dns_doapi.sh --- dnsapi/dns_doapi.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_doapi.sh b/dnsapi/dns_doapi.sh index f3d56b6..fa2b7d3 100755 --- a/dnsapi/dns_doapi.sh +++ b/dnsapi/dns_doapi.sh @@ -26,13 +26,13 @@ dns_doapi_add() { fi _saveaccountconf_mutable DO_LETOKEN "$DO_LETOKEN" - _info "Adding TXT record to ${_domain} as ${fulldomain}" + _info "Adding TXT record to ${fulldomain}" response="$(_get "$DO_API?token=$DO_LETOKEN&domain=${fulldomain}&value=${txtvalue}")" if _contains "${response}" 'success'; then return 0 fi _err "Could not create resource record, check logs" - _err $response + _err "${response}" return 1 } @@ -54,6 +54,6 @@ dns_doapi_rm() { return 0 fi _err "Could not delete resource record, check logs" - _err $response + _err "${response}" return 1 } From 5f9b57d3004831cbd0e4455c0676633c56b5f708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20M=C3=A4del?= Date: Thu, 24 Jan 2019 17:00:37 +0100 Subject: [PATCH 250/280] Cleaned up dns_doapi.sh --- dnsapi/dns_doapi.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_doapi.sh b/dnsapi/dns_doapi.sh index fa2b7d3..135f0b0 100755 --- a/dnsapi/dns_doapi.sh +++ b/dnsapi/dns_doapi.sh @@ -24,7 +24,7 @@ dns_doapi_add() { _err "Please set DO_LETOKEN and try again." return 1 fi - _saveaccountconf_mutable DO_LETOKEN "$DO_LETOKEN" + _saveaccountconf_mutable DO_LETOKEN "$DO_LETOKEN" _info "Adding TXT record to ${fulldomain}" response="$(_get "$DO_API?token=$DO_LETOKEN&domain=${fulldomain}&value=${txtvalue}")" @@ -46,7 +46,7 @@ dns_doapi_rm() { _err "Please set DO_LETOKEN and try again." return 1 fi - _saveaccountconf_mutable DO_LETOKEN "$DO_LETOKEN" + _saveaccountconf_mutable DO_LETOKEN "$DO_LETOKEN" _info "Deleting resource record $fulldomain" response="$(_get "$DO_API?token=$DO_LETOKEN&domain=${fulldomain}&action=delete")" From e2f1338f941dfca192ebc51c1cb65bb09bf8f6d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20M=C3=A4del?= Date: Thu, 24 Jan 2019 17:05:01 +0100 Subject: [PATCH 251/280] Added documentation --- dnsapi/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index fc65748..e0532bc 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1139,6 +1139,22 @@ You can then issue certs by using: ```acme.sh --issue --dns dns_pointhq -d example.com -d www.example.com ``` +## 59. Use do.de API + +Create an API token in your do.de account. + +Set your API token: +``` +export DO_LETOKEN='FmD408PdqT1E269gUK57' +``` + +To issue a certificate run: +``` +acme.sh --issue --dns dns_doapi -d example.com -d *.example.com +``` + +The API token will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. From c1ec2afeca11ad8afdb8feec5e6e3bba1bf113da Mon Sep 17 00:00:00 2001 From: Grant Millar Date: Fri, 25 Jan 2019 09:27:30 +0000 Subject: [PATCH 252/280] Changed records per page to 5000 --- dnsapi/dns_dnsimple.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index b2cba58..d831eb2 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -152,7 +152,7 @@ _get_records() { sub_domain=$3 _debug "fetching txt records" - _dnsimple_rest GET "$account_id/zones/$domain/records?per_page=100&sort=id:desc" + _dnsimple_rest GET "$account_id/zones/$domain/records?per_page=5000&sort=id:desc" if ! _contains "$response" "\"id\":"; then _err "failed to retrieve records" From 75fe022f96dce0baeaef6f8fe9c206f8ab094d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20M=C3=A4del?= Date: Fri, 25 Jan 2019 15:26:41 +0100 Subject: [PATCH 253/280] Changed order in readme, added do.de --- README.md | 1 + dnsapi/README.md | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 70abcc6..90a648d 100644 --- a/README.md +++ b/README.md @@ -350,6 +350,7 @@ You don't have to do anything manually! 1. Exoscale.com API (https://www.exoscale.com/) 1. PointDNS API (https://pointhq.com/) 1. Active24.cz API (https://www.active24.cz/) +1. do.de API (https://www.do.de/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index dc20ac9..4f9b410 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1139,38 +1139,38 @@ You can then issue certs by using: ```acme.sh --issue --dns dns_pointhq -d example.com -d www.example.com ``` -## 59. Use do.de API +## 59. Use Active24 API -Create an API token in your do.de account. +Create an API token in the Active24 account section, documentation on https://faq.active24.com/cz/790131-REST-API-rozhran%C3%AD. Set your API token: + ``` -export DO_LETOKEN='FmD408PdqT1E269gUK57' +export ACTIVE24_Token='xxx' ``` -To issue a certificate run: +Now, let's issue a cert, set `dnssleep` for propagation new DNS record: ``` -acme.sh --issue --dns dns_doapi -d example.com -d *.example.com +acme.sh --issue --dns dns_active24 -d example.com -d www.example.com --dnssleep 1000 ``` -The API token will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +The `ACTIVE24_Token` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 60. Use Active24 API +## 60. Use do.de API -Create an API token in the Active24 account section, documentation on https://faq.active24.com/cz/790131-REST-API-rozhran%C3%AD. +Create an API token in your do.de account. Set your API token: - ``` -export ACTIVE24_Token='xxx' +export DO_LETOKEN='FmD408PdqT1E269gUK57' ``` -Now, let's issue a cert, set `dnssleep` for propagation new DNS record: +To issue a certificate run: ``` -acme.sh --issue --dns dns_active24 -d example.com -d www.example.com --dnssleep 1000 +acme.sh --issue --dns dns_doapi -d example.com -d *.example.com ``` -The `ACTIVE24_Token` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +The API token will be saved in `~/.acme.sh/account.conf` and will be reused when needed. # Use custom API From 36335984629d07d7c048981cea921bce60e37dbf Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 25 Jan 2019 22:39:22 +0800 Subject: [PATCH 254/280] Lets start 2.8.1 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d651c4f..85c17f1 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.8.0 +VER=2.8.1 PROJECT_NAME="acme.sh" From 43ff787b04b56fb1b8cf73857351c8fbad1c382e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 26 Jan 2019 18:32:11 +0800 Subject: [PATCH 255/280] remove tls-sni --- acme.sh | 44 ++------------------------------------------ 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/acme.sh b/acme.sh index 85c17f1..cfdf571 100755 --- a/acme.sh +++ b/acme.sh @@ -35,7 +35,6 @@ _OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" -VTYPE_TLS="tls-sni-01" VTYPE_ALPN="tls-alpn-01" LOCAL_ANY_ADDRESS="0.0.0.0" @@ -46,7 +45,6 @@ DEFAULT_DNS_SLEEP=120 NO_VALUE="no" -W_TLS="tls" W_DNS="dns" W_ALPN="alpn" DNS_ALIAS_PREFIX="=" @@ -3080,8 +3078,8 @@ _on_before_issue() { _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" fi _checkport="$Le_HTTPPort" - elif [ "$_currentRoot" = "$W_TLS" ] || [ "$_currentRoot" = "$W_ALPN" ]; then - _info "Standalone tls/alpn mode." + elif [ "$_currentRoot" = "$W_ALPN" ]; then + _info "Standalone alpn mode." if [ -z "$Le_TLSPort" ]; then Le_TLSPort=443 else @@ -3701,10 +3699,6 @@ $_authorizations_map" vtype="$VTYPE_DNS" fi - if [ "$_currentRoot" = "$W_TLS" ]; then - vtype="$VTYPE_TLS" - fi - if [ "$_currentRoot" = "$W_ALPN" ]; then vtype="$VTYPE_ALPN" fi @@ -3988,40 +3982,6 @@ $_authorizations_map" fi fi - - elif [ "$vtype" = "$VTYPE_TLS" ]; then - #create A - #_hash_A="$(printf "%s" $token | _digest "sha256" "hex" )" - #_debug2 _hash_A "$_hash_A" - #_x="$(echo $_hash_A | cut -c 1-32)" - #_debug2 _x "$_x" - #_y="$(echo $_hash_A | cut -c 33-64)" - #_debug2 _y "$_y" - #_SAN_A="$_x.$_y.token.acme.invalid" - #_debug2 _SAN_A "$_SAN_A" - - #create B - _hash_B="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")" - _debug2 _hash_B "$_hash_B" - _x="$(echo "$_hash_B" | cut -c 1-32)" - _debug2 _x "$_x" - _y="$(echo "$_hash_B" | cut -c 33-64)" - _debug2 _y "$_y" - - #_SAN_B="$_x.$_y.ka.acme.invalid" - - _SAN_B="$_x.$_y.acme.invalid" - _debug2 _SAN_B "$_SAN_B" - - _ncaddr="$(_getfield "$_local_addr" "$_ncIndex")" - _ncIndex="$(_math "$_ncIndex" + 1)" - if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" "$_ncaddr"; then - _err "Start tls server error." - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 - fi elif [ "$vtype" = "$VTYPE_ALPN" ]; then acmevalidationv1="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")" _debug acmevalidationv1 "$acmevalidationv1" From cc6159b39b5305778e1f437fcbe2673a3012cb13 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 26 Jan 2019 19:15:13 +0800 Subject: [PATCH 256/280] urlencode the existing txt record value fix https://github.com/Neilpang/acme.sh/issues/2052 --- dnsapi/dns_namecheap.sh | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index 2f401bd..27eda3a 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -3,16 +3,15 @@ # Namecheap API # https://www.namecheap.com/support/api/intro.aspx # -# Requires Namecheap API key set in NAMECHEAP_API_KEY, NAMECHEAP_SOURCEIP and NAMECHEAP_USERNAME set as environment variable +# Requires Namecheap API key set in +#NAMECHEAP_API_KEY, +#NAMECHEAP_USERNAME, +#NAMECHEAP_SOURCEIP # Due to Namecheap's API limitation all the records of your domain will be read and re applied, make sure to have a backup of your records you could apply if any issue would arise. ######## Public functions ##################### -if [ "$STAGE" -eq 1 ]; then - NAMECHEAP_API="https://api.sandbox.namecheap.com/xml.response" -else - NAMECHEAP_API="https://api.namecheap.com/xml.response" -fi +NAMECHEAP_API="https://api.namecheap.com/xml.response" #Usage: dns_namecheap_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_namecheap_add() { @@ -144,7 +143,7 @@ _namecheap_set_publicip() { _namecheap_post() { command=$1 data="ApiUser=${NAMECHEAP_USERNAME}&ApiKey=${NAMECHEAP_API_KEY}&ClientIp=${_publicip}&UserName=${NAMECHEAP_USERNAME}&Command=${command}" - + _debug2 "_namecheap_post data" "$data" response="$(_post "$data" "$NAMECHEAP_API" "" "POST")" _debug2 response "$response" @@ -224,6 +223,12 @@ _set_namecheap_TXT() { while read -r host; do if _contains "$host" " Date: Sat, 26 Jan 2019 20:27:53 +0800 Subject: [PATCH 257/280] fix rm method to urlencode the existing txt records. fix https://github.com/Neilpang/acme.sh/issues/2052 --- dnsapi/dns_namecheap.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index 27eda3a..fbf93c3 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -283,6 +283,7 @@ _del_namecheap_TXT() { _debug "TXT entry found" found=1 else + _hostaddress="$(printf "%s" "$_hostaddress" | _url_encode)" _namecheap_add_host "$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl" fi fi From a96464680361dde97e1388b81de275756612ba83 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 28 Jan 2019 19:11:45 +0800 Subject: [PATCH 258/280] fix https://github.com/Neilpang/acme.sh/issues/1364#issuecomment-458035330 --- dnsapi/dns_dp.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 3cc720a..6bbf149 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -63,7 +63,7 @@ dns_dp_rm() { return 0 fi - record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'"$txtvalue"'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \") + record_id=$(echo "$response" | tr "{" "\n" | grep "$txtvalue" | grep '^"id"' | cut -d : -f 2 | cut -d '"' -f 2) _debug record_id "$record_id" if [ -z "$record_id" ]; then _err "Can not get record id." From 227547f8263a87d9241a8f0a5de84ded1c6aa3d3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 30 Jan 2019 20:13:23 +0800 Subject: [PATCH 259/280] fix https://github.com/Neilpang/acme.sh/pull/1979 --- dnsapi/dns_linode_v4.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_linode_v4.sh b/dnsapi/dns_linode_v4.sh index dfa1a65..c9a83c7 100755 --- a/dnsapi/dns_linode_v4.sh +++ b/dnsapi/dns_linode_v4.sh @@ -8,7 +8,7 @@ LINODE_V4_API_URL="https://api.linode.com/v4/domains" ######## Public functions ##################### #Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_linode_add() { +dns_linode_v4_add() { fulldomain="${1}" txtvalue="${2}" @@ -51,7 +51,7 @@ dns_linode_add() { } #Usage: dns_linode_rm _acme-challenge.www.domain.com -dns_linode_rm() { +dns_linode_v4_rm() { fulldomain="${1}" if ! _Linode_API; then From 759b75ca482db36b6862dc5ba181c4230893deb7 Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Mon, 4 Feb 2019 11:27:04 +0100 Subject: [PATCH 260/280] better parsing of json responses fixes an error if customer does not have access to dns-groups --- dnsapi/dns_hostingde.sh | 50 ++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index b61acb7..4a7a214 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -13,6 +13,7 @@ dns_hostingde_add() { txtvalue="${2}" _debug "Calling: _hostingde_addRecord() '${fulldomain}' '${txtvalue}'" _hostingde_apiKey && _hostingde_getZoneConfig && _hostingde_addRecord + return $? } dns_hostingde_rm() { @@ -20,6 +21,7 @@ dns_hostingde_rm() { txtvalue="${2}" _debug "Calling: _hostingde_removeRecord() '${fulldomain}' '${txtvalue}'" _hostingde_apiKey && _hostingde_getZoneConfig && _hostingde_removeRecord + return $? } #################### own Private functions below ################################## @@ -38,6 +40,18 @@ _hostingde_apiKey() { _saveaccountconf_mutable HOSTINGDE_ENDPOINT "$HOSTINGDE_ENDPOINT" } +_hostingde_parse() { + find="${1}" + if [ "${2}" ]; then + notfind="${2}" + fi + if [ "${notfind}" ]; then + _egrep_o \""${find}\":.*" | grep -v "${notfind}" | cut -d ':' -f 2 | cut -d ',' -f 1 | tr -d '[:space:]' + else + _egrep_o \""${find}\":.*" | cut -d ':' -f 2 | cut -d ',' -f 1 | tr -d '[:space:]' + fi +} + _hostingde_getZoneConfig() { _info "Getting ZoneConfig" curZone="${fulldomain#*.}" @@ -59,18 +73,18 @@ _hostingde_getZoneConfig() { if _contains "${curResult}" '"totalEntries": 1'; then _info "Retrieved zone data." _debug "Zone data: '${curResult}'" - zoneConfigId=$(echo "${curResult}" | _egrep_o '"id":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) - zoneConfigName=$(echo "${curResult}" | _egrep_o '"name":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) - zoneConfigType=$(echo "${curResult}" | grep -v "FindZoneConfigsResult" | _egrep_o '"type":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) - zoneConfigExpire=$(echo "${curResult}" | _egrep_o '"expire":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1) - zoneConfigNegativeTtl=$(echo "${curResult}" | _egrep_o '"negativeTtl":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1) - zoneConfigRefresh=$(echo "${curResult}" | _egrep_o '"refresh":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1) - zoneConfigRetry=$(echo "${curResult}" | _egrep_o '"retry":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1) - zoneConfigTtl=$(echo "${curResult}" | _egrep_o '"ttl":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1) - zoneConfigDnsServerGroupId=$(echo "${curResult}" | _egrep_o '"dnsServerGroupId":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) - zoneConfigEmailAddress=$(echo "${curResult}" | _egrep_o '"emailAddress":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) - zoneConfigDnsSecMode=$(echo "${curResult}" | _egrep_o '"dnsSecMode":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) - if [ "${zoneConfigType}" != "NATIVE" ]; then + zoneConfigId=$(echo "${curResult}" | _hostingde_parse "id") + zoneConfigName=$(echo "${curResult}" | _hostingde_parse "name") + zoneConfigType=$(echo "${curResult}" | _hostingde_parse "type" "FindZoneConfigsResult") + zoneConfigExpire=$(echo "${curResult}" | _hostingde_parse "expire") + zoneConfigNegativeTtl=$(echo "${curResult}" | _hostingde_parse "negativeTtl") + zoneConfigRefresh=$(echo "${curResult}" | _hostingde_parse "refresh") + zoneConfigRetry=$(echo "${curResult}" | _hostingde_parse "retry") + zoneConfigTtl=$(echo "${curResult}" | _hostingde_parse "ttl") + zoneConfigDnsServerGroupId=$(echo "${curResult}" | _hostingde_parse "dnsServerGroupId") + zoneConfigEmailAddress=$(echo "${curResult}" | _hostingde_parse "emailAddress") + zoneConfigDnsSecMode=$(echo "${curResult}" | _hostingde_parse "dnsSecMode") + if [ ${zoneConfigType} != "\"NATIVE\"" ]; then _err "Zone is not native" returnCode=1 break @@ -89,11 +103,11 @@ _hostingde_getZoneConfig() { _hostingde_getZoneStatus() { _debug "Checking Zone status" - curData="{\"filter\":{\"field\":\"zoneConfigId\",\"value\":\"${zoneConfigId}\"},\"limit\":1,\"authToken\":\"${HOSTINGDE_APIKEY}\"}" + curData="{\"filter\":{\"field\":\"zoneConfigId\",\"value\":${zoneConfigId}},\"limit\":1,\"authToken\":\"${HOSTINGDE_APIKEY}\"}" curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zonesFind")" _debug "Calling zonesFind '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zonesFind'" _debug "Result of zonesFind '$curResult'" - zoneStatus=$(echo "${curResult}" | grep -v success | _egrep_o '"status":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + zoneStatus=$(echo "${curResult}" | _hostingde_parse "status" "success") _debug "zoneStatus '${zoneStatus}'" return 0 } @@ -102,12 +116,12 @@ _hostingde_addRecord() { _info "Adding record to zone" _hostingde_getZoneStatus _debug "Result of zoneStatus: '${zoneStatus}'" - while [ "${zoneStatus}" != "active" ]; do + while [ "${zoneStatus}" != "\"active\"" ]; do _sleep 5 _hostingde_getZoneStatus _debug "Result of zoneStatus: '${zoneStatus}'" done - curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\",\"name\":\"${zoneConfigName}\",\"type\":\"${zoneConfigType}\",\"dnsServerGroupId\":\"${zoneConfigDnsServerGroupId}\",\"dnsSecMode\":\"${zoneConfigDnsSecMode}\",\"emailAddress\":\"${zoneConfigEmailAddress}\",\"soaValues\":{\"expire\":${zoneConfigExpire},\"negativeTtl\":${zoneConfigNegativeTtl},\"refresh\":${zoneConfigRefresh},\"retry\":${zoneConfigRetry},\"ttl\":${zoneConfigTtl}}},\"recordsToAdd\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\",\"ttl\":3600}]}" + curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":${zoneConfigId},\"name\":${zoneConfigName},\"type\":${zoneConfigType},\"dnsServerGroupId\":${zoneConfigDnsServerGroupId},\"dnsSecMode\":${zoneConfigDnsSecMode},\"emailAddress\":${zoneConfigEmailAddress},\"soaValues\":{\"expire\":${zoneConfigExpire},\"negativeTtl\":${zoneConfigNegativeTtl},\"refresh\":${zoneConfigRefresh},\"retry\":${zoneConfigRetry},\"ttl\":${zoneConfigTtl}}},\"recordsToAdd\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\",\"ttl\":3600}]}" curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")" _debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'" _debug "Result of zoneUpdate: '$curResult'" @@ -126,12 +140,12 @@ _hostingde_removeRecord() { _info "Removing record from zone" _hostingde_getZoneStatus _debug "Result of zoneStatus: '$zoneStatus'" - while [ "$zoneStatus" != "active" ]; do + while [ "$zoneStatus" != "\"active\"" ]; do _sleep 5 _hostingde_getZoneStatus _debug "Result of zoneStatus: '$zoneStatus'" done - curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\",\"name\":\"${zoneConfigName}\",\"type\":\"${zoneConfigType}\",\"dnsServerGroupId\":\"${zoneConfigDnsServerGroupId}\",\"dnsSecMode\":\"${zoneConfigDnsSecMode}\",\"emailAddress\":\"${zoneConfigEmailAddress}\",\"soaValues\":{\"expire\":${zoneConfigExpire},\"negativeTtl\":${zoneConfigNegativeTtl},\"refresh\":${zoneConfigRefresh},\"retry\":${zoneConfigRetry},\"ttl\":${zoneConfigTtl}}},\"recordsToDelete\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\"}]}" + curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":${zoneConfigId},\"name\":${zoneConfigName},\"type\":${zoneConfigType},\"dnsServerGroupId\":${zoneConfigDnsServerGroupId},\"dnsSecMode\":${zoneConfigDnsSecMode},\"emailAddress\":${zoneConfigEmailAddress},\"soaValues\":{\"expire\":${zoneConfigExpire},\"negativeTtl\":${zoneConfigNegativeTtl},\"refresh\":${zoneConfigRefresh},\"retry\":${zoneConfigRetry},\"ttl\":${zoneConfigTtl}}},\"recordsToDelete\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\"}]}" curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")" _debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'" _debug "Result of zoneUpdate: '$curResult'" From 4eda39a31d7a87ff3d741f39477206fa33554110 Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Mon, 4 Feb 2019 15:40:45 +0100 Subject: [PATCH 261/280] making shellcheck happy --- dnsapi/dns_hostingde.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index 4a7a214..56eeec7 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -84,7 +84,7 @@ _hostingde_getZoneConfig() { zoneConfigDnsServerGroupId=$(echo "${curResult}" | _hostingde_parse "dnsServerGroupId") zoneConfigEmailAddress=$(echo "${curResult}" | _hostingde_parse "emailAddress") zoneConfigDnsSecMode=$(echo "${curResult}" | _hostingde_parse "dnsSecMode") - if [ ${zoneConfigType} != "\"NATIVE\"" ]; then + if [ "${zoneConfigType}" != "\"NATIVE\"" ]; then _err "Zone is not native" returnCode=1 break From 84d80e93bcd9dcef9183658a5af4fc47efa8758f Mon Sep 17 00:00:00 2001 From: Frank Laszlo Date: Wed, 6 Feb 2019 10:42:11 -0500 Subject: [PATCH 262/280] Add support for Thermo, Nexcess, and Futurehosting DNS APIs --- README.md | 9 +- dnsapi/README.md | 62 +++++++++++++- dnsapi/dns_nw.sh | 211 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 276 insertions(+), 6 deletions(-) create mode 100644 dnsapi/dns_nw.sh diff --git a/README.md b/README.md index 90a648d..65b83e7 100644 --- a/README.md +++ b/README.md @@ -253,7 +253,7 @@ Just set string "apache" as the second argument and it will force use of apache 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. +**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.** @@ -277,7 +277,7 @@ So, the config is not changed. 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. +**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.** @@ -351,6 +351,9 @@ You don't have to do anything manually! 1. PointDNS API (https://pointhq.com/) 1. Active24.cz API (https://www.active24.cz/) 1. do.de API (https://www.do.de/) +1. Nexcess API (https://www.nexcess.net) +1. Thermo.io API (https://www.thermo.io) +1. Futurehosting API (https://www.futurehosting.com) And: @@ -528,5 +531,5 @@ Please Star and Fork me. 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) diff --git a/dnsapi/README.md b/dnsapi/README.md index 4f9b410..a9b78ef 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1,6 +1,6 @@ # How to use DNS API -If your dns provider doesn't provide api access, you can use our dns alias mode: +If your dns provider doesn't provide api access, you can use our dns alias mode: https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode @@ -891,7 +891,7 @@ acme.sh --issue --dns dns_loopia -d example.com -d *.example.com The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed. ## 45. Use ACME DNS API -ACME DNS is a limited DNS server with RESTful HTTP API to handle ACME DNS challenges easily and securely. +ACME DNS is a limited DNS server with RESTful HTTP API to handle ACME DNS challenges easily and securely. https://github.com/joohoi/acme-dns ``` @@ -1011,7 +1011,6 @@ acme.sh --issue --dns dns_netcup -d example.com -d www.example.com ``` The `NC_Apikey`,`NC_Apipw` and `NC_CID` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - ## 52. Use GratisDNS.dk GratisDNS.dk (https://gratisdns.dk/) does not provide an API to update DNS records (other than IPv4 and IPv6 @@ -1172,6 +1171,63 @@ acme.sh --issue --dns dns_doapi -d example.com -d *.example.com The API token will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 61. Use Nexcess API + +First, you'll need to login to the [Nexcess.net Client Portal](https://portal.nexcess.net) and [generate a new API token](https://portal.nexcess.net/api-token). + +Once you have a token, set it in your systems environment: + +``` +export NW_API_TOKEN="YOUR_TOKEN_HERE" +export NW_API_ENDPOINT="https://portal.nexcess.net" +``` + +Finally, we'll issue the certificate: (Nexcess DNS publishes at max every 15 minutes, we recommend setting a 900 second `--dnssleep`) + +``` +acme.sh --issue --dns dns_nw -d example.com --dnssleep 900 +``` + +The `NW_API_TOKEN` and `NW_API_ENDPOINT` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +## 62. Use Thermo.io API + +First, you'll need to login to the [Thermo.io Client Portal](https://core.thermo.io) and [generate a new API token](https://core.thermo.io/api-token). + +Once you have a token, set it in your systems environment: + +``` +export NW_API_TOKEN="YOUR_TOKEN_HERE" +export NW_API_ENDPOINT="https://core.thermo.io" +``` + +Finally, we'll issue the certificate: (Thermo DNS publishes at max every 15 minutes, we recommend setting a 900 second `--dnssleep`) + +``` +acme.sh --issue --dns dns_nw -d example.com --dnssleep 900 +``` + +The `NW_API_TOKEN` and `NW_API_ENDPOINT` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +## 63. Use Futurehosting API + +First, you'll need to login to the [Futurehosting Client Portal](https://my.futurehosting.com) and [generate a new API token](https://my.futurehosting.com/api-token). + +Once you have a token, set it in your systems environment: + +``` +export NW_API_TOKEN="YOUR_TOKEN_HERE" +export NW_API_ENDPOINT="https://my.futurehosting.com" +``` + +Finally, we'll issue the certificate: (Futurehosting DNS publishes at max every 15 minutes, we recommend setting a 900 second `--dnssleep`) + +``` +acme.sh --issue --dns dns_nw -d example.com --dnssleep 900 +``` + +The `NW_API_TOKEN` and `NW_API_ENDPOINT` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_nw.sh b/dnsapi/dns_nw.sh new file mode 100644 index 0000000..c57d27c --- /dev/null +++ b/dnsapi/dns_nw.sh @@ -0,0 +1,211 @@ +#!/usr/bin/env sh +######################################################################## +# NocWorx script for acme.sh +# +# Handles DNS Updates for the Following vendors: +# - Nexcess.net +# - Thermo.io +# - Futurehosting.com +# +# Environment variables: +# +# - NW_API_TOKEN (Your API Token) +# - NW_API_ENDPOINT (One of the following listed below) +# +# Endpoints: +# - https://portal.nexcess.net (default) +# - https://core.thermo.io +# - https://my.futurehosting.com +# +# Note: If you do not have an API token, one can be generated at one +# of the following URLs: +# - https://portal.nexcess.net/api-token +# - https://core.thermo.io/api-token +# - https://my.futurehosting.com/api-token +# +# Author: Frank Laszlo + +NW_API_VERSION="0" + +# dns_nw_add() - Add TXT record +# Usage: dns_nw_add _acme-challenge.subdomain.domain.com "XyZ123..." +dns_nw_add() { + host="${1}" + txtvalue="${2}" + + _debug host "${host}" + _debug txtvalue "${txtvalue}" + + if ! _check_nw_api_creds; then + return 1 + fi + + _info "Using NocWorx (${NW_API_ENDPOINT})" + _debug "Calling: dns_nw_add() '${host}' '${txtvalue}'" + + _debug "Detecting root zone" + if ! _get_root "${host}"; then + _err "Zone for domain does not exist." + return 1 + fi + _debug _zone_id "${_zone_id}" + _debug _sub_domain "${_sub_domain}" + _debug _domain "${_domain}" + + _post_data="{\"zone_id\": \"${_zone_id}\", \"type\": \"TXT\", \"host\": \"${host}\", \"target\": \"${txtvalue}\", \"ttl\": \"300\"}" + + if _rest POST "dns-record" "${_post_data}" && [ -n "${response}" ]; then + _record_id=$(printf "%s\n" "${response}" | _egrep_o "\"record_id\": *[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + _debug _record_id "${_record_id}" + + if [ -z "$_record_id" ]; then + _err "Error adding the TXT record." + return 1 + fi + + _info "TXT record successfully added." + return 0 + fi + + return 1 +} + +# dns_nw_rm() - Remove TXT record +# Usage: dns_nw_rm _acme-challenge.subdomain.domain.com "XyZ123..." +dns_nw_rm() { + host="${1}" + txtvalue="${2}" + + _debug host "${host}" + _debug txtvalue "${txtvalue}" + + if ! _check_nw_api_creds; then + return 1 + fi + + _info "Using NocWorx (${NW_API_ENDPOINT})" + _debug "Calling: dns_nw_rm() '${host}'" + + _debug "Detecting root zone" + if ! _get_root "${host}"; then + _err "Zone for domain does not exist." + return 1 + fi + _debug _zone_id "${_zone_id}" + _debug _sub_domain "${_sub_domain}" + _debug _domain "${_domain}" + + _parameters="?zone_id=${_zone_id}" + + if _rest GET "dns-record" "${_parameters}" && [ -n "${response}" ]; then + response="$(echo "${response}" | tr -d "\n" | sed 's/^\[\(.*\)\]$/\1/' | sed -e 's/{"record_id":/|"record_id":/g' | sed 's/|/&{/g' | tr "|" "\n")" + _debug response "${response}" + + record="$(echo "${response}" | _egrep_o "{.*\"host\": *\"${_sub_domain}\", *\"target\": *\"${txtvalue}\".*}")" + _debug record "${record}" + + if [ "${record}" ]; then + _record_id=$(printf "%s\n" "${record}" | _egrep_o "\"record_id\": *[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "${_record_id}" ]; then + _debug _record_id "${_record_id}" + + _rest DELETE "dns-record/${_record_id}" + + _info "TXT record successfully deleted." + return 0 + fi + + return 1 + fi + + return 0 + fi + + return 1 +} + +_check_nw_api_creds() { + NW_API_TOKEN="${NW_API_TOKEN:-$(_readaccountconf_mutable NW_API_TOKEN)}" + NW_API_ENDPOINT="${NW_API_ENDPOINT:-$(_readaccountconf_mutable NW_API_ENDPOINT)}" + + if [ -z "${NW_API_ENDPOINT}" ]; then + NW_API_ENDPOINT="https://portal.nexcess.net" + fi + + if [ -z "${NW_API_TOKEN}" ]; then + _err "You have not defined your NW_API_TOKEN." + _err "Please create your token and try again." + _err "If you need to generate a new token, please visit one of the following URLs:" + _err " - https://portal.nexcess.net/api-token" + _err " - https://core.thermo.io/api-token" + _err " - https://my.futurehosting.com/api-token" + + return 1 + fi + + _saveaccountconf_mutable NW_API_TOKEN "${NW_API_TOKEN}" + _saveaccountconf_mutable NW_API_ENDPOINT "${NW_API_ENDPOINT}" +} + +_get_root() { + domain="${1}" + i=2 + p=1 + + if _rest GET "dns-zone"; then + response="$(echo "${response}" | tr -d "\n" | sed 's/^\[\(.*\)\]$/\1/' | sed -e 's/{"zone_id":/|"zone_id":/g' | sed 's/|/&{/g' | tr "|" "\n")" + + _debug response "${response}" + while true; do + h=$(printf "%s" "${domain}" | cut -d . -f $i-100) + _debug h "${h}" + if [ -z "${h}" ]; then + #not valid + return 1 + fi + + hostedzone="$(echo "${response}" | _egrep_o "{.*\"domain\": *\"${h}\".*}")" + if [ "${hostedzone}" ]; then + _zone_id=$(printf "%s\n" "${hostedzone}" | _egrep_o "\"zone_id\": *[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "${_zone_id}" ]; then + _sub_domain=$(printf "%s" "${domain}" | cut -d . -f 1-${p}) + _domain="${h}" + return 0 + fi + return 1 + fi + p=$i + i=$(_math "${i}" + 1) + done + fi + return 1 +} + +_rest() { + method="${1}" + ep="/${2}" + data="${3}" + + _debug method "${method}" + _debug ep "${ep}" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + export _H3="Api-Version: ${NW_API_VERSION}" + export _H4="User-Agent: NW-ACME-CLIENT" + export _H5="Authorization: Bearer ${NW_API_TOKEN}" + + if [ "${method}" != "GET" ]; then + _debug data "${data}" + response="$(_post "${data}" "${NW_API_ENDPOINT}${ep}" "" "${method}")" + else + response="$(_get "${NW_API_ENDPOINT}${ep}${data}")" + fi + + if [ "${?}" != "0" ]; then + _err "error ${ep}" + return 1 + fi + _debug2 response "${response}" + return 0 +} From ebc90f6ab831ab2f35e3c7411bcba41a366583d2 Mon Sep 17 00:00:00 2001 From: Simon Wydooghe Date: Wed, 6 Feb 2019 17:42:50 +0100 Subject: [PATCH 263/280] Set NS1 DNS record TTL to 0 Default of a zone might be high, which is annoying when testing with the ACME staging API. I think setting the TTL to 0 makes sense as acme.sh is the only one checking this, so having an always up to date response seems desirable. --- dnsapi/dns_nsone.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index 00e186d..9a99834 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -46,7 +46,7 @@ dns_nsone_add() { if [ "$count" = "0" ]; then _info "Adding record" - if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; then + if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\",\"ttl\":0}"; then if _contains "$response" "$fulldomain"; then _info "Added" #todo: check if the record takes effect @@ -62,7 +62,7 @@ dns_nsone_add() { prev_txt=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",\"short_answers\":\[\"[^,]*\]" | _head_n 1 | cut -d: -f3 | cut -d, -f1) _debug "prev_txt" "$prev_txt" - _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]},{\"answer\": $prev_txt}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}" + _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]},{\"answer\": $prev_txt}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\",\"ttl\":0}" if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then _info "Updated!" #todo: check if the record takes effect From 2cf01c23a2b1f09a317e58aa99f8c9fbedb7146d Mon Sep 17 00:00:00 2001 From: Christian Burmeister Date: Sat, 9 Feb 2019 19:38:32 +0100 Subject: [PATCH 264/280] Update Dockerfile --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c1a2199..68385d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.6 +FROM alpine:3.9 RUN apk update -f \ && apk --no-cache add -f \ @@ -7,6 +7,7 @@ RUN apk update -f \ bind-tools \ curl \ socat \ + tzdata \ && rm -rf /var/cache/apk/* ENV LE_CONFIG_HOME /acme.sh From 1fa026b9c7315128f60f6a1e9137f44aa01d60bf Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Mon, 11 Feb 2019 11:47:48 +0100 Subject: [PATCH 265/280] using ' ' instead of '[:space:]' for tr --- dnsapi/dns_hostingde.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index 56eeec7..50aa142 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -46,9 +46,9 @@ _hostingde_parse() { notfind="${2}" fi if [ "${notfind}" ]; then - _egrep_o \""${find}\":.*" | grep -v "${notfind}" | cut -d ':' -f 2 | cut -d ',' -f 1 | tr -d '[:space:]' + _egrep_o \""${find}\":.*" | grep -v "${notfind}" | cut -d ':' -f 2 | cut -d ',' -f 1 | tr -d ' ' else - _egrep_o \""${find}\":.*" | cut -d ':' -f 2 | cut -d ',' -f 1 | tr -d '[:space:]' + _egrep_o \""${find}\":.*" | cut -d ':' -f 2 | cut -d ',' -f 1 | tr -d ' ' fi } From d30b441ede3d2907c0645cf4dea78d740c2a6f08 Mon Sep 17 00:00:00 2001 From: Tom Cocca Date: Wed, 2 Jan 2019 00:18:25 -0600 Subject: [PATCH 266/280] Rackspace Cloud DNS Support Rackspace Cloud DNS This commit is based on the original pull request by tcocca https://github.com/Neilpang/acme.sh/pull/1297 Addtional cleanup was provided by senseisimple in https://github.com/Neilpang/acme.sh/pull/1999 This pull request has squashed the changes for review, fixed a minor (but breaking) problem with the field ordering in the response, and added documenation per the API guide. Co-Author: Chris Co-Author: Ian Wienand --- README.md | 1 + dnsapi/README.md | 15 +++ dnsapi/dns_rackspace.sh | 207 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 dnsapi/dns_rackspace.sh diff --git a/README.md b/README.md index 65b83e7..793df06 100644 --- a/README.md +++ b/README.md @@ -354,6 +354,7 @@ You don't have to do anything manually! 1. Nexcess API (https://www.nexcess.net) 1. Thermo.io API (https://www.thermo.io) 1. Futurehosting API (https://www.futurehosting.com) +1. Rackspace Cloud DNS (https://www.rackspace.com) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index a9b78ef..c136ed3 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1228,6 +1228,21 @@ acme.sh --issue --dns dns_nw -d example.com --dnssleep 900 The `NW_API_TOKEN` and `NW_API_ENDPOINT` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 64. Use Rackspace API + +Set username and API key, which is available under "My Profile & Settings" + +``` +export RACKSPACE_Username='username' +export RACKSPACE_Apikey='xxx' +``` + +Now, let's issue a cert: + +``` +acme.sh --issue --dns dns_rackspace -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_rackspace.sh b/dnsapi/dns_rackspace.sh new file mode 100644 index 0000000..3939fd8 --- /dev/null +++ b/dnsapi/dns_rackspace.sh @@ -0,0 +1,207 @@ +#!/usr/bin/env sh +# +# +#RACKSPACE_Username="" +# +#RACKSPACE_Apikey="" + +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 + +######## Public functions ##################### +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_rackspace_add() { + fulldomain="$1" + _debug fulldomain="$fulldomain" + txtvalue="$2" + _debug txtvalue="$txtvalue" + _rackspace_check_auth || return 1 + _rackspace_check_rootzone || return 1 + _info "Creating TXT record." + if ! _rackspace_rest POST "$RACKSPACE_Tenant/domains/$_domain_id/records" "{\"records\":[{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":300}]}"; then + return 1 + fi + _debug2 response "$response" + if ! _contains "$response" "$txtvalue" >/dev/null; then + _err "Could not add TXT record." + return 1 + fi + return 0 +} + +#fulldomain txtvalue +dns_rackspace_rm() { + fulldomain=$1 + _debug fulldomain="$fulldomain" + txtvalue=$2 + _debug txtvalue="$txtvalue" + _rackspace_check_auth || return 1 + _rackspace_check_rootzone || return 1 + _info "Checking for TXT record." + if ! _get_recordid "$_domain_id" "$fulldomain" "$txtvalue"; then + _err "Could not get TXT record id." + return 1 + fi + if [ "$_dns_record_id" = "" ]; then + _err "TXT record not found." + return 1 + fi + _info "Removing TXT record." + if ! _delete_txt_record "$_domain_id" "$_dns_record_id"; then + _err "Could not remove TXT record $_dns_record_id." + fi + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root_zone() { + domain="$1" + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + if ! _rackspace_rest GET "$RACKSPACE_Tenant/domains"; then + return 1 + fi + _debug2 response "$response" + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + # Response looks like: + # {"ttl":300,"accountId":12345,"id":1111111,"name":"example.com","emailAddress": ... + _domain_id=$(echo "$response" | sed -n "s/^.*\"id\":\([^,]*\),\"name\":\"$h\",.*/\1/p") + _debug2 domain_id "$_domain_id" + if [ -n "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_get_recordid() { + domainid="$1" + fulldomain="$2" + txtvalue="$3" + if ! _rackspace_rest GET "$RACKSPACE_Tenant/domains/$domainid/records?name=$fulldomain&type=TXT"; then + return 1 + fi + _debug response "$response" + if ! _contains "$response" "$txtvalue"; then + _dns_record_id=0 + return 0 + fi + _dns_record_id=$(echo "$response" | tr '{' "\n" | grep "\"data\":\"$txtvalue\"" | sed -n 's/^.*"id":"\([^"]*\)".*/\1/p') + _debug _dns_record_id "$_dns_record_id" + return 0 +} + +_delete_txt_record() { + domainid="$1" + _dns_record_id="$2" + if ! _rackspace_rest DELETE "$RACKSPACE_Tenant/domains/$domainid/records?id=$_dns_record_id"; then + return 1 + fi + _debug response "$response" + if ! _contains "$response" "RUNNING"; then + return 1 + fi + return 0 +} + +_rackspace_rest() { + m="$1" + ep="$2" + data="$3" + _debug ep "$ep" + export _H1="Accept: application/json" + export _H2="X-Auth-Token: $RACKSPACE_Token" + export _H3="X-Project-Id: $RACKSPACE_Tenant" + export _H4="Content-Type: application/json" + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$RACKSPACE_Endpoint/$ep" "" "$m")" + retcode=$? + else + _info "Getting $RACKSPACE_Endpoint/$ep" + response="$(_get "$RACKSPACE_Endpoint/$ep")" + retcode=$? + fi + + if [ "$retcode" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + +_rackspace_authorization() { + export _H1="Content-Type: application/json" + data="{\"auth\":{\"RAX-KSKEY:apiKeyCredentials\":{\"username\":\"$RACKSPACE_Username\",\"apiKey\":\"$RACKSPACE_Apikey\"}}}" + _debug data "$data" + response="$(_post "$data" "https://identity.api.rackspacecloud.com/v2.0/tokens" "" "POST")" + retcode=$? + _debug2 response "$response" + if [ "$retcode" != "0" ]; then + _err "Authentication failed." + return 1 + fi + if _contains "$response" "token"; then + RACKSPACE_Token="$(echo "$response" | _normalizeJson | sed -n 's/^.*"token":{.*,"id":"\([^"]*\)",".*/\1/p')" + RACKSPACE_Tenant="$(echo "$response" | _normalizeJson | sed -n 's/^.*"token":{.*,"id":"\([^"]*\)"}.*/\1/p')" + _debug RACKSPACE_Token "$RACKSPACE_Token" + _debug RACKSPACE_Tenant "$RACKSPACE_Tenant" + fi + return 0 +} + +_rackspace_check_auth() { + # retrieve the rackspace creds + RACKSPACE_Username="${RACKSPACE_Username:-$(_readaccountconf_mutable RACKSPACE_Username)}" + RACKSPACE_Apikey="${RACKSPACE_Apikey:-$(_readaccountconf_mutable RACKSPACE_Apikey)}" + # check their vals for null + if [ -z "$RACKSPACE_Username" ] || [ -z "$RACKSPACE_Apikey" ]; then + RACKSPACE_Username="" + RACKSPACE_Apikey="" + _err "You didn't specify a Rackspace username and api key." + _err "Please set those values and try again." + return 1 + fi + # save the username and api key to the account conf file. + _saveaccountconf_mutable RACKSPACE_Username "$RACKSPACE_Username" + _saveaccountconf_mutable RACKSPACE_Apikey "$RACKSPACE_Apikey" + if [ -z "$RACKSPACE_Token" ]; then + _info "Getting authorization token." + if ! _rackspace_authorization; then + _err "Can not get token." + fi + fi +} + +_rackspace_check_rootzone() { + _debug "First detect the root zone" + if ! _get_root_zone "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" +} From ec5fad433c3cdfb8b9d64ed8197ed445297adc1c Mon Sep 17 00:00:00 2001 From: Augustin-FL Date: Wed, 13 Feb 2019 23:33:54 +0100 Subject: [PATCH 267/280] Add online.net DNS API --- README.md | 1 + dnsapi/README.md | 16 ++++ dnsapi/dns_online.sh | 214 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+) create mode 100755 dnsapi/dns_online.sh diff --git a/README.md b/README.md index 793df06..8d749dc 100644 --- a/README.md +++ b/README.md @@ -355,6 +355,7 @@ You don't have to do anything manually! 1. Thermo.io API (https://www.thermo.io) 1. Futurehosting API (https://www.futurehosting.com) 1. Rackspace Cloud DNS (https://www.rackspace.com) +1. Online.net API (https://online.net/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index c136ed3..f022cab 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1243,6 +1243,22 @@ Now, let's issue a cert: acme.sh --issue --dns dns_rackspace -d example.com -d www.example.com ``` +## 65. Use Online API + +First, you'll need to retrive your API key, which is available under https://console.online.net/en/api/access + +``` +export ONLINE_API_KEY='xxx' +``` + +To issue a cert run: + +``` +acme.sh --issue --dns dns_online -d example.com -d www.example.com +``` + +`ONLINE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_online.sh b/dnsapi/dns_online.sh new file mode 100755 index 0000000..02d07dc --- /dev/null +++ b/dnsapi/dns_online.sh @@ -0,0 +1,214 @@ +#!/usr/bin/env sh + +# Online API +# https://console.online.net/en/api/ +# +# Requires Online API key set in ONLINE_API_KEY + +######## Public functions ##################### + +ONLINE_API="https://api.online.net/api/v1" + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_online_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _online_check_config; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + _debug _real_dns_version "$_real_dns_version" + + _info "Creating temporary zone version" + _online_create_temporary_zone_version + _info "Enabling temporary zone version" + _online_enable_zone "$_temporary_dns_version" + + _info "Adding record" + _online_create_TXT_record "$_real_dns_version" "$_sub_domain" "$txtvalue" + _info "Disabling temporary version" + _online_enable_zone "$_real_dns_version" + _info "Destroying temporary version" + _online_destroy_zone "$_temporary_dns_version" + + _info "Record added." + return 0 +} + +#fulldomain +dns_online_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! _online_check_config; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + _debug _real_dns_version "$_real_dns_version" + + _debug "Getting txt records" + if ! _online_rest GET "domain/$_domain/version/active"; then + return 1 + fi + + rid=$(echo "$response" | _egrep_o "\"id\":[0-9]+,\"name\":\"$_sub_domain\",\"data\":\"\\\u0022$txtvalue\\\u0022\"" | cut -d ':' -f 2 | cut -d ',' -f 1) + _debug rid "$rid" + if [ -z "$rid" ]; then + return 1 + fi + + _info "Creating temporary zone version" + _online_create_temporary_zone_version + _info "Enabling temporary zone version" + _online_enable_zone "$_temporary_dns_version" + + _info "Removing DNS record" + _online_rest DELETE "domain/$_domain/version/$_real_dns_version/zone/$rid" + _info "Disabling temporary version" + _online_enable_zone "$_real_dns_version" + _info "Destroying temporary version" + _online_destroy_zone "$_temporary_dns_version" + + return 0 +} + +#################### Private functions below ################################## + +_online_check_config() { + + if [ -z "$ONLINE_API_KEY" ]; then + _err "No API key specified for Online API." + _err "Create your key and export it as ONLINE_API_KEY" + return 1 + fi + + _saveaccountconf ONLINE_API_KEY "$ONLINE_API_KEY" + + return 0 +} + +#_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 + if ! _online_rest GET "domain/$h/version/active"; then + _err "Unable to retrive DNS zone matching this domain" + return 1 + fi + + if ! _contains "$response" "Domain not found" >/dev/null; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + _real_dns_version=$(echo "$response" | _egrep_o '"uuid_ref":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +# this function create a temporary zone version +# as online.net does not allow updating an active version +_online_create_temporary_zone_version() { + + _online_rest POST "domain/$_domain/version" "name=acme.sh" + if [ "$?" != "0" ]; then + return 1 + fi + + _temporary_dns_version=$(echo "$response" | _egrep_o '"uuid_ref":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + + # Creating a dummy record in this temporary version, because online.net doesn't accept enabling an empty version + _online_create_TXT_record "$_temporary_dns_version" "dummy.acme.sh" "dummy" + + return 0 +} + +_online_destroy_zone() { + version_id=$1 + _online_rest DELETE "domain/$_domain/version/$version_id" + + if [ "$?" != "0" ]; then + return 1 + fi + return 0 +} + +_online_enable_zone() { + version_id=$1 + _online_rest PATCH "domain/$_domain/version/$version_id/enable" + + if [ "$?" != "0" ]; then + return 1 + fi + return 0 +} + +_online_create_TXT_record() { + version=$1 + txt_name=$2 + txt_value=$3 + + _online_rest POST "domain/$_domain/version/$version/zone" "type=TXT&name=$txt_name&data=%22$txt_value%22&ttl=60&priority=0" + + # Note : the normal, expected response SHOULD be "Unknown method". + # this happens because the API HTTP response contains a Location: header, that redirect + # to an unknown online.net endpoint. + if [ "$?" != "0" ] || _contains "$response" "Unknown method"; then + return 0 + else + _err "error $response" + return 1 + fi +} + +_online_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + _online_url="$ONLINE_API/$ep" + _debug2 _online_url "$_online_url" + export _H1="Authorization: Bearer $ONLINE_API_KEY" + export _H2="X-Pretty-JSON: 1" + if [ "$data" ] || [ "$m" = "PATCH" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] || [ "$m" = "DELETE" ]; then + _debug data "$data" + response="$(_post "$data" "$_online_url" "" "$m")" + else + response="$(_get "$_online_url")" + fi + if [ "$?" != "0" ] || _contains "$response" "invalid_grant" || _contains "$response" "Method not allowed"; then + _err "error $response" + return 1 + fi + _debug2 response "$response" + return 0 +} From 02f6d4cb66c3837490295379a59c67936dcb0b90 Mon Sep 17 00:00:00 2001 From: Augustin-FL Date: Fri, 15 Feb 2019 07:56:13 +0000 Subject: [PATCH 268/280] use read/saveconf_mutable, not readconf from OVH --- dnsapi/dns_online.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_online.sh b/dnsapi/dns_online.sh index 02d07dc..c6ee485 100755 --- a/dnsapi/dns_online.sh +++ b/dnsapi/dns_online.sh @@ -92,14 +92,18 @@ dns_online_rm() { #################### Private functions below ################################## _online_check_config() { - + ONLINE_API_KEY="${CF_Key:-$(_readaccountconf_mutable ONLINE_API_KEY)}" if [ -z "$ONLINE_API_KEY" ]; then _err "No API key specified for Online API." _err "Create your key and export it as ONLINE_API_KEY" return 1 fi + if [ ! _online_rest GET "domain/" ]; then + _err "Invalid API key specified for Online API." + return 1 + fi - _saveaccountconf ONLINE_API_KEY "$ONLINE_API_KEY" + _saveaccountconf_mutable ONLINE_API_KEY "$ONLINE_API_KEY" return 0 } From 5c94147603b4d9c3d903c01344bde9751095eddc Mon Sep 17 00:00:00 2001 From: Augustin-FL Date: Fri, 15 Feb 2019 08:08:10 +0000 Subject: [PATCH 269/280] use read/saveconf_mutable, not readconf from OVH --- dnsapi/dns_online.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_online.sh b/dnsapi/dns_online.sh index c6ee485..ee00685 100755 --- a/dnsapi/dns_online.sh +++ b/dnsapi/dns_online.sh @@ -92,13 +92,13 @@ dns_online_rm() { #################### Private functions below ################################## _online_check_config() { - ONLINE_API_KEY="${CF_Key:-$(_readaccountconf_mutable ONLINE_API_KEY)}" + ONLINE_API_KEY="${ONLINE_API_KEY:-$(_readaccountconf_mutable ONLINE_API_KEY)}" if [ -z "$ONLINE_API_KEY" ]; then _err "No API key specified for Online API." _err "Create your key and export it as ONLINE_API_KEY" return 1 fi - if [ ! _online_rest GET "domain/" ]; then + if ! _online_rest GET "domain/"; then _err "Invalid API key specified for Online API." return 1 fi From 841513501a69aab5ae9ec98a9c383df65f1fb8f6 Mon Sep 17 00:00:00 2001 From: Augustin-FL Date: Fri, 15 Feb 2019 07:58:43 +0000 Subject: [PATCH 270/280] update get_root --- dnsapi/dns_online.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_online.sh b/dnsapi/dns_online.sh index ee00685..8c5a046 100755 --- a/dnsapi/dns_online.sh +++ b/dnsapi/dns_online.sh @@ -122,10 +122,8 @@ _get_root() { #not valid return 1 fi - if ! _online_rest GET "domain/$h/version/active"; then - _err "Unable to retrive DNS zone matching this domain" - return 1 - fi + + _online_rest GET "domain/$h/version/active" if ! _contains "$response" "Domain not found" >/dev/null; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) @@ -136,7 +134,8 @@ _get_root() { p=$i i=$(_math "$i" + 1) done - return 1 + _err "Unable to retrive DNS zone matching this domain" + return 1 } # this function create a temporary zone version From 9ace7db216cdce631475e3df1eb66e2d14f92489 Mon Sep 17 00:00:00 2001 From: Augustin-FL Date: Fri, 15 Feb 2019 08:03:13 +0000 Subject: [PATCH 271/280] simplify online_rest --- dnsapi/dns_online.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_online.sh b/dnsapi/dns_online.sh index 8c5a046..8831f9a 100755 --- a/dnsapi/dns_online.sh +++ b/dnsapi/dns_online.sh @@ -202,7 +202,7 @@ _online_rest() { _debug2 _online_url "$_online_url" export _H1="Authorization: Bearer $ONLINE_API_KEY" export _H2="X-Pretty-JSON: 1" - if [ "$data" ] || [ "$m" = "PATCH" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] || [ "$m" = "DELETE" ]; then + if [ "$data" ] || [ "$m" != "GET" ]; then _debug data "$data" response="$(_post "$data" "$_online_url" "" "$m")" else From 63ea3e8d277e8868bcbf5f6a2242a0028a26bb5d Mon Sep 17 00:00:00 2001 From: Augustin-FL Date: Fri, 15 Feb 2019 08:29:00 +0000 Subject: [PATCH 272/280] acme.sh does not follow Location: headers when using wget --- dnsapi/dns_online.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_online.sh b/dnsapi/dns_online.sh index 8831f9a..6f4c40d 100755 --- a/dnsapi/dns_online.sh +++ b/dnsapi/dns_online.sh @@ -185,7 +185,7 @@ _online_create_TXT_record() { # Note : the normal, expected response SHOULD be "Unknown method". # this happens because the API HTTP response contains a Location: header, that redirect # to an unknown online.net endpoint. - if [ "$?" != "0" ] || _contains "$response" "Unknown method"; then + if [ "$?" != "0" ] || _contains "$response" "Unknown method" || _contains "$response" "\$ref"; then return 0 else _err "error $response" From 1ad6742dbc0e0bc9df869afbcbc67959d91452a0 Mon Sep 17 00:00:00 2001 From: Augustin-FL Date: Fri, 15 Feb 2019 08:43:07 +0000 Subject: [PATCH 273/280] fix travis --- dnsapi/dns_online.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_online.sh b/dnsapi/dns_online.sh index 6f4c40d..0d1fca2 100755 --- a/dnsapi/dns_online.sh +++ b/dnsapi/dns_online.sh @@ -134,7 +134,7 @@ _get_root() { p=$i i=$(_math "$i" + 1) done - _err "Unable to retrive DNS zone matching this domain" + _err "Unable to retrive DNS zone matching this domain" return 1 } From ec6569fbea21bb9eef2397cdcfb66b202cea9671 Mon Sep 17 00:00:00 2001 From: Augustin-FL Date: Fri, 15 Feb 2019 08:56:09 +0000 Subject: [PATCH 274/280] fix travis --- dnsapi/dns_online.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_online.sh b/dnsapi/dns_online.sh index 0d1fca2..9158c26 100755 --- a/dnsapi/dns_online.sh +++ b/dnsapi/dns_online.sh @@ -135,7 +135,7 @@ _get_root() { i=$(_math "$i" + 1) done _err "Unable to retrive DNS zone matching this domain" - return 1 + return 1 } # this function create a temporary zone version From f2acdd27fd0f8d0407058ad05b12137197d99afc Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 17 Feb 2019 14:19:14 +0800 Subject: [PATCH 275/280] fix tr err for Mac --- acme.sh | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/acme.sh b/acme.sh index cfdf571..82c5e50 100755 --- a/acme.sh +++ b/acme.sh @@ -1882,29 +1882,34 @@ _send_signed_request() { _err "Can not post to $url" return 1 fi - _debug2 original "$response" - response="$(echo "$response" | _normalizeJson)" responseHeaders="$(cat "$HTTP_HEADER")" - _debug2 responseHeaders "$responseHeaders" - _debug2 response "$response" + code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" _debug code "$code" - _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" - - _body="$response" - if [ "$needbase64" ]; then - _body="$(echo "$_body" | _dbase64 | tr -d '\0')" - _debug3 _body "$_body" + _debug2 original "$response" + if echo "$responseHeaders" | grep -i "Content-Type: application/json" >/dev/null 2>&1; then + response="$(echo "$response" | _normalizeJson)" fi + _debug2 response "$response" - if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then - _info "It seems the CA server is busy now, let's wait and retry. Sleeping $_sleep_retry_sec seconds." - _CACHED_NONCE="" - _sleep $_sleep_retry_sec - continue + _CACHED_NONCE="$(echo "$responseHeaders" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + + if ! _startswith "$code" "2"; then + _body="$response" + if [ "$needbase64" ]; then + _body="$(echo "$_body" | _dbase64 multiline)" + _debug3 _body "$_body" + fi + + if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then + _info "It seems the CA server is busy now, let's wait and retry. Sleeping $_sleep_retry_sec seconds." + _CACHED_NONCE="" + _sleep $_sleep_retry_sec + continue + fi fi break done @@ -4113,14 +4118,14 @@ $_authorizations_map" Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" _tempSignedResponse="$response" - if ! _send_signed_request "$Le_LinkCert" "" "needbase64"; then + if ! _send_signed_request "$Le_LinkCert"; then _err "Sign failed, can not download cert:$Le_LinkCert." _err "$response" _on_issue_err "$_post_hook" return 1 fi - echo "$response" | _dbase64 "multiline" >"$CERT_PATH" + echo "$response" >"$CERT_PATH" if [ "$(grep -- "$BEGIN_CERT" "$CERT_PATH" | wc -l)" -gt "1" ]; then _debug "Found cert chain" From a0ec5b18e79bfa21f22634806e80d0659105b35a Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 17 Feb 2019 14:26:27 +0800 Subject: [PATCH 276/280] fx format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 82c5e50..7b094e9 100755 --- a/acme.sh +++ b/acme.sh @@ -1897,7 +1897,7 @@ _send_signed_request() { _CACHED_NONCE="$(echo "$responseHeaders" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" - if ! _startswith "$code" "2"; then + if ! _startswith "$code" "2"; then _body="$response" if [ "$needbase64" ]; then _body="$(echo "$_body" | _dbase64 multiline)" From 97147b594b185786ef1d69ce0d85b70a91f0ccc9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 18 Feb 2019 20:57:13 +0800 Subject: [PATCH 277/280] fix https://github.com/Neilpang/acme.sh/issues/2096 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7b094e9..5c093e4 100755 --- a/acme.sh +++ b/acme.sh @@ -1188,7 +1188,7 @@ _ss() { if _exists "netstat"; then _debug "Using: netstat" - if netstat -h 2>&1 | grep "\-p proto" >/dev/null; then + if netstat -help 2>&1 | grep "\-p proto" >/dev/null; then #for windows version netstat tool netstat -an -p tcp | grep "LISTENING" | grep ":$_port " else From b5ca9bbab2a73f11b9336d2ffe10a07add142130 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 19 Feb 2019 21:39:06 +0800 Subject: [PATCH 278/280] Doh (#2100) support doh to poll dns status fix https://github.com/Neilpang/acme.sh/issues/2015 --- acme.sh | 192 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 144 insertions(+), 48 deletions(-) diff --git a/acme.sh b/acme.sh index 23bc4f6..93112a1 100755 --- a/acme.sh +++ b/acme.sh @@ -2929,42 +2929,38 @@ _clearup() { _clearupdns() { _debug "_clearupdns" - _debug "dnsadded" "$dnsadded" - _debug "vlist" "$vlist" - #dnsadded is "0" or "1" means dns-01 method was used for at least one domain - if [ -z "$dnsadded" ] || [ -z "$vlist" ]; then + _debug "dns_entries" "$dns_entries" + + if [ -z "$dns_entries" ]; then _debug "skip dns." return fi _info "Removing DNS records." - ventries=$(echo "$vlist" | tr ',' ' ') - _alias_index=1 - for ventry in $ventries; do - d=$(echo "$ventry" | cut -d "$sep" -f 1) - keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) - vtype=$(echo "$ventry" | cut -d "$sep" -f 4) - _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" - _debug txt "$txt" - if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then - _debug "$d is already verified, skip $vtype." - _alias_index="$(_math "$_alias_index" + 1)" - continue - fi - if [ "$vtype" != "$VTYPE_DNS" ]; then - _debug "Skip $d for $vtype" - continue + for entry in $dns_entries; do + d=$(_getfield "$entry" 1) + txtdomain=$(_getfield "$entry" 2) + aliasDomain=$(_getfield "$entry" 3) + txt=$(_getfield "$entry" 5) + d_api=$(_getfield "$entry" 6) + _debug "d" "$d" + _debug "txtdomain" "$txtdomain" + _debug "aliasDomain" "$aliasDomain" + _debug "txt" "$txt" + _debug "d_api" "$d_api" + if [ "$d_api" = "$txt" ]; then + d_api="" fi - d_api="$(_findHook "$d" dnsapi "$_currentRoot")" - _debug d_api "$d_api" - if [ -z "$d_api" ]; then _info "Not Found domain api file: $d_api" continue fi + if [ "$aliasDomain" ]; then + txtdomain="$aliasDomain" + fi + ( if ! . "$d_api"; then _err "Load file $d_api error. Please check your api file and try again." @@ -2977,24 +2973,6 @@ _clearupdns() { return 1 fi - _dns_root_d="$d" - if _startswith "$_dns_root_d" "*."; then - _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')" - fi - - _d_alias="$(_getfield "$_challenge_alias" "$_alias_index")" - _alias_index="$(_math "$_alias_index" + 1)" - _debug "_d_alias" "$_d_alias" - if [ "$_d_alias" ]; then - if _startswith "$_d_alias" "$DNS_ALIAS_PREFIX"; then - txtdomain="$(echo "$_d_alias" | sed "s/$DNS_ALIAS_PREFIX//")" - else - txtdomain="_acme-challenge.$_d_alias" - fi - else - txtdomain="_acme-challenge.$_dns_root_d" - fi - if ! $rmcommand "$txtdomain" "$txt"; then _err "Error removing txt for domain:$txtdomain" return 1 @@ -3463,6 +3441,113 @@ __trigger_validation() { fi } +#endpoint domain type +_ns_lookup() { + _ns_ep="$1" + _ns_domain="$2" + _ns_type="$3" + _debug2 "_ns_ep" "$_ns_ep" + _debug2 "_ns_domain" "$_ns_domain" + _debug2 "_ns_type" "$_ns_type" + + response="$(_H1="accept: application/dns-json" _get "$_ns_ep?name=$_ns_domain&type=$_ns_type")" + _ret=$? + _debug2 "response" "$response" + if [ "$_ret" != "0" ]; then + return $_ret + fi + _answers="$(echo "$response" | tr '{}' '<>' | _egrep_o '"Answer":\[[^]]*]' | tr '<>' '\n\n')" + _debug2 "_answers" "$_answers" + echo "$_answers" +} + +#domain, type +_ns_lookup_cf() { + _cf_ld="$1" + _cf_ld_type="$2" + _cf_ep="https://cloudflare-dns.com/dns-query" + _ns_lookup "$_cf_ep" "$_cf_ld" "$_cf_ld_type" +} + +#domain, type +_ns_purge_cf() { + _cf_d="$1" + _cf_d_type="$2" + _debug "Cloudflare purge $_cf_d_type record for domain $_cf_d" + _cf_purl="https://1.1.1.1/api/v1/purge?domain=$_cf_d&type=$_cf_d_type" + response="$(_post "" "$_cf_purl")" + _debug2 response "$response" +} + +#txtdomain, alias, txt +__check_txt() { + _c_txtdomain="$1" + _c_aliasdomain="$2" + _c_txt="$3" + _debug "_c_txtdomain" "$_c_txtdomain" + _debug "_c_aliasdomain" "$_c_aliasdomain" + _debug "_c_txt" "$_c_txt" + _answers="$(_ns_lookup_cf "$_c_aliasdomain" TXT)" + _contains "$_answers" "$_c_txt" + +} + +#txtdomain +__purge_txt() { + _p_txtdomain="$1" + _debug _p_txtdomain "$_p_txtdomain" + _ns_purge_cf "$_p_txtdomain" "TXT" +} + +#wait and check each dns entries +_check_dns_entries() { + _success_txt="," + _end_time="$(_time)" + _end_time="$(_math "$_end_time" + 1200)" #let's check no more than 20 minutes. + + while [ "$(_time)" -le "$_end_time" ]; do + _left="" + for entry in $dns_entries; do + d=$(_getfield "$entry" 1) + txtdomain=$(_getfield "$entry" 2) + aliasDomain=$(_getfield "$entry" 3) + txt=$(_getfield "$entry" 5) + d_api=$(_getfield "$entry" 6) + _debug "d" "$d" + _debug "txtdomain" "$txtdomain" + _debug "aliasDomain" "$aliasDomain" + _debug "txt" "$txt" + _debug "d_api" "$d_api" + _info "Checking $d for $aliasDomain" + if _contains "$_success_txt" ",$txt,"; then + _info "Already success, continue next one." + continue + fi + + if __check_txt "$txtdomain" "$aliasDomain" "$txt"; then + _info "Domain $d '$aliasDomain' success." + _success_txt="$_success_txt,$txt," + continue + fi + _left=1 + _info "Not valid yet, let's wait 10 seconds and check next one." + _sleep 10 + __purge_txt "$txtdomain" + if [ "$txtdomain" != "$aliasDomain" ]; then + __purge_txt "$aliasDomain" + fi + done + if [ "$_left" ]; then + _info "Let's wait 10 seconds and check again". + _sleep 10 + else + _info "All success, let's return" + break + fi + done + +} + #webroot, domain domainlist keylength issue() { if [ -z "$2" ]; then @@ -3786,6 +3871,7 @@ $_authorizations_map" done _debug vlist "$vlist" #add entry + dns_entries="" dnsadded="" ventries=$(echo "$vlist" | tr "$dvsep" ' ') _alias_index=1 @@ -3816,8 +3902,10 @@ $_authorizations_map" else txtdomain="_acme-challenge.$_d_alias" fi + dns_entries="${dns_entries}${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$txtdomain$dvsep$_currentRoot" else txtdomain="_acme-challenge.$_dns_root_d" + dns_entries="${dns_entries}${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$dvsep$_currentRoot" fi _debug txtdomain "$txtdomain" txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" @@ -3826,7 +3914,9 @@ $_authorizations_map" d_api="$(_findHook "$_dns_root_d" dnsapi "$_currentRoot")" _debug d_api "$d_api" - + dns_entries="$dns_entries$dvsep$txt${dvsep}$d_api +" + _debug2 "$dns_entries" if [ "$d_api" ]; then _info "Found domain api file: $d_api" else @@ -3880,15 +3970,21 @@ $_authorizations_map" fi - if [ "$dnsadded" = '1' ]; then + if [ "$dns_entries" ]; then if [ -z "$Le_DNSSleep" ]; then - Le_DNSSleep="$DEFAULT_DNS_SLEEP" + _info "Let's check each dns records now. Sleep 20 seconds first." + _sleep 20 + if ! _check_dns_entries; then + _err "check dns error." + _on_issue_err "$_post_hook" + _clearup + return 1 + fi else _savedomainconf "Le_DNSSleep" "$Le_DNSSleep" + _info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect" + _sleep "$Le_DNSSleep" fi - - _info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect" - _sleep "$Le_DNSSleep" fi NGINX_RESTORE_VLIST="" From 16a0f40ac27b85180b55a383f8ceebf3a7cc342f Mon Sep 17 00:00:00 2001 From: Marcin Konicki Date: Wed, 20 Feb 2019 02:40:36 +0100 Subject: [PATCH 279/280] Support for MyDevil.net (#2076) support mydevil --- README.md | 1 + deploy/README.md | 10 +++++ deploy/mydevil.sh | 59 ++++++++++++++++++++++++++ dnsapi/README.md | 20 +++++++++ dnsapi/dns_mydevil.sh | 97 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 187 insertions(+) create mode 100755 deploy/mydevil.sh create mode 100755 dnsapi/dns_mydevil.sh diff --git a/README.md b/README.md index 8d749dc..f79b860 100644 --- a/README.md +++ b/README.md @@ -356,6 +356,7 @@ You don't have to do anything manually! 1. Futurehosting API (https://www.futurehosting.com) 1. Rackspace Cloud DNS (https://www.rackspace.com) 1. Online.net API (https://online.net/) +1. MyDevil.net (https://www.mydevil.net/) And: diff --git a/deploy/README.md b/deploy/README.md index 091e9fe..f290756 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -381,3 +381,13 @@ you want to update: $ export QINIU_CDN_DOMAIN="cdn.example.com" $ acme.sh --deploy -d example.com --deploy-hook qiniu ``` + +## 14. Deploy your cert on MyDevil.net + +Once you have acme.sh installed and certificate issued (see info in [DNS API](../dnsapi/README.md#61-use-mydevilnet)), you can install it by following command: + +```sh +acme.sh --deploy --deploy-hook mydevil -d example.com +``` + +That will remove old certificate and install new one. diff --git a/deploy/mydevil.sh b/deploy/mydevil.sh new file mode 100755 index 0000000..bd9868a --- /dev/null +++ b/deploy/mydevil.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env sh + +# MyDevil.net API (2019-02-03) +# +# MyDevil.net already supports automatic Let's Encrypt certificates, +# except for wildcard domains. +# +# This script depends on `devil` command that MyDevil.net provides, +# which means that it works only on server side. +# +# Author: Marcin Konicki +# +######## Public functions ##################### + +# Usage: mydevil_deploy domain keyfile certfile cafile fullchain +mydevil_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + ip="" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if ! _exists "devil"; then + _err "Could not find 'devil' command." + return 1 + fi + + ip=$(mydevil_get_ip "$_cdomain") + if [ -z "$ip" ]; then + _err "Could not find IP for domain $_cdomain." + return 1 + fi + + # Delete old certificate first + _info "Removing old certificate for $_cdomain at $ip" + devil ssl www del "$ip" "$_cdomain" + + # Add new certificate + _info "Adding new certificate for $_cdomain at $ip" + devil ssl www add "$ip" "$_cfullchain" "$_ckey" "$_cdomain" || return 1 + + return 0 +} + +#################### Private functions below ################################## + +# Usage: ip=$(mydevil_get_ip domain.com) +# echo $ip +mydevil_get_ip() { + devil dns list "$1" | cut -w -s -f 3,7 | grep "^A$(printf '\t')" | cut -w -s -f 2 || return 1 + return 0 +} diff --git a/dnsapi/README.md b/dnsapi/README.md index f022cab..9f176c0 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1259,6 +1259,26 @@ acme.sh --issue --dns dns_online -d example.com -d www.example.com `ONLINE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 66. Use MyDevil.net + +Make sure that you can execute own binaries: + +```sh +devil binexec on +``` + +Install acme.sh, or simply `git clone` it into some directory on your MyDevil host account (in which case you should link to it from your `~/bin` directory). + +If you're not using private IP and depend on default IP provided by host, you may want to edit `crontab` too, and make sure that `acme.sh --cron` is run also after reboot (you can find out how to do that on their wiki pages). + +To issue a new certificate, run: + +```sh +acme.sh --issue --dns dns_mydevil -d example.com -d *.example.com +``` + +After certificate is ready, you can install it with [deploy command](../deploy/README.md#14-deploy-your-cert-on-mydevilnet). + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_mydevil.sh b/dnsapi/dns_mydevil.sh new file mode 100755 index 0000000..2f39895 --- /dev/null +++ b/dnsapi/dns_mydevil.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env sh + +# MyDevil.net API (2019-02-03) +# +# MyDevil.net already supports automatic Let's Encrypt certificates, +# except for wildcard domains. +# +# This script depends on `devil` command that MyDevil.net provides, +# which means that it works only on server side. +# +# Author: Marcin Konicki +# +######## Public functions ##################### + +#Usage: dns_mydevil_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_mydevil_add() { + fulldomain=$1 + txtvalue=$2 + domain="" + + if ! _exists "devil"; then + _err "Could not find 'devil' command." + return 1 + fi + + _info "Using mydevil" + + domain=$(mydevil_get_domain "$fulldomain") + if [ -z "$domain" ]; then + _err "Invalid domain name: could not find root domain of $fulldomain." + return 1 + fi + + # No need to check if record name exists, `devil` always adds new record. + # In worst case scenario, we end up with multiple identical records. + + _info "Adding $fulldomain record for domain $domain" + if devil dns add "$domain" "$fulldomain" TXT "$txtvalue"; then + _info "Successfully added TXT record, ready for validation." + return 0 + else + _err "Unable to add DNS record." + return 1 + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_mydevil_rm() { + fulldomain=$1 + txtvalue=$2 + domain="" + + if ! _exists "devil"; then + _err "Could not find 'devil' command." + return 1 + fi + + _info "Using mydevil" + + domain=$(mydevil_get_domain "$fulldomain") + if [ -z "$domain" ]; then + _err "Invalid domain name: could not find root domain of $fulldomain." + return 1 + fi + + # catch one or more numbers + num='[0-9][0-9]*' + # catch one or more whitespace + w=$(printf '[\t ][\t ]*') + # catch anything, except newline + any='.*' + # filter to make sure we do not delete other records + validRecords="^${num}${w}${fulldomain}${w}TXT${w}${any}${txtvalue}$" + for id in $(devil dns list "$domain" | tail -n+2 | grep "${validRecords}" | cut -w -s -f 1); do + _info "Removing record $id from domain $domain" + devil dns del "$domain" "$id" || _err "Could not remove DNS record." + done +} + +#################### Private functions below ################################## + +# Usage: domain=$(mydevil_get_domain "_acme-challenge.www.domain.com" || _err "Invalid domain name") +# echo $domain +mydevil_get_domain() { + fulldomain=$1 + domain="" + + for domain in $(devil dns list | cut -w -s -f 1 | tail -n+2); do + if _endswith "$fulldomain" "$domain"; then + printf -- "%s" "$domain" + return 0 + fi + done + + return 1 +} From ec54074392561f3f697b489fb278445aee34ada5 Mon Sep 17 00:00:00 2001 From: Timothy Nelson Date: Mon, 25 Feb 2019 05:19:36 -0600 Subject: [PATCH 280/280] Fix verification for namecheap domains not *owned* by the calling user (#2106) --- dnsapi/dns_namecheap.sh | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index fbf93c3..6553deb 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -76,6 +76,22 @@ dns_namecheap_rm() { # _sub_domain=_acme-challenge.www # _domain=domain.com _get_root() { + fulldomain=$1 + + if ! _get_root_by_getList "$fulldomain"; then + _debug "Failed domain lookup via domains.getList api call. Trying domain lookup via domains.dns.getHosts api." + # The above "getList" api will only return hosts *owned* by the calling user. However, if the calling + # user is not the owner, but still has administrative rights, we must query the getHosts api directly. + # See this comment and the official namecheap response: http://disq.us/p/1q6v9x9 + if ! _get_root_by_getHosts "$fulldomain"; then + return 1 + fi + fi + + return 0 +} + +_get_root_by_getList() { domain=$1 if ! _namecheap_post "namecheap.domains.getList"; then @@ -94,6 +110,10 @@ _get_root() { #not valid return 1 fi + if ! _contains "$h" "\\."; then + #not valid + return 1 + fi if ! _contains "$response" "$h"; then _debug "$h not found" @@ -108,6 +128,31 @@ _get_root() { return 1 } +_get_root_by_getHosts() { + i=100 + p=99 + + while [ $p -ne 0 ]; do + + h=$(printf "%s" "$1" | cut -d . -f $i-100) + if [ -n "$h" ]; then + if _contains "$h" "\\."; then + _debug h "$h" + if _namecheap_set_tld_sld "$h"; then + _sub_domain=$(printf "%s" "$1" | cut -d . -f 1-$p) + _domain="$h" + return 0 + else + _debug "$h not found" + fi + fi + fi + i="$p" + p=$(_math "$p" - 1) + done + return 1 +} + _namecheap_set_publicip() { if [ -z "$NAMECHEAP_SOURCEIP" ]; then
$2.*?id=\K(\d*)") + if [ -n "$_id" ]; then + _debug "Entry found with _id=$_id" + return 0 + fi + return 1 +} From 1f25b4a8a94ad14999fd19b87a29ea3d4383c237 Mon Sep 17 00:00:00 2001 From: Herman Sletteng Date: Fri, 24 Aug 2018 00:18:04 +0200 Subject: [PATCH 146/280] Replacing "grep -o -P" with "_egrep_o" and sed --- dnsapi/dns_gdnsdk.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_gdnsdk.sh b/dnsapi/dns_gdnsdk.sh index 05a4c9f..7dc7894 100755 --- a/dnsapi/dns_gdnsdk.sh +++ b/dnsapi/dns_gdnsdk.sh @@ -137,7 +137,7 @@ _mypost() { _get_domain() { _myget 'action=dns_primarydns' - _domains=$(echo "$_result" | grep -o -P ' domain="\K([[:alnum:].-_]+)') + _domains=$(echo "$_result" | _egrep_o ' domain="[[:alnum:].-_]+' | sed 's/^.*"//') if [ -z "$_domains" ]; then _err "Primary domain list not found!" return 1 @@ -159,7 +159,7 @@ _successful_update() { _findentry() { #returns id of dns entry, if it exists _myget "action=dns_primary_changeDNSsetup&user_domain=$_domain" - _id=$(echo "$_result" | grep -o -P "$1$2.*?id=\K(\d*)") + _id=$(echo "$_result" | _egrep_o "$1$2