From b8a8e2280db53b68e405f0e37e45d2c569ad6639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20H=C3=A5land?= Date: Sun, 5 Mar 2017 13:43:01 +0100 Subject: [PATCH 001/565] Added deploy script to deploy to the routeros system --- deploy/README.md | 16 +++++++++++ deploy/routeros.sh | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 deploy/routeros.sh diff --git a/deploy/README.md b/deploy/README.md index 4a13e09..65d8cc2 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -72,3 +72,19 @@ export DEPLOY_EXIM4_RELOAD="/etc/init.d/exim4 restart" acme.sh --deploy -d ftp.example.com --deploy-hook exim4 ``` +## 6. Deploy the cert to remote routeros + +```sh +acme.sh --deploy -d ftp.example.com --deploy-hook routeros +``` + +Before you can deploy the certificate to router os, you need to add the id_rsa.pub key to the routeros and assign a user to that key. +The user need to have access to ssh, ftp, read and write. + +Then you need to set the environment variables for the deploy script to work. +```sh +export ROUTER_OS_USERNAME=certuser +export ROUTER_OS_HOST=router.example.com + +acme.sh --deploy -d ftp.example.com --deploy-hook routeros +``` diff --git a/deploy/routeros.sh b/deploy/routeros.sh new file mode 100644 index 0000000..e4e8c46 --- /dev/null +++ b/deploy/routeros.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +#Here is a script to deploy cert to routeros router. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +routeros_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 "$ROUTER_OS_HOST" ]; then + _err "Need to set the env variable ROUTER_OS_HOST" + return 1 + fi + + if [ -z "$ROUTER_OS_USERNAME" ]; then + _err "Need to set the env variable ROUTER_OS_USERNAME" + return 1 + fi + + _info "Trying to push key '$_ckey' to router" + scp $_ckey $ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain".key" + _info "Trying to push cert '$_ccert' to router" + scp $_ccert $ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain".cer" + _info "Trying to push ca cert '$_cca' to router" + scp $_cca $ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain".ca" + + ssh $ROUTER_OS_USERNAME@$ROUTER_OS_HOST bash -c "' + +/certificate remove $_cdomain.cer_0 + +/certificate remove $_cdomain.ca_0 + +delay 1 + +/certificate import file-name=$_cdomain.cer passphrase=\"\" + +/certificate import file-name=$_cdomain.ca passphrase=\"\" + +/certificate import file-name=$_cdomain.key passphrase=\"\" + +delay 1 + +/file remove $_cdomain.cer + +/file remove $_cdomain.key + +delay 2 + +/ip service set www-ssl certificate=$_cdomain.cer_0 + +'" + + + return 0 +} From 8a604bd2a172a15a58420ec401595c6604d8146f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20H=C3=A5land?= Date: Mon, 6 Mar 2017 19:39:55 +0100 Subject: [PATCH 002/565] Fixing syntax for schell script checking --- deploy/routeros.sh | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/deploy/routeros.sh b/deploy/routeros.sh index e4e8c46..9471ba8 100644 --- a/deploy/routeros.sh +++ b/deploy/routeros.sh @@ -31,38 +31,40 @@ routeros_deploy() { fi _info "Trying to push key '$_ckey' to router" - scp $_ckey $ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain".key" + scp "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key" _info "Trying to push cert '$_ccert' to router" - scp $_ccert $ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain".cer" + scp "$_ccert" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer" _info "Trying to push ca cert '$_cca' to router" - scp $_cca $ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain".ca" - - ssh $ROUTER_OS_USERNAME@$ROUTER_OS_HOST bash -c "' + scp "$_cca" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.ca" + # shellcheck disable=SC2029 + ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" bash -c "' /certificate remove $_cdomain.cer_0 +/certificate remove $_cdomain.cer_1 + /certificate remove $_cdomain.ca_0 delay 1 /certificate import file-name=$_cdomain.cer passphrase=\"\" -/certificate import file-name=$_cdomain.ca passphrase=\"\" - /certificate import file-name=$_cdomain.key passphrase=\"\" +/certificate import file-name=$_cdomain.ca passphrase=\"\" + delay 1 /file remove $_cdomain.cer /file remove $_cdomain.key +/file remove $_cdomain.ca + delay 2 /ip service set www-ssl certificate=$_cdomain.cer_0 '" - - return 0 } From 52351d7dc8f0cccf3139e16ea56e5f1d001e6deb Mon Sep 17 00:00:00 2001 From: martgras Date: Tue, 13 Mar 2018 12:43:07 +0100 Subject: [PATCH 003/565] 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 004/565] 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 e629985cf494b388fb23cc8dfc8c5a6179a45de7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20H=C3=A5land?= Date: Mon, 26 Mar 2018 07:41:56 +0200 Subject: [PATCH 005/565] Use _cdomain if ROUTER_OS_HOST is missing --- deploy/routeros.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/routeros.sh b/deploy/routeros.sh index 9471ba8..27fc377 100644 --- a/deploy/routeros.sh +++ b/deploy/routeros.sh @@ -21,8 +21,8 @@ routeros_deploy() { _debug _cfullchain "$_cfullchain" if [ -z "$ROUTER_OS_HOST" ]; then - _err "Need to set the env variable ROUTER_OS_HOST" - return 1 + _debug "Using _cdomain as ROUTER_OS_HOST, please set if not correct." + ROUTER_OS_HOST = "$_cdomain" fi if [ -z "$ROUTER_OS_USERNAME" ]; then From 7b327d47c0f2bae9f585030e10e1e847da43bc43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20H=C3=A5land?= Date: Mon, 26 Mar 2018 08:21:31 +0200 Subject: [PATCH 006/565] Fix documentation --- deploy/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/README.md b/deploy/README.md index 6ec033f..fd2a5fc 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -254,6 +254,7 @@ 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 remote routeros From d698c1093aba8d2c2361e3ad968fe15e25024a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20H=C3=A5land?= Date: Mon, 26 Mar 2018 08:24:04 +0200 Subject: [PATCH 007/565] remove spaces around assignment --- deploy/routeros.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/routeros.sh b/deploy/routeros.sh index 27fc377..1db74b4 100644 --- a/deploy/routeros.sh +++ b/deploy/routeros.sh @@ -22,7 +22,7 @@ routeros_deploy() { if [ -z "$ROUTER_OS_HOST" ]; then _debug "Using _cdomain as ROUTER_OS_HOST, please set if not correct." - ROUTER_OS_HOST = "$_cdomain" + ROUTER_OS_HOST="$_cdomain" fi if [ -z "$ROUTER_OS_USERNAME" ]; then From 8d38cf4d1f7e8e7059cb629b691a99aff88290c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20H=C3=A5land?= Date: Mon, 26 Mar 2018 22:00:01 +0200 Subject: [PATCH 008/565] Use allchain instead of ca an cert, add documentation after review --- deploy/README.md | 16 ++++++++++++++++ deploy/routeros.sh | 12 ++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index fd2a5fc..2693b6e 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -265,6 +265,8 @@ acme.sh --deploy -d ftp.example.com --deploy-hook routeros Before you can deploy the certificate to router os, you need to add the id_rsa.pub key to the routeros and assign a user to that key. The user need to have access to ssh, ftp, read and write. +There are no need to enable ftp service for the script to work, as they are transmitted over SCP, however ftp is needed to store the files on the router. + Then you need to set the environment variables for the deploy script to work. ```sh export ROUTER_OS_USERNAME=certuser @@ -272,3 +274,17 @@ export ROUTER_OS_HOST=router.example.com acme.sh --deploy -d ftp.example.com --deploy-hook routeros ``` + +The deploy script will remove previously deployed certificates, and it does this with an assumption on how RouterOS names imported certificates, adding a "cer_0" suffix at the end. This is true for versions 6.32 -> 6.41.3, but it is not guaranteed that it will be true for future versions when upgrading. + +If the router have other certificates with the same name as the one beeing deployed, then this script will remove those certificates. + +At the end of the script, the services that use those certificates could be updated. Currently only the www-ssl service is beeing updated, but more services could be added. + +For instance: +``` +/ip service set www-ssl certificate=$_cdomain.cer_0 +/ip service set api-ssl certificate=$_cdomain.cer_0 +``` + +One optional thing to do as well is to create a script that updates all the required services and run that script in a single command. diff --git a/deploy/routeros.sh b/deploy/routeros.sh index 1db74b4..d590bc9 100644 --- a/deploy/routeros.sh +++ b/deploy/routeros.sh @@ -32,10 +32,8 @@ routeros_deploy() { _info "Trying to push key '$_ckey' to router" scp "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key" - _info "Trying to push cert '$_ccert' to router" - scp "$_ccert" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer" - _info "Trying to push ca cert '$_cca' to router" - scp "$_cca" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.ca" + _info "Trying to push cert '$_cfullchain' to router" + scp "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer" # shellcheck disable=SC2029 ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" bash -c "' @@ -43,24 +41,18 @@ routeros_deploy() { /certificate remove $_cdomain.cer_1 -/certificate remove $_cdomain.ca_0 - delay 1 /certificate import file-name=$_cdomain.cer passphrase=\"\" /certificate import file-name=$_cdomain.key passphrase=\"\" -/certificate import file-name=$_cdomain.ca passphrase=\"\" - delay 1 /file remove $_cdomain.cer /file remove $_cdomain.key -/file remove $_cdomain.ca - delay 2 /ip service set www-ssl certificate=$_cdomain.cer_0 From e36fbd6af5c56b4672077694e7db9adebcb49d25 Mon Sep 17 00:00:00 2001 From: Grant Millar Date: Fri, 20 Apr 2018 09:41:07 +0100 Subject: [PATCH 009/565] 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 676402d918cb064999d05d33289e9f41fb3fe48a Mon Sep 17 00:00:00 2001 From: Kordian Bruck Date: Thu, 26 Apr 2018 11:40:17 +0200 Subject: [PATCH 010/565] 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 03a1386902fc38ce042c04e7af11c1fa629b6c58 Mon Sep 17 00:00:00 2001 From: Kordian Bruck Date: Wed, 2 May 2018 23:01:52 +0200 Subject: [PATCH 011/565] 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 c58465d6304afc7d4e1d052fdf3b70af8ce84a7e Mon Sep 17 00:00:00 2001 From: Vlad Roskov Date: Thu, 3 May 2018 00:57:50 +0300 Subject: [PATCH 012/565] fix comparison on empty var --- dnsapi/dns_yandex.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 318dee0..496fcde 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -54,7 +54,7 @@ _PDD_get_domain() { _debug2 "res1" "$res1" __found="$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p')" _debug "found: $__found results on page" - if [ "$__found" -lt 20 ]; then + if [ "0$__found" -lt 20 ]; then _debug "last page: $__page" __last=1 fi From f254bb39a541801d136f8e08dc973dbd5d9f3cda Mon Sep 17 00:00:00 2001 From: Vlad Roskov Date: Thu, 3 May 2018 00:58:25 +0300 Subject: [PATCH 013/565] bail out on no access --- dnsapi/dns_yandex.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 496fcde..fc122f0 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,7 +16,7 @@ dns_yandex_add() { _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" - _PDD_get_domain "$fulldomain" + _PDD_get_domain "$fulldomain" || return 1 _debug "Found suitable domain in pdd: $curDomain" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" @@ -33,7 +33,7 @@ dns_yandex_rm() { record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" - _PDD_get_domain "$fulldomain" + _PDD_get_domain "$fulldomain" || return 1 _debug "Found suitable domain in pdd: $curDomain" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" From 2f15ad4be091e4cf6ce1ea394f1ee6edb16ada38 Mon Sep 17 00:00:00 2001 From: Vlad Roskov Date: Thu, 3 May 2018 01:00:51 +0300 Subject: [PATCH 014/565] fix authentication --- dnsapi/dns_yandex.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index fc122f0..6d92809 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -30,12 +30,13 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" - record_id=$(pdd_get_record_id "${fulldomain}") - _debug "Result: $record_id" _PDD_get_domain "$fulldomain" || return 1 _debug "Found suitable domain in pdd: $curDomain" + record_id=$(pdd_get_record_id "${fulldomain}") + _debug "Result: $record_id" + curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" From f85348ba949f8a25f5cbdf9ca2252e91e5077c15 Mon Sep 17 00:00:00 2001 From: Vlad Roskov Date: Thu, 3 May 2018 01:01:14 +0300 Subject: [PATCH 015/565] fix delete multiple records --- dnsapi/dns_yandex.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 6d92809..a4f3978 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -37,10 +37,12 @@ dns_yandex_rm() { record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" - curUri="https://pddimp.yandex.ru/api2/admin/dns/del" - curData="domain=${curDomain}&record_id=${record_id}" - curResult="$(_post "${curData}" "${curUri}")" - _debug "Result: $curResult" + for rec_i in $record_id; do + curUri="https://pddimp.yandex.ru/api2/admin/dns/del" + curData="domain=${curDomain}&record_id=${rec_i}" + curResult="$(_post "${curData}" "${curUri}")" + _debug "Result: $curResult" + done } #################### Private functions below ################################## From 360dc140ea101a319973afeaead4cdb2a016f027 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Thu, 3 May 2018 01:28:56 -0500 Subject: [PATCH 016/565] 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 017/565] 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 018/565] 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 019/565] 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 020/565] 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 e9e999542d62ef30f417f84254264051060068a6 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Fri, 4 May 2018 10:14:31 -0500 Subject: [PATCH 021/565] 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 022/565] 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 023/565] 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 6567bb4c12d684f5856a96115777770ae762ccf3 Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Thu, 10 May 2018 11:51:59 +0800 Subject: [PATCH 024/565] Update haproxy deploy hook Add functionality to add OCSP stapling info (.ocsp file), issuer (.issuer file) and multi-cert bundles (suffix on pem file based on key type). This also corrects the order of key, certificate and intermediate in the PEM file, which although HAProxy does not seem to care, was incorrect in the prior version. --- deploy/haproxy.sh | 268 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 228 insertions(+), 40 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 5c1a40e..02f6a06 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -1,8 +1,32 @@ #!/usr/bin/env sh -#Here is a script to deploy cert to haproxy server. - -#returns 0 means success, otherwise error. +# Script for acme.sh to deploy certificates to haproxy +# +# The following variables can be exported: +# +# export DEPLOY_HAPROXY_PEM="" +# +# REQUIRED: Defines location of PEM file for HAProxy +# +# export DEPLOY_HAPROXY_RELOAD="systemctl reload haproxy" +# +# OPTIONAL: Reload command used post deploy +# +# export DEPLOY_HAPROXY_ISSUER="no" +# +# OPTIONAL: Places CA file as "${DEPLOY_HAPROXY_PEM}.issuer" +# Note: Required for OCSP stapling to work +# +# export DEPLOY_HAPROXY_BUNDLE="no" +# +# OPTIONAL: Deploy this certificate as part of a multi-cert bundle +# This adds a suffix to the certificate based on the certificate type +# eg RSA certificates will have .rsa as a suffix to the file name +# HAProxy will load all certificates and provide one or the other +# depending on client capabilities +# Note: This functionality requires HAProxy was compiled against +# a version of OpenSSL that supports this. +# ######## Public functions ##################### @@ -14,45 +38,209 @@ haproxy_deploy() { _cca="$4" _cfullchain="$5" - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - # 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 + # Some defaults + DEPLOY_HAPROXY_BUNDLE_DEFAULT="no" + DEPLOY_HAPROXY_ISSUER_DEFAULT="no" + DEPLOY_HAPROXY_RELOAD_DEFAULT="systemctl reload haproxy" + + if [ -f "${DOMAIN_CONF}" ]; then + # shellcheck disable=SC1090 + . "${DOMAIN_CONF}" + fi + + _debug _cdomain "${_cdomain}" + _debug _ckey "${_ckey}" + _debug _ccert "${_ccert}" + _debug _cca "${_cca}" + _debug _cfullchain "${_cfullchain}" + + # CERT is required + if [ -z "${DEPLOY_HAPROXY_PEM}" ]; then + if [ -z "${Le_Deploy_haproxy_pem}" ]; then + _err "{DEPLOY_HAPROXY_PEM} not defined." + return 1 + fi + else + Le_Deploy_haproxy_cert="${DEPLOY_HAPROXY_PEM}" + _savedomainconf Le_Deploy_haproxy_cert "${Le_Deploy_haproxy_pem}" + fi + + # BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}" + if [ -n "${DEPLOY_HAPROXY_BUNDLE}" ]; then + Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE}" + _savedomainconf Le_Deploy_haproxy_bundle "${Le_Deploy_haproxy_bundle}" + elif [ -z "${Le_Deploy_haproxy_bundle}" ]; then + Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE_DEFAULT}" + fi + + # ISSUER is optional. If not provided then assume "${DEPLOY_HAPROXY_ISSUER_DEFAULT}" + if [ -n "${DEPLOY_HAPROXY_ISSUER}" ]; then + Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER}" + _savedomainconf Le_Deploy_haproxy_issuer "${Le_Deploy_haproxy_issuer}" + elif [ -z "${Le_Deploy_haproxy_issuer}" ]; then + Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER_DEFAULT}" + fi + + # RELOAD is optional. If not provided then assume "${DEPLOY_HAPROXY_RELOAD_DEFAULT}" + if [ -n "${DEPLOY_HAPROXY_RELOAD}" ]; then + Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD}" + _savedomainconf Le_Deploy_haproxy_reload "${Le_Deploy_haproxy_reload}" + elif [ -z "${Le_Deploy_haproxy_reload}" ]; then + Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD_DEFAULT}" + fi + + # Set the suffix depending if we are creating a bundle or not + if [ "${Le_Deploy_haproxy_bundle}" = "yes" ]; then + _info "Bundle creation requested" + # Initialise $Le_KeyLength if its not already set + if [ -z "${Le_KeyLength}" ]; then + Le_KeyLength="" + fi + if _isEccKey "${Le_KeyLength}"; then + _info "ECC key type so set suffix to .ecc" + _suffix=".ecc" + else + _info "RSA key type so set suffix to .rsa" + _suffix=".rsa" + fi 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." - return 1 - fi - _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" - - # restart HAProxy - _info "Run reload: $_reload" - if eval "$_reload"; then - _info "Reload success!" - return 0 + _suffix="" + fi + + # Set variables for later + _pem="${Le_Deploy_haproxy_pem}${_suffix}" + _issuer="${_pem}.issuer" + _ocsp="${_pem}.ocsp" + _reload="${Le_Deploy_haproxy_reload}" + + _info "Deploying PEM file" + # Create a temporary PEM file + _temppem="$(_mktemp)" + _debug _temppem "${_temppem}" + cat "${_ckey}" "${_ccert}" "${_cca}" > "${_temppem}" + _ret="$?" + + # Check that we could create the temporary file + if [ "${_ret}" != "0" ]; then + _err "Error code ${_ret} returned during PEM file creation" + [ -f "${_temppem}" ] && rm -f "${_temppem}" + return ${_ret} + fi + + # Move PEM file into place + _info "Moving new certificate into place" + _debug _pem "${_pem}" + cat "${_temppem}" > "${_pem}" + _ret=$? + + # Clean up temp file + [ -f "${_temppem}" ] && rm -f "${_temppem}" + + # Deal with any failure of moving PEM file into place + if [ "${_ret}" != "0" ]; then + _err "Error code ${_ret} returned while moving new certificate into place" + return ${_ret} + fi + + # Update .issuer file if requested + if [ "${Le_Deploy_haproxy_issuer}" = "yes" ]; then + _info "Updating .issuer file" + _debug _issuer "${_issuer}" + cat "${_cca}" > "${_issuer}" + _ret="$?" + + if [ "${_ret}" != "0" ]; then + _err "Error code ${_ret} returned while copying issuer/CA certificate into place" + return ${_ret} + fi + else + [ -f "${_issuer}" ] _err "Issuer file update not requested but .issuer file exists" + fi + + # Update .ocsp file if certificate was requested with --ocsp/--ocsp-must-staple option + if [ -z "${Le_OCSP_Staple}" ]; then + Le_OCSP_Staple="0" + fi + if [ "${Le_OCSP_Staple}" = "1" ]; then + _info "Updating OCSP stapling info" + _debug _ocsp "${_ocsp}" + _info "Extracting OCSP URL" + _ocsp_url=$(openssl x509 -noout -ocsp_uri -in "${_pem}") + _debug _ocsp_url "${_ocsp_url}" + + # Only process OCSP if URL was present + if [ "${_ocsp_url}" != "" ]; then + # Extract the hostname from the OCSP URL + _info "Extracting OCSP URL" + _ocsp_host=$(echo "${_ocsp_url}" | cut -d/ -f3) + _debug _ocsp_host "${_ocsp_host}" + + # Only process the certificate if we have a .issuer file + if [ -r "${_issuer}" ]; then + # Check if issuer cert is also a root CA cert + _subjectdn=$(openssl x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10) + _debug _subjectdn "${_subjectdn}" + _issuerdn=$(openssl x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10) + _debug _issuerdn "${_issuerdn}" + _info "Requesting OCSP response" + # Request the OCSP response from the issuer and store it + if [ "${_subjectdn}" = "${_issuerdn}" ]; then + # If the issuer is a CA cert then our command line has "-CAfile" added + openssl ocsp \ + -issuer "${_issuer}" \ + -cert "${_pem}" \ + -url "${_ocsp_url}" \ + -header Host "${_ocsp_host}" \ + -respout "${_ocsp}" \ + -verify_other "${_issuer}" \ + -no_nonce \ + -CAfile "${_issuer}" + _ret=$? + else + # Issuer is not a root CA so no "-CAfile" option + openssl ocsp \ + -issuer "${_issuer}" \ + -cert "${_pem}" \ + -url "${_ocsp_url}" \ + -header Host "${_ocsp_host}" \ + -respout "${_ocsp}" \ + -verify_other "${_issuer}" \ + -no_nonce + _ret=$? + fi + else + # Non fatal: No issuer file was present so no OCSP stapling file created + _err "OCSP stapling in use but no .issuer file was present" + fi + else + # Non fatal: No OCSP url was found int the certificate + _err "OCSP update requested but no OCSP URL was found in certificate" + fi + + # Check return code of openssl command + if [ "${_ret}" != "0" ]; then + _err "Updating OCSP stapling failed with return code ${_ret}" + return ${_ret} + fi + else + # An OCSP file was already present but certificate did not have OCSP extension + if [ -f "${_ocsp}" ]; then + _err "OCSP was not requested but .ocsp file exists." + # Should remove the file at this step, although HAProxy just ignores it in this case + # rm -f "${_ocsp}" || _err "Problem removing stale .ocsp file" + fi + fi + + # Reload HAProxy + _debug _reload "${_reload}" + eval "${_reload}" + _ret=$? + if [ "${_ret}" != "0" ]; then + _info "Reload successful" else - _err "Reload error" - return 1 + _err "Error code ${_ret} during reload" + return ${_ret} fi + return 0 } From 3a95bfb699b602a5ce544f375a2aba5b266a3d94 Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Thu, 10 May 2018 12:02:58 +0800 Subject: [PATCH 025/565] Document updated haproxy deploy hook --- deploy/README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 181989d..621e15f 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -258,15 +258,27 @@ 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. +You must specify the file where you want the concatenated key and certificate chain written. ```sh -export DEPLOY_HAPROXY_PEM_PATH=/etc/haproxy +export DEPLOY_HAPROXY_PEM=/etc/haproxy/server.pem ``` 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" +export DEPLOY_HAPROXY_RELOAD="systemctl reload haproxy" +``` + +You may optionally specify that the issuer certificate is transferred to "${DEPLOY_HAPROXY_PEM}.issuer". This is a requirement to support OCSP stapling in HAProxy. The value shown below will be used as the default if you don't set this environment variable. + +```sh +export DEPLOY_HAPROXY_ISSUER="no" +``` + +You may optionally specify that you wish to support HAProxy's multi-cert bundle functionality. This allows serving of both RSA and ECC certificates on the same proxy. This adds a ".rsa" or ".ecc" suffix to the files generated (.pem, .ocsp and .issuer). The value shown below will be used as the default if you don't set this environment variable. + +```sh +export DEPLOY_HAPROXY_BUNDLE="no" ``` You can then deploy the certificate as follows From c47e67e52c95f18a0133413763287741c7d02865 Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Thu, 10 May 2018 12:06:25 +0800 Subject: [PATCH 026/565] Fix variable name --- deploy/haproxy.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 02f6a06..06bd74e 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -61,8 +61,8 @@ haproxy_deploy() { return 1 fi else - Le_Deploy_haproxy_cert="${DEPLOY_HAPROXY_PEM}" - _savedomainconf Le_Deploy_haproxy_cert "${Le_Deploy_haproxy_pem}" + Le_Deploy_haproxy_pem="${DEPLOY_HAPROXY_PEM}" + _savedomainconf Le_Deploy_haproxy_pem "${Le_Deploy_haproxy_pem}" fi # BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}" From 707e053949c839073c4b1f46db09a4ebb299aab5 Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Thu, 10 May 2018 12:18:03 +0800 Subject: [PATCH 027/565] whitespace fixes --- deploy/haproxy.sh | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 06bd74e..47a935b 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -117,7 +117,7 @@ haproxy_deploy() { # Create a temporary PEM file _temppem="$(_mktemp)" _debug _temppem "${_temppem}" - cat "${_ckey}" "${_ccert}" "${_cca}" > "${_temppem}" + cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}" _ret="$?" # Check that we could create the temporary file @@ -130,7 +130,7 @@ haproxy_deploy() { # Move PEM file into place _info "Moving new certificate into place" _debug _pem "${_pem}" - cat "${_temppem}" > "${_pem}" + cat "${_temppem}" >"${_pem}" _ret=$? # Clean up temp file @@ -146,7 +146,7 @@ haproxy_deploy() { if [ "${Le_Deploy_haproxy_issuer}" = "yes" ]; then _info "Updating .issuer file" _debug _issuer "${_issuer}" - cat "${_cca}" > "${_issuer}" + cat "${_cca}" >"${_issuer}" _ret="$?" if [ "${_ret}" != "0" ]; then @@ -187,25 +187,25 @@ haproxy_deploy() { if [ "${_subjectdn}" = "${_issuerdn}" ]; then # If the issuer is a CA cert then our command line has "-CAfile" added openssl ocsp \ - -issuer "${_issuer}" \ - -cert "${_pem}" \ - -url "${_ocsp_url}" \ - -header Host "${_ocsp_host}" \ - -respout "${_ocsp}" \ - -verify_other "${_issuer}" \ - -no_nonce \ - -CAfile "${_issuer}" + -issuer "${_issuer}" \ + -cert "${_pem}" \ + -url "${_ocsp_url}" \ + -header Host "${_ocsp_host}" \ + -respout "${_ocsp}" \ + -verify_other "${_issuer}" \ + -no_nonce \ + -CAfile "${_issuer}" _ret=$? else # Issuer is not a root CA so no "-CAfile" option openssl ocsp \ - -issuer "${_issuer}" \ - -cert "${_pem}" \ - -url "${_ocsp_url}" \ - -header Host "${_ocsp_host}" \ - -respout "${_ocsp}" \ - -verify_other "${_issuer}" \ - -no_nonce + -issuer "${_issuer}" \ + -cert "${_pem}" \ + -url "${_ocsp_url}" \ + -header Host "${_ocsp_host}" \ + -respout "${_ocsp}" \ + -verify_other "${_issuer}" \ + -no_nonce _ret=$? fi else @@ -219,8 +219,8 @@ haproxy_deploy() { # Check return code of openssl command if [ "${_ret}" != "0" ]; then - _err "Updating OCSP stapling failed with return code ${_ret}" - return ${_ret} + _err "Updating OCSP stapling failed with return code ${_ret}" + return ${_ret} fi else # An OCSP file was already present but certificate did not have OCSP extension @@ -228,7 +228,7 @@ haproxy_deploy() { _err "OCSP was not requested but .ocsp file exists." # Should remove the file at this step, although HAProxy just ignores it in this case # rm -f "${_ocsp}" || _err "Problem removing stale .ocsp file" - fi + fi fi # Reload HAProxy From ba20af48d32720fa011be9b27c6b5597cb32ff54 Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Thu, 10 May 2018 15:25:28 +0800 Subject: [PATCH 028/565] Support HAPROXY_DEPLOY_PEM_PATH Adds compatibility to original haproxy deploy hook while still allowing custom PEM file name (via HAPROXY_DEPLOY_PEM_NAME) --- deploy/haproxy.sh | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 47a935b..cadc8a6 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -4,9 +4,15 @@ # # The following variables can be exported: # -# export DEPLOY_HAPROXY_PEM="" +# export DEPLOY_HAPROXY_PEM_NAME="${domain}.pem" # -# REQUIRED: Defines location of PEM file for HAProxy +# Defines the name of the PEM file. +# Defaults to "domain.pem" +# +# export DEPLOY_HAPROXY_PEM_PATH="/etc/haproxy" +# +# Defines location of PEM file for HAProxy. +# Defaults to /etc/haproxy # # export DEPLOY_HAPROXY_RELOAD="systemctl reload haproxy" # @@ -39,6 +45,8 @@ haproxy_deploy() { _cfullchain="$5" # Some defaults + DEPLOY_HAPROXY_PEM_PATH_DEFAULT="/etc/haproxy" + DEPLOY_HAPROXY_PEM_NAME_DEFAULT="${_cdomain}.pem" DEPLOY_HAPROXY_BUNDLE_DEFAULT="no" DEPLOY_HAPROXY_ISSUER_DEFAULT="no" DEPLOY_HAPROXY_RELOAD_DEFAULT="systemctl reload haproxy" @@ -54,15 +62,28 @@ haproxy_deploy() { _debug _cca "${_cca}" _debug _cfullchain "${_cfullchain}" - # CERT is required - if [ -z "${DEPLOY_HAPROXY_PEM}" ]; then - if [ -z "${Le_Deploy_haproxy_pem}" ]; then - _err "{DEPLOY_HAPROXY_PEM} not defined." - return 1 - fi + # PEM_PATH is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}" + if [ -n "${DEPLOY_HAPROXY_PEM_PATH}" ]; then + Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH}" + _savedomainconf Le_Deploy_haproxy_pem_path "${Le_Deploy_haproxy_pem_path}" + elif [ -z "${Le_Deploy_haproxy_pem_path}" ]; then + Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}" + fi + + # Ensure PEM_PATH exists + if [ -d "${Le_Deploy_haproxy_pem_path}" ]; then + _debug "PEM_PATH ${Le_Deploy_haproxy_pem_path} exists" else - Le_Deploy_haproxy_pem="${DEPLOY_HAPROXY_PEM}" - _savedomainconf Le_Deploy_haproxy_pem "${Le_Deploy_haproxy_pem}" + _err "PEM_PATH ${Le_Deploy_haproxy_pem_path} does not exist" + return 1 + fi + + # PEM_NAME is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}" + if [ -n "${DEPLOY_HAPROXY_PEM_NAME}" ]; then + Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME}" + _savedomainconf Le_Deploy_haproxy_pem_name "${Le_Deploy_haproxy_pem_name}" + elif [ -z "${Le_Deploy_haproxy_pem_name}" ]; then + Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}" fi # BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}" @@ -108,7 +129,7 @@ haproxy_deploy() { fi # Set variables for later - _pem="${Le_Deploy_haproxy_pem}${_suffix}" + _pem="${Le_Deploy_haproxy_pem_path}/${Le_Deploy_haproxy_pem_name}${_suffix}" _issuer="${_pem}.issuer" _ocsp="${_pem}.ocsp" _reload="${Le_Deploy_haproxy_reload}" From 675e2d25d6f7c75745d866c6b08f9414977134a4 Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Thu, 10 May 2018 15:28:54 +0800 Subject: [PATCH 029/565] update for new haproxy deploy vars --- deploy/README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 621e15f..7b058c4 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -258,9 +258,16 @@ acme.sh --deploy -d ftp.example.com --deploy-hook strongswan ## 10. Deploy the cert to HAProxy -You must specify the file where you want the concatenated key and certificate chain written. +You may specify the directory where you want the concatenated key and certificate chain written. The value shown below will be used as the default if you don't set this environment variable. + +```sh +export DEPLOY_HAPROXY_PEM_PATH=/etc/haproxy +``` + +You may optionally specify the file name where you want the concatenated key and certificate chain written. The value shown below will be used as the default if you don't set this environment variable. + ```sh -export DEPLOY_HAPROXY_PEM=/etc/haproxy/server.pem +export DEPLOY_HAPROXY_PEM_PATH=$domain ``` 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. From 08d29a8342309e4c4a7c9a63c88af9d2dea26735 Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Mon, 14 May 2018 10:58:46 +0800 Subject: [PATCH 030/565] Fix return from reload --- deploy/haproxy.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index cadc8a6..cf5dc32 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -257,10 +257,10 @@ haproxy_deploy() { eval "${_reload}" _ret=$? if [ "${_ret}" != "0" ]; then - _info "Reload successful" - else _err "Error code ${_ret} during reload" return ${_ret} + else + _info "Reload successful" fi return 0 From 733b4e0a342d2bb2096b9e88e8ca7b93ba2449d5 Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Mon, 14 May 2018 11:26:03 +0800 Subject: [PATCH 031/565] Fix Le_Keylength case --- deploy/haproxy.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index cf5dc32..75e76ef 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -113,11 +113,11 @@ haproxy_deploy() { # Set the suffix depending if we are creating a bundle or not if [ "${Le_Deploy_haproxy_bundle}" = "yes" ]; then _info "Bundle creation requested" - # Initialise $Le_KeyLength if its not already set - if [ -z "${Le_KeyLength}" ]; then - Le_KeyLength="" + # Initialise $Le_Keylength if its not already set + if [ -z "${Le_Keylength}" ]; then + Le_Keylength="" fi - if _isEccKey "${Le_KeyLength}"; then + if _isEccKey "${Le_Keylength}"; then _info "ECC key type so set suffix to .ecc" _suffix=".ecc" else From 7d19d784dfd34691cca574c26ef004e6df303e9a Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Mon, 14 May 2018 13:16:56 +0800 Subject: [PATCH 032/565] Update cert suffix for bundles .ocsp generation --- deploy/haproxy.sh | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 75e76ef..0f5874d 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -118,15 +118,16 @@ haproxy_deploy() { Le_Keylength="" fi if _isEccKey "${Le_Keylength}"; then - _info "ECC key type so set suffix to .ecc" - _suffix=".ecc" + _info "ECC key type detected" + _suffix=".ecdsa" else - _info "RSA key type so set suffix to .rsa" + _info "RSA key type detected" _suffix=".rsa" fi else _suffix="" fi + _debug _suffix "${_suffix}" # Set variables for later _pem="${Le_Deploy_haproxy_pem_path}/${Le_Deploy_haproxy_pem_name}${_suffix}" @@ -215,7 +216,8 @@ haproxy_deploy() { -respout "${_ocsp}" \ -verify_other "${_issuer}" \ -no_nonce \ - -CAfile "${_issuer}" + -CAfile "${_issuer}" | \ + grep -q "${_pem}: good" _ret=$? else # Issuer is not a root CA so no "-CAfile" option @@ -226,7 +228,8 @@ haproxy_deploy() { -header Host "${_ocsp_host}" \ -respout "${_ocsp}" \ -verify_other "${_issuer}" \ - -no_nonce + -no_nonce | \ + grep -q "${_pem}: good" _ret=$? fi else @@ -238,10 +241,9 @@ haproxy_deploy() { _err "OCSP update requested but no OCSP URL was found in certificate" fi - # Check return code of openssl command + # Non fatal: Check return code of openssl command if [ "${_ret}" != "0" ]; then _err "Updating OCSP stapling failed with return code ${_ret}" - return ${_ret} fi else # An OCSP file was already present but certificate did not have OCSP extension From 8d348954a7f9af9418727159f5c4376133c06a60 Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Mon, 14 May 2018 13:22:46 +0800 Subject: [PATCH 033/565] Whitepspace --- deploy/haproxy.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 0f5874d..f6e3716 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -216,8 +216,8 @@ haproxy_deploy() { -respout "${_ocsp}" \ -verify_other "${_issuer}" \ -no_nonce \ - -CAfile "${_issuer}" | \ - grep -q "${_pem}: good" + -CAfile "${_issuer}" \ + | grep -q "${_pem}: good" _ret=$? else # Issuer is not a root CA so no "-CAfile" option @@ -228,8 +228,8 @@ haproxy_deploy() { -header Host "${_ocsp_host}" \ -respout "${_ocsp}" \ -verify_other "${_issuer}" \ - -no_nonce | \ - grep -q "${_pem}: good" + -no_nonce \ + | grep -q "${_pem}: good" _ret=$? fi else 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 034/565] 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 035/565] 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 036/565] 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 037/565] 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 038/565] 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 039/565] 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 040/565] 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 041/565] 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 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 042/565] 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 043/565] 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 044/565] 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 045/565] 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 046/565] 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 047/565] 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 048/565] 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 049/565] 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 050/565] 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 051/565] 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 052/565] 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 053/565] 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 054/565] 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 055/565] 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 056/565] 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 057/565] 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 058/565] 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 059/565] 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 060/565] 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 061/565] 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 062/565] 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 063/565] 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 064/565] 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 065/565] 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 066/565] 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 067/565] 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 068/565] 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 069/565] 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 070/565] 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 071/565] 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 072/565] 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 073/565] 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 074/565] 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 075/565] 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 076/565] 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 077/565] 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 078/565] 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 079/565] 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 080/565] 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 081/565] 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 082/565] 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 083/565] 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 084/565] 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 085/565] 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 086/565] 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 087/565] 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 088/565] 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 089/565] 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 090/565] 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 091/565] 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 092/565] 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 093/565] 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 094/565] 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 095/565] 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 096/565] 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 097/565] 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 098/565] 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 099/565] 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*$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 100/565] 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\s*$2.*?id=\K(\d*)") + _id=$(echo "$_result" | _egrep_o "$1\s*$2[^?]*[^&]*&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 101/565] 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 102/565] 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 103/565] 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 104/565] 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 105/565] 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 106/565] 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 107/565] 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 108/565] 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 109/565] 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 110/565] 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 111/565] 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 112/565] 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 113/565] 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 114/565] [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 115/565] 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 116/565] 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 31d9ba7e02777cfd1492f2cfeea2db1bd78b9867 Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Fri, 28 Sep 2018 08:45:18 +0800 Subject: [PATCH 117/565] Change default for reload --- deploy/haproxy.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index f6e3716..0318c23 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -17,6 +17,9 @@ # export DEPLOY_HAPROXY_RELOAD="systemctl reload haproxy" # # OPTIONAL: Reload command used post deploy +# This defaults to be a no-op (ie "true"). +# It is strongly recommended to set this something that makes sense +# for your distro. # # export DEPLOY_HAPROXY_ISSUER="no" # @@ -249,7 +252,7 @@ haproxy_deploy() { # An OCSP file was already present but certificate did not have OCSP extension if [ -f "${_ocsp}" ]; then _err "OCSP was not requested but .ocsp file exists." - # Should remove the file at this step, although HAProxy just ignores it in this case + # Could remove the file at this step, although HAProxy just ignores it in this case # rm -f "${_ocsp}" || _err "Problem removing stale .ocsp file" fi fi From 0a4e61c1dd421f1e36eb9945891c1e1a0ac2d848 Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Fri, 28 Sep 2018 08:46:39 +0800 Subject: [PATCH 118/565] Readme update --- deploy/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 7b058c4..8cefeff 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -267,13 +267,13 @@ export DEPLOY_HAPROXY_PEM_PATH=/etc/haproxy You may optionally specify the file name where you want the concatenated key and certificate chain written. The value shown below will be used as the default if you don't set this environment variable. ```sh -export DEPLOY_HAPROXY_PEM_PATH=$domain +export DEPLOY_HAPROXY_PEM_NAME=$domain ``` 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="systemctl reload haproxy" +export DEPLOY_HAPROXY_RELOAD="true" ``` You may optionally specify that the issuer certificate is transferred to "${DEPLOY_HAPROXY_PEM}.issuer". This is a requirement to support OCSP stapling in HAProxy. The value shown below will be used as the default if you don't set this environment variable. From 454c90820d56db2d62d0315d4232eefecbc2cc8a Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Fri, 28 Sep 2018 08:57:13 +0800 Subject: [PATCH 119/565] Actually set reload default --- deploy/haproxy.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 0318c23..2479aeb 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -7,7 +7,7 @@ # export DEPLOY_HAPROXY_PEM_NAME="${domain}.pem" # # Defines the name of the PEM file. -# Defaults to "domain.pem" +# Defaults to ".pem" # # export DEPLOY_HAPROXY_PEM_PATH="/etc/haproxy" # @@ -52,7 +52,7 @@ haproxy_deploy() { DEPLOY_HAPROXY_PEM_NAME_DEFAULT="${_cdomain}.pem" DEPLOY_HAPROXY_BUNDLE_DEFAULT="no" DEPLOY_HAPROXY_ISSUER_DEFAULT="no" - DEPLOY_HAPROXY_RELOAD_DEFAULT="systemctl reload haproxy" + DEPLOY_HAPROXY_RELOAD_DEFAULT="true" if [ -f "${DOMAIN_CONF}" ]; then # shellcheck disable=SC1090 From 4c1f70af4b27781a3f5055328f704a268fb8a5d4 Mon Sep 17 00:00:00 2001 From: evoadmin Date: Tue, 2 Oct 2018 10:43:25 +0300 Subject: [PATCH 120/565] 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 475e6e28eb1eb998f37adcfa09f22faa869a7d9a Mon Sep 17 00:00:00 2001 From: Ne-Lexa Date: Fri, 12 Oct 2018 19:04:18 +0300 Subject: [PATCH 121/565] Added dns api support for internet.bs --- README.md | 1 + dnsapi/dns_internetbs.sh | 173 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100755 dnsapi/dns_internetbs.sh diff --git a/README.md b/README.md index b9a5cc5..b0c2d02 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. Internet.bs API (https://internetbs.net/) And: diff --git a/dnsapi/dns_internetbs.sh b/dnsapi/dns_internetbs.sh new file mode 100755 index 0000000..bf227e3 --- /dev/null +++ b/dnsapi/dns_internetbs.sh @@ -0,0 +1,173 @@ +#!/usr/bin/env sh + +#This is the Internet.BS api wrapper for acme.sh +# +#Author: Ne-Lexa +#Report Bugs here: https://github.com/Ne-Lexa/acme.sh + +#INTERNETBS_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" +#INTERNETBS_API_PASSWORD="sdfsdfsdfljlbjkljlkjsdfoiwje" +INTERNETBS_API_URL="https://api.internet.bs" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_internetbs_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$INTERNETBS_API_KEY" ] || [ -z "$INTERNETBS_API_PASSWORD" ]; then + INTERNETBS_API_KEY="" + INTERNETBS_API_PASSWORD="" + _err "You didn't specify the INTERNET.BS api key and password yet." + _err "Please create you key and try again." + return 1 + fi + + _saveaccountconf INTERNETBS_API_KEY "$INTERNETBS_API_KEY" + _saveaccountconf INTERNETBS_API_PASSWORD "$INTERNETBS_API_PASSWORD" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + # https://testapi.internet.bs/Domain/DnsRecord/Add?ApiKey=testapi&Password=testpass&FullRecordName=w3.test-api-domain7.net&Type=CNAME&Value=www.internet.bs%&ResponseFormat=json + if _internetbs_rest POST "Domain/DnsRecord/Add" "FullRecordName=${_sub_domain}.${_domain}&Type=TXT&Value=${txtvalue}&ResponseFormat=json"; then + if ! _contains "$response" "\"status\":\"SUCCESS\""; then + _err "ERROR add TXT record" + _err "$response" + _clearaccountconf INTERNETBS_API_KEY + _clearaccountconf INTERNETBS_API_PASSWORD + return 1 + fi + + _info "txt record add success." + return 0 + fi + + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_internetbs_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + # https://testapi.internet.bs/Domain/DnsRecord/List?ApiKey=testapi&Password=testpass&Domain=test-api-domain7.net&FilterType=CNAME&ResponseFormat=json + _internetbs_rest POST "Domain/DnsRecord/List" "Domain=$_domain&FilterType=TXT&ResponseFormat=json" + + if ! _contains "$response" "\"status\":\"SUCCESS\""; then + _err "ERROR list dns records" + _err "$response" + _clearaccountconf INTERNETBS_API_KEY + _clearaccountconf INTERNETBS_API_PASSWORD + return 1 + fi + + if _contains "$response" "\name\":\"${_sub_domain}.${_domain}\""; then + _info "txt record find." + + # https://testapi.internet.bs/Domain/DnsRecord/Remove?ApiKey=testapi&Password=testpass&FullRecordName=www.test-api-domain7.net&Type=cname&ResponseFormat=json + _internetbs_rest POST "Domain/DnsRecord/Remove" "FullRecordName=${_sub_domain}.${_domain}&Type=TXT&ResponseFormat=json" + + if ! _contains "$response" "\"status\":\"SUCCESS\""; then + _err "ERROR remove dns record" + _err "$response" + _clearaccountconf INTERNETBS_API_KEY + _clearaccountconf INTERNETBS_API_PASSWORD + return 1 + fi + + _info "txt record deleted success." + return 0 + fi + + return 1 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=12345 +_get_root() { + domain=$1 + i=2 + p=1 + + # https://testapi.internet.bs/Domain/List?ApiKey=testapi&Password=testpass&CompactList=yes&ResponseFormat=json + if _internetbs_rest POST "Domain/List" "CompactList=yes&ResponseFormat=json"; then + + if ! _contains "$response" "\"status\":\"SUCCESS\""; then + _err "ERROR fetch domain list" + _err "$response" + _clearaccountconf INTERNETBS_API_KEY + _clearaccountconf INTERNETBS_API_PASSWORD + return 1 + fi + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f ${i}-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"$h\""; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-${p}) + _domain=${h} + return 0 + fi + + p=i + i=$(_math "$i" + 1) + done + fi + return 1 +} + +#Usage: method URI data +_internetbs_rest() { + m="$1" + ep="$2" + data="$3" + url="${INTERNETBS_API_URL}/${ep}" + + _debug url "$url" + + apiKey="$(printf "%s" "${INTERNETBS_API_KEY}" | _url_encode)" + password="$(printf "%s" "${INTERNETBS_API_PASSWORD}" | _url_encode)" + + if [ "$m" = "GET" ]; then + response="$(_get "${url}?ApiKey=${apiKey}&Password=${password}&${data}" | tr -d '\r')" + else + _debug2 data "$data" + response="$(_post "$data" "${url}?ApiKey=${apiKey}&Password=${password}" | tr -d '\r')" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + + _debug2 response "$response" + return 0 +} From fdb9d93b1211b673ddf9589f367343256ba677a3 Mon Sep 17 00:00:00 2001 From: Ne-Lexa Date: Fri, 12 Oct 2018 19:27:41 +0300 Subject: [PATCH 122/565] formatted --- dnsapi/dns_internetbs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_internetbs.sh b/dnsapi/dns_internetbs.sh index bf227e3..ba17083 100755 --- a/dnsapi/dns_internetbs.sh +++ b/dnsapi/dns_internetbs.sh @@ -69,7 +69,7 @@ dns_internetbs_rm() { _debug _domain "$_domain" _debug "Getting txt records" - # https://testapi.internet.bs/Domain/DnsRecord/List?ApiKey=testapi&Password=testpass&Domain=test-api-domain7.net&FilterType=CNAME&ResponseFormat=json + # https://testapi.internet.bs/Domain/DnsRecord/List?ApiKey=testapi&Password=testpass&Domain=test-api-domain7.net&FilterType=CNAME&ResponseFormat=json _internetbs_rest POST "Domain/DnsRecord/List" "Domain=$_domain&FilterType=TXT&ResponseFormat=json" if ! _contains "$response" "\"status\":\"SUCCESS\""; then From 9f6f721a133a30ea135d33ea004d30ffbac31de8 Mon Sep 17 00:00:00 2001 From: Ephen Date: Mon, 15 Oct 2018 17:11:25 +0800 Subject: [PATCH 123/565] 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 a63dc75b43414d0d553cf89ee3a82e613420739d Mon Sep 17 00:00:00 2001 From: Ne-Lexa Date: Mon, 15 Oct 2018 18:20:26 +0300 Subject: [PATCH 124/565] Added documentation on using dns api internet.bs --- dnsapi/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 2cecfa5..0f86758 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 Internet.bs + +First you need to create/obtain API credentials on your Internet.bs (https://internetbs.net) account. Go to the "Get my API Key" section in the "My Domains" section. + +``` +export INTERNETBS_API_KEY="..." +export INTERNETBS_API_PASSWORD="..." +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_internetbs -d example.com -d www.example.com +``` + +The `INTERNETBS_API_KEY` and `INTERNETBS_API_PASSWORD` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. From fd536d373ebd65eecf8ce8e2f760ef186e5ce74f Mon Sep 17 00:00:00 2001 From: Phil Ross Date: Thu, 18 Oct 2018 17:12:06 +0100 Subject: [PATCH 125/565] 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 126/565] 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 127/565] 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 128/565] 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 a207199879a21c58433273f7461bf4a464d7a8f9 Mon Sep 17 00:00:00 2001 From: Ne-Lexa Date: Mon, 29 Oct 2018 15:18:43 +0300 Subject: [PATCH 129/565] fixed _get_root() function --- dnsapi/dns_internetbs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_internetbs.sh b/dnsapi/dns_internetbs.sh index ba17083..05a1ada 100755 --- a/dnsapi/dns_internetbs.sh +++ b/dnsapi/dns_internetbs.sh @@ -137,7 +137,7 @@ _get_root() { return 0 fi - p=i + p=${i} i=$(_math "$i" + 1) done fi From 9672c6b885a100a9c83ce1651591271a5f3e2b2a Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 30 Oct 2018 22:14:49 +0800 Subject: [PATCH 130/565] 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 131/565] 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 132/565] 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 133/565] 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 134/565] 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 135/565] 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 136/565] 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 137/565] 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 138/565] 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 139/565] 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 140/565] 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 141/565] 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 142/565] 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 143/565] 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 144/565] 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 145/565] 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 146/565] 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 147/565] 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 148/565] 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 149/565] 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 150/565] 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 151/565] 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 152/565] 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 153/565] 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 154/565] 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 155/565] 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 156/565] 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 157/565] 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 158/565] 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 159/565] 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 160/565] 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 161/565] 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 162/565] 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 163/565] 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 164/565] 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 0b363a5c98d56df8c45a689ccc55087484f64306 Mon Sep 17 00:00:00 2001 From: Ne-Lexa Date: Mon, 24 Dec 2018 13:33:25 +0300 Subject: [PATCH 165/565] removed the _clearaccountconf() call for erroneous requests --- dnsapi/dns_internetbs.sh | 8 -------- 1 file changed, 8 deletions(-) diff --git a/dnsapi/dns_internetbs.sh b/dnsapi/dns_internetbs.sh index 05a1ada..d25c832 100755 --- a/dnsapi/dns_internetbs.sh +++ b/dnsapi/dns_internetbs.sh @@ -41,8 +41,6 @@ dns_internetbs_add() { if ! _contains "$response" "\"status\":\"SUCCESS\""; then _err "ERROR add TXT record" _err "$response" - _clearaccountconf INTERNETBS_API_KEY - _clearaccountconf INTERNETBS_API_PASSWORD return 1 fi @@ -75,8 +73,6 @@ dns_internetbs_rm() { if ! _contains "$response" "\"status\":\"SUCCESS\""; then _err "ERROR list dns records" _err "$response" - _clearaccountconf INTERNETBS_API_KEY - _clearaccountconf INTERNETBS_API_PASSWORD return 1 fi @@ -89,8 +85,6 @@ dns_internetbs_rm() { if ! _contains "$response" "\"status\":\"SUCCESS\""; then _err "ERROR remove dns record" _err "$response" - _clearaccountconf INTERNETBS_API_KEY - _clearaccountconf INTERNETBS_API_PASSWORD return 1 fi @@ -118,8 +112,6 @@ _get_root() { if ! _contains "$response" "\"status\":\"SUCCESS\""; then _err "ERROR fetch domain list" _err "$response" - _clearaccountconf INTERNETBS_API_KEY - _clearaccountconf INTERNETBS_API_PASSWORD return 1 fi From b7b94e38ac7c3183d3c6d0bd8709dd9d8fdd589d Mon Sep 17 00:00:00 2001 From: Ne-Lexa Date: Mon, 24 Dec 2018 14:59:14 +0300 Subject: [PATCH 166/565] support change account conf from env --- dnsapi/dns_internetbs.sh | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_internetbs.sh b/dnsapi/dns_internetbs.sh index d25c832..ae6b9e1 100755 --- a/dnsapi/dns_internetbs.sh +++ b/dnsapi/dns_internetbs.sh @@ -7,6 +7,7 @@ #INTERNETBS_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" #INTERNETBS_API_PASSWORD="sdfsdfsdfljlbjkljlkjsdfoiwje" + INTERNETBS_API_URL="https://api.internet.bs" ######## Public functions ##################### @@ -16,6 +17,9 @@ dns_internetbs_add() { fulldomain=$1 txtvalue=$2 + INTERNETBS_API_KEY="${INTERNETBS_API_KEY:-$(_readaccountconf_mutable INTERNETBS_API_KEY)}" + INTERNETBS_API_PASSWORD="${INTERNETBS_API_PASSWORD:-$(_readaccountconf_mutable INTERNETBS_API_PASSWORD)}" + if [ -z "$INTERNETBS_API_KEY" ] || [ -z "$INTERNETBS_API_PASSWORD" ]; then INTERNETBS_API_KEY="" INTERNETBS_API_PASSWORD="" @@ -24,8 +28,8 @@ dns_internetbs_add() { return 1 fi - _saveaccountconf INTERNETBS_API_KEY "$INTERNETBS_API_KEY" - _saveaccountconf INTERNETBS_API_PASSWORD "$INTERNETBS_API_PASSWORD" + _saveaccountconf_mutable INTERNETBS_API_KEY "$INTERNETBS_API_KEY" + _saveaccountconf_mutable INTERNETBS_API_PASSWORD "$INTERNETBS_API_PASSWORD" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -57,6 +61,17 @@ dns_internetbs_rm() { fulldomain=$1 txtvalue=$2 + INTERNETBS_API_KEY="${INTERNETBS_API_KEY:-$(_readaccountconf_mutable INTERNETBS_API_KEY)}" + INTERNETBS_API_PASSWORD="${INTERNETBS_API_PASSWORD:-$(_readaccountconf_mutable INTERNETBS_API_PASSWORD)}" + + if [ -z "$INTERNETBS_API_KEY" ] || [ -z "$INTERNETBS_API_PASSWORD" ]; then + INTERNETBS_API_KEY="" + INTERNETBS_API_PASSWORD="" + _err "You didn't specify the INTERNET.BS api key and password yet." + _err "Please create you key and try again." + return 1 + fi + _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" From 2671af13cdfb592f56c5de1ffdbe438f79db72d8 Mon Sep 17 00:00:00 2001 From: Ketil Date: Thu, 27 Dec 2018 15:17:19 +0100 Subject: [PATCH 167/565] 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 168/565] 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 169/565] 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 170/565] 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 171/565] 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 172/565] 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 173/565] 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 174/565] 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 175/565] 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 176/565] 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 177/565] [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 178/565] 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 179/565] 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 180/565] 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 181/565] 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 182/565] 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 183/565] 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 184/565] 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 185/565] 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 186/565] 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 187/565] 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 188/565] 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 189/565] 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 190/565] 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 191/565] 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 192/565] 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 193/565] 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 194/565] 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 195/565] 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 196/565] 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 197/565] 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 198/565] 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 199/565] 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 200/565] 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 201/565] 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 202/565] 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 203/565] 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 204/565] 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 205/565] 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 206/565] 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 207/565] 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 208/565] 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 209/565] 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 210/565] 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 211/565] 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 212/565] 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 213/565] 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 214/565] 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 215/565] 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 216/565] 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 217/565] 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 218/565] 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 219/565] 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 220/565] 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 221/565] 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 222/565] 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 223/565] 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 224/565] 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 1167cdcaec8e21dfd68bd2300412a733658b258d Mon Sep 17 00:00:00 2001 From: Sebastiaan Hoogeveen Date: Tue, 5 Feb 2019 16:32:41 +0100 Subject: [PATCH 225/565] Added DNS API support for NederHost (https://www.nederhost.nl/) --- dnsapi/dns_nederhost.sh | 133 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100755 dnsapi/dns_nederhost.sh diff --git a/dnsapi/dns_nederhost.sh b/dnsapi/dns_nederhost.sh new file mode 100755 index 0000000..32357f8 --- /dev/null +++ b/dnsapi/dns_nederhost.sh @@ -0,0 +1,133 @@ +#!/usr/bin/env sh + +#NederHost_Key="sdfgikogfdfghjklkjhgfcdcfghjk" + +NederHost_Api="https://api.nederhost.nl/dns/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_nederhost_add() { + fulldomain=$1 + txtvalue=$2 + + NederHost_Key="${NederHost_Key:-$(_readaccountconf_mutable NederHost_Key)}" + if [ -z "$NederHost_Key" ]; then + NederHost_Key="" + _err "You didn't specify a NederHost api key." + _err "You can get yours from https://www.nederhost.nl/mijn_nederhost" + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable NederHost_Key "$NederHost_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + if _nederhost_rest PATCH "zones/$_domain/records/$fulldomain/TXT" "[{\"content\":\"$txtvalue\",\"ttl\":60}]"; then + if _contains "$response" "$fulldomain"; 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_nederhost_rm() { + fulldomain=$1 + txtvalue=$2 + + NederHost_Key="${NederHost_Key:-$(_readaccountconf_mutable NederHost_Key)}" + if [ -z "$NederHost_Key" ]; then + NederHost_Key="" + _err "You didn't specify a NederHost api key." + _err "You can get yours from https://www.nederhost.nl/mijn_nederhost" + 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 "Removing txt record" + _nederhost_rest DELETE "zones/${_domain}/records/$fulldomain/TXT?content=$txtvalue" + +} + +#################### 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 + _domain=$(printf "%s" "$domain" | cut -d . -f $i-100) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _debug _domain "$_domain" + if [ -z "$_domain" ]; then + #not valid + return 1 + fi + + if _nederhost_rest GET "zones/${_domain}"; then + if [ "${_code}" == "204" ]; then + return 0; + fi + else + return 1; + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_nederhost_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Authorization: Bearer $NederHost_Key" + export _H2="Content-Type: application/json" + + :>$HTTP_HEADER + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$NederHost_Api/$ep" "" "$m")" + else + response="$(_get "$NederHost_Api/$ep")" + fi + + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + _debug "http response code $_code" + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From b3e3e080a9a18c005384942de6616fe076e8a8d4 Mon Sep 17 00:00:00 2001 From: Sebastiaan Hoogeveen Date: Tue, 5 Feb 2019 16:37:08 +0100 Subject: [PATCH 226/565] Cleaned up some of the comments from shellcheck. --- dnsapi/dns_nederhost.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_nederhost.sh b/dnsapi/dns_nederhost.sh index 32357f8..0058c84 100755 --- a/dnsapi/dns_nederhost.sh +++ b/dnsapi/dns_nederhost.sh @@ -91,7 +91,7 @@ _get_root() { fi if _nederhost_rest GET "zones/${_domain}"; then - if [ "${_code}" == "204" ]; then + if [ "${_code}" = "204" ]; then return 0; fi else @@ -112,7 +112,7 @@ _nederhost_rest() { export _H1="Authorization: Bearer $NederHost_Key" export _H2="Content-Type: application/json" - :>$HTTP_HEADER + :>"$HTTP_HEADER" if [ "$m" != "GET" ]; then _debug data "$data" From 44dcb0d0a9b0b22f88d3d7942b1aac9004a273b7 Mon Sep 17 00:00:00 2001 From: Sebastiaan Hoogeveen Date: Wed, 6 Feb 2019 11:46:47 +0100 Subject: [PATCH 227/565] Make Travis happy; fixed formatting of return statements. --- dnsapi/dns_nederhost.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_nederhost.sh b/dnsapi/dns_nederhost.sh index 0058c84..84c5ecd 100755 --- a/dnsapi/dns_nederhost.sh +++ b/dnsapi/dns_nederhost.sh @@ -92,10 +92,10 @@ _get_root() { if _nederhost_rest GET "zones/${_domain}"; then if [ "${_code}" = "204" ]; then - return 0; + return 0 fi else - return 1; + return 1 fi p=$i i=$(_math "$i" + 1) From b7e92dbcedf358a2234ed6567662b71bb5ee2953 Mon Sep 17 00:00:00 2001 From: Sebastiaan Hoogeveen Date: Wed, 6 Feb 2019 14:27:26 +0100 Subject: [PATCH 228/565] Documentation update. --- README.md | 1 + dnsapi/README.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/README.md b/README.md index 90a648d..4bde4ea 100644 --- a/README.md +++ b/README.md @@ -351,6 +351,7 @@ 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. NederHost API (https://www.nederhost.nl/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 4f9b410..a2bf0c1 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1172,6 +1172,20 @@ 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 NederHost API + +Create an API token in Mijn NederHost. + +Set your API key: +``` +export NederHost_Key='xxx' +``` + +To issue a certificate run: +``` +acme.sh --issue --dns dns_nederhost -d example.com -d *.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. From 84d80e93bcd9dcef9183658a5af4fc47efa8758f Mon Sep 17 00:00:00 2001 From: Frank Laszlo Date: Wed, 6 Feb 2019 10:42:11 -0500 Subject: [PATCH 229/565] 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 230/565] 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 231/565] 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 232/565] 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 233/565] 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 234/565] 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 235/565] 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 236/565] 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 237/565] 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 238/565] 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 239/565] 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 240/565] 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 241/565] 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 242/565] 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 243/565] 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 9ff6d6e7b5bcaf41ccae97ee29d06223cda67455 Mon Sep 17 00:00:00 2001 From: dsc Date: Sun, 17 Feb 2019 23:20:17 +0100 Subject: [PATCH 244/565] initial commit --- dnsapi/dns_one.sh | 146 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 dnsapi/dns_one.sh diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh new file mode 100644 index 0000000..185669c --- /dev/null +++ b/dnsapi/dns_one.sh @@ -0,0 +1,146 @@ +#!/usr/bin/env sh +# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*- + +# one.com ui wrapper for acme.sh +# Author: github: @diseq +# Created: 2019-02-17 +# +# export ONECOM_USER="username" +# export ONECOM_PASSWORD="password" +# +# Usage: +# acme.sh --issue --dns dns_one -d example.com +# +# only single domain supported atm + +dns_one_add() { + mysubdomain=$(printf -- "%s" "$1" | rev | cut -d"." -f3- | rev) + mydomain=$(printf -- "%s" "$1" | rev | cut -d"." -f1-2 | rev) + txtvalue=$2 + + # get credentials + ONECOM_USER="${ONECOM_USER:-$(_readaccountconf_mutable ONECOM_USER)}" + ONECOM_PASSWORD="${ONECOM_PASSWORD:-$(_readaccountconf_mutable ONECOM_PASSWORD)}" + if [ -z "$ONECOM_USER" ] || [ -z "$ONECOM_PASSWORD" ]; then + ONECOM_USER="" + ONECOM_PASSWORD="" + _err "You didn't specify a one.com username and password yet." + _err "Please create the key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable ONECOM_USER "$ONECOM_USER" + _saveaccountconf_mutable ONECOM_PASSWORD "$ONECOM_PASSWORD" + + + # Login with user and password + postdata="loginDomain=true" + postdata="$postdata&displayUsername=$ONECOM_USER" + postdata="$postdata&username=$ONECOM_USER" + postdata="$postdata&targetDomain=$mydomain" + postdata="$postdata&password1=$ONECOM_PASSWORD" + postdata="$postdata&loginTarget=" + + #_debug postdata "$postdata" + + response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST")" + #_debug response "$response" + + JSESSIONID="$(grep "JSESSIONID=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'JSESSIONID=[^;]*;' | tr -d ';')" + _debug jsessionid "$JSESSIONID" + + export _H1="Cookie: ${JSESSIONID}" + + + # get entries + response="$(_get "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records")" + _debug response "$response" + + + CSRF_G_TOKEN="$(grep "CSRF_G_TOKEN=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'CSRF_G_TOKEN=[^;]*;' | tr -d ';')" + export _H2="Cookie: ${CSRF_G_TOKEN}" + + + # Update the IP address for domain entry + postdata="{\"type\":\"dns_custom_records\",\"attributes\":{\"priority\":0,\"ttl\":600,\"type\":\"TXT\",\"prefix\":\"$mysubdomain\",\"content\":\"$txtvalue\"}}" + _debug postdata "$postdata" + response="$(_post "$postdata" "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records" "" "POST" "application/json")" + response="$(echo "$response" | _normalizeJson)" + _debug response "$response" + + id=$(printf -- "%s" "$response" | sed -n "s/{\"result\":{\"data\":{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$mysubdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}}},\"metadata\":null}/\1/p") + + if [ -z "$id" ]; then + _err "Add txt record error." + return 1 + else + _info "Added, OK ($id)" + return 0 + fi + +} + +dns_one_rm() { + mysubdomain=$(printf -- "%s" "$1" | rev | cut -d"." -f3- | rev) + mydomain=$(printf -- "%s" "$1" | rev | cut -d"." -f1-2 | rev) + txtvalue=$2 + + # get credentials + ONECOM_USER="${ONECOM_USER:-$(_readaccountconf_mutable ONECOM_USER)}" + ONECOM_PASSWORD="${ONECOM_PASSWORD:-$(_readaccountconf_mutable ONECOM_PASSWORD)}" + if [ -z "$ONECOM_USER" ] || [ -z "$ONECOM_PASSWORD" ]; then + ONECOM_USER="" + ONECOM_PASSWORD="" + _err "You didn't specify a one.com username and password yet." + _err "Please create the key and try again." + return 1 + fi + + + # Login with user and password + postdata="loginDomain=true" + postdata="$postdata&displayUsername=$ONECOM_USER" + postdata="$postdata&username=$ONECOM_USER" + postdata="$postdata&targetDomain=$mydomain" + postdata="$postdata&password1=$ONECOM_PASSWORD" + postdata="$postdata&loginTarget=" + + response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST")" + + JSESSIONID="$(grep "JSESSIONID=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'JSESSIONID=[^;]*;' | tr -d ';')" + _debug jsessionid "$JSESSIONID" + + export _H1="Cookie: ${JSESSIONID}" + + + # get entries + response="$(_get "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records")" + response="$(echo "$response" | _normalizeJson)" + _debug response "$response" + + CSRF_G_TOKEN="$(grep "CSRF_G_TOKEN=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'CSRF_G_TOKEN=[^;]*;' | tr -d ';')" + export _H2="Cookie: ${CSRF_G_TOKEN}" + + id=$(printf -- "%s" "$response" | sed -n "s/.*{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$mysubdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}.*/\1/p") + + if [ -z "$id" ]; then + _err "Txt record not found." + return 1 + fi + + # delete entry + response="$(_post "$postdata" "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records/$id" "" "DELETE" "application/json")" + response="$(echo "$response" | _normalizeJson)" + _debug response "$response" + + if [ "$response" = '{"result":null,"metadata":null}' ]; + then + _info "Removed, OK" + return 0 + else + _err "Removing txt record error." + return 1 + fi + +} \ No newline at end of file From 97147b594b185786ef1d69ce0d85b70a91f0ccc9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 18 Feb 2019 20:57:13 +0800 Subject: [PATCH 245/565] 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 246/565] 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 247/565] 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 0bb746ba39d2e1cc5fdf732422050f77fb28e513 Mon Sep 17 00:00:00 2001 From: diseq Date: Wed, 20 Feb 2019 09:44:25 +0100 Subject: [PATCH 248/565] Update dns_one.sh --- dnsapi/dns_one.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh index 185669c..521b034 100644 --- a/dnsapi/dns_one.sh +++ b/dnsapi/dns_one.sh @@ -143,4 +143,4 @@ dns_one_rm() { return 1 fi -} \ No newline at end of file +} From 81ba629b5684e75e450345ae6024987ce8d80a90 Mon Sep 17 00:00:00 2001 From: diseq Date: Wed, 20 Feb 2019 11:27:49 +0100 Subject: [PATCH 249/565] allow set-cookie as well as Set-Cookie --- dnsapi/dns_one.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh index 521b034..5dc002d 100644 --- a/dnsapi/dns_one.sh +++ b/dnsapi/dns_one.sh @@ -41,13 +41,12 @@ dns_one_add() { postdata="$postdata&targetDomain=$mydomain" postdata="$postdata&password1=$ONECOM_PASSWORD" postdata="$postdata&loginTarget=" - #_debug postdata "$postdata" - response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST")" + response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST" "application/x-www-form-urlencoded")" #_debug response "$response" - JSESSIONID="$(grep "JSESSIONID=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'JSESSIONID=[^;]*;' | tr -d ';')" + JSESSIONID="$(grep "JSESSIONID" "$HTTP_HEADER" | grep "^[Ss]et-[Cc]ookie:" | _tail_n 1 | _egrep_o 'JSESSIONID=[^;]*;' | tr -d ';')" _debug jsessionid "$JSESSIONID" export _H1="Cookie: ${JSESSIONID}" @@ -106,9 +105,10 @@ dns_one_rm() { postdata="$postdata&password1=$ONECOM_PASSWORD" postdata="$postdata&loginTarget=" - response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST")" + response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST" "application/x-www-form-urlencoded")" + #_debug response "$response" - JSESSIONID="$(grep "JSESSIONID=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'JSESSIONID=[^;]*;' | tr -d ';')" + JSESSIONID="$(grep "JSESSIONID" "$HTTP_HEADER" | grep "^[Ss]et-[Cc]ookie:" | _tail_n 1 | _egrep_o 'JSESSIONID=[^;]*;' | tr -d ';')" _debug jsessionid "$JSESSIONID" export _H1="Cookie: ${JSESSIONID}" From 0499d2b5c4bef6bd105ff64f1bc5df419fd4ab9a Mon Sep 17 00:00:00 2001 From: diseq Date: Wed, 20 Feb 2019 11:51:06 +0100 Subject: [PATCH 250/565] remove line break --- dnsapi/dns_one.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh index 5dc002d..1bc30ab 100644 --- a/dnsapi/dns_one.sh +++ b/dnsapi/dns_one.sh @@ -134,8 +134,7 @@ dns_one_rm() { response="$(echo "$response" | _normalizeJson)" _debug response "$response" - if [ "$response" = '{"result":null,"metadata":null}' ]; - then + if [ "$response" = '{"result":null,"metadata":null}' ]; then _info "Removed, OK" return 0 else From ed3f2646f0d9188de9cf9b1efe2d6c612ce624ea Mon Sep 17 00:00:00 2001 From: diseq Date: Wed, 20 Feb 2019 11:54:48 +0100 Subject: [PATCH 251/565] fix format --- dnsapi/dns_one.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh index 1bc30ab..d3ad670 100644 --- a/dnsapi/dns_one.sh +++ b/dnsapi/dns_one.sh @@ -135,11 +135,11 @@ dns_one_rm() { _debug response "$response" if [ "$response" = '{"result":null,"metadata":null}' ]; then - _info "Removed, OK" - return 0 - else - _err "Removing txt record error." - return 1 + _info "Removed, OK" + return 0 + else + _err "Removing txt record error." + return 1 fi } From 472ed721a38312c8bc53b3cfd7764c2ccc8c75ef Mon Sep 17 00:00:00 2001 From: diseq Date: Wed, 20 Feb 2019 21:51:59 +0100 Subject: [PATCH 252/565] fix format --- dnsapi/dns_one.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh index d3ad670..c99c9c9 100644 --- a/dnsapi/dns_one.sh +++ b/dnsapi/dns_one.sh @@ -33,7 +33,6 @@ dns_one_add() { _saveaccountconf_mutable ONECOM_USER "$ONECOM_USER" _saveaccountconf_mutable ONECOM_PASSWORD "$ONECOM_PASSWORD" - # Login with user and password postdata="loginDomain=true" postdata="$postdata&displayUsername=$ONECOM_USER" @@ -51,16 +50,13 @@ dns_one_add() { export _H1="Cookie: ${JSESSIONID}" - # get entries response="$(_get "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records")" _debug response "$response" - CSRF_G_TOKEN="$(grep "CSRF_G_TOKEN=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'CSRF_G_TOKEN=[^;]*;' | tr -d ';')" export _H2="Cookie: ${CSRF_G_TOKEN}" - # Update the IP address for domain entry postdata="{\"type\":\"dns_custom_records\",\"attributes\":{\"priority\":0,\"ttl\":600,\"type\":\"TXT\",\"prefix\":\"$mysubdomain\",\"content\":\"$txtvalue\"}}" _debug postdata "$postdata" @@ -96,7 +92,6 @@ dns_one_rm() { return 1 fi - # Login with user and password postdata="loginDomain=true" postdata="$postdata&displayUsername=$ONECOM_USER" @@ -113,7 +108,6 @@ dns_one_rm() { export _H1="Cookie: ${JSESSIONID}" - # get entries response="$(_get "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records")" response="$(echo "$response" | _normalizeJson)" From 23b4c9c667d6aab198cf4f633b9ccc1b05b66640 Mon Sep 17 00:00:00 2001 From: dsc Date: Thu, 21 Feb 2019 08:43:09 +0100 Subject: [PATCH 253/565] add docs for one.com --- dnsapi/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index f022cab..cb8ac57 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1280,3 +1280,19 @@ 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 + +## 66. Use one.com domain API to automatically issue cert + +Use your one.com credentials as you would login into the control panel. + +``` +export ONECOM_USER="sdfsdfsdfljlbjkljlkjsdfoiwje" +export ONECOM_PASSWORD="xxxx@sss.com" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_one -d example.com -d www.example.com +``` + +The `ONECOM_USER` and `ONECOM_PASSWORD` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. From ec54074392561f3f697b489fb278445aee34ada5 Mon Sep 17 00:00:00 2001 From: Timothy Nelson Date: Mon, 25 Feb 2019 05:19:36 -0600 Subject: [PATCH 254/565] 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 From e7f7e96d589ca757ab91744a97893f83d615c481 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 27 Feb 2019 20:36:13 +0800 Subject: [PATCH 255/565] Peb (#2126) * support pebble * support async finalize order --- acme.sh | 88 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/acme.sh b/acme.sh index 93112a1..8ee2247 100755 --- a/acme.sh +++ b/acme.sh @@ -1827,23 +1827,29 @@ _send_signed_request() { nonceurl="$ACME_NEW_NONCE" if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then _headers="$(cat "$HTTP_HEADER")" + _debug2 _headers "$_headers" + _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" fi fi - if [ -z "$_headers" ]; then + if [ -z "$_CACHED_NONCE" ]; then _debug2 "Get nonce with GET. ACME_DIRECTORY" "$ACME_DIRECTORY" nonceurl="$ACME_DIRECTORY" _headers="$(_get "$nonceurl" "onlyheader")" + _debug2 _headers "$_headers" + _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" fi - + if [ -z "$_CACHED_NONCE" ] && [ "$ACME_NEW_NONCE" ]; then + _debug2 "Get nonce with GET. ACME_NEW_NONCE" "$ACME_NEW_NONCE" + nonceurl="$ACME_NEW_NONCE" + _headers="$(_get "$nonceurl" "onlyheader")" + _debug2 _headers "$_headers" + _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + fi + _debug2 _CACHED_NONCE "$_CACHED_NONCE" if [ "$?" != "0" ]; then _err "Can not connect to $nonceurl to get nonce." return 1 fi - - _debug2 _headers "$_headers" - - _CACHED_NONCE="$(echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" - _debug2 _CACHED_NONCE "$_CACHED_NONCE" else _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE" fi @@ -2060,6 +2066,7 @@ _clearcaconf() { _startserver() { content="$1" ncaddr="$2" + _debug "content" "$content" _debug "ncaddr" "$ncaddr" _debug "startserver: $$" @@ -2086,8 +2093,14 @@ _startserver() { SOCAT_OPTIONS="$SOCAT_OPTIONS,bind=${ncaddr}" fi + _content_len="$(printf "%s" "$content" | wc -c)" + _debug _content_len "$_content_len" _debug "_NC" "$_NC $SOCAT_OPTIONS" - $_NC $SOCAT_OPTIONS SYSTEM:"sleep 1; echo HTTP/1.0 200 OK; echo ; echo $content; echo;" & + $_NC $SOCAT_OPTIONS SYSTEM:"sleep 1; \ +echo 'HTTP/1.0 200 OK'; \ +echo 'Content-Length\: $_content_len'; \ +echo ''; \ +printf '$content';" & serverproc="$!" } @@ -3062,6 +3075,7 @@ _on_before_issue() { _info "Standalone mode." if [ -z "$Le_HTTPPort" ]; then Le_HTTPPort=80 + _cleardomainconf "Le_HTTPPort" else _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" fi @@ -3269,7 +3283,7 @@ _regAccount() { fi _debug2 responseHeaders "$responseHeaders" - _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" + _accUri="$(echo "$responseHeaders" | grep -i "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" _debug "_accUri" "$_accUri" if [ -z "$_accUri" ]; then _err "Can not find account id url." @@ -3435,7 +3449,7 @@ __trigger_validation() { _t_vtype="$3" _debug2 _t_vtype "$_t_vtype" if [ "$ACME_VERSION" = "2" ]; then - _send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}" + _send_signed_request "$_t_url" "{}" else _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"type\": \"$_t_vtype\", \"keyAuthorization\": \"$_t_key_authz\"}" fi @@ -4205,20 +4219,66 @@ $_authorizations_map" der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" if [ "$ACME_VERSION" = "2" ]; then + _info "Lets finalize the order, Le_OrderFinalize: $Le_OrderFinalize" if ! _send_signed_request "${Le_OrderFinalize}" "{\"csr\": \"$der\"}"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 fi if [ "$code" != "200" ]; then - _err "Sign failed, code is not 200." + _err "Sign failed, finalize code is not 200." _err "$response" _on_issue_err "$_post_hook" return 1 fi - Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" + Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)" + if [ -z "$Le_LinkOrder" ]; then + _err "Sign error, can not get order link location header" + _err "responseHeaders" "$responseHeaders" + _on_issue_err "$_post_hook" + return 1 + fi + _savedomainconf "Le_LinkOrder" "$Le_LinkOrder" + + _link_cert_retry=0 + _MAX_CERT_RETRY=5 + while [ -z "$Le_LinkCert" ] && [ "$_link_cert_retry" -lt "$_MAX_CERT_RETRY" ]; do + if _contains "$response" "\"status\":\"valid\""; then + _debug "Order status is valid." + Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" + _debug Le_LinkCert "$Le_LinkCert" + if [ -z "$Le_LinkCert" ]; then + _err "Sign error, can not find Le_LinkCert" + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + break + elif _contains "$response" "\"processing\""; then + _info "Order status is processing, lets sleep and retry." + _sleep 2 + else + _err "Sign error, wrong status" + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + if ! _send_signed_request "$Le_LinkOrder"; then + _err "Sign failed, can not post to Le_LinkOrder cert:$Le_LinkOrder." + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + _link_cert_retry="$(_math $_link_cert_retry + 1)" + done - _tempSignedResponse="$response" + if [ -z "$Le_LinkCert" ]; then + _err "Sign failed, can not get Le_LinkCert, retry time limit." + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + _info "Download cert, Le_LinkCert: $Le_LinkCert" if ! _send_signed_request "$Le_LinkCert"; then _err "Sign failed, can not download cert:$Le_LinkCert." _err "$response" @@ -4237,7 +4297,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" From 81f0189d2342069ca74bd942f2d3592c1054232b Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 27 Feb 2019 20:40:10 +0800 Subject: [PATCH 256/565] add Pebble --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f79b860..f68eb00 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ https://github.com/Neilpang/acmetest - Letsencrypt.org CA(default) - [BuyPass.com CA](https://github.com/Neilpang/acme.sh/wiki/BuyPass.com-CA) +- [Pebble strict Mode](https://github.com/letsencrypt/pebble) # Supported modes From 693d692a472e9298c3bf3ee71ffc7d3328451887 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 27 Feb 2019 20:41:50 +0800 Subject: [PATCH 257/565] sync (#2127) * Support for MyDevil.net (#2076) support mydevil * Fix verification for namecheap domains not *owned* by the calling user (#2106) * Peb (#2126) * support pebble * support async finalize order * add Pebble --- README.md | 2 + acme.sh | 88 +++++++++++++++++++++++++++++++------ deploy/README.md | 10 +++++ deploy/mydevil.sh | 59 +++++++++++++++++++++++++ dnsapi/README.md | 20 +++++++++ dnsapi/dns_mydevil.sh | 97 +++++++++++++++++++++++++++++++++++++++++ dnsapi/dns_namecheap.sh | 45 +++++++++++++++++++ 7 files changed, 307 insertions(+), 14 deletions(-) create mode 100755 deploy/mydevil.sh create mode 100755 dnsapi/dns_mydevil.sh diff --git a/README.md b/README.md index 8d749dc..f68eb00 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ https://github.com/Neilpang/acmetest - Letsencrypt.org CA(default) - [BuyPass.com CA](https://github.com/Neilpang/acme.sh/wiki/BuyPass.com-CA) +- [Pebble strict Mode](https://github.com/letsencrypt/pebble) # Supported modes @@ -356,6 +357,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/acme.sh b/acme.sh index 93112a1..8ee2247 100755 --- a/acme.sh +++ b/acme.sh @@ -1827,23 +1827,29 @@ _send_signed_request() { nonceurl="$ACME_NEW_NONCE" if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then _headers="$(cat "$HTTP_HEADER")" + _debug2 _headers "$_headers" + _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" fi fi - if [ -z "$_headers" ]; then + if [ -z "$_CACHED_NONCE" ]; then _debug2 "Get nonce with GET. ACME_DIRECTORY" "$ACME_DIRECTORY" nonceurl="$ACME_DIRECTORY" _headers="$(_get "$nonceurl" "onlyheader")" + _debug2 _headers "$_headers" + _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" fi - + if [ -z "$_CACHED_NONCE" ] && [ "$ACME_NEW_NONCE" ]; then + _debug2 "Get nonce with GET. ACME_NEW_NONCE" "$ACME_NEW_NONCE" + nonceurl="$ACME_NEW_NONCE" + _headers="$(_get "$nonceurl" "onlyheader")" + _debug2 _headers "$_headers" + _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + fi + _debug2 _CACHED_NONCE "$_CACHED_NONCE" if [ "$?" != "0" ]; then _err "Can not connect to $nonceurl to get nonce." return 1 fi - - _debug2 _headers "$_headers" - - _CACHED_NONCE="$(echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" - _debug2 _CACHED_NONCE "$_CACHED_NONCE" else _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE" fi @@ -2060,6 +2066,7 @@ _clearcaconf() { _startserver() { content="$1" ncaddr="$2" + _debug "content" "$content" _debug "ncaddr" "$ncaddr" _debug "startserver: $$" @@ -2086,8 +2093,14 @@ _startserver() { SOCAT_OPTIONS="$SOCAT_OPTIONS,bind=${ncaddr}" fi + _content_len="$(printf "%s" "$content" | wc -c)" + _debug _content_len "$_content_len" _debug "_NC" "$_NC $SOCAT_OPTIONS" - $_NC $SOCAT_OPTIONS SYSTEM:"sleep 1; echo HTTP/1.0 200 OK; echo ; echo $content; echo;" & + $_NC $SOCAT_OPTIONS SYSTEM:"sleep 1; \ +echo 'HTTP/1.0 200 OK'; \ +echo 'Content-Length\: $_content_len'; \ +echo ''; \ +printf '$content';" & serverproc="$!" } @@ -3062,6 +3075,7 @@ _on_before_issue() { _info "Standalone mode." if [ -z "$Le_HTTPPort" ]; then Le_HTTPPort=80 + _cleardomainconf "Le_HTTPPort" else _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" fi @@ -3269,7 +3283,7 @@ _regAccount() { fi _debug2 responseHeaders "$responseHeaders" - _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" + _accUri="$(echo "$responseHeaders" | grep -i "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" _debug "_accUri" "$_accUri" if [ -z "$_accUri" ]; then _err "Can not find account id url." @@ -3435,7 +3449,7 @@ __trigger_validation() { _t_vtype="$3" _debug2 _t_vtype "$_t_vtype" if [ "$ACME_VERSION" = "2" ]; then - _send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}" + _send_signed_request "$_t_url" "{}" else _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"type\": \"$_t_vtype\", \"keyAuthorization\": \"$_t_key_authz\"}" fi @@ -4205,20 +4219,66 @@ $_authorizations_map" der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" if [ "$ACME_VERSION" = "2" ]; then + _info "Lets finalize the order, Le_OrderFinalize: $Le_OrderFinalize" if ! _send_signed_request "${Le_OrderFinalize}" "{\"csr\": \"$der\"}"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 fi if [ "$code" != "200" ]; then - _err "Sign failed, code is not 200." + _err "Sign failed, finalize code is not 200." _err "$response" _on_issue_err "$_post_hook" return 1 fi - Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" + Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)" + if [ -z "$Le_LinkOrder" ]; then + _err "Sign error, can not get order link location header" + _err "responseHeaders" "$responseHeaders" + _on_issue_err "$_post_hook" + return 1 + fi + _savedomainconf "Le_LinkOrder" "$Le_LinkOrder" + + _link_cert_retry=0 + _MAX_CERT_RETRY=5 + while [ -z "$Le_LinkCert" ] && [ "$_link_cert_retry" -lt "$_MAX_CERT_RETRY" ]; do + if _contains "$response" "\"status\":\"valid\""; then + _debug "Order status is valid." + Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" + _debug Le_LinkCert "$Le_LinkCert" + if [ -z "$Le_LinkCert" ]; then + _err "Sign error, can not find Le_LinkCert" + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + break + elif _contains "$response" "\"processing\""; then + _info "Order status is processing, lets sleep and retry." + _sleep 2 + else + _err "Sign error, wrong status" + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + if ! _send_signed_request "$Le_LinkOrder"; then + _err "Sign failed, can not post to Le_LinkOrder cert:$Le_LinkOrder." + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + _link_cert_retry="$(_math $_link_cert_retry + 1)" + done - _tempSignedResponse="$response" + if [ -z "$Le_LinkCert" ]; then + _err "Sign failed, can not get Le_LinkCert, retry time limit." + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + _info "Download cert, Le_LinkCert: $Le_LinkCert" if ! _send_signed_request "$Le_LinkCert"; then _err "Sign failed, can not download cert:$Le_LinkCert." _err "$response" @@ -4237,7 +4297,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" 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 +} 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 From af5f7a77796ff03e82bf554675816962d523fe28 Mon Sep 17 00:00:00 2001 From: tianji Date: Thu, 28 Feb 2019 23:43:58 +0800 Subject: [PATCH 258/565] fix deploy/qiniu.sh base64 According to the doc (https://developer.qiniu.com/kodo/manual/1231/appendix#1), we should use URL-safe base64 instead of plain base64 for token calculation. --- deploy/qiniu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index 158b8db..e46e6fb 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -87,6 +87,6 @@ qiniu_deploy() { } _make_access_token() { - _token="$(printf "%s\n" "$1" | _hmac "sha1" "$(printf "%s" "$QINIU_SK" | _hex_dump | tr -d " ")" | _base64)" + _token="$(printf "%s\n" "$1" | _hmac "sha1" "$(printf "%s" "$QINIU_SK" | _hex_dump | tr -d " ")" | _base64 | tr -- '+/' '-_')" echo "$QINIU_AK:$_token" } From 22e7b4c91184201225a8dbe52d5cb20efb90e860 Mon Sep 17 00:00:00 2001 From: tianji Date: Thu, 28 Feb 2019 23:51:43 +0800 Subject: [PATCH 259/565] fix doc of qiniu deploy script A leading dot should be included when updating wildcard domains. --- deploy/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index f290756..44d5322 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -349,10 +349,10 @@ $ export QINIU_SK="bar" $ acme.sh --deploy -d example.com --deploy-hook qiniu ``` -假如您部署的证书为泛域名证书,您还需要设置 `QINIU_CDN_DOMAIN` 变量,指定实际需要部署的域名: +假如您部署的证书为泛域名证书,您还需要设置 `QINIU_CDN_DOMAIN` 变量,指定实际需要部署的域名(请注意泛域名前的点): ```sh -$ export QINIU_CDN_DOMAIN="cdn.example.com" +$ export QINIU_CDN_DOMAIN=".cdn.example.com" $ acme.sh --deploy -d example.com --deploy-hook qiniu ``` @@ -375,10 +375,10 @@ $ 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: +you want to update (please note the leading dot): ```sh -$ export QINIU_CDN_DOMAIN="cdn.example.com" +$ export QINIU_CDN_DOMAIN=".cdn.example.com" $ acme.sh --deploy -d example.com --deploy-hook qiniu ``` From b3f6129718bf0e7b7f352344b7149c725cf1576b Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Mar 2019 20:44:08 +0800 Subject: [PATCH 260/565] fix https://github.com/Neilpang/acme.sh/issues/2122 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 8ee2247..005b133 100755 --- a/acme.sh +++ b/acme.sh @@ -4886,7 +4886,7 @@ _installcert() { export CERT_KEY_PATH export CA_CERT_PATH export CERT_FULLCHAIN_PATH - export Le_Domain + export Le_Domain="$_main_domain" cd "$DOMAIN_PATH" && eval "$_reload_cmd" ); then _info "$(__green "Reload success")" From 86fbb5952e2fad1065836f89502ca34aad7f78a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20H=C3=A5land?= Date: Sat, 2 Mar 2019 16:39:41 +0100 Subject: [PATCH 261/565] Use env sh --- deploy/routeros.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/routeros.sh b/deploy/routeros.sh index d590bc9..d0d15c5 100644 --- a/deploy/routeros.sh +++ b/deploy/routeros.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh #Here is a script to deploy cert to routeros router. From 7690f73e815a0b3af86fdf2901cc27519a1b0b33 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 5 Mar 2019 21:05:10 +0800 Subject: [PATCH 262/565] base64 encode reloadcmd. fix https://github.com/Neilpang/acme.sh/issues/2134 --- acme.sh | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/acme.sh b/acme.sh index 005b133..6c42d7e 100755 --- a/acme.sh +++ b/acme.sh @@ -66,6 +66,9 @@ END_CERT="-----END CERTIFICATE-----" CONTENT_TYPE_JSON="application/jose+json" RENEW_SKIP=2 +B64CONF_START="__ACME_BASE64__START_" +B64CONF_END="__ACME_BASE64__END_" + ECC_SEP="_" ECC_SUFFIX="${ECC_SEP}ecc" @@ -1964,12 +1967,16 @@ _setopt() { _debug3 "$(grep -n "^$__opt$__sep" "$__conf")" } -#_save_conf file key value +#_save_conf file key value base64encode #save to conf _save_conf() { _s_c_f="$1" _sdkey="$2" _sdvalue="$3" + _b64encode="$4" + if [ "$_b64encode" ]; then + _sdvalue="${B64CONF_START}$(printf "%s" "${_sdvalue}" | _base64)${B64CONF_END}" + fi if [ "$_s_c_f" ]; then _setopt "$_s_c_f" "$_sdkey" "=" "'$_sdvalue'" else @@ -1994,19 +2001,20 @@ _read_conf() { _r_c_f="$1" _sdkey="$2" if [ -f "$_r_c_f" ]; then - ( - eval "$(grep "^$_sdkey *=" "$_r_c_f")" - eval "printf \"%s\" \"\$$_sdkey\"" - ) + _sdv="$(grep "^$_sdkey *=" "$_r_c_f" | cut -d = -f 2-1000 | tr -d "'")" + if _startswith "$_sdv" "${B64CONF_START}" && _endswith "$_sdv" "${B64CONF_END}"; then + _sdv="$(echo "$_sdv" | sed "s/${B64CONF_START}//" | sed "s/${B64CONF_END}//" | _dbase64)" + fi + printf "%s" "$_sdv" else _debug "config file is empty, can not read $_sdkey" fi } -#_savedomainconf key value +#_savedomainconf key value base64encode #save to domain.conf _savedomainconf() { - _save_conf "$DOMAIN_CONF" "$1" "$2" + _save_conf "$DOMAIN_CONF" "$@" } #_cleardomainconf key @@ -2019,14 +2027,14 @@ _readdomainconf() { _read_conf "$DOMAIN_CONF" "$1" } -#_saveaccountconf key value +#_saveaccountconf key value base64encode _saveaccountconf() { - _save_conf "$ACCOUNT_CONF_PATH" "$1" "$2" + _save_conf "$ACCOUNT_CONF_PATH" "$@" } -#key value +#key value base64encode _saveaccountconf_mutable() { - _save_conf "$ACCOUNT_CONF_PATH" "SAVED_$1" "$2" + _save_conf "$ACCOUNT_CONF_PATH" "SAVED_$1" "$2" "$3" #remove later _clearaccountconf "$1" } @@ -4455,7 +4463,7 @@ $_authorizations_map" _savedomainconf "Le_RealCertPath" "$_real_cert" _savedomainconf "Le_RealCACertPath" "$_real_ca" _savedomainconf "Le_RealKeyPath" "$_real_key" - _savedomainconf "Le_ReloadCmd" "$_reload_cmd" + _savedomainconf "Le_ReloadCmd" "$_reload_cmd" "base64" _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" if ! _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"; then return 1 @@ -4522,6 +4530,7 @@ renew() { fi IS_RENEW="1" + Le_ReloadCmd="$(_readdomainconf Le_ReloadCmd)" issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" "$Le_ChallengeAlias" res="$?" if [ "$res" != "0" ]; then @@ -4802,7 +4811,7 @@ installcert() { _savedomainconf "Le_RealCertPath" "$_real_cert" _savedomainconf "Le_RealCACertPath" "$_real_ca" _savedomainconf "Le_RealKeyPath" "$_real_key" - _savedomainconf "Le_ReloadCmd" "$_reload_cmd" + _savedomainconf "Le_ReloadCmd" "$_reload_cmd" "base64" _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd" From dfca8c09e046ee157516b6f05dadf4d5240ba2fa Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 5 Mar 2019 21:22:03 +0800 Subject: [PATCH 263/565] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 6c42d7e..c63f294 100755 --- a/acme.sh +++ b/acme.sh @@ -2001,7 +2001,7 @@ _read_conf() { _r_c_f="$1" _sdkey="$2" if [ -f "$_r_c_f" ]; then - _sdv="$(grep "^$_sdkey *=" "$_r_c_f" | cut -d = -f 2-1000 | tr -d "'")" + _sdv="$(grep "^$_sdkey *=" "$_r_c_f" | cut -d = -f 2-1000 | tr -d "'")" if _startswith "$_sdv" "${B64CONF_START}" && _endswith "$_sdv" "${B64CONF_END}"; then _sdv="$(echo "$_sdv" | sed "s/${B64CONF_START}//" | sed "s/${B64CONF_END}//" | _dbase64)" fi From c7257bcf464d09096b9543e42fef12094fcdf18b Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 5 Mar 2019 21:44:34 +0800 Subject: [PATCH 264/565] base64 hooks, fix https://github.com/Neilpang/acme.sh/issues/1969 --- acme.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index c63f294..408f09c 100755 --- a/acme.sh +++ b/acme.sh @@ -3650,9 +3650,9 @@ issue() { _savedomainconf "Le_Alt" "$_alt_domains" _savedomainconf "Le_Webroot" "$_web_roots" - _savedomainconf "Le_PreHook" "$_pre_hook" - _savedomainconf "Le_PostHook" "$_post_hook" - _savedomainconf "Le_RenewHook" "$_renew_hook" + _savedomainconf "Le_PreHook" "$_pre_hook" "base64" + _savedomainconf "Le_PostHook" "$_post_hook" "base64" + _savedomainconf "Le_RenewHook" "$_renew_hook" "base64" if [ "$_local_addr" ]; then _savedomainconf "Le_LocalAddress" "$_local_addr" @@ -4531,6 +4531,9 @@ renew() { IS_RENEW="1" Le_ReloadCmd="$(_readdomainconf Le_ReloadCmd)" + Le_PreHook="$(_readdomainconf Le_PreHook)" + Le_PostHook="$(_readdomainconf Le_PostHook)" + Le_RenewHook="$(_readdomainconf Le_RenewHook)" issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" "$Le_ChallengeAlias" res="$?" if [ "$res" != "0" ]; then From a3d8b9935ab7eb6656d63f95c69ae0423c747cfa Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 8 Mar 2019 14:31:11 +0800 Subject: [PATCH 265/565] fix https://github.com/Neilpang/acme.sh/issues/2141 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 408f09c..d81812f 100755 --- a/acme.sh +++ b/acme.sh @@ -4250,7 +4250,7 @@ $_authorizations_map" _link_cert_retry=0 _MAX_CERT_RETRY=5 - while [ -z "$Le_LinkCert" ] && [ "$_link_cert_retry" -lt "$_MAX_CERT_RETRY" ]; do + while [ "$_link_cert_retry" -lt "$_MAX_CERT_RETRY" ]; do if _contains "$response" "\"status\":\"valid\""; then _debug "Order status is valid." Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" From 110a41d18def8f8305952600c07240e72aba7a67 Mon Sep 17 00:00:00 2001 From: 5ll <5ll@users.noreply.github.com> Date: Fri, 8 Mar 2019 10:33:09 +0100 Subject: [PATCH 266/565] initial commit DNS API for acme.sh for Core-Networks (https://beta.api.core-networks.de/doc/) --- dnsapi/dns_cn.sh | 158 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 dnsapi/dns_cn.sh diff --git a/dnsapi/dns_cn.sh b/dnsapi/dns_cn.sh new file mode 100644 index 0000000..b35f81c --- /dev/null +++ b/dnsapi/dns_cn.sh @@ -0,0 +1,158 @@ +#!/usr/bin/env sh + +# DNS API for acme.sh for Core-Networks (https://beta.api.core-networks.de/doc/). +# created by 5ll and francis + +CN_API="https://beta.api.core-networks.de" + +######## Public functions ##################### + +dns_cn_add(){ + fulldomain=$1 + txtvalue=$2 + + if ! _cn_login; then + _err "login failed" + return 1 + fi + + _debug "First detect the root zone" + if ! _cn_get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug "_sub_domain $_sub_domain" + _debug "_domain $_domain" + + _info "Adding record" + curData="{\"name\":\"$_sub_domain\",\"ttl\":120,\"type\":\"TXT\",\"data\":\"$txtvalue\"}" + curResult="$(_post "${curData}" "${CN_API}/dnszones/${_domain}/records/")" + + _debug "curData $curData" + _debug "curResult $curResult" + + if _contains "$curResult" ""; then + _info "Added, OK" + + if ! _cn_commit; then + _err "commiting changes failed" + return 1 + fi + return 0 + + else + _err "Add txt record error." + _debug "curData is $curData" + _debug "curResult is $curResult" + _err "error adding text record, response was $curResult" + return 1 + fi +} + +dns_cn_rm(){ + fulldomain=$1 + txtvalue=$2 + + if ! _cn_login; then + _err "login failed" + return 1 + fi + + _debug "First detect the root zone" + if ! _cn_get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _info "Deleting record" + curData="{\"name\":\"$_sub_domain\",\"data\":\"$txtvalue\"}" + curResult="$(_post "${curData}" "${CN_API}/dnszones/${_domain}/records/delete")" + _debug curData is "$curData" + + _info "commiting changes" + if ! _cn_commit; then + _err "commiting changes failed" + return 1 + fi + + _info "Deletet txt record" + return 0 +} + + +################### Private functions below ################################## +_cn_login() { + CN_User="${CN_User:-$(_readaccountconf_mutable CN_User)}" + CN_Password="${CN_Password:-$(_readaccountconf_mutable CN_Password)}" + if [ -z "$CN_User" ] || [ -z "$CN_Password" ]; then + CN_User="" + CN_Password="" + _err "You must export variables: CN_User and CN_Password" + return 1 + fi + + #save the config variables to the account conf file. + _saveaccountconf_mutable CN_User "$CN_User" + _saveaccountconf_mutable CN_Password "$CN_Password" + + _info "Getting an AUTH-Token" + curData="{\"login\":\"${CN_User}\",\"password\":\"${CN_Password}\"}" + curResult="$(_post "${curData}" "${CN_API}/auth/token")" + _debug "Calling _CN_login: '${curData}' '${CN_API}/auth/token'" + + if _contains "${curResult}" '"token":"'; then + authToken=$(echo "${curResult}" | cut -d ":" -f2 | cut -d "," -f1 | sed 's/^.\(.*\).$/\1/') + export _H1="Authorization: Bearer $authToken" + _info "Successfully acquired AUTH-Token" + _debug "AUTH-Token: '${authToken}'" + _debug "_H1 '${_H1}'" + else + _err "Couldn't acquire an AUTH-Token" + return 1 + fi +} + +# Commit changes +_cn_commit(){ + _info "Commiting changes" + _post "" "${CN_API}/dnszones/$h/records/commit" +} + +_cn_get_root(){ + domain=$1 + i=2 + p=1 + while true; do + + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + _debug _H1 "${_H1}" + + if [ -z "$h" ]; then + #not valid + return 1 + fi + + _cn_zonelist="$(_get ${CN_API}/dnszones/)" + _debug _cn_zonelist "${_cn_zonelist}" + + if [ "$?" != "0" ]; then + _err "something went wrong while getting the zone list" + return 1 + fi + + if _contains "$_cn_zonelist" "\"name\":\"$h\"" >/dev/null; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + else + _debug "Zonelist does not contain domain - iterating " + fi + p=$i + i=$(_math "$i" + 1) + + done + _err "Zonelist does not contain domain - exiting" + return 1 +} From 1d5967d143ddedddb8831be9e09583c406fd7c16 Mon Sep 17 00:00:00 2001 From: 5ll <5ll@users.noreply.github.com> Date: Fri, 8 Mar 2019 10:45:36 +0100 Subject: [PATCH 267/565] Updated README with Core-Networks support --- dnsapi/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 9f176c0..23620c4 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1300,3 +1300,22 @@ 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 + + +## Use Core-Networks API to automatically issue cert + +First you need to login to your Core-Networks account to to set up an API-User. +Then export username and password to use these credentials. + +``` +export CN_User="user" +export CN_Password="passowrd" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_cn -d example.com -d www.example.com +``` + +The `CN_User` and `CN_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + From 3d5c75420a517eb199dcd4fb572856e77f1cc549 Mon Sep 17 00:00:00 2001 From: 5ll <5ll@users.noreply.github.com> Date: Fri, 8 Mar 2019 10:46:35 +0100 Subject: [PATCH 268/565] Changed Order --- dnsapi/README.md | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 23620c4..33d724c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1279,6 +1279,26 @@ 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). +## 67. Use Core-Networks API to automatically issue cert + +First you need to login to your Core-Networks account to to set up an API-User. +Then export username and password to use these credentials. + +``` +export CN_User="user" +export CN_Password="passowrd" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_cn -d example.com -d www.example.com +``` + +The `CN_User` and `CN_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. @@ -1302,20 +1322,3 @@ See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api -## Use Core-Networks API to automatically issue cert - -First you need to login to your Core-Networks account to to set up an API-User. -Then export username and password to use these credentials. - -``` -export CN_User="user" -export CN_Password="passowrd" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_cn -d example.com -d www.example.com -``` - -The `CN_User` and `CN_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - From 30d0ac0784311d0f55c1737bb035242f58349c0e Mon Sep 17 00:00:00 2001 From: 5ll <5ll@users.noreply.github.com> Date: Fri, 8 Mar 2019 10:48:06 +0100 Subject: [PATCH 269/565] Updated README with Core-Networks support --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f68eb00..d0d526d 100644 --- a/README.md +++ b/README.md @@ -358,7 +358,7 @@ You don't have to do anything manually! 1. Rackspace Cloud DNS (https://www.rackspace.com) 1. Online.net API (https://online.net/) 1. MyDevil.net (https://www.mydevil.net/) - +1. Core-Networks.de (https://core-networks.de) And: **lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api From f5850d0c08bb72c1453043482ac5dd365df1e66b Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 8 Mar 2019 22:20:56 +0800 Subject: [PATCH 270/565] fix format --- dnsapi/dns_cn.sh | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/dnsapi/dns_cn.sh b/dnsapi/dns_cn.sh index b35f81c..e90d7e6 100644 --- a/dnsapi/dns_cn.sh +++ b/dnsapi/dns_cn.sh @@ -7,7 +7,7 @@ CN_API="https://beta.api.core-networks.de" ######## Public functions ##################### -dns_cn_add(){ +dns_cn_add() { fulldomain=$1 txtvalue=$2 @@ -21,17 +21,17 @@ dns_cn_add(){ _err "invalid domain" return 1 fi - + _debug "_sub_domain $_sub_domain" _debug "_domain $_domain" - + _info "Adding record" curData="{\"name\":\"$_sub_domain\",\"ttl\":120,\"type\":\"TXT\",\"data\":\"$txtvalue\"}" curResult="$(_post "${curData}" "${CN_API}/dnszones/${_domain}/records/")" _debug "curData $curData" _debug "curResult $curResult" - + if _contains "$curResult" ""; then _info "Added, OK" @@ -40,7 +40,7 @@ dns_cn_add(){ return 1 fi return 0 - + else _err "Add txt record error." _debug "curData is $curData" @@ -50,7 +50,7 @@ dns_cn_add(){ fi } -dns_cn_rm(){ +dns_cn_rm() { fulldomain=$1 txtvalue=$2 @@ -64,14 +64,14 @@ dns_cn_rm(){ _err "invalid domain" return 1 fi - + _info "Deleting record" curData="{\"name\":\"$_sub_domain\",\"data\":\"$txtvalue\"}" curResult="$(_post "${curData}" "${CN_API}/dnszones/${_domain}/records/delete")" _debug curData is "$curData" _info "commiting changes" - if ! _cn_commit; then + if ! _cn_commit; then _err "commiting changes failed" return 1 fi @@ -80,7 +80,6 @@ dns_cn_rm(){ return 0 } - ################### Private functions below ################################## _cn_login() { CN_User="${CN_User:-$(_readaccountconf_mutable CN_User)}" @@ -100,7 +99,7 @@ _cn_login() { curData="{\"login\":\"${CN_User}\",\"password\":\"${CN_Password}\"}" curResult="$(_post "${curData}" "${CN_API}/auth/token")" _debug "Calling _CN_login: '${curData}' '${CN_API}/auth/token'" - + if _contains "${curResult}" '"token":"'; then authToken=$(echo "${curResult}" | cut -d ":" -f2 | cut -d "," -f1 | sed 's/^.\(.*\).$/\1/') export _H1="Authorization: Bearer $authToken" @@ -114,12 +113,12 @@ _cn_login() { } # Commit changes -_cn_commit(){ +_cn_commit() { _info "Commiting changes" _post "" "${CN_API}/dnszones/$h/records/commit" } -_cn_get_root(){ +_cn_get_root() { domain=$1 i=2 p=1 From 04eaf7f1751149ae0af7c29728996004cf6e1de2 Mon Sep 17 00:00:00 2001 From: Sylvia van Os Date: Fri, 22 Feb 2019 15:10:39 +0100 Subject: [PATCH 271/565] Add OpenProvider support --- README.md | 1 + dnsapi/README.md | 17 +++ dnsapi/dns_openprovider.sh | 244 +++++++++++++++++++++++++++++++++++++ 3 files changed, 262 insertions(+) create mode 100755 dnsapi/dns_openprovider.sh diff --git a/README.md b/README.md index f79b860..e7ad4cf 100644 --- a/README.md +++ b/README.md @@ -357,6 +357,7 @@ You don't have to do anything manually! 1. Rackspace Cloud DNS (https://www.rackspace.com) 1. Online.net API (https://online.net/) 1. MyDevil.net (https://www.mydevil.net/) +1. OpenProvider API (https://www.openprovider.com/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 9f176c0..3cbfe19 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1279,6 +1279,23 @@ 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). +## 67. Use OpenProvider API + +First, you need to enable API access and retrieve your password hash on https://rcp.openprovider.eu/account/dashboard.php + +``` +export OPENPROVIDER_USER='username' +export OPENPROVIDER_PASSWORDHASH='xxx' +``` + +To issue a cert run: + +``` +acme.sh --issue --dns dns_openprovider -d example.com -d www.example.com +``` + +`OPENPROVIDER_USER` and `OPENPROVIDER_PASSWORDHASH` 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_openprovider.sh b/dnsapi/dns_openprovider.sh new file mode 100755 index 0000000..3d66dfe --- /dev/null +++ b/dnsapi/dns_openprovider.sh @@ -0,0 +1,244 @@ +#!/usr/bin/env sh + +# This is the OpenProvider API wrapper for acme.sh +# +# Author: Sylvia van Os +# Report Bugs here: https://github.com/Neilpang/acme.sh/issues/2104 +# +# export OPENPROVIDER_USER="username" +# export OPENPROVIDER_PASSWORDHASH="hashed_password" +# +# Usage: +# acme.sh --issue --dns dns_openprovider -d example.com + +OPENPROVIDER_API="https://api.openprovider.eu/" +#OPENPROVIDER_API="https://api.cte.openprovider.eu/" # Test API + +######## Public functions ##################### + +#Usage: dns_openprovider_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_openprovider_add() { + fulldomain="$1" + txtvalue="$2" + + OPENPROVIDER_USER="${OPENPROVIDER_USER:-$(_readaccountconf_mutable OPENPROVIDER_USER)}" + OPENPROVIDER_PASSWORDHASH="${OPENPROVIDER_PASSWORDHASH:-$(_readaccountconf_mutable OPENPROVIDER_PASSWORDHASH)}" + + if [ -z "$OPENPROVIDER_USER" ] || [ -z "$OPENPROVIDER_PASSWORDHASH" ]; then + _err "You didn't specify the openprovider user and/or password hash." + return 1 + fi + + # save the username and password to the account conf file. + _saveaccountconf_mutable OPENPROVIDER_USER "$OPENPROVIDER_USER" + _saveaccountconf_mutable OPENPROVIDER_PASSWORDHASH "$OPENPROVIDER_PASSWORDHASH" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _domain_name "$_domain_name" + _debug _domain_extension "$_domain_extension" + + _debug "Getting current records" + existing_items="" + results_retrieved=0 + while true; do + _openprovider_request "$(printf '%s.%s%s' "$_domain_name" "$_domain_extension" "$results_retrieved")" + + items="$response" + while true; do + item="$(printf '%s' "$items" | _egrep_o '.*<\/openXML>' | sed -n -E 's/.*(.*<\/item>).*/\1/p')" + _debug existing_items "$existing_items" + _debug results_retrieved "$results_retrieved" + _debug item "$item" + + if [ -z "$item" ]; then + break + fi + + items="$(printf '%s' "$items" | sed "s$item")" + + results_retrieved=$((results_retrieved + 1)) + new_item="$(printf '%s' "$item" | sed -n -E "s/.*.*((.*)\.$_domain_name\.$_domain_extension<\/name>.*(.*<\/type>).*(.*<\/value>).*(.*<\/prio>).*(.*<\/ttl>)).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p")" + if [ -z "$new_item" ]; then + # Base record + new_item="$(printf '%s' "$item" | sed -n -E "s/.*.*((.*)$_domain_name\.$_domain_extension<\/name>.*(.*<\/type>).*(.*<\/value>).*(.*<\/prio>).*(.*<\/ttl>)).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p")" + fi + + if [ -z "$(printf '%s' "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA)<\/type>.*")" ]; then + _debug "not an allowed record type, skipping" "$new_item" + continue + fi + + existing_items="$(printf '%s%s' "$existing_items" "$new_item")" + done + + total="$(printf '%s' "$response" | _egrep_o '.*?<\/total>' | sed -n -E 's/.*(.*)<\/total>.*/\1/p')" + + _debug total "$total" + if [ "$results_retrieved" -eq "$total" ]; then + break + fi + done + + _debug "Creating acme record" + acme_record="$(printf '%s' "$fulldomain" | sed -e "s/.$_domain_name.$_domain_extension$//")" + _openprovider_request "$(printf '%s%smaster%s%sTXT%s86400' "$_domain_name" "$_domain_extension" "$existing_items" "$acme_record" "$txtvalue")" + + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_openprovider_rm() { + fulldomain="$1" + txtvalue="$2" + + OPENPROVIDER_USER="${OPENPROVIDER_USER:-$(_readaccountconf_mutable OPENPROVIDER_USER)}" + OPENPROVIDER_PASSWORDHASH="${OPENPROVIDER_PASSWORDHASH:-$(_readaccountconf_mutable OPENPROVIDER_PASSWORDHASH)}" + + if [ -z "$OPENPROVIDER_USER" ] || [ -z "$OPENPROVIDER_PASSWORDHASH" ]; then + _err "You didn't specify the openprovider user and/or password hash." + return 1 + fi + + # save the username and password to the account conf file. + _saveaccountconf_mutable OPENPROVIDER_USER "$OPENPROVIDER_USER" + _saveaccountconf_mutable OPENPROVIDER_PASSWORDHASH "$OPENPROVIDER_PASSWORDHASH" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _domain_name "$_domain_name" + _debug _domain_extension "$_domain_extension" + + _debug "Getting current records" + existing_items="" + results_retrieved=0 + while true; do + _openprovider_request "$(printf '%s.%s%s' "$_domain_name" "$_domain_extension" "$results_retrieved")" + + # Remove acme records from items + items="$response" + while true; do + item="$(printf '%s' "$items" | _egrep_o '.*<\/openXML>' | sed -n -E 's/.*(.*<\/item>).*/\1/p')" + _debug existing_items "$existing_items" + _debug results_retrieved "$results_retrieved" + _debug item "$item" + + if [ -z "$item" ]; then + break + fi + + items="$(printf '%s' "$items" | sed "s$item")" + + results_retrieved=$((results_retrieved + 1)) + if ! printf '%s' "$item" | grep -v "$fulldomain"; then + _debug "acme record, skipping" "$item" + continue + fi + + new_item="$(printf '%s' "$item" | sed -n -E "s/.*.*((.*)\.$_domain_name\.$_domain_extension<\/name>.*(.*<\/type>).*(.*<\/value>).*(.*<\/prio>).*(.*<\/ttl>)).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p")" + + if [ -z "$new_item" ]; then + # Base record + new_item="$(printf '%s' "$item" | sed -n -E "s/.*.*((.*)$_domain_name\.$_domain_extension<\/name>.*(.*<\/type>).*(.*<\/value>).*(.*<\/prio>).*(.*<\/ttl>)).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p")" + fi + + if [ -z "$(printf '%s' "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA)<\/type>.*")" ]; then + _debug "not an allowed record type, skipping" "$new_item" + continue + fi + + existing_items="$(printf '%s%s' "$existing_items" "$new_item")" + done + + total="$(printf '%s' "$response" | _egrep_o '.*?<\/total>' | sed -n -E 's/.*(.*)<\/total>.*/\1/p')" + + _debug total "$total" + + if [ "$results_retrieved" -eq "$total" ]; then + break + fi + done + + _debug "Removing acme record" + _openprovider_request "$(printf '%s%smaster%s' "$_domain_name" "$_domain_extension" "$existing_items")" + + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _domain_name=domain +# _domain_extension=com +_get_root() { + domain=$1 + i=2 + + results_retrieved=0 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + _openprovider_request "$(printf '%s%s' "$(printf "%s" "$h" | cut -d . -f 1)" "$results_retrieved")" + + items="$response" + while true; do + item="$(printf '%s' "$items" | _egrep_o '.*<\/openXML>' | sed -n -E 's/.*(.*<\/domain>).*/\1/p')" + _debug existing_items "$existing_items" + _debug results_retrieved "$results_retrieved" + _debug item "$item" + + if [ -z "$item" ]; then + break + fi + + items="$(printf '%s' "$items" | sed "s$item")" + + results_retrieved=$((results_retrieved + 1)) + + _domain_name="$(printf "%s" "$item" | sed -n -E 's/.*.*(.*)<\/name>.*<\/domain>.*/\1/p')" + _domain_extension="$(printf "%s" "$item" | sed -n -E 's/.*.*(.*)<\/extension>.*<\/domain>.*/\1/p')" + _debug _domain_name "$_domain_name" + _debug _domain_extension "$_domain_extension" + if [ "$(printf "%s.%s" "$_domain_name" "$_domain_extension")" = "$h" ]; then + return 0 + fi + done + + total="$(printf '%s' "$response" | _egrep_o '.*?<\/total>' | sed -n -E 's/.*(.*)<\/total>.*/\1/p')" + + _debug total "$total" + + if [ "$results_retrieved" -eq "$total" ]; then + results_retrieved=0 + i=$(_math "$i" + 1) + fi + done + return 1 +} + +_openprovider_request() { + request_xml=$1 + + xml_prefix=$(printf '') + xml_content=$(printf '%s%s%s' "$OPENPROVIDER_USER" "$OPENPROVIDER_PASSWORDHASH" "$request_xml") + response="$(_post "$(printf "%s%s" "$xml_prefix" "$xml_content" | tr -d '\n')" "$OPENPROVIDER_API" "" "POST" "application/xml")" + _debug response "$response" + if ! _contains "$response" "0.*"; then + _err "API request failed." + return 1 + fi +} From 725addafda8c3ffbad2b0feb2ff03b4ff518abb9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 9 Mar 2019 09:13:49 +0800 Subject: [PATCH 272/565] fix format --- dnsapi/dns_cn.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cn.sh b/dnsapi/dns_cn.sh index e90d7e6..38d1f4a 100644 --- a/dnsapi/dns_cn.sh +++ b/dnsapi/dns_cn.sh @@ -69,7 +69,7 @@ dns_cn_rm() { curData="{\"name\":\"$_sub_domain\",\"data\":\"$txtvalue\"}" curResult="$(_post "${curData}" "${CN_API}/dnszones/${_domain}/records/delete")" _debug curData is "$curData" - + _info "commiting changes" if ! _cn_commit; then _err "commiting changes failed" @@ -132,7 +132,7 @@ _cn_get_root() { #not valid return 1 fi - + _cn_zonelist="$(_get ${CN_API}/dnszones/)" _debug _cn_zonelist "${_cn_zonelist}" From 53c018824862934939ac91c8e06c558c15d469a4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 11 Mar 2019 21:30:24 +0800 Subject: [PATCH 273/565] fix https://github.com/Neilpang/acme.sh/issues/2150 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d81812f..a31cf08 100755 --- a/acme.sh +++ b/acme.sh @@ -1974,7 +1974,7 @@ _save_conf() { _sdkey="$2" _sdvalue="$3" _b64encode="$4" - if [ "$_b64encode" ]; then + if [ "$_sdvalue" ] && [ "$_b64encode" ]; then _sdvalue="${B64CONF_START}$(printf "%s" "${_sdvalue}" | _base64)${B64CONF_END}" fi if [ "$_s_c_f" ]; then From f2add8de94e0ad9646f86dba3ea8666c9e39b348 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 12 Mar 2019 21:16:15 +0800 Subject: [PATCH 274/565] use acme v2 as default --- acme.sh | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index a31cf08..b3ccf9e 100755 --- a/acme.sh +++ b/acme.sh @@ -19,8 +19,8 @@ LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory" LETSENCRYPT_CA_V2="https://acme-v02.api.letsencrypt.org/directory" LETSENCRYPT_STAGING_CA_V2="https://acme-staging-v02.api.letsencrypt.org/directory" -DEFAULT_CA=$LETSENCRYPT_CA_V1 -DEFAULT_STAGING_CA=$LETSENCRYPT_STAGING_CA_V1 +DEFAULT_CA=$LETSENCRYPT_CA_V2 +DEFAULT_STAGING_CA=$LETSENCRYPT_STAGING_CA_V2 DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" DEFAULT_ACCOUNT_EMAIL="" @@ -3665,8 +3665,12 @@ issue() { _cleardomainconf "Le_ChallengeAlias" fi - Le_API="$ACME_DIRECTORY" - _savedomainconf "Le_API" "$Le_API" + if [ "$ACME_DIRECTORY" != "$DEFAULT_CA" ]; then + Le_API="$ACME_DIRECTORY" + _savedomainconf "Le_API" "$Le_API" + else + _cleardomainconf Le_API + fi if [ "$_alt_domains" = "$NO_VALUE" ]; then _alt_domains="" @@ -4500,6 +4504,16 @@ renew() { . "$DOMAIN_CONF" _debug Le_API "$Le_API" + + if [ "$Le_API" = "$LETSENCRYPT_CA_V1" ]; then + _cleardomainconf Le_API + Le_API="$DEFAULT_CA" + fi + if [ "$Le_API" = "$LETSENCRYPT_STAGING_CA_V1" ]; then + _cleardomainconf Le_API + Le_API="$DEFAULT_STAGING_CA" + fi + if [ "$Le_API" ]; then if [ "$_OLD_CA_HOST" = "$Le_API" ]; then export Le_API="$DEFAULT_CA" From db6db6a4e964befb0575030f1703d4e0a37db36a Mon Sep 17 00:00:00 2001 From: Sebastiaan Hoogeveen Date: Tue, 12 Mar 2019 14:36:42 +0100 Subject: [PATCH 275/565] Removed overwriting of the HTTP header file before sending a request. --- dnsapi/dns_nederhost.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/dnsapi/dns_nederhost.sh b/dnsapi/dns_nederhost.sh index 84c5ecd..0954ab6 100755 --- a/dnsapi/dns_nederhost.sh +++ b/dnsapi/dns_nederhost.sh @@ -112,8 +112,6 @@ _nederhost_rest() { export _H1="Authorization: Bearer $NederHost_Key" export _H2="Content-Type: application/json" - :>"$HTTP_HEADER" - if [ "$m" != "GET" ]; then _debug data "$data" response="$(_post "$data" "$NederHost_Api/$ep" "" "$m")" From 77f96b386e9d60380a1dcfc80577c126eadba49c Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 13 Mar 2019 20:42:02 +0800 Subject: [PATCH 276/565] support Windows scheduler. fix https://github.com/Neilpang/acme.sh/issues/2145 --- acme.sh | 130 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 110 insertions(+), 20 deletions(-) diff --git a/acme.sh b/acme.sh index b3ccf9e..ceacd57 100755 --- a/acme.sh +++ b/acme.sh @@ -9,6 +9,9 @@ PROJECT_ENTRY="acme.sh" PROJECT="https://github.com/Neilpang/$PROJECT_NAME" DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME" + +_WINDOWS_SCHEDULER_NAME="$PROJECT_NAME.cron" + _SCRIPT_="$0" _SUB_FOLDERS="dnsapi deploy" @@ -4923,35 +4926,108 @@ _installcert() { } +__read_password() { + unset _pp + prompt="Enter Password:" + while IFS= read -p "$prompt" -r -s -n 1 char + do + if [ "$char" = $'\0' ]; then + break + fi + prompt='*' + _pp="$_pp$char" + done + echo "$_pp" +} + +_install_win_taskscheduler() { + _lesh="$1" + _centry="$2" + _randomminute="$3" + if ! _exists cygpath; then + _err "cygpath not found" + return 1 + fi + if ! _exists schtasks; then + _err "schtasks.exe is not found, are you on Windows?" + return 1 + fi + _winbash="$(cygpath -w $(which bash))" + _debug _winbash "$_winbash" + if [ -z "$_winbash" ]; then + _err "can not find bash path" + return 1 + fi + _myname="$(whoami)" + _debug "_myname" "$_myname" + if [ -z "$_myname" ]; then + _err "can not find my user name" + return 1 + fi + _debug "_lesh" "$_lesh" + + _info "To install scheduler task in your Windows account, you must input your windows password." + _info "$PROJECT_NAME doesn't save your password." + _info "Please input your Windows password for: $(__green "$_myname")" + _password="$(__read_password)" + #SCHTASKS.exe '/create' '/SC' 'DAILY' '/TN' "$_WINDOWS_SCHEDULER_NAME" '/F' '/ST' "00:$_randomminute" '/RU' "$_myname" '/RP' "$_password" '/TR' "$_winbash -l -c '$_lesh --cron --home \"$LE_WORKING_DIR\" $_centry'" >/dev/null + echo SCHTASKS.exe '/create' '/SC' 'DAILY' '/TN' "$_WINDOWS_SCHEDULER_NAME" '/F' '/ST' "00:$_randomminute" '/RU' "$_myname" '/RP' "$_password" '/TR' "\"$_winbash -l -c '$_lesh --cron --home \"$LE_WORKING_DIR\" $_centry'\"" | cmd.exe >/dev/null + echo + +} + +_uninstall_win_taskscheduler() { + if ! _exists schtasks; then + _err "schtasks.exe is not found, are you on Windows?" + return 1 + fi + if ! echo SCHTASKS /query /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null; then + _debug "scheduler $_WINDOWS_SCHEDULER_NAME is not found." + else + _info "Removing $_WINDOWS_SCHEDULER_NAME" + echo SCHTASKS /delete /f /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null + fi +} + #confighome installcronjob() { _c_home="$1" _initpath _CRONTAB="crontab" + if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then + lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY" + else + _err "Can not install cronjob, $PROJECT_ENTRY not found." + return 1 + fi + if [ "$_c_home" ]; then + _c_entry="--config-home \"$_c_home\" " + fi + _t=$(_time) + random_minute=$(_math $_t % 60) + if ! _exists "$_CRONTAB" && _exists "fcrontab"; then _CRONTAB="fcrontab" fi + if ! _exists "$_CRONTAB"; then + if _exists cygpath && _exists schtasks.exe; then + _info "It seems you are on Windows, let's install Windows scheduler task." + if _install_win_taskscheduler "$lesh" "$_c_entry" "$random_minute"; then + _info "Install Windows scheduler task success." + return 0 + else + _err "Install Windows scheduler task failed." + return 1 + fi + fi _err "crontab/fcrontab doesn't exist, so, we can not install cron jobs." _err "All your certs will not be renewed automatically." _err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday." return 1 fi - _info "Installing cron job" if ! $_CRONTAB -l | grep "$PROJECT_ENTRY --cron"; then - if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then - lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY" - else - _err "Can not install cronjob, $PROJECT_ENTRY not found." - return 1 - fi - - if [ "$_c_home" ]; then - _c_entry="--config-home \"$_c_home\" " - fi - _t=$(_time) - random_minute=$(_math $_t % 60) if _exists uname && uname -a | grep SunOS >/dev/null; then $_CRONTAB -l | { cat @@ -4979,6 +5055,16 @@ uninstallcronjob() { fi if ! _exists "$_CRONTAB"; then + if _exists cygpath && _exists schtasks.exe; then + _info "It seems you are on Windows, let's uninstall Windows scheduler task." + if _uninstall_win_taskscheduler; then + _info "Uninstall Windows scheduler task success." + return 0 + else + _err "Uninstall Windows scheduler task failed." + return 1 + fi + fi return fi _info "Removing cron job" @@ -5306,13 +5392,17 @@ _precheck() { if [ -z "$_nocron" ]; then if ! _exists "crontab" && ! _exists "fcrontab"; then - _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." - _err "We need to set cron job to renew the certs automatically." - _err "Otherwise, your certs will not be able to be renewed automatically." - if [ -z "$FORCE" ]; then - _err "Please add '--force' and try install again to go without crontab." - _err "./$PROJECT_ENTRY --install --force" - return 1 + if _exists cygpath && _exists schtasks.exe; then + _info "It seems you are on Windows, we will install Windows scheduler task." + else + _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." + _err "We need to set cron job to renew the certs automatically." + _err "Otherwise, your certs will not be able to be renewed automatically." + if [ -z "$FORCE" ]; then + _err "Please add '--force' and try install again to go without crontab." + _err "./$PROJECT_ENTRY --install --force" + return 1 + fi fi fi fi From 0b04a7f17f467db477fca6588d8d078e2ac017f0 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 13 Mar 2019 20:49:26 +0800 Subject: [PATCH 277/565] fix format --- acme.sh | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index ceacd57..127b6ab 100755 --- a/acme.sh +++ b/acme.sh @@ -4929,13 +4929,12 @@ _installcert() { __read_password() { unset _pp prompt="Enter Password:" - while IFS= read -p "$prompt" -r -s -n 1 char - do - if [ "$char" = $'\0' ]; then - break - fi - prompt='*' - _pp="$_pp$char" + while IFS= read -p "$prompt" -r -s -n 1 char; do + if [ "$char" = $'\0' ]; then + break + fi + prompt='*' + _pp="$_pp$char" done echo "$_pp" } @@ -4985,7 +4984,7 @@ _uninstall_win_taskscheduler() { _debug "scheduler $_WINDOWS_SCHEDULER_NAME is not found." else _info "Removing $_WINDOWS_SCHEDULER_NAME" - echo SCHTASKS /delete /f /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null + echo SCHTASKS /delete /f /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null fi } From 4ebad10557d3f05de6b4bddb8c173a2030af4145 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 13 Mar 2019 21:11:59 +0800 Subject: [PATCH 278/565] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 127b6ab..1887bc9 100755 --- a/acme.sh +++ b/acme.sh @@ -4931,7 +4931,7 @@ __read_password() { prompt="Enter Password:" while IFS= read -p "$prompt" -r -s -n 1 char; do if [ "$char" = $'\0' ]; then - break + break fi prompt='*' _pp="$_pp$char" From 532e79c7d0d8dcfcf514195c0d8b2873aa4717ee Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Wed, 13 Mar 2019 14:14:40 +0100 Subject: [PATCH 279/565] Fix reading endpoint --- dnsapi/dns_hostingde.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index 50aa142..1819e63 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -28,6 +28,7 @@ dns_hostingde_rm() { _hostingde_apiKey() { HOSTINGDE_APIKEY="${HOSTINGDE_APIKEY:-$(_readaccountconf_mutable HOSTINGDE_APIKEY)}" + HOSTINGDE_ENDPOINT="${HOSTINGDE_ENDPOINT:-$(_readaccountconf_mutable HOSTINGDE_ENDPOINT)}" if [ -z "$HOSTINGDE_APIKEY" ] || [ -z "$HOSTINGDE_ENDPOINT" ]; then HOSTINGDE_APIKEY="" HOSTINGDE_ENDPOINT="" From 0f00862e5efd76cf998fe2b7511432c4893a249f Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 13 Mar 2019 21:28:30 +0800 Subject: [PATCH 280/565] support windows scheduler (#2158) * support Windows scheduler. fix https://github.com/Neilpang/acme.sh/issues/2145 --- acme.sh | 129 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 109 insertions(+), 20 deletions(-) diff --git a/acme.sh b/acme.sh index b3ccf9e..1887bc9 100755 --- a/acme.sh +++ b/acme.sh @@ -9,6 +9,9 @@ PROJECT_ENTRY="acme.sh" PROJECT="https://github.com/Neilpang/$PROJECT_NAME" DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME" + +_WINDOWS_SCHEDULER_NAME="$PROJECT_NAME.cron" + _SCRIPT_="$0" _SUB_FOLDERS="dnsapi deploy" @@ -4923,35 +4926,107 @@ _installcert() { } +__read_password() { + unset _pp + prompt="Enter Password:" + while IFS= read -p "$prompt" -r -s -n 1 char; do + if [ "$char" = $'\0' ]; then + break + fi + prompt='*' + _pp="$_pp$char" + done + echo "$_pp" +} + +_install_win_taskscheduler() { + _lesh="$1" + _centry="$2" + _randomminute="$3" + if ! _exists cygpath; then + _err "cygpath not found" + return 1 + fi + if ! _exists schtasks; then + _err "schtasks.exe is not found, are you on Windows?" + return 1 + fi + _winbash="$(cygpath -w $(which bash))" + _debug _winbash "$_winbash" + if [ -z "$_winbash" ]; then + _err "can not find bash path" + return 1 + fi + _myname="$(whoami)" + _debug "_myname" "$_myname" + if [ -z "$_myname" ]; then + _err "can not find my user name" + return 1 + fi + _debug "_lesh" "$_lesh" + + _info "To install scheduler task in your Windows account, you must input your windows password." + _info "$PROJECT_NAME doesn't save your password." + _info "Please input your Windows password for: $(__green "$_myname")" + _password="$(__read_password)" + #SCHTASKS.exe '/create' '/SC' 'DAILY' '/TN' "$_WINDOWS_SCHEDULER_NAME" '/F' '/ST' "00:$_randomminute" '/RU' "$_myname" '/RP' "$_password" '/TR' "$_winbash -l -c '$_lesh --cron --home \"$LE_WORKING_DIR\" $_centry'" >/dev/null + echo SCHTASKS.exe '/create' '/SC' 'DAILY' '/TN' "$_WINDOWS_SCHEDULER_NAME" '/F' '/ST' "00:$_randomminute" '/RU' "$_myname" '/RP' "$_password" '/TR' "\"$_winbash -l -c '$_lesh --cron --home \"$LE_WORKING_DIR\" $_centry'\"" | cmd.exe >/dev/null + echo + +} + +_uninstall_win_taskscheduler() { + if ! _exists schtasks; then + _err "schtasks.exe is not found, are you on Windows?" + return 1 + fi + if ! echo SCHTASKS /query /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null; then + _debug "scheduler $_WINDOWS_SCHEDULER_NAME is not found." + else + _info "Removing $_WINDOWS_SCHEDULER_NAME" + echo SCHTASKS /delete /f /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null + fi +} + #confighome installcronjob() { _c_home="$1" _initpath _CRONTAB="crontab" + if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then + lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY" + else + _err "Can not install cronjob, $PROJECT_ENTRY not found." + return 1 + fi + if [ "$_c_home" ]; then + _c_entry="--config-home \"$_c_home\" " + fi + _t=$(_time) + random_minute=$(_math $_t % 60) + if ! _exists "$_CRONTAB" && _exists "fcrontab"; then _CRONTAB="fcrontab" fi + if ! _exists "$_CRONTAB"; then + if _exists cygpath && _exists schtasks.exe; then + _info "It seems you are on Windows, let's install Windows scheduler task." + if _install_win_taskscheduler "$lesh" "$_c_entry" "$random_minute"; then + _info "Install Windows scheduler task success." + return 0 + else + _err "Install Windows scheduler task failed." + return 1 + fi + fi _err "crontab/fcrontab doesn't exist, so, we can not install cron jobs." _err "All your certs will not be renewed automatically." _err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday." return 1 fi - _info "Installing cron job" if ! $_CRONTAB -l | grep "$PROJECT_ENTRY --cron"; then - if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then - lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY" - else - _err "Can not install cronjob, $PROJECT_ENTRY not found." - return 1 - fi - - if [ "$_c_home" ]; then - _c_entry="--config-home \"$_c_home\" " - fi - _t=$(_time) - random_minute=$(_math $_t % 60) if _exists uname && uname -a | grep SunOS >/dev/null; then $_CRONTAB -l | { cat @@ -4979,6 +5054,16 @@ uninstallcronjob() { fi if ! _exists "$_CRONTAB"; then + if _exists cygpath && _exists schtasks.exe; then + _info "It seems you are on Windows, let's uninstall Windows scheduler task." + if _uninstall_win_taskscheduler; then + _info "Uninstall Windows scheduler task success." + return 0 + else + _err "Uninstall Windows scheduler task failed." + return 1 + fi + fi return fi _info "Removing cron job" @@ -5306,13 +5391,17 @@ _precheck() { if [ -z "$_nocron" ]; then if ! _exists "crontab" && ! _exists "fcrontab"; then - _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." - _err "We need to set cron job to renew the certs automatically." - _err "Otherwise, your certs will not be able to be renewed automatically." - if [ -z "$FORCE" ]; then - _err "Please add '--force' and try install again to go without crontab." - _err "./$PROJECT_ENTRY --install --force" - return 1 + if _exists cygpath && _exists schtasks.exe; then + _info "It seems you are on Windows, we will install Windows scheduler task." + else + _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." + _err "We need to set cron job to renew the certs automatically." + _err "Otherwise, your certs will not be able to be renewed automatically." + if [ -z "$FORCE" ]; then + _err "Please add '--force' and try install again to go without crontab." + _err "./$PROJECT_ENTRY --install --force" + return 1 + fi fi fi fi From 709d82e7641916da2ad9e9035472e4f5f622dd0d Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 13 Mar 2019 21:32:10 +0800 Subject: [PATCH 281/565] sync sync --- dnsapi/dns_hostingde.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index 50aa142..1819e63 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -28,6 +28,7 @@ dns_hostingde_rm() { _hostingde_apiKey() { HOSTINGDE_APIKEY="${HOSTINGDE_APIKEY:-$(_readaccountconf_mutable HOSTINGDE_APIKEY)}" + HOSTINGDE_ENDPOINT="${HOSTINGDE_ENDPOINT:-$(_readaccountconf_mutable HOSTINGDE_ENDPOINT)}" if [ -z "$HOSTINGDE_APIKEY" ] || [ -z "$HOSTINGDE_ENDPOINT" ]; then HOSTINGDE_APIKEY="" HOSTINGDE_ENDPOINT="" From 5048c6c22a19ae31006c3d5fa6a15733045fd4f8 Mon Sep 17 00:00:00 2001 From: tambetliiv <35329231+tambetliiv@users.noreply.github.com> Date: Thu, 14 Mar 2019 14:20:39 +0200 Subject: [PATCH 282/565] Add zone.ee (zone.eu) DNS API (#2151) * add zone.ee (zone.eu) dns api --- README.md | 1 + dnsapi/README.md | 16 +++++ dnsapi/dns_zone.sh | 149 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100755 dnsapi/dns_zone.sh diff --git a/README.md b/README.md index fae0bbf..50466ad 100644 --- a/README.md +++ b/README.md @@ -360,6 +360,7 @@ You don't have to do anything manually! 1. MyDevil.net (https://www.mydevil.net/) 1. Core-Networks.de (https://core-networks.de) 1. NederHost API (https://www.nederhost.nl/) +1. Zone.ee (zone.eu) API (https://api.zone.eu/v2) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 7ef1c30..de3148c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1310,6 +1310,22 @@ To issue a certificate run: acme.sh --issue --dns dns_nederhost -d example.com -d *.example.com ``` +## 69. Use Zone.ee DNS API + +First, you'll need to retrive your API key. Estonian insructions https://help.zone.eu/kb/zoneid-api-v2/ + +``` +export ZONE_Username=yourusername +export ZONE_Key=keygoeshere +``` + +To issue a cert run: + +``` +acme.sh --issue -d example.com -d www.example.com --dns dns_zone +``` + +`ZONE_Username` and `ZONE_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_zone.sh b/dnsapi/dns_zone.sh new file mode 100755 index 0000000..847e32c --- /dev/null +++ b/dnsapi/dns_zone.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env sh + +# Zone.ee dns API +# https://help.zone.eu/kb/zoneid-api-v2/ +# required ZONE_Username and ZONE_Key + +ZONE_Api="https://api.zone.eu/v2" +######## Public functions ##################### + +#Usage: dns_zone_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_zone_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using zone.ee dns api" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + ZONE_Username="${ZONE_Username:-$(_readaccountconf_mutable ZONE_Username)}" + ZONE_Key="${ZONE_Key:-$(_readaccountconf_mutable ZONE_Key)}" + if [ -z "$ZONE_Username" ] || [ -z "$ZONE_Key" ]; then + ZONE_Username="" + ZONE_Key="" + _err "Zone api key and username must be present." + return 1 + fi + _saveaccountconf_mutable ZONE_Username "$ZONE_Username" + _saveaccountconf_mutable ZONE_Key "$ZONE_Key" + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug "Adding txt record" + + if _zone_rest POST "dns/${_domain}/txt" "{\"name\": \"$fulldomain\", \"destination\": \"$txtvalue\"}"; then + if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then + _info "Added, OK" + return 0 + else + _err "Adding txt record error." + return 1 + fi + else + _err "Adding txt record error." + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_zone_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using zone.ee dns api" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + ZONE_Username="${ZONE_Username:-$(_readaccountconf_mutable ZONE_Username)}" + ZONE_Key="${ZONE_Key:-$(_readaccountconf_mutable ZONE_Key)}" + if [ -z "$ZONE_Username" ] || [ -z "$ZONE_Key" ]; then + ZONE_Username="" + ZONE_Key="" + _err "Zone api key and username must be present." + return 1 + fi + _saveaccountconf_mutable ZONE_Username "$ZONE_Username" + _saveaccountconf_mutable ZONE_Key "$ZONE_Key" + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug "Getting txt records" + _debug _domain "$_domain" + + _zone_rest GET "dns/${_domain}/txt" + + if printf "%s" "$response" | grep \"error\" >/dev/null; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l) + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Nothing to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\",\"resource_url\":\"[^\"]*\",\"name\":\"$fulldomain\"," | cut -d : -f2 | cut -d , -f1 | tr -d \" | _head_n 1) + if [ -z "$record_id" ]; then + _err "No id found to remove." + return 1 + fi + if ! _zone_rest DELETE "dns/${_domain}/txt/$record_id"; then + _err "Record deleting error." + return 1 + fi + _info "Record deleted" + return 0 + fi + +} + +#################### Private functions below ################################## + +_zone_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + realm="$(printf "%s" "$ZONE_Username:$ZONE_Key" | _base64)" + + export _H1="Authorization: Basic $realm" + export _H2="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$ZONE_Api/$ep" "" "$m")" + else + response="$(_get "$ZONE_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + +_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 + return 1 + fi + if ! _zone_rest GET "dns/$h/a"; then + return 1 + fi + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _domain=$h + return 0 + fi + i=$(_math "$i" + 1) + done + return 0 +} From 46fbd7f1e1fc355c34c76b6457e6a6959b5a387b Mon Sep 17 00:00:00 2001 From: "Steven M. Miano" Date: Thu, 14 Mar 2019 08:41:13 -0400 Subject: [PATCH 283/565] support ultradns.com api (#2117) support ultradns.com api (#2117) --- README.md | 1 + dnsapi/README.md | 24 +++++++ dnsapi/dns_ultra.sh | 164 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100644 dnsapi/dns_ultra.sh diff --git a/README.md b/README.md index 50466ad..68d1b57 100644 --- a/README.md +++ b/README.md @@ -361,6 +361,7 @@ You don't have to do anything manually! 1. Core-Networks.de (https://core-networks.de) 1. NederHost API (https://www.nederhost.nl/) 1. Zone.ee (zone.eu) API (https://api.zone.eu/v2) +1. UltraDNS API (https://portal.ultradns.com) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index de3148c..3cce294 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1326,6 +1326,30 @@ acme.sh --issue -d example.com -d www.example.com --dns dns_zone ``` `ZONE_Username` and `ZONE_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +## 70. Use UltraDNS API + +UltraDNS is a paid for service that provides DNS, as well as Web and Mail forwarding (as well as reporting, auditing, and advanced tools). + +More information can be found here: https://www.security.neustar/lp/ultra20/index.html + +The REST API documentation for this service is found here: https://portal.ultradns.com/static/docs/REST-API_User_Guide.pdf + +Set your UltraDNS User name, and password; these would be the same you would use here: + +https://portal.ultradns.com/ - or if you create an API only user, that username and password would be better utilized. + +``` +export ULTRA_USR="abcd" +export ULTRA_PWD="efgh" + +To issue a cert run: + +acme.sh --issue --dns dns_ultra -d example.com -d www.example.com +``` + +`ULTRA_USR` and `ULTRA_PWD` will be saved in `~/.acme.sh/account.conf` and will be resued when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_ultra.sh b/dnsapi/dns_ultra.sh new file mode 100644 index 0000000..0100b3b --- /dev/null +++ b/dnsapi/dns_ultra.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env sh + +# +# ULTRA_USR="your_user_goes_here" +# +# ULTRA_PWD="some_password_goes_here" + +ULTRA_API="https://restapi.ultradns.com/v2/" + +#Usage: add _acme-challenge.www.domain.com "some_long_string_of_characters_go_here_from_lets_encrypt" +dns_ultra_add() { + fulldomain=$1 + txtvalue=$2 + export txtvalue + ULTRA_USR="${ULTRA_USR:-$(_readaccountconf_mutable ULTRA_USR)}" + ULTRA_PWD="${ULTRA_PWD:-$(_readaccountconf_mutable ULTRA_PWD)}" + if [ -z "$ULTRA_USR" ] || [ -z "$ULTRA_PWD" ]; then + ULTRA_USR="" + ULTRA_PWD="" + _err "You didn't specify an UltraDNS username and password yet" + return 1 + fi + # save the username and password to the account conf file. + _saveaccountconf_mutable ULTRA_USR "$ULTRA_USR" + _saveaccountconf_mutable ULTRA_PWD "$ULTRA_PWD" + _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" + _ultra_rest GET "zones/${_domain_id}/rrsets/TXT?q=value:${fulldomain}" + if printf "%s" "$response" | grep \"totalCount\" >/dev/null; then + _err "Error, it would appear that this record already exists. Please review existing TXT records for this domain." + return 1 + fi + + _info "Adding record" + if _ultra_rest POST "zones/$_domain_id/rrsets/TXT/${_sub_domain}" '{"ttl":300,"rdata":["'"${txtvalue}"'"]}'; then + if _contains "$response" "Successful"; then + _info "Added, OK" + return 0 + elif _contains "$response" "Resource Record of type 16 with these attributes already exists"; then + _info "Already exists, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + +} + +dns_ultra_rm() { + fulldomain=$1 + txtvalue=$2 + export txtvalue + ULTRA_USR="${ULTRA_USR:-$(_readaccountconf_mutable ULTRA_USR)}" + ULTRA_PWD="${ULTRA_PWD:-$(_readaccountconf_mutable ULTRA_PWD)}" + if [ -z "$ULTRA_USR" ] || [ -z "$ULTRA_PWD" ]; then + ULTRA_USR="" + ULTRA_PWD="" + _err "You didn't specify an UltraDNS username and password yet" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "${_domain_id}" + _debug _sub_domain "${_sub_domain}" + _debug _domain "${domain}" + + _debug "Getting TXT records" + _ultra_rest GET "zones/${_domain_id}/rrsets?q=kind:RECORDS+owner:${_sub_domain}" + + if ! printf "%s" "$response" | grep \"resultInfo\" >/dev/null; then + _err "There was an error in obtaining the resource records for ${_domain_id}" + return 1 + fi + + count=$(echo "$response" | _egrep_o "\"returnedCount\":[^,]*" | cut -d: -f2 | cut -d'}' -f1) + _debug count "${count}" + if [ "${count}" = "" ]; then + _info "Text record is not present, will not delete anything." + else + if ! _ultra_rest DELETE "zones/$_domain_id/rrsets/TXT/${_sub_domain}" '{"ttl":300,"rdata":["'"${txtvalue}"'"]}'; then + _err "Deleting the record did not succeed, please verify/check." + return 1 + fi + _contains "$response" "" + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + _debug response "$response" + if [ -z "$h" ]; then + #not valid + return 1 + fi + if ! _ultra_rest GET "zones"; then + return 1 + fi + if _contains "${response}" "${h}." >/dev/null; then + _domain_id=$(echo "$response" | _egrep_o "${h}") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="${h}" + _debug sub_domain "${_sub_domain}" + _debug domain "${_domain}" + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_ultra_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + _debug TOKEN "${AUTH_TOKEN}" + + _ultra_login + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer ${AUTH_TOKEN}" + + if [ "$m" != "GET" ]; then + _debug data "${data}" + response="$(_post "${data}" "${ULTRA_API}"/"${ep}" "" "${m}")" + else + response="$(_get "$ULTRA_API/$ep")" + fi +} + +_ultra_login() { + export _H1="" + export _H2="" + AUTH_TOKEN=$(_post "grant_type=password&username=${ULTRA_USR}&password=${ULTRA_PWD}" "${ULTRA_API}authorization/token" | cut -d, -f3 | cut -d\" -f4) + export AUTH_TOKEN +} From dbc44c08df9e06c5db45ee85e797185dea81fd6e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 16 Mar 2019 13:38:17 +0800 Subject: [PATCH 284/565] fix for solaris --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 1887bc9..f4f5126 100755 --- a/acme.sh +++ b/acme.sh @@ -3751,7 +3751,7 @@ issue() { return 1 fi - Le_OrderFinalize="$(echo "$response" | tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" + Le_OrderFinalize="$(echo "$response" | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" _debug Le_OrderFinalize "$Le_OrderFinalize" if [ -z "$Le_OrderFinalize" ]; then _err "Create new order error. Le_OrderFinalize not found. $response" @@ -3763,7 +3763,7 @@ issue() { #for dns manual mode _savedomainconf "Le_OrderFinalize" "$Le_OrderFinalize" - _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" + _authorizations_seg="$(echo "$response" | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" _debug2 _authorizations_seg "$_authorizations_seg" if [ -z "$_authorizations_seg" ]; then _err "_authorizations_seg not found." @@ -3849,7 +3849,7 @@ $_authorizations_map" thumbprint="$(__calc_account_thumbprint)" fi - entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" + entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ]; then _err "Error, can not get domain token entry $d" @@ -3861,7 +3861,7 @@ $_authorizations_map" _on_issue_err "$_post_hook" return 1 fi - token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" + token="$(echo "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" _debug token "$token" if [ -z "$token" ]; then @@ -3871,9 +3871,9 @@ $_authorizations_map" return 1 fi if [ "$ACME_VERSION" = "2" ]; then - uri="$(printf "%s\n" "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)" + uri="$(echo "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)" else - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)" + uri="$(echo "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)" fi _debug uri "$uri" From d0d749074e35057aacc020448b700a3af7e4e63f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 16 Mar 2019 14:00:15 +0800 Subject: [PATCH 285/565] fix for solaris --- acme.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index f4f5126..3c7bc6d 100755 --- a/acme.sh +++ b/acme.sh @@ -4194,7 +4194,7 @@ $_authorizations_map" fi if [ "$status" = "invalid" ]; then - error="$(echo "$response" | tr -d "\r\n" | _egrep_o '"error":\{[^\}]*')" + error="$(echo "$response" | _egrep_o '"error":\{[^\}]*')" _debug2 error "$error" errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)" _debug2 errordetail "$errordetail" @@ -4260,7 +4260,7 @@ $_authorizations_map" while [ "$_link_cert_retry" -lt "$_MAX_CERT_RETRY" ]; do if _contains "$response" "\"status\":\"valid\""; then _debug "Order status is valid." - Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" + Le_LinkCert="$(echo "$response" | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" _debug Le_LinkCert "$Le_LinkCert" if [ -z "$Le_LinkCert" ]; then _err "Sign error, can not find Le_LinkCert" @@ -5195,7 +5195,7 @@ _deactivate() { _err "Can not get domain new order." return 1 fi - _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" + _authorizations_seg="$(echo "$response" | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" _debug2 _authorizations_seg "$_authorizations_seg" if [ -z "$_authorizations_seg" ]; then _err "_authorizations_seg not found." @@ -5241,16 +5241,16 @@ _deactivate() { fi _debug "Trigger validation." vtype="$VTYPE_DNS" - entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" + entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ]; then _err "Error, can not get domain token $d" return 1 fi - token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" + token="$(echo "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" _debug token "$token" - uri="$(printf "%s\n" "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" + uri="$(echo "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" _debug uri "$uri" keyauthorization="$token.$thumbprint" @@ -5272,11 +5272,11 @@ _deactivate() { break fi - _vtype="$(printf "%s\n" "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')" + _vtype="$(echo "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')" _debug _vtype "$_vtype" _info "Found $_vtype" - uri="$(printf "%s\n" "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" + uri="$(echo "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" _debug uri "$uri" if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then From 2ffd8637e10d3ed7178769d219a6a85a09d79c63 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 16 Mar 2019 14:28:24 +0800 Subject: [PATCH 286/565] fix standalone content --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 3c7bc6d..d9ea4ee 100755 --- a/acme.sh +++ b/acme.sh @@ -2111,7 +2111,7 @@ _startserver() { echo 'HTTP/1.0 200 OK'; \ echo 'Content-Length\: $_content_len'; \ echo ''; \ -printf '$content';" & +printf -- '$content';" & serverproc="$!" } From 3f35006c264cf002a875b21a9cde97cc67ffccfa Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 16 Mar 2019 14:35:33 +0800 Subject: [PATCH 287/565] fix error message --- dnsapi/dns_namecom.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 254952d..a9a7ac5 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -130,6 +130,8 @@ _namecom_login() { if [ "$retcode" ]; then _info "Successfully logged in." else + _err "$response" + _err "Please add your ip to api whitelist" _err "Logging in failed." return 1 fi From 82b0ebb787ac87d1712a8cc3cc4982e030ed659a Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 16 Mar 2019 14:53:02 +0800 Subject: [PATCH 288/565] minor, remove dns records only when it's added success --- acme.sh | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index d9ea4ee..752b49b 100755 --- a/acme.sh +++ b/acme.sh @@ -3931,21 +3931,21 @@ $_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" + dns_entry="${_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" + dns_entry="${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$dvsep$_currentRoot" fi + _debug txtdomain "$txtdomain" txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" _debug txt "$txt" 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" + + dns_entry="$dns_entry$dvsep$txt${dvsep}$d_api" + _debug2 dns_entry "$dns_entry" if [ "$d_api" ]; then _info "Found domain api file: $d_api" else @@ -3984,6 +3984,9 @@ $_authorizations_map" _clearup return 1 fi + dns_entries="$dns_entries$dns_entry +" + _debug2 "$dns_entries" dnsadded='1' fi done From 2b36f4f57f1f9a484c5f6caf8fcff5472636a6a4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 16 Mar 2019 15:07:34 +0800 Subject: [PATCH 289/565] update --- dnsapi/dns_namecom.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index a9a7ac5..769a208 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -13,6 +13,8 @@ dns_namecom_add() { fulldomain=$1 txtvalue=$2 + Namecom_Username="${Namecom_Username:-$(_readaccountconf_mutable Namecom_Username)}" + Namecom_Token="${Namecom_Token:-$(_readaccountconf_mutable Namecom_Token)}" # First we need name.com credentials. if [ -z "$Namecom_Username" ]; then Namecom_Username="" @@ -29,8 +31,8 @@ dns_namecom_add() { fi # Save them in configuration. - _saveaccountconf Namecom_Username "$Namecom_Username" - _saveaccountconf Namecom_Token "$Namecom_Token" + _saveaccountconf_mutable Namecom_Username "$Namecom_Username" + _saveaccountconf_mutable Namecom_Token "$Namecom_Token" # Login in using API if ! _namecom_login; then @@ -46,7 +48,7 @@ dns_namecom_add() { # Add TXT record. _namecom_addtxt_json="{\"host\":\"$_sub_domain\",\"type\":\"TXT\",\"answer\":\"$txtvalue\",\"ttl\":\"300\"}" if _namecom_rest POST "domains/$_domain/records" "$_namecom_addtxt_json"; then - _retvalue=$(printf "%s\n" "$response" | _egrep_o "\"$_sub_domain\"") + _retvalue=$(echo "$response" | _egrep_o "\"$_sub_domain\"") if [ "$_retvalue" ]; then _info "Successfully added TXT record, ready for validation." return 0 @@ -63,6 +65,8 @@ dns_namecom_rm() { fulldomain=$1 txtvalue=$2 + Namecom_Username="${Namecom_Username:-$(_readaccountconf_mutable Namecom_Username)}" + Namecom_Token="${Namecom_Token:-$(_readaccountconf_mutable Namecom_Token)}" if ! _namecom_login; then return 1 fi @@ -75,7 +79,7 @@ dns_namecom_rm() { # Get the record id. if _namecom_rest GET "domains/$_domain/records"; then - _record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]+,\"domainName\":\"$_domain\",\"host\":\"$_sub_domain\",\"fqdn\":\"$fulldomain.\",\"type\":\"TXT\",\"answer\":\"$txtvalue\"" | cut -d \" -f 3 | _egrep_o [0-9]+) + _record_id=$(echo "$response" | _egrep_o "\"id\":[0-9]+,\"domainName\":\"$_domain\",\"host\":\"$_sub_domain\",\"fqdn\":\"$fulldomain.\",\"type\":\"TXT\",\"answer\":\"$txtvalue\"" | cut -d \" -f 3 | _egrep_o [0-9]+) _debug record_id "$_record_id" if [ "$_record_id" ]; then _info "Successfully retrieved the record id for ACME challenge." @@ -126,7 +130,7 @@ _namecom_login() { _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\"") + retcode=$(echo "$response" | _egrep_o "\"username\"\:\"$Namecom_Username\"") if [ "$retcode" ]; then _info "Successfully logged in." else From 653c77e852b879559c3daa338b9f4f247ac97ed2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 16 Mar 2019 15:09:49 +0800 Subject: [PATCH 290/565] update --- dnsapi/dns_namecom.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 769a208..0d5dd2c 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -29,7 +29,8 @@ dns_namecom_add() { _err "Please specify that in your environment variable." return 1 fi - + _debug Namecom_Username "$Namecom_Username" + _secure_debug Namecom_Token "$Namecom_Token" # Save them in configuration. _saveaccountconf_mutable Namecom_Username "$Namecom_Username" _saveaccountconf_mutable Namecom_Token "$Namecom_Token" From c74d597c84342f14a3f5af9d7c6c2514383a1242 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 16 Mar 2019 18:34:44 +0800 Subject: [PATCH 291/565] add debug info --- dnsapi/dns_netcup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh index 2273eb7..d5d7c22 100644 --- a/dnsapi/dns_netcup.sh +++ b/dnsapi/dns_netcup.sh @@ -8,6 +8,7 @@ end="https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON" client="" dns_netcup_add() { + _debug NC_Apikey "$NC_Apikey" login if [ "$NC_Apikey" = "" ] || [ "$NC_Apipw" = "" ] || [ "$NC_CID" = "" ]; then _err "No Credentials given" From 7decce97180bd1431eb63c6ed027bbb2898bdff1 Mon Sep 17 00:00:00 2001 From: Sylvia van Os Date: Mon, 18 Mar 2019 14:48:01 +0100 Subject: [PATCH 292/565] Resolve comments on pull request --- dnsapi/dns_openprovider.sh | 60 +++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/dnsapi/dns_openprovider.sh b/dnsapi/dns_openprovider.sh index 3d66dfe..a0171e4 100755 --- a/dnsapi/dns_openprovider.sh +++ b/dnsapi/dns_openprovider.sh @@ -50,7 +50,7 @@ dns_openprovider_add() { items="$response" while true; do - item="$(printf '%s' "$items" | _egrep_o '.*<\/openXML>' | sed -n -E 's/.*(.*<\/item>).*/\1/p')" + item="$(echo "$items" | _egrep_o '.*<\/openXML>' | sed -n 's/.*\(.*<\/item>\).*/\1/p')" _debug existing_items "$existing_items" _debug results_retrieved "$results_retrieved" _debug item "$item" @@ -59,24 +59,24 @@ dns_openprovider_add() { break fi - items="$(printf '%s' "$items" | sed "s$item")" + items="$(echo "$items" | sed "s|${item}||")" - results_retrieved=$((results_retrieved + 1)) - new_item="$(printf '%s' "$item" | sed -n -E "s/.*.*((.*)\.$_domain_name\.$_domain_extension<\/name>.*(.*<\/type>).*(.*<\/value>).*(.*<\/prio>).*(.*<\/ttl>)).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p")" + results_retrieved="$(_math "$results_retrieved" + 1)" + new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)\.'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" if [ -z "$new_item" ]; then # Base record - new_item="$(printf '%s' "$item" | sed -n -E "s/.*.*((.*)$_domain_name\.$_domain_extension<\/name>.*(.*<\/type>).*(.*<\/value>).*(.*<\/prio>).*(.*<\/ttl>)).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p")" + new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" fi - if [ -z "$(printf '%s' "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA)<\/type>.*")" ]; then + if [ -z "$(echo "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA)<\/type>.*")" ]; then _debug "not an allowed record type, skipping" "$new_item" continue fi - existing_items="$(printf '%s%s' "$existing_items" "$new_item")" + existing_items="$existing_items$new_item" done - total="$(printf '%s' "$response" | _egrep_o '.*?<\/total>' | sed -n -E 's/.*(.*)<\/total>.*/\1/p')" + total="$(echo "$response" | _egrep_o '.*?<\/total>' | sed -n 's/.*\(.*\)<\/total>.*/\1/p')" _debug total "$total" if [ "$results_retrieved" -eq "$total" ]; then @@ -85,7 +85,7 @@ dns_openprovider_add() { done _debug "Creating acme record" - acme_record="$(printf '%s' "$fulldomain" | sed -e "s/.$_domain_name.$_domain_extension$//")" + acme_record="$(echo "$fulldomain" | sed -e "s/.$_domain_name.$_domain_extension$//")" _openprovider_request "$(printf '%s%smaster%s%sTXT%s86400' "$_domain_name" "$_domain_extension" "$existing_items" "$acme_record" "$txtvalue")" return 0 @@ -127,7 +127,7 @@ dns_openprovider_rm() { # Remove acme records from items items="$response" while true; do - item="$(printf '%s' "$items" | _egrep_o '.*<\/openXML>' | sed -n -E 's/.*(.*<\/item>).*/\1/p')" + item="$(echo "$items" | _egrep_o '.*<\/openXML>' | sed -n 's/.*\(.*<\/item>\).*/\1/p')" _debug existing_items "$existing_items" _debug results_retrieved "$results_retrieved" _debug item "$item" @@ -136,30 +136,30 @@ dns_openprovider_rm() { break fi - items="$(printf '%s' "$items" | sed "s$item")" + items="$(echo "$items" | sed "s|${item}||")" - results_retrieved=$((results_retrieved + 1)) - if ! printf '%s' "$item" | grep -v "$fulldomain"; then + results_retrieved="$(_math "$results_retrieved" + 1)" + if ! echo "$item" | grep -v "$fulldomain"; then _debug "acme record, skipping" "$item" continue fi - new_item="$(printf '%s' "$item" | sed -n -E "s/.*.*((.*)\.$_domain_name\.$_domain_extension<\/name>.*(.*<\/type>).*(.*<\/value>).*(.*<\/prio>).*(.*<\/ttl>)).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p")" + new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)\.'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" if [ -z "$new_item" ]; then # Base record - new_item="$(printf '%s' "$item" | sed -n -E "s/.*.*((.*)$_domain_name\.$_domain_extension<\/name>.*(.*<\/type>).*(.*<\/value>).*(.*<\/prio>).*(.*<\/ttl>)).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p")" + new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" fi - if [ -z "$(printf '%s' "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA)<\/type>.*")" ]; then + if [ -z "$(echo "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA)<\/type>.*")" ]; then _debug "not an allowed record type, skipping" "$new_item" continue fi - existing_items="$(printf '%s%s' "$existing_items" "$new_item")" + existing_items="$existing_items$new_item" done - total="$(printf '%s' "$response" | _egrep_o '.*?<\/total>' | sed -n -E 's/.*(.*)<\/total>.*/\1/p')" + total="$(echo "$response" | _egrep_o '.*?<\/total>' | sed -n 's/.*\(.*\)<\/total>.*/\1/p')" _debug total "$total" @@ -185,18 +185,18 @@ _get_root() { results_retrieved=0 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 return 1 fi - _openprovider_request "$(printf '%s%s' "$(printf "%s" "$h" | cut -d . -f 1)" "$results_retrieved")" + _openprovider_request "$(printf '%s%s' "$(echo "$h" | cut -d . -f 1)" "$results_retrieved")" items="$response" while true; do - item="$(printf '%s' "$items" | _egrep_o '.*<\/openXML>' | sed -n -E 's/.*(.*<\/domain>).*/\1/p')" + item="$(echo "$items" | _egrep_o '.*<\/openXML>' | sed -n 's/.*\(.*<\/domain>\).*/\1/p')" _debug existing_items "$existing_items" _debug results_retrieved "$results_retrieved" _debug item "$item" @@ -205,26 +205,26 @@ _get_root() { break fi - items="$(printf '%s' "$items" | sed "s$item")" + items="$(echo "$items" | sed "s|${item}||")" - results_retrieved=$((results_retrieved + 1)) + results_retrieved="$(_math "$results_retrieved" + 1)" - _domain_name="$(printf "%s" "$item" | sed -n -E 's/.*.*(.*)<\/name>.*<\/domain>.*/\1/p')" - _domain_extension="$(printf "%s" "$item" | sed -n -E 's/.*.*(.*)<\/extension>.*<\/domain>.*/\1/p')" + _domain_name="$(echo "$item" | sed -n 's/.*.*\(.*\)<\/name>.*<\/domain>.*/\1/p')" + _domain_extension="$(echo "$item" | sed -n 's/.*.*\(.*\)<\/extension>.*<\/domain>.*/\1/p')" _debug _domain_name "$_domain_name" _debug _domain_extension "$_domain_extension" - if [ "$(printf "%s.%s" "$_domain_name" "$_domain_extension")" = "$h" ]; then + if [ "$_domain_name.$_domain_extension" = "$h" ]; then return 0 fi done - total="$(printf '%s' "$response" | _egrep_o '.*?<\/total>' | sed -n -E 's/.*(.*)<\/total>.*/\1/p')" + total="$(echo "$response" | _egrep_o '.*?<\/total>' | sed -n 's/.*\(.*\)<\/total>.*/\1/p')" _debug total "$total" if [ "$results_retrieved" -eq "$total" ]; then results_retrieved=0 - i=$(_math "$i" + 1) + i="$(_math "$i" + 1)" fi done return 1 @@ -233,9 +233,9 @@ _get_root() { _openprovider_request() { request_xml=$1 - xml_prefix=$(printf '') + xml_prefix=$(echo '') xml_content=$(printf '%s%s%s' "$OPENPROVIDER_USER" "$OPENPROVIDER_PASSWORDHASH" "$request_xml") - response="$(_post "$(printf "%s%s" "$xml_prefix" "$xml_content" | tr -d '\n')" "$OPENPROVIDER_API" "" "POST" "application/xml")" + response="$(_post "$(echo "$xml_prefix$xml_content" | tr -d '\n')" "$OPENPROVIDER_API" "" "POST" "application/xml")" _debug response "$response" if ! _contains "$response" "0.*"; then _err "API request failed." From 71cfd874aeaa8282efb2f1200666dab5fa6fec68 Mon Sep 17 00:00:00 2001 From: Sylvia van Os Date: Mon, 18 Mar 2019 16:10:58 +0100 Subject: [PATCH 293/565] Fix SC2116 --- dnsapi/dns_openprovider.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_openprovider.sh b/dnsapi/dns_openprovider.sh index a0171e4..1b1b760 100755 --- a/dnsapi/dns_openprovider.sh +++ b/dnsapi/dns_openprovider.sh @@ -233,7 +233,7 @@ _get_root() { _openprovider_request() { request_xml=$1 - xml_prefix=$(echo '') + xml_prefix='' xml_content=$(printf '%s%s%s' "$OPENPROVIDER_USER" "$OPENPROVIDER_PASSWORDHASH" "$request_xml") response="$(_post "$(echo "$xml_prefix$xml_content" | tr -d '\n')" "$OPENPROVIDER_API" "" "POST" "application/xml")" _debug response "$response" From 7679df062c246e72c24ce2a57ca5d58cd02095ca Mon Sep 17 00:00:00 2001 From: Herman Sletteng Date: Tue, 19 Mar 2019 14:16:05 +0100 Subject: [PATCH 294/565] dns_gdnsdk: Fixed stupid regex error, want literal "-", not a range --- dnsapi/dns_gdnsdk.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gdnsdk.sh b/dnsapi/dns_gdnsdk.sh index 7dc7894..8c4962c 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" | _egrep_o ' domain="[[:alnum:].-_]+' | sed 's/^.*"//') + _domains=$(echo "$_result" | _egrep_o ' domain="[[:alnum:]._-]+' | sed 's/^.*"//') if [ -z "$_domains" ]; then _err "Primary domain list not found!" return 1 From 34be7e99f01c716465f6f3701310ba81f6121d76 Mon Sep 17 00:00:00 2001 From: bz-heilig <35926736+bz-heilig@users.noreply.github.com> Date: Tue, 19 Mar 2019 15:04:37 +0100 Subject: [PATCH 295/565] Update README.md Added links for do.de API token creation and documentation of API. --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 3cce294..a5779a3 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1157,7 +1157,7 @@ The `ACTIVE24_Token` will be saved in `~/.acme.sh/account.conf` and will be reus ## 60. Use do.de API -Create an API token in your do.de account. +Create an API token in your do.de account ([Create token here](https://www.do.de/account/letsencrypt/) | [Documentation](https://www.do.de/wiki/LetsEncrypt_-_Entwickler)). Set your API token: ``` From 307336cfc4ca136514423f43294a1768b727a2a7 Mon Sep 17 00:00:00 2001 From: Valentin Brandl Date: Tue, 19 Mar 2019 18:42:47 +0100 Subject: [PATCH 296/565] Add deploy hook for mailcow This hook will copy the key and certificate chain to the specified mailcow installation (as described in https://mailcow.github.io/mailcow-dockerized-docs/firststeps-ssl/#use-own-certificates) and restarts the containers, that are using the certificates. The hook has 2 parameters: * `DEPLOY_MAILCOW_PATH`: The path to the mailcow installation (required) * `DEPLOY_MAILCOW_RELOAD`: The reload command, defaults to `docker-compose restart postfix-mailcow dovecot-mailcow nginx-mailcow` --- deploy/mailcow.sh | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 deploy/mailcow.sh diff --git a/deploy/mailcow.sh b/deploy/mailcow.sh new file mode 100644 index 0000000..3b38fa8 --- /dev/null +++ b/deploy/mailcow.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to mailcow. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +mailcow_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _ssl_path="${DEPLOY_MAILCOW_PATH}/data/assets/ssl/" + if [ ! -d "$_ssl_path"; ] then + _err "Cannot find mailcow ssl path: $_ssl_path" + return 1 + fi + + _info "Copying key and cert" + _real_key="$_ssl_path/key.pem" + if ! cat "$_ckey" >"$_real_key"; then + _err "Error: write key file to: $_real_key" + return 1 + fi + + _real_fullchain="$_ssl_path/cert.pem" + if ! cat "$_cfullchain" >"$_real_fullchain"; then + _err "Error: write cert file to: $_real_fullchain" + return 1 + fi + + DEFAULT_MAILCOW_RELOAD="docker-compose restart postfix-mailcow dovecot-mailcow nginx-mailcow" + _reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}" + + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" + fi + return 0 + +} From b581a171f0a09870fcae71272ec6fe5b99c4df20 Mon Sep 17 00:00:00 2001 From: Valentin Brandl Date: Tue, 19 Mar 2019 18:43:07 +0100 Subject: [PATCH 297/565] Add documentation for mailcow deploy hook --- deploy/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index 44d5322..8cced4d 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -391,3 +391,23 @@ acme.sh --deploy --deploy-hook mydevil -d example.com ``` That will remove old certificate and install new one. + +## 15. Deploy your cert to local mailcow server + +You can install your certificates to a local [mailcow](https://github.com/mailcow/mailcow-dockerized/) instance. The +deploy hook will copy the certificates and reload the containers, that use the certificates (`postfix-mailcow` +`dovecot-mailcow` and `nginx-mailcow`). + +```sh +$ export DEPLOY_MAILCOW_PATH="/path/to/mailcow" +$ acme.sh --deploy -d example.com --deploy-hook mailcow +``` + +The default command to restart is `docker-compose restart postfix-mailcow dovecot-mailcow nginx-mailcow`, if you want a +custom restart command, specify it by setting `DEPLOY_MAILCOW_RELOAD`: + +```sh +$ export DEPLOY_MAILCOW_PATH="/path/to/mailcow" +$ export DEPLOY_MAILCOW_RELOAD="docker-compose restart" +$ acme.sh --deploy -d example.com --deploy-hook mailcow +``` From d643a2ff13ae642ca16ecc87c04a0c88bb8a63bb Mon Sep 17 00:00:00 2001 From: Valentin Brandl Date: Tue, 19 Mar 2019 19:09:25 +0100 Subject: [PATCH 298/565] Check if mailcow path is set and fix directory check --- deploy/mailcow.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/deploy/mailcow.sh b/deploy/mailcow.sh index 3b38fa8..bdba3e2 100644 --- a/deploy/mailcow.sh +++ b/deploy/mailcow.sh @@ -20,8 +20,15 @@ mailcow_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _ssl_path="${DEPLOY_MAILCOW_PATH}/data/assets/ssl/" - if [ ! -d "$_ssl_path"; ] then + _mailcow_path="${DEPLOY_MAILCOW_PATH}" + + if [ -z "$_mailcow_path" ]; then + _err "Mailcow path is not found, please define DEPLOY_MAILCOW_PATH." + return 1 + fi + + _ssl_path="${_mailcow_path}/data/assets/ssl/" + if [ ! -d "$_ssl_path" ]; then _err "Cannot find mailcow ssl path: $_ssl_path" return 1 fi @@ -39,7 +46,7 @@ mailcow_deploy() { return 1 fi - DEFAULT_MAILCOW_RELOAD="docker-compose restart postfix-mailcow dovecot-mailcow nginx-mailcow" + DEFAULT_MAILCOW_RELOAD="cd ${_mailcow_path} && docker-compose restart postfix-mailcow dovecot-mailcow nginx-mailcow" _reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}" _info "Run reload: $_reload" From d604166194491503a54b5c73be4fc1986fae9456 Mon Sep 17 00:00:00 2001 From: Valentin Brandl Date: Tue, 19 Mar 2019 19:15:31 +0100 Subject: [PATCH 299/565] Fix formatting --- deploy/mailcow.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/mailcow.sh b/deploy/mailcow.sh index bdba3e2..3a806e8 100644 --- a/deploy/mailcow.sh +++ b/deploy/mailcow.sh @@ -23,14 +23,14 @@ mailcow_deploy() { _mailcow_path="${DEPLOY_MAILCOW_PATH}" if [ -z "$_mailcow_path" ]; then - _err "Mailcow path is not found, please define DEPLOY_MAILCOW_PATH." - return 1 + _err "Mailcow path is not found, please define DEPLOY_MAILCOW_PATH." + return 1 fi _ssl_path="${_mailcow_path}/data/assets/ssl/" if [ ! -d "$_ssl_path" ]; then - _err "Cannot find mailcow ssl path: $_ssl_path" - return 1 + _err "Cannot find mailcow ssl path: $_ssl_path" + return 1 fi _info "Copying key and cert" From 228c835466b41448897c23c41350dc07a29fe9e1 Mon Sep 17 00:00:00 2001 From: temoffey Date: Wed, 20 Mar 2019 03:03:10 +0300 Subject: [PATCH 300/565] gcore_cdn_deploy --- deploy/README.md | 15 +++++ deploy/gcore_cdn.sh | 130 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 deploy/gcore_cdn.sh diff --git a/deploy/README.md b/deploy/README.md index 44d5322..e89add8 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -391,3 +391,18 @@ acme.sh --deploy --deploy-hook mydevil -d example.com ``` That will remove old certificate and install new one. + +## 15. Deploy the cert to G-Core CDN servise + +Deploy the cert to G-Core CDN servise (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/). +Uses command line curl for send requests and jq for parse responses. + +Then you can deploy now: + +```sh +export DEPLOY_GCORE_CDN_USERNAME=myusername +export DEPLOY_GCORE_CDN_PASSWORD=mypassword +acme.sh --deploy -d example.com --deploy-hook gcore_cdn +``` + +Please note, need installed jq. diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh new file mode 100644 index 0000000..051226d --- /dev/null +++ b/deploy/gcore_cdn.sh @@ -0,0 +1,130 @@ +#!/usr/bin/env sh + +# Here is the script to deploy the cert to G-Core CDN servise (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/). +# Uses command line curl for send requests and jq for parse responses. +# Returns 0 when success. +# +# Written by temoffey +# Public domain, 2019 + +#export DEPLOY_GCORE_CDN_USERNAME=myusername +#export DEPLOY_GCORE_CDN_PASSWORD=mypassword + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain + +gcore_cdn_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" + + _fullchain=$(awk 1 ORS='\\n' "$_cfullchain") + _key=$(awk 1 ORS='\\n' "$_ckey") + + _debug _fullchain "$_fullchain" + _debug _key "$_key" + + if [ -z "$DEPLOY_GCORE_CDN_USERNAME" ]; then + if [ -z "$Le_Deploy_gcore_cdn_username" ]; then + _err "Please define the target username: export DEPLOY_GCORE_CDN_USERNAME=username" + return 1 + else + DEPLOY_GCORE_CDN_USERNAME="$Le_Deploy_gcore_cdn_username" + fi + else + _savedomainconf Le_Deploy_gcore_cdn_username "$DEPLOY_GCORE_CDN_USERNAME" + fi + + if [ -z "$DEPLOY_GCORE_CDN_PASSWORD" ]; then + if [ -z "$Le_Deploy_gcore_cdn_password" ]; then + _err "Please define the target password: export DEPLOY_GCORE_CDN_PASSWORD=password" + return 1 + else + DEPLOY_GCORE_CDN_PASSWORD="$Le_Deploy_gcore_cdn_password" + fi + else + _savedomainconf Le_Deploy_gcore_cdn_password "$DEPLOY_GCORE_CDN_PASSWORD" + fi + + if ! [ -x "$(command -v jq)" ]; then + _err "Please install the package jq: sudo apt-get install jq" + return 1 + fi + + _info "Get authorization token" + _request="{ \"username\": \"$DEPLOY_GCORE_CDN_USERNAME\", \"password\": \"$DEPLOY_GCORE_CDN_PASSWORD\" }" + _debug _request "$_request" + _response=$(curl -s -X POST https://api.gcdn.co/auth/signin -H "Content-Type:application/json" -d "$_request") + _debug _response "$_response" + _token=$(echo "$_response" | jq -r '.token') + _debug _token "$_token" + + if [ "$_token" == "null" ]; then + _err "Error G-Core Labs API authorization" + return 1 + fi + + _info "Find CDN resource with cname $_cdomain" + _response=$(curl -s -X GET https://api.gcdn.co/resources -H "Authorization:Token $_token") + _debug _response "$_response" + _resource=$(echo "$_response" | jq -r ".[] | select(.cname == \"$_cdomain\")") + _debug _resource "$_resource" + _resourceId=$(echo "$_resource" | jq -r '.id') + _sslDataOld=$(echo "$_resource" | jq -r '.sslData') + _originGroup=$(echo "$_resource" | jq -r '.originGroup') + _debug _resourceId "$_resourceId" + _debug _sslDataOld "$_sslDataOld" + _debug _originGroup "$_originGroup" + + if [ -z "$_resourceId" ] || [ "$_resourceId" == "null" ] || [ -z "$_originGroup" ] || [ "$_originGroup" == "null" ]; then + _err "Not found CDN resource with cname $_cdomain" + return 1 + fi + + _info "Add new SSL certificate" + _date=$(date "+%d.%m.%Y %H:%M:%S") + _request="{ \"name\": \"$_cdomain ($_date)\", \"sslCertificate\": \"$_fullchain\n\", \"sslPrivateKey\": \"$_key\n\" }" + _debug _request "$_request" + _response=$(curl -s -X POST https://api.gcdn.co/sslData -H "Content-Type:application/json" -H "Authorization:Token $_token" -d "$_request") + _debug _response "$_response" + _sslDataAdd=$(echo "$_response" | jq -r '.id') + _debug _sslDataAdd "$_sslDataAdd" + + if [ "$_sslDataAdd" == "null" ]; then + _err "Error new SSL certificate add" + return 1 + fi + + _info "Update CDN resource" + _request="{ \"originGroup\": $_originGroup, \"sslData\": $_sslDataAdd }" + _debug _request "$_request" + _response=$(curl -s -X PUT https://api.gcdn.co/resources/$_resourceId -H "Content-Type:application/json" -H "Authorization:Token $_token" -d "$_request") + _debug _response "$_response" + _sslDataNew=$(echo "$_response" | jq -r '.sslData') + _debug _sslDataNew "$_sslDataNew" + + if [ "$_sslDataNew" != "$_sslDataAdd" ]; then + _err "Error CDN resource update" + return 1 + fi + + if [ -z "$_sslDataOld" ] || [ "$_sslDataOld" = "null" ]; then + _info "Not found old SSL certificate" + else + _info "Delete old SSL certificate" + _response=$(curl -s -X DELETE https://api.gcdn.co/sslData/$_sslDataOld -H "Authorization:Token $_token") + _debug _response "$_response" + fi + + _info "Certificate successfully deployed" + return 0 +} \ No newline at end of file From 95cdb4b2bc606e1641850359e9bf55abce2d46f4 Mon Sep 17 00:00:00 2001 From: temoffey Date: Wed, 20 Mar 2019 14:02:11 +0300 Subject: [PATCH 301/565] fix syntax --- deploy/README.md | 4 ++-- deploy/gcore_cdn.sh | 26 ++++++++++++-------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index e89add8..76a6cc9 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -392,9 +392,9 @@ acme.sh --deploy --deploy-hook mydevil -d example.com That will remove old certificate and install new one. -## 15. Deploy the cert to G-Core CDN servise +## 15. Deploy the cert to G-Core CDN service -Deploy the cert to G-Core CDN servise (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/). +Deploy the cert to G-Core CDN service (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/). Uses command line curl for send requests and jq for parse responses. Then you can deploy now: diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index 051226d..621d445 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -# Here is the script to deploy the cert to G-Core CDN servise (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/). +# Here is the script to deploy the cert to G-Core CDN service (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/). # Uses command line curl for send requests and jq for parse responses. # Returns 0 when success. # @@ -37,22 +37,20 @@ gcore_cdn_deploy() { if [ -z "$Le_Deploy_gcore_cdn_username" ]; then _err "Please define the target username: export DEPLOY_GCORE_CDN_USERNAME=username" return 1 - else - DEPLOY_GCORE_CDN_USERNAME="$Le_Deploy_gcore_cdn_username" fi else - _savedomainconf Le_Deploy_gcore_cdn_username "$DEPLOY_GCORE_CDN_USERNAME" + Le_Deploy_gcore_cdn_username="$DEPLOY_GCORE_CDN_USERNAME" + _savedomainconf Le_Deploy_gcore_cdn_username "$Le_Deploy_gcore_cdn_username" fi if [ -z "$DEPLOY_GCORE_CDN_PASSWORD" ]; then if [ -z "$Le_Deploy_gcore_cdn_password" ]; then _err "Please define the target password: export DEPLOY_GCORE_CDN_PASSWORD=password" return 1 - else - DEPLOY_GCORE_CDN_PASSWORD="$Le_Deploy_gcore_cdn_password" fi else - _savedomainconf Le_Deploy_gcore_cdn_password "$DEPLOY_GCORE_CDN_PASSWORD" + Le_Deploy_gcore_cdn_password="$DEPLOY_GCORE_CDN_PASSWORD" + _savedomainconf Le_Deploy_gcore_cdn_password "$Le_Deploy_gcore_cdn_password" fi if ! [ -x "$(command -v jq)" ]; then @@ -61,14 +59,14 @@ gcore_cdn_deploy() { fi _info "Get authorization token" - _request="{ \"username\": \"$DEPLOY_GCORE_CDN_USERNAME\", \"password\": \"$DEPLOY_GCORE_CDN_PASSWORD\" }" + _request="{ \"username\": \"$Le_Deploy_gcore_cdn_username\", \"password\": \"$Le_Deploy_gcore_cdn_password\" }" _debug _request "$_request" _response=$(curl -s -X POST https://api.gcdn.co/auth/signin -H "Content-Type:application/json" -d "$_request") _debug _response "$_response" _token=$(echo "$_response" | jq -r '.token') _debug _token "$_token" - if [ "$_token" == "null" ]; then + if [ "$_token" = "null" ]; then _err "Error G-Core Labs API authorization" return 1 fi @@ -85,7 +83,7 @@ gcore_cdn_deploy() { _debug _sslDataOld "$_sslDataOld" _debug _originGroup "$_originGroup" - if [ -z "$_resourceId" ] || [ "$_resourceId" == "null" ] || [ -z "$_originGroup" ] || [ "$_originGroup" == "null" ]; then + if [ -z "$_resourceId" ] || [ "$_resourceId" = "null" ] || [ -z "$_originGroup" ] || [ "$_originGroup" = "null" ]; then _err "Not found CDN resource with cname $_cdomain" return 1 fi @@ -107,7 +105,7 @@ gcore_cdn_deploy() { _info "Update CDN resource" _request="{ \"originGroup\": $_originGroup, \"sslData\": $_sslDataAdd }" _debug _request "$_request" - _response=$(curl -s -X PUT https://api.gcdn.co/resources/$_resourceId -H "Content-Type:application/json" -H "Authorization:Token $_token" -d "$_request") + _response=$(curl -s -X PUT "https://api.gcdn.co/resources/$_resourceId" -H "Content-Type:application/json" -H "Authorization:Token $_token" -d "$_request") _debug _response "$_response" _sslDataNew=$(echo "$_response" | jq -r '.sslData') _debug _sslDataNew "$_sslDataNew" @@ -118,13 +116,13 @@ gcore_cdn_deploy() { fi if [ -z "$_sslDataOld" ] || [ "$_sslDataOld" = "null" ]; then - _info "Not found old SSL certificate" + _info "Not found old SSL certificate" else _info "Delete old SSL certificate" - _response=$(curl -s -X DELETE https://api.gcdn.co/sslData/$_sslDataOld -H "Authorization:Token $_token") + _response=$(curl -s -X DELETE "https://api.gcdn.co/sslData/$_sslDataOld" -H "Authorization:Token $_token") _debug _response "$_response" fi _info "Certificate successfully deployed" return 0 -} \ No newline at end of file +} From 89989adcadd31cbd162beff2ca7ab746c3928324 Mon Sep 17 00:00:00 2001 From: temoffey Date: Wed, 20 Mar 2019 14:05:18 +0300 Subject: [PATCH 302/565] fix syntax --- deploy/gcore_cdn.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index 621d445..18d137a 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -65,7 +65,7 @@ gcore_cdn_deploy() { _debug _response "$_response" _token=$(echo "$_response" | jq -r '.token') _debug _token "$_token" - + if [ "$_token" = "null" ]; then _err "Error G-Core Labs API authorization" return 1 @@ -97,7 +97,7 @@ gcore_cdn_deploy() { _sslDataAdd=$(echo "$_response" | jq -r '.id') _debug _sslDataAdd "$_sslDataAdd" - if [ "$_sslDataAdd" == "null" ]; then + if [ "$_sslDataAdd" = "null" ]; then _err "Error new SSL certificate add" return 1 fi From fbdc5a0eb540865b52d4647ac5eda84ecaa9a0be Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 20 Mar 2019 22:52:40 +0800 Subject: [PATCH 303/565] fix https://github.com/Neilpang/acme.sh/issues/2179 --- acme.sh | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 752b49b..f47a5eb 100755 --- a/acme.sh +++ b/acme.sh @@ -3750,7 +3750,8 @@ issue() { _on_issue_err "$_post_hook" return 1 fi - + Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)" + _debug Le_LinkOrder "$Le_LinkOrder" Le_OrderFinalize="$(echo "$response" | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" _debug Le_OrderFinalize "$Le_OrderFinalize" if [ -z "$Le_OrderFinalize" ]; then @@ -4249,13 +4250,10 @@ $_authorizations_map" _on_issue_err "$_post_hook" return 1 fi - Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)" if [ -z "$Le_LinkOrder" ]; then - _err "Sign error, can not get order link location header" - _err "responseHeaders" "$responseHeaders" - _on_issue_err "$_post_hook" - return 1 + Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)" fi + _savedomainconf "Le_LinkOrder" "$Le_LinkOrder" _link_cert_retry=0 @@ -4281,6 +4279,14 @@ $_authorizations_map" _on_issue_err "$_post_hook" return 1 fi + #the order is processing, so we are going to poll order status + if [ -z "$Le_LinkOrder" ]; then + _err "Sign error, can not get order link location header" + _err "responseHeaders" "$responseHeaders" + _on_issue_err "$_post_hook" + return 1 + fi + _info "Polling order status: $Le_LinkOrder" if ! _send_signed_request "$Le_LinkOrder"; then _err "Sign failed, can not post to Le_LinkOrder cert:$Le_LinkOrder." _err "$response" From 0629c2a086e390b5fc502ad5c0e6bdb8d11ac470 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 20 Mar 2019 23:01:24 +0800 Subject: [PATCH 304/565] move to wiki --- dnsapi/README.md | 1373 +--------------------------------------------- 1 file changed, 2 insertions(+), 1371 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index a5779a3..d9ab46f 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1,1375 +1,6 @@ # How to use DNS API +DNS api usage: -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). - -``` -export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" -export CF_Email="xxxx@sss.com" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_cf -d example.com -d www.example.com -``` - -The `CF_Key` and `CF_Email` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - - -## 2. Use DNSPod.cn domain API to automatically issue cert - -First you need to login to your DNSPod account to get your API Key and ID. - -``` -export DP_Id="1234" -export DP_Key="sADDsdasdgdsf" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_dp -d example.com -d www.example.com -``` - -The `DP_Id` and `DP_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - - -## 3. Use CloudXNS.com domain API to automatically issue cert - -First you need to login to your CloudXNS account to get your API Key and Secret. - -``` -export CX_Key="1234" -export CX_Secret="sADDsdasdgdsf" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_cx -d example.com -d www.example.com -``` - -The `CX_Key` and `CX_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - - -## 4. Use GoDaddy.com domain API to automatically issue cert - -First you need to login to your GoDaddy account to get your API Key and Secret. - -https://developer.godaddy.com/keys/ - -Please create a Production key, instead of a Test key. - -``` -export GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" -export GD_Secret="asdfsdafdsfdsfdsfdsfdsafd" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_gd -d example.com -d www.example.com -``` - -The `GD_Key` and `GD_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - - -## 5. Use PowerDNS embedded API to automatically issue cert - -First you need to login to your PowerDNS account to enable the API and set your API-Token in the configuration. - -https://doc.powerdns.com/md/httpapi/README/ - -``` -export PDNS_Url="http://ns.example.com:8081" -export PDNS_ServerId="localhost" -export PDNS_Token="0123456789ABCDEF" -export PDNS_Ttl=60 -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_pdns -d example.com -d www.example.com -``` - -The `PDNS_Url`, `PDNS_ServerId`, `PDNS_Token` and `PDNS_Ttl` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - - -## 6. Use OVH/kimsufi/soyoustart/runabove API to automatically issue cert - -https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api - - -## 7. Use nsupdate to automatically issue cert - -First, generate a key for updating the zone -``` -b=$(dnssec-keygen -a hmac-sha512 -b 512 -n USER -K /tmp foo) -cat > /etc/named/keys/update.key < /etc/knot/acme.key -``` - -Include this key in your knot configuration file. - -``` -include: /etc/knot/acme.key -``` - -Next, configure your zone to allow dynamic updates. - -Dynamic updates for the zone are allowed via proper ACL rule with the `update` action. For in-depth instructions, please see [Knot DNS's documentation](https://www.knot-dns.cz/documentation/). - -``` -acl: - - id: acme_acl - address: 192.168.1.0/24 - key: acme_key - action: update - -zone: - - domain: example.com - file: example.com.zone - acl: acme_acl -``` - -Finally, make the DNS server and TSIG Key available to `acme.sh` - -``` -export KNOT_SERVER="dns.example.com" -export KNOT_KEY=`grep \# /etc/knot/acme.key | cut -d' ' -f2` -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_knot -d example.com -d www.example.com -``` - -The `KNOT_SERVER` and `KNOT_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 20. Use DigitalOcean API (native) - -You need to obtain a read and write capable API key from your DigitalOcean account. See: https://www.digitalocean.com/help/api/ - -``` -export DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_dgon -d example.com -d www.example.com -``` - -## 21. Use ClouDNS.net API - -You need to set the HTTP API user ID and password credentials. See: https://www.cloudns.net/wiki/article/42/. For security reasons, it's recommended to use a sub user ID that only has access to the necessary zones, as a regular API user has access to your entire account. - -``` -# Use this for a sub auth ID -export CLOUDNS_SUB_AUTH_ID=XXXXX -# Use this for a regular auth ID -#export CLOUDNS_AUTH_ID=XXXXX -export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com -``` -The `CLOUDNS_AUTH_ID` and `CLOUDNS_AUTH_PASSWORD` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 22. Use Infoblox API - -First you need to create/obtain API credentials on your Infoblox appliance. - -``` -export Infoblox_Creds="username:password" -export Infoblox_Server="ip or fqdn of infoblox appliance" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com -``` - -Note: This script will automatically create and delete the ephemeral txt record. -The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - - -## 23. Use VSCALE API - -First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). - -``` -export VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_vscale -d example.com -d www.example.com -``` - -## 24. Use Dynu API - -First you need to create/obtain API credentials from your Dynu account. See: https://www.dynu.com/resources/api/documentation - -``` -export Dynu_ClientId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -export Dynu_Secret="yyyyyyyyyyyyyyyyyyyyyyyyy" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_dynu -d example.com -d www.example.com -``` - -The `Dynu_ClientId` and `Dynu_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 25. Use DNSimple API - -First you need to login to your DNSimple account and generate a new oauth token. - -https://dnsimple.com/a/{your account id}/account/access_tokens - -Note that this is an _account_ token and not a user token. The account token is -needed to infer the `account_id` used in requests. A user token will not be able -to determine the correct account to use. - -``` -export DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje" -``` - -To issue the cert just specify the `dns_dnsimple` API. - -``` -acme.sh --issue --dns dns_dnsimple -d example.com -``` - -The `DNSimple_OAUTH_TOKEN` will be saved in `~/.acme.sh/account.conf` and will -be reused when needed. - -If you have any issues with this integration please report them to -https://github.com/pho3nixf1re/acme.sh/issues. - -## 26. Use NS1.com API - -``` -export NS1_Key="fdmlfsdklmfdkmqsdfk" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_nsone -d example.com -d www.example.com -``` - -## 27. Use DuckDNS.org API - -``` -export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" -``` - -Please note that since DuckDNS uses StartSSL as their cert provider, thus ---insecure may need to be used when issuing certs: -``` -acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org -``` - -For issues, please report to https://github.com/raidenii/acme.sh/issues. - -## 28. Use Name.com API - -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" -export Namecom_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -``` - -And now you can issue certs with: - -``` -acme.sh --issue --dns dns_namecom -d example.com -d www.example.com -``` - -For issues, please report to https://github.com/raidenii/acme.sh/issues. - -## 29. Use Dyn Managed DNS API to automatically issue cert - -First, login to your Dyn Managed DNS account: https://portal.dynect.net/login/ - -It is recommended to add a new user specific for API access. - -The minimum "Zones & Records Permissions" required are: -``` -RecordAdd -RecordUpdate -RecordDelete -RecordGet -ZoneGet -ZoneAddNode -ZoneRemoveNode -ZonePublish -``` - -Pass the API user credentials to the environment: -``` -export DYN_Customer="customer" -export DYN_Username="apiuser" -export DYN_Password="secret" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_dyn -d example.com -d www.example.com -``` - -The `DYN_Customer`, `DYN_Username` and `DYN_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 30. Use pdd.yandex.ru API - -``` -export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -``` - -Follow these instructions to get the token for your domain https://tech.yandex.com/domain/doc/concepts/access-docpage/ -``` -acme.sh --issue --dns dns_yandex -d mydomain.example.org -``` - -For issues, please report to https://github.com/non7top/acme.sh/issues. - -## 31. Use Hurricane Electric - -Hurricane Electric (https://dns.he.net/) doesn't have an API so just set your login credentials like so: - -``` -export HE_Username="yourusername" -export HE_Password="password" -``` - -Then you can issue your certificate: - -``` -acme.sh --issue --dns dns_he -d example.com -d www.example.com -``` - -The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -Please report any issues to https://github.com/angel333/acme.sh or to . - -## 32. Use UnoEuro API to automatically issue cert - -First you need to login to your UnoEuro account to get your API key. - -``` -export UNO_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" -export UNO_User="UExxxxxx" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_unoeuro -d example.com -d www.example.com -``` - -The `UNO_Key` and `UNO_User` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 33. Use INWX - -[INWX](https://www.inwx.de/) offers an [xmlrpc api](https://www.inwx.de/de/help/apidoc) with your standard login credentials, set them like so: - -``` -export INWX_User="yourusername" -export INWX_Password="password" -``` - -Then you can issue your certificates with: - -``` -acme.sh --issue --dns dns_inwx -d example.com -d www.example.com -``` - -The `INWX_User` and `INWX_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -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. - -``` -export SERVERCOW_API_Username=username -export SERVERCOW_API_Password=password -``` - -Now you cann issue a cert: - -``` -acme.sh --issue --dns dns_servercow -d example.com -d www.example.com -``` -Both, `SERVERCOW_API_Username` and `SERVERCOW_API_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 35. Use Namesilo.com API - -You'll need to generate an API key at https://www.namesilo.com/account_api.php -Optionally you may restrict the access to an IP range there. - -``` -export Namesilo_Key="xxxxxxxxxxxxxxxxxxxxxxxx" -``` - -And now you can issue certs with: - -``` -acme.sh --issue --dns dns_namesilo --dnssleep 900 -d example.com -d www.example.com -``` - -## 36. Use autoDNS (InternetX) - -[InternetX](https://www.internetx.com/) offers an [xml api](https://help.internetx.com/display/API/AutoDNS+XML-API) with your standard login credentials, set them like so: - -``` -export AUTODNS_USER="yourusername" -export AUTODNS_PASSWORD="password" -export AUTODNS_CONTEXT="context" -``` - -Then you can issue your certificates with: - -``` -acme.sh --issue --dns dns_autodns -d example.com -d www.example.com -``` - -The `AUTODNS_USER`, `AUTODNS_PASSWORD` and `AUTODNS_CONTEXT` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 37. Use Azure DNS - -You have to create a service principal first. See:[How to use Azure DNS](../../../wiki/How-to-use-Azure-DNS) - -``` -export AZUREDNS_SUBSCRIPTIONID="12345678-9abc-def0-1234-567890abcdef" -export AZUREDNS_TENANTID="11111111-2222-3333-4444-555555555555" -export AZUREDNS_APPID="3b5033b5-7a66-43a5-b3b9-a36b9e7c25ed" -export AZUREDNS_CLIENTSECRET="1b0224ef-34d4-5af9-110f-77f527d561bd" -``` - -Then you can issue your certificates with: - -``` -acme.sh --issue --dns dns_azure -d example.com -d www.example.com -``` - -`AZUREDNS_SUBSCRIPTIONID`, `AZUREDNS_TENANTID`,`AZUREDNS_APPID` and `AZUREDNS_CLIENTSECRET` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 38. Use selectel.com(selectel.ru) domain API to automatically issue cert - -First you need to login to your account to get your API key from: https://my.selectel.ru/profile/apikeys. - -```sh -export SL_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" - -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_selectel -d example.com -d www.example.com -``` - -The `SL_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 39. Use zonomi.com domain API to automatically issue cert - -First you need to login to your account to find your API key from: http://zonomi.com/app/dns/dyndns.jsp - -Your will find your api key in the example urls: - -```sh -https://zonomi.com/app/dns/dyndns.jsp?host=example.com&api_key=1063364558943540954358668888888888 -``` - -```sh -export ZM_Key="1063364558943540954358668888888888" - -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_zonomi -d example.com -d www.example.com -``` - -The `ZM_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 40. Use DreamHost DNS API - -DNS API keys may be created at https://panel.dreamhost.com/?tree=home.api. -Ensure the created key has add and remove privelages. - -``` -export DH_API_KEY="" -acme.sh --issue --dns dns_dreamhost -d example.com -d www.example.com -``` - -The 'DH_API_KEY' will be saved in `~/.acme.sh/account.conf` and will -be reused when needed. - -## 41. Use DirectAdmin API -The DirectAdmin interface has it's own Let's encrypt functionality, but this -script can be used to generate certificates for names which are not hosted on -DirectAdmin - -User must provide login data and URL to the DirectAdmin incl. port. -You can create an user which only has access to - -- CMD_API_DNS_CONTROL -- CMD_API_SHOW_DOMAINS - -By using the Login Keys function. -See also https://www.directadmin.com/api.php and https://www.directadmin.com/features.php?id=1298 - -``` -export DA_Api="https://remoteUser:remotePassword@da.domain.tld:8443" -export DA_Api_Insecure=1 -``` -Set `DA_Api_Insecure` to 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1) - -Ok, let's issue a cert now: -``` -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 - -First, get your API key at https://my.zilore.com/account/api - -``` -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 *.example.com -``` - -The `Zilore_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 44. Use Loopia.se 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. -## 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. -## 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. - -## 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) - -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. - -``` -export EUSERV_Username="99999.user123" -export EUSERV_Password="Asbe54gHde" -``` - -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 -``` - -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. - -## 49. 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). - -## 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. - -## 51. Use netcup DNS API to automatically issue cert - -First you need to login in your CCP account to get your API Key and API Password. -``` -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. -## 52. Use GratisDNS.dk - -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. - -```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. - -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 --dnssleep 300 -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 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="..." -export NAMECHEAP_API_KEY="..." -export NAMECHEAP_SOURCEIP="..." -``` - -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. - -Now you can issue a certificate. - -```sh -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. - -## 55. 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. - -## 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. - -## 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_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 -``` - -## 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. - -## 60. Use do.de API - -Create an API token in your do.de account ([Create token here](https://www.do.de/account/letsencrypt/) | [Documentation](https://www.do.de/wiki/LetsEncrypt_-_Entwickler)). - -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. - -## 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. - -## 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 -``` - -## 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. - -## 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). - -## 67. Use Core-Networks API to automatically issue cert - -First you need to login to your Core-Networks account to to set up an API-User. -Then export username and password to use these credentials. - -``` -export CN_User="user" -export CN_Password="passowrd" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_cn -d example.com -d www.example.com -``` - -The `CN_User` and `CN_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 68. Use NederHost API - -Create an API token in Mijn NederHost. - -Set your API key: -``` -export NederHost_Key='xxx' -``` - -To issue a certificate run: -``` -acme.sh --issue --dns dns_nederhost -d example.com -d *.example.com -``` - -## 69. Use Zone.ee DNS API - -First, you'll need to retrive your API key. Estonian insructions https://help.zone.eu/kb/zoneid-api-v2/ - -``` -export ZONE_Username=yourusername -export ZONE_Key=keygoeshere -``` - -To issue a cert run: - -``` -acme.sh --issue -d example.com -d www.example.com --dns dns_zone -``` - -`ZONE_Username` and `ZONE_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 70. Use UltraDNS API - -UltraDNS is a paid for service that provides DNS, as well as Web and Mail forwarding (as well as reporting, auditing, and advanced tools). - -More information can be found here: https://www.security.neustar/lp/ultra20/index.html - -The REST API documentation for this service is found here: https://portal.ultradns.com/static/docs/REST-API_User_Guide.pdf - -Set your UltraDNS User name, and password; these would be the same you would use here: - -https://portal.ultradns.com/ - or if you create an API only user, that username and password would be better utilized. - -``` -export ULTRA_USR="abcd" -export ULTRA_PWD="efgh" - -To issue a cert run: - -acme.sh --issue --dns dns_ultra -d example.com -d www.example.com -``` - -`ULTRA_USR` and `ULTRA_PWD` will be saved in `~/.acme.sh/account.conf` and will be resued when needed. - -# Use custom API - -If your API is not supported yet, you can write your own DNS API. - -Let's assume you want to name it 'myapi': - -1. Create a bash script named `~/.acme.sh/dns_myapi.sh`, -2. In the script you must have a function named `dns_myapi_add()` which will be called by acme.sh to add the DNS records. -3. Then you can use your API to issue cert like this: - -``` -acme.sh --issue --dns dns_myapi -d example.com -d www.example.com -``` - -For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) - -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/dnsapi From 61bcd67a5d34e0183b421c5d941fa602706e3394 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 20 Mar 2019 23:03:49 +0800 Subject: [PATCH 305/565] move to wiki --- deploy/README.md | 411 +---------------------------------------------- 1 file changed, 2 insertions(+), 409 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 8cced4d..fc633ad 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1,413 +1,6 @@ # Using deploy api -Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). +deploy hook usage: -Here are the scripts to deploy the certs/key to the server/services. +https://github.com/Neilpang/acme.sh/wiki/deployhooks -## 1. Deploy the certs to your cpanel host - -If you want to deploy using cpanel UAPI see 7. - -(cpanel deploy hook is not finished yet, this is just an example.) - - - -Then you can deploy now: - -```sh -export DEPLOY_CPANEL_USER=myusername -export DEPLOY_CPANEL_PASSWORD=PASSWORD -acme.sh --deploy -d example.com --deploy-hook cpanel -``` - -## 2. Deploy ssl cert on kong proxy engine based on api - -Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). -Currently supports Kong-v0.10.x. - -```sh -acme.sh --deploy -d ftp.example.com --deploy-hook kong -``` - -## 3. Deploy the cert to remote server through SSH access - -The ssh deploy plugin allows you to deploy certificates to a remote host -using SSH command to connect to the remote server. The ssh plugin is invoked -with the following command... - -```sh -acme.sh --deploy -d example.com --deploy-hook ssh -``` -Prior to running this for the first time you must tell the plugin where -and how to deploy the certificates. This is done by exporting the following -environment variables. This is not required for subsequent runs as the -values are stored by acme.sh in the domain configuration files. - -Required... -``` -export DEPLOY_SSH_USER=username -``` -Optional... -``` -export DEPLOY_SSH_CMD=custom ssh command -export DEPLOY_SSH_SERVER=url or ip address of remote host -export DEPLOY_SSH_KEYFILE=filename for private key -export DEPLOY_SSH_CERTFILE=filename for certificate file -export DEPLOY_SSH_CAFILE=filename for intermediate CA file -export DEPLOY_SSH_FULLCHAIN=filename for fullchain file -export DEPLOY_SSH_REMOTE_CMD=command to execute on remote host -export DEPLOY_SSH_BACKUP=yes or no -``` - -**DEPLOY_SSH_USER** -Username at the remote host that SSH will login with. Note that -SSH must be able to login to remote host without a password... SSH Keys -must have been exchanged with the remote host. Validate and test that you -can login to USER@URL from the host running acme.sh before using this script. - -The USER@URL at the remote server must also have has permissions to write to -the target location of the certificate files and to execute any commands -(e.g. to stop/start services). - -**DEPLOY_SSH_CMD** -You can customize the ssh command used to connect to the remote host. For example -if you need to connect to a specific port at the remote server you can set this -to, for example, "ssh -p 22" or to use `sshpass` to provide password inline -instead of exchanging ssh keys (this is not recommended, using keys is -more secure). - -**DEPLOY_SSH_SERVER** -URL or IP Address of the remote server. If not provided then the domain -name provided on the acme.sh --deploy command line is used. - -**DEPLOY_SSH_KEYFILE** -Target filename for the private key issued by LetsEncrypt. - -**DEPLOY_SSH_CERTFILE** -Target filename for the certificate issued by LetsEncrypt. -If this is the same as the previous filename (for keyfile) then it is -appended to the same file. - -**DEPLOY_SSH_CAFILE** -Target filename for the CA intermediate certificate issued by LetsEncrypt. -If this is the same as a previous filename (for keyfile or certfile) then -it is appended to the same file. - -**DEPLOY_SSH_FULLCHAIN** -Target filename for the fullchain certificate issued by LetsEncrypt. -If this is the same as a previous filename (for keyfile, certfile or -cafile) then it is appended to the same file. - -**DEPLOY_SSH_REMOTE_CMD** -Command to execute on the remote server after copying any certificates. This -could be any additional command required for example to stop and restart -the service. - -**DEPLOY_SSH_BACKUP** -Before writing a certificate file to the remote server the existing -certificate will be copied to a backup directory on the remote server. -These are placed in a hidden directory in the home directory of the SSH -user -```sh -~/.acme_ssh_deploy/[domain name]-backup-[timestamp] -``` -Any backups older than 180 days will be deleted when new certificates -are deployed. This defaults to "yes" set to "no" to disable backup. - -###Examples using SSH deploy -The following example illustrates deploying certificates to a QNAP NAS -(tested with QTS version 4.2.3) - -```sh -export DEPLOY_SSH_USER="admin" -export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" -export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" -export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" -export DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" - -acme.sh --deploy -d qnap.example.com --deploy-hook ssh -``` -Note how in this example both the private key and certificate point to -the same file. This will result in the certificate being appended -to the same file as the private key... a common requirement of several -services. - -The next example illustrates deploying certificates to a Unifi -Controller (tested with version 5.4.11). - -```sh -export DEPLOY_SSH_USER="root" -export DEPLOY_SSH_KEYFILE="/var/lib/unifi/unifi.example.com.key" -export DEPLOY_SSH_FULLCHAIN="/var/lib/unifi/unifi.example.com.cer" -export DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ - -inkey /var/lib/unifi/unifi.example.com.key \ - -in /var/lib/unifi/unifi.example.com.cer \ - -out /var/lib/unifi/unifi.example.com.p12 \ - -name ubnt -password pass:temppass \ - && keytool -importkeystore -deststorepass aircontrolenterprise \ - -destkeypass aircontrolenterprise \ - -destkeystore /var/lib/unifi/keystore \ - -srckeystore /var/lib/unifi/unifi.example.com.p12 \ - -srcstoretype PKCS12 -srcstorepass temppass -alias ubnt -noprompt \ - && service unifi restart" - -acme.sh --deploy -d unifi.example.com --deploy-hook ssh -``` -In this example we execute several commands on the remote host -after the certificate files have been copied... to generate a pkcs12 file -compatible with Unifi, to import it into the Unifi keystore and then finally -to restart the service. - -Note also that once the certificate is imported -into the keystore the individual certificate files are no longer -required. We could if we desired delete those files immediately. If we -do that then we should disable backup at the remote host (as there are -no files to backup -- they were erased during deployment). For example... -```sh -export DEPLOY_SSH_BACKUP=no -# modify the end of the remote command... -&& rm /var/lib/unifi/unifi.example.com.key \ - /var/lib/unifi/unifi.example.com.cer \ - /var/lib/unifi/unifi.example.com.p12 \ -&& service unifi restart -``` - -## 4. Deploy the cert to local vsftpd server - -```sh -acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd -``` - -The default vsftpd conf file is `/etc/vsftpd.conf`, if your vsftpd conf is not in the default location, you can specify one: - -```sh -export DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf" - -acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd -``` - -The default command to restart vsftpd server is `service vsftpd restart`, if it doesn't work, you can specify one: - -```sh -export DEPLOY_VSFTPD_RELOAD="/etc/init.d/vsftpd restart" - -acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd -``` - -## 5. Deploy the cert to local exim4 server - -```sh -acme.sh --deploy -d ftp.example.com --deploy-hook exim4 -``` - -The default exim4 conf file is `/etc/exim/exim.conf`, if your exim4 conf is not in the default location, you can specify one: - -```sh -export DEPLOY_EXIM4_CONF="/etc/exim4/exim4.conf.template" - -acme.sh --deploy -d ftp.example.com --deploy-hook exim4 -``` - -The default command to restart exim4 server is `service exim4 restart`, if it doesn't work, you can specify one: - -```sh -export DEPLOY_EXIM4_RELOAD="/etc/init.d/exim4 restart" - -acme.sh --deploy -d ftp.example.com --deploy-hook exim4 -``` - -## 6. Deploy the cert to OSX Keychain - -```sh -acme.sh --deploy -d ftp.example.com --deploy-hook keychain -``` - -## 7. Deploy to cpanel host using UAPI - -This hook is using UAPI and works in cPanel & WHM version 56 or newer. -``` -acme.sh --deploy -d example.com --deploy-hook cpanel_uapi -``` -DEPLOY_CPANEL_USER is required only if you run the script as root and it should contain cpanel username. -```sh -export DEPLOY_CPANEL_USER=username -acme.sh --deploy -d example.com --deploy-hook cpanel_uapi -``` -Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separate certificate for each domain. - -## 8. Deploy the cert to your FRITZ!Box router - -You must specify the credentials that have administrative privileges on the FRITZ!Box in order to deploy the certificate, plus the URL of your FRITZ!Box, through the following environment variables: -```sh -$ export DEPLOY_FRITZBOX_USERNAME=my_username -$ export DEPLOY_FRITZBOX_PASSWORD=the_password -$ export DEPLOY_FRITZBOX_URL=https://fritzbox.example.com -``` - -After the first deployment, these values will be stored in your $HOME/.acme.sh/account.conf. You may now deploy the certificate like this: - -```sh -acme.sh --deploy -d fritzbox.example.com --deploy-hook fritzbox -``` - -## 9. Deploy the cert to strongswan - -```sh -acme.sh --deploy -d ftp.example.com --deploy-hook strongswan -``` - -## 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 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 -``` - -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 -``` - -## 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" -``` - -## 13. Deploy your certificate to Qiniu.com - -使用 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 -your domain name. You can enable it in https://portal.qiniu.com/cdn/domain. - -```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 -``` - -(Optional), If you are using wildcard certificate, -you may need export `QINIU_CDN_DOMAIN` to specify which domain -you want to update (please note the leading dot): - -```sh -$ 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. - -## 15. Deploy your cert to local mailcow server - -You can install your certificates to a local [mailcow](https://github.com/mailcow/mailcow-dockerized/) instance. The -deploy hook will copy the certificates and reload the containers, that use the certificates (`postfix-mailcow` -`dovecot-mailcow` and `nginx-mailcow`). - -```sh -$ export DEPLOY_MAILCOW_PATH="/path/to/mailcow" -$ acme.sh --deploy -d example.com --deploy-hook mailcow -``` - -The default command to restart is `docker-compose restart postfix-mailcow dovecot-mailcow nginx-mailcow`, if you want a -custom restart command, specify it by setting `DEPLOY_MAILCOW_RELOAD`: - -```sh -$ export DEPLOY_MAILCOW_PATH="/path/to/mailcow" -$ export DEPLOY_MAILCOW_RELOAD="docker-compose restart" -$ acme.sh --deploy -d example.com --deploy-hook mailcow -``` From 16b0704acc635a5e43033d199c3f7ba0208cfbaa Mon Sep 17 00:00:00 2001 From: temoffey Date: Wed, 20 Mar 2019 18:10:53 +0300 Subject: [PATCH 306/565] remove readme --- deploy/README.md | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 76a6cc9..44d5322 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -391,18 +391,3 @@ acme.sh --deploy --deploy-hook mydevil -d example.com ``` That will remove old certificate and install new one. - -## 15. Deploy the cert to G-Core CDN service - -Deploy the cert to G-Core CDN service (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/). -Uses command line curl for send requests and jq for parse responses. - -Then you can deploy now: - -```sh -export DEPLOY_GCORE_CDN_USERNAME=myusername -export DEPLOY_GCORE_CDN_PASSWORD=mypassword -acme.sh --deploy -d example.com --deploy-hook gcore_cdn -``` - -Please note, need installed jq. From 236acbd6e8c45f68d0cecc648cd124796ae4427f Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 20 Mar 2019 23:11:13 +0800 Subject: [PATCH 307/565] move to wiki --- README.md | 88 +++---------------------------------------------------- 1 file changed, 4 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index 68d1b57..6682c55 100644 --- a/README.md +++ b/README.md @@ -290,90 +290,10 @@ If your DNS provider supports API access, we can use that API to automatically i You don't have to do anything manually! -### Currently acme.sh supports: - -1. CloudFlare.com API -1. DNSPod.cn API -1. CloudXNS.com API -1. GoDaddy.com API -1. PowerDNS.com API -1. OVH, kimsufi, soyoustart and runabove API -1. nsupdate API -1. LuaDNS.com API -1. DNSMadeEasy.com API -1. AWS Route 53 -1. aliyun.com(阿里云) API -1. ISPConfig 3.1 API -1. Alwaysdata.com API -1. Linode.com API -1. FreeDNS (https://freedns.afraid.org/) -1. cyon.ch -1. Domain-Offensive/Resellerinterface/Domainrobot API -1. Gandi LiveDNS API -1. Knot DNS API -1. DigitalOcean API (native) -1. ClouDNS.net API -1. Infoblox NIOS API (https://www.infoblox.com/) -1. VSCALE (https://vscale.io/) -1. Dynu API (https://www.dynu.com) -1. DNSimple API -1. NS1.com API -1. DuckDNS.org API -1. Name.com API -1. Dyn Managed DNS API -1. Yandex PDD API (https://pdd.yandex.ru) -1. Hurricane Electric DNS service (https://dns.he.net) -1. UnoEuro API (https://www.unoeuro.com/) -1. INWX (https://www.inwx.de/) -1. Servercow (https://servercow.de) -1. Namesilo (https://www.namesilo.com) -1. InternetX autoDNS API (https://internetx.com) -1. Azure DNS -1. selectel.com(selectel.ru) DNS API -1. zonomi.com DNS API -1. DreamHost.com API -1. DirectAdmin API -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) -1. TELE3 (https://www.tele3.cz) -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) -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/) -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/) -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) -1. Rackspace Cloud DNS (https://www.rackspace.com) -1. Online.net API (https://online.net/) -1. MyDevil.net (https://www.mydevil.net/) -1. Core-Networks.de (https://core-networks.de) -1. NederHost API (https://www.nederhost.nl/) -1. Zone.ee (zone.eu) API (https://api.zone.eu/v2) -1. UltraDNS API (https://portal.ultradns.com) - -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.)** - - -**More APIs coming soon...** - -If your DNS provider is not on the supported list above, you can write your own DNS API script easily. If you do, please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute it to the project. - -For more details: [How to use DNS API](dnsapi) +### Currently acme.sh supports most of the dns providers: + +https://github.com/Neilpang/acme.sh/wiki/dnsapi + # 9. Use DNS manual mode: From 92477800738ceb8d465395ae2365a5404a3e64e2 Mon Sep 17 00:00:00 2001 From: Maximilian Hippler Date: Wed, 20 Mar 2019 22:34:50 +0100 Subject: [PATCH 308/565] Added oathtool to Dockerfile --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 68385d7..5aa8da1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,7 @@ RUN apk update -f \ curl \ socat \ tzdata \ + && apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/testing oath-toolkit-oathtool \ && rm -rf /var/cache/apk/* ENV LE_CONFIG_HOME /acme.sh From 3bb97b81ded2d7528cd432d2219df69af5de2870 Mon Sep 17 00:00:00 2001 From: James Qian Date: Thu, 14 Mar 2019 13:26:58 +0800 Subject: [PATCH 309/565] dnsapi: add deSEC.io api support Signed-off-by: James Qian --- dnsapi/dns_desec.sh | 204 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 dnsapi/dns_desec.sh diff --git a/dnsapi/dns_desec.sh b/dnsapi/dns_desec.sh new file mode 100644 index 0000000..6488b7f --- /dev/null +++ b/dnsapi/dns_desec.sh @@ -0,0 +1,204 @@ +#!/usr/bin/env sh +# +# deSEC.io Domain API +# +# Author: Zheng Qian +# +# deSEC API doc +# https://desec.readthedocs.io/en/latest/ + +REST_API="https://desec.io/api/v1/domains" + +######## Public functions ##################### + +#Usage: dns_desec_add _acme-challenge.foobar.dedyn.io "d41d8cd98f00b204e9800998ecf8427e" +dns_desec_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using desec.io api" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + DEDYN_TOKEN="${DEDYN_TOKEN:-$(_readaccountconf_mutable DEDYN_TOKEN)}" + DEDYN_NAME="${DEDYN_NAME:-$(_readaccountconf_mutable DEDYN_NAME)}" + + if [ -z "$DEDYN_TOKEN" ] || [ -z "$DEDYN_NAME" ]; then + DEDYN_TOKEN="" + DEDYN_NAME="" + _err "You don't specify DEDYN_TOKEN and DEDYN_NAME yet." + _err "Please create you key and try again." + _err "e.g." + _err "export DEDYN_TOKEN=d41d8cd98f00b204e9800998ecf8427e" + _err "export DEDYN_NAME=foobar.dedyn.io" + return 1 + fi + #save the api token and name to the account conf file. + _saveaccountconf_mutable DEDYN_TOKEN "$DEDYN_TOKEN" + _saveaccountconf_mutable DEDYN_NAME "$DEDYN_NAME" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain" "$REST_API/"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + # Get existing TXT record + _debug "Getting txt records" + txtvalues="\"\\\"$txtvalue\\\"\"" + _desec_rest GET "$REST_API/$DEDYN_NAME/rrsets/$_sub_domain/TXT/" + + if [ "$_code" = "200" ]; then + oldtxtvalues="$(echo "$response" | _egrep_o "\"records\":\\[\"\\S*\"\\]" | cut -d : -f 2 | tr -d "[]\\\\\"" | sed "s/,/ /g")" + _debug "existing TXT found" + _debug oldtxtvalues "$oldtxtvalues" + if [ -n "$oldtxtvalues" ]; then + for oldtxtvalue in $oldtxtvalues; do + txtvalues="$txtvalues, \"\\\"$oldtxtvalue\\\"\"" + done + fi + fi + _debug txtvalues "$txtvalues" + _info "Adding record" + body="[{\"subname\":\"$_sub_domain\", \"type\":\"TXT\", \"records\":[$txtvalues], \"ttl\":60}]" + + if _desec_rest PUT "$REST_API/$DEDYN_NAME/rrsets/" "$body"; then + if _contains "$response" "$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_desec_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using desec.io api" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + DEDYN_TOKEN="${DEDYN_TOKEN:-$(_readaccountconf_mutable DEDYN_TOKEN)}" + DEDYN_NAME="${DEDYN_NAME:-$(_readaccountconf_mutable DEDYN_NAME)}" + + if [ -z "$DEDYN_TOKEN" ] || [ -z "$DEDYN_NAME" ]; then + DEDYN_TOKEN="" + DEDYN_NAME="" + _err "You don't specify DEDYN_TOKEN and DEDYN_NAME yet." + _err "Please create you key and try again." + _err "e.g." + _err "export DEDYN_TOKEN=d41d8cd98f00b204e9800998ecf8427e" + _err "export DEDYN_NAME=foobar.dedyn.io" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain" "$REST_API/"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + # Get existing TXT record + _debug "Getting txt records" + txtvalues="" + _desec_rest GET "$REST_API/$DEDYN_NAME/rrsets/$_sub_domain/TXT/" + + if [ "$_code" = "200" ]; then + oldtxtvalues="$(echo "$response" | _egrep_o "\"records\":\\[\"\\S*\"\\]" | cut -d : -f 2 | tr -d "[]\\\\\"" | sed "s/,/ /g")" + _debug "existing TXT found" + _debug oldtxtvalues "$oldtxtvalues" + if [ -n "$oldtxtvalues" ]; then + for oldtxtvalue in $oldtxtvalues; do + if [ "$txtvalue" != "$oldtxtvalue" ]; then + txtvalues="$txtvalues, \"\\\"$oldtxtvalue\\\"\"" + fi + done + fi + fi + txtvalues="$(echo "$txtvalues" | cut -c3-)" + _debug txtvalues "$txtvalues" + + _info "Deleting record" + body="[{\"subname\":\"$_sub_domain\", \"type\":\"TXT\", \"records\":[$txtvalues], \"ttl\":60}]" + _desec_rest PUT "$REST_API/$DEDYN_NAME/rrsets/" "$body" + if [ "$_code" = "200" ]; then + _info "Deleted, OK" + return 0 + fi + + _err "Delete txt record error." + return 1 +} + +#################### Private functions below ################################## + +_desec_rest() { + m="$1" + ep="$2" + data="$3" + + export _H1="Authorization: Token $DEDYN_TOKEN" + export _H2="Accept: application/json" + export _H3="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _secure_debug2 data "$data" + response="$(_post "$data" "$ep" "" "$m")" + else + response="$(_get "$ep")" + fi + _ret="$?" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + _debug "http response code $_code" + _secure_debug2 response "$response" + if [ "$_ret" != "0" ]; then + _err "error $ep" + return 1 + fi + + response="$(printf "%s" "$response" | _normalizeJson)" + return 0 +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain="$1" + ep="$2" + 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 ! _desec_rest GET "$ep"; 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 +} From b8489464b3d9600d9f06f363c484256f97140d09 Mon Sep 17 00:00:00 2001 From: temoffey Date: Fri, 22 Mar 2019 03:41:26 +0300 Subject: [PATCH 310/565] remove use awk, jq, curl --- deploy/gcore_cdn.sh | 52 +++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index 18d137a..31f8db6 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -27,8 +27,8 @@ gcore_cdn_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _fullchain=$(awk 1 ORS='\\n' "$_cfullchain") - _key=$(awk 1 ORS='\\n' "$_ckey") + _fullchain=$(while read line; do printf "%s" "$line\n"; done < "$_cfullchain") + _key=$(while read line; do printf "%s" "$line\n"; done < "$_ckey") _debug _fullchain "$_fullchain" _debug _key "$_key" @@ -61,43 +61,57 @@ gcore_cdn_deploy() { _info "Get authorization token" _request="{ \"username\": \"$Le_Deploy_gcore_cdn_username\", \"password\": \"$Le_Deploy_gcore_cdn_password\" }" _debug _request "$_request" - _response=$(curl -s -X POST https://api.gcdn.co/auth/signin -H "Content-Type:application/json" -d "$_request") + _H1="Content-Type:application/json" + _response=$(_post "$_request" "https://api.gcdn.co/auth/signin") _debug _response "$_response" - _token=$(echo "$_response" | jq -r '.token') + _regex="\"token\":\"([^\"]+)\"" + _debug _regex "$_regex" + _token=$(if [[ $_response =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) _debug _token "$_token" - if [ "$_token" = "null" ]; then + if [ -z "$_token" ]; then _err "Error G-Core Labs API authorization" return 1 fi _info "Find CDN resource with cname $_cdomain" - _response=$(curl -s -X GET https://api.gcdn.co/resources -H "Authorization:Token $_token") + _H2="Authorization:Token $_token" + _response=$(_get "https://api.gcdn.co/resources") _debug _response "$_response" - _resource=$(echo "$_response" | jq -r ".[] | select(.cname == \"$_cdomain\")") + _regex=".*(\"id\".*?\"cname\":\"$_cdomain\".*?})" + _debug _regex "$_regex" + _resource=$(if [[ $_response =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) _debug _resource "$_resource" - _resourceId=$(echo "$_resource" | jq -r '.id') - _sslDataOld=$(echo "$_resource" | jq -r '.sslData') - _originGroup=$(echo "$_resource" | jq -r '.originGroup') + _regex="\"id\":([0-9]+)" + _debug _regex "$_regex" + _resourceId=$(if [[ $_resource =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) _debug _resourceId "$_resourceId" + _regex="\"sslData\":([0-9]+|null)" + _debug _regex "$_regex" + _sslDataOld=$(if [[ $_resource =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) _debug _sslDataOld "$_sslDataOld" + _regex="\"originGroup\":([0-9]+)" + _debug _regex "$_regex" + _originGroup=$(if [[ $_resource =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) _debug _originGroup "$_originGroup" - if [ -z "$_resourceId" ] || [ "$_resourceId" = "null" ] || [ -z "$_originGroup" ] || [ "$_originGroup" = "null" ]; then + if [ -z "$_resourceId" ] || [ -z "$_originGroup" ]; then _err "Not found CDN resource with cname $_cdomain" return 1 fi _info "Add new SSL certificate" _date=$(date "+%d.%m.%Y %H:%M:%S") - _request="{ \"name\": \"$_cdomain ($_date)\", \"sslCertificate\": \"$_fullchain\n\", \"sslPrivateKey\": \"$_key\n\" }" + _request="{ \"name\": \"$_cdomain ($_date)\", \"sslCertificate\": \"$_fullchain\", \"sslPrivateKey\": \"$_key\" }" _debug _request "$_request" - _response=$(curl -s -X POST https://api.gcdn.co/sslData -H "Content-Type:application/json" -H "Authorization:Token $_token" -d "$_request") + _response=$(_post "$_request" "https://api.gcdn.co/sslData") _debug _response "$_response" - _sslDataAdd=$(echo "$_response" | jq -r '.id') + _regex="\"id\":([0-9]+)" + _debug _regex "$_regex" + _sslDataAdd=$(if [[ $_response =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) _debug _sslDataAdd "$_sslDataAdd" - if [ "$_sslDataAdd" = "null" ]; then + if [ -z "$_sslDataAdd" ]; then _err "Error new SSL certificate add" return 1 fi @@ -105,9 +119,11 @@ gcore_cdn_deploy() { _info "Update CDN resource" _request="{ \"originGroup\": $_originGroup, \"sslData\": $_sslDataAdd }" _debug _request "$_request" - _response=$(curl -s -X PUT "https://api.gcdn.co/resources/$_resourceId" -H "Content-Type:application/json" -H "Authorization:Token $_token" -d "$_request") + _response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT") _debug _response "$_response" - _sslDataNew=$(echo "$_response" | jq -r '.sslData') + _regex="\"sslData\":([0-9]+)" + _debug _regex "$_regex" + _sslDataNew=$(if [[ $_response =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) _debug _sslDataNew "$_sslDataNew" if [ "$_sslDataNew" != "$_sslDataAdd" ]; then @@ -119,7 +135,7 @@ gcore_cdn_deploy() { _info "Not found old SSL certificate" else _info "Delete old SSL certificate" - _response=$(curl -s -X DELETE "https://api.gcdn.co/sslData/$_sslDataOld" -H "Authorization:Token $_token") + _response=$(_post '' "https://api.gcdn.co/sslData/$_sslDataOld" '' "DELETE") _debug _response "$_response" fi From d289b0b450a3c4c3a4645ddefb136560f9125deb Mon Sep 17 00:00:00 2001 From: temoffey Date: Fri, 22 Mar 2019 04:21:41 +0300 Subject: [PATCH 311/565] fix syntax --- deploy/gcore_cdn.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index 31f8db6..439508c 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -27,8 +27,8 @@ gcore_cdn_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _fullchain=$(while read line; do printf "%s" "$line\n"; done < "$_cfullchain") - _key=$(while read line; do printf "%s" "$line\n"; done < "$_ckey") + _fullchain=$(while read -r line; do printf "%s" "$line\n"; done <"$_cfullchain") + _key=$(while read -r line; do printf "%s" "$line\n"; done <"$_ckey") _debug _fullchain "$_fullchain" _debug _key "$_key" @@ -66,7 +66,7 @@ gcore_cdn_deploy() { _debug _response "$_response" _regex="\"token\":\"([^\"]+)\"" _debug _regex "$_regex" - _token=$(if [[ $_response =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) + _token=$(if [[ $_response =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) _debug _token "$_token" if [ -z "$_token" ]; then @@ -80,19 +80,19 @@ gcore_cdn_deploy() { _debug _response "$_response" _regex=".*(\"id\".*?\"cname\":\"$_cdomain\".*?})" _debug _regex "$_regex" - _resource=$(if [[ $_response =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) + _resource=$(if [[ $_response =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) _debug _resource "$_resource" _regex="\"id\":([0-9]+)" _debug _regex "$_regex" - _resourceId=$(if [[ $_resource =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) + _resourceId=$(if [[ $_resource =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) _debug _resourceId "$_resourceId" _regex="\"sslData\":([0-9]+|null)" _debug _regex "$_regex" - _sslDataOld=$(if [[ $_resource =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) + _sslDataOld=$(if [[ $_resource =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) _debug _sslDataOld "$_sslDataOld" _regex="\"originGroup\":([0-9]+)" _debug _regex "$_regex" - _originGroup=$(if [[ $_resource =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) + _originGroup=$(if [[ $_resource =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) _debug _originGroup "$_originGroup" if [ -z "$_resourceId" ] || [ -z "$_originGroup" ]; then @@ -108,7 +108,7 @@ gcore_cdn_deploy() { _debug _response "$_response" _regex="\"id\":([0-9]+)" _debug _regex "$_regex" - _sslDataAdd=$(if [[ $_response =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) + _sslDataAdd=$(if [[ $_response =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) _debug _sslDataAdd "$_sslDataAdd" if [ -z "$_sslDataAdd" ]; then @@ -123,7 +123,7 @@ gcore_cdn_deploy() { _debug _response "$_response" _regex="\"sslData\":([0-9]+)" _debug _regex "$_regex" - _sslDataNew=$(if [[ $_response =~ $_regex ]]; then printf "${BASH_REMATCH[1]}"; fi) + _sslDataNew=$(if [[ $_response =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) _debug _sslDataNew "$_sslDataNew" if [ "$_sslDataNew" != "$_sslDataAdd" ]; then From 0ecb5a3fec0b14e410ac4cc6682eae7051651510 Mon Sep 17 00:00:00 2001 From: temoffey Date: Fri, 22 Mar 2019 04:31:58 +0300 Subject: [PATCH 312/565] fix syntax --- deploy/gcore_cdn.sh | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index 439508c..2655cbc 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -61,8 +61,7 @@ gcore_cdn_deploy() { _info "Get authorization token" _request="{ \"username\": \"$Le_Deploy_gcore_cdn_username\", \"password\": \"$Le_Deploy_gcore_cdn_password\" }" _debug _request "$_request" - _H1="Content-Type:application/json" - _response=$(_post "$_request" "https://api.gcdn.co/auth/signin") + _response=$(_H1="Content-Type:application/json" && _post "$_request" "https://api.gcdn.co/auth/signin") _debug _response "$_response" _regex="\"token\":\"([^\"]+)\"" _debug _regex "$_regex" @@ -75,8 +74,7 @@ gcore_cdn_deploy() { fi _info "Find CDN resource with cname $_cdomain" - _H2="Authorization:Token $_token" - _response=$(_get "https://api.gcdn.co/resources") + _response=$(_H1="Content-Type:application/json" && _H2="Authorization:Token $_token" && _get "https://api.gcdn.co/resources") _debug _response "$_response" _regex=".*(\"id\".*?\"cname\":\"$_cdomain\".*?})" _debug _regex "$_regex" @@ -104,7 +102,7 @@ gcore_cdn_deploy() { _date=$(date "+%d.%m.%Y %H:%M:%S") _request="{ \"name\": \"$_cdomain ($_date)\", \"sslCertificate\": \"$_fullchain\", \"sslPrivateKey\": \"$_key\" }" _debug _request "$_request" - _response=$(_post "$_request" "https://api.gcdn.co/sslData") + _response=$(_H1="Content-Type:application/json" && _H2="Authorization:Token $_token" && _post "$_request" "https://api.gcdn.co/sslData") _debug _response "$_response" _regex="\"id\":([0-9]+)" _debug _regex "$_regex" @@ -119,7 +117,7 @@ gcore_cdn_deploy() { _info "Update CDN resource" _request="{ \"originGroup\": $_originGroup, \"sslData\": $_sslDataAdd }" _debug _request "$_request" - _response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT") + _response=$(_H1="Content-Type:application/json" && _H2="Authorization:Token $_token" && _post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT") _debug _response "$_response" _regex="\"sslData\":([0-9]+)" _debug _regex "$_regex" @@ -135,7 +133,7 @@ gcore_cdn_deploy() { _info "Not found old SSL certificate" else _info "Delete old SSL certificate" - _response=$(_post '' "https://api.gcdn.co/sslData/$_sslDataOld" '' "DELETE") + _response=$(_H1="Content-Type:application/json" && _H2="Authorization:Token $_token" && _post '' "https://api.gcdn.co/sslData/$_sslDataOld" '' "DELETE") _debug _response "$_response" fi From 8896642e2541265a4627792b922204129d6c9cca Mon Sep 17 00:00:00 2001 From: temoffey Date: Fri, 22 Mar 2019 20:01:39 +0300 Subject: [PATCH 313/565] fix syntax --- deploy/gcore_cdn.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index 2655cbc..f9ed6c7 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -61,7 +61,8 @@ gcore_cdn_deploy() { _info "Get authorization token" _request="{ \"username\": \"$Le_Deploy_gcore_cdn_username\", \"password\": \"$Le_Deploy_gcore_cdn_password\" }" _debug _request "$_request" - _response=$(_H1="Content-Type:application/json" && _post "$_request" "https://api.gcdn.co/auth/signin") + export _H1="Content-Type:application/json" + _response=$(_post "$_request" "https://api.gcdn.co/auth/signin") _debug _response "$_response" _regex="\"token\":\"([^\"]+)\"" _debug _regex "$_regex" @@ -74,7 +75,8 @@ gcore_cdn_deploy() { fi _info "Find CDN resource with cname $_cdomain" - _response=$(_H1="Content-Type:application/json" && _H2="Authorization:Token $_token" && _get "https://api.gcdn.co/resources") + export _H2="Authorization:Token $_token" + _response=$(_get "https://api.gcdn.co/resources") _debug _response "$_response" _regex=".*(\"id\".*?\"cname\":\"$_cdomain\".*?})" _debug _regex "$_regex" @@ -102,7 +104,7 @@ gcore_cdn_deploy() { _date=$(date "+%d.%m.%Y %H:%M:%S") _request="{ \"name\": \"$_cdomain ($_date)\", \"sslCertificate\": \"$_fullchain\", \"sslPrivateKey\": \"$_key\" }" _debug _request "$_request" - _response=$(_H1="Content-Type:application/json" && _H2="Authorization:Token $_token" && _post "$_request" "https://api.gcdn.co/sslData") + _response=$(_post "$_request" "https://api.gcdn.co/sslData") _debug _response "$_response" _regex="\"id\":([0-9]+)" _debug _regex "$_regex" @@ -117,7 +119,7 @@ gcore_cdn_deploy() { _info "Update CDN resource" _request="{ \"originGroup\": $_originGroup, \"sslData\": $_sslDataAdd }" _debug _request "$_request" - _response=$(_H1="Content-Type:application/json" && _H2="Authorization:Token $_token" && _post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT") + _response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT") _debug _response "$_response" _regex="\"sslData\":([0-9]+)" _debug _regex "$_regex" @@ -133,7 +135,7 @@ gcore_cdn_deploy() { _info "Not found old SSL certificate" else _info "Delete old SSL certificate" - _response=$(_H1="Content-Type:application/json" && _H2="Authorization:Token $_token" && _post '' "https://api.gcdn.co/sslData/$_sslDataOld" '' "DELETE") + _response=$(_post '' "https://api.gcdn.co/sslData/$_sslDataOld" '' "DELETE") _debug _response "$_response" fi From 4b6e7e6c371a7945e2b3304ff7241bf05691d453 Mon Sep 17 00:00:00 2001 From: temoffey Date: Fri, 22 Mar 2019 20:02:59 +0300 Subject: [PATCH 314/565] remove use while, [[ ]], array --- deploy/gcore_cdn.sh | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index f9ed6c7..f0cc43e 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -27,8 +27,8 @@ gcore_cdn_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _fullchain=$(while read -r line; do printf "%s" "$line\n"; done <"$_cfullchain") - _key=$(while read -r line; do printf "%s" "$line\n"; done <"$_ckey") + _fullchain=$(cat "$_cfullchain" | tr '\n\r' '@#' | sed 's/@/\\n/g;s/#/\\r/g') + _key=$(cat "$_ckey" | tr '\n\r' '@#' | sed 's/@/\\n/g;s/#/\\r/g') _debug _fullchain "$_fullchain" _debug _key "$_key" @@ -59,14 +59,14 @@ gcore_cdn_deploy() { fi _info "Get authorization token" - _request="{ \"username\": \"$Le_Deploy_gcore_cdn_username\", \"password\": \"$Le_Deploy_gcore_cdn_password\" }" + _request="{\"username\":\"$Le_Deploy_gcore_cdn_username\",\"password\":\"$Le_Deploy_gcore_cdn_password\"}" _debug _request "$_request" export _H1="Content-Type:application/json" _response=$(_post "$_request" "https://api.gcdn.co/auth/signin") _debug _response "$_response" - _regex="\"token\":\"([^\"]+)\"" + _regex=".*\"token\":\"\([-._0-9A-Za-z]*\)\".*$" _debug _regex "$_regex" - _token=$(if [[ $_response =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) + _token=$(echo "$_response" | sed -n "s/$_regex/\1/p") _debug _token "$_token" if [ -z "$_token" ]; then @@ -79,20 +79,21 @@ gcore_cdn_deploy() { _response=$(_get "https://api.gcdn.co/resources") _debug _response "$_response" _regex=".*(\"id\".*?\"cname\":\"$_cdomain\".*?})" + _regex="\"cname\":\"$_cdomain\"" _debug _regex "$_regex" - _resource=$(if [[ $_response =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) + _resource=$(echo "$_response" | sed 's/},{/},\n{/g' | grep -E "$_regex") _debug _resource "$_resource" - _regex="\"id\":([0-9]+)" + _regex=".*\"id\":\([0-9]*\),.*$" _debug _regex "$_regex" - _resourceId=$(if [[ $_resource =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) + _resourceId=$(echo "$_resource" | sed -n "s/$_regex/\1/p") _debug _resourceId "$_resourceId" - _regex="\"sslData\":([0-9]+|null)" + _regex=".*\"sslData\":\([0-9]*\)}.*$" _debug _regex "$_regex" - _sslDataOld=$(if [[ $_resource =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) + _sslDataOld=$(echo "$_resource" | sed -n "s/$_regex/\1/p") _debug _sslDataOld "$_sslDataOld" - _regex="\"originGroup\":([0-9]+)" + _regex=".*\"originGroup\":\([0-9]*\),.*$" _debug _regex "$_regex" - _originGroup=$(if [[ $_resource =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) + _originGroup=$(echo "$_resource" | sed -n "s/$_regex/\1/p") _debug _originGroup "$_originGroup" if [ -z "$_resourceId" ] || [ -z "$_originGroup" ]; then @@ -102,13 +103,13 @@ gcore_cdn_deploy() { _info "Add new SSL certificate" _date=$(date "+%d.%m.%Y %H:%M:%S") - _request="{ \"name\": \"$_cdomain ($_date)\", \"sslCertificate\": \"$_fullchain\", \"sslPrivateKey\": \"$_key\" }" + _request="{\"name\":\"$_cdomain ($_date)\",\"sslCertificate\":\"$_fullchain\",\"sslPrivateKey\":\"$_key\"}" _debug _request "$_request" _response=$(_post "$_request" "https://api.gcdn.co/sslData") _debug _response "$_response" - _regex="\"id\":([0-9]+)" + _regex=".*\"id\":\([0-9]*\),.*$" _debug _regex "$_regex" - _sslDataAdd=$(if [[ $_response =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) + _sslDataAdd=$(echo "$_response" | sed -n "s/$_regex/\1/p") _debug _sslDataAdd "$_sslDataAdd" if [ -z "$_sslDataAdd" ]; then @@ -117,13 +118,13 @@ gcore_cdn_deploy() { fi _info "Update CDN resource" - _request="{ \"originGroup\": $_originGroup, \"sslData\": $_sslDataAdd }" + _request="{\"originGroup\":$_originGroup,\"sslData\":$_sslDataAdd}" _debug _request "$_request" _response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT") _debug _response "$_response" - _regex="\"sslData\":([0-9]+)" + _regex=".*\"sslData\":\([0-9]*\)}.*$" _debug _regex "$_regex" - _sslDataNew=$(if [[ $_response =~ $_regex ]]; then printf "%s" "${BASH_REMATCH[1]}"; fi) + _sslDataNew=$(echo "$_response" | sed -n "s/$_regex/\1/p") _debug _sslDataNew "$_sslDataNew" if [ "$_sslDataNew" != "$_sslDataAdd" ]; then From bd1bb7a71bf79daa70db446995c9ca54517f57e2 Mon Sep 17 00:00:00 2001 From: temoffey Date: Fri, 22 Mar 2019 20:08:35 +0300 Subject: [PATCH 315/565] fix syntax --- deploy/gcore_cdn.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index f0cc43e..40fbf48 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -27,8 +27,8 @@ gcore_cdn_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _fullchain=$(cat "$_cfullchain" | tr '\n\r' '@#' | sed 's/@/\\n/g;s/#/\\r/g') - _key=$(cat "$_ckey" | tr '\n\r' '@#' | sed 's/@/\\n/g;s/#/\\r/g') + _fullchain=$(tr '\n\r' '@#' <"$_cfullchain" | sed 's/@/\\n/g;s/#/\\r/g') + _key=$(tr '\n\r' '@#' <"$_ckey" | sed 's/@/\\n/g;s/#/\\r/g') _debug _fullchain "$_fullchain" _debug _key "$_key" From df9174577a503811973c5d185abc5f3000736a2a Mon Sep 17 00:00:00 2001 From: temoffey Date: Fri, 22 Mar 2019 23:00:47 +0300 Subject: [PATCH 316/565] remove check jq --- deploy/gcore_cdn.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index 40fbf48..b38226f 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -53,11 +53,6 @@ gcore_cdn_deploy() { _savedomainconf Le_Deploy_gcore_cdn_password "$Le_Deploy_gcore_cdn_password" fi - if ! [ -x "$(command -v jq)" ]; then - _err "Please install the package jq: sudo apt-get install jq" - return 1 - fi - _info "Get authorization token" _request="{\"username\":\"$Le_Deploy_gcore_cdn_username\",\"password\":\"$Le_Deploy_gcore_cdn_password\"}" _debug _request "$_request" From 189a7766d4fc4684ba971147474a7dd3187a29dd Mon Sep 17 00:00:00 2001 From: Charles Surett Date: Fri, 22 Mar 2019 18:43:06 -0400 Subject: [PATCH 317/565] Made dns_dgon.sh use _lower_case Fixed private function which breaks on embedded systems before. --- dnsapi/dns_dgon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dgon.sh b/dnsapi/dns_dgon.sh index 24e1a9f..c176afd 100755 --- a/dnsapi/dns_dgon.sh +++ b/dnsapi/dns_dgon.sh @@ -178,7 +178,7 @@ dns_dgon_rm() { ## _domain="domain.com" _get_base_domain() { # args - fulldomain="$(echo "$1" | tr '[:upper:]' '[:lower:]')" + fulldomain="$(echo "$1" | _lower_case)" _debug fulldomain "$fulldomain" # domain max legal length = 253 From bea52aa7435d57733be37fe45bd06938c8ffab0f Mon Sep 17 00:00:00 2001 From: temoffey Date: Sat, 23 Mar 2019 16:29:33 +0300 Subject: [PATCH 318/565] remove use grep -E --- deploy/gcore_cdn.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index b38226f..56ca9af 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -74,9 +74,9 @@ gcore_cdn_deploy() { _response=$(_get "https://api.gcdn.co/resources") _debug _response "$_response" _regex=".*(\"id\".*?\"cname\":\"$_cdomain\".*?})" - _regex="\"cname\":\"$_cdomain\"" + _regex="^.*\"cname\":\"$_cdomain\".*$" _debug _regex "$_regex" - _resource=$(echo "$_response" | sed 's/},{/},\n{/g' | grep -E "$_regex") + _resource=$(echo "$_response" | sed 's/},{/},\n{/g' | _egrep_o "$_regex") _debug _resource "$_resource" _regex=".*\"id\":\([0-9]*\),.*$" _debug _regex "$_regex" From 978ec91107db6adb140a33141577de2119db5822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Toki=C4=87?= Date: Tue, 5 Mar 2019 20:16:54 +0100 Subject: [PATCH 319/565] Extract configuration loading code to function --- dnsapi/dns_loopia.sh | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh index ece5ef8..a66a443 100644 --- a/dnsapi/dns_loopia.sh +++ b/dnsapi/dns_loopia.sh @@ -14,13 +14,7 @@ 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." + if ! _loopia_load_config; then return 1 fi @@ -47,13 +41,7 @@ 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." + if ! _loopia_load_config; then return 1 fi @@ -96,6 +84,23 @@ dns_loopia_rm() { #################### Private functions below ################################## +_loopia_load_config() { + 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 + + return 0 +} + _loopia_get_records() { domain=$1 sub_domain=$2 From a7d614616997d6e109b30711c804d194d5a68fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Toki=C4=87?= Date: Tue, 5 Mar 2019 20:21:14 +0100 Subject: [PATCH 320/565] Extract configuration saving code to function --- dnsapi/dns_loopia.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh index a66a443..92556e7 100644 --- a/dnsapi/dns_loopia.sh +++ b/dnsapi/dns_loopia.sh @@ -18,9 +18,7 @@ dns_loopia_add() { 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" + _loopia_save_config _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -45,9 +43,7 @@ dns_loopia_rm() { 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" + _loopia_save_config _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -101,6 +97,11 @@ _loopia_load_config() { return 0 } +_loopia_save_config() { + _saveaccountconf_mutable LOOPIA_User "$LOOPIA_User" + _saveaccountconf_mutable LOOPIA_Password "$LOOPIA_Password" +} + _loopia_get_records() { domain=$1 sub_domain=$2 From 85be2b85fd9103efc391f0c08de73d59638aa7a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Toki=C4=87?= Date: Tue, 5 Mar 2019 21:10:11 +0100 Subject: [PATCH 321/565] Fix error message language --- 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 92556e7..e8d19d1 100644 --- a/dnsapi/dns_loopia.sh +++ b/dnsapi/dns_loopia.sh @@ -88,8 +88,8 @@ _loopia_load_config() { LOOPIA_User="" LOOPIA_Password="" - _err "You don't specify loopia user and password yet." - _err "Please create you key and try again." + _err "A valid Loopia API user and password not provided." + _err "Please provide a valid API user and try again." return 1 fi From 0daa225e2641da94d0045e4974b6af9ba91effc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Toki=C4=87?= Date: Tue, 5 Mar 2019 20:56:34 +0100 Subject: [PATCH 322/565] Make the Loopia API endpoint configurable Loopia provides hosting in several countries. Each hosting location has it's own API endpoint, such as "https://api.loopia./RPCSERV", where is one of: com, no, rs, se. The current LOOPIA_Api variable is hard-coded to ".se". This prevents using the Loopia DNS API on other hosting locations. This commit makes the LOOPIA_Api variable configurable and it falls back to ".se" TLD if LOOPIA_Api is not set. References: - https://www.loopia.com/api/authentication/ - https://www.loopia.no/api/authentication/ - https://www.loopia.rs/api/authentication/ - https://www.loopia.se/api/authentication/ --- dnsapi/dns_loopia.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh index e8d19d1..109507c 100644 --- a/dnsapi/dns_loopia.sh +++ b/dnsapi/dns_loopia.sh @@ -4,8 +4,10 @@ #LOOPIA_User="username" # #LOOPIA_Password="password" +# +#LOOPIA_Api="https://api.loopia./RPCSERV" -LOOPIA_Api="https://api.loopia.se/RPCSERV" +LOOPIA_Api_Default="https://api.loopia.se/RPCSERV" ######## Public functions ##################### @@ -81,9 +83,14 @@ dns_loopia_rm() { #################### Private functions below ################################## _loopia_load_config() { + LOOPIA_Api="${LOOPIA_Api:-$(_readaccountconf_mutable LOOPIA_Api)}" LOOPIA_User="${LOOPIA_User:-$(_readaccountconf_mutable LOOPIA_User)}" LOOPIA_Password="${LOOPIA_Password:-$(_readaccountconf_mutable LOOPIA_Password)}" + if [ -z "$LOOPIA_Api" ]; then + LOOPIA_Api="$LOOPIA_Api_Default" + fi + if [ -z "$LOOPIA_User" ] || [ -z "$LOOPIA_Password" ]; then LOOPIA_User="" LOOPIA_Password="" @@ -98,6 +105,9 @@ _loopia_load_config() { } _loopia_save_config() { + if [ "$LOOPIA_Api" != "$LOOPIA_Api_Default" ]; then + _saveaccountconf_mutable LOOPIA_Api "$LOOPIA_Api" + fi _saveaccountconf_mutable LOOPIA_User "$LOOPIA_User" _saveaccountconf_mutable LOOPIA_Password "$LOOPIA_Password" } From aec9c3c9a4820dbd05660bffc074c95f3aee77a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Toki=C4=87?= Date: Thu, 28 Mar 2019 16:34:13 +0100 Subject: [PATCH 323/565] Double quote unquoted variables Double quote unquoted variables to prevent globbing and word splitting. --- dnsapi/dns_loopia.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh index 109507c..1316a27 100644 --- a/dnsapi/dns_loopia.sh +++ b/dnsapi/dns_loopia.sh @@ -70,7 +70,7 @@ dns_loopia_rm() { %s - ' $LOOPIA_User $LOOPIA_Password "$_domain" "$_sub_domain") + ' "$LOOPIA_User" "$LOOPIA_Password" "$_domain" "$_sub_domain") response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" From c2d0d4d28c86b3edeb2321f6ea98e9ffbd22fccf Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 31 Mar 2019 21:46:14 +0800 Subject: [PATCH 324/565] root domain as dns alias mode --- 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 532199f..9673143 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -147,7 +147,7 @@ dns_cf_rm() { # _domain_id=sdjkglgdfewsdfg _get_root() { domain=$1 - i=2 + i=1 p=1 while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) From 6e917d156c0abcf7f3ebc0c8d008af44a8cba45f Mon Sep 17 00:00:00 2001 From: Gorbachev Date: Tue, 2 Apr 2019 18:05:52 +0300 Subject: [PATCH 325/565] Trim double quotes for email and key Currently dns_cf generates headers like this: 'X-Auth-Email: "sample@mail.com"'. Cloudflare API responses 400 BadRequest for quoted headers with message "Invalid format for X-Auth-Email header". --- dnsapi/dns_cf.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 532199f..7308997 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -182,8 +182,11 @@ _cf_rest() { data="$3" _debug "$ep" - export _H1="X-Auth-Email: $CF_Email" - export _H2="X-Auth-Key: $CF_Key" + email_trimmed=$(echo $CF_Email | tr -d '"') + key_trimmed=$(echo $CF_Key | tr -d '"') + + export _H1="X-Auth-Email: $email_trimmed" + export _H2="X-Auth-Key: $key_trimmed" export _H3="Content-Type: application/json" if [ "$m" != "GET" ]; then From 987f95221c66abcd2a439102096d87510004de74 Mon Sep 17 00:00:00 2001 From: Kimmax Date: Tue, 2 Apr 2019 23:08:39 +0000 Subject: [PATCH 326/565] Added missing "templateValues" object to "zoneConfig" on "_hostingde_getZoneConfig" --- dnsapi/dns_hostingde.sh | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index 1819e63..4cfe33f 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -53,6 +53,18 @@ _hostingde_parse() { fi } +_hostingde_parse_no_strip_whitespace() { + 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 + else + _egrep_o \""${find}\":.*" | cut -d ':' -f 2 | cut -d ',' -f 1 + fi +} + _hostingde_getZoneConfig() { _info "Getting ZoneConfig" curZone="${fulldomain#*.}" @@ -85,6 +97,22 @@ _hostingde_getZoneConfig() { zoneConfigDnsServerGroupId=$(echo "${curResult}" | _hostingde_parse "dnsServerGroupId") zoneConfigEmailAddress=$(echo "${curResult}" | _hostingde_parse "emailAddress") zoneConfigDnsSecMode=$(echo "${curResult}" | _hostingde_parse "dnsSecMode") + zoneConfigTemplateValues=$(echo "${curResult}" | _hostingde_parse_object "templateValues") + + if [ "$zoneConfigTemplateValues" != "null" ]; then + _debug "Zone is tied to a template." + zoneConfigTemplateValuesTemplateId=$(echo "${curResult}" | _hostingde_parse "templateId") + zoneConfigTemplateValuesTemplateName=$(echo "${curResult}" | _hostingde_parse_no_strip_whitespace "templateName") + zoneConfigTemplateValuesTemplateReplacementsIPv4=$(echo "${curResult}" | _hostingde_parse "ipv4Replacement") + zoneConfigTemplateValuesTemplateReplacementsIPv6=$(echo "${curResult}" | _hostingde_parse "ipv6Replacement") + zoneConfigTemplateValuesTemplateReplacementsMailIPv4=$(echo "${curResult}" | _hostingde_parse "mailIpv4Replacement") + zoneConfigTemplateValuesTemplateReplacementsMailIPv6=$(echo "${curResult}" | _hostingde_parse "mailIpv6Replacement") + zoneConfigTemplateValuesTemplateTieToTemplate=$(echo "${curResult}" | _hostingde_parse "tieToTemplate") + + zoneConfigTemplateValues="{\"templateId\":${zoneConfigTemplateValuesTemplateId},\"templateName\":${zoneConfigTemplateValuesTemplateName},\"templateReplacements\":{\"ipv4Replacement\":${zoneConfigTemplateValuesTemplateReplacementsIPv4},\"ipv6Replacement\":${zoneConfigTemplateValuesTemplateReplacementsIPv6},\"mailIpv4Replacement\":${zoneConfigTemplateValuesTemplateReplacementsMailIPv4},\"mailIpv6Replacement\":${zoneConfigTemplateValuesTemplateReplacementsMailIPv6}},\"tieToTemplate\":${zoneConfigTemplateValuesTemplateTieToTemplate}}" + _debug "Template values: '{$zoneConfigTemplateValues}'" + fi + if [ "${zoneConfigType}" != "\"NATIVE\"" ]; then _err "Zone is not native" returnCode=1 @@ -122,7 +150,7 @@ _hostingde_addRecord() { _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}},\"templateValues\":${zoneConfigTemplateValues}},\"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'" From 64e53927880732978cf3702b6afa792156ae4db3 Mon Sep 17 00:00:00 2001 From: Kimmax Date: Tue, 2 Apr 2019 23:29:58 +0000 Subject: [PATCH 327/565] Zone delete also needs new "templateValues" field --- 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 4cfe33f..1aa7039 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -97,7 +97,7 @@ _hostingde_getZoneConfig() { zoneConfigDnsServerGroupId=$(echo "${curResult}" | _hostingde_parse "dnsServerGroupId") zoneConfigEmailAddress=$(echo "${curResult}" | _hostingde_parse "emailAddress") zoneConfigDnsSecMode=$(echo "${curResult}" | _hostingde_parse "dnsSecMode") - zoneConfigTemplateValues=$(echo "${curResult}" | _hostingde_parse_object "templateValues") + zoneConfigTemplateValues=$(echo "${curResult}" | _hostingde_parse_no_strip_whitespace "templateValues") if [ "$zoneConfigTemplateValues" != "null" ]; then _debug "Zone is tied to a template." @@ -174,7 +174,7 @@ _hostingde_removeRecord() { _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}},\"templateValues\":${zoneConfigTemplateValues}},\"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 eda321954dfb31ecf18dbe41e0123dd329592cd1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Apr 2019 16:05:08 +0800 Subject: [PATCH 328/565] fix https://github.com/Neilpang/acme.sh/issues/2208 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index f47a5eb..14b23de 100755 --- a/acme.sh +++ b/acme.sh @@ -2004,7 +2004,7 @@ _read_conf() { _r_c_f="$1" _sdkey="$2" if [ -f "$_r_c_f" ]; then - _sdv="$(grep "^$_sdkey *=" "$_r_c_f" | cut -d = -f 2-1000 | tr -d "'")" + _sdv="$(eval "$(grep "^$_sdkey *=" "$_r_c_f")" ; eval "printf \"%s\" \"\$$_sdkey\"")" if _startswith "$_sdv" "${B64CONF_START}" && _endswith "$_sdv" "${B64CONF_END}"; then _sdv="$(echo "$_sdv" | sed "s/${B64CONF_START}//" | sed "s/${B64CONF_END}//" | _dbase64)" fi From c97e43dcd6b4d6447f69402d31522d4f02586813 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Apr 2019 16:45:58 +0800 Subject: [PATCH 329/565] fix format --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 14b23de..7994cc2 100755 --- a/acme.sh +++ b/acme.sh @@ -2004,7 +2004,10 @@ _read_conf() { _r_c_f="$1" _sdkey="$2" if [ -f "$_r_c_f" ]; then - _sdv="$(eval "$(grep "^$_sdkey *=" "$_r_c_f")" ; eval "printf \"%s\" \"\$$_sdkey\"")" + _sdv="$( + eval "$(grep "^$_sdkey *=" "$_r_c_f")" + eval "printf \"%s\" \"\$$_sdkey\"" + )" if _startswith "$_sdv" "${B64CONF_START}" && _endswith "$_sdv" "${B64CONF_END}"; then _sdv="$(echo "$_sdv" | sed "s/${B64CONF_START}//" | sed "s/${B64CONF_END}//" | _dbase64)" fi From 0cfeee4ded53a34db628af4eefd4372e8a6e3d1b Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Apr 2019 16:48:17 +0800 Subject: [PATCH 330/565] fix format --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 7994cc2..77f84a2 100755 --- a/acme.sh +++ b/acme.sh @@ -2004,9 +2004,9 @@ _read_conf() { _r_c_f="$1" _sdkey="$2" if [ -f "$_r_c_f" ]; then - _sdv="$( - eval "$(grep "^$_sdkey *=" "$_r_c_f")" - eval "printf \"%s\" \"\$$_sdkey\"" + _sdv="$( + eval "$(grep "^$_sdkey *=" "$_r_c_f")" + eval "printf \"%s\" \"\$$_sdkey\"" )" if _startswith "$_sdv" "${B64CONF_START}" && _endswith "$_sdv" "${B64CONF_END}"; then _sdv="$(echo "$_sdv" | sed "s/${B64CONF_START}//" | sed "s/${B64CONF_END}//" | _dbase64)" From 98d27c4a6a780ff333a99201166e899b017259ae Mon Sep 17 00:00:00 2001 From: Matthew R Chase Date: Sun, 7 Apr 2019 15:04:03 -0400 Subject: [PATCH 331/565] Fix most-specific zone match Most specific zone selected by deepest sub-domain (how many '.' in the domain) rather than seemingly irrelevant count of the number of characters within the zone. --- 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 99fbf41..87aceaa 100755 --- a/dnsapi/dns_gcloud.sh +++ b/dnsapi/dns_gcloud.sh @@ -134,12 +134,12 @@ _dns_gcloud_find_zone() { filter="$filter)" _debug filter "$filter" - # List domains and find the longest match (in case of some levels of delegation) + # List domains and find the zone with the deepest sub-domain (in case of some levels of delegation) if ! match=$(gcloud dns managed-zones list \ --format="value(name, dnsName)" \ --filter="$filter" \ | while read -r dnsName name; do - printf "%s\t%s\t%s\n" "${#dnsName}" "$dnsName" "$name" + printf "%s\t%s\t%s\n" "$(awk -F"." '{print NF-1}' <<< "$name")" "$dnsName" "$name" done \ | 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?" From f23b0aacd79b249382f73029850e11b03107afb0 Mon Sep 17 00:00:00 2001 From: chasefox <49169974+chasefox@users.noreply.github.com> Date: Mon, 8 Apr 2019 07:11:08 -0400 Subject: [PATCH 332/565] Remove here string CI doesn't want here strings --- dnsapi/dns_gcloud.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gcloud.sh b/dnsapi/dns_gcloud.sh index 87aceaa..9dfc574 100755 --- a/dnsapi/dns_gcloud.sh +++ b/dnsapi/dns_gcloud.sh @@ -139,7 +139,7 @@ _dns_gcloud_find_zone() { --format="value(name, dnsName)" \ --filter="$filter" \ | while read -r dnsName name; do - printf "%s\t%s\t%s\n" "$(awk -F"." '{print NF-1}' <<< "$name")" "$dnsName" "$name" + printf "%s\t%s\t%s\n" "$(echo $name | awk -F"." '{print NF-1}')" "$dnsName" "$name" done \ | 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?" From 2d72b25c4393716efabd4b241c729efa50794845 Mon Sep 17 00:00:00 2001 From: chasefox <49169974+chasefox@users.noreply.github.com> Date: Mon, 8 Apr 2019 07:44:41 -0400 Subject: [PATCH 333/565] CI wanted double-quote --- dnsapi/dns_gcloud.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gcloud.sh b/dnsapi/dns_gcloud.sh index 9dfc574..919223a 100755 --- a/dnsapi/dns_gcloud.sh +++ b/dnsapi/dns_gcloud.sh @@ -139,7 +139,7 @@ _dns_gcloud_find_zone() { --format="value(name, dnsName)" \ --filter="$filter" \ | while read -r dnsName name; do - printf "%s\t%s\t%s\n" "$(echo $name | awk -F"." '{print NF-1}')" "$dnsName" "$name" + printf "%s\t%s\t%s\n" "$(echo "$name" | awk -F"." '{print NF-1}')" "$dnsName" "$name" done \ | 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?" From 4aa488f48b68f5271ba90e6f04673f0f234d06d1 Mon Sep 17 00:00:00 2001 From: chasefox <49169974+chasefox@users.noreply.github.com> Date: Mon, 8 Apr 2019 07:51:39 -0400 Subject: [PATCH 334/565] Formatting - indentation I think this is what CI wants.... --- dnsapi/dns_gcloud.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gcloud.sh b/dnsapi/dns_gcloud.sh index 919223a..c2ead9a 100755 --- a/dnsapi/dns_gcloud.sh +++ b/dnsapi/dns_gcloud.sh @@ -141,7 +141,7 @@ _dns_gcloud_find_zone() { | while read -r dnsName name; do printf "%s\t%s\t%s\n" "$(echo "$name" | awk -F"." '{print NF-1}')" "$dnsName" "$name" done \ - | sort -n -r | _head_n 1 | 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 79e2f8a2e5ebd9d070903ca1e5294a1b24f03d06 Mon Sep 17 00:00:00 2001 From: dim0x69 Date: Wed, 17 Apr 2019 14:51:07 +0200 Subject: [PATCH 335/565] implement account update for acmev2 --- acme.sh | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 77f84a2..2fe9acb 100755 --- a/acme.sh +++ b/acme.sh @@ -3218,11 +3218,6 @@ _on_issue_success() { } -updateaccount() { - _initpath - _regAccount -} - registeraccount() { _reg_length="$1" _initpath @@ -3320,6 +3315,61 @@ _regAccount() { _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" } +#implement updateaccount +updateaccount() { + _initpath + + if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then + _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" + mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" + fi + + if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then + _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" + mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" + fi + + if [ ! -f "$ACCOUNT_KEY_PATH" ]; then + _err "Account key is not found at: $ACCOUNT_KEY_PATH" + return 1 + fi + + _accUri=$(_readcaconf "ACCOUNT_URL") + _debug _accUri "$_accUri" + + if [ -z "$_accUri" ]; then + _err "The account url is empty, please run '--update-account' first to update the account info first," + _err "Then try again." + return 1 + fi + + if ! _calcjwk "$ACCOUNT_KEY_PATH"; then + return 1 + fi + _initAPI + + if [ "$ACME_VERSION" = "2" ]; then + if [ "$ACCOUNT_EMAIL" ]; then + updjson='{"contact": ["mailto: '$ACCOUNT_EMAIL'"]}' + fi + else + # ACMEv1: Updates happen the same way a registration is done. + # https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-6.3 + _regAccount + return + fi + + # this part handles ACMEv2 account updates. + _send_signed_request "$_accUri" "$updjson" + + if [ "$code" = '200' ]; then + _info "account update success for $_accUri." + else + _info "Error. The account was not updated." + return 1 + fi +} + #Implement deactivate account deactivateaccount() { _initpath From 61556a54e2955d0ab913422489e0e9e90adcf885 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Fri, 19 Apr 2019 17:27:32 +0200 Subject: [PATCH 336/565] feat: add `--noprofile` option to `install` command --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 77f84a2..7adda61 100755 --- a/acme.sh +++ b/acme.sh @@ -5795,6 +5795,7 @@ Parameters: --ca-bundle Specifies the path to the CA certificate bundle to verify api server's certificate. --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. + --noprofile Only valid for '--install' command, which means: do not install aliases to user profile. --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' @@ -5928,6 +5929,7 @@ _process() { _ca_bundle="" _ca_path="" _nocron="" + _noprofile="" _ecc="" _csr="" _pre_hook="" @@ -6272,6 +6274,9 @@ _process() { --nocron) _nocron="1" ;; + --noprofile) + _noprofile="1" + ;; --no-color) export ACME_NO_COLOR=1 ;; @@ -6430,7 +6435,7 @@ _process() { fi case "${_CMD}" in - install) install "$_nocron" "$_confighome" ;; + install) install "$_nocron" "$_confighome" "$_noprofile" ;; uninstall) uninstall "$_nocron" ;; upgrade) upgrade ;; issue) From 9c9fed749aef146c63afe5ff16e9b1115d13d0da Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 20 Apr 2019 12:49:51 +0800 Subject: [PATCH 337/565] fix https://github.com/Neilpang/acme.sh/issues/2225 make NSUPDATE_SERVER can be overwritten --- dnsapi/dns_nsupdate.sh | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 8b479f9..dfb3672 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -6,14 +6,22 @@ dns_nsupdate_add() { fulldomain=$1 txtvalue=$2 + NSUPDATE_SERVER="${NSUPDATE_SERVER:-$(_readaccountconf_mutable NSUPDATE_SERVER)}" + NSUPDATE_SERVER_PORT="${NSUPDATE_SERVER_PORT:-$(_readaccountconf_mutable NSUPDATE_SERVER_PORT)}" + NSUPDATE_KEY="${NSUPDATE_KEY:-$(_readaccountconf_mutable NSUPDATE_KEY)}" + NSUPDATE_ZONE="${NSUPDATE_ZONE:-$(_readaccountconf_mutable NSUPDATE_ZONE)}" + _checkKeyFile || return 1 + + # save the dns server and key to the account conf file. + _saveaccountconf_mutable NSUPDATE_SERVER "${NSUPDATE_SERVER}" + _saveaccountconf_mutable NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}" + _saveaccountconf_mutable NSUPDATE_KEY "${NSUPDATE_KEY}" + _saveaccountconf_mutable NSUPDATE_ZONE "${NSUPDATE_ZONE}" + [ -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_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" @@ -42,6 +50,12 @@ EOF #Usage: dns_nsupdate_rm _acme-challenge.www.domain.com dns_nsupdate_rm() { fulldomain=$1 + + NSUPDATE_SERVER="${NSUPDATE_SERVER:-$(_readaccountconf_mutable NSUPDATE_SERVER)}" + NSUPDATE_SERVER_PORT="${NSUPDATE_SERVER_PORT:-$(_readaccountconf_mutable NSUPDATE_SERVER_PORT)}" + NSUPDATE_KEY="${NSUPDATE_KEY:-$(_readaccountconf_mutable NSUPDATE_KEY)}" + NSUPDATE_ZONE="${NSUPDATE_ZONE:-$(_readaccountconf_mutable NSUPDATE_ZONE)}" + _checkKeyFile || return 1 [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 From 4f1888d2ea755332b83f955a2dde1a52624bff40 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 21 Apr 2019 12:23:06 +0800 Subject: [PATCH 338/565] fix https://github.com/Neilpang/acme.sh/issues/2192 --- acme.sh | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 77f84a2..ff6f8e4 100755 --- a/acme.sh +++ b/acme.sh @@ -1312,13 +1312,19 @@ _create_account_key() { _initpath mkdir -p "$CA_DIR" - if [ -f "$ACCOUNT_KEY_PATH" ]; then + if [ -s "$ACCOUNT_KEY_PATH" ]; then _info "Account key exists, skip" - return + return 0 else #generate account key - _createkey "$length" "$ACCOUNT_KEY_PATH" - chmod 600 "$ACCOUNT_KEY_PATH" + if _createkey "$length" "$ACCOUNT_KEY_PATH"; then + chmod 600 "$ACCOUNT_KEY_PATH" + _info "Create account key ok." + return 0 + else + _err "Create account key error." + return 1 + fi fi } @@ -1341,11 +1347,14 @@ createDomainKey() { _initpath "$domain" "$_cdl" - if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]) || [ "$Le_ForceNewDomainKey" = "1" ]; then + if [ ! -f "$CERT_KEY_PATH" ] || [ ! -s "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]) || [ "$Le_ForceNewDomainKey" = "1" ]; then if _createkey "$_cdl" "$CERT_KEY_PATH"; then _savedomainconf Le_Keylength "$_cdl" _info "The domain key is here: $(__green $CERT_KEY_PATH)" return 0 + else + _err "Can not domain key" + return 1 fi else if [ "$IS_RENEW" ]; then From e6df1828d9029f278a74798eac81f4a3c86a052d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 21 Apr 2019 12:37:26 +0800 Subject: [PATCH 339/565] fix https://github.com/Neilpang/acme.sh/issues/2192 --- acme.sh | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index c004934..9d5b6e5 100755 --- a/acme.sh +++ b/acme.sh @@ -1006,10 +1006,20 @@ _createkey() { if _isEccKey "$length"; then _debug "Using ec name: $eccname" - ${ACME_OPENSSL_BIN:-openssl} ecparam -name "$eccname" -genkey 2>/dev/null >"$f" + if _opkey="$(${ACME_OPENSSL_BIN:-openssl} ecparam -name "$eccname" -genkey 2>/dev/null)"; then + echo "$_opkey" >"$f" + else + _err "error ecc key name: $eccname" + return 1 + fi else _debug "Using RSA: $length" - ${ACME_OPENSSL_BIN:-openssl} genrsa "$length" 2>/dev/null >"$f" + if _opkey="$(${ACME_OPENSSL_BIN:-openssl} genrsa "$length" 2>/dev/null)"; then + echo "$_opkey" >"$f" + else + _err "error rsa key: $length" + return 1 + fi fi if [ "$?" != "0" ]; then From d1030eb0b2939a0748cd1208442bafdc1fd39a46 Mon Sep 17 00:00:00 2001 From: mod242 <40213799+mod242@users.noreply.github.com> Date: Wed, 24 Apr 2019 14:03:54 +0200 Subject: [PATCH 340/565] Create DDNSS API based on the work of helbgd --- dnsapi/dns_ddnss.sh | 133 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 dnsapi/dns_ddnss.sh diff --git a/dnsapi/dns_ddnss.sh b/dnsapi/dns_ddnss.sh new file mode 100644 index 0000000..f2e9947 --- /dev/null +++ b/dnsapi/dns_ddnss.sh @@ -0,0 +1,133 @@ +#!/usr/bin/env sh + +#Created by RaidenII, to use DuckDNS's API to add/remove text records +#06/27/201 +#modified by helbgd @ 03/13/2018 to support ddnss.de +#modified by mod242 @ 04/24/2018 to support different ddnss domains +#Please note: the Wildcard Feature must be turned on for the Host record +#and the checkbox for TXT needs to be enabled + + +# Pass credentials before "acme.sh --issue --dns dns_ddnss ..." +# -- +# export DDNSS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" +# -- +# + + +DDNSS_DNS_API="https://ddnss.de/upd.php" + +######## Public functions ##################### + +#Usage: dns_ddnss_add _acme-challenge.domain.ddnss.de "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ddnss_add() { + fulldomain=$1 + txtvalue=$2 + + DDNSS_Token="${DDNSS_Token:-$(_readaccountconf_mutable DDNSS_Token)}" + if [ -z "$DDNSS_Token" ]; then + _err "You must export variable: DDNSS_Token" + _err "The token for your DDNSS account is necessary." + _err "You can look it up in your DDNSS account." + return 1 + fi + + # Now save the credentials. + _saveaccountconf_mutable DDNSS_Token "$DDNSS_Token" + + # Unfortunately, DDNSS does not seems to support lookup domain through API + # So I assume your credentials (which are your domain and token) are correct + # If something goes wrong, we will get a KO response from DDNSS + + if ! _ddnss_get_domain; then + return 1 + fi + + # Now add the TXT record to DDNSS DNS + _info "Trying to add TXT record" + if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=1&txt=$txtvalue"; then + if [ "$response" = "Updated 1 hostname." ]; then + _info "TXT record has been successfully added to your DDNSS domain." + _info "Note that all subdomains under this domain uses the same TXT record." + return 0 + else + _err "Errors happened during adding the TXT record, response=$response" + return 1 + fi + else + _err "Errors happened during adding the TXT record." + return 1 + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_ddnss_rm() { + fulldomain=$1 + txtvalue=$2 + + DDNSS_Token="${DDNSS_Token:-$(_readaccountconf_mutable DDNSS_Token)}" + if [ -z "$DDNSS_Token" ]; then + _err "You must export variable: DDNSS_Token" + _err "The token for your DDNSS account is necessary." + _err "You can look it up in your DDNSS account." + return 1 + fi + + if ! _ddnss_get_domain; then + return 1 + fi + + # Now remove the TXT record from DDNS DNS + _info "Trying to remove TXT record" + if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=1&txt=."; then + if [ "$response" = "Updated 1 hostname." ]; then + _info "TXT record has been successfully removed from your DDNSS domain." + return 0 + else + _err "Errors happened during removing the TXT record, response=$response" + return 1 + fi + else + _err "Errors happened during removing the TXT record." + return 1 + fi +} + +#################### Private functions below ################################## + +#fulldomain=_acme-challenge.domain.ddnss.de +#returns +# _ddnss_domain=domain +_ddnss_get_domain() { + + # We'll extract the domain/username from full domain + _ddnss_domain="$(echo "$fulldomain" | _lower_case | _egrep_o '[.][^.][^.]*[.](ddnss|dyn-ip24|dyndns|dyn|dyndns1|home-webserver|myhome-server|dynip)\..*' | cut -d . -f 2-)" + + if [ -z "$_ddnss_domain" ]; then + _err "Error extracting the domain." + return 1 + fi + + return 0 +} + +#Usage: method URI +_ddnss_rest() { + method=$1 + param="$2" + _debug param "$param" + url="$DDNSS_DNS_API?$param" + _debug url "$url" + + # DDNSS uses GET to update domain info + if [ "$method" = "GET" ]; then + response="$(_get "$url" | sed -e :a -e 's/<[^>]*>//g;/ Date: Wed, 24 Apr 2019 14:57:48 +0200 Subject: [PATCH 341/565] Removed -e and changed tail to funktion --- dnsapi/dns_ddnss.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ddnss.sh b/dnsapi/dns_ddnss.sh index f2e9947..711936d 100644 --- a/dnsapi/dns_ddnss.sh +++ b/dnsapi/dns_ddnss.sh @@ -122,7 +122,7 @@ _ddnss_rest() { # DDNSS uses GET to update domain info if [ "$method" = "GET" ]; then - response="$(_get "$url" | sed -e :a -e 's/<[^>]*>//g;/]*>//g;/ Date: Wed, 24 Apr 2019 16:05:44 +0200 Subject: [PATCH 342/565] Update dns_ddnss.sh --- dnsapi/dns_ddnss.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ddnss.sh b/dnsapi/dns_ddnss.sh index 711936d..f0cf04f 100644 --- a/dnsapi/dns_ddnss.sh +++ b/dnsapi/dns_ddnss.sh @@ -122,7 +122,7 @@ _ddnss_rest() { # DDNSS uses GET to update domain info if [ "$method" = "GET" ]; then - response="$(_get "$url" | sed :a -e 's/<[^>]*>//g;/]*>//g;/ Date: Wed, 24 Apr 2019 16:15:01 +0200 Subject: [PATCH 343/565] Cleanup according to styleguide --- dnsapi/dns_ddnss.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/dnsapi/dns_ddnss.sh b/dnsapi/dns_ddnss.sh index f0cf04f..53665ad 100644 --- a/dnsapi/dns_ddnss.sh +++ b/dnsapi/dns_ddnss.sh @@ -7,14 +7,12 @@ #Please note: the Wildcard Feature must be turned on for the Host record #and the checkbox for TXT needs to be enabled - # Pass credentials before "acme.sh --issue --dns dns_ddnss ..." # -- # export DDNSS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" # -- # - DDNSS_DNS_API="https://ddnss.de/upd.php" ######## Public functions ##################### From 20af1ceb7d4cdadcc9fae50914159fff716bc7f9 Mon Sep 17 00:00:00 2001 From: mod242 <40213799+mod242@users.noreply.github.com> Date: Wed, 24 Apr 2019 19:38:07 +0200 Subject: [PATCH 344/565] Cleanup comment --- dnsapi/dns_ddnss.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_ddnss.sh b/dnsapi/dns_ddnss.sh index 53665ad..c38e6c7 100644 --- a/dnsapi/dns_ddnss.sh +++ b/dnsapi/dns_ddnss.sh @@ -1,7 +1,6 @@ #!/usr/bin/env sh #Created by RaidenII, to use DuckDNS's API to add/remove text records -#06/27/201 #modified by helbgd @ 03/13/2018 to support ddnss.de #modified by mod242 @ 04/24/2018 to support different ddnss domains #Please note: the Wildcard Feature must be turned on for the Host record From 52f556412212040fbaeb8aa1cb6e5cb6a58a74c9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 25 Apr 2019 20:58:13 +0800 Subject: [PATCH 345/565] fix image links --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 2885982..8d40d51 100644 --- a/README.md +++ b/README.md @@ -45,25 +45,25 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) | NO | Status| Platform| |----|-------|---------| -|1|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Ubuntu -|2|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Debian -|3|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/centos-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|CentOS -|4|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/windows-cygwin.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Windows (cygwin with curl, openssl and crontab included) -|5|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|FreeBSD -|6|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/pfsense.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|pfsense -|7|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|openSUSE -|8|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Alpine Linux (with curl) -|9|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Archlinux -|10|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|fedora -|11|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Kali Linux -|12|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Oracle Linux -|13|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/proxmox.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh +|1|[![](https://neilpang.github.io/acmetest/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Ubuntu +|2|[![](https://neilpang.github.io/acmetest/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Debian +|3|[![](https://neilpang.github.io/acmetest/status/centos-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|CentOS +|4|[![](https://neilpang.github.io/acmetest/status/windows-cygwin.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Windows (cygwin with curl, openssl and crontab included) +|5|[![](https://neilpang.github.io/acmetest/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|FreeBSD +|6|[![](https://neilpang.github.io/acmetest/status/pfsense.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|pfsense +|7|[![](https://neilpang.github.io/acmetest/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|openSUSE +|8|[![](https://neilpang.github.io/acmetest/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Alpine Linux (with curl) +|9|[![](https://neilpang.github.io/acmetest/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Archlinux +|10|[![](https://neilpang.github.io/acmetest/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|fedora +|11|[![](https://neilpang.github.io/acmetest/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Kali Linux +|12|[![](https://neilpang.github.io/acmetest/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Oracle Linux +|13|[![](https://neilpang.github.io/acmetest/status/proxmox.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh |14|-----| Cloud Linux https://github.com/Neilpang/le/issues/111 -|15|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/openbsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|OpenBSD -|16|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/mageia.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Mageia +|15|[![](https://neilpang.github.io/acmetest/status/openbsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|OpenBSD +|16|[![](https://neilpang.github.io/acmetest/status/mageia.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Mageia |17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT) -|18|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/solaris.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris -|19|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/gentoo-stage3-amd64.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux +|18|[![](https://neilpang.github.io/acmetest/status/solaris.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris +|19|[![](https://neilpang.github.io/acmetest/status/gentoo-stage3-amd64.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux |20|[![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)|Mac OSX For all build statuses, check our [weekly build project](https://github.com/Neilpang/acmetest): From bb703281a289531643cf47331a8fa829f81f5f3d Mon Sep 17 00:00:00 2001 From: mod242 <40213799+mod242@users.noreply.github.com> Date: Thu, 25 Apr 2019 16:18:52 +0200 Subject: [PATCH 346/565] Update dns_ddnss.sh --- dnsapi/dns_ddnss.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ddnss.sh b/dnsapi/dns_ddnss.sh index c38e6c7..dfe6dcb 100644 --- a/dnsapi/dns_ddnss.sh +++ b/dnsapi/dns_ddnss.sh @@ -119,7 +119,7 @@ _ddnss_rest() { # DDNSS uses GET to update domain info if [ "$method" = "GET" ]; then - response="$(_get "$url" | sed :a -e 's/<[^>]*>//g;/]*>//g;/ Date: Fri, 26 Apr 2019 23:44:25 +0800 Subject: [PATCH 347/565] fix idn issues --- acme.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 9d5b6e5..5c9bf0c 100755 --- a/acme.sh +++ b/acme.sh @@ -1084,11 +1084,12 @@ _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 [ "$acmeValidationv1" ]; then + domainlist="$(_idn "$domainlist")" printf -- "\nsubjectAltName=DNS:$domainlist" >>"$csrconf" elif [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then #single domain _info "Single domain" "$domain" - printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf" + printf -- "\nsubjectAltName=DNS:$(_idn $domain)" >>"$csrconf" else domainlist="$(_idn "$domainlist")" _debug2 domainlist "$domainlist" @@ -3557,7 +3558,9 @@ _check_dns_entries() { for entry in $dns_entries; do d=$(_getfield "$entry" 1) txtdomain=$(_getfield "$entry" 2) + txtdomain=$(_idn $txtdomain) aliasDomain=$(_getfield "$entry" 3) + aliasDomain=$(_idn $aliasDomain) txt=$(_getfield "$entry" 5) d_api=$(_getfield "$entry" 6) _debug "d" "$d" @@ -3754,7 +3757,7 @@ issue() { if [ -z "$vlist" ]; then if [ "$ACME_VERSION" = "2" ]; then #make new order request - _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}" + _identifiers="{\"type\":\"dns\",\"value\":\"$(_idn $_main_domain)\"}" _w_index=1 while true; do d="$(echo "$_alt_domains," | cut -d , -f "$_w_index")" @@ -3851,7 +3854,7 @@ $_authorizations_map" fi if [ "$ACME_VERSION" = "2" ]; then - response="$(echo "$_authorizations_map" | grep "^$d," | sed "s/$d,//")" + response="$(echo "$_authorizations_map" | grep "^$(_idn $d)," | sed "s/$d,//")" _debug2 "response" "$response" if [ -z "$response" ]; then _err "get to authz error." From 47ff768b70aa8ab40ea7966b5a8fa90c4f2e6e2c Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 26 Apr 2019 23:57:40 +0800 Subject: [PATCH 348/565] fix https://github.com/Neilpang/acme.sh/issues/2195 --- 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 9673143..7825084 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -58,7 +58,7 @@ 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 _contains "$response" "$fulldomain"; then + if _contains "$response" "$txtvalue"; then _info "Added, OK" return 0 elif _contains "$response" "The record already exists"; then From a7420ca3d4e0c73b315df3c746c78b10aaf7f74b Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 27 Apr 2019 09:17:26 +0800 Subject: [PATCH 349/565] typo --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 6694aed..93ad83d 100755 --- a/acme.sh +++ b/acme.sh @@ -1364,7 +1364,7 @@ createDomainKey() { _info "The domain key is here: $(__green $CERT_KEY_PATH)" return 0 else - _err "Can not domain key" + _err "Can not create domain key" return 1 fi else From 1b062ab929f4e3b62d72a61dbe77b17c0252d405 Mon Sep 17 00:00:00 2001 From: mod242 <40213799+mod242@users.noreply.github.com> Date: Sun, 28 Apr 2019 15:58:08 +0200 Subject: [PATCH 350/565] Correct sed parsing error --- dnsapi/dns_ddnss.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ddnss.sh b/dnsapi/dns_ddnss.sh index dfe6dcb..903b961 100644 --- a/dnsapi/dns_ddnss.sh +++ b/dnsapi/dns_ddnss.sh @@ -119,7 +119,7 @@ _ddnss_rest() { # DDNSS uses GET to update domain info if [ "$method" = "GET" ]; then - response="$(_get "$url" | sed 's/<[^>]*>//g;/]*>//g' | _tail_n 1)" else _err "Unsupported method" return 1 From 5b1b5cc8f2c76c31859cf2047c230730707689d3 Mon Sep 17 00:00:00 2001 From: mod242 <40213799+mod242@users.noreply.github.com> Date: Mon, 29 Apr 2019 10:43:16 +0200 Subject: [PATCH 351/565] Create dns_schlundtech.sh --- dnsapi/dns_schlundtech.sh | 261 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 dnsapi/dns_schlundtech.sh diff --git a/dnsapi/dns_schlundtech.sh b/dnsapi/dns_schlundtech.sh new file mode 100644 index 0000000..202b346 --- /dev/null +++ b/dnsapi/dns_schlundtech.sh @@ -0,0 +1,261 @@ +#!/usr/bin/env sh +# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*- + +# Schlundtech DNS API +# Author: mod242 +# Created: 2019-40-29 +# Completly based on the autoDNS xml api wrapper by auerswald@gmail.com +# +# export SCHLUNDTECH_USER="username" +# export SCHLUNDTECH_PASSWORD="password" +# +# Usage: +# acme.sh --issue --dns dns_autodns -d example.com + +AUTODNS_API="https://gateway.schlundtech.de" + +# Arguments: +# txtdomain +# txt +dns_schlundtech_add() { + fulldomain="$1" + txtvalue="$2" + + SCHLUNDTECH_USER="${SCHLUNDTECH_USER:-$(_readaccountconf_mutable AUTODNS_USER)}" + SCHLUNDTECH_PASSWORD="${SCHLUNDTECH_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}" + + if [ -z "$SCHLUNDTECH_USER" ] || [ -z "$SCHLUNDTECH_PASSWORD" ]; then + _err "You didn't specify schlundtech user and password." + return 1 + fi + + _saveaccountconf_mutable SCHLUNDTECH_USER "$SCHLUNDTECH_USER" + _saveaccountconf_mutable SCHLUNDTECH_PASSWORD "$SCHLUNDTECH_PASSWORD" + + _debug "First detect the root zone" + + if ! _get_autodns_zone "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _zone "$_zone" + _debug _system_ns "$_system_ns" + + _info "Adding TXT record" + + autodns_response="$(_autodns_zone_update "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" + + if [ "$?" -eq "0" ]; then + _info "Added, OK" + return 0 + fi + + return 1 +} + +# Arguments: +# txtdomain +# txt +dns_schlundtech_rm() { + fulldomain="$1" + txtvalue="$2" + + SCHLUNDTECH_USER="${SCHLUNDTECH_USER:-$(_readaccountconf_mutable AUTODNS_USER)}" + SCHLUNDTECH_PASSWORD="${SCHLUNDTECH_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}" + + if [ -z "$SCHLUNDTECH_USER" ] || [ -z "$SCHLUNDTECH_PASSWORD" ]; then + _err "You didn't specify schlundtech user and password." + return 1 + fi + + _debug "First detect the root zone" + + if ! _get_autodns_zone "$fulldomain"; then + _err "zone not found" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _zone "$_zone" + _debug _system_ns "$_system_ns" + + _info "Delete TXT record" + + autodns_response="$(_autodns_zone_cleanup "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" + + if [ "$?" -eq "0" ]; then + _info "Deleted, OK" + return 0 + fi + + return 1 +} + +#################### Private functions below ################################## + +# Arguments: +# fulldomain +# Returns: +# _sub_domain=_acme-challenge.www +# _zone=domain.com +# _system_ns +_get_autodns_zone() { + domain="$1" + + i=2 + p=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + + if [ -z "$h" ]; then + # not valid + return 1 + fi + + autodns_response="$(_autodns_zone_inquire "$h")" + + if [ "$?" -ne "0" ]; then + _err "invalid domain" + return 1 + fi + + if _contains "$autodns_response" "1" >/dev/null; then + _zone="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _system_ns="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +_build_request_auth_xml() { + printf " + %s + %s + 10 + " "$SCHLUNDTECH_USER" "$SCHLUNDTECH_PASSWORD" +} + +# Arguments: +# zone +_build_zone_inquire_xml() { + printf " + + %s + + 0205 + + 1 + 1 + + + name + eq + %s + + + " "$(_build_request_auth_xml)" "$1" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_build_zone_update_xml() { + printf " + + %s + + 0202001 + + + %s + 600 + TXT + %s + + + + %s + %s + + + " "$(_build_request_auth_xml)" "$2" "$3" "$1" "$4" +} + +# Arguments: +# zone +_autodns_zone_inquire() { + request_data="$(_build_zone_inquire_xml "$1")" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_autodns_zone_update() { + request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_autodns_zone_cleanup() { + request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" + # replace 'rr_add>' with 'rr_rem>' in request_data + request_data="$(printf -- "%s" "$request_data" | sed 's/rr_add>/rr_rem>/g')" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# request_data +_autodns_api_call() { + request_data="$1" + + _debug request_data "$request_data" + + autodns_response="$(_post "$request_data" "$AUTODNS_API")" + ret="$?" + + _debug autodns_response "$autodns_response" + + if [ "$ret" -ne "0" ]; then + _err "error" + return 1 + fi + + if _contains "$autodns_response" "success" >/dev/null; then + _info "success" + printf "%s" "$autodns_response" + return 0 + fi + + return 1 +} From 345d6c5687e48dae07494565d735a367f6faa7af Mon Sep 17 00:00:00 2001 From: mod242 <40213799+mod242@users.noreply.github.com> Date: Mon, 29 Apr 2019 10:44:23 +0200 Subject: [PATCH 352/565] Update dns_schlundtech.sh --- dnsapi/dns_schlundtech.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_schlundtech.sh b/dnsapi/dns_schlundtech.sh index 202b346..c5e7d63 100644 --- a/dnsapi/dns_schlundtech.sh +++ b/dnsapi/dns_schlundtech.sh @@ -21,8 +21,8 @@ dns_schlundtech_add() { fulldomain="$1" txtvalue="$2" - SCHLUNDTECH_USER="${SCHLUNDTECH_USER:-$(_readaccountconf_mutable AUTODNS_USER)}" - SCHLUNDTECH_PASSWORD="${SCHLUNDTECH_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}" + SCHLUNDTECH_USER="${SCHLUNDTECH_USER:-$(_readaccountconf_mutable SCHLUNDTECH_USER)}" + SCHLUNDTECH_PASSWORD="${SCHLUNDTECH_PASSWORD:-$(_readaccountconf_mutable SCHLUNDTECH_PASSWORD)}" if [ -z "$SCHLUNDTECH_USER" ] || [ -z "$SCHLUNDTECH_PASSWORD" ]; then _err "You didn't specify schlundtech user and password." From 9b68a3ef4acb7112119d01182965394cd653c761 Mon Sep 17 00:00:00 2001 From: mod242 <40213799+mod242@users.noreply.github.com> Date: Mon, 29 Apr 2019 12:13:40 +0200 Subject: [PATCH 353/565] Update dns_schlundtech.sh --- dnsapi/dns_schlundtech.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_schlundtech.sh b/dnsapi/dns_schlundtech.sh index c5e7d63..efb021a 100644 --- a/dnsapi/dns_schlundtech.sh +++ b/dnsapi/dns_schlundtech.sh @@ -62,8 +62,8 @@ dns_schlundtech_rm() { fulldomain="$1" txtvalue="$2" - SCHLUNDTECH_USER="${SCHLUNDTECH_USER:-$(_readaccountconf_mutable AUTODNS_USER)}" - SCHLUNDTECH_PASSWORD="${SCHLUNDTECH_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}" + SCHLUNDTECH_USER="${SCHLUNDTECH_USER:-$(_readaccountconf_mutable SCHLUNDTECH_USER)}" + SCHLUNDTECH_PASSWORD="${SCHLUNDTECH_PASSWORD:-$(_readaccountconf_mutable SCHLUNDTECH_PASSWORD)}" if [ -z "$SCHLUNDTECH_USER" ] || [ -z "$SCHLUNDTECH_PASSWORD" ]; then _err "You didn't specify schlundtech user and password." From 175b56b43c05ed0ed2ec432e3e1ead2f12f78414 Mon Sep 17 00:00:00 2001 From: mod242 <40213799+mod242@users.noreply.github.com> Date: Mon, 29 Apr 2019 12:18:05 +0200 Subject: [PATCH 354/565] Update dns_schlundtech.sh --- dnsapi/dns_schlundtech.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_schlundtech.sh b/dnsapi/dns_schlundtech.sh index efb021a..1240863 100644 --- a/dnsapi/dns_schlundtech.sh +++ b/dnsapi/dns_schlundtech.sh @@ -10,9 +10,9 @@ # export SCHLUNDTECH_PASSWORD="password" # # Usage: -# acme.sh --issue --dns dns_autodns -d example.com +# acme.sh --issue --dns dns_schlundtech -d example.com -AUTODNS_API="https://gateway.schlundtech.de" +SCHLUNDTECH_API="https://gateway.schlundtech.de" # Arguments: # txtdomain @@ -241,7 +241,7 @@ _autodns_api_call() { _debug request_data "$request_data" - autodns_response="$(_post "$request_data" "$AUTODNS_API")" + autodns_response="$(_post "$request_data" "$SCHLUNDTECH_API")" ret="$?" _debug autodns_response "$autodns_response" From d10f40f109d417ba9810eefd482662ba44fec208 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 29 Apr 2019 21:44:25 +0800 Subject: [PATCH 355/565] fix idn issue. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 93ad83d..0ce42ff 100755 --- a/acme.sh +++ b/acme.sh @@ -1032,7 +1032,7 @@ _createkey() { _is_idn() { _is_idn_d="$1" _debug2 _is_idn_d "$_is_idn_d" - _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '*.,-') + _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '*.,-_') _debug2 _idn_temp "$_idn_temp" [ "$_idn_temp" ] } From a89d50d34ee8d20ca7365f6aa6d1e6465f2f626c Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 29 Apr 2019 21:52:22 +0800 Subject: [PATCH 356/565] use mutable --- dnsapi/dns_cx.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index d07d8e0..c287d50 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -16,6 +16,8 @@ dns_cx_add() { fulldomain=$1 txtvalue=$2 + CX_Key="${CX_Key:-$(_readaccountconf_mutable CX_Key)}" + CX_Secret="${CX_Secret:-$(_readaccountconf_mutable CX_Secret)}" if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then CX_Key="" CX_Secret="" @@ -27,8 +29,8 @@ dns_cx_add() { REST_API="$CX_Api" #save the api key and email to the account conf file. - _saveaccountconf CX_Key "$CX_Key" - _saveaccountconf CX_Secret "$CX_Secret" + _saveaccountconf_mutable CX_Key "$CX_Key" + _saveaccountconf_mutable CX_Secret "$CX_Secret" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -43,6 +45,8 @@ dns_cx_add() { dns_cx_rm() { fulldomain=$1 txtvalue=$2 + CX_Key="${CX_Key:-$(_readaccountconf_mutable CX_Key)}" + CX_Secret="${CX_Secret:-$(_readaccountconf_mutable CX_Secret)}" REST_API="$CX_Api" if _get_root "$fulldomain"; then record_id="" From b7a04430913063b8801fba50a8647ae51aefabc3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 29 Apr 2019 22:11:25 +0800 Subject: [PATCH 357/565] lets start 2.8.2 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 0ce42ff..153b953 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.8.1 +VER=2.8.2 PROJECT_NAME="acme.sh" From b50e701caefed9fdde1bd2c388e7f3a0011ebb54 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 29 Apr 2019 22:13:54 +0800 Subject: [PATCH 358/565] Add notification (#2241) * add cron notify * fix format * fix format --- acme.sh | 270 ++++++++++++++++++++++++++++++++++++++++++--- notify/mail.sh | 15 +++ notify/mailgun.sh | 123 +++++++++++++++++++++ notify/pop.sh | 15 +++ notify/sendgrid.sh | 56 ++++++++++ notify/smtp.sh | 15 +++ 6 files changed, 481 insertions(+), 13 deletions(-) create mode 100644 notify/mail.sh create mode 100644 notify/mailgun.sh create mode 100644 notify/pop.sh create mode 100644 notify/sendgrid.sh create mode 100644 notify/smtp.sh diff --git a/acme.sh b/acme.sh index 153b953..dc110a0 100755 --- a/acme.sh +++ b/acme.sh @@ -14,7 +14,11 @@ _WINDOWS_SCHEDULER_NAME="$PROJECT_NAME.cron" _SCRIPT_="$0" -_SUB_FOLDERS="dnsapi deploy" +_SUB_FOLDER_NOTIFY="notify" +_SUB_FOLDER_DNSAPI="dnsapi" +_SUB_FOLDER_DEPLOY="deploy" + +_SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY" LETSENCRYPT_CA_V1="https://acme-v01.api.letsencrypt.org/directory" LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory" @@ -107,6 +111,18 @@ SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_ERROR #none SYSLOG_LEVEL_NONE=0 +NOTIFY_LEVEL_DISABLE=0 +NOTIFY_LEVEL_ERROR=1 +NOTIFY_LEVEL_RENEW=2 +NOTIFY_LEVEL_SKIP=3 + +NOTIFY_LEVEL_DEFAULT=$NOTIFY_LEVEL_RENEW + +NOTIFY_MODE_BULK=0 +NOTIFY_MODE_CERT=1 + +NOTIFY_MODE_DEFAULT=$NOTIFY_MODE_BULK + _DEBUG_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh" _PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations" @@ -117,6 +133,8 @@ _DNS_ALIAS_WIKI="https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode" _DNS_MANUAL_WIKI="https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode" +_NOTIFY_WIKI="https://github.com/Neilpang/acme.sh/wiki/notify" + _DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead." _DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR" @@ -784,6 +802,13 @@ _url_encode() { done } +_json_encode() { + _j_str="$(sed 's/"/\\"/g' | sed "s/\r/\\r/g")" + _debug3 "_json_encode" + _debug3 "_j_str" "$_j_str" + echo "$_j_str" | _hex_dump | _lower_case | sed 's/0a/5c 6e/g' | tr -d ' ' | _h2b | tr -d "\r\n" +} + #options file _sed_i() { options="$1" @@ -3168,6 +3193,14 @@ _on_issue_err() { _err "See: $_DEBUG_WIKI" fi + if [ "$IN_CRON" ]; then + if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_ERROR ]; then + if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then + _send_notify "Renew $_main_domain error" "There is an error." "$NOTIFY_HOOK" 1 + fi + fi + fi + #run the post hook if [ "$_chk_post_hook" ]; then _info "Run post hook:'$_chk_post_hook'" @@ -3210,6 +3243,13 @@ _on_issue_success() { _chk_post_hook="$1" _chk_renew_hook="$2" _debug _on_issue_success + if [ "$IN_CRON" ]; then + if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_RENEW ]; then + if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then + _send_notify "Renew $_main_domain success" "Good, the cert is renewed." "$NOTIFY_HOOK" 0 + fi + fi + fi #run the post hook if [ "$_chk_post_hook" ]; then _info "Run post hook:'$_chk_post_hook'" @@ -3467,9 +3507,9 @@ _findHook() { d_api="$_SCRIPT_HOME/$_hookcat/$_hookname" elif [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname.sh" ]; then d_api="$_SCRIPT_HOME/$_hookcat/$_hookname.sh" - elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ]; then + elif [ "$_hookdomain" ] && [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ]; then d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname" - elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ]; then + elif [ "$_hookdomain" ] && [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ]; then d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" elif [ -f "$LE_WORKING_DIR/$_hookname" ]; then d_api="$LE_WORKING_DIR/$_hookname" @@ -4017,7 +4057,7 @@ $_authorizations_map" txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" _debug txt "$txt" - d_api="$(_findHook "$_dns_root_d" dnsapi "$_currentRoot")" + d_api="$(_findHook "$_dns_root_d" $_SUB_FOLDER_DNSAPI "$_currentRoot")" _debug d_api "$d_api" dns_entry="$dns_entry$dvsep$txt${dvsep}$d_api" @@ -4622,6 +4662,15 @@ renew() { if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")" _info "Add '$(__red '--force')' to force to renew." + + if [ "$IN_CRON" = "1" ]; then + if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_SKIP ]; then + if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then + _send_notify "Renew $Le_Domain skipped" "Good, the cert next renewal time is $Le_NextRenewTimeStr." "$NOTIFY_HOOK" "$RENEW_SKIP" + fi + fi + fi + return "$RENEW_SKIP" fi @@ -4657,7 +4706,9 @@ renewAll() { _stopRenewOnError="$1" _debug "_stopRenewOnError" "$_stopRenewOnError" _ret="0" - + _success_msg="" + _error_msg="" + _skipped_msg="" for di in "${CERT_HOME}"/*.*/; do _debug di "$di" if ! [ -d "$di" ]; then @@ -4678,15 +4729,49 @@ renewAll() { if [ "$rc" != "0" ]; then if [ "$rc" = "$RENEW_SKIP" ]; then _info "Skipped $d" - elif [ "$_stopRenewOnError" ]; then - _err "Error renew $d, stop now." - return "$rc" + _skipped_msg="${_skipped_msg} $d +" else - _ret="$rc" - _err "Error renew $d." + _error_msg="${_error_msg} $d +" + if [ "$_stopRenewOnError" ]; then + _err "Error renew $d, stop now." + _ret="$rc" + break + else + _ret="$rc" + _err "Error renew $d." + fi fi + else + _success_msg="${_success_msg} $d +" fi done + + if [ "$IN_CRON" = "1" ]; then + if [ -z "$NOTIFY_MODE" ] || [ "$NOTIFY_MODE" = "$NOTIFY_MODE_BULK" ]; then + _msg_subject="Renew" + if [ "$_error_msg" ]; then + _msg_subject="${_msg_subject} Error" + fi + if [ "$_success_msg" ]; then + _msg_subject="${_msg_subject} Success" + fi + if [ "$_skipped_msg" ]; then + _msg_subject="${_msg_subject} Skipped" + fi + _msg_data="Error certs: +${_error_msg} +Success certs: +${_success_msg} +Skipped certs: +$_skipped_msg +" + _send_notify "$_msg_subject" "$_msg_data" "$NOTIFY_HOOK" 0 + fi + fi + return "$_ret" } @@ -4835,7 +4920,7 @@ _deploy() { _hooks="$2" for _d_api in $(echo "$_hooks" | tr ',' " "); do - _deployApi="$(_findHook "$_d" deploy "$_d_api")" + _deployApi="$(_findHook "$_d" $_SUB_FOLDER_DEPLOY "$_d_api")" if [ -z "$_deployApi" ]; then _err "The deploy hook $_d_api is not found." return 1 @@ -5785,6 +5870,113 @@ version() { echo "v$VER" } +# subject content hooks code +_send_notify() { + _nsubject="$1" + _ncontent="$2" + _nhooks="$3" + _nerror="$4" + + if [ "$NOTIFY_LEVEL" = "$NOTIFY_LEVEL_DISABLE" ]; then + _debug "The NOTIFY_LEVEL is $NOTIFY_LEVEL, disabled, just return." + return 0 + fi + + if [ -z "$_nhooks" ]; then + _debug "The NOTIFY_HOOK is empty, just return." + return 0 + fi + + _send_err=0 + for _n_hook in $(echo "$_nhooks" | tr ',' " "); do + _n_hook_file="$(_findHook "" $_SUB_FOLDER_NOTIFY "$_n_hook")" + _info "Found $_n_hook_file" + + if ! ( + if ! . "$_n_hook_file"; then + _err "Load file $_n_hook_file error. Please check your api file and try again." + return 1 + fi + + d_command="${_n_hook}_send" + if ! _exists "$d_command"; then + _err "It seems that your api file is not correct, it must have a function named: $d_command" + return 1 + fi + + if ! $d_command "$_nsubject" "$_ncontent" "$_nerror"; then + _err "Error send message by $d_command" + return 1 + fi + + return 0 + ); then + _err "Set $_n_hook_file error." + _send_err=1 + else + _info "$_n_hook $(__green Success)" + fi + done + return $_send_err + +} + +# hook +_set_notify_hook() { + _nhooks="$1" + + _test_subject="Hello, this is notification from $PROJECT_NAME" + _test_content="If you receive this email, your notification works." + + _send_notify "$_test_subject" "$_test_content" "$_nhooks" 0 + +} + +#[hook] [level] [mode] +setnotify() { + _nhook="$1" + _nlevel="$2" + _nmode="$3" + + _initpath + + if [ -z "$_nhook$_nlevel$_nmode" ]; then + _usage "Usage: $PROJECT_ENTRY --set-notify [--notify-hook mailgun] [--notify-level $NOTIFY_LEVEL_DEFAULT] [--notify-mode $NOTIFY_MODE_DEFAULT]" + _usage "$_NOTIFY_WIKI" + return 1 + fi + + if [ "$_nlevel" ]; then + _info "Set notify level to: $_nlevel" + export "NOTIFY_LEVEL=$_nlevel" + _saveaccountconf "NOTIFY_LEVEL" "$NOTIFY_LEVEL" + fi + + if [ "$_nmode" ]; then + _info "Set notify mode to: $_nmode" + export "NOTIFY_MODE=$_nmode" + _saveaccountconf "NOTIFY_MODE" "$NOTIFY_MODE" + fi + + if [ "$_nhook" ]; then + _info "Set notify hook to: $_nhook" + if [ "$_nhook" = "$NO_VALUE" ]; then + _info "Clear notify hook" + _clearaccountconf "NOTIFY_HOOK" + else + if _set_notify_hook "$_nhook"; then + export NOTIFY_HOOK="$_nhook" + _saveaccountconf "NOTIFY_HOOK" "$NOTIFY_HOOK" + return 0 + else + _err "Can not set notify hook to: $_nhook" + return 1 + fi + fi + fi + +} + showhelp() { _initpath version @@ -5817,6 +6009,8 @@ Commands: --create-domain-key Create an domain private key, professional use. --createCSR, -ccsr Create CSR , professional use. --deactivate Deactivate the domain authz, professional use. + --set-notify Set the cron notification hook, level or mode. + Parameters: --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc. @@ -5885,7 +6079,18 @@ Parameters: --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. - " + + --notify-level 0|1|2|3 Set the notification level: Default value is $NOTIFY_LEVEL_DEFAULT. + 0: disabled, no notification will be sent. + 1: send notification only when there is an error. No news is good news. + 2: send notification when a cert is successfully renewed, or there is an error + 3: send notification when a cert is skipped, renewdd, or error + --notify-mode 0|1 Set notification mode. Default value is $NOTIFY_MODE_DEFAULT. + 0: Bulk mode. Send all the domain's notifications in one message(mail) + 1: Cert mode. Send a message for every single cert. + --notify-hook [hookname] Set the notify hook + +" } # nocron noprofile @@ -6019,6 +6224,9 @@ _process() { _syslog="" _use_wget="" _server="" + _notify_hook="" + _notify_level="" + _notify_mode="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -6105,6 +6313,9 @@ _process() { --deactivate-account) _CMD="deactivateaccount" ;; + --set-notify) + _CMD="setnotify" + ;; --domain | -d) _dvalue="$2" @@ -6453,6 +6664,37 @@ _process() { export BRANCH="$2" shift ;; + --notify-hook) + _nhook="$2" + if _startswith "$_nhook" "-"; then + _err "'$_nhook' is not a hook name for '$1'" + return 1 + fi + if [ "$_notify_hook" ]; then + _notify_hook="$_notify_hook,$_nhook" + else + _notify_hook="$_nhook" + fi + shift + ;; + --notify-level) + _nlevel="$2" + if _startswith "$_nlevel" "-"; then + _err "'$_nlevel' is not a integer for '$1'" + return 1 + fi + _notify_level="$_nlevel" + shift + ;; + --notify-mode) + _nmode="$2" + if _startswith "$_nmode" "-"; then + _err "'$_nmode' is not a integer for '$1'" + return 1 + fi + _notify_mode="$_nmode" + shift + ;; *) _err "Unknown parameter : $1" return 1 @@ -6570,7 +6812,9 @@ _process() { createCSR) createCSR "$_domain" "$_altdomains" "$_ecc" ;; - + setnotify) + setnotify "$_notify_hook" "$_notify_level" "$_notify_mode" + ;; *) if [ "$_CMD" ]; then _err "Invalid command: $_CMD" diff --git a/notify/mail.sh b/notify/mail.sh new file mode 100644 index 0000000..3dfef0b --- /dev/null +++ b/notify/mail.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh + +# support local mail app + +mail_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + _err "Not implemented yet." + return 1 +} diff --git a/notify/mailgun.sh b/notify/mailgun.sh new file mode 100644 index 0000000..1689a0b --- /dev/null +++ b/notify/mailgun.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env sh + +#Support mailgun.com api + +#MAILGUN_API_KEY="xxxx" +#MAILGUN_TO="yyyy@gmail.com" + +#MAILGUN_REGION="us|eu" #optional, use "us" as default +#MAILGUN_API_DOMAIN="xxxxxx.com" #optional, use the default sandbox domain +#MAILGUN_FROM="xxx@xxxxx.com" #optional, use the default sendbox account + +_MAILGUN_BASE="https://api.mailgun.net/v3" + +# subject content statusCode +mailgun_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + MAILGUN_API_KEY="${MAILGUN_API_KEY:-$(_readaccountconf_mutable MAILGUN_API_KEY)}" + if [ -z "$MAILGUN_API_KEY" ]; then + MAILGUN_API_KEY="" + _err "You didn't specify a mailgun api key MAILGUN_API_KEY yet ." + _err "You can get yours from here https://mailgun.com" + return 1 + fi + _saveaccountconf_mutable MAILGUN_API_KEY "$MAILGUN_API_KEY" + + MAILGUN_REGION="${MAILGUN_REGION:-$(_readaccountconf_mutable MAILGUN_REGION)}" + if [ -z "$MAILGUN_REGION" ]; then + MAILGUN_REGION="" + _info "The MAILGUN_REGION is not set, so use the default us region." + _MAILGUN_BASE="https://api.mailgun.net/v3" + else + _saveaccountconf_mutable MAILGUN_REGION "$MAILGUN_REGION" + _MAILGUN_BASE="https://api.eu.mailgun.net/v3" + fi + + MAILGUN_TO="${MAILGUN_TO:-$(_readaccountconf_mutable MAILGUN_TO)}" + if [ -z "$MAILGUN_TO" ]; then + MAILGUN_TO="" + _err "You didn't specify an email to MAILGUN_TO receive messages." + return 1 + fi + _saveaccountconf_mutable MAILGUN_TO "$MAILGUN_TO" + + MAILGUN_API_DOMAIN="${MAILGUN_API_DOMAIN:-$(_readaccountconf_mutable MAILGUN_API_DOMAIN)}" + if [ -z "$MAILGUN_API_DOMAIN" ]; then + _info "The MAILGUN_API_DOMAIN is not set, try to get the default sending sandbox domain for you." + if ! _mailgun_rest GET "/domains"; then + _err "Can not get sandbox domain." + return 1 + fi + _sendboxDomain="$(echo "$response" | _egrep_o '"name": *"sandbox.*.mailgun.org"' | cut -d : -f 2 | tr -d '" ')" + _debug _sendboxDomain "$_sendboxDomain" + MAILGUN_API_DOMAIN="$_sendboxDomain" + if [ -z "$MAILGUN_API_DOMAIN" ]; then + _err "Can not get sandbox domain for MAILGUN_API_DOMAIN" + return 1 + fi + + _info "$(__green "When using sandbox domain, you must verify your email first.")" + #todo: add recepient + fi + if [ -z "$MAILGUN_API_DOMAIN" ]; then + _err "Can not get MAILGUN_API_DOMAIN" + return 1 + fi + _saveaccountconf_mutable MAILGUN_API_DOMAIN "$MAILGUN_API_DOMAIN" + + MAILGUN_FROM="${MAILGUN_FROM:-$(_readaccountconf_mutable MAILGUN_FROM)}" + if [ -z "$MAILGUN_FROM" ]; then + MAILGUN_FROM="$PROJECT_NAME@$MAILGUN_API_DOMAIN" + _info "The MAILGUN_FROM is not set, so use the default value: $MAILGUN_FROM" + else + _debug MAILGUN_FROM "$MAILGUN_FROM" + _saveaccountconf_mutable MAILGUN_FROM "$MAILGUN_FROM" + fi + + #send from url + _msg="/$MAILGUN_API_DOMAIN/messages?from=$(printf "%s" "$MAILGUN_FROM" | _url_encode)&to=$(printf "%s" "$MAILGUN_TO" | _url_encode)&subject=$(printf "%s" "$_subject" | _url_encode)&text=$(printf "%s" "$_content" | _url_encode)" + _debug "_msg" "$_msg" + _mailgun_rest POST "$_msg" + if _contains "$response" "Queued. Thank you."; then + _info "mailgun send success." + return 0 + else + _err "mailgun send error" + _err "$response" + return 1 + fi + +} + +# method uri data +_mailgun_rest() { + _method="$1" + _mguri="$2" + _mgdata="$3" + _debug _mguri "$_mguri" + _mgurl="$_MAILGUN_BASE$_mguri" + _debug _mgurl "$_mgurl" + + _auth="$(printf "%s" "api:$MAILGUN_API_KEY" | _base64)" + export _H1="Authorization: Basic $_auth" + export _H2="Content-Type: application/json" + + if [ "$_method" = "GET" ]; then + response="$(_get "$_mgurl")" + else + _debug _mgdata "$_mgdata" + response="$(_post "$_mgdata" "$_mgurl" "" "$_method")" + fi + if [ "$?" != "0" ]; then + _err "Error: $_mguri" + _err "$response" + return 1 + fi + _debug2 response "$response" + return 0 + +} diff --git a/notify/pop.sh b/notify/pop.sh new file mode 100644 index 0000000..f118d79 --- /dev/null +++ b/notify/pop.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh + +# support pop + +pop_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + _err "Not implemented yet." + return 1 +} diff --git a/notify/sendgrid.sh b/notify/sendgrid.sh new file mode 100644 index 0000000..5c5bfdb --- /dev/null +++ b/notify/sendgrid.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env sh + +#Support SENDGRID.com api + +#SENDGRID_API_KEY="" +#SENDGRID_TO="xxxx@xxx.com" +#SENDGRID_FROM="xxxx@cccc.com" + +sendgrid_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + SENDGRID_API_KEY="${SENDGRID_API_KEY:-$(_readaccountconf_mutable SENDGRID_API_KEY)}" + if [ -z "$SENDGRID_API_KEY" ]; then + SENDGRID_API_KEY="" + _err "You didn't specify a sendgrid api key SENDGRID_API_KEY yet ." + _err "You can get yours from here https://sendgrid.com" + return 1 + fi + _saveaccountconf_mutable SENDGRID_API_KEY "$SENDGRID_API_KEY" + + SENDGRID_TO="${SENDGRID_TO:-$(_readaccountconf_mutable SENDGRID_TO)}" + if [ -z "$SENDGRID_TO" ]; then + SENDGRID_TO="" + _err "You didn't specify an email to SENDGRID_TO receive messages." + return 1 + fi + _saveaccountconf_mutable SENDGRID_TO "$SENDGRID_TO" + + SENDGRID_FROM="${SENDGRID_FROM:-$(_readaccountconf_mutable SENDGRID_FROM)}" + if [ -z "$SENDGRID_FROM" ]; then + SENDGRID_FROM="" + _err "You didn't specify an email to SENDGRID_FROM receive messages." + return 1 + fi + _saveaccountconf_mutable SENDGRID_FROM "$SENDGRID_FROM" + + export _H1="Authorization: Bearer $SENDGRID_API_KEY" + export _H2="Content-Type: application/json" + + _content="$(echo "$_content" | _json_encode)" + _data="{\"personalizations\": [{\"to\": [{\"email\": \"$SENDGRID_TO\"}]}],\"from\": {\"email\": \"$SENDGRID_FROM\"},\"subject\": \"$_subject\",\"content\": [{\"type\": \"text/plain\", \"value\": \"$_content\"}]}" + response="" #just make shellcheck happy + if _post "$_data" "https://api.sendgrid.com/v3/mail/send"; then + if [ -z "$response" ]; then + _info "sendgrid send sccess." + return 0 + fi + fi + _err "sendgrid send error." + _err "$response" + return 1 + +} diff --git a/notify/smtp.sh b/notify/smtp.sh new file mode 100644 index 0000000..6aa37ca --- /dev/null +++ b/notify/smtp.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh + +# support smtp + +smtp_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + _err "Not implemented yet." + return 1 +} From d7be2c5b8a4eb49da47faea5ded8da66d30f98b6 Mon Sep 17 00:00:00 2001 From: mod242 <40213799+mod242@users.noreply.github.com> Date: Mon, 29 Apr 2019 16:17:24 +0200 Subject: [PATCH 359/565] Remove from Master Branch --- dnsapi/dns_schlundtech.sh | 261 -------------------------------------- 1 file changed, 261 deletions(-) delete mode 100644 dnsapi/dns_schlundtech.sh diff --git a/dnsapi/dns_schlundtech.sh b/dnsapi/dns_schlundtech.sh deleted file mode 100644 index 1240863..0000000 --- a/dnsapi/dns_schlundtech.sh +++ /dev/null @@ -1,261 +0,0 @@ -#!/usr/bin/env sh -# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*- - -# Schlundtech DNS API -# Author: mod242 -# Created: 2019-40-29 -# Completly based on the autoDNS xml api wrapper by auerswald@gmail.com -# -# export SCHLUNDTECH_USER="username" -# export SCHLUNDTECH_PASSWORD="password" -# -# Usage: -# acme.sh --issue --dns dns_schlundtech -d example.com - -SCHLUNDTECH_API="https://gateway.schlundtech.de" - -# Arguments: -# txtdomain -# txt -dns_schlundtech_add() { - fulldomain="$1" - txtvalue="$2" - - SCHLUNDTECH_USER="${SCHLUNDTECH_USER:-$(_readaccountconf_mutable SCHLUNDTECH_USER)}" - SCHLUNDTECH_PASSWORD="${SCHLUNDTECH_PASSWORD:-$(_readaccountconf_mutable SCHLUNDTECH_PASSWORD)}" - - if [ -z "$SCHLUNDTECH_USER" ] || [ -z "$SCHLUNDTECH_PASSWORD" ]; then - _err "You didn't specify schlundtech user and password." - return 1 - fi - - _saveaccountconf_mutable SCHLUNDTECH_USER "$SCHLUNDTECH_USER" - _saveaccountconf_mutable SCHLUNDTECH_PASSWORD "$SCHLUNDTECH_PASSWORD" - - _debug "First detect the root zone" - - if ! _get_autodns_zone "$fulldomain"; then - _err "invalid domain" - return 1 - fi - - _debug _sub_domain "$_sub_domain" - _debug _zone "$_zone" - _debug _system_ns "$_system_ns" - - _info "Adding TXT record" - - autodns_response="$(_autodns_zone_update "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" - - if [ "$?" -eq "0" ]; then - _info "Added, OK" - return 0 - fi - - return 1 -} - -# Arguments: -# txtdomain -# txt -dns_schlundtech_rm() { - fulldomain="$1" - txtvalue="$2" - - SCHLUNDTECH_USER="${SCHLUNDTECH_USER:-$(_readaccountconf_mutable SCHLUNDTECH_USER)}" - SCHLUNDTECH_PASSWORD="${SCHLUNDTECH_PASSWORD:-$(_readaccountconf_mutable SCHLUNDTECH_PASSWORD)}" - - if [ -z "$SCHLUNDTECH_USER" ] || [ -z "$SCHLUNDTECH_PASSWORD" ]; then - _err "You didn't specify schlundtech user and password." - return 1 - fi - - _debug "First detect the root zone" - - if ! _get_autodns_zone "$fulldomain"; then - _err "zone not found" - return 1 - fi - - _debug _sub_domain "$_sub_domain" - _debug _zone "$_zone" - _debug _system_ns "$_system_ns" - - _info "Delete TXT record" - - autodns_response="$(_autodns_zone_cleanup "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" - - if [ "$?" -eq "0" ]; then - _info "Deleted, OK" - return 0 - fi - - return 1 -} - -#################### Private functions below ################################## - -# Arguments: -# fulldomain -# Returns: -# _sub_domain=_acme-challenge.www -# _zone=domain.com -# _system_ns -_get_autodns_zone() { - domain="$1" - - i=2 - p=1 - - while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - _debug h "$h" - - if [ -z "$h" ]; then - # not valid - return 1 - fi - - autodns_response="$(_autodns_zone_inquire "$h")" - - if [ "$?" -ne "0" ]; then - _err "invalid domain" - return 1 - fi - - if _contains "$autodns_response" "1" >/dev/null; then - _zone="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" - _system_ns="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - return 0 - fi - - p=$i - i=$(_math "$i" + 1) - done - - return 1 -} - -_build_request_auth_xml() { - printf " - %s - %s - 10 - " "$SCHLUNDTECH_USER" "$SCHLUNDTECH_PASSWORD" -} - -# Arguments: -# zone -_build_zone_inquire_xml() { - printf " - - %s - - 0205 - - 1 - 1 - - - name - eq - %s - - - " "$(_build_request_auth_xml)" "$1" -} - -# Arguments: -# zone -# subdomain -# txtvalue -# system_ns -_build_zone_update_xml() { - printf " - - %s - - 0202001 - - - %s - 600 - TXT - %s - - - - %s - %s - - - " "$(_build_request_auth_xml)" "$2" "$3" "$1" "$4" -} - -# Arguments: -# zone -_autodns_zone_inquire() { - request_data="$(_build_zone_inquire_xml "$1")" - autodns_response="$(_autodns_api_call "$request_data")" - ret="$?" - - printf "%s" "$autodns_response" - return "$ret" -} - -# Arguments: -# zone -# subdomain -# txtvalue -# system_ns -_autodns_zone_update() { - request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" - autodns_response="$(_autodns_api_call "$request_data")" - ret="$?" - - printf "%s" "$autodns_response" - return "$ret" -} - -# Arguments: -# zone -# subdomain -# txtvalue -# system_ns -_autodns_zone_cleanup() { - request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" - # replace 'rr_add>' with 'rr_rem>' in request_data - request_data="$(printf -- "%s" "$request_data" | sed 's/rr_add>/rr_rem>/g')" - autodns_response="$(_autodns_api_call "$request_data")" - ret="$?" - - printf "%s" "$autodns_response" - return "$ret" -} - -# Arguments: -# request_data -_autodns_api_call() { - request_data="$1" - - _debug request_data "$request_data" - - autodns_response="$(_post "$request_data" "$SCHLUNDTECH_API")" - ret="$?" - - _debug autodns_response "$autodns_response" - - if [ "$ret" -ne "0" ]; then - _err "error" - return 1 - fi - - if _contains "$autodns_response" "success" >/dev/null; then - _info "success" - printf "%s" "$autodns_response" - return 0 - fi - - return 1 -} From 37ef0a0cb62cc70c0b4ef6158d21946576e56fac Mon Sep 17 00:00:00 2001 From: andrewheberle Date: Tue, 30 Apr 2019 15:32:36 +0800 Subject: [PATCH 360/565] Fix README.md confict --- deploy/README.md | 294 +---------------------------------------------- 1 file changed, 2 insertions(+), 292 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 8cefeff..fc633ad 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1,296 +1,6 @@ # Using deploy api -Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). +deploy hook usage: -Here are the scripts to deploy the certs/key to the server/services. +https://github.com/Neilpang/acme.sh/wiki/deployhooks -## 1. Deploy the certs to your cpanel host - -If you want to deploy using cpanel UAPI see 7. - -(cpanel deploy hook is not finished yet, this is just an example.) - - - -Then you can deploy now: - -```sh -export DEPLOY_CPANEL_USER=myusername -export DEPLOY_CPANEL_PASSWORD=PASSWORD -acme.sh --deploy -d example.com --deploy-hook cpanel -``` - -## 2. Deploy ssl cert on kong proxy engine based on api - -Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). -Currently supports Kong-v0.10.x. - -```sh -acme.sh --deploy -d ftp.example.com --deploy-hook kong -``` - -## 3. Deploy the cert to remote server through SSH access - -The ssh deploy plugin allows you to deploy certificates to a remote host -using SSH command to connect to the remote server. The ssh plugin is invoked -with the following command... - -```sh -acme.sh --deploy -d example.com --deploy-hook ssh -``` -Prior to running this for the first time you must tell the plugin where -and how to deploy the certificates. This is done by exporting the following -environment variables. This is not required for subsequent runs as the -values are stored by acme.sh in the domain configuration files. - -Required... -``` -export DEPLOY_SSH_USER=username -``` -Optional... -``` -export DEPLOY_SSH_CMD=custom ssh command -export DEPLOY_SSH_SERVER=url or ip address of remote host -export DEPLOY_SSH_KEYFILE=filename for private key -export DEPLOY_SSH_CERTFILE=filename for certificate file -export DEPLOY_SSH_CAFILE=filename for intermediate CA file -export DEPLOY_SSH_FULLCHAIN=filename for fullchain file -export DEPLOY_SSH_REMOTE_CMD=command to execute on remote host -export DEPLOY_SSH_BACKUP=yes or no -``` - -**DEPLOY_SSH_USER** -Username at the remote host that SSH will login with. Note that -SSH must be able to login to remote host without a password... SSH Keys -must have been exchanged with the remote host. Validate and test that you -can login to USER@URL from the host running acme.sh before using this script. - -The USER@URL at the remote server must also have has permissions to write to -the target location of the certificate files and to execute any commands -(e.g. to stop/start services). - -**DEPLOY_SSH_CMD** -You can customize the ssh command used to connect to the remote host. For example -if you need to connect to a specific port at the remote server you can set this -to, for example, "ssh -p 22" or to use `sshpass` to provide password inline -instead of exchanging ssh keys (this is not recommended, using keys is -more secure). - -**DEPLOY_SSH_SERVER** -URL or IP Address of the remote server. If not provided then the domain -name provided on the acme.sh --deploy command line is used. - -**DEPLOY_SSH_KEYFILE** -Target filename for the private key issued by LetsEncrypt. - -**DEPLOY_SSH_CERTFILE** -Target filename for the certificate issued by LetsEncrypt. -If this is the same as the previous filename (for keyfile) then it is -appended to the same file. - -**DEPLOY_SSH_CAFILE** -Target filename for the CA intermediate certificate issued by LetsEncrypt. -If this is the same as a previous filename (for keyfile or certfile) then -it is appended to the same file. - -**DEPLOY_SSH_FULLCHAIN** -Target filename for the fullchain certificate issued by LetsEncrypt. -If this is the same as a previous filename (for keyfile, certfile or -cafile) then it is appended to the same file. - -**DEPLOY_SSH_REMOTE_CMD** -Command to execute on the remote server after copying any certificates. This -could be any additional command required for example to stop and restart -the service. - -**DEPLOY_SSH_BACKUP** -Before writing a certificate file to the remote server the existing -certificate will be copied to a backup directory on the remote server. -These are placed in a hidden directory in the home directory of the SSH -user -```sh -~/.acme_ssh_deploy/[domain name]-backup-[timestamp] -``` -Any backups older than 180 days will be deleted when new certificates -are deployed. This defaults to "yes" set to "no" to disable backup. - -###Examples using SSH deploy -The following example illustrates deploying certificates to a QNAP NAS -(tested with QTS version 4.2.3) - -```sh -export DEPLOY_SSH_USER="admin" -export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" -export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" -export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" -export DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" - -acme.sh --deploy -d qnap.example.com --deploy-hook ssh -``` -Note how in this example both the private key and certificate point to -the same file. This will result in the certificate being appended -to the same file as the private key... a common requirement of several -services. - -The next example illustrates deploying certificates to a Unifi -Controller (tested with version 5.4.11). - -```sh -export DEPLOY_SSH_USER="root" -export DEPLOY_SSH_KEYFILE="/var/lib/unifi/unifi.example.com.key" -export DEPLOY_SSH_FULLCHAIN="/var/lib/unifi/unifi.example.com.cer" -export DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ - -inkey /var/lib/unifi/unifi.example.com.key \ - -in /var/lib/unifi/unifi.example.com.cer \ - -out /var/lib/unifi/unifi.example.com.p12 \ - -name ubnt -password pass:temppass \ - && keytool -importkeystore -deststorepass aircontrolenterprise \ - -destkeypass aircontrolenterprise \ - -destkeystore /var/lib/unifi/keystore \ - -srckeystore /var/lib/unifi/unifi.example.com.p12 \ - -srcstoretype PKCS12 -srcstorepass temppass -alias ubnt -noprompt \ - && service unifi restart" - -acme.sh --deploy -d unifi.example.com --deploy-hook ssh -``` -In this example we execute several commands on the remote host -after the certificate files have been copied... to generate a pkcs12 file -compatible with Unifi, to import it into the Unifi keystore and then finally -to restart the service. - -Note also that once the certificate is imported -into the keystore the individual certificate files are no longer -required. We could if we desired delete those files immediately. If we -do that then we should disable backup at the remote host (as there are -no files to backup -- they were erased during deployment). For example... -```sh -export DEPLOY_SSH_BACKUP=no -# modify the end of the remote command... -&& rm /var/lib/unifi/unifi.example.com.key \ - /var/lib/unifi/unifi.example.com.cer \ - /var/lib/unifi/unifi.example.com.p12 \ -&& service unifi restart -``` - -## 4. Deploy the cert to local vsftpd server - -```sh -acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd -``` - -The default vsftpd conf file is `/etc/vsftpd.conf`, if your vsftpd conf is not in the default location, you can specify one: - -```sh -export DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf" - -acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd -``` - -The default command to restart vsftpd server is `service vsftpd restart`, if it doesn't work, you can specify one: - -```sh -export DEPLOY_VSFTPD_RELOAD="/etc/init.d/vsftpd restart" - -acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd -``` - -## 5. Deploy the cert to local exim4 server - -```sh -acme.sh --deploy -d ftp.example.com --deploy-hook exim4 -``` - -The default exim4 conf file is `/etc/exim/exim.conf`, if your exim4 conf is not in the default location, you can specify one: - -```sh -export DEPLOY_EXIM4_CONF="/etc/exim4/exim4.conf.template" - -acme.sh --deploy -d ftp.example.com --deploy-hook exim4 -``` - -The default command to restart exim4 server is `service exim4 restart`, if it doesn't work, you can specify one: - -```sh -export DEPLOY_EXIM4_RELOAD="/etc/init.d/exim4 restart" - -acme.sh --deploy -d ftp.example.com --deploy-hook exim4 -``` - -## 6. Deploy the cert to OSX Keychain - -```sh -acme.sh --deploy -d ftp.example.com --deploy-hook keychain -``` - -## 7. Deploy to cpanel host using UAPI - -This hook is using UAPI and works in cPanel & WHM version 56 or newer. -``` -acme.sh --deploy -d example.com --deploy-hook cpanel_uapi -``` -DEPLOY_CPANEL_USER is required only if you run the script as root and it should contain cpanel username. -```sh -export DEPLOY_CPANEL_USER=username -acme.sh --deploy -d example.com --deploy-hook cpanel_uapi -``` -Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separate certificate for each domain. - -## 8. Deploy the cert to your FRITZ!Box router - -You must specify the credentials that have administrative privileges on the FRITZ!Box in order to deploy the certificate, plus the URL of your FRITZ!Box, through the following environment variables: -```sh -$ export DEPLOY_FRITZBOX_USERNAME=my_username -$ export DEPLOY_FRITZBOX_PASSWORD=the_password -$ export DEPLOY_FRITZBOX_URL=https://fritzbox.example.com -``` - -After the first deployment, these values will be stored in your $HOME/.acme.sh/account.conf. You may now deploy the certificate like this: - -```sh -acme.sh --deploy -d fritzbox.example.com --deploy-hook fritzbox -``` - -## 9. Deploy the cert to strongswan - -```sh -acme.sh --deploy -d ftp.example.com --deploy-hook strongswan -``` - -## 10. Deploy the cert to HAProxy - -You may specify the directory where you want the concatenated key and certificate chain written. The value shown below will be used as the default if you don't set this environment variable. - -```sh -export DEPLOY_HAPROXY_PEM_PATH=/etc/haproxy -``` - -You may optionally specify the file name where you want the concatenated key and certificate chain written. The value shown below will be used as the default if you don't set this environment variable. - -```sh -export DEPLOY_HAPROXY_PEM_NAME=$domain -``` - -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="true" -``` - -You may optionally specify that the issuer certificate is transferred to "${DEPLOY_HAPROXY_PEM}.issuer". This is a requirement to support OCSP stapling in HAProxy. The value shown below will be used as the default if you don't set this environment variable. - -```sh -export DEPLOY_HAPROXY_ISSUER="no" -``` - -You may optionally specify that you wish to support HAProxy's multi-cert bundle functionality. This allows serving of both RSA and ECC certificates on the same proxy. This adds a ".rsa" or ".ecc" suffix to the files generated (.pem, .ocsp and .issuer). The value shown below will be used as the default if you don't set this environment variable. - -```sh -export DEPLOY_HAPROXY_BUNDLE="no" -``` - -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 388ff75260ea86e6f24f4326b5a0ba5e8e003d93 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 30 Apr 2019 20:43:10 +0800 Subject: [PATCH 361/565] --- Auto-Git Commit --- --- .gitignore | 1 + test.sh | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 .gitignore create mode 100644 test.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..427ec6b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.autogit \ No newline at end of file diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..d976bfe --- /dev/null +++ b/test.sh @@ -0,0 +1,8 @@ + + +_data='aaaaa +bbb"bb +ccccc +ddddd +' + From 522b7c51f74298a11beea2e20a9f8e69b31c76fe Mon Sep 17 00:00:00 2001 From: Jakub Filo Date: Wed, 1 May 2019 01:53:51 +0200 Subject: [PATCH 362/565] Adding NLnetLabs NSD API --- dnsapi/dns_nsd.sh | 67 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 dnsapi/dns_nsd.sh diff --git a/dnsapi/dns_nsd.sh b/dnsapi/dns_nsd.sh new file mode 100644 index 0000000..2c5b64c --- /dev/null +++ b/dnsapi/dns_nsd.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env sh + +#Nsd_ZoneFile="/etc/nsd/zones/example.com.zone" +#Nsd_Command="sudo nsd-control reload" + +# args: fulldomain txtvalue +dns_nsd_add() +{ + fulldomain=$1 + txtvalue=$2 + ttlvalue=300 + + Nsd_ZoneFile="${Nsd_ZoneFile:-$(_readdomainconf Nsd_ZoneFile)}" + Nsd_Command="${Nsd_Command:-$(_readdomainconf Nsd_Command)}" + + # Arg checks + if [ -z "$Nsd_ZoneFile" ] || [ -z "$Nsd_Command" ]; then + Nsd_ZoneFile="" + Nsd_Command="" + _err "Specify ENV vars Nsd_ZoneFile and Nsd_Command" + return 1 + fi + + if [ ! -f "$Nsd_ZoneFile" ]; then + Nsd_ZoneFile="" + Nsd_Command="" + _err "No such file: $Nsd_ZoneFile" + return 1 + fi + + _savedomainconf Nsd_ZoneFile "$Nsd_ZoneFile" + _savedomainconf Nsd_Command "$Nsd_Command" + + echo "$fulldomain. $ttlvalue IN TXT \"$txtvalue\"" >> "$Nsd_ZoneFile" + _info "Added TXT record for $fulldomain" + _debug "Running $Nsd_Command" + if eval "$Nsd_Command"; then + _info "Successfully updated the zone" + return 0 + else + _err "Problem updating the zone" + return 1 + fi +} + +# args: fulldomain txtvalue +dns_nsd_rm() +{ + fulldomain=$1 + txtvalue=$2 + ttlvalue=300 + + Nsd_ZoneFile="${Nsd_ZoneFile:-$(_readdomainconf Nsd_ZoneFile)}" + Nsd_Command="${Nsd_Command:-$(_readdomainconf Nsd_Command)}" + + sed -i "/$fulldomain. $ttlvalue IN TXT \"$txtvalue\"/d" "$Nsd_ZoneFile" + _info "Removed TXT record for $fulldomain" + _debug "Running $Nsd_Command" + if eval "$Nsd_Command"; then + _info "Successfully reloaded NSD " + return 0 + else + _err "Problem reloading NSD" + return 1 + fi +} + From 63407041738634e16b761542bc1de163cfa8b7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=B8=D0=BC=D1=83=D1=80=20=D0=AF=D1=85=D0=B8=D0=BD?= Date: Wed, 1 May 2019 10:11:39 +0300 Subject: [PATCH 363/565] fixed line breaks for support api gcore_cdn (#2237) --- deploy/gcore_cdn.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index 56ca9af..e0921bc 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -27,8 +27,8 @@ gcore_cdn_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _fullchain=$(tr '\n\r' '@#' <"$_cfullchain" | sed 's/@/\\n/g;s/#/\\r/g') - _key=$(tr '\n\r' '@#' <"$_ckey" | sed 's/@/\\n/g;s/#/\\r/g') + _fullchain=$(tr '\r\n' '*#' <"$_cfullchain" | sed 's/*#/#/g;s/##/#/g;s/#/\\n/g') + _key=$(tr '\r\n' '*#' <"$_ckey" | sed 's/*#/#/g;s/#/\\n/g') _debug _fullchain "$_fullchain" _debug _key "$_key" From 040ca5320d4a409b9c5787940f47796443158cbe Mon Sep 17 00:00:00 2001 From: Jakub Filo Date: Wed, 1 May 2019 12:17:54 +0200 Subject: [PATCH 364/565] Fixed style to match upstream --- dnsapi/dns_nsd.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_nsd.sh b/dnsapi/dns_nsd.sh index 2c5b64c..a741670 100644 --- a/dnsapi/dns_nsd.sh +++ b/dnsapi/dns_nsd.sh @@ -4,8 +4,7 @@ #Nsd_Command="sudo nsd-control reload" # args: fulldomain txtvalue -dns_nsd_add() -{ +dns_nsd_add() { fulldomain=$1 txtvalue=$2 ttlvalue=300 @@ -31,7 +30,7 @@ dns_nsd_add() _savedomainconf Nsd_ZoneFile "$Nsd_ZoneFile" _savedomainconf Nsd_Command "$Nsd_Command" - echo "$fulldomain. $ttlvalue IN TXT \"$txtvalue\"" >> "$Nsd_ZoneFile" + echo "$fulldomain. $ttlvalue IN TXT \"$txtvalue\"" >>"$Nsd_ZoneFile" _info "Added TXT record for $fulldomain" _debug "Running $Nsd_Command" if eval "$Nsd_Command"; then @@ -44,8 +43,7 @@ dns_nsd_add() } # args: fulldomain txtvalue -dns_nsd_rm() -{ +dns_nsd_rm() { fulldomain=$1 txtvalue=$2 ttlvalue=300 From d1ef039e39fe246c0b7ec26eb656b6ee62f81648 Mon Sep 17 00:00:00 2001 From: Jakub Filo Date: Wed, 1 May 2019 12:25:46 +0200 Subject: [PATCH 365/565] Removed trailing line --- dnsapi/dns_nsd.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_nsd.sh b/dnsapi/dns_nsd.sh index a741670..83cc4ca 100644 --- a/dnsapi/dns_nsd.sh +++ b/dnsapi/dns_nsd.sh @@ -62,4 +62,3 @@ dns_nsd_rm() { return 1 fi } - From 096ce1a20749ddd9e7738f5fd2a614c0d89002da Mon Sep 17 00:00:00 2001 From: mod242 <40213799+mod242@users.noreply.github.com> Date: Thu, 2 May 2019 12:18:16 +0200 Subject: [PATCH 366/565] Create DNS API for Schlundtech --- dnsapi/dns_schlundtech.sh | 261 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 dnsapi/dns_schlundtech.sh diff --git a/dnsapi/dns_schlundtech.sh b/dnsapi/dns_schlundtech.sh new file mode 100644 index 0000000..399c50e --- /dev/null +++ b/dnsapi/dns_schlundtech.sh @@ -0,0 +1,261 @@ +#!/usr/bin/env sh +# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*- + +# Schlundtech DNS API +# Author: mod242 +# Created: 2019-40-29 +# Completly based on the autoDNS xml api wrapper by auerswald@gmail.com +# +# export SCHLUNDTECH_USER="username" +# export SCHLUNDTECH_PASSWORD="password" +# +# Usage: +# acme.sh --issue --dns dns_schlundtech -d example.com + +SCHLUNDTECH_API="https://gateway.schlundtech.de" + +# Arguments: +# txtdomain +# txt +dns_schlundtech_add() { + fulldomain="$1" + txtvalue="$2" + + SCHLUNDTECH_USER="${SCHLUNDTECH_USER:-$(_readaccountconf_mutable SCHLUNDTECH_USER)}" + SCHLUNDTECH_PASSWORD="${SCHLUNDTECH_PASSWORD:-$(_readaccountconf_mutable SCHLUNDTECH_PASSWORD)}" + + if [ -z "$SCHLUNDTECH_USER" ] || [ -z "$SCHLUNDTECH_PASSWORD" ]; then + _err "You didn't specify schlundtech user and password." + return 1 + fi + + _saveaccountconf_mutable SCHLUNDTECH_USER "$SCHLUNDTECH_USER" + _saveaccountconf_mutable SCHLUNDTECH_PASSWORD "$SCHLUNDTECH_PASSWORD" + + _debug "First detect the root zone" + + if ! _get_autodns_zone "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _zone "$_zone" + _debug _system_ns "$_system_ns" + + _info "Adding TXT record" + + autodns_response="$(_autodns_zone_update "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" + + if [ "$?" -eq "0" ]; then + _info "Added, OK" + return 0 + fi + + return 1 +} + +# Arguments: +# txtdomain +# txt +dns_schlundtech_rm() { + fulldomain="$1" + txtvalue="$2" + + SCHLUNDTECH_USER="${SCHLUNDTECH_USER:-$(_readaccountconf_mutable SCHLUNDTECH_USER)}" + SCHLUNDTECH_PASSWORD="${SCHLUNDTECH_PASSWORD:-$(_readaccountconf_mutable SCHLUNDTECH_PASSWORD)}" + + if [ -z "$SCHLUNDTECH_USER" ] || [ -z "$SCHLUNDTECH_PASSWORD" ]; then + _err "You didn't specify schlundtech user and password." + return 1 + fi + + _debug "First detect the root zone" + + if ! _get_autodns_zone "$fulldomain"; then + _err "zone not found" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _zone "$_zone" + _debug _system_ns "$_system_ns" + + _info "Delete TXT record" + + autodns_response="$(_autodns_zone_cleanup "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" + + if [ "$?" -eq "0" ]; then + _info "Deleted, OK" + return 0 + fi + + return 1 +} + +#################### Private functions below ################################## + +# Arguments: +# fulldomain +# Returns: +# _sub_domain=_acme-challenge.www +# _zone=domain.com +# _system_ns +_get_autodns_zone() { + domain="$1" + + i=2 + p=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + + if [ -z "$h" ]; then + # not valid + return 1 + fi + + autodns_response="$(_autodns_zone_inquire "$h")" + + if [ "$?" -ne "0" ]; then + _err "invalid domain" + return 1 + fi + + if _contains "$autodns_response" "1" >/dev/null; then + _zone="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _system_ns="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +_build_request_auth_xml() { + printf " + %s + %s + 10 + " "$SCHLUNDTECH_USER" "$SCHLUNDTECH_PASSWORD" +} + +# Arguments: +# zone +_build_zone_inquire_xml() { + printf " + + %s + + 0205 + + 1 + 1 + + + name + eq + %s + + + " "$(_build_request_auth_xml)" "$1" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_build_zone_update_xml() { + printf " + + %s + + 0202001 + + + %s + 600 + TXT + %s + + + + %s + %s + + + " "$(_build_request_auth_xml)" "$2" "$3" "$1" "$4" +} + +# Arguments: +# zone +_autodns_zone_inquire() { + request_data="$(_build_zone_inquire_xml "$1")" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_autodns_zone_update() { + request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_autodns_zone_cleanup() { + request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" + # replace 'rr_add>' with 'rr_rem>' in request_data + request_data="$(printf -- "%s" "$request_data" | sed 's/rr_add>/rr_rem>/g')" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# request_data +_autodns_api_call() { + request_data="$1" + + _debug request_data "$request_data" + + autodns_response="$(_post "$request_data" "$SCHLUNDTECH_API")" + ret="$?" + + _debug autodns_response "$autodns_response" + + if [ "$ret" -ne "0" ]; then + _err "error" + return 1 + fi + + if _contains "$autodns_response" "success" >/dev/null; then + _info "success" + printf "%s" "$autodns_response" + return 0 + fi + + return 1 +} From dac75a1dda7681df3e9cfae93675d93ceca7f574 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 3 May 2019 20:50:42 +0800 Subject: [PATCH 367/565] rename --- dnsapi/dns_one.sh | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh index c99c9c9..94ac49c 100644 --- a/dnsapi/dns_one.sh +++ b/dnsapi/dns_one.sh @@ -5,8 +5,8 @@ # Author: github: @diseq # Created: 2019-02-17 # -# export ONECOM_USER="username" -# export ONECOM_PASSWORD="password" +# export ONECOM_User="username" +# export ONECOM_Password="password" # # Usage: # acme.sh --issue --dns dns_one -d example.com @@ -19,26 +19,26 @@ dns_one_add() { txtvalue=$2 # get credentials - ONECOM_USER="${ONECOM_USER:-$(_readaccountconf_mutable ONECOM_USER)}" - ONECOM_PASSWORD="${ONECOM_PASSWORD:-$(_readaccountconf_mutable ONECOM_PASSWORD)}" - if [ -z "$ONECOM_USER" ] || [ -z "$ONECOM_PASSWORD" ]; then - ONECOM_USER="" - ONECOM_PASSWORD="" + ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}" + ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}" + if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then + ONECOM_User="" + ONECOM_Password="" _err "You didn't specify a one.com username and password yet." _err "Please create the key and try again." return 1 fi #save the api key and email to the account conf file. - _saveaccountconf_mutable ONECOM_USER "$ONECOM_USER" - _saveaccountconf_mutable ONECOM_PASSWORD "$ONECOM_PASSWORD" + _saveaccountconf_mutable ONECOM_User "$ONECOM_User" + _saveaccountconf_mutable ONECOM_Password "$ONECOM_Password" # Login with user and password postdata="loginDomain=true" - postdata="$postdata&displayUsername=$ONECOM_USER" - postdata="$postdata&username=$ONECOM_USER" + postdata="$postdata&displayUsername=$ONECOM_User" + postdata="$postdata&username=$ONECOM_User" postdata="$postdata&targetDomain=$mydomain" - postdata="$postdata&password1=$ONECOM_PASSWORD" + postdata="$postdata&password1=$ONECOM_Password" postdata="$postdata&loginTarget=" #_debug postdata "$postdata" @@ -64,7 +64,7 @@ dns_one_add() { response="$(echo "$response" | _normalizeJson)" _debug response "$response" - id=$(printf -- "%s" "$response" | sed -n "s/{\"result\":{\"data\":{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$mysubdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}}},\"metadata\":null}/\1/p") + id=$(echo "$response" | sed -n "s/{\"result\":{\"data\":{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$mysubdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}}},\"metadata\":null}/\1/p") if [ -z "$id" ]; then _err "Add txt record error." @@ -82,11 +82,11 @@ dns_one_rm() { txtvalue=$2 # get credentials - ONECOM_USER="${ONECOM_USER:-$(_readaccountconf_mutable ONECOM_USER)}" - ONECOM_PASSWORD="${ONECOM_PASSWORD:-$(_readaccountconf_mutable ONECOM_PASSWORD)}" - if [ -z "$ONECOM_USER" ] || [ -z "$ONECOM_PASSWORD" ]; then - ONECOM_USER="" - ONECOM_PASSWORD="" + ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}" + ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}" + if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then + ONECOM_User="" + ONECOM_Password="" _err "You didn't specify a one.com username and password yet." _err "Please create the key and try again." return 1 @@ -94,10 +94,10 @@ dns_one_rm() { # Login with user and password postdata="loginDomain=true" - postdata="$postdata&displayUsername=$ONECOM_USER" - postdata="$postdata&username=$ONECOM_USER" + postdata="$postdata&displayUsername=$ONECOM_User" + postdata="$postdata&username=$ONECOM_User" postdata="$postdata&targetDomain=$mydomain" - postdata="$postdata&password1=$ONECOM_PASSWORD" + postdata="$postdata&password1=$ONECOM_Password" postdata="$postdata&loginTarget=" response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST" "application/x-www-form-urlencoded")" From 621d4745b4a65ea63658ad82c93aa0e185e80b07 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 4 May 2019 10:18:42 +0800 Subject: [PATCH 368/565] fix idn --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index dc110a0..727e35e 100755 --- a/acme.sh +++ b/acme.sh @@ -3856,7 +3856,7 @@ issue() { if [ -z "$d" ]; then break fi - _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$d\"}" + _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$$(_idn $d)\"}" done _debug2 _identifiers "$_identifiers" if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then From 6198e43fe69ca87c2f0eed639d2b8f098d11f039 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 4 May 2019 10:21:15 +0800 Subject: [PATCH 369/565] fix idn --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 727e35e..e84619f 100755 --- a/acme.sh +++ b/acme.sh @@ -3856,7 +3856,7 @@ issue() { if [ -z "$d" ]; then break fi - _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$$(_idn $d)\"}" + _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$(_idn $d)\"}" done _debug2 _identifiers "$_identifiers" if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then From a77f2fa4246ef4de4859924dbe563a67516608df Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 4 May 2019 10:32:01 +0800 Subject: [PATCH 370/565] remove test file --- test.sh | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 test.sh diff --git a/test.sh b/test.sh deleted file mode 100644 index d976bfe..0000000 --- a/test.sh +++ /dev/null @@ -1,8 +0,0 @@ - - -_data='aaaaa -bbb"bb -ccccc -ddddd -' - From 0f866510895e1130fcdc22cffcd5464e9e966841 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 4 May 2019 10:43:39 +0800 Subject: [PATCH 371/565] fix idn --- .gitignore | 1 - acme.sh | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 427ec6b..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.autogit \ No newline at end of file diff --git a/acme.sh b/acme.sh index e84619f..0397e5d 100755 --- a/acme.sh +++ b/acme.sh @@ -1119,9 +1119,9 @@ _createcsr() { domainlist="$(_idn "$domainlist")" _debug2 domainlist "$domainlist" if _contains "$domainlist" ","; then - alt="DNS:$domain,DNS:$(echo "$domainlist" | sed "s/,,/,/g" | sed "s/,/,DNS:/g")" + alt="DNS:$(_idn $domain),DNS:$(echo "$domainlist" | sed "s/,,/,/g" | sed "s/,/,DNS:/g")" else - alt="DNS:$domain,DNS:$domainlist" + alt="DNS:$(_idn $domain),DNS:$domainlist" fi #multi _info "Multi domain" "$alt" From acae0ac2a647c7b3c59b8e7bb4d41bfd40b89b73 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 4 May 2019 10:59:00 +0800 Subject: [PATCH 372/565] fix RENEW_SKIP code --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 0397e5d..19af5b0 100755 --- a/acme.sh +++ b/acme.sh @@ -4622,7 +4622,7 @@ renew() { _info "$(__green "Renew: '$Le_Domain'")" if [ ! -f "$DOMAIN_CONF" ]; then _info "'$Le_Domain' is not a issued domain, skip." - return 0 + return $RENEW_SKIP fi if [ "$Le_RenewalDays" ]; then @@ -4676,7 +4676,7 @@ renew() { if [ "$IN_CRON" = "1" ] && [ -z "$Le_CertCreateTime" ]; then _info "Skip invalid cert for: $Le_Domain" - return 0 + return $RENEW_SKIP fi IS_RENEW="1" From 83768f0531432a3d0de05264240485871f2b8703 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 4 May 2019 11:02:10 +0800 Subject: [PATCH 373/565] reduce info message --- notify/mailgun.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notify/mailgun.sh b/notify/mailgun.sh index 1689a0b..7f5c914 100644 --- a/notify/mailgun.sh +++ b/notify/mailgun.sh @@ -30,7 +30,7 @@ mailgun_send() { MAILGUN_REGION="${MAILGUN_REGION:-$(_readaccountconf_mutable MAILGUN_REGION)}" if [ -z "$MAILGUN_REGION" ]; then MAILGUN_REGION="" - _info "The MAILGUN_REGION is not set, so use the default us region." + _debug "The MAILGUN_REGION is not set, so use the default us region." _MAILGUN_BASE="https://api.mailgun.net/v3" else _saveaccountconf_mutable MAILGUN_REGION "$MAILGUN_REGION" @@ -83,7 +83,7 @@ mailgun_send() { _debug "_msg" "$_msg" _mailgun_rest POST "$_msg" if _contains "$response" "Queued. Thank you."; then - _info "mailgun send success." + _debug "mailgun send success." return 0 else _err "mailgun send error" From 5d468f7ca5cbf82982bc4d07e4a5762157e2c2c6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 4 May 2019 11:06:25 +0800 Subject: [PATCH 374/565] add notifications --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8d40d51..ab3412c 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ - DOES NOT require `root/sudoer` access. - Docker friendly - IPv6 support +- Cron job notifications for renewal or error etc. It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. @@ -432,20 +433,25 @@ acme.sh --upgrade --auto-upgrade 0 https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR -# 16. Under the Hood +# 16. Send notifications in cronjob + +https://github.com/Neilpang/acme.sh/wiki/notify + + +# 17. Under the Hood Speak ACME language using shell, directly to "Let's Encrypt". TODO: -# 17. Acknowledgments +# 18. Acknowledgments 1. Acme-tiny: https://github.com/diafygi/acme-tiny 2. ACME protocol: https://github.com/ietf-wg-acme/acme -# 18. License & Others +# 19. License & Others License is GPLv3 @@ -454,7 +460,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. -# 19. Donate +# 20. Donate Your donation makes **acme.sh** better: 1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/) From 2b765fdedb84532052918a5524da5090604dbe18 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 4 May 2019 11:54:59 +0800 Subject: [PATCH 375/565] add set-notify --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 68385d7..0e8b58d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,6 +48,7 @@ RUN for verb in help \ createCSR \ deactivate \ deactivate-account \ + set-notify \ ; do \ printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \ ; done From b8f4fa359cea941397b6aa867efb57e082025eed Mon Sep 17 00:00:00 2001 From: Maarten den Braber Date: Mon, 6 May 2019 17:12:50 +0200 Subject: [PATCH 376/565] Add acmeproxy provider --- dnsapi/dns_acmeproxy.sh | 85 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 dnsapi/dns_acmeproxy.sh diff --git a/dnsapi/dns_acmeproxy.sh b/dnsapi/dns_acmeproxy.sh new file mode 100644 index 0000000..762f865 --- /dev/null +++ b/dnsapi/dns_acmeproxy.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env sh + +## API integration by Jason Keller and Elijah Tenai +## +## Report any bugs via https://github.com/jasonkeller/acme.sh + +dns_acmeproxy_add() { + fulldomain="${1}" + txtvalue="${2}" + action="present" + + _debug "Calling: _acmeproxy_request() '${fulldomain}' '${txtvalue}' '${action}'" + _acmeproxy_request $fulldomain $txtvalue $action +} + +dns_acmeproxy_rm() { + fulldomain="${1}" + txtvalue="${2}" + action="cleanup" + + _debug "Calling: _acmeproxy_request() '${fulldomain}' '${txtvalue}' '${action}'" + _acmeproxy_request $fulldomain $txtvalue $action +} + +_acmeproxy_request() { + + ## Nothing to see here, just some housekeeping + fulldomain=$1 + txtvalue=$2 + action=$3 + + _info "Using acmeproxy" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ACMEPROXY_ENDPOINT="${ACMEPROXY_ENDPOINT:-$(_readaccountconf_mutable ACMEPROXY_ENDPOINT)}" + ACMEPROXY_USERNAME="${ACMEPROXY_USERNAME:-$(_readaccountconf_mutable ACMEPROXY_USERNAME)}" + ACMEPROXY_PASSWORD="${ACMEPROXY_PASSWORD:-$(_readaccountconf_mutable ACMEPROXY_PASSWORD)}" + + ## Check for the endpoint + if [ -z "ACMEPROXY_ENDPOINT" ]; then + ACMEPROXY_ENDPOINT="" + _err "You didn't specify the endpoint" + _err "Please set them via 'export ACMEPROXY_ENDPOINT=https://ip:port' and try again." + return 1 + fi + + ## Check for the credentials + if [ -z "$ACMEPROXY_USERNAME" ] || [ -z "$ACMEPROXY_PASSWORD" ]; then + ACMEPROXY_USERNAME="" + ACMEPROXY_PASSWORD="" + _err "You didn't set username and password" + _err "Please set them via 'export ACMEPROXY_USERNAME=...' and 'export ACMEPROXY_PASSWORD=...' and try again." + return 1 + fi + + ## Save the credentials to the account file + _saveaccountconf_mutable ACMEPROXY_ENDPOINT "$ACMEPROXY_ENDPOINT" + _saveaccountconf_mutable ACMEPROXY_USERNAME "$ACMEPROXY_USERNAME" + _saveaccountconf_mutable ACMEPROXY_PASSWORD "$ACMEPROXY_PASSWORD" + + ## Base64 encode the credentials + credentials=$(printf "%b" "$ACMEPROXY_USERNAME:$ACMEPROXY_PASSWORD" | _base64) + + ## Construct the HTTP Authorization header + export _H1="Authorization: Basic $credentials" + export _H2="Accept: application/json" + export _H3="Content-Type: application/json" + + ## Add the challenge record to the acmeproxy grid member + response="$(_post "{\"fqdn\": \"$fulldomain.\", \"value\": \"$txtvalue\"}" "$ACMEPROXY_ENDPOINT/$action" "" "POST")" + + ## Let's see if we get something intelligible back from the unit + if echo "$response" | grep "\"$txtvalue\"" > /dev/null; then + _info "Successfully created the txt record" + return 0 + else + _err "Error encountered during record addition" + _err "$response" + return 1 + fi + +} + +#################### Private functions below ################################## From 68142c9835d77e9b564056460ff1116b1636395f Mon Sep 17 00:00:00 2001 From: Maarten den Braber Date: Mon, 6 May 2019 17:14:31 +0200 Subject: [PATCH 377/565] Update description --- dnsapi/dns_acmeproxy.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_acmeproxy.sh b/dnsapi/dns_acmeproxy.sh index 762f865..36bfc00 100644 --- a/dnsapi/dns_acmeproxy.sh +++ b/dnsapi/dns_acmeproxy.sh @@ -1,8 +1,9 @@ #!/usr/bin/env sh -## API integration by Jason Keller and Elijah Tenai +## Acmeproxy DNS provider to be used with acmeproxy (http://github.com/mdbraber/acmeproxy) +## API integration by Maarten den Braber ## -## Report any bugs via https://github.com/jasonkeller/acme.sh +## Report any bugs via https://github.com/mdbraber/acme.sh dns_acmeproxy_add() { fulldomain="${1}" From c297aff99bd1abca6b0b554d7681bc073af45e33 Mon Sep 17 00:00:00 2001 From: Maarten den Braber Date: Mon, 6 May 2019 18:31:58 +0200 Subject: [PATCH 378/565] Improved logging description --- dnsapi/dns_acmeproxy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_acmeproxy.sh b/dnsapi/dns_acmeproxy.sh index 36bfc00..7f17ae6 100644 --- a/dnsapi/dns_acmeproxy.sh +++ b/dnsapi/dns_acmeproxy.sh @@ -73,7 +73,7 @@ _acmeproxy_request() { ## Let's see if we get something intelligible back from the unit if echo "$response" | grep "\"$txtvalue\"" > /dev/null; then - _info "Successfully created the txt record" + _info "Successfully updated the txt record" return 0 else _err "Error encountered during record addition" From 585ef998d0ee5fe752484ddef13b92a3ce7dca88 Mon Sep 17 00:00:00 2001 From: Maarten den Braber Date: Tue, 7 May 2019 16:47:23 +0200 Subject: [PATCH 379/565] Fixed CI errors --- dnsapi/dns_acmeproxy.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_acmeproxy.sh b/dnsapi/dns_acmeproxy.sh index 7f17ae6..656e310 100644 --- a/dnsapi/dns_acmeproxy.sh +++ b/dnsapi/dns_acmeproxy.sh @@ -11,7 +11,7 @@ dns_acmeproxy_add() { action="present" _debug "Calling: _acmeproxy_request() '${fulldomain}' '${txtvalue}' '${action}'" - _acmeproxy_request $fulldomain $txtvalue $action + _acmeproxy_request "$fulldomain" "$txtvalue" "$action" } dns_acmeproxy_rm() { @@ -20,7 +20,7 @@ dns_acmeproxy_rm() { action="cleanup" _debug "Calling: _acmeproxy_request() '${fulldomain}' '${txtvalue}' '${action}'" - _acmeproxy_request $fulldomain $txtvalue $action + _acmeproxy_request "$fulldomain" "$txtvalue" "$action" } _acmeproxy_request() { @@ -39,7 +39,7 @@ _acmeproxy_request() { ACMEPROXY_PASSWORD="${ACMEPROXY_PASSWORD:-$(_readaccountconf_mutable ACMEPROXY_PASSWORD)}" ## Check for the endpoint - if [ -z "ACMEPROXY_ENDPOINT" ]; then + if [ -z "$ACMEPROXY_ENDPOINT" ]; then ACMEPROXY_ENDPOINT="" _err "You didn't specify the endpoint" _err "Please set them via 'export ACMEPROXY_ENDPOINT=https://ip:port' and try again." @@ -72,7 +72,7 @@ _acmeproxy_request() { response="$(_post "{\"fqdn\": \"$fulldomain.\", \"value\": \"$txtvalue\"}" "$ACMEPROXY_ENDPOINT/$action" "" "POST")" ## Let's see if we get something intelligible back from the unit - if echo "$response" | grep "\"$txtvalue\"" > /dev/null; then + if echo "$response" | grep "\"$txtvalue\"" >/dev/null; then _info "Successfully updated the txt record" return 0 else From 11ecbd27be9fd92143c05ed22294d7059284419f Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 8 May 2019 22:07:27 +0800 Subject: [PATCH 380/565] fix punycode domain --- 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 6898eb1..cd93189 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -161,7 +161,7 @@ _get_root() { return 1 fi - if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_count":1'; 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) From 1a126b700feb18f780a826d943e92cdb3165ce37 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 8 May 2019 22:13:33 +0800 Subject: [PATCH 381/565] fix https://github.com/Neilpang/acme.sh/issues/2252 --- deploy/haproxy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 2479aeb..836c518 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -179,7 +179,7 @@ haproxy_deploy() { return ${_ret} fi else - [ -f "${_issuer}" ] _err "Issuer file update not requested but .issuer file exists" + [ -f "${_issuer}" ] && _err "Issuer file update not requested but .issuer file exists" fi # Update .ocsp file if certificate was requested with --ocsp/--ocsp-must-staple option From f9e3a2132f1d957b0190243cc703a472eb20ee7a Mon Sep 17 00:00:00 2001 From: Maarten den Braber Date: Thu, 9 May 2019 21:14:26 +0200 Subject: [PATCH 382/565] Username/password no longer required --- dnsapi/dns_acmeproxy.sh | 9 --------- 1 file changed, 9 deletions(-) diff --git a/dnsapi/dns_acmeproxy.sh b/dnsapi/dns_acmeproxy.sh index 656e310..8ca3eb0 100644 --- a/dnsapi/dns_acmeproxy.sh +++ b/dnsapi/dns_acmeproxy.sh @@ -46,15 +46,6 @@ _acmeproxy_request() { return 1 fi - ## Check for the credentials - if [ -z "$ACMEPROXY_USERNAME" ] || [ -z "$ACMEPROXY_PASSWORD" ]; then - ACMEPROXY_USERNAME="" - ACMEPROXY_PASSWORD="" - _err "You didn't set username and password" - _err "Please set them via 'export ACMEPROXY_USERNAME=...' and 'export ACMEPROXY_PASSWORD=...' and try again." - return 1 - fi - ## Save the credentials to the account file _saveaccountconf_mutable ACMEPROXY_ENDPOINT "$ACMEPROXY_ENDPOINT" _saveaccountconf_mutable ACMEPROXY_USERNAME "$ACMEPROXY_USERNAME" From d9ef8c17792f4dcf4bd40b9dae5890f47e23d087 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sun, 12 May 2019 00:25:36 +0200 Subject: [PATCH 383/565] add sendmail notify --- notify/sendmail.sh | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 notify/sendmail.sh diff --git a/notify/sendmail.sh b/notify/sendmail.sh new file mode 100644 index 0000000..3964e90 --- /dev/null +++ b/notify/sendmail.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env sh + +#Support sendmail + +#SENDMAIL_BIN="sendmail" +#SENDMAIL_FROM="yyyy@gmail.com" +#SENDMAIL_TO="yyyy@gmail.com" + +sendmail_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + SENDMAIL_BIN="${SENDMAIL_BIN:-$(_readaccountconf_mutable SENDMAIL_BIN)}" + if [ -z "$SENDMAIL_BIN" ]; then + SENDMAIL_BIN="sendmail" + _info "The SENDMAIL_BIN is not set, so use the default value: $SENDMAIL_BIN" + fi + if ! _exists "$SENDMAIL_BIN"; then + _err "Please install sendmail first." + return 1 + fi + _saveaccountconf_mutable SENDMAIL_BIN "$SENDMAIL_BIN" + + SENDMAIL_FROM="${SENDMAIL_FROM:-$(_readaccountconf_mutable SENDMAIL_FROM)}" + if [ -z "$SENDMAIL_FROM" ]; then + SENDMAIL_FROM="$USER@$HOSTNAME" + _info "The SENDMAIL_FROM is not set, so use the default value: $SENDMAIL_FROM" + fi + _saveaccountconf_mutable SENDMAIL_FROM "$SENDMAIL_FROM" + + SENDMAIL_TO="${SENDMAIL_TO:-$(_readaccountconf_mutable SENDMAIL_TO)}" + if [ -z "$SENDMAIL_TO" ]; then + SENDMAIL_TO="$(_readaccountconf ACCOUNT_EMAIL)" + _info "The SENDMAIL_TO is not set, so use the account email: $SENDMAIL_TO" + fi + _saveaccountconf_mutable SENDMAIL_TO "$SENDMAIL_TO" + + subject="=?UTF-8?B?$(echo "$_subject" | _base64)?=" + error=$( { echo "From: $SENDMAIL_FROM +To: $SENDMAIL_TO +Subject: $subject +Content-Type: text/plain; charset=utf-8 + +$_content +" | "$SENDMAIL_BIN" -f "$SENDMAIL_FROM" "$SENDMAIL_TO"; } 2>&1 ) + + if [ $? -ne 0 ]; then + _debug "sendmail send error." + _err "$error" + return 1 + fi + + _debug "sendmail send success." + return 0 +} From 773e1d4e059fce80bb92bd43f3c23ab5c764b2d0 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sun, 12 May 2019 00:34:46 +0200 Subject: [PATCH 384/565] use hostname function instead of HOSTNAME env variable --- notify/sendmail.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notify/sendmail.sh b/notify/sendmail.sh index 3964e90..162b539 100644 --- a/notify/sendmail.sh +++ b/notify/sendmail.sh @@ -27,7 +27,7 @@ sendmail_send() { SENDMAIL_FROM="${SENDMAIL_FROM:-$(_readaccountconf_mutable SENDMAIL_FROM)}" if [ -z "$SENDMAIL_FROM" ]; then - SENDMAIL_FROM="$USER@$HOSTNAME" + SENDMAIL_FROM="$USER@$(hostname -f)" _info "The SENDMAIL_FROM is not set, so use the default value: $SENDMAIL_FROM" fi _saveaccountconf_mutable SENDMAIL_FROM "$SENDMAIL_FROM" From 4f0354860885807fe3c29321a4400cce0eb721e5 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sun, 12 May 2019 00:35:47 +0200 Subject: [PATCH 385/565] typos --- notify/sendmail.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notify/sendmail.sh b/notify/sendmail.sh index 162b539..7c253e9 100644 --- a/notify/sendmail.sh +++ b/notify/sendmail.sh @@ -40,13 +40,13 @@ sendmail_send() { _saveaccountconf_mutable SENDMAIL_TO "$SENDMAIL_TO" subject="=?UTF-8?B?$(echo "$_subject" | _base64)?=" - error=$( { echo "From: $SENDMAIL_FROM + error=$({ echo "From: $SENDMAIL_FROM To: $SENDMAIL_TO Subject: $subject Content-Type: text/plain; charset=utf-8 $_content -" | "$SENDMAIL_BIN" -f "$SENDMAIL_FROM" "$SENDMAIL_TO"; } 2>&1 ) +" | "$SENDMAIL_BIN" -f "$SENDMAIL_FROM" "$SENDMAIL_TO"; } 2>&1) if [ $? -ne 0 ]; then _debug "sendmail send error." From a4b83895a37750801c5fbf250bc69386a896146e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 12 May 2019 15:34:58 +0800 Subject: [PATCH 386/565] fix https://github.com/Neilpang/acme.sh/issues/2258 --- notify/mailgun.sh | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/notify/mailgun.sh b/notify/mailgun.sh index 7f5c914..4b6ee3b 100644 --- a/notify/mailgun.sh +++ b/notify/mailgun.sh @@ -9,7 +9,10 @@ #MAILGUN_API_DOMAIN="xxxxxx.com" #optional, use the default sandbox domain #MAILGUN_FROM="xxx@xxxxx.com" #optional, use the default sendbox account -_MAILGUN_BASE="https://api.mailgun.net/v3" +_MAILGUN_BASE_US="https://api.mailgun.net/v3" +_MAILGUN_BASE_EU="https://api.eu.mailgun.net/v3" + +_MAILGUN_BASE="$_MAILGUN_BASE_US" # subject content statusCode mailgun_send() { @@ -31,12 +34,17 @@ mailgun_send() { if [ -z "$MAILGUN_REGION" ]; then MAILGUN_REGION="" _debug "The MAILGUN_REGION is not set, so use the default us region." - _MAILGUN_BASE="https://api.mailgun.net/v3" + _MAILGUN_BASE="$_MAILGUN_BASE_US" else + MAILGUN_REGION="$(echo "$MAILGUN_REGION" | _lower_case)" _saveaccountconf_mutable MAILGUN_REGION "$MAILGUN_REGION" - _MAILGUN_BASE="https://api.eu.mailgun.net/v3" + if [ "$MAILGUN_REGION" = "us" ]; then + _MAILGUN_BASE="$_MAILGUN_BASE_US" + else + _MAILGUN_BASE="$_MAILGUN_BASE_EU" + fi fi - + _debug _MAILGUN_BASE "$_MAILGUN_BASE" MAILGUN_TO="${MAILGUN_TO:-$(_readaccountconf_mutable MAILGUN_TO)}" if [ -z "$MAILGUN_TO" ]; then MAILGUN_TO="" From f6f6d89e0683422338c55d2a6b8b3c97fe66b403 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sun, 12 May 2019 10:41:32 +0200 Subject: [PATCH 387/565] move sendmail notify to mail notify --- notify/mail.sh | 64 +++++++++++++++++++++++++++++++++++++++++++--- notify/sendmail.sh | 59 ------------------------------------------ 2 files changed, 61 insertions(+), 62 deletions(-) delete mode 100644 notify/sendmail.sh diff --git a/notify/mail.sh b/notify/mail.sh index 3dfef0b..949e8b5 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -1,6 +1,9 @@ #!/usr/bin/env sh -# support local mail app +#Support local mail app + +#MAIL_FROM="yyyy@gmail.com" +#MAIL_TO="yyyy@gmail.com" mail_send() { _subject="$1" @@ -10,6 +13,61 @@ mail_send() { _debug "_content" "$_content" _debug "_statusCode" "$_statusCode" - _err "Not implemented yet." - return 1 + if _exists "sendmail"; then + _MAIL_BIN="sendmail" + elif _exists "mail"; then + _MAIL_BIN="mail" + else + _err "Please install mail or sendmail first." + return 1 + fi + + MAIL_FROM="${MAIL_FROM:-$(_readaccountconf_mutable MAIL_FROM)}" + if [ -z "$MAIL_FROM" ]; then + MAIL_FROM="$USER@$(hostname -f)" + _info "The MAIL_FROM is not set, so use the default value: $MAIL_FROM" + fi + _saveaccountconf_mutable MAIL_FROM "$MAIL_FROM" + + MAIL_TO="${MAIL_TO:-$(_readaccountconf_mutable MAIL_TO)}" + if [ -z "$MAIL_TO" ]; then + MAIL_TO="$(_readaccountconf ACCOUNT_EMAIL)" + _info "The MAIL_TO is not set, so use the account email: $MAIL_TO" + fi + _saveaccountconf_mutable MAIL_TO "$MAIL_TO" + + subject="=?UTF-8?B?$(echo "$_subject" | _base64)?=" + result=$({ _mail_body | _mail_send; } 2>&1) + + if [ $? -ne 0 ]; then + _debug "mail send error." + _err "$result" + return 1 + fi + + _debug "mail send success." + return 0 +} + +_mail_send() { + case "$_MAIL_BIN" in + sendmail) + sendmail -f "$MAIL_FROM" "$MAIL_TO" + ;; + mail) + mail -s "$subject" -a "From:$MAIL_FROM" -a "Content-Type:text/plain; charset=utf-8" "$MAIL_TO" + ;; + esac +} + +_mail_body() { + if [ "$_MAIL_BIN" = "sendmail" ]; then + echo "From: $MAIL_FROM" + echo "To: $MAIL_TO" + echo "Subject: =?UTF-8?B?$(echo "$_subject" | _base64)?=" + echo "Content-Type: text/plain; charset=utf-8" + echo + fi + + echo "$_content" } diff --git a/notify/sendmail.sh b/notify/sendmail.sh deleted file mode 100644 index 7c253e9..0000000 --- a/notify/sendmail.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env sh - -#Support sendmail - -#SENDMAIL_BIN="sendmail" -#SENDMAIL_FROM="yyyy@gmail.com" -#SENDMAIL_TO="yyyy@gmail.com" - -sendmail_send() { - _subject="$1" - _content="$2" - _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped - _debug "_subject" "$_subject" - _debug "_content" "$_content" - _debug "_statusCode" "$_statusCode" - - SENDMAIL_BIN="${SENDMAIL_BIN:-$(_readaccountconf_mutable SENDMAIL_BIN)}" - if [ -z "$SENDMAIL_BIN" ]; then - SENDMAIL_BIN="sendmail" - _info "The SENDMAIL_BIN is not set, so use the default value: $SENDMAIL_BIN" - fi - if ! _exists "$SENDMAIL_BIN"; then - _err "Please install sendmail first." - return 1 - fi - _saveaccountconf_mutable SENDMAIL_BIN "$SENDMAIL_BIN" - - SENDMAIL_FROM="${SENDMAIL_FROM:-$(_readaccountconf_mutable SENDMAIL_FROM)}" - if [ -z "$SENDMAIL_FROM" ]; then - SENDMAIL_FROM="$USER@$(hostname -f)" - _info "The SENDMAIL_FROM is not set, so use the default value: $SENDMAIL_FROM" - fi - _saveaccountconf_mutable SENDMAIL_FROM "$SENDMAIL_FROM" - - SENDMAIL_TO="${SENDMAIL_TO:-$(_readaccountconf_mutable SENDMAIL_TO)}" - if [ -z "$SENDMAIL_TO" ]; then - SENDMAIL_TO="$(_readaccountconf ACCOUNT_EMAIL)" - _info "The SENDMAIL_TO is not set, so use the account email: $SENDMAIL_TO" - fi - _saveaccountconf_mutable SENDMAIL_TO "$SENDMAIL_TO" - - subject="=?UTF-8?B?$(echo "$_subject" | _base64)?=" - error=$({ echo "From: $SENDMAIL_FROM -To: $SENDMAIL_TO -Subject: $subject -Content-Type: text/plain; charset=utf-8 - -$_content -" | "$SENDMAIL_BIN" -f "$SENDMAIL_FROM" "$SENDMAIL_TO"; } 2>&1) - - if [ $? -ne 0 ]; then - _debug "sendmail send error." - _err "$error" - return 1 - fi - - _debug "sendmail send success." - return 0 -} From a89a62071b3728e1e6ad885fe3e9441cfb0b78bd Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sun, 12 May 2019 13:03:01 +0200 Subject: [PATCH 388/565] cleanup, lint --- notify/mail.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/notify/mail.sh b/notify/mail.sh index 949e8b5..6c6ef4e 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -18,7 +18,7 @@ mail_send() { elif _exists "mail"; then _MAIL_BIN="mail" else - _err "Please install mail or sendmail first." + _err "Please install sendmail or mail first." return 1 fi @@ -36,6 +36,7 @@ mail_send() { fi _saveaccountconf_mutable MAIL_TO "$MAIL_TO" + contenttype="text/plain; charset=utf-8" subject="=?UTF-8?B?$(echo "$_subject" | _base64)?=" result=$({ _mail_body | _mail_send; } 2>&1) @@ -52,10 +53,10 @@ mail_send() { _mail_send() { case "$_MAIL_BIN" in sendmail) - sendmail -f "$MAIL_FROM" "$MAIL_TO" + "$_MAIL_BIN" -f "$MAIL_FROM" "$MAIL_TO" ;; mail) - mail -s "$subject" -a "From:$MAIL_FROM" -a "Content-Type:text/plain; charset=utf-8" "$MAIL_TO" + "$_MAIL_BIN" -s "$subject" -a "From:$MAIL_FROM" -a "Content-Type:$contenttype" "$MAIL_TO" ;; esac } @@ -64,8 +65,8 @@ _mail_body() { if [ "$_MAIL_BIN" = "sendmail" ]; then echo "From: $MAIL_FROM" echo "To: $MAIL_TO" - echo "Subject: =?UTF-8?B?$(echo "$_subject" | _base64)?=" - echo "Content-Type: text/plain; charset=utf-8" + echo "Subject: $subject" + echo "Content-Type: $contenttype" echo fi From 10801bfb255a3dd0894ca8db1694ee019fcc4018 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sun, 12 May 2019 13:06:45 +0200 Subject: [PATCH 389/565] use mutt if installed --- notify/mail.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/notify/mail.sh b/notify/mail.sh index 6c6ef4e..cfd381f 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -15,6 +15,8 @@ mail_send() { if _exists "sendmail"; then _MAIL_BIN="sendmail" + elif _exists "mutt"; then + _MAIL_BIN="mutt" elif _exists "mail"; then _MAIL_BIN="mail" else @@ -55,6 +57,9 @@ _mail_send() { sendmail) "$_MAIL_BIN" -f "$MAIL_FROM" "$MAIL_TO" ;; + mutt) + "$_MAIL_BIN" -s "$subject" -e "my_hdr From:$MAIL_FROM" -e "my_hdr Content-Type:$contenttype" "$MAIL_TO" + ;; mail) "$_MAIL_BIN" -s "$subject" -a "From:$MAIL_FROM" -a "Content-Type:$contenttype" "$MAIL_TO" ;; From f6ca92337b62801222ee643cfb9def25742153b9 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sun, 12 May 2019 20:24:02 +0200 Subject: [PATCH 390/565] remove unsupported options from mail and mutt command --- notify/mail.sh | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/notify/mail.sh b/notify/mail.sh index cfd381f..cd92627 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -57,11 +57,8 @@ _mail_send() { sendmail) "$_MAIL_BIN" -f "$MAIL_FROM" "$MAIL_TO" ;; - mutt) - "$_MAIL_BIN" -s "$subject" -e "my_hdr From:$MAIL_FROM" -e "my_hdr Content-Type:$contenttype" "$MAIL_TO" - ;; - mail) - "$_MAIL_BIN" -s "$subject" -a "From:$MAIL_FROM" -a "Content-Type:$contenttype" "$MAIL_TO" + mutt|mail) + "$_MAIL_BIN" -s "$_subject" "$MAIL_TO" ;; esac } From 91c09dd0a076ff4d037dc3fc65a39d799fe4e903 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sun, 12 May 2019 20:26:31 +0200 Subject: [PATCH 391/565] ssmtp --- notify/mail.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/notify/mail.sh b/notify/mail.sh index cd92627..6bb7520 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -15,12 +15,14 @@ mail_send() { if _exists "sendmail"; then _MAIL_BIN="sendmail" + elif _exists "ssmtp"; then + _MAIL_BIN="ssmtp" elif _exists "mutt"; then _MAIL_BIN="mutt" elif _exists "mail"; then _MAIL_BIN="mail" else - _err "Please install sendmail or mail first." + _err "Please install sendmail, ssmtp, mutt or mail first." return 1 fi @@ -57,6 +59,9 @@ _mail_send() { sendmail) "$_MAIL_BIN" -f "$MAIL_FROM" "$MAIL_TO" ;; + ssmtp) + "$_MAIL_BIN" "$MAIL_TO" + ;; mutt|mail) "$_MAIL_BIN" -s "$_subject" "$MAIL_TO" ;; @@ -64,7 +69,7 @@ _mail_send() { } _mail_body() { - if [ "$_MAIL_BIN" = "sendmail" ]; then + if [ "$_MAIL_BIN" = "sendmail" ] || [ "$_MAIL_BIN" = "ssmtp" ]; then echo "From: $MAIL_FROM" echo "To: $MAIL_TO" echo "Subject: $subject" From d180f01b458d607559d28b853a2d42af2e42063a Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sun, 12 May 2019 22:28:37 +0200 Subject: [PATCH 392/565] typos --- notify/mail.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notify/mail.sh b/notify/mail.sh index 6bb7520..034fc03 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -62,7 +62,7 @@ _mail_send() { ssmtp) "$_MAIL_BIN" "$MAIL_TO" ;; - mutt|mail) + mutt | mail) "$_MAIL_BIN" -s "$_subject" "$MAIL_TO" ;; esac From 5e165819a1df9d6eef5f55bd6fd464f231cec570 Mon Sep 17 00:00:00 2001 From: Maarten den Braber Date: Mon, 13 May 2019 08:45:57 +0200 Subject: [PATCH 393/565] Update authentication logic / info --- dnsapi/dns_acmeproxy.sh | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_acmeproxy.sh b/dnsapi/dns_acmeproxy.sh index 8ca3eb0..d4a0e17 100644 --- a/dnsapi/dns_acmeproxy.sh +++ b/dnsapi/dns_acmeproxy.sh @@ -51,13 +51,19 @@ _acmeproxy_request() { _saveaccountconf_mutable ACMEPROXY_USERNAME "$ACMEPROXY_USERNAME" _saveaccountconf_mutable ACMEPROXY_PASSWORD "$ACMEPROXY_PASSWORD" - ## Base64 encode the credentials - credentials=$(printf "%b" "$ACMEPROXY_USERNAME:$ACMEPROXY_PASSWORD" | _base64) + if [ -z "$ACMEPROXY_USERNAME" ] || [ -z "$ACMEPROXY_PASSWORD" ]; then + _info "ACMEPROXY_USERNAME and/or ACMEPROXY_PASSWORD not set - using without client authentication! Make sure you're using server authentication (e.g. IP-based)" + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + else + ## Base64 encode the credentials + credentials=$(printf "%b" "$ACMEPROXY_USERNAME:$ACMEPROXY_PASSWORD" | _base64) - ## Construct the HTTP Authorization header - export _H1="Authorization: Basic $credentials" - export _H2="Accept: application/json" - export _H3="Content-Type: application/json" + ## Construct the HTTP Authorization header + export _H1="Authorization: Basic $credentials" + export _H2="Accept: application/json" + export _H3="Content-Type: application/json" + fi ## Add the challenge record to the acmeproxy grid member response="$(_post "{\"fqdn\": \"$fulldomain.\", \"value\": \"$txtvalue\"}" "$ACMEPROXY_ENDPOINT/$action" "" "POST")" From d509ef7581789697164a38e2bdd5ae12617dfb7c Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Mon, 13 May 2019 16:06:24 +0200 Subject: [PATCH 394/565] make MAIL_FROM not required --- notify/mail.sh | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/notify/mail.sh b/notify/mail.sh index 034fc03..33ed8fe 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -27,11 +27,14 @@ mail_send() { fi MAIL_FROM="${MAIL_FROM:-$(_readaccountconf_mutable MAIL_FROM)}" - if [ -z "$MAIL_FROM" ]; then - MAIL_FROM="$USER@$(hostname -f)" - _info "The MAIL_FROM is not set, so use the default value: $MAIL_FROM" + if [ -n "$MAIL_FROM" ]; then + if ! _contains "$MAIL_FROM" "@"; then + _err "It seems that the MAIL_FROM=$MAIL_FROM is not a valid email address." + return 1 + fi + + _saveaccountconf_mutable MAIL_FROM "$MAIL_FROM" fi - _saveaccountconf_mutable MAIL_FROM "$MAIL_FROM" MAIL_TO="${MAIL_TO:-$(_readaccountconf_mutable MAIL_TO)}" if [ -z "$MAIL_TO" ]; then @@ -57,7 +60,11 @@ mail_send() { _mail_send() { case "$_MAIL_BIN" in sendmail) - "$_MAIL_BIN" -f "$MAIL_FROM" "$MAIL_TO" + if [ -n "$MAIL_FROM" ]; then + "$_MAIL_BIN" -f "$MAIL_FROM" "$MAIL_TO" + else + "$_MAIL_BIN" "$MAIL_TO" + fi ;; ssmtp) "$_MAIL_BIN" "$MAIL_TO" @@ -70,7 +77,10 @@ _mail_send() { _mail_body() { if [ "$_MAIL_BIN" = "sendmail" ] || [ "$_MAIL_BIN" = "ssmtp" ]; then - echo "From: $MAIL_FROM" + if [ -n "$MAIL_FROM" ]; then + echo "From: $MAIL_FROM" + fi + echo "To: $MAIL_TO" echo "Subject: $subject" echo "Content-Type: $contenttype" From 0093dc3d32cf26e2815ddb476e3bd3398604c985 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 13 May 2019 23:30:31 +0800 Subject: [PATCH 395/565] fix https://github.com/Neilpang/acme.sh/issues/2256 --- acme.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index 19af5b0..4c1e45d 100755 --- a/acme.sh +++ b/acme.sh @@ -1114,14 +1114,14 @@ _createcsr() { elif [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then #single domain _info "Single domain" "$domain" - printf -- "\nsubjectAltName=DNS:$(_idn $domain)" >>"$csrconf" + printf -- "\nsubjectAltName=DNS:$(_idn "$domain")" >>"$csrconf" else domainlist="$(_idn "$domainlist")" _debug2 domainlist "$domainlist" if _contains "$domainlist" ","; then - alt="DNS:$(_idn $domain),DNS:$(echo "$domainlist" | sed "s/,,/,/g" | sed "s/,/,DNS:/g")" + alt="DNS:$(_idn "$domain"),DNS:$(echo "$domainlist" | sed "s/,,/,/g" | sed "s/,/,DNS:/g")" else - alt="DNS:$(_idn $domain),DNS:$domainlist" + alt="DNS:$(_idn "$domain"),DNS:$domainlist" fi #multi _info "Multi domain" "$alt" @@ -3648,9 +3648,9 @@ _check_dns_entries() { for entry in $dns_entries; do d=$(_getfield "$entry" 1) txtdomain=$(_getfield "$entry" 2) - txtdomain=$(_idn $txtdomain) + txtdomain=$(_idn "$txtdomain") aliasDomain=$(_getfield "$entry" 3) - aliasDomain=$(_idn $aliasDomain) + aliasDomain=$(_idn "$aliasDomain") txt=$(_getfield "$entry" 5) d_api=$(_getfield "$entry" 6) _debug "d" "$d" @@ -3847,7 +3847,7 @@ issue() { if [ -z "$vlist" ]; then if [ "$ACME_VERSION" = "2" ]; then #make new order request - _identifiers="{\"type\":\"dns\",\"value\":\"$(_idn $_main_domain)\"}" + _identifiers="{\"type\":\"dns\",\"value\":\"$(_idn "$_main_domain")\"}" _w_index=1 while true; do d="$(echo "$_alt_domains," | cut -d , -f "$_w_index")" @@ -3856,7 +3856,7 @@ issue() { if [ -z "$d" ]; then break fi - _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$(_idn $d)\"}" + _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$(_idn "$d")\"}" done _debug2 _identifiers "$_identifiers" if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then @@ -3944,7 +3944,7 @@ $_authorizations_map" fi if [ "$ACME_VERSION" = "2" ]; then - response="$(echo "$_authorizations_map" | grep "^$(_idn $d)," | sed "s/$d,//")" + response="$(echo "$_authorizations_map" | grep "^$(_idn "$d")," | sed "s/$d,//")" _debug2 "response" "$response" if [ -z "$response" ]; then _err "get to authz error." From 7b6ebc5c989350c113ee3516d47192dffaaac128 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Mon, 13 May 2019 17:42:07 +0200 Subject: [PATCH 396/565] try to use ACCOUNT_MAIL if MAIL_FROM is not set --- notify/mail.sh | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/notify/mail.sh b/notify/mail.sh index 33ed8fe..a1970c0 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -37,11 +37,21 @@ mail_send() { fi MAIL_TO="${MAIL_TO:-$(_readaccountconf_mutable MAIL_TO)}" - if [ -z "$MAIL_TO" ]; then + if [ -n "$MAIL_TO" ]; then + if ! _contains "$MAIL_TO" "@"; then + _err "It seems that the MAIL_TO=$MAIL_TO is not a valid email address." + return 1 + fi + + _saveaccountconf_mutable MAIL_TO "$MAIL_TO" + else MAIL_TO="$(_readaccountconf ACCOUNT_EMAIL)" - _info "The MAIL_TO is not set, so use the account email: $MAIL_TO" + + if [ -z "$MAIL_TO" ]; then + _err "It seems that account email is empty." + return 1 + fi fi - _saveaccountconf_mutable MAIL_TO "$MAIL_TO" contenttype="text/plain; charset=utf-8" subject="=?UTF-8?B?$(echo "$_subject" | _base64)?=" From e3052c8c57279f5732d849e63530efba90cd5af6 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Mon, 13 May 2019 17:44:04 +0200 Subject: [PATCH 397/565] expose MAIL_BIN variable --- notify/mail.sh | 54 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/notify/mail.sh b/notify/mail.sh index a1970c0..44148d9 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -2,6 +2,7 @@ #Support local mail app +#MAIL_BIN="sendmail" #MAIL_FROM="yyyy@gmail.com" #MAIL_TO="yyyy@gmail.com" @@ -13,18 +14,18 @@ mail_send() { _debug "_content" "$_content" _debug "_statusCode" "$_statusCode" - if _exists "sendmail"; then - _MAIL_BIN="sendmail" - elif _exists "ssmtp"; then - _MAIL_BIN="ssmtp" - elif _exists "mutt"; then - _MAIL_BIN="mutt" - elif _exists "mail"; then - _MAIL_BIN="mail" - else - _err "Please install sendmail, ssmtp, mutt or mail first." + unset -f _MAIL_BIN _MAIL_BODY _MAIL_CMD + + MAIL_BIN="${MAIL_BIN:-$(_readaccountconf_mutable MAIL_BIN)}" + if [ -n "$MAIL_BIN" ] && ! _exists "$MAIL_BIN"; then + _err "It seems that the command $MAIL_BIN is not in path." return 1 fi + _MAIL_CMD=$(_mail_cmnd) + if [ -n "$MAIL_BIN" ]; then + _saveaccountconf_mutable MAIL_BIN "$MAIL_BIN" + fi + _MAIL_BODY=$(_mail_body) MAIL_FROM="${MAIL_FROM:-$(_readaccountconf_mutable MAIL_FROM)}" if [ -n "$MAIL_FROM" ]; then @@ -47,6 +48,8 @@ mail_send() { else MAIL_TO="$(_readaccountconf ACCOUNT_EMAIL)" + echo "MAIL_TO: $MAIL_TO" + if [ -z "$MAIL_TO" ]; then _err "It seems that account email is empty." return 1 @@ -55,7 +58,7 @@ mail_send() { contenttype="text/plain; charset=utf-8" subject="=?UTF-8?B?$(echo "$_subject" | _base64)?=" - result=$({ _mail_body | _mail_send; } 2>&1) + result=$({ echo "$_MAIL_BODY" | eval "$_MAIL_CMD"; } 2>&1) if [ $? -ne 0 ]; then _debug "mail send error." @@ -67,20 +70,39 @@ mail_send() { return 0 } -_mail_send() { +_mail_cmnd() { + if [ -n "$MAIL_BIN" ]; then + _MAIL_BIN=$(basename "$MAIL_BIN") + elif _exists "sendmail"; then + _MAIL_BIN="sendmail" + elif _exists "ssmtp"; then + _MAIL_BIN="ssmtp" + elif _exists "mutt"; then + _MAIL_BIN="mutt" + elif _exists "mail"; then + _MAIL_BIN="mail" + else + _err "Please install sendmail, ssmtp, mutt or mail first." + return 1 + fi + case "$_MAIL_BIN" in sendmail) if [ -n "$MAIL_FROM" ]; then - "$_MAIL_BIN" -f "$MAIL_FROM" "$MAIL_TO" + echo "'$_MAIL_BIN' -f '$MAIL_FROM' '$MAIL_TO'" else - "$_MAIL_BIN" "$MAIL_TO" + echo "'$_MAIL_BIN' '$MAIL_TO'" fi ;; ssmtp) - "$_MAIL_BIN" "$MAIL_TO" + echo "'$_MAIL_BIN' '$MAIL_TO'" ;; mutt | mail) - "$_MAIL_BIN" -s "$_subject" "$MAIL_TO" + echo "'$_MAIL_BIN' -s '$_subject' '$MAIL_TO'" + ;; + *) + _err "Command $MAIL_BIN is not supported, use sendmail, ssmtp, mutt or mail." + return 1 ;; esac } From 30f2c2bd7781149e3a51368f1be1fcebd273d78c Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Mon, 13 May 2019 18:11:44 +0200 Subject: [PATCH 398/565] prevent _MAIL_BIN modification --- notify/mail.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notify/mail.sh b/notify/mail.sh index 44148d9..3aa0536 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -72,7 +72,7 @@ mail_send() { _mail_cmnd() { if [ -n "$MAIL_BIN" ]; then - _MAIL_BIN=$(basename "$MAIL_BIN") + _MAIL_BIN="$MAIL_BIN" elif _exists "sendmail"; then _MAIL_BIN="sendmail" elif _exists "ssmtp"; then @@ -86,7 +86,7 @@ _mail_cmnd() { return 1 fi - case "$_MAIL_BIN" in + case $(basename "$_MAIL_BIN") in sendmail) if [ -n "$MAIL_FROM" ]; then echo "'$_MAIL_BIN' -f '$MAIL_FROM' '$MAIL_TO'" From 7625d662599f01fabbcfbd8c72034591e94743ce Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Mon, 13 May 2019 18:58:28 +0200 Subject: [PATCH 399/565] wip --- notify/slack.sh | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 notify/slack.sh diff --git a/notify/slack.sh b/notify/slack.sh new file mode 100644 index 0000000..00d38b2 --- /dev/null +++ b/notify/slack.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env sh + +#Support Slack webhooks + +#SLACK_WEBHOOK_URL="" + +slack_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + SLACK_WEBHOOK_URL="${SLACK_WEBHOOK_URL:-$(_readaccountconf_mutable SLACK_WEBHOOK_URL)}" + if [ -z "$SLACK_WEBHOOK_URL" ]; then + SLACK_WEBHOOK_URL="" + _err "You didn't specify a Slack webhook url SLACK_WEBHOOK_URL yet." + return 1 + fi + _saveaccountconf_mutable SLACK_WEBHOOK_URL "$SLACK_WEBHOOK_URL" + + export _H1="Content-Type: application/json" + + _content="$(echo "$_subject: $_content" | _json_encode)" + _data="{\"text\": \"$_content\"}" + +echo "$_content" +echo "$_data" + + if _post "$_data" "$SLACK_WEBHOOK_URL"; then + # shellcheck disable=SC2154 + if [ -z "$response" ]; then + _info "slack send sccess." + return 0 + fi + fi + _err "slack send error." + _err "$response" + return 1 + +} From fc5e3a0aec38c9108322489dd16ff72cec8b55b6 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Mon, 13 May 2019 18:59:58 +0200 Subject: [PATCH 400/565] remove echo command --- notify/mail.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/notify/mail.sh b/notify/mail.sh index 3aa0536..73f180d 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -47,9 +47,6 @@ mail_send() { _saveaccountconf_mutable MAIL_TO "$MAIL_TO" else MAIL_TO="$(_readaccountconf ACCOUNT_EMAIL)" - - echo "MAIL_TO: $MAIL_TO" - if [ -z "$MAIL_TO" ]; then _err "It seems that account email is empty." return 1 From 73bbe25d2692dd8e5e2a5985becaf69d416e8f34 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Mon, 13 May 2019 19:49:16 +0200 Subject: [PATCH 401/565] add slack notify --- notify/slack.sh | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/notify/slack.sh b/notify/slack.sh index 00d38b2..cc1ed76 100644 --- a/notify/slack.sh +++ b/notify/slack.sh @@ -3,6 +3,8 @@ #Support Slack webhooks #SLACK_WEBHOOK_URL="" +#SLACK_CHANNEL="" +#SLACK_USERNAME="" slack_send() { _subject="$1" @@ -18,23 +20,36 @@ slack_send() { fi _saveaccountconf_mutable SLACK_WEBHOOK_URL "$SLACK_WEBHOOK_URL" - export _H1="Content-Type: application/json" + SLACK_CHANNEL="${SLACK_CHANNEL:-$(_readaccountconf_mutable SLACK_CHANNEL)}" + if [ -n "$SLACK_CHANNEL" ]; then + _saveaccountconf_mutable SLACK_CHANNEL "$SLACK_CHANNEL" + fi + + SLACK_USERNAME="${SLACK_USERNAME:-$(_readaccountconf_mutable SLACK_USERNAME)}" + if [ -n "$SLACK_USERNAME" ]; then + _saveaccountconf_mutable SLACK_USERNAME "$SLACK_USERNAME" + fi - _content="$(echo "$_subject: $_content" | _json_encode)" - _data="{\"text\": \"$_content\"}" + export _H1="Content-Type: application/json" -echo "$_content" -echo "$_data" + _content="$(printf "*%s*\n%s" "$_subject" "$_content" | _json_encode)" + _data="{\"text\": \"$_content\", " + if [ -n "$SLACK_CHANNEL" ]; then + _data="$_data\"channel\": \"$SLACK_CHANNEL\", " + fi + if [ -n "$SLACK_USERNAME" ]; then + _data="$_data\"username\": \"$SLACK_USERNAME\", " + fi + _data="$_data\"mrkdwn\": \"true\"}" if _post "$_data" "$SLACK_WEBHOOK_URL"; then # shellcheck disable=SC2154 - if [ -z "$response" ]; then - _info "slack send sccess." + if [ "$response" = "ok" ]; then + _info "slack send success." return 0 fi fi _err "slack send error." _err "$response" return 1 - } From a180b95ccaeda85769e413ed6ce54dd0a6f54c9e Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 17 May 2019 20:16:26 +0800 Subject: [PATCH 402/565] add more debug info --- acme.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 4c1e45d..60580f8 100755 --- a/acme.sh +++ b/acme.sh @@ -3044,11 +3044,12 @@ _clearupdns() { _err "It seems that your api file doesn't define $rmcommand" return 1 fi - + _info "Removing txt: $txt for domain: $txtdomain" if ! $rmcommand "$txtdomain" "$txt"; then _err "Error removing txt for domain:$txtdomain" return 1 fi + _info "Removed: Success" ) done @@ -4063,7 +4064,7 @@ $_authorizations_map" dns_entry="$dns_entry$dvsep$txt${dvsep}$d_api" _debug2 dns_entry "$dns_entry" if [ "$d_api" ]; then - _info "Found domain api file: $d_api" + _debug "Found domain api file: $d_api" else if [ "$_currentRoot" != "$W_DNS" ]; then _err "Can not find dns api hook for: $_currentRoot" @@ -4088,11 +4089,12 @@ $_authorizations_map" _err "It seems that your api file is not correct, it must have a function named: $addcommand" return 1 fi - + _info "Adding txt value: $txt for domain: $txtdomain" if ! $addcommand "$txtdomain" "$txt"; then _err "Error add txt for domain:$txtdomain" return 1 fi + _info "The txt record is added: Success." ) if [ "$?" != "0" ]; then From ace947e6b3fce69ecd97881daaaf22917dafc9a6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 18 May 2019 21:00:39 +0800 Subject: [PATCH 403/565] add dns_durabledns.sh --- dnsapi/dns_durabledns.sh | 182 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 dnsapi/dns_durabledns.sh diff --git a/dnsapi/dns_durabledns.sh b/dnsapi/dns_durabledns.sh new file mode 100644 index 0000000..5de1eaa --- /dev/null +++ b/dnsapi/dns_durabledns.sh @@ -0,0 +1,182 @@ +#!/usr/bin/env sh + + +#DD_API_User="xxxxx" +#DD_API_Key="xxxxxx" + +_DD_BASE="https://durabledns.com/services/dns" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_durabledns_add() { + fulldomain=$1 + txtvalue=$2 + + DD_API_User="${DD_API_User:-$(_readaccountconf_mutable DD_API_User)}" + DD_API_Key="${DD_API_Key:-$(_readaccountconf_mutable DD_API_Key)}" + if [ -z "$DD_API_User" ] || [ -z "$DD_API_Key" ]; then + DD_API_User="" + DD_API_Key="" + _err "You didn't specify a durabledns api user or key yet." + _err "You can get yours from here https://durabledns.com/dashboard/index.php" + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable DD_API_User "$DD_API_User" + _saveaccountconf_mutable DD_API_Key "$DD_API_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _dd_soap createRecord string zonename "$_domain." string name "$_sub_domain" string type "TXT" string data "$txtvalue" int aux 0 int ttl 10 string ddns_enabled N + _contains "$response" "createRecordResponse" +} + + +dns_durabledns_rm() { + fulldomain=$1 + txtvalue=$2 + + DD_API_User="${DD_API_User:-$(_readaccountconf_mutable DD_API_User)}" + DD_API_Key="${DD_API_Key:-$(_readaccountconf_mutable DD_API_Key)}" + if [ -z "$DD_API_User" ] || [ -z "$DD_API_Key" ]; then + DD_API_User="" + DD_API_Key="" + _err "You didn't specify a durabledns api user or key yet." + _err "You can get yours from here https://durabledns.com/dashboard/index.php" + 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 "Find record id" + if ! _dd_soap listRecords string zonename "$_domain."; then + _err "can not listRecords" + return 1 + fi + + subtxt="$(echo "$txtvalue" | cut -c 1-30)" + record="$(echo "$response" | sed 's//#/g' | tr '#' '\n' | grep ">$subtxt")" + _debug record "$record" + if [ -z "$record" ]; then + _err "can not find record for txtvalue" "$txtvalue" + _err "$response" + return 1 + fi + + recordid="$(echo "$record" | _egrep_o '[0-9]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _debug recordid "$recordid" + if [ -z "$recordid" ]; then + _err "can not find record id" + return 1 + fi + + if ! _dd_soap deleteRecord string zonename "$_domain." int id "$recordid"; then + _err "delete error" + return 1 + fi + + _contains "$response" "Success" +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + if ! _dd_soap "listZones"; then + return 1 + fi + + i=1 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _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 + +} + + +#method +_dd_soap() { + _method="$1" + shift + _urn="${_method}wsdl" + # put the parameters to xml + body=" + $DD_API_User + $DD_API_Key + " + while [ "$1" ]; do + _t="$1" + shift + _k="$1" + shift + _v="$1" + shift + body="$body<$_k xsi:type=\"xsd:$_t\">$_v" + done + body="$body" + _debug2 "SOAP request ${body}" + + # build SOAP XML + _xml=' + + '"$body"' +' + + _debug2 _xml "$_xml" + # set SOAP headers + _action="SOAPAction: \"urn:$_urn#$_method\"" + _debug2 "_action" "$_action" + export _H1="$_action" + export _H2="Content-Type: text/xml; charset=utf-8" + + _url="$_DD_BASE/$_method.php" + _debug "_url" "$_url" + if ! response="$(_post "${_xml}" "${_url}")"; then + _err "Error <$1>" + return 1 + fi + _debug2 "response" "$response" + response="$(echo "$response" | tr -d "\r\n" | _egrep_o ":${_method}Response .*:${_method}Response><")" + _debug2 "response" "$response" + return 0 +} + + + From 9a7c9e8d989fb8f0cfea976fb7e5b14f1a7d4743 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sat, 18 May 2019 18:20:16 +0200 Subject: [PATCH 404/565] remove unset --- notify/mail.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/notify/mail.sh b/notify/mail.sh index 73f180d..5ad8e88 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -14,8 +14,6 @@ mail_send() { _debug "_content" "$_content" _debug "_statusCode" "$_statusCode" - unset -f _MAIL_BIN _MAIL_BODY _MAIL_CMD - MAIL_BIN="${MAIL_BIN:-$(_readaccountconf_mutable MAIL_BIN)}" if [ -n "$MAIL_BIN" ] && ! _exists "$MAIL_BIN"; then _err "It seems that the command $MAIL_BIN is not in path." From d83c9da8308decbdbd9cbab5b551189423c2004a Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sat, 18 May 2019 18:21:19 +0200 Subject: [PATCH 405/565] add clearaccountconf MAIL_BIN --- notify/mail.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/notify/mail.sh b/notify/mail.sh index 5ad8e88..dbecc3a 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -22,6 +22,8 @@ mail_send() { _MAIL_CMD=$(_mail_cmnd) if [ -n "$MAIL_BIN" ]; then _saveaccountconf_mutable MAIL_BIN "$MAIL_BIN" + else + _clearaccountconf "MAIL_BIN" fi _MAIL_BODY=$(_mail_body) From cf4c603362acee171e2786476a0b02ff2e1f3619 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 May 2019 08:05:40 +0800 Subject: [PATCH 406/565] fix format --- dnsapi/dns_durabledns.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dnsapi/dns_durabledns.sh b/dnsapi/dns_durabledns.sh index 5de1eaa..9a05eb3 100644 --- a/dnsapi/dns_durabledns.sh +++ b/dnsapi/dns_durabledns.sh @@ -1,6 +1,5 @@ #!/usr/bin/env sh - #DD_API_User="xxxxx" #DD_API_Key="xxxxxx" @@ -40,7 +39,6 @@ dns_durabledns_add() { _contains "$response" "createRecordResponse" } - dns_durabledns_rm() { fulldomain=$1 txtvalue=$2 @@ -125,7 +123,6 @@ _get_root() { } - #method _dd_soap() { _method="$1" @@ -177,6 +174,3 @@ xmlns:xsd="http://www.w3.org/2001/XMLSchema"> _debug2 "response" "$response" return 0 } - - - From f6d6658de7e5c9b762f944e22ce583c94168e9f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20P=C3=A1la?= Date: Sun, 19 May 2019 11:47:19 +0200 Subject: [PATCH 407/565] Fix saving token for DNS Active24 --- dnsapi/dns_active24.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_active24.sh b/dnsapi/dns_active24.sh index 90ffaf6..862f734 100755 --- a/dnsapi/dns_active24.sh +++ b/dnsapi/dns_active24.sh @@ -129,7 +129,7 @@ _active24_init() { return 1 fi - _saveaccountconf_mutable ACTIVE24_Token "ACTIVE24_Token" + _saveaccountconf_mutable ACTIVE24_Token "$ACTIVE24_Token" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then From 68b42a00e07f7e35bc777fd41a6b147233918a38 Mon Sep 17 00:00:00 2001 From: der-berni Date: Mon, 20 May 2019 17:40:43 +0200 Subject: [PATCH 408/565] updated to work with one.com rev command not found on OpenWrt CURL does not work, using wget JSESSIONID replaced with OneSIDCrmAdmin CSRF_G_TOKEN not needed --- dnsapi/dns_one.sh | 139 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 105 insertions(+), 34 deletions(-) diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh index 94ac49c..6049ca1 100644 --- a/dnsapi/dns_one.sh +++ b/dnsapi/dns_one.sh @@ -4,9 +4,11 @@ # one.com ui wrapper for acme.sh # Author: github: @diseq # Created: 2019-02-17 +# Fixed by: @der-berni +# Modified: 2019-05-20 # -# export ONECOM_User="username" -# export ONECOM_Password="password" +# export ONECOM_USER="username" +# export ONECOM_PASSWORD="password" # # Usage: # acme.sh --issue --dns dns_one -d example.com @@ -14,38 +16,56 @@ # only single domain supported atm dns_one_add() { - mysubdomain=$(printf -- "%s" "$1" | rev | cut -d"." -f3- | rev) - mydomain=$(printf -- "%s" "$1" | rev | cut -d"." -f1-2 | rev) + #rev command not found on OpenWrt + #mysubdomain=$(printf -- "%s" "$1" | rev | cut -d"." -f3- | rev) + #mydomain=$(printf -- "%s" "$1" | rev | cut -d"." -f1-2 | rev) + + fulldomain=$1 txtvalue=$2 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + mysubdomain=$_sub_domain + mydomain=$_domain + _debug mysubdomain "$mysubdomain" + _debug mydomain "$mydomain" # get credentials - ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}" - ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}" - if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then - ONECOM_User="" - ONECOM_Password="" + ONECOM_USER="${ONECOM_USER:-$(_readaccountconf_mutable ONECOM_USER)}" + ONECOM_PASSWORD="${ONECOM_PASSWORD:-$(_readaccountconf_mutable ONECOM_PASSWORD)}" + if [ -z "$ONECOM_USER" ] || [ -z "$ONECOM_PASSWORD" ]; then + ONECOM_USER="" + ONECOM_PASSWORD="" _err "You didn't specify a one.com username and password yet." _err "Please create the key and try again." return 1 fi #save the api key and email to the account conf file. - _saveaccountconf_mutable ONECOM_User "$ONECOM_User" - _saveaccountconf_mutable ONECOM_Password "$ONECOM_Password" + _saveaccountconf_mutable ONECOM_USER "$ONECOM_USER" + _saveaccountconf_mutable ONECOM_PASSWORD "$ONECOM_PASSWORD" # Login with user and password postdata="loginDomain=true" - postdata="$postdata&displayUsername=$ONECOM_User" - postdata="$postdata&username=$ONECOM_User" + postdata="$postdata&displayUsername=$ONECOM_USER" + postdata="$postdata&username=$ONECOM_USER" postdata="$postdata&targetDomain=$mydomain" - postdata="$postdata&password1=$ONECOM_Password" + postdata="$postdata&password1=$ONECOM_PASSWORD" postdata="$postdata&loginTarget=" #_debug postdata "$postdata" - + + #CURL does not work + local tmp_USE_WGET=$ACME_USE_WGET + ACME_USE_WGET=1 + response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST" "application/x-www-form-urlencoded")" #_debug response "$response" - JSESSIONID="$(grep "JSESSIONID" "$HTTP_HEADER" | grep "^[Ss]et-[Cc]ookie:" | _tail_n 1 | _egrep_o 'JSESSIONID=[^;]*;' | tr -d ';')" + JSESSIONID="$(grep "OneSIDCrmAdmin" "$HTTP_HEADER" | grep "^[Ss]et-[Cc]ookie:" | _tail_n 1 | _egrep_o 'OneSIDCrmAdmin=[^;]*;' | tr -d ';')" _debug jsessionid "$JSESSIONID" export _H1="Cookie: ${JSESSIONID}" @@ -54,8 +74,8 @@ dns_one_add() { response="$(_get "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records")" _debug response "$response" - CSRF_G_TOKEN="$(grep "CSRF_G_TOKEN=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'CSRF_G_TOKEN=[^;]*;' | tr -d ';')" - export _H2="Cookie: ${CSRF_G_TOKEN}" + #CSRF_G_TOKEN="$(grep "CSRF_G_TOKEN=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'CSRF_G_TOKEN=[^;]*;' | tr -d ';')" + #export _H2="Cookie: ${CSRF_G_TOKEN}" # Update the IP address for domain entry postdata="{\"type\":\"dns_custom_records\",\"attributes\":{\"priority\":0,\"ttl\":600,\"type\":\"TXT\",\"prefix\":\"$mysubdomain\",\"content\":\"$txtvalue\"}}" @@ -65,7 +85,9 @@ dns_one_add() { _debug response "$response" id=$(echo "$response" | sed -n "s/{\"result\":{\"data\":{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$mysubdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}}},\"metadata\":null}/\1/p") - + + ACME_USE_WGET=$tmp_USE_WGET + if [ -z "$id" ]; then _err "Add txt record error." return 1 @@ -77,16 +99,30 @@ dns_one_add() { } dns_one_rm() { - mysubdomain=$(printf -- "%s" "$1" | rev | cut -d"." -f3- | rev) - mydomain=$(printf -- "%s" "$1" | rev | cut -d"." -f1-2 | rev) + #rev command not found on OpenWrt + #mysubdomain=$(printf -- "%s" "$1" | rev | cut -d"." -f3- | rev) + #mydomain=$(printf -- "%s" "$1" | rev | cut -d"." -f1-2 | rev) + + fulldomain=$1 txtvalue=$2 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + mysubdomain=$_sub_domain + mydomain=$_domain + _debug mysubdomain "$mysubdomain" + _debug mydomain "$mydomain" # get credentials - ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}" - ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}" - if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then - ONECOM_User="" - ONECOM_Password="" + ONECOM_USER="${ONECOM_USER:-$(_readaccountconf_mutable ONECOM_USER)}" + ONECOM_PASSWORD="${ONECOM_PASSWORD:-$(_readaccountconf_mutable ONECOM_PASSWORD)}" + if [ -z "$ONECOM_USER" ] || [ -z "$ONECOM_PASSWORD" ]; then + ONECOM_USER="" + ONECOM_PASSWORD="" _err "You didn't specify a one.com username and password yet." _err "Please create the key and try again." return 1 @@ -94,16 +130,20 @@ dns_one_rm() { # Login with user and password postdata="loginDomain=true" - postdata="$postdata&displayUsername=$ONECOM_User" - postdata="$postdata&username=$ONECOM_User" + postdata="$postdata&displayUsername=$ONECOM_USER" + postdata="$postdata&username=$ONECOM_USER" postdata="$postdata&targetDomain=$mydomain" - postdata="$postdata&password1=$ONECOM_Password" + postdata="$postdata&password1=$ONECOM_PASSWORD" postdata="$postdata&loginTarget=" - + + #CURL does not work + local tmp_USE_WGET=$ACME_USE_WGET + ACME_USE_WGET=1 + response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST" "application/x-www-form-urlencoded")" #_debug response "$response" - JSESSIONID="$(grep "JSESSIONID" "$HTTP_HEADER" | grep "^[Ss]et-[Cc]ookie:" | _tail_n 1 | _egrep_o 'JSESSIONID=[^;]*;' | tr -d ';')" + JSESSIONID="$(grep "OneSIDCrmAdmin" "$HTTP_HEADER" | grep "^[Ss]et-[Cc]ookie:" | _tail_n 1 | _egrep_o 'OneSIDCrmAdmin=[^;]*;' | tr -d ';')" _debug jsessionid "$JSESSIONID" export _H1="Cookie: ${JSESSIONID}" @@ -113,13 +153,14 @@ dns_one_rm() { response="$(echo "$response" | _normalizeJson)" _debug response "$response" - CSRF_G_TOKEN="$(grep "CSRF_G_TOKEN=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'CSRF_G_TOKEN=[^;]*;' | tr -d ';')" - export _H2="Cookie: ${CSRF_G_TOKEN}" + #CSRF_G_TOKEN="$(grep "CSRF_G_TOKEN=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'CSRF_G_TOKEN=[^;]*;' | tr -d ';')" + #export _H2="Cookie: ${CSRF_G_TOKEN}" id=$(printf -- "%s" "$response" | sed -n "s/.*{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$mysubdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}.*/\1/p") if [ -z "$id" ]; then _err "Txt record not found." + ACME_USE_WGET=$tmp_USE_WGET return 1 fi @@ -127,7 +168,9 @@ dns_one_rm() { response="$(_post "$postdata" "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records/$id" "" "DELETE" "application/json")" response="$(echo "$response" | _normalizeJson)" _debug response "$response" - + + ACME_USE_WGET=$tmp_USE_WGET + if [ "$response" = '{"result":null,"metadata":null}' ]; then _info "Removed, OK" return 0 @@ -137,3 +180,31 @@ dns_one_rm() { fi } + +#_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 [ "$(printf "%s" "$h" | tr '.' ' ' | wc -w)" = "2" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + _err "Unable to parse this domain" + return 1 +} From 688fe131c93c23ecc2a1510034a7c973201d2356 Mon Sep 17 00:00:00 2001 From: mjthompson Date: Tue, 21 May 2019 18:21:54 +0800 Subject: [PATCH 409/565] Fix typo --- dnsapi/dns_aws.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 2ad3c81..246f477 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -49,7 +49,7 @@ dns_aws_add() { _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 From 49bdcad4b60da9f8efec18eff7b8fc81bcb0a4e0 Mon Sep 17 00:00:00 2001 From: Maximilian Hippler Date: Tue, 21 May 2019 18:50:12 +0200 Subject: [PATCH 410/565] Updated oathtoolkit from edge/testing to edge/community --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5aa8da1..f9d7b1b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ RUN apk update -f \ curl \ socat \ tzdata \ - && apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/testing oath-toolkit-oathtool \ + && apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/community oath-toolkit-oathtool \ && rm -rf /var/cache/apk/* ENV LE_CONFIG_HOME /acme.sh @@ -22,7 +22,7 @@ RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/ RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab - -RUN for verb in help \ +RUN for verb in help \ version \ install \ uninstall \ From c2dd7e0f6ed2a3e099bd6409b37cfd9a84f5f752 Mon Sep 17 00:00:00 2001 From: neil <8305679+Neilpang@users.noreply.github.com> Date: Wed, 22 May 2019 22:00:39 +0800 Subject: [PATCH 411/565] Create LICENSE.md --- LICENSE.md | 674 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From 0e9ba9a0047fcbac58edb2e01d1db7ff9c7175c7 Mon Sep 17 00:00:00 2001 From: Oliver Dick Date: Wed, 22 May 2019 16:20:28 +0200 Subject: [PATCH 412/565] remove _hostingde_parse_no_strip_whitespace function as this breaks API requests --- dnsapi/dns_hostingde.sh | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index 1aa7039..9e3e566 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -53,18 +53,6 @@ _hostingde_parse() { fi } -_hostingde_parse_no_strip_whitespace() { - 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 - else - _egrep_o \""${find}\":.*" | cut -d ':' -f 2 | cut -d ',' -f 1 - fi -} - _hostingde_getZoneConfig() { _info "Getting ZoneConfig" curZone="${fulldomain#*.}" @@ -97,12 +85,12 @@ _hostingde_getZoneConfig() { zoneConfigDnsServerGroupId=$(echo "${curResult}" | _hostingde_parse "dnsServerGroupId") zoneConfigEmailAddress=$(echo "${curResult}" | _hostingde_parse "emailAddress") zoneConfigDnsSecMode=$(echo "${curResult}" | _hostingde_parse "dnsSecMode") - zoneConfigTemplateValues=$(echo "${curResult}" | _hostingde_parse_no_strip_whitespace "templateValues") + zoneConfigTemplateValues=$(echo "${curResult}" | _hostingde_parse "templateValues") if [ "$zoneConfigTemplateValues" != "null" ]; then _debug "Zone is tied to a template." zoneConfigTemplateValuesTemplateId=$(echo "${curResult}" | _hostingde_parse "templateId") - zoneConfigTemplateValuesTemplateName=$(echo "${curResult}" | _hostingde_parse_no_strip_whitespace "templateName") + zoneConfigTemplateValuesTemplateName=$(echo "${curResult}" | _hostingde_parse "templateName") zoneConfigTemplateValuesTemplateReplacementsIPv4=$(echo "${curResult}" | _hostingde_parse "ipv4Replacement") zoneConfigTemplateValuesTemplateReplacementsIPv6=$(echo "${curResult}" | _hostingde_parse "ipv6Replacement") zoneConfigTemplateValuesTemplateReplacementsMailIPv4=$(echo "${curResult}" | _hostingde_parse "mailIpv4Replacement") From 50d5c4b9ca9c639d121caa6bfcbf2b8729bcea0b Mon Sep 17 00:00:00 2001 From: devNan0 Date: Wed, 22 May 2019 17:01:11 +0200 Subject: [PATCH 413/565] Fix sessionid parsing on BSD --- dnsapi/dns_netcup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh index d5d7c22..6e17925 100644 --- a/dnsapi/dns_netcup.sh +++ b/dnsapi/dns_netcup.sh @@ -117,7 +117,7 @@ dns_netcup_rm() { 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') + sid=$(echo "$tmp" | tr '{}' '\n\n' | grep apisessionid | cut -d '"' -f 4) _debug "$tmp" if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then _err "$msg" From 09fb9dcd92d56d3552177ae86a466157cb908fb8 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 22 May 2019 22:16:46 -0400 Subject: [PATCH 414/565] Fix bug preventing multipart TLD names to work. And simplify/cleanup the code. --- dnsapi/dns_freedns.sh | 303 ++++++++++++++++++++++++------------------ 1 file changed, 174 insertions(+), 129 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 7262755..e6c6ba5 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -46,76 +46,34 @@ dns_freedns_add() { _saveaccountconf FREEDNS_COOKIE "$FREEDNS_COOKIE" - # split our full domain name into two parts... - i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" - i="$(_math "$i" - 1)" - top_domain="$(echo "$fulldomain" | cut -d. -f "$i"-100)" - i="$(_math "$i" - 1)" - sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" - - _debug "top_domain: $top_domain" - _debug "sub_domain: $sub_domain" - - # Sometimes FreeDNS does not return the subdomain page but rather - # returns a page regarding becoming a premium member. This usually - # happens after a period of inactivity. Immediately trying again - # returns the correct subdomain page. So, we will try twice to - # load the page and obtain our domain ID - attempts=2 - while [ "$attempts" -gt "0" ]; do - attempts="$(_math "$attempts" - 1)" - - htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" - if [ "$?" != "0" ]; then - if [ "$using_cached_cookies" = "true" ]; then - _err "Has your FreeDNS username and password changed? If so..." - _err "Please export as FREEDNS_User / FREEDNS_Password and try again." - fi - return 1 - fi - - subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '
' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep "$top_domain")" - _debug3 "subdomain_csv: $subdomain_csv" - - # The above beauty ends with striping out rows that do not have an - # href to edit.php and do not have the top domain we are looking for. - # So all we should be left with is CSV of table of subdomains we are - # interested in. - - # Now we have to read through this table and extract the data we need - lines="$(echo "$subdomain_csv" | wc -l)" - i=0 - found=0 - DNSdomainid="" - while [ "$i" -lt "$lines" ]; do - i="$(_math "$i" + 1)" - line="$(echo "$subdomain_csv" | sed -n "${i}p")" - _debug2 "line: $line" - if [ $found = 0 ] && _contains "$line" "$top_domain"; then - # this line will contain DNSdomainid for the top_domain - DNSdomainid="$(echo "$line" | _egrep_o "edit_domain_id *= *.*>" | cut -d = -f 2 | cut -d '>' -f 1)" - _debug2 "DNSdomainid: $DNSdomainid" - found=1 - break - fi - done - - if [ -z "$DNSdomainid" ]; then - # If domain ID is empty then something went wrong (top level - # domain not found at FreeDNS). - if [ "$attempts" = "0" ]; then - # exhausted maximum retry attempts - _err "Domain $top_domain not found at FreeDNS" - return 1 - fi - else - # break out of the 'retry' loop... we have found our domain ID + # We may have to cycle through the domain name to find the + # TLD that we own... + i=1 + wmax="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" + while [ "$i" -lt "$wmax" ]; do + # split our full domain name into two parts... + sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" + i="$(_math "$i" + 1)" + top_domain="$(echo "$fulldomain" | cut -d. -f "$i"-100)" + _debug "sub_domain: $sub_domain" + _debug "top_domain: $top_domain" + + DNSdomainid="$(_freedns_domain_id $top_domain)" + if [ "$?" = "0" ]; then + _info "Domain $top_domain found at FreeDNS, domain_id $DNSdomainid" break + else + _info "Domain $top_domain not found at FreeDNS, try with next level of TLD" fi - _info "Domain $top_domain not found at FreeDNS" - _info "Retry loading subdomain page ($attempts attempts remaining)" done + if [ -z "$DNSdomainid" ]; then + # If domain ID is empty then something went wrong (top level + # domain not found at FreeDNS). + _err "Domain $top_domain not found at FreeDNS" + return 1 + fi + # Add in new TXT record with the value provided _debug "Adding TXT record for $fulldomain, $txtvalue" _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" @@ -138,76 +96,44 @@ dns_freedns_rm() { FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")" _debug "FreeDNS login cookies: $FREEDNS_COOKIE" - # Sometimes FreeDNS does not return the subdomain page but rather - # returns a page regarding becoming a premium member. This usually - # happens after a period of inactivity. Immediately trying again - # returns the correct subdomain page. So, we will try twice to - # load the page and obtain our TXT record. - attempts=2 - while [ "$attempts" -gt "0" ]; do - attempts="$(_math "$attempts" - 1)" - - htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" + TXTdataid="$(_freedns_data_id "$fulldomain" "TXT")" + if [ "$?" != "0" ]; then + _info "Cannot delete TXT record for $fulldomain, record does not exist at FreeDNS" + return 1 + fi + _debug "Data ID's found, $TXTdataid" + + # now we have one (or more) TXT record data ID's. Load the page + # for that record and search for the record txt value. If match + # then we can delete it. + lines="$(echo "$TXTdataid" | wc -l)" + _debug "Found $lines TXT data records for $fulldomain" + i=0 + while [ "$i" -lt "$lines" ]; do + i="$(_math "$i" + 1)" + dataid="$(echo "$TXTdataid" | sed -n "${i}p")" + _debug "$dataid" + + htmlpage="$(_freedns_retrieve_data_page "$FREEDNS_COOKIE" "$dataid")" if [ "$?" != "0" ]; then + if [ "$using_cached_cookies" = "true" ]; then + _err "Has your FreeDNS username and password changed? If so..." + _err "Please export as FREEDNS_User / FREEDNS_Password and try again." + fi return 1 fi - subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep "$fulldomain")" - _debug3 "subdomain_csv: $subdomain_csv" - - # The above beauty ends with striping out rows that do not have an - # href to edit.php and do not have the domain name we are looking for. - # So all we should be left with is CSV of table of subdomains we are - # interested in. - - # Now we have to read through this table and extract the data we need - lines="$(echo "$subdomain_csv" | wc -l)" - i=0 - found=0 - DNSdataid="" - while [ "$i" -lt "$lines" ]; do - i="$(_math "$i" + 1)" - line="$(echo "$subdomain_csv" | sed -n "${i}p")" - _debug3 "line: $line" - DNSname="$(echo "$line" | _egrep_o 'edit.php.*' | cut -d '>' -f 2 | cut -d '<' -f 1)" - _debug2 "DNSname: $DNSname" - if [ "$DNSname" = "$fulldomain" ]; then - DNStype="$(echo "$line" | sed 's/' -f 2 | cut -d '<' -f 1)" - _debug2 "DNStype: $DNStype" - if [ "$DNStype" = "TXT" ]; then - DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)" - _debug2 "DNSdataid: $DNSdataid" - DNSvalue="$(echo "$line" | sed 's/' -f 2 | cut -d '<' -f 1)" - if _startswith "$DNSvalue" """; then - # remove the quotation from the start - DNSvalue="$(echo "$DNSvalue" | cut -c 7-)" - fi - if _endswith "$DNSvalue" "..."; then - # value was truncated, remove the dot dot dot from the end - DNSvalue="$(echo "$DNSvalue" | sed 's/...$//')" - elif _endswith "$DNSvalue" """; then - # else remove the closing quotation from the end - DNSvalue="$(echo "$DNSvalue" | sed 's/......$//')" - fi - _debug2 "DNSvalue: $DNSvalue" - - if [ -n "$DNSdataid" ] && _startswith "$txtvalue" "$DNSvalue"; then - # Found a match. But note... Website is truncating the - # value field so we are only testing that part that is not - # truncated. This should be accurate enough. - _debug "Deleting TXT record for $fulldomain, $txtvalue" - _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" - return $? - fi - - fi - fi - done + echo "$htmlpage" | grep "value=\""$txtvalue"\"" >/dev/null + if [ "$?" = "0" ]; then + # Found a match... delete the record and return + _info "Deleting TXT record for $fulldomain, $txtvalue" + _freedns_delete_txt_record "$FREEDNS_COOKIE" "$dataid" + return $? + fi done - # If we get this far we did not find a match (after two attempts) + # If we get this far we did not find a match # Not necessarily an error, but log anyway. - _debug3 "$subdomain_csv" _info "Cannot delete TXT record for $fulldomain, $txtvalue. Does not exist at FreeDNS" return 0 } @@ -271,6 +197,33 @@ _freedns_retrieve_subdomain_page() { return 0 } +# usage _freedns_retrieve_data_page login_cookies data_id +# echo page retrieved (html) +# returns 0 success +_freedns_retrieve_data_page() { + export _H1="Cookie:$1" + export _H2="Accept-Language:en-US" + data_id="$2" + url="https://freedns.afraid.org/subdomain/edit.php?data_id=$2" + + _debug "Retrieve data page for ID $data_id from FreeDNS" + + htmlpage="$(_get "$url")" + + if [ "$?" != "0" ]; then + _err "FreeDNS retrieve data page failed bad RC from _get" + return 1 + elif [ -z "$htmlpage" ]; then + _err "FreeDNS returned empty data page" + return 1 + fi + + _debug3 "htmlpage: $htmlpage" + + printf "%s" "$htmlpage" + return 0 +} + # usage _freedns_add_txt_record login_cookies domain_id subdomain value # returns 0 success _freedns_add_txt_record() { @@ -324,3 +277,95 @@ _freedns_delete_txt_record() { _info "Deleted acme challenge TXT record for $fulldomain at FreeDNS" return 0 } + +# usage _freedns_domain_id domain_name +# echo the domain_id if found +# return 0 success +_freedns_domain_id() { + # Start by escaping the dots in the domain name + search_domain="$(echo "$1" | sed 's/\./\\./g')" + + # Sometimes FreeDNS does not return the subdomain page but rather + # returns a page regarding becoming a premium member. This usually + # happens after a period of inactivity. Immediately trying again + # returns the correct subdomain page. So, we will try twice to + # load the page and obtain our domain ID + attempts=2 + while [ "$attempts" -gt "0" ]; do + attempts="$(_math "$attempts" - 1)" + + htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" + if [ "$?" != "0" ]; then + if [ "$using_cached_cookies" = "true" ]; then + _err "Has your FreeDNS username and password changed? If so..." + _err "Please export as FREEDNS_User / FREEDNS_Password and try again." + fi + return 1 + fi + + domain_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ + | grep "$search_domain\|$search_domain(.*)" \ + | _egrep_o "edit\.php\?edit_domain_id=[0-9a-zA-Z]+" \ + | cut -d = -f 2 )" + # The above beauty extracts domain ID from the html page... + # strip out all blank space and new lines. Then insert newlines + # before each table row + # search for the domain within each row (which may or may not have + # a text string in brackets (.*) after it. + # And finally extract the domain ID. + if [ -n "$domain_id" ]; then + printf "%s" "$domain_id" + return 0 + fi + _debug "Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)" + done + _debug "Domain $search_domain not found after retry" + return 1 +} + +# usage _freedns_data_id domain_name record_type +# echo the data_id(s) if found +# return 0 success +_freedns_data_id() { + # Start by escaping the dots in the domain name + search_domain="$(echo "$1" | sed 's/\./\\./g')" + record_type="$2" + + # Sometimes FreeDNS does not return the subdomain page but rather + # returns a page regarding becoming a premium member. This usually + # happens after a period of inactivity. Immediately trying again + # returns the correct subdomain page. So, we will try twice to + # load the page and obtain our domain ID + attempts=2 + while [ "$attempts" -gt "0" ]; do + attempts="$(_math "$attempts" - 1)" + + htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" + if [ "$?" != "0" ]; then + if [ "$using_cached_cookies" = "true" ]; then + _err "Has your FreeDNS username and password changed? If so..." + _err "Please export as FREEDNS_User / FREEDNS_Password and try again." + fi + return 1 + fi + + data_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ + | grep "$record_type" \ + | grep "$search_domain" \ + | _egrep_o "edit\.php\?data_id=[0-9a-zA-Z]+" \ + | cut -d = -f 2)" + # The above beauty extracts data ID from the html page... + # strip out all blank space and new lines. Then insert newlines + # before each table row + # search for the record type withing each row (e.g. TXT) + # search for the domain within each row (which is within a + # anchor. And finally extract the domain ID. + if [ -n "$data_id" ]; then + printf "%s" "$data_id" + return 0 + fi + _debug "Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)" + done + _debug "Domain $search_domain not found after retry" + return 1 +} From 66c39a953ae170e5cb64ab57f8cd2d51987a1f7d Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 22 May 2019 22:50:26 -0400 Subject: [PATCH 415/565] Fix warnings from Travis build --- dnsapi/dns_freedns.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index e6c6ba5..d1f3d41 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -58,7 +58,7 @@ dns_freedns_add() { _debug "sub_domain: $sub_domain" _debug "top_domain: $top_domain" - DNSdomainid="$(_freedns_domain_id $top_domain)" + DNSdomainid="$(_freedns_domain_id "$top_domain")" if [ "$?" = "0" ]; then _info "Domain $top_domain found at FreeDNS, domain_id $DNSdomainid" break @@ -304,9 +304,9 @@ _freedns_domain_id() { fi domain_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ - | grep "$search_domain\|$search_domain(.*)" \ - | _egrep_o "edit\.php\?edit_domain_id=[0-9a-zA-Z]+" \ - | cut -d = -f 2 )" + | grep "$search_domain\|$search_domain(.*)" \ + | _egrep_o "edit\.php\?edit_domain_id=[0-9a-zA-Z]+" \ + | cut -d = -f 2 )" # The above beauty extracts domain ID from the html page... # strip out all blank space and new lines. Then insert newlines # before each table row @@ -319,7 +319,7 @@ _freedns_domain_id() { fi _debug "Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)" done - _debug "Domain $search_domain not found after retry" + _debug "Domain $search_domain not found after retry" return 1 } @@ -350,10 +350,10 @@ _freedns_data_id() { fi data_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ - | grep "$record_type" \ - | grep "$search_domain" \ - | _egrep_o "edit\.php\?data_id=[0-9a-zA-Z]+" \ - | cut -d = -f 2)" + | grep "$record_type" \ + | grep "$search_domain" \ + | _egrep_o "edit\.php\?data_id=[0-9a-zA-Z]+" \ + | cut -d = -f 2)" # The above beauty extracts data ID from the html page... # strip out all blank space and new lines. Then insert newlines # before each table row @@ -366,6 +366,6 @@ _freedns_data_id() { fi _debug "Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)" done - _debug "Domain $search_domain not found after retry" + _debug "Domain $search_domain not found after retry" return 1 } From a18ce275ab91a88149cf580a964e237897f85cf6 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 22 May 2019 22:54:56 -0400 Subject: [PATCH 416/565] Another Travis CI warning fixed. --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index d1f3d41..e92cf61 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -306,7 +306,7 @@ _freedns_domain_id() { domain_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ | grep "$search_domain\|$search_domain(.*)" \ | _egrep_o "edit\.php\?edit_domain_id=[0-9a-zA-Z]+" \ - | cut -d = -f 2 )" + | cut -d = -f 2)" # The above beauty extracts domain ID from the html page... # strip out all blank space and new lines. Then insert newlines # before each table row From 10994d65bed6039aa32adfa39cf454fe3619eb2c Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 22 May 2019 23:01:23 -0400 Subject: [PATCH 417/565] Even blank lines (with spaces) give Travis heartache. Sigh. --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index e92cf61..71c6aa8 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -348,7 +348,7 @@ _freedns_data_id() { fi return 1 fi - + data_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ | grep "$record_type" \ | grep "$search_domain" \ From 05b6afcd172cd7e15909c6162094f1a00595bf77 Mon Sep 17 00:00:00 2001 From: devNan0 Date: Thu, 23 May 2019 08:15:03 +0200 Subject: [PATCH 418/565] Make travis happy. (SC2020) --- dnsapi/dns_netcup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh index 6e17925..d519e4f 100644 --- a/dnsapi/dns_netcup.sh +++ b/dnsapi/dns_netcup.sh @@ -117,7 +117,7 @@ dns_netcup_rm() { login() { tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") - sid=$(echo "$tmp" | tr '{}' '\n\n' | grep apisessionid | cut -d '"' -f 4) + sid=$(echo "$tmp" | tr '{}' '\n' | grep apisessionid | cut -d '"' -f 4) _debug "$tmp" if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then _err "$msg" From e340593ad1c313d178ef1b425bd66831b5f425be Mon Sep 17 00:00:00 2001 From: der-berni Date: Thu, 23 May 2019 09:39:54 +0200 Subject: [PATCH 419/565] Revert parameter changes Revert ONECOM_PASSWORD back to ONECOM_Password and ONECOM_USER back to ONECOM_User --- dnsapi/dns_one.sh | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh index 6049ca1..a237a0d 100644 --- a/dnsapi/dns_one.sh +++ b/dnsapi/dns_one.sh @@ -7,8 +7,8 @@ # Fixed by: @der-berni # Modified: 2019-05-20 # -# export ONECOM_USER="username" -# export ONECOM_PASSWORD="password" +# export ONECOM_User="username" +# export ONECOM_Password="password" # # Usage: # acme.sh --issue --dns dns_one -d example.com @@ -35,26 +35,26 @@ dns_one_add() { _debug mydomain "$mydomain" # get credentials - ONECOM_USER="${ONECOM_USER:-$(_readaccountconf_mutable ONECOM_USER)}" - ONECOM_PASSWORD="${ONECOM_PASSWORD:-$(_readaccountconf_mutable ONECOM_PASSWORD)}" - if [ -z "$ONECOM_USER" ] || [ -z "$ONECOM_PASSWORD" ]; then - ONECOM_USER="" - ONECOM_PASSWORD="" + ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}" + ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}" + if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then + ONECOM_User="" + ONECOM_Password="" _err "You didn't specify a one.com username and password yet." _err "Please create the key and try again." return 1 fi #save the api key and email to the account conf file. - _saveaccountconf_mutable ONECOM_USER "$ONECOM_USER" - _saveaccountconf_mutable ONECOM_PASSWORD "$ONECOM_PASSWORD" + _saveaccountconf_mutable ONECOM_User "$ONECOM_User" + _saveaccountconf_mutable ONECOM_Password "$ONECOM_Password" # Login with user and password postdata="loginDomain=true" - postdata="$postdata&displayUsername=$ONECOM_USER" - postdata="$postdata&username=$ONECOM_USER" + postdata="$postdata&displayUsername=$ONECOM_User" + postdata="$postdata&username=$ONECOM_User" postdata="$postdata&targetDomain=$mydomain" - postdata="$postdata&password1=$ONECOM_PASSWORD" + postdata="$postdata&password1=$ONECOM_Password" postdata="$postdata&loginTarget=" #_debug postdata "$postdata" @@ -118,11 +118,11 @@ dns_one_rm() { _debug mydomain "$mydomain" # get credentials - ONECOM_USER="${ONECOM_USER:-$(_readaccountconf_mutable ONECOM_USER)}" - ONECOM_PASSWORD="${ONECOM_PASSWORD:-$(_readaccountconf_mutable ONECOM_PASSWORD)}" - if [ -z "$ONECOM_USER" ] || [ -z "$ONECOM_PASSWORD" ]; then - ONECOM_USER="" - ONECOM_PASSWORD="" + ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}" + ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}" + if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then + ONECOM_User="" + ONECOM_Password="" _err "You didn't specify a one.com username and password yet." _err "Please create the key and try again." return 1 @@ -130,10 +130,10 @@ dns_one_rm() { # Login with user and password postdata="loginDomain=true" - postdata="$postdata&displayUsername=$ONECOM_USER" - postdata="$postdata&username=$ONECOM_USER" + postdata="$postdata&displayUsername=$ONECOM_User" + postdata="$postdata&username=$ONECOM_User" postdata="$postdata&targetDomain=$mydomain" - postdata="$postdata&password1=$ONECOM_PASSWORD" + postdata="$postdata&password1=$ONECOM_Password" postdata="$postdata&loginTarget=" #CURL does not work From 93740c997c5ea74fe198c37223bba13e4e777b36 Mon Sep 17 00:00:00 2001 From: andreasschulze Date: Thu, 23 May 2019 16:19:08 +0200 Subject: [PATCH 420/565] fix for https://github.com/Neilpang/acme.sh/issues/2286 --- acme.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/acme.sh b/acme.sh index 60580f8..eb2194a 100755 --- a/acme.sh +++ b/acme.sh @@ -4338,6 +4338,8 @@ $_authorizations_map" if [ "$status" = "pending" ]; then _info "Pending" + elif [ "$status" = "processing" ]; then + _info "Processing" else _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" From 2cb0b00e3acb6f1530a811b2e0eda32d628771b6 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Thu, 23 May 2019 18:11:25 -0400 Subject: [PATCH 421/565] replace _read_conf() with _readaccountconf() --- dnsapi/dns_freedns.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 71c6aa8..5928837 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -92,8 +92,7 @@ dns_freedns_rm() { # Need to read cookie from conf file again in case new value set # during login to FreeDNS when TXT record was created. - # acme.sh does not have a _readaccountconf() function - FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")" + FREEDNS_COOKIE="$(_readaccountconf "FREEDNS_COOKIE")" _debug "FreeDNS login cookies: $FREEDNS_COOKIE" TXTdataid="$(_freedns_data_id "$fulldomain" "TXT")" From a3089a719f8dcd2be92ee8c236671cfc7d5ac5f6 Mon Sep 17 00:00:00 2001 From: der-berni Date: Fri, 24 May 2019 09:44:13 +0200 Subject: [PATCH 422/565] Updated to work with curl Now works with curl. Check the root domain. --- dnsapi/dns_one.sh | 153 ++++++++++++++++++---------------------------- 1 file changed, 61 insertions(+), 92 deletions(-) diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh index a237a0d..a77603e 100644 --- a/dnsapi/dns_one.sh +++ b/dnsapi/dns_one.sh @@ -16,16 +16,17 @@ # only single domain supported atm dns_one_add() { - #rev command not found on OpenWrt - #mysubdomain=$(printf -- "%s" "$1" | rev | cut -d"." -f3- | rev) - #mydomain=$(printf -- "%s" "$1" | rev | cut -d"." -f1-2 | rev) - fulldomain=$1 txtvalue=$2 - _debug "First detect the root zone" + if ! _dns_one_login; then + _err "login failed" + return 1 + fi + + _debug "detect the root domain" if ! _get_root "$fulldomain"; then - _err "invalid domain" + _err "root domain not found" return 1 fi @@ -33,50 +34,11 @@ dns_one_add() { mydomain=$_domain _debug mysubdomain "$mysubdomain" _debug mydomain "$mydomain" - - # get credentials - ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}" - ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}" - if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then - ONECOM_User="" - ONECOM_Password="" - _err "You didn't specify a one.com username and password yet." - _err "Please create the key and try again." - return 1 - fi - - #save the api key and email to the account conf file. - _saveaccountconf_mutable ONECOM_User "$ONECOM_User" - _saveaccountconf_mutable ONECOM_Password "$ONECOM_Password" - - # Login with user and password - postdata="loginDomain=true" - postdata="$postdata&displayUsername=$ONECOM_User" - postdata="$postdata&username=$ONECOM_User" - postdata="$postdata&targetDomain=$mydomain" - postdata="$postdata&password1=$ONECOM_Password" - postdata="$postdata&loginTarget=" - #_debug postdata "$postdata" - #CURL does not work - local tmp_USE_WGET=$ACME_USE_WGET - ACME_USE_WGET=1 - - response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST" "application/x-www-form-urlencoded")" - #_debug response "$response" - - JSESSIONID="$(grep "OneSIDCrmAdmin" "$HTTP_HEADER" | grep "^[Ss]et-[Cc]ookie:" | _tail_n 1 | _egrep_o 'OneSIDCrmAdmin=[^;]*;' | tr -d ';')" - _debug jsessionid "$JSESSIONID" - - export _H1="Cookie: ${JSESSIONID}" - # get entries response="$(_get "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records")" _debug response "$response" - #CSRF_G_TOKEN="$(grep "CSRF_G_TOKEN=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'CSRF_G_TOKEN=[^;]*;' | tr -d ';')" - #export _H2="Cookie: ${CSRF_G_TOKEN}" - # Update the IP address for domain entry postdata="{\"type\":\"dns_custom_records\",\"attributes\":{\"priority\":0,\"ttl\":600,\"type\":\"TXT\",\"prefix\":\"$mysubdomain\",\"content\":\"$txtvalue\"}}" _debug postdata "$postdata" @@ -86,8 +48,6 @@ dns_one_add() { id=$(echo "$response" | sed -n "s/{\"result\":{\"data\":{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$mysubdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}}},\"metadata\":null}/\1/p") - ACME_USE_WGET=$tmp_USE_WGET - if [ -z "$id" ]; then _err "Add txt record error." return 1 @@ -99,16 +59,17 @@ dns_one_add() { } dns_one_rm() { - #rev command not found on OpenWrt - #mysubdomain=$(printf -- "%s" "$1" | rev | cut -d"." -f3- | rev) - #mydomain=$(printf -- "%s" "$1" | rev | cut -d"." -f1-2 | rev) - fulldomain=$1 txtvalue=$2 - _debug "First detect the root zone" + if ! _dns_one_login; then + _err "login failed" + return 1 + fi + + _debug "detect the root domain" if ! _get_root "$fulldomain"; then - _err "invalid domain" + _err "root domain not found" return 1 fi @@ -116,51 +77,16 @@ dns_one_rm() { mydomain=$_domain _debug mysubdomain "$mysubdomain" _debug mydomain "$mydomain" - - # get credentials - ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}" - ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}" - if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then - ONECOM_User="" - ONECOM_Password="" - _err "You didn't specify a one.com username and password yet." - _err "Please create the key and try again." - return 1 - fi - - # Login with user and password - postdata="loginDomain=true" - postdata="$postdata&displayUsername=$ONECOM_User" - postdata="$postdata&username=$ONECOM_User" - postdata="$postdata&targetDomain=$mydomain" - postdata="$postdata&password1=$ONECOM_Password" - postdata="$postdata&loginTarget=" - - #CURL does not work - local tmp_USE_WGET=$ACME_USE_WGET - ACME_USE_WGET=1 - response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST" "application/x-www-form-urlencoded")" - #_debug response "$response" - - JSESSIONID="$(grep "OneSIDCrmAdmin" "$HTTP_HEADER" | grep "^[Ss]et-[Cc]ookie:" | _tail_n 1 | _egrep_o 'OneSIDCrmAdmin=[^;]*;' | tr -d ';')" - _debug jsessionid "$JSESSIONID" - - export _H1="Cookie: ${JSESSIONID}" - # get entries response="$(_get "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records")" response="$(echo "$response" | _normalizeJson)" _debug response "$response" - #CSRF_G_TOKEN="$(grep "CSRF_G_TOKEN=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'CSRF_G_TOKEN=[^;]*;' | tr -d ';')" - #export _H2="Cookie: ${CSRF_G_TOKEN}" - id=$(printf -- "%s" "$response" | sed -n "s/.*{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$mysubdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}.*/\1/p") if [ -z "$id" ]; then _err "Txt record not found." - ACME_USE_WGET=$tmp_USE_WGET return 1 fi @@ -169,8 +95,6 @@ dns_one_rm() { response="$(echo "$response" | _normalizeJson)" _debug response "$response" - ACME_USE_WGET=$tmp_USE_WGET - if [ "$response" = '{"result":null,"metadata":null}' ]; then _info "Removed, OK" return 0 @@ -196,8 +120,10 @@ _get_root() { #not valid return 1 fi - - if [ "$(printf "%s" "$h" | tr '.' ' ' | wc -w)" = "2" ]; then + + response="$(_get "https://www.one.com/admin/api/domains/$h/dns/custom_records")" + + if ! _contains "$response" "CRMRST_000302" ; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain="$h" return 0 @@ -208,3 +134,46 @@ _get_root() { _err "Unable to parse this domain" return 1 } + +_dns_one_login() { + + # get credentials + ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}" + ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}" + if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then + ONECOM_User="" + ONECOM_Password="" + _err "You didn't specify a one.com username and password yet." + _err "Please create the key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable ONECOM_User "$ONECOM_User" + _saveaccountconf_mutable ONECOM_Password "$ONECOM_Password" + + # Login with user and password + postdata="loginDomain=true" + postdata="$postdata&displayUsername=$ONECOM_User" + postdata="$postdata&username=$ONECOM_User" + postdata="$postdata&targetDomain=" + postdata="$postdata&password1=$ONECOM_Password" + postdata="$postdata&loginTarget=" + #_debug postdata "$postdata" + + response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST" "application/x-www-form-urlencoded")" + #_debug response "$response" + + # Get SessionID + JSESSIONID="$(grep "OneSIDCrmAdmin" "$HTTP_HEADER" | grep "^[Ss]et-[Cc]ookie:" | _head_n 1 | _egrep_o 'OneSIDCrmAdmin=[^;]*;' | tr -d ';')" + _debug jsessionid "$JSESSIONID" + + if [ -z "$JSESSIONID" ]; then + _err "error sessionid cookie not found" + return 1 + fi + + export _H1="Cookie: ${JSESSIONID}" + + return 0 + } From 815230943543fe74205e1a23ddbf1e575a30e6e5 Mon Sep 17 00:00:00 2001 From: Awal Garg Date: Tue, 26 Mar 2019 12:18:53 +0530 Subject: [PATCH 423/565] Add support for MaraDNS MaraDNS is a lightweight self-hosting DNS server. This patch adds support for adding records to zone files stored on the server in the format expected by MaraDNS. Path to the file should be exported in MARA_ZONE_FILE environment variable. To reload the configuration automatically, the user must provide path to the pid file of duende (the daemonization tool that ships with MaraDNS) in MARA_DUENDE_PID_PATH (--pid argument to duende). --- dnsapi/dns_maradns.sh | 69 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100755 dnsapi/dns_maradns.sh diff --git a/dnsapi/dns_maradns.sh b/dnsapi/dns_maradns.sh new file mode 100755 index 0000000..4ff6ca2 --- /dev/null +++ b/dnsapi/dns_maradns.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env sh + +#Usage: dns_maradns_add _acme-challenge.www.domain.com "token" +dns_maradns_add() { + fulldomain="$1" + txtvalue="$2" + + MARA_ZONE_FILE="${MARA_ZONE_FILE:-$(_readaccountconf_mutable MARA_ZONE_FILE)}" + MARA_DUENDE_PID_PATH="${MARA_DUENDE_PID_PATH:-$(_readaccountconf_mutable MARA_DUENDE_PID_PATH)}" + + _check_zone_file "$MARA_ZONE_FILE" || return 1 + _check_duende_pid_path "$MARA_DUENDE_PID_PATH" || return 1 + + _saveaccountconf_mutable MARA_ZONE_FILE "$MARA_ZONE_FILE" + _saveaccountconf_mutable MARA_DUENDE_PID_PATH "$MARA_DUENDE_PID_PATH" + + printf "%s. TXT '%s' ~\n" "$fulldomain" "$txtvalue" >>"$MARA_ZONE_FILE" + _reload_maradns "$MARA_DUENDE_PID_PATH" || return 1 +} + +#Usage: dns_maradns_rm _acme-challenge.www.domain.com "token" +dns_maradns_rm() { + fulldomain="$1" + txtvalue="$2" + + MARA_ZONE_FILE="${MARA_ZONE_FILE:-$(_readaccountconf_mutable MARA_ZONE_FILE)}" + MARA_DUENDE_PID_PATH="${MARA_DUENDE_PID_PATH:-$(_readaccountconf_mutable MARA_DUENDE_PID_PATH)}" + + _check_zone_file "$MARA_ZONE_FILE" || return 1 + _check_duende_pid_path "$MARA_DUENDE_PID_PATH" || return 1 + + _saveaccountconf_mutable MARA_ZONE_FILE "$MARA_ZONE_FILE" + _saveaccountconf_mutable MARA_DUENDE_PID_PATH "$MARA_DUENDE_PID_PATH" + + _sed_i "/^$fulldomain.\+TXT '$txtvalue' ~/d" "$MARA_ZONE_FILE" + _reload_maradns "$MARA_DUENDE_PID_PATH" || return 1 +} + +_check_zone_file() { + zonefile="$1" + if [ -z "$zonefile" ]; then + _err "MARA_ZONE_FILE not passed!" + return 1 + elif [ ! -w "$zonefile" ]; then + _err "MARA_ZONE_FILE not writable: $zonefile" + return 1 + fi +} + +_check_duende_pid_path() { + pidpath="$1" + if [ -z "$pidpath" ]; then + _err "MARA_DUENDE_PID_PATH not passed!" + return 1 + fi + if [ ! -r "$pidpath" ]; then + _err "MARA_DUENDE_PID_PATH not readable: $pidpath" + return 1 + fi +} + +_reload_maradns() { + pidpath="$1" + kill -s HUP -- "$(cat "$pidpath")" + if [ $? -ne 0 ]; then + _err "Unable to reload MaraDNS, kill returned $?" + return 1 + fi +} From 0cddc8a154ea137c2e49193a91e9bf72d86356f6 Mon Sep 17 00:00:00 2001 From: Charlie Garrison Date: Sun, 26 May 2019 01:32:13 +1000 Subject: [PATCH 424/565] change to routeros native script rather than bash multiline commands --- deploy/routeros.sh | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/deploy/routeros.sh b/deploy/routeros.sh index b22c64f..aa7f976 100644 --- a/deploy/routeros.sh +++ b/deploy/routeros.sh @@ -86,29 +86,23 @@ routeros_deploy() { _info "Trying to push cert '$_cfullchain' to router" scp "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer" # shellcheck disable=SC2029 - ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" bash -c "' + ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=\ + ftp,read,write,password,sensitive source=\"## generated by routeros deploy script in acme.sh \\r\ + \n/certificate remove [ find name=$_cdomain.cer_0 ]\\r\ + \n/certificate remove [ find name=$_cdomain.cer_1 ]\\r\ + \ndelay 1\\r\ + \n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\"\\r\ + \n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\"\\r\ + \ndelay 1\\r\ + \n/file remove $_cdomain.cer\\r\ + \n/file remove $_cdomain.key\\r\ + \ndelay 2\\r\ + \n/ip service set www-ssl certificate=$_cdomain.cer_0\\r\ + \n$ROUTER_OS_ADDITIONAL_SERVICES\\r\ + \n\" + " + ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script run \"LE Cert Deploy - $_cdomain\"" + ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script remove \"LE Cert Deploy - $_cdomain\"" -/certificate remove $_cdomain.cer_0 - -/certificate remove $_cdomain.cer_1 - -delay 1 - -/certificate import file-name=$_cdomain.cer passphrase=\"\" - -/certificate import file-name=$_cdomain.key passphrase=\"\" - -delay 1 - -/file remove $_cdomain.cer - -/file remove $_cdomain.key - -delay 2 - -/ip service set www-ssl certificate=$_cdomain.cer_0 -$ROUTER_OS_ADDITIONAL_SERVICES - -'" return 0 } From 89e73594eb04dbc3ca4eaed3acacc0b59b4e5a60 Mon Sep 17 00:00:00 2001 From: der-berni Date: Sat, 25 May 2019 17:35:40 +0200 Subject: [PATCH 425/565] fixed error in CI --- dnsapi/dns_one.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh index a77603e..74db40b 100644 --- a/dnsapi/dns_one.sh +++ b/dnsapi/dns_one.sh @@ -123,7 +123,7 @@ _get_root() { response="$(_get "https://www.one.com/admin/api/domains/$h/dns/custom_records")" - if ! _contains "$response" "CRMRST_000302" ; then + if ! _contains "$response" "CRMRST_000302"; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain="$h" return 0 From 51447961cbc7350a77052d3fab12381986573832 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Mon, 27 May 2019 16:45:44 +0200 Subject: [PATCH 426/565] Notify mail update (#2293) * feat: disable e-mail validation if MAIL_NOVALIDATE is set * fix: expose _MAIL_BIN variable * fix: call _mail_body and _mail_cmnd directly to make sure that all used variables are exposed * fix: update notify/mail.sh Co-Authored-By: Matej Mihevc * fix: remove useless echo, quote eval --- notify/mail.sh | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/notify/mail.sh b/notify/mail.sh index dbecc3a..ec9aa0d 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -5,6 +5,7 @@ #MAIL_BIN="sendmail" #MAIL_FROM="yyyy@gmail.com" #MAIL_TO="yyyy@gmail.com" +#MAIL_NOVALIDATE="" mail_send() { _subject="$1" @@ -14,22 +15,28 @@ mail_send() { _debug "_content" "$_content" _debug "_statusCode" "$_statusCode" + MAIL_NOVALIDATE="${MAIL_NOVALIDATE:-$(_readaccountconf_mutable MAIL_NOVALIDATE)}" + if [ -n "$MAIL_NOVALIDATE" ]; then + _saveaccountconf_mutable MAIL_NOVALIDATE 1 + else + _clearaccountconf "MAIL_NOVALIDATE" + fi + MAIL_BIN="${MAIL_BIN:-$(_readaccountconf_mutable MAIL_BIN)}" if [ -n "$MAIL_BIN" ] && ! _exists "$MAIL_BIN"; then _err "It seems that the command $MAIL_BIN is not in path." return 1 fi - _MAIL_CMD=$(_mail_cmnd) + _MAIL_BIN=$(_mail_bin) if [ -n "$MAIL_BIN" ]; then _saveaccountconf_mutable MAIL_BIN "$MAIL_BIN" else _clearaccountconf "MAIL_BIN" fi - _MAIL_BODY=$(_mail_body) MAIL_FROM="${MAIL_FROM:-$(_readaccountconf_mutable MAIL_FROM)}" if [ -n "$MAIL_FROM" ]; then - if ! _contains "$MAIL_FROM" "@"; then + if ! _mail_valid "$MAIL_FROM"; then _err "It seems that the MAIL_FROM=$MAIL_FROM is not a valid email address." return 1 fi @@ -39,7 +46,7 @@ mail_send() { MAIL_TO="${MAIL_TO:-$(_readaccountconf_mutable MAIL_TO)}" if [ -n "$MAIL_TO" ]; then - if ! _contains "$MAIL_TO" "@"; then + if ! _mail_valid "$MAIL_TO"; then _err "It seems that the MAIL_TO=$MAIL_TO is not a valid email address." return 1 fi @@ -55,8 +62,9 @@ mail_send() { contenttype="text/plain; charset=utf-8" subject="=?UTF-8?B?$(echo "$_subject" | _base64)?=" - result=$({ echo "$_MAIL_BODY" | eval "$_MAIL_CMD"; } 2>&1) + result=$({ _mail_body | eval "$(_mail_cmnd)"; } 2>&1) + # shellcheck disable=SC2181 if [ $? -ne 0 ]; then _debug "mail send error." _err "$result" @@ -67,7 +75,7 @@ mail_send() { return 0 } -_mail_cmnd() { +_mail_bin() { if [ -n "$MAIL_BIN" ]; then _MAIL_BIN="$MAIL_BIN" elif _exists "sendmail"; then @@ -83,6 +91,10 @@ _mail_cmnd() { return 1 fi + echo "$_MAIL_BIN" +} + +_mail_cmnd() { case $(basename "$_MAIL_BIN") in sendmail) if [ -n "$MAIL_FROM" ]; then @@ -105,16 +117,22 @@ _mail_cmnd() { } _mail_body() { - if [ "$_MAIL_BIN" = "sendmail" ] || [ "$_MAIL_BIN" = "ssmtp" ]; then - if [ -n "$MAIL_FROM" ]; then - echo "From: $MAIL_FROM" - fi + case $(basename "$_MAIL_BIN") in + sendmail | ssmtp) + if [ -n "$MAIL_FROM" ]; then + echo "From: $MAIL_FROM" + fi - echo "To: $MAIL_TO" - echo "Subject: $subject" - echo "Content-Type: $contenttype" - echo - fi + echo "To: $MAIL_TO" + echo "Subject: $subject" + echo "Content-Type: $contenttype" + echo + ;; + esac echo "$_content" } + +_mail_valid() { + [ -n "$MAIL_NOVALIDATE" ] || _contains "$1" "@" +} From 09bce5e6d6be6b97b3c843b815087874e3e44a21 Mon Sep 17 00:00:00 2001 From: neil <8305679+Neilpang@users.noreply.github.com> Date: Tue, 28 May 2019 08:47:33 +0800 Subject: [PATCH 427/565] sync (#2297) * Create LICENSE.md * remove _hostingde_parse_no_strip_whitespace function as this breaks API requests * Fix sessionid parsing on BSD * Make travis happy. (SC2020) * fix for https://github.com/Neilpang/acme.sh/issues/2286 * Notify mail update (#2293) * feat: disable e-mail validation if MAIL_NOVALIDATE is set * fix: expose _MAIL_BIN variable * fix: call _mail_body and _mail_cmnd directly to make sure that all used variables are exposed * fix: update notify/mail.sh Co-Authored-By: Matej Mihevc * fix: remove useless echo, quote eval --- LICENSE.md | 674 ++++++++++++++++++++++++++++++++++++++++ acme.sh | 2 + dnsapi/dns_hostingde.sh | 16 +- dnsapi/dns_netcup.sh | 2 +- notify/mail.sh | 48 ++- 5 files changed, 712 insertions(+), 30 deletions(-) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/acme.sh b/acme.sh index 60580f8..eb2194a 100755 --- a/acme.sh +++ b/acme.sh @@ -4338,6 +4338,8 @@ $_authorizations_map" if [ "$status" = "pending" ]; then _info "Pending" + elif [ "$status" = "processing" ]; then + _info "Processing" else _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" diff --git a/dnsapi/dns_hostingde.sh b/dnsapi/dns_hostingde.sh index 1aa7039..9e3e566 100644 --- a/dnsapi/dns_hostingde.sh +++ b/dnsapi/dns_hostingde.sh @@ -53,18 +53,6 @@ _hostingde_parse() { fi } -_hostingde_parse_no_strip_whitespace() { - 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 - else - _egrep_o \""${find}\":.*" | cut -d ':' -f 2 | cut -d ',' -f 1 - fi -} - _hostingde_getZoneConfig() { _info "Getting ZoneConfig" curZone="${fulldomain#*.}" @@ -97,12 +85,12 @@ _hostingde_getZoneConfig() { zoneConfigDnsServerGroupId=$(echo "${curResult}" | _hostingde_parse "dnsServerGroupId") zoneConfigEmailAddress=$(echo "${curResult}" | _hostingde_parse "emailAddress") zoneConfigDnsSecMode=$(echo "${curResult}" | _hostingde_parse "dnsSecMode") - zoneConfigTemplateValues=$(echo "${curResult}" | _hostingde_parse_no_strip_whitespace "templateValues") + zoneConfigTemplateValues=$(echo "${curResult}" | _hostingde_parse "templateValues") if [ "$zoneConfigTemplateValues" != "null" ]; then _debug "Zone is tied to a template." zoneConfigTemplateValuesTemplateId=$(echo "${curResult}" | _hostingde_parse "templateId") - zoneConfigTemplateValuesTemplateName=$(echo "${curResult}" | _hostingde_parse_no_strip_whitespace "templateName") + zoneConfigTemplateValuesTemplateName=$(echo "${curResult}" | _hostingde_parse "templateName") zoneConfigTemplateValuesTemplateReplacementsIPv4=$(echo "${curResult}" | _hostingde_parse "ipv4Replacement") zoneConfigTemplateValuesTemplateReplacementsIPv6=$(echo "${curResult}" | _hostingde_parse "ipv6Replacement") zoneConfigTemplateValuesTemplateReplacementsMailIPv4=$(echo "${curResult}" | _hostingde_parse "mailIpv4Replacement") diff --git a/dnsapi/dns_netcup.sh b/dnsapi/dns_netcup.sh index d5d7c22..d519e4f 100644 --- a/dnsapi/dns_netcup.sh +++ b/dnsapi/dns_netcup.sh @@ -117,7 +117,7 @@ dns_netcup_rm() { 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') + sid=$(echo "$tmp" | tr '{}' '\n' | grep apisessionid | cut -d '"' -f 4) _debug "$tmp" if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then _err "$msg" diff --git a/notify/mail.sh b/notify/mail.sh index dbecc3a..ec9aa0d 100644 --- a/notify/mail.sh +++ b/notify/mail.sh @@ -5,6 +5,7 @@ #MAIL_BIN="sendmail" #MAIL_FROM="yyyy@gmail.com" #MAIL_TO="yyyy@gmail.com" +#MAIL_NOVALIDATE="" mail_send() { _subject="$1" @@ -14,22 +15,28 @@ mail_send() { _debug "_content" "$_content" _debug "_statusCode" "$_statusCode" + MAIL_NOVALIDATE="${MAIL_NOVALIDATE:-$(_readaccountconf_mutable MAIL_NOVALIDATE)}" + if [ -n "$MAIL_NOVALIDATE" ]; then + _saveaccountconf_mutable MAIL_NOVALIDATE 1 + else + _clearaccountconf "MAIL_NOVALIDATE" + fi + MAIL_BIN="${MAIL_BIN:-$(_readaccountconf_mutable MAIL_BIN)}" if [ -n "$MAIL_BIN" ] && ! _exists "$MAIL_BIN"; then _err "It seems that the command $MAIL_BIN is not in path." return 1 fi - _MAIL_CMD=$(_mail_cmnd) + _MAIL_BIN=$(_mail_bin) if [ -n "$MAIL_BIN" ]; then _saveaccountconf_mutable MAIL_BIN "$MAIL_BIN" else _clearaccountconf "MAIL_BIN" fi - _MAIL_BODY=$(_mail_body) MAIL_FROM="${MAIL_FROM:-$(_readaccountconf_mutable MAIL_FROM)}" if [ -n "$MAIL_FROM" ]; then - if ! _contains "$MAIL_FROM" "@"; then + if ! _mail_valid "$MAIL_FROM"; then _err "It seems that the MAIL_FROM=$MAIL_FROM is not a valid email address." return 1 fi @@ -39,7 +46,7 @@ mail_send() { MAIL_TO="${MAIL_TO:-$(_readaccountconf_mutable MAIL_TO)}" if [ -n "$MAIL_TO" ]; then - if ! _contains "$MAIL_TO" "@"; then + if ! _mail_valid "$MAIL_TO"; then _err "It seems that the MAIL_TO=$MAIL_TO is not a valid email address." return 1 fi @@ -55,8 +62,9 @@ mail_send() { contenttype="text/plain; charset=utf-8" subject="=?UTF-8?B?$(echo "$_subject" | _base64)?=" - result=$({ echo "$_MAIL_BODY" | eval "$_MAIL_CMD"; } 2>&1) + result=$({ _mail_body | eval "$(_mail_cmnd)"; } 2>&1) + # shellcheck disable=SC2181 if [ $? -ne 0 ]; then _debug "mail send error." _err "$result" @@ -67,7 +75,7 @@ mail_send() { return 0 } -_mail_cmnd() { +_mail_bin() { if [ -n "$MAIL_BIN" ]; then _MAIL_BIN="$MAIL_BIN" elif _exists "sendmail"; then @@ -83,6 +91,10 @@ _mail_cmnd() { return 1 fi + echo "$_MAIL_BIN" +} + +_mail_cmnd() { case $(basename "$_MAIL_BIN") in sendmail) if [ -n "$MAIL_FROM" ]; then @@ -105,16 +117,22 @@ _mail_cmnd() { } _mail_body() { - if [ "$_MAIL_BIN" = "sendmail" ] || [ "$_MAIL_BIN" = "ssmtp" ]; then - if [ -n "$MAIL_FROM" ]; then - echo "From: $MAIL_FROM" - fi + case $(basename "$_MAIL_BIN") in + sendmail | ssmtp) + if [ -n "$MAIL_FROM" ]; then + echo "From: $MAIL_FROM" + fi - echo "To: $MAIL_TO" - echo "Subject: $subject" - echo "Content-Type: $contenttype" - echo - fi + echo "To: $MAIL_TO" + echo "Subject: $subject" + echo "Content-Type: $contenttype" + echo + ;; + esac echo "$_content" } + +_mail_valid() { + [ -n "$MAIL_NOVALIDATE" ] || _contains "$1" "@" +} From 145b1f4fb3cbeafa167d86f8f6004df194e5cd55 Mon Sep 17 00:00:00 2001 From: Kay Roepke Date: Tue, 28 May 2019 13:46:19 +0200 Subject: [PATCH 428/565] Improve compatibility with *BSD xargs The --no-run-if-empty option is a GNU extension and the long version isn't supported by *BSD variants. Instead use the short version (-r) which is present, but ignored as it is the default behavior, in at least FreeBSD: https://www.freebsd.org/cgi/man.cgi?xargs --- 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 c2ead9a..ebbeecf 100755 --- a/dnsapi/dns_gcloud.sh +++ b/dnsapi/dns_gcloud.sh @@ -93,7 +93,7 @@ _dns_gcloud_execute_tr() { } _dns_gcloud_remove_rrs() { - if ! xargs --no-run-if-empty gcloud dns record-sets transaction remove \ + if ! xargs -r gcloud dns record-sets transaction remove \ --name="$fulldomain." \ --ttl="$ttl" \ --type=TXT \ @@ -108,7 +108,7 @@ _dns_gcloud_remove_rrs() { _dns_gcloud_add_rrs() { ttl=60 - if ! xargs --no-run-if-empty gcloud dns record-sets transaction add \ + if ! xargs -r gcloud dns record-sets transaction add \ --name="$fulldomain." \ --ttl="$ttl" \ --type=TXT \ From 03a407d4dfefb41eb35693c74d45a49d125df83a Mon Sep 17 00:00:00 2001 From: Charlie Garrison Date: Wed, 29 May 2019 14:05:20 +1000 Subject: [PATCH 429/565] Added additional `shellcheck` ignores for client-side evaluation warning Should pass CI tests now --- deploy/routeros.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deploy/routeros.sh b/deploy/routeros.sh index aa7f976..035e13a 100644 --- a/deploy/routeros.sh +++ b/deploy/routeros.sh @@ -101,7 +101,9 @@ routeros_deploy() { \n$ROUTER_OS_ADDITIONAL_SERVICES\\r\ \n\" " + # shellcheck disable=SC2029 ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script run \"LE Cert Deploy - $_cdomain\"" + # shellcheck disable=SC2029 ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script remove \"LE Cert Deploy - $_cdomain\"" return 0 From 937d5b5472a85f998177a00547327f144d2b7fcd Mon Sep 17 00:00:00 2001 From: der-berni Date: Fri, 31 May 2019 08:26:48 +0200 Subject: [PATCH 430/565] try to remove errors in travis-ci --- dnsapi/dns_one.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh index 74db40b..68f54ed 100644 --- a/dnsapi/dns_one.sh +++ b/dnsapi/dns_one.sh @@ -5,7 +5,7 @@ # Author: github: @diseq # Created: 2019-02-17 # Fixed by: @der-berni -# Modified: 2019-05-20 +# Modified: 2019-05-31 # # export ONECOM_User="username" # export ONECOM_Password="password" @@ -18,7 +18,7 @@ dns_one_add() { fulldomain=$1 txtvalue=$2 - + if ! _dns_one_login; then _err "login failed" return 1 @@ -29,12 +29,12 @@ dns_one_add() { _err "root domain not found" return 1 fi - + mysubdomain=$_sub_domain mydomain=$_domain _debug mysubdomain "$mysubdomain" _debug mydomain "$mydomain" - + # get entries response="$(_get "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records")" _debug response "$response" @@ -47,7 +47,7 @@ dns_one_add() { _debug response "$response" id=$(echo "$response" | sed -n "s/{\"result\":{\"data\":{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$mysubdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}}},\"metadata\":null}/\1/p") - + if [ -z "$id" ]; then _err "Add txt record error." return 1 @@ -61,7 +61,7 @@ dns_one_add() { dns_one_rm() { fulldomain=$1 txtvalue=$2 - + if ! _dns_one_login; then _err "login failed" return 1 @@ -72,12 +72,12 @@ dns_one_rm() { _err "root domain not found" return 1 fi - + mysubdomain=$_sub_domain mydomain=$_domain _debug mysubdomain "$mysubdomain" _debug mydomain "$mydomain" - + # get entries response="$(_get "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records")" response="$(echo "$response" | _normalizeJson)" @@ -94,7 +94,7 @@ dns_one_rm() { response="$(_post "$postdata" "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records/$id" "" "DELETE" "application/json")" response="$(echo "$response" | _normalizeJson)" _debug response "$response" - + if [ "$response" = '{"result":null,"metadata":null}' ]; then _info "Removed, OK" return 0 @@ -176,4 +176,4 @@ _dns_one_login() { export _H1="Cookie: ${JSESSIONID}" return 0 - } +} From 1a5279bd6e8773786b388fc31def1c21da6ec2c7 Mon Sep 17 00:00:00 2001 From: der-berni Date: Fri, 31 May 2019 08:55:21 +0200 Subject: [PATCH 432/565] cleanup according to styleguide --- dnsapi/dns_one.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_one.sh b/dnsapi/dns_one.sh index 68f54ed..0fdc3d5 100644 --- a/dnsapi/dns_one.sh +++ b/dnsapi/dns_one.sh @@ -110,19 +110,19 @@ dns_one_rm() { # _sub_domain=_acme-challenge.www # _domain=domain.com _get_root() { - domain=$1 + 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 - + response="$(_get "https://www.one.com/admin/api/domains/$h/dns/custom_records")" - + if ! _contains "$response" "CRMRST_000302"; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain="$h" @@ -160,20 +160,20 @@ _dns_one_login() { postdata="$postdata&password1=$ONECOM_Password" postdata="$postdata&loginTarget=" #_debug postdata "$postdata" - + response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST" "application/x-www-form-urlencoded")" #_debug response "$response" - + # Get SessionID JSESSIONID="$(grep "OneSIDCrmAdmin" "$HTTP_HEADER" | grep "^[Ss]et-[Cc]ookie:" | _head_n 1 | _egrep_o 'OneSIDCrmAdmin=[^;]*;' | tr -d ';')" _debug jsessionid "$JSESSIONID" - + if [ -z "$JSESSIONID" ]; then _err "error sessionid cookie not found" return 1 fi - + export _H1="Cookie: ${JSESSIONID}" - + return 0 } From 561803c0a75a73abe3a392c080d6678b84a31891 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 1 Jun 2019 22:30:25 +0800 Subject: [PATCH 433/565] add deploy hook to docker containers --- Dockerfile | 1 + deploy/docker.sh | 264 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100755 deploy/docker.sh diff --git a/Dockerfile b/Dockerfile index 0e8b58d..8a7fd03 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,7 @@ RUN apk update -f \ curl \ socat \ tzdata \ + tar \ && rm -rf /var/cache/apk/* ENV LE_CONFIG_HOME /acme.sh diff --git a/deploy/docker.sh b/deploy/docker.sh new file mode 100755 index 0000000..57081cc --- /dev/null +++ b/deploy/docker.sh @@ -0,0 +1,264 @@ +#!/usr/bin/env sh + +#DEPLOY_DOCKER_CONTAINER_LABEL="xxxxxxx" +#DOCKER_HOST=/var/run/docker.sock | tcp://localhost:8888 + + +#DEPLOY_DOCKER_CONTAINER_KEY_FILE="/path/to/key.pem" +#DEPLOY_DOCKER_CONTAINER_CERT_FILE="/path/to/cert.pem" +#DEPLOY_DOCKER_CONTAINER_CA_FILE="/path/to/ca.pem" +#DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/path/to/fullchain.pem" +#DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="service nginx force-reload" + +_DEPLOY_DOCKER_WIKI="http://xxxxxx" + +_DOCKER_HOST_DEFAULT="/var/run/docker.sock" + +docker_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + if [ -z "$DEPLOY_DOCKER_CONTAINER_LABEL" ]; then + _err "The DEPLOY_DOCKER_CONTAINER_LABEL variable is not defined, we use this label to find the container." + _err "See: $_DEPLOY_DOCKER_WIKI" + fi + + _savedomainconf DEPLOY_DOCKER_CONTAINER_LABEL "$DEPLOY_DOCKER_CONTAINER_LABEL" + + if [ "$DOCKER_HOST" ]; then + _saveaccountconf DOCKER_HOST "$DOCKER_HOST" + fi + + if _exists docker && docker version | grep -i docker >/dev/null; then + _info "Using docker command" + export _USE_DOCKER_COMMAND=1 + else + export _USE_DOCKER_COMMAND= + fi + + export _USE_UNIX_SOCKET= + if [ -z "$_USE_DOCKER_COMMAND" ]; then + export _USE_REST= + if [ "$DOCKER_HOST" ]; then + _debug "Try use docker host: $DOCKER_HOST" + export _USE_REST=1 + else + export _DOCKER_SOCK="$_DOCKER_HOST_DEFAULT" + _debug "Try use $_DOCKER_SOCK" + if [ ! -e "$_DOCKER_SOCK" ] || [ ! -w "$_DOCKER_SOCK" ]; then + _err "$_DOCKER_SOCK is not available" + return 1 + fi + export _USE_UNIX_SOCKET=1 + if ! _exists "curl"; then + _err "Please install curl first." + _err "We need curl to work." + return 1 + fi + if ! _check_curl_version; then + return 1 + fi + fi + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" ]; then + _savedomainconf DEPLOY_DOCKER_CONTAINER_KEY_FILE "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" ]; then + _savedomainconf DEPLOY_DOCKER_CONTAINER_CERT_FILE "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_CA_FILE" ]; then + _savedomainconf DEPLOY_DOCKER_CONTAINER_CA_FILE "$DEPLOY_DOCKER_CONTAINER_CA_FILE" + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" ]; then + _savedomainconf DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then + _savedomainconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" + fi + + _cid="$(_get_id "$DEPLOY_DOCKER_CONTAINER_LABEL")" + _info "Container id: $_cid" + if [ -z "$_cid" ]; then + _err "can not find container id" + return 1 + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" ]; then + if ! _docker_cp "$_cid" "$_ckey" "$DEPLOY_DOCKER_CONTAINER_KEY_FILE"; then + return 1 + fi + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" ]; then + if ! _docker_cp "$_cid" "$_ccert" "$DEPLOY_DOCKER_CONTAINER_CERT_FILE"; then + return 1 + fi + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_CA_FILE" ]; then + if ! _docker_cp "$_cid" "$_cca" "$DEPLOY_DOCKER_CONTAINER_CA_FILE"; then + return 1 + fi + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" ]; then + if ! _docker_cp "$_cid" "$_cfullchain" "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE"; then + return 1 + fi + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then + if ! _docker_exec "$_cid" "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"; then + return 1 + fi + fi + return 0 +} + +#label +_get_id() { + _label="$1" + if [ "$_USE_DOCKER_COMMAND" ]; then + docker ps -f label="$_label" --format "{{.ID}}" + elif [ "$_USE_REST" ]; then + _err "Not implemented yet." + return 1 + elif [ "$_USE_UNIX_SOCKET" ]; then + _req="{\"label\":[\"$_label\"]}" + _debug2 _req "$_req" + _req="$(printf "%s" "$_req" | _url_encode)" + _debug2 _req "$_req" + listjson="$(_curl_unix_sock "${_DOCKER_SOCK:-$_DOCKER_HOST_DEFAULT}" GET "/containers/json?filters=$_req")" + _debug2 "listjson" "$listjson" + echo "$listjson" | tr '{,' '\n' | grep -i '"id":' | _head_n 1 | cut -d '"' -f 4 + else + _err "Not implemented yet." + return 1 + fi +} + +#id cmd +_docker_exec() { + _eargs="$@" + _debug2 "_docker_exec $_eargs" + _dcid="$1" + shift + if [ "$_USE_DOCKER_COMMAND" ]; then + docker exec -i "$_dcid" $@ + elif [ "$_USE_REST" ]; then + _err "Not implemented yet." + return 1 + elif [ "$_USE_UNIX_SOCKET" ]; then + _cmd="$@" + _cmd="$(printf "$_cmd" | sed 's/ /","/g')" + _debug2 _cmd "$_cmd" + #create exec instance: + cjson="$(_curl_unix_sock "$_DOCKER_SOCK" POST "/containers/$_dcid/exec" "{\"Cmd\": [\"$_cmd\"]}")"; + _debug2 cjson "$cjson" + execid="$(echo "$cjson" | cut -d '"' -f 4)" + _debug execid "$execid" + ejson="$(_curl_unix_sock "$_DOCKER_SOCK" POST "/exec/$execid/start" "{\"Detach\": false,\"Tty\": false}")"; + _debug2 ejson "$ejson" + else + _err "Not implemented yet." + return 1 + fi +} + +#id from to +_docker_cp() { + _dcid="$1" + _from="$2" + _to="$3" + _info "Copying file from $_from to $_to" + _dir="$(dirname "$_to")" + _docker_exec "$_dcid" mkdir -p "$_dir" + if [ "$_USE_DOCKER_COMMAND" ]; then + cat "$_from" | _docker_exec "$_dcid" tee "$_to" >/dev/null + if [ "$?" = "0" ]; then + _info "Success" + return 0 + else + _info "Error" + return 1 + fi + elif [ "$_USE_REST" ]; then + _err "Not implemented yet." + return 1 + elif [ "$_USE_UNIX_SOCKET" ]; then + _frompath="$_from" + if _startswith "$_frompath" '/'; then + _frompath="$(echo "$_from" | cut -b 2- )" #remove the first '/' char + fi + _debug2 "_frompath" "$_frompath" + _toname="$(basename "$_to")" + _debug2 "_toname" "$_toname" + if ! tar --transform="s,$_frompath,$_toname," -cz "$_from" 2>/dev/null | _curl_unix_sock "$_DOCKER_SOCK" PUT "/containers/$_dcid/archive?noOverwriteDirNonDir=1&path=$(printf "%s" "$_dir" | _url_encode)" '@-' "Content-Type: application/octet-stream"; then + _err "copy error" + return 1 + fi + return 0 + else + _err "Not implemented yet." + return 1 + fi + +} + +#sock method endpoint data content-type +_curl_unix_sock() { + _socket="$1" + _method="$2" + _endpoint="$3" + _data="$4" + _ctype="$5" + if [ -z "$_ctype" ]; then + _ctype="Content-Type: application/json" + fi + _debug _data "$_data" + _debug2 "url" "http://localhost$_endpoint" + if [ "$_CURL_NO_HOST" ]; then + _cux_url="http:$_endpoint" + else + _cux_url="http://localhost$_endpoint" + fi + + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + curl -vvv --silent --unix-socket "$_socket" -X $_method --data-binary "$_data" --header "$_ctype" "$_cux_url" + else + curl --silent --unix-socket "$_socket" -X $_method --data-binary "$_data" --header "$_ctype" "$_cux_url" + fi + +} + +_check_curl_version() { + _cversion="$(curl -V | grep '^curl ' | cut -d ' ' -f 2)" + _debug2 "_cversion" "$_cversion" + + _major="$(_getfield "$_cversion" 1 '.')" + _debug2 "_major" "$_major" + + _minor="$(_getfield "$_cversion" 2 '.')" + _debug2 "_minor" "$_minor" + + if [ "$_major$_minor" -lt "740" ]; then + _err "curl v$_cversion doesn't support unit socket" + return 1 + fi + if [ "$_major$_minor" -lt "750" ]; then + _debug "Use short host name" + export _CURL_NO_HOST=1 + else + export _CURL_NO_HOST= + fi + return 0 +} + From 0bbaa51945f882c1197f64ccb8c4522cd4d3b304 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jun 2019 10:05:24 +0800 Subject: [PATCH 434/565] fix format --- deploy/docker.sh | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/deploy/docker.sh b/deploy/docker.sh index 57081cc..0e22ddc 100755 --- a/deploy/docker.sh +++ b/deploy/docker.sh @@ -1,8 +1,6 @@ #!/usr/bin/env sh #DEPLOY_DOCKER_CONTAINER_LABEL="xxxxxxx" -#DOCKER_HOST=/var/run/docker.sock | tcp://localhost:8888 - #DEPLOY_DOCKER_CONTAINER_KEY_FILE="/path/to/key.pem" #DEPLOY_DOCKER_CONTAINER_CERT_FILE="/path/to/cert.pem" @@ -10,7 +8,7 @@ #DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/path/to/fullchain.pem" #DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="service nginx force-reload" -_DEPLOY_DOCKER_WIKI="http://xxxxxx" +_DEPLOY_DOCKER_WIKI="https://github.com/Neilpang/acme.sh/wiki/deploy-to-docker-containers" _DOCKER_HOST_DEFAULT="/var/run/docker.sock" @@ -20,7 +18,7 @@ docker_deploy() { _ccert="$3" _cca="$4" _cfullchain="$5" - + _debug _cdomain "$_cdomain" if [ -z "$DEPLOY_DOCKER_CONTAINER_LABEL" ]; then _err "The DEPLOY_DOCKER_CONTAINER_LABEL variable is not defined, we use this label to find the container." _err "See: $_DEPLOY_DOCKER_WIKI" @@ -136,7 +134,7 @@ _get_id() { _debug2 _req "$_req" _req="$(printf "%s" "$_req" | _url_encode)" _debug2 _req "$_req" - listjson="$(_curl_unix_sock "${_DOCKER_SOCK:-$_DOCKER_HOST_DEFAULT}" GET "/containers/json?filters=$_req")" + listjson="$(_curl_unix_sock "${_DOCKER_SOCK:-$_DOCKER_HOST_DEFAULT}" GET "/containers/json?filters=$_req")" _debug2 "listjson" "$listjson" echo "$listjson" | tr '{,' '\n' | grep -i '"id":' | _head_n 1 | cut -d '"' -f 4 else @@ -147,25 +145,25 @@ _get_id() { #id cmd _docker_exec() { - _eargs="$@" + _eargs="$*" _debug2 "_docker_exec $_eargs" _dcid="$1" shift if [ "$_USE_DOCKER_COMMAND" ]; then - docker exec -i "$_dcid" $@ + docker exec -i "$_dcid" "$@" elif [ "$_USE_REST" ]; then _err "Not implemented yet." return 1 elif [ "$_USE_UNIX_SOCKET" ]; then - _cmd="$@" - _cmd="$(printf "$_cmd" | sed 's/ /","/g')" + _cmd="$*" + _cmd="$(printf "%s" "$_cmd" | sed 's/ /","/g')" _debug2 _cmd "$_cmd" #create exec instance: - cjson="$(_curl_unix_sock "$_DOCKER_SOCK" POST "/containers/$_dcid/exec" "{\"Cmd\": [\"$_cmd\"]}")"; + cjson="$(_curl_unix_sock "$_DOCKER_SOCK" POST "/containers/$_dcid/exec" "{\"Cmd\": [\"$_cmd\"]}")" _debug2 cjson "$cjson" execid="$(echo "$cjson" | cut -d '"' -f 4)" _debug execid "$execid" - ejson="$(_curl_unix_sock "$_DOCKER_SOCK" POST "/exec/$execid/start" "{\"Detach\": false,\"Tty\": false}")"; + ejson="$(_curl_unix_sock "$_DOCKER_SOCK" POST "/exec/$execid/start" "{\"Detach\": false,\"Tty\": false}")" _debug2 ejson "$ejson" else _err "Not implemented yet." @@ -182,7 +180,11 @@ _docker_cp() { _dir="$(dirname "$_to")" _docker_exec "$_dcid" mkdir -p "$_dir" if [ "$_USE_DOCKER_COMMAND" ]; then - cat "$_from" | _docker_exec "$_dcid" tee "$_to" >/dev/null + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + _docker_exec "$_dcid" tee "$_to" <"$_from" + else + _docker_exec "$_dcid" tee "$_to" <"$_from" >/dev/null + fi if [ "$?" = "0" ]; then _info "Success" return 0 @@ -196,7 +198,7 @@ _docker_cp() { elif [ "$_USE_UNIX_SOCKET" ]; then _frompath="$_from" if _startswith "$_frompath" '/'; then - _frompath="$(echo "$_from" | cut -b 2- )" #remove the first '/' char + _frompath="$(echo "$_from" | cut -b 2-)" #remove the first '/' char fi _debug2 "_frompath" "$_frompath" _toname="$(basename "$_to")" @@ -232,9 +234,9 @@ _curl_unix_sock() { fi if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - curl -vvv --silent --unix-socket "$_socket" -X $_method --data-binary "$_data" --header "$_ctype" "$_cux_url" + curl -vvv --silent --unix-socket "$_socket" -X "$_method" --data-binary "$_data" --header "$_ctype" "$_cux_url" else - curl --silent --unix-socket "$_socket" -X $_method --data-binary "$_data" --header "$_ctype" "$_cux_url" + curl --silent --unix-socket "$_socket" -X "$_method" --data-binary "$_data" --header "$_ctype" "$_cux_url" fi } @@ -261,4 +263,3 @@ _check_curl_version() { fi return 0 } - From 64928b28bcb77165e9630355b37e85574da3fe65 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jun 2019 11:11:34 +0800 Subject: [PATCH 435/565] trim quotation marks --- deploy/docker.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/deploy/docker.sh b/deploy/docker.sh index 0e22ddc..18a9d42 100755 --- a/deploy/docker.sh +++ b/deploy/docker.sh @@ -19,6 +19,7 @@ docker_deploy() { _cca="$4" _cfullchain="$5" _debug _cdomain "$_cdomain" + DEPLOY_DOCKER_CONTAINER_LABEL="$(echo "$DEPLOY_DOCKER_CONTAINER_LABEL" | tr -d '"')" if [ -z "$DEPLOY_DOCKER_CONTAINER_LABEL" ]; then _err "The DEPLOY_DOCKER_CONTAINER_LABEL variable is not defined, we use this label to find the container." _err "See: $_DEPLOY_DOCKER_WIKI" @@ -62,22 +63,27 @@ docker_deploy() { fi fi + DEPLOY_DOCKER_CONTAINER_KEY_FILE="$(echo "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" | tr -d '"')" if [ "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" ]; then _savedomainconf DEPLOY_DOCKER_CONTAINER_KEY_FILE "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" fi + DEPLOY_DOCKER_CONTAINER_CERT_FILE="$(echo "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" | tr -d '"')" if [ "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" ]; then _savedomainconf DEPLOY_DOCKER_CONTAINER_CERT_FILE "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" fi + DEPLOY_DOCKER_CONTAINER_CA_FILE="$(echo "$DEPLOY_DOCKER_CONTAINER_CA_FILE" | tr -d '"')" if [ "$DEPLOY_DOCKER_CONTAINER_CA_FILE" ]; then _savedomainconf DEPLOY_DOCKER_CONTAINER_CA_FILE "$DEPLOY_DOCKER_CONTAINER_CA_FILE" fi + DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="$(echo "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" | tr -d '"')" if [ "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" ]; then _savedomainconf DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" fi + DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="$(echo "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" | tr -d '"')" if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then _savedomainconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" fi From a18c3ff07d83a28dad3bf4391633a3e86cf6721d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jun 2019 15:21:08 +0800 Subject: [PATCH 436/565] use `sh -c` --- deploy/docker.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/deploy/docker.sh b/deploy/docker.sh index 18a9d42..d2dc70b 100755 --- a/deploy/docker.sh +++ b/deploy/docker.sh @@ -156,21 +156,25 @@ _docker_exec() { _dcid="$1" shift if [ "$_USE_DOCKER_COMMAND" ]; then - docker exec -i "$_dcid" "$@" + docker exec -i "$_dcid" sh -c "$*" elif [ "$_USE_REST" ]; then _err "Not implemented yet." return 1 elif [ "$_USE_UNIX_SOCKET" ]; then _cmd="$*" - _cmd="$(printf "%s" "$_cmd" | sed 's/ /","/g')" + #_cmd="$(printf "%s" "$_cmd" | sed 's/ /","/g')" _debug2 _cmd "$_cmd" #create exec instance: - cjson="$(_curl_unix_sock "$_DOCKER_SOCK" POST "/containers/$_dcid/exec" "{\"Cmd\": [\"$_cmd\"]}")" + cjson="$(_curl_unix_sock "$_DOCKER_SOCK" POST "/containers/$_dcid/exec" "{\"Cmd\": [\"sh\", \"-c\", \"$_cmd\"]}")" _debug2 cjson "$cjson" execid="$(echo "$cjson" | cut -d '"' -f 4)" _debug execid "$execid" ejson="$(_curl_unix_sock "$_DOCKER_SOCK" POST "/exec/$execid/start" "{\"Detach\": false,\"Tty\": false}")" _debug2 ejson "$ejson" + if [ "$ejson" ]; then + _err "$ejson" + return 1 + fi else _err "Not implemented yet." return 1 From aec6636205d539eae83f54b4fa4f868f5079d55b Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jun 2019 19:36:11 +0800 Subject: [PATCH 437/565] add _getdeployconf --- acme.sh | 17 +++++++++++++++++ deploy/docker.sh | 24 ++++++++++++------------ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index eb2194a..45f0ea8 100755 --- a/acme.sh +++ b/acme.sh @@ -2078,6 +2078,23 @@ _readdomainconf() { _read_conf "$DOMAIN_CONF" "$1" } +#key value base64encode +_savedeployconf() { + _savedomainconf "SAVED_$1" "$2" "$3" + #remove later + _clearaccountconf "$1" +} + +#key +_getdeployconf() { + _rac_key="$1" + if [ "$(eval echo \$"$_rac_key")" ]; then + return 0 # do nothing + fi + _saved=$(_readdomainconf "SAVED_$_rac_key") + eval "export $_rac_key=$_saved" +} + #_saveaccountconf key value base64encode _saveaccountconf() { _save_conf "$ACCOUNT_CONF_PATH" "$@" diff --git a/deploy/docker.sh b/deploy/docker.sh index d2dc70b..6f3a271 100755 --- a/deploy/docker.sh +++ b/deploy/docker.sh @@ -19,13 +19,13 @@ docker_deploy() { _cca="$4" _cfullchain="$5" _debug _cdomain "$_cdomain" - DEPLOY_DOCKER_CONTAINER_LABEL="$(echo "$DEPLOY_DOCKER_CONTAINER_LABEL" | tr -d '"')" + _getdeployconf DEPLOY_DOCKER_CONTAINER_LABEL if [ -z "$DEPLOY_DOCKER_CONTAINER_LABEL" ]; then _err "The DEPLOY_DOCKER_CONTAINER_LABEL variable is not defined, we use this label to find the container." _err "See: $_DEPLOY_DOCKER_WIKI" fi - _savedomainconf DEPLOY_DOCKER_CONTAINER_LABEL "$DEPLOY_DOCKER_CONTAINER_LABEL" + _savedeployconf DEPLOY_DOCKER_CONTAINER_LABEL "$DEPLOY_DOCKER_CONTAINER_LABEL" if [ "$DOCKER_HOST" ]; then _saveaccountconf DOCKER_HOST "$DOCKER_HOST" @@ -63,29 +63,29 @@ docker_deploy() { fi fi - DEPLOY_DOCKER_CONTAINER_KEY_FILE="$(echo "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" | tr -d '"')" + _getdeployconf DEPLOY_DOCKER_CONTAINER_KEY_FILE if [ "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" ]; then - _savedomainconf DEPLOY_DOCKER_CONTAINER_KEY_FILE "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" + _savedeployconf DEPLOY_DOCKER_CONTAINER_KEY_FILE "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" fi - DEPLOY_DOCKER_CONTAINER_CERT_FILE="$(echo "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" | tr -d '"')" + _getdeployconf DEPLOY_DOCKER_CONTAINER_CERT_FILE if [ "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" ]; then - _savedomainconf DEPLOY_DOCKER_CONTAINER_CERT_FILE "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" + _savedeployconf DEPLOY_DOCKER_CONTAINER_CERT_FILE "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" fi - DEPLOY_DOCKER_CONTAINER_CA_FILE="$(echo "$DEPLOY_DOCKER_CONTAINER_CA_FILE" | tr -d '"')" + _getdeployconf DEPLOY_DOCKER_CONTAINER_CA_FILE if [ "$DEPLOY_DOCKER_CONTAINER_CA_FILE" ]; then - _savedomainconf DEPLOY_DOCKER_CONTAINER_CA_FILE "$DEPLOY_DOCKER_CONTAINER_CA_FILE" + _savedeployconf DEPLOY_DOCKER_CONTAINER_CA_FILE "$DEPLOY_DOCKER_CONTAINER_CA_FILE" fi - DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="$(echo "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" | tr -d '"')" + _getdeployconf DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE if [ "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" ]; then - _savedomainconf DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" + _savedeployconf DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" fi - DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="$(echo "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" | tr -d '"')" + _getdeployconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then - _savedomainconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" + _savedeployconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" fi _cid="$(_get_id "$DEPLOY_DOCKER_CONTAINER_LABEL")" From dc5eda7ebb53ba9dadb631d703829b37a3879be7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jun 2019 20:04:36 +0800 Subject: [PATCH 438/565] fix savedeployconf --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 45f0ea8..4c856db 100755 --- a/acme.sh +++ b/acme.sh @@ -2082,7 +2082,7 @@ _readdomainconf() { _savedeployconf() { _savedomainconf "SAVED_$1" "$2" "$3" #remove later - _clearaccountconf "$1" + _cleardomainconf "$1" } #key From 924e0261f9431be00e24d08080bd7774ee0e4de0 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 2 Jun 2019 13:09:57 -0400 Subject: [PATCH 439/565] Update dns_freedns.sh --- dnsapi/dns_freedns.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 5928837..e76e649 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -7,6 +7,7 @@ # #Author: David Kerr #Report Bugs here: https://github.com/dkerr64/acme.sh +#or here... https://github.com/Neilpang/acme.sh/issues/2305 # ######## Public functions ##################### From 51099bf1487a3637f00ccd2ba033128afab0416c Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Mon, 3 Jun 2019 01:54:04 +0200 Subject: [PATCH 440/565] Add postmark notify --- notify/postmark.sh | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 notify/postmark.sh diff --git a/notify/postmark.sh b/notify/postmark.sh new file mode 100644 index 0000000..6523feb --- /dev/null +++ b/notify/postmark.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env sh + +#Support postmarkapp.com API (https://postmarkapp.com/developer/user-guide/sending-email/sending-with-api) + +#POSTMARK_TOKEN="" +#POSTMARK_TO="xxxx@xxx.com" +#POSTMARK_FROM="xxxx@cccc.com" + +postmark_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + POSTMARK_TOKEN="${POSTMARK_TOKEN:-$(_readaccountconf_mutable POSTMARK_TOKEN)}" + if [ -z "$POSTMARK_TOKEN" ]; then + POSTMARK_TOKEN="" + _err "You didn't specify a POSTMARK api token POSTMARK_TOKEN yet ." + _err "You can get yours from here https://account.postmarkapp.com" + return 1 + fi + _saveaccountconf_mutable POSTMARK_TOKEN "$POSTMARK_TOKEN" + + POSTMARK_TO="${POSTMARK_TO:-$(_readaccountconf_mutable POSTMARK_TO)}" + if [ -z "$POSTMARK_TO" ]; then + POSTMARK_TO="" + _err "You didn't specify an email to POSTMARK_TO receive messages." + return 1 + fi + _saveaccountconf_mutable POSTMARK_TO "$POSTMARK_TO" + + POSTMARK_FROM="${POSTMARK_FROM:-$(_readaccountconf_mutable POSTMARK_FROM)}" + if [ -z "$POSTMARK_FROM" ]; then + POSTMARK_FROM="" + _err "You didn't specify an email from POSTMARK_FROM receive messages." + return 1 + fi + _saveaccountconf_mutable POSTMARK_FROM "$POSTMARK_FROM" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + export _H3="X-Postmark-Server-Token: $POSTMARK_TOKEN" + + _content="$(echo "$_content" | _json_encode)" + _data="{\"To\": \"$POSTMARK_TO\", \"From\": \"$POSTMARK_FROM\", \"Subject\": \"$_subject\", \"TextBody\": \"$_content\"}" + if _post "$_data" "https://api.postmarkapp.com/email"; then + # shellcheck disable=SC2154 + _message=$(printf "%s\n" "$response" | _lower_case | _egrep_o "\"message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) + if [ "$_message" = "ok" ]; then + _info "postmark send success." + return 0 + fi + fi + _err "postmark send error." + _err "$response" + return 1 + +} From c42dbbfec841aee2c515821e02a73cc3c0b80702 Mon Sep 17 00:00:00 2001 From: Charlie Garrison Date: Mon, 3 Jun 2019 11:38:39 +1000 Subject: [PATCH 441/565] reformatted RouterOS script for shfmt checks --- deploy/routeros.sh | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/deploy/routeros.sh b/deploy/routeros.sh index 035e13a..21c9196 100644 --- a/deploy/routeros.sh +++ b/deploy/routeros.sh @@ -85,22 +85,23 @@ routeros_deploy() { scp "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key" _info "Trying to push cert '$_cfullchain' to router" scp "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer" + DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=ftp,read,write,password,sensitive +source=\"## generated by routeros deploy script in acme.sh +\n/certificate remove [ find name=$_cdomain.cer_0 ] +\n/certificate remove [ find name=$_cdomain.cer_1 ] +\ndelay 1 +\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\" +\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\" +\ndelay 1 +\n/file remove $_cdomain.cer +\n/file remove $_cdomain.key +\ndelay 2 +\n/ip service set www-ssl certificate=$_cdomain.cer_0 +\n$ROUTER_OS_ADDITIONAL_SERVICES +\n\" +" # shellcheck disable=SC2029 - ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=\ - ftp,read,write,password,sensitive source=\"## generated by routeros deploy script in acme.sh \\r\ - \n/certificate remove [ find name=$_cdomain.cer_0 ]\\r\ - \n/certificate remove [ find name=$_cdomain.cer_1 ]\\r\ - \ndelay 1\\r\ - \n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\"\\r\ - \n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\"\\r\ - \ndelay 1\\r\ - \n/file remove $_cdomain.cer\\r\ - \n/file remove $_cdomain.key\\r\ - \ndelay 2\\r\ - \n/ip service set www-ssl certificate=$_cdomain.cer_0\\r\ - \n$ROUTER_OS_ADDITIONAL_SERVICES\\r\ - \n\" - " + ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "$DEPLOY_SCRIPT_CMD" # shellcheck disable=SC2029 ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script run \"LE Cert Deploy - $_cdomain\"" # shellcheck disable=SC2029 From 2e3ddd3a61da8a412d0926520e9a0006bd48857f Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 3 Jun 2019 20:55:22 +0800 Subject: [PATCH 442/565] trim quotation marks --- acme.sh | 7 ++++++- deploy/docker.sh | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4c856db..42988ac 100755 --- a/acme.sh +++ b/acme.sh @@ -2088,7 +2088,12 @@ _savedeployconf() { #key _getdeployconf() { _rac_key="$1" - if [ "$(eval echo \$"$_rac_key")" ]; then + _rac_value="$(eval echo \$"$_rac_key")" + if [ "$_rac_value" ]; then + if _startswith "$_rac_value" '"' && _endswith "$_rac_value" '"'; then + _debug2 "trim quotation marks" + eval "export $_rac_key=$_rac_value" + fi return 0 # do nothing fi _saved=$(_readdomainconf "SAVED_$_rac_key") diff --git a/deploy/docker.sh b/deploy/docker.sh index 6f3a271..dc3c010 100755 --- a/deploy/docker.sh +++ b/deploy/docker.sh @@ -20,6 +20,7 @@ docker_deploy() { _cfullchain="$5" _debug _cdomain "$_cdomain" _getdeployconf DEPLOY_DOCKER_CONTAINER_LABEL + _debug2 DEPLOY_DOCKER_CONTAINER_LABEL "$DEPLOY_DOCKER_CONTAINER_LABEL" if [ -z "$DEPLOY_DOCKER_CONTAINER_LABEL" ]; then _err "The DEPLOY_DOCKER_CONTAINER_LABEL variable is not defined, we use this label to find the container." _err "See: $_DEPLOY_DOCKER_WIKI" @@ -64,26 +65,31 @@ docker_deploy() { fi _getdeployconf DEPLOY_DOCKER_CONTAINER_KEY_FILE + _debug2 DEPLOY_DOCKER_CONTAINER_KEY_FILE "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" if [ "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" ]; then _savedeployconf DEPLOY_DOCKER_CONTAINER_KEY_FILE "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" fi _getdeployconf DEPLOY_DOCKER_CONTAINER_CERT_FILE + _debug2 DEPLOY_DOCKER_CONTAINER_CERT_FILE "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" if [ "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" ]; then _savedeployconf DEPLOY_DOCKER_CONTAINER_CERT_FILE "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" fi _getdeployconf DEPLOY_DOCKER_CONTAINER_CA_FILE + _debug2 DEPLOY_DOCKER_CONTAINER_CA_FILE "$DEPLOY_DOCKER_CONTAINER_CA_FILE" if [ "$DEPLOY_DOCKER_CONTAINER_CA_FILE" ]; then _savedeployconf DEPLOY_DOCKER_CONTAINER_CA_FILE "$DEPLOY_DOCKER_CONTAINER_CA_FILE" fi _getdeployconf DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE + _debug2 DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" if [ "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" ]; then _savedeployconf DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" fi _getdeployconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD + _debug2 DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then _savedeployconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" fi @@ -188,6 +194,7 @@ _docker_cp() { _to="$3" _info "Copying file from $_from to $_to" _dir="$(dirname "$_to")" + _debug2 _dir "$_dir" _docker_exec "$_dcid" mkdir -p "$_dir" if [ "$_USE_DOCKER_COMMAND" ]; then if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then From 951bd3a5172945d36344428d6710e211157ad50b Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 3 Jun 2019 21:03:03 +0800 Subject: [PATCH 443/565] minor, check for mkdir --- deploy/docker.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deploy/docker.sh b/deploy/docker.sh index dc3c010..4e55099 100755 --- a/deploy/docker.sh +++ b/deploy/docker.sh @@ -195,7 +195,10 @@ _docker_cp() { _info "Copying file from $_from to $_to" _dir="$(dirname "$_to")" _debug2 _dir "$_dir" - _docker_exec "$_dcid" mkdir -p "$_dir" + if ! _docker_exec "$_dcid" mkdir -p "$_dir"; then + _err "Can not create dir: $_dir" + return 1 + fi if [ "$_USE_DOCKER_COMMAND" ]; then if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then _docker_exec "$_dcid" tee "$_to" <"$_from" From 10d1361a2c4baa57dc7db17af3a1ac42300c9af2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 10 Jun 2019 22:35:55 +0800 Subject: [PATCH 444/565] add guide link --- dnsapi/dns_myapi.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index 6bf6250..2451d19 100755 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -11,6 +11,8 @@ # ######## Public functions ##################### +# Please Read this guide first: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide + #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_myapi_add() { fulldomain=$1 From 465ece5d2529f38f44c147a7b554a52884bd001c Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 10 Jun 2019 22:40:14 +0800 Subject: [PATCH 445/565] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 42988ac..7aa500e 100755 --- a/acme.sh +++ b/acme.sh @@ -2092,7 +2092,7 @@ _getdeployconf() { if [ "$_rac_value" ]; then if _startswith "$_rac_value" '"' && _endswith "$_rac_value" '"'; then _debug2 "trim quotation marks" - eval "export $_rac_key=$_rac_value" + eval "export $_rac_key=$_rac_value" fi return 0 # do nothing fi From e05ef230a7b62fff63865843d0ed182305a43ef4 Mon Sep 17 00:00:00 2001 From: AndreyIsakov Date: Tue, 11 Jun 2019 19:37:39 +0300 Subject: [PATCH 446/565] test CI error --- dnsapi/dns_regru.sh | 205 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 dnsapi/dns_regru.sh diff --git a/dnsapi/dns_regru.sh b/dnsapi/dns_regru.sh new file mode 100644 index 0000000..cd93189 --- /dev/null +++ b/dnsapi/dns_regru.sh @@ -0,0 +1,205 @@ +#!/usr/bin/env sh + +# +#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#CF_Email="xxxx@sss.com" + +CF_Api="https://api.cloudflare.com/client/v4" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_cf_add() { + fulldomain=$1 + txtvalue=$2 + + CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" + CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" + if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then + CF_Key="" + CF_Email="" + _err "You 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 + + if ! _contains "$CF_Email" "@"; then + _err "It seems that the CF_Email=$CF_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 CF_Key "$CF_Key" + _saveaccountconf_mutable CF_Email "$CF_Email" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain" + + if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then + _err "Error" + return 1 + fi + + # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so + # we can not use updating anymore. + # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) + # _debug count "$count" + # 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 _contains "$response" "$txtvalue"; 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 + fi + fi + _err "Add txt record error." + return 1 + # else + # _info "Updating record" + # record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) + # _debug "record_id" "$record_id" + # + # _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" + # if [ "$?" = "0" ]; then + # _info "Updated, OK" + # return 0 + # fi + # _err "Update error" + # return 1 + # fi + +} + +#fulldomain txtvalue +dns_cf_rm() { + fulldomain=$1 + txtvalue=$2 + + CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" + CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" + if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then + CF_Key="" + CF_Email="" + _err "You 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 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain&content=$txtvalue" + + if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _cf_rest DELETE "zones/$_domain_id/dns_records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" '"success":true' + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=1 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _cf_rest GET "zones?name=$h"; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_count":1'; 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 + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_cf_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + email_trimmed=$(echo $CF_Email | tr -d '"') + key_trimmed=$(echo $CF_Key | tr -d '"') + + export _H1="X-Auth-Email: $email_trimmed" + export _H2="X-Auth-Key: $key_trimmed" + export _H3="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$CF_Api/$ep" "" "$m")" + else + response="$(_get "$CF_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From 6151debeab598245fc86cb711b759f1816a88b89 Mon Sep 17 00:00:00 2001 From: AndreyIsakov Date: Tue, 11 Jun 2019 19:59:02 +0300 Subject: [PATCH 447/565] dnsapi for regru: CI linter ok --- dnsapi/dns_regru.sh | 211 ++++++++------------------------------------ 1 file changed, 36 insertions(+), 175 deletions(-) diff --git a/dnsapi/dns_regru.sh b/dnsapi/dns_regru.sh index cd93189..4efec56 100644 --- a/dnsapi/dns_regru.sh +++ b/dnsapi/dns_regru.sh @@ -1,205 +1,66 @@ #!/usr/bin/env sh # -#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# REGRU_API_Username="test" # -#CF_Email="xxxx@sss.com" +# REGRU_API_Password="test" +# +_domain=$_domain -CF_Api="https://api.cloudflare.com/client/v4" +REGRU_API_URL="https://api.reg.ru/api/regru2" ######## Public functions ##################### -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cf_add() { +dns_regru_add() { fulldomain=$1 txtvalue=$2 - CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" - CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" - if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then - CF_Key="" - CF_Email="" - _err "You 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 - - if ! _contains "$CF_Email" "@"; then - _err "It seems that the CF_Email=$CF_Email is not a valid email address." - _err "Please check and retry." + REGRU_API_Username="${REGRU_API_Username:-$(_readaccountconf_mutable REGRU_API_Username)}" + REGRU_API_Password="${REGRU_API_Password:-$(_readaccountconf_mutable REGRU_API_Password)}" + if [ -z "$REGRU_API_Username" ] || [ -z "$REGRU_API_Password" ]; then + REGRU_API_Username="" + REGRU_API_Password="" + _err "You don't specify regru password or username." return 1 fi - #save the api key and email to the account conf file. - _saveaccountconf_mutable CF_Key "$CF_Key" - _saveaccountconf_mutable CF_Email "$CF_Email" - _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" + _saveaccountconf_mutable REGRU_API_Username "$REGRU_API_Username" + _saveaccountconf_mutable REGRU_API_Password "$REGRU_API_Password" - _debug "Getting txt records" - _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain" - - if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then - _err "Error" - return 1 - fi + _info "Adding TXT record to ${fulldomain}" + response="$(_get "$REGRU_API_URL/zone/add_txt?input_data={%22username%22:%22${REGRU_API_Username}%22,%22password%22:%22${REGRU_API_Password}%22,%22domains%22:[{%22dname%22:%22${_domain}%22}],%22subdomain%22:%22_acme-challenge%22,%22text%22:%22${txtvalue}%22,%22output_content_type%22:%22plain%22}&input_format=json")" - # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so - # we can not use updating anymore. - # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) - # _debug count "$count" - # 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 _contains "$response" "$txtvalue"; 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 - fi + if _contains "${response}" 'success'; then + return 0 fi - _err "Add txt record error." + _err "Could not create resource record, check logs" + _err "${response}" return 1 - # else - # _info "Updating record" - # record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) - # _debug "record_id" "$record_id" - # - # _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" - # if [ "$?" = "0" ]; then - # _info "Updated, OK" - # return 0 - # fi - # _err "Update error" - # return 1 - # fi - } -#fulldomain txtvalue -dns_cf_rm() { +dns_regru_rm() { fulldomain=$1 txtvalue=$2 - - CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" - CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" - if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then - CF_Key="" - CF_Email="" - _err "You 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 - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" + echo 'RM-ONE '"$1" + echo 'RM-TWO '"$2" + + REGRU_API_Username="${REGRU_API_Username:-$(_readaccountconf_mutable REGRU_API_Username)}" + REGRU_API_Password="${REGRU_API_Password:-$(_readaccountconf_mutable REGRU_API_Password)}" + if [ -z "$REGRU_API_Username" ] || [ -z "$REGRU_API_Password" ]; then + REGRU_API_Username="" + REGRU_API_Password="" + _err "You don't specify regru password or username." return 1 fi - _debug _domain_id "$_domain_id" - _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - _debug "Getting txt records" - _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain&content=$txtvalue" + _info "Deleting resource record $fulldomain" + response="$(_get "$REGRU_API_URL/zone/remove_record?input_data={%22username%22:%22${REGRU_API_Username}%22,%22password%22:%22${REGRU_API_Password}%22,%22domains%22:[{%22dname%22:%22${_domain}%22}],%22subdomain%22:%22_acme-challenge%22,%22content%22:%22${txtvalue}%22,%22record_type%22:%22TXT%22,%22output_content_type%22:%22plain%22}&input_format=json")" - if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then - _err "Error" - return 1 + if _contains "${response}" 'success'; then + return 0 fi - - count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) - _debug count "$count" - if [ "$count" = "0" ]; then - _info "Don't need to remove." - else - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) - _debug "record_id" "$record_id" - if [ -z "$record_id" ]; then - _err "Can not get record id to remove." - return 1 - fi - if ! _cf_rest DELETE "zones/$_domain_id/dns_records/$record_id"; then - _err "Delete record error." - return 1 - fi - _contains "$response" '"success":true' - fi - -} - -#################### Private functions below ################################## -#_acme-challenge.www.domain.com -#returns -# _sub_domain=_acme-challenge.www -# _domain=domain.com -# _domain_id=sdjkglgdfewsdfg -_get_root() { - domain=$1 - i=1 - p=1 - while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - _debug h "$h" - if [ -z "$h" ]; then - #not valid - return 1 - fi - - if ! _cf_rest GET "zones?name=$h"; then - return 1 - fi - - if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_count":1'; 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 - return 0 - fi - return 1 - fi - p=$i - i=$(_math "$i" + 1) - done + _err "Could not delete resource record, check logs" + _err "${response}" return 1 } - -_cf_rest() { - m=$1 - ep="$2" - data="$3" - _debug "$ep" - - email_trimmed=$(echo $CF_Email | tr -d '"') - key_trimmed=$(echo $CF_Key | tr -d '"') - - export _H1="X-Auth-Email: $email_trimmed" - export _H2="X-Auth-Key: $key_trimmed" - export _H3="Content-Type: application/json" - - if [ "$m" != "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$CF_Api/$ep" "" "$m")" - else - response="$(_get "$CF_Api/$ep")" - fi - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - _debug2 response "$response" - return 0 -} From 487d2a9221802f5c4287c3a4637245f8ce1e329c Mon Sep 17 00:00:00 2001 From: AndreyIsakov Date: Tue, 11 Jun 2019 20:13:48 +0300 Subject: [PATCH 448/565] dnsapi for regru: CI linter remove empty line --- dnsapi/dns_regru.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_regru.sh b/dnsapi/dns_regru.sh index 4efec56..4c9dc9f 100644 --- a/dnsapi/dns_regru.sh +++ b/dnsapi/dns_regru.sh @@ -24,7 +24,6 @@ dns_regru_add() { return 1 fi - _saveaccountconf_mutable REGRU_API_Username "$REGRU_API_Username" _saveaccountconf_mutable REGRU_API_Password "$REGRU_API_Password" From 9b564431b08bc433e34c4d4b1cdac45eb333c4c5 Mon Sep 17 00:00:00 2001 From: Endre Szabo Date: Thu, 13 Jun 2019 12:39:38 +0200 Subject: [PATCH 449/565] Help text suggests bad practice. Please remove the phrase `No news is good news.` as it suggests to decide to go on with a bad operational habit. Why I am stating this is because that `no news` also could mean that: - your `cron` daemon stopped working, - your MTA has issues (in case or mail notifications of course), - anything in between the host running `acme.sh` and your client went wrong. (... and probably you will not notice in time if `acme.sh` would otherwise send an error notification (if it runs anyway)) If you expect a daily mail (using `--notify-level 3`) you can always be sure that `acme.sh` has ran successfully before. You can also tick the `acme.sh` checkbox in the daily operational report of your enterprise. ;) --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7aa500e..9bcab81 100755 --- a/acme.sh +++ b/acme.sh @@ -6108,7 +6108,7 @@ Parameters: --notify-level 0|1|2|3 Set the notification level: Default value is $NOTIFY_LEVEL_DEFAULT. 0: disabled, no notification will be sent. - 1: send notification only when there is an error. No news is good news. + 1: send notification only when there is an error. 2: send notification when a cert is successfully renewed, or there is an error 3: send notification when a cert is skipped, renewdd, or error --notify-mode 0|1 Set notification mode. Default value is $NOTIFY_MODE_DEFAULT. From f2c6e3f65b41e66257744afb8c8baca89c2d18cf Mon Sep 17 00:00:00 2001 From: AndreyIsakov Date: Thu, 13 Jun 2019 19:31:44 +0300 Subject: [PATCH 450/565] dnsapi for regru: replace echo by _info() --- dnsapi/dns_regru.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_regru.sh b/dnsapi/dns_regru.sh index 4c9dc9f..ff4443b 100644 --- a/dnsapi/dns_regru.sh +++ b/dnsapi/dns_regru.sh @@ -41,8 +41,8 @@ dns_regru_add() { dns_regru_rm() { fulldomain=$1 txtvalue=$2 - echo 'RM-ONE '"$1" - echo 'RM-TWO '"$2" + _info 'RM-ONE '"$1" + _info 'RM-TWO '"$2" REGRU_API_Username="${REGRU_API_Username:-$(_readaccountconf_mutable REGRU_API_Username)}" REGRU_API_Password="${REGRU_API_Password:-$(_readaccountconf_mutable REGRU_API_Password)}" From d883a870e183a5f5679a0d3be597b38745c359c5 Mon Sep 17 00:00:00 2001 From: AndreyIsakov Date: Thu, 13 Jun 2019 19:56:40 +0300 Subject: [PATCH 451/565] dnsapi for regru: remove debug info --- dnsapi/dns_regru.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/dnsapi/dns_regru.sh b/dnsapi/dns_regru.sh index ff4443b..369f62a 100644 --- a/dnsapi/dns_regru.sh +++ b/dnsapi/dns_regru.sh @@ -41,8 +41,6 @@ dns_regru_add() { dns_regru_rm() { fulldomain=$1 txtvalue=$2 - _info 'RM-ONE '"$1" - _info 'RM-TWO '"$2" REGRU_API_Username="${REGRU_API_Username:-$(_readaccountconf_mutable REGRU_API_Username)}" REGRU_API_Password="${REGRU_API_Password:-$(_readaccountconf_mutable REGRU_API_Password)}" From 882ac74a0c0dfa1e389dd54e6ce8180eddcfda91 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 14 Jun 2019 22:41:28 +0800 Subject: [PATCH 452/565] fix issue: clear Le_Vlist earlier --- acme.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 9bcab81..7042533 100755 --- a/acme.sh +++ b/acme.sh @@ -3863,7 +3863,7 @@ issue() { _savedomainconf "Le_Keylength" "$_key_length" vlist="$Le_Vlist" - + _cleardomainconf "Le_Vlist" _info "Getting domain auth token for each domain" sep='#' dvsep=',' @@ -4512,8 +4512,6 @@ $_authorizations_map" fi fi - _cleardomainconf "Le_Vlist" - if [ "$ACME_VERSION" = "2" ]; then _debug "v2 chain." else From c6b6855131108ca16c94e25349e24c1243d7703b Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 14 Jun 2019 23:55:59 +0800 Subject: [PATCH 453/565] fix https://github.com/Neilpang/acme.sh/issues/2321 https://github.com/Neilpang/acme.sh/issues/2291 --- acme.sh | 133 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 73 insertions(+), 60 deletions(-) diff --git a/acme.sh b/acme.sh index 7042533..bcc88ef 100755 --- a/acme.sh +++ b/acme.sh @@ -2450,7 +2450,7 @@ _initpath() { . "$ACCOUNT_CONF_PATH" fi - if [ "$IN_CRON" ]; then + if [ "$ACME_IN_CRON" ]; then if [ ! "$_USER_PATH_EXPORTED" ]; then _USER_PATH_EXPORTED=1 export PATH="$USER_PATH:$PATH" @@ -3216,14 +3216,6 @@ _on_issue_err() { _err "See: $_DEBUG_WIKI" fi - if [ "$IN_CRON" ]; then - if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_ERROR ]; then - if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then - _send_notify "Renew $_main_domain error" "There is an error." "$NOTIFY_HOOK" 1 - fi - fi - fi - #run the post hook if [ "$_chk_post_hook" ]; then _info "Run post hook:'$_chk_post_hook'" @@ -3266,13 +3258,7 @@ _on_issue_success() { _chk_post_hook="$1" _chk_renew_hook="$2" _debug _on_issue_success - if [ "$IN_CRON" ]; then - if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_RENEW ]; then - if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then - _send_notify "Renew $_main_domain success" "Good, the cert is renewed." "$NOTIFY_HOOK" 0 - fi - fi - fi + #run the post hook if [ "$_chk_post_hook" ]; then _info "Run post hook:'$_chk_post_hook'" @@ -4506,7 +4492,7 @@ $_authorizations_map" _info "Your cert key is in $(__green " $CERT_KEY_PATH ")" fi - if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ]; then + if [ ! "$USER_PATH" ] || [ ! "$ACME_IN_CRON" ]; then USER_PATH="$PATH" _saveaccountconf "USER_PATH" "$USER_PATH" fi @@ -4686,19 +4672,10 @@ renew() { if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")" _info "Add '$(__red '--force')' to force to renew." - - if [ "$IN_CRON" = "1" ]; then - if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_SKIP ]; then - if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then - _send_notify "Renew $Le_Domain skipped" "Good, the cert next renewal time is $Le_NextRenewTimeStr." "$NOTIFY_HOOK" "$RENEW_SKIP" - fi - fi - fi - return "$RENEW_SKIP" fi - if [ "$IN_CRON" = "1" ] && [ -z "$Le_CertCreateTime" ]; then + if [ "$ACME_IN_CRON" = "1" ] && [ -z "$Le_CertCreateTime" ]; then _info "Skip invalid cert for: $Le_Domain" return $RENEW_SKIP fi @@ -4733,6 +4710,8 @@ renewAll() { _success_msg="" _error_msg="" _skipped_msg="" + _error_level=$NOTIFY_LEVEL_SKIP + _notify_code=$RENEW_SKIP for di in "${CERT_HOME}"/*.*/; do _debug di "$di" if ! [ -d "$di" ]; then @@ -4750,49 +4729,83 @@ renewAll() { ) rc="$?" _debug "Return code: $rc" - if [ "$rc" != "0" ]; then - if [ "$rc" = "$RENEW_SKIP" ]; then - _info "Skipped $d" - _skipped_msg="${_skipped_msg} $d -" - else - _error_msg="${_error_msg} $d + if [ "$rc" = "0" ]; then + if [ $_error_level -gt $NOTIFY_LEVEL_RENEW ]; then + _error_level="$NOTIFY_LEVEL_RENEW" + _notify_code=0 + fi + if [ "$ACME_IN_CRON" ]; then + if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_RENEW ]; then + if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then + _send_notify "Renew $d success" "Good, the cert is renewed." "$NOTIFY_HOOK" 0 + fi + fi + fi + _success_msg="${_success_msg} $d " - if [ "$_stopRenewOnError" ]; then - _err "Error renew $d, stop now." - _ret="$rc" - break - else - _ret="$rc" - _err "Error renew $d." + elif [ "$rc" = "$RENEW_SKIP" ]; then + if [ $_error_level -gt $NOTIFY_LEVEL_SKIP ]; then + _error_level="$NOTIFY_LEVEL_SKIP" + _notify_code=$RENEW_SKIP + fi + if [ "$ACME_IN_CRON" ]; then + if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_SKIP ]; then + if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then + _send_notify "Renew $d skipped" "Good, the cert is skipped." "$NOTIFY_HOOK" "$RENEW_SKIP" + fi fi fi + _info "Skipped $d" + _skipped_msg="${_skipped_msg} $d +" else - _success_msg="${_success_msg} $d + if [ $_error_level -gt $NOTIFY_LEVEL_ERROR ]; then + _error_level="$NOTIFY_LEVEL_ERROR" + _notify_code=1 + fi + if [ "$ACME_IN_CRON" ]; then + if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_ERROR ]; then + if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then + _send_notify "Renew $d error" "There is an error." "$NOTIFY_HOOK" 1 + fi + fi + fi + _error_msg="${_error_msg} $d " + if [ "$_stopRenewOnError" ]; then + _err "Error renew $d, stop now." + _ret="$rc" + break + else + _ret="$rc" + _err "Error renew $d." + fi fi done - - if [ "$IN_CRON" = "1" ]; then + _debug _error_level "$_error_level" + if [ "$ACME_IN_CRON" ] && [ $_error_level -le $NOTIFY_LEVEL ]; then if [ -z "$NOTIFY_MODE" ] || [ "$NOTIFY_MODE" = "$NOTIFY_MODE_BULK" ]; then _msg_subject="Renew" if [ "$_error_msg" ]; then _msg_subject="${_msg_subject} Error" + _msg_data="Error certs: +${_error_msg} +" fi if [ "$_success_msg" ]; then _msg_subject="${_msg_subject} Success" + _msg_data="${_msg_data}Success certs: +${_success_msg} +" fi if [ "$_skipped_msg" ]; then _msg_subject="${_msg_subject} Skipped" - fi - _msg_data="Error certs: -${_error_msg} -Success certs: -${_success_msg} -Skipped certs: -$_skipped_msg + _msg_data="${_msg_data}Skipped certs: +${_skipped_msg} " - _send_notify "$_msg_subject" "$_msg_data" "$NOTIFY_HOOK" 0 + fi + + _send_notify "$_msg_subject" "$_msg_data" "$NOTIFY_HOOK" "$_notify_code" fi fi @@ -5708,7 +5721,7 @@ install() { _debug "Skip install cron job" fi - if [ "$IN_CRON" != "1" ]; then + if [ "$ACME_IN_CRON" != "1" ]; then if ! _precheck "$_nocron"; then _err "Pre-check failed, can not install." return 1 @@ -5765,7 +5778,7 @@ install() { _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" - if [ "$IN_CRON" != "1" ] && [ -z "$_noprofile" ]; then + if [ "$ACME_IN_CRON" != "1" ] && [ -z "$_noprofile" ]; then _installalias "$_c_home" fi @@ -5863,7 +5876,7 @@ _uninstallalias() { } cron() { - export IN_CRON=1 + export ACME_IN_CRON=1 _initpath _info "$(__green "===Starting cron===")" if [ "$AUTO_UPGRADE" = "1" ]; then @@ -5884,7 +5897,7 @@ cron() { fi renewAll _ret="$?" - IN_CRON="" + ACME_IN_CRON="" _info "$(__green "===End cron===")" exit $_ret } @@ -6106,11 +6119,11 @@ Parameters: --notify-level 0|1|2|3 Set the notification level: Default value is $NOTIFY_LEVEL_DEFAULT. 0: disabled, no notification will be sent. - 1: send notification only when there is an error. - 2: send notification when a cert is successfully renewed, or there is an error - 3: send notification when a cert is skipped, renewdd, or error + 1: send notifications only when there is an error. + 2: send notifications when a cert is successfully renewed, or there is an error. + 3: send notifications when a cert is skipped, renewed, or error. --notify-mode 0|1 Set notification mode. Default value is $NOTIFY_MODE_DEFAULT. - 0: Bulk mode. Send all the domain's notifications in one message(mail) + 0: Bulk mode. Send all the domain's notifications in one message(mail). 1: Cert mode. Send a message for every single cert. --notify-hook [hookname] Set the notify hook From f803c6c0bf3988efd9579832cf1f108a21d06316 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 15 Jun 2019 08:33:16 +0800 Subject: [PATCH 454/565] fix https://github.com/Neilpang/acme.sh/issues/2341 --- acme.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index bcc88ef..c9f65ec 100755 --- a/acme.sh +++ b/acme.sh @@ -4712,6 +4712,8 @@ renewAll() { _skipped_msg="" _error_level=$NOTIFY_LEVEL_SKIP _notify_code=$RENEW_SKIP + _set_level=${NOTIFY_LEVEL:-$NOTIFY_LEVEL_DEFAULT} + _debug "_set_level" "$_set_level" for di in "${CERT_HOME}"/*.*/; do _debug di "$di" if ! [ -d "$di" ]; then @@ -4735,7 +4737,7 @@ renewAll() { _notify_code=0 fi if [ "$ACME_IN_CRON" ]; then - if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_RENEW ]; then + if [ $_set_level -ge $NOTIFY_LEVEL_RENEW ]; then if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then _send_notify "Renew $d success" "Good, the cert is renewed." "$NOTIFY_HOOK" 0 fi @@ -4749,7 +4751,7 @@ renewAll() { _notify_code=$RENEW_SKIP fi if [ "$ACME_IN_CRON" ]; then - if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_SKIP ]; then + if [ $_set_level -ge $NOTIFY_LEVEL_SKIP ]; then if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then _send_notify "Renew $d skipped" "Good, the cert is skipped." "$NOTIFY_HOOK" "$RENEW_SKIP" fi @@ -4764,7 +4766,7 @@ renewAll() { _notify_code=1 fi if [ "$ACME_IN_CRON" ]; then - if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_ERROR ]; then + if [ $_set_level -ge $NOTIFY_LEVEL_ERROR ]; then if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then _send_notify "Renew $d error" "There is an error." "$NOTIFY_HOOK" 1 fi @@ -4783,7 +4785,7 @@ renewAll() { fi done _debug _error_level "$_error_level" - if [ "$ACME_IN_CRON" ] && [ $_error_level -le $NOTIFY_LEVEL ]; then + if [ "$ACME_IN_CRON" ] && [ $_error_level -le $_set_level ]; then if [ -z "$NOTIFY_MODE" ] || [ "$NOTIFY_MODE" = "$NOTIFY_MODE_BULK" ]; then _msg_subject="Renew" if [ "$_error_msg" ]; then From c83f2f98bd2edde3c602bfdf7cc9f9bfd061d4b8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 19 Jun 2019 21:49:42 +0800 Subject: [PATCH 455/565] fix https://github.com/Neilpang/acme.sh/issues/2300 --- dnsapi/dns_ovh.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 2669cc8..65567ef 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -121,7 +121,7 @@ _initAuth() { _info "Checking authentication" - if ! _ovh_rest GET "domain" || _contains "$response" "INVALID_CREDENTIAL"; then + if ! _ovh_rest GET "domain" || _contains "$response" "INVALID_CREDENTIAL" || _contains "$response" "NOT_CREDENTIAL"; then _err "The consumer key is invalid: $OVH_CK" _err "Please retry to create a new one." _clearaccountconf OVH_CK From a2738e8599918f3e7309237d686e7e1cbd28982d Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 19 Jun 2019 21:50:41 +0800 Subject: [PATCH 456/565] minor, add debug info --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index c9f65ec..67fcdcb 100755 --- a/acme.sh +++ b/acme.sh @@ -4785,6 +4785,7 @@ renewAll() { fi done _debug _error_level "$_error_level" + _debug _set_level "$_set_level" if [ "$ACME_IN_CRON" ] && [ $_error_level -le $_set_level ]; then if [ -z "$NOTIFY_MODE" ] || [ "$NOTIFY_MODE" = "$NOTIFY_MODE_BULK" ]; then _msg_subject="Renew" From e0d4115ed7c45dd31f46cf3ff68d1b03e7f545a9 Mon Sep 17 00:00:00 2001 From: Maximilian Hippler Date: Fri, 21 Jun 2019 23:43:32 +0200 Subject: [PATCH 457/565] Finally added oathtool --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index f9d7b1b..752692c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.9 +FROM alpine:3.10 RUN apk update -f \ && apk --no-cache add -f \ @@ -8,7 +8,7 @@ RUN apk update -f \ curl \ socat \ tzdata \ - && apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/community oath-toolkit-oathtool \ + oath-toolkit-oathtool \ && rm -rf /var/cache/apk/* ENV LE_CONFIG_HOME /acme.sh From 971a85a6f82a72d74ab3bf29e4c80d9b05318b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Berlamont?= Date: Sat, 29 Jun 2019 18:14:34 +0200 Subject: [PATCH 458/565] dns_azure : Multiple domains with same ending bug We have a few domains that ends the same. For example : iperfony.com perfony.com The problem was in the _get_root functions, when getting the domain_id : only the first result "iperfony.com" was returned, because "perfony.com" is contained in the "iperfony.com" string. The correction consist of being strict in the regex, adding a slash (/) so that it will only match on ".*/(perfony.com).*" and not ".*(perfony.com).*". --- dnsapi/dns_azure.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index ae8aa1c..8b52dee 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -317,7 +317,7 @@ _get_root() { ## 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?\$top=500&api-version=2017-09-01" "" "$accesstoken" - # Find matching domain name is Json response + # Find matching domain name in Json response while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug2 "Checking domain: $h" @@ -328,7 +328,7 @@ _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 if [ "$i" = 1 ]; then #create the record at the domain apex (@) if only the domain name was provided as --domain-alias From d694ee8651a25b585cae76377e8d0e622f170b0b Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 30 Jun 2019 10:48:21 +0800 Subject: [PATCH 459/565] update --- .github/ISSUE_TEMPLATE.md | 4 +++- .github/PULL_REQUEST_TEMPLATE.md | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index f7d4d1d..189155e 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,5 +1,7 @@ \ No newline at end of file From ae66c6f0b484ce5c451ff8c195f382115b3d15a0 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Thu, 11 Jul 2019 15:46:17 -0400 Subject: [PATCH 460/565] Fix bug (in egrep regex) reported by @maks2018 in issue 2305 Fix bug reported by @maks2018 in issue https://github.com/Neilpang/acme.sh/issues/2305 by updating the regex in egrep of the subdomain html page. --- dnsapi/dns_freedns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index e76e649..ec845f8 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -305,7 +305,7 @@ _freedns_domain_id() { domain_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ | grep "$search_domain\|$search_domain(.*)" \ - | _egrep_o "edit\.php\?edit_domain_id=[0-9a-zA-Z]+" \ + | _egrep_o "edit\.php?edit_domain_id=[0-9a-zA-Z]*" \ | cut -d = -f 2)" # The above beauty extracts domain ID from the html page... # strip out all blank space and new lines. Then insert newlines @@ -352,7 +352,7 @@ _freedns_data_id() { data_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ | grep "$record_type" \ | grep "$search_domain" \ - | _egrep_o "edit\.php\?data_id=[0-9a-zA-Z]+" \ + | _egrep_o "edit\.php?data_id=[0-9a-zA-Z]*" \ | cut -d = -f 2)" # The above beauty extracts data ID from the html page... # strip out all blank space and new lines. Then insert newlines From 2ce9fb976024373850bb1de1e9ed939a995d3378 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Thu, 11 Jul 2019 18:06:56 -0400 Subject: [PATCH 461/565] Work around bug in _egrep_o() function _egrep_o() function accepts extended regex and on systems that do not have egrep uses sed to emulate egrep. This is failing on the specific regex I was using before my last commit... https://github.com/dkerr64/acme.sh/commit/ae66c6f0b484ce5c451ff8c195f382115b3d15a0 The problem is that I fixed it by passing in non-extended regex which then fails on systems that do have egrep. So I am no longer using _egrep_o. --- dnsapi/dns_freedns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index ec845f8..8a48cf7 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -305,7 +305,7 @@ _freedns_domain_id() { domain_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ | grep "$search_domain\|$search_domain(.*)" \ - | _egrep_o "edit\.php?edit_domain_id=[0-9a-zA-Z]*" \ + | grep -o "edit\.php?edit_domain_id=[0-9a-zA-Z]*" \ | cut -d = -f 2)" # The above beauty extracts domain ID from the html page... # strip out all blank space and new lines. Then insert newlines @@ -352,7 +352,7 @@ _freedns_data_id() { data_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ | grep "$record_type" \ | grep "$search_domain" \ - | _egrep_o "edit\.php?data_id=[0-9a-zA-Z]*" \ + | grep -o "edit\.php?data_id=[0-9a-zA-Z]*" \ | cut -d = -f 2)" # The above beauty extracts data ID from the html page... # strip out all blank space and new lines. Then insert newlines From bd9af86de152697f3dbc8532ee813dad01566c10 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 13 Jul 2019 17:33:04 +0800 Subject: [PATCH 462/565] support jdcloud.com --- dnsapi/dns_jd.sh | 305 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 dnsapi/dns_jd.sh diff --git a/dnsapi/dns_jd.sh b/dnsapi/dns_jd.sh new file mode 100644 index 0000000..28ac7dc --- /dev/null +++ b/dnsapi/dns_jd.sh @@ -0,0 +1,305 @@ +#!/usr/bin/env sh + +# +#JD_ACCESS_KEY_ID="sdfsdfsdfljlbjkljlkjsdfoiwje" +#JD_ACCESS_KEY_SECRET="xxxxxxx" +#JD_REGION="cn-north-1" +#JD_PACK_ID=0 + + +_JD_ACCOUNT="https://uc.jdcloud.com/account/accesskey" + +_JD_PROD="clouddnsservice" +_JD_API="jdcloud-api.com" + +_JD_API_VERSION="v1" +_JD_DEFAULT_REGION="cn-north-1" + +_JD_HOST="$_JD_PROD.$_JD_API" + +_JD_PACK_FREE=0 +_JD_PACK_ENTERPRISE=1 +_JD_PACK_PREMIUM=2 + + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_jd_add() { + fulldomain=$1 + txtvalue=$2 + + JD_ACCESS_KEY_ID="${JD_ACCESS_KEY_ID:-$(_readaccountconf_mutable JD_ACCESS_KEY_ID)}" + JD_ACCESS_KEY_SECRET="${JD_ACCESS_KEY_SECRET:-$(_readaccountconf_mutable JD_ACCESS_KEY_SECRET)}" + JD_REGION="${JD_REGION:-$(_readaccountconf_mutable JD_REGION)}" + JD_PACK_ID="${JD_PACK_ID:-$(_readaccountconf_mutable JD_PACK_ID)}" + + if [ -z "$JD_ACCESS_KEY_ID" ] || [ -z "$JD_ACCESS_KEY_SECRET" ]; then + JD_ACCESS_KEY_ID="" + JD_ACCESS_KEY_SECRET="" + _err "You haven't specifed the jdcloud api key id or api key secret yet." + _err "Please create your key and try again. see $(__green $_JD_ACCOUNT)" + return 1 + fi + + _saveaccountconf_mutable JD_ACCESS_KEY_ID "$JD_ACCESS_KEY_ID" + _saveaccountconf_mutable JD_ACCESS_KEY_SECRET "$JD_ACCESS_KEY_SECRET" + if [ -z "$JD_REGION" ]; then + _debug "Using default region: $_JD_DEFAULT_REGION" + JD_REGION="$_JD_DEFAULT_REGION" + else + _saveaccountconf_mutable JD_REGION "$JD_REGION" + fi + _JD_BASE_URI="$_JD_API_VERSION/regions/$JD_REGION" + + if [ -z "$JD_PACK_ID" ]; then + _debug "Using default free pack: $_JD_PACK_FREE" + JD_PACK_ID=$_JD_PACK_FREE + else + _saveaccountconf_mutable JD_PACK_ID "$JD_PACK_ID" + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + #_debug "Getting getViewTree" + + _debug "Adding records" + + _addrr="{\"req\":{\"hostRecord\":\"$_sub_domain\",\"hostValue\":\"$txtvalue\",\"ttl\":120,\"type\":\"TXT\",\"viewValue\":-1},\"regionId\":\"$JD_REGION\",\"domainId\":\"$_domain_id\"}" + #_addrr='{"req":{"hostRecord":"xx","hostValue":"\"value4\"","jcloudRes":false,"mxPriority":null,"port":null,"ttl":300,"type":"TXT","weight":null,"viewValue":-1},"regionId":"cn-north-1","domainId":"8824"}' + if jd_rest POST "domain/$_domain_id/RRAdd" "" "$_addrr"; then + _rid="$(echo "$response" | tr '{},' '\n' | grep '"id":' | cut -d : -f 2)" + if [ -z "$_rid" ]; then + _err "Can not find record id from the result." + return 1 + fi + _info "TXT record added successfully." + _srid="$(_readdomainconf "JD_CLOUD_RIDS")" + if [ "$_srid" ]; then + _rid="$_srid,$_rid" + fi + _savedomainconf "JD_CLOUD_RIDS" "$_rid" + return 0 + fi + + return 1 +} + + +dns_jd_rm() { + fulldomain=$1 + txtvalue=$2 + + JD_ACCESS_KEY_ID="${JD_ACCESS_KEY_ID:-$(_readaccountconf_mutable JD_ACCESS_KEY_ID)}" + JD_ACCESS_KEY_SECRET="${JD_ACCESS_KEY_SECRET:-$(_readaccountconf_mutable JD_ACCESS_KEY_SECRET)}" + JD_REGION="${JD_REGION:-$(_readaccountconf_mutable JD_REGION)}" + JD_PACK_ID="${JD_PACK_ID:-$(_readaccountconf_mutable JD_PACK_ID)}" + if [ -z "$JD_REGION" ]; then + _debug "Using default region: $_JD_DEFAULT_REGION" + JD_REGION="$_JD_DEFAULT_REGION" + fi + + _JD_BASE_URI="$_JD_API_VERSION/regions/$JD_REGION" + + _info "Getting existing records for $fulldomain" + _srid="$(_readdomainconf "JD_CLOUD_RIDS")" + _debug _srid "$_srid" + + if [ -z "$_srid" ]; then + _err "Not rid skip" + return 0 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _cleardomainconf JD_CLOUD_RIDS + + _aws_tmpl_xml="{\"ids\":[$_srid],\"action\":\"del\",\"regionId\":\"$JD_REGION\",\"domainId\":\"$_domain_id\"}" + + if jd_rest POST "domain/$_domain_id/RROperate" "" "$_aws_tmpl_xml" && _contains "$response" "\"code\":\"OK\""; then + _info "TXT record deleted successfully." + return 0 + fi + return 1 + +} + + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + i=1 + p=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug2 "Checking domain: $h" + if ! jd_rest GET "domain"; then + _err "error get domain list" + return 1 + fi + if [ -z "$h" ]; then + #not valid + _err "Invalid domain" + return 1 + fi + + if _contains "$response" "\"domainName\":\"$h\""; then + hostedzone="$(echo "$response" | tr '{}' '\n' | grep "\"domainName\":\"$h\"")" + _debug hostedzone "$hostedzone" + if [ "$hostedzone" ]; then + _domain_id="$(echo "$hostedzone" | tr ',' '\n' | grep "\"id\":" | cut -d : -f 2)" + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + fi + _err "Can't find domain with id: $h" + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + + +#method uri qstr data +jd_rest() { + mtd="$1" + ep="$2" + qsr="$3" + data="$4" + + _debug mtd "$mtd" + _debug ep "$ep" + _debug qsr "$qsr" + _debug data "$data" + + CanonicalURI="/$_JD_BASE_URI/$ep" + _debug2 CanonicalURI "$CanonicalURI" + + CanonicalQueryString="$qsr" + _debug2 CanonicalQueryString "$CanonicalQueryString" + + RequestDate="$(date -u +"%Y%m%dT%H%M%SZ")" + #RequestDate="20190713T082155Z" ###################################################### + _debug2 RequestDate "$RequestDate" + export _H1="X-Jdcloud-Date: $RequestDate" + + RequestNonce="2bd0852a-8bae-4087-b2d5-$(_time)" + #RequestNonce="894baff5-72d4-4244-883a-7b2eb51e7fbe" ################################# + _debug2 RequestNonce "$RequestNonce" + export _H2="X-Jdcloud-Nonce: $RequestNonce" + + if [ "$data" ]; then + CanonicalHeaders="content-type:application/json\n" + SignedHeaders="content-type;" + else + CanonicalHeaders="" + SignedHeaders="" + fi + CanonicalHeaders="${CanonicalHeaders}host:$_JD_HOST\nx-jdcloud-date:$RequestDate\nx-jdcloud-nonce:$RequestNonce\n" + SignedHeaders="${SignedHeaders}host;x-jdcloud-date;x-jdcloud-nonce" + + _debug2 CanonicalHeaders "$CanonicalHeaders" + _debug2 SignedHeaders "$SignedHeaders" + + Hash="sha256" + + RequestPayload="$data" + _debug2 RequestPayload "$RequestPayload" + + RequestPayloadHash="$(printf "%s" "$RequestPayload" | _digest "$Hash" hex | _lower_case)" + _debug2 RequestPayloadHash "$RequestPayloadHash" + + CanonicalRequest="$mtd\n$CanonicalURI\n$CanonicalQueryString\n$CanonicalHeaders\n$SignedHeaders\n$RequestPayloadHash" + _debug2 CanonicalRequest "$CanonicalRequest" + + HashedCanonicalRequest="$(printf "$CanonicalRequest%s" | _digest "$Hash" hex)" + _debug2 HashedCanonicalRequest "$HashedCanonicalRequest" + + Algorithm="JDCLOUD2-HMAC-SHA256" + _debug2 Algorithm "$Algorithm" + + RequestDateOnly="$(echo "$RequestDate" | cut -c 1-8)" + _debug2 RequestDateOnly "$RequestDateOnly" + + Region="$JD_REGION" + Service="$_JD_PROD" + + CredentialScope="$RequestDateOnly/$Region/$Service/jdcloud2_request" + _debug2 CredentialScope "$CredentialScope" + + StringToSign="$Algorithm\n$RequestDate\n$CredentialScope\n$HashedCanonicalRequest" + + _debug2 StringToSign "$StringToSign" + + kSecret="JDCLOUD2$JD_ACCESS_KEY_SECRET" + + _secure_debug2 kSecret "$kSecret" + + kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")" + _secure_debug2 kSecretH "$kSecretH" + + kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" + _debug2 kDateH "$kDateH" + + kRegionH="$(printf "$Region%s" | _hmac "$Hash" "$kDateH" hex)" + _debug2 kRegionH "$kRegionH" + + kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)" + _debug2 kServiceH "$kServiceH" + + kSigningH="$(printf "%s" "jdcloud2_request" | _hmac "$Hash" "$kServiceH" hex)" + _debug2 kSigningH "$kSigningH" + + signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)" + _debug2 signature "$signature" + + Authorization="$Algorithm Credential=$JD_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" + _debug2 Authorization "$Authorization" + + _H3="Authorization: $Authorization" + _debug _H3 "$_H3" + + url="https://$_JD_HOST$CanonicalURI" + if [ "$qsr" ]; then + url="https://$_JD_HOST$CanonicalURI?$qsr" + fi + + if [ "$mtd" = "GET" ]; then + response="$(_get "$url")" + else + response="$(_post "$data" "$url" "" "$mtd" "application/json")" + fi + + _ret="$?" + _debug2 response "$response" + if [ "$_ret" = "0" ]; then + if _contains "$response" "\"error\""; then + _err "Response error:$response" + return 1 + fi + fi + + return "$_ret" +} + From 57b16e3ac2f18401cecceef1ca32d818c3b11bf0 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 13 Jul 2019 17:42:01 +0800 Subject: [PATCH 463/565] fix format --- dnsapi/dns_jd.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dnsapi/dns_jd.sh b/dnsapi/dns_jd.sh index 28ac7dc..2efc91a 100644 --- a/dnsapi/dns_jd.sh +++ b/dnsapi/dns_jd.sh @@ -6,7 +6,6 @@ #JD_REGION="cn-north-1" #JD_PACK_ID=0 - _JD_ACCOUNT="https://uc.jdcloud.com/account/accesskey" _JD_PROD="clouddnsservice" @@ -21,7 +20,6 @@ _JD_PACK_FREE=0 _JD_PACK_ENTERPRISE=1 _JD_PACK_PREMIUM=2 - ######## Public functions ##################### #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" @@ -92,7 +90,6 @@ dns_jd_add() { return 1 } - dns_jd_rm() { fulldomain=$1 txtvalue=$2 @@ -138,7 +135,6 @@ dns_jd_rm() { } - #################### Private functions below ################################## _get_root() { @@ -180,7 +176,6 @@ _get_root() { return 1 } - #method uri qstr data jd_rest() { mtd="$1" @@ -302,4 +297,3 @@ jd_rest() { return "$_ret" } - From 42497028c458053f9fba1cb9fe43e3c03a3701b4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 13 Jul 2019 19:35:55 +0800 Subject: [PATCH 464/565] ttl 3000 --- dnsapi/dns_jd.sh | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/dnsapi/dns_jd.sh b/dnsapi/dns_jd.sh index 2efc91a..d0f2a50 100644 --- a/dnsapi/dns_jd.sh +++ b/dnsapi/dns_jd.sh @@ -4,7 +4,6 @@ #JD_ACCESS_KEY_ID="sdfsdfsdfljlbjkljlkjsdfoiwje" #JD_ACCESS_KEY_SECRET="xxxxxxx" #JD_REGION="cn-north-1" -#JD_PACK_ID=0 _JD_ACCOUNT="https://uc.jdcloud.com/account/accesskey" @@ -16,10 +15,6 @@ _JD_DEFAULT_REGION="cn-north-1" _JD_HOST="$_JD_PROD.$_JD_API" -_JD_PACK_FREE=0 -_JD_PACK_ENTERPRISE=1 -_JD_PACK_PREMIUM=2 - ######## Public functions ##################### #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" @@ -30,7 +25,6 @@ dns_jd_add() { JD_ACCESS_KEY_ID="${JD_ACCESS_KEY_ID:-$(_readaccountconf_mutable JD_ACCESS_KEY_ID)}" JD_ACCESS_KEY_SECRET="${JD_ACCESS_KEY_SECRET:-$(_readaccountconf_mutable JD_ACCESS_KEY_SECRET)}" JD_REGION="${JD_REGION:-$(_readaccountconf_mutable JD_REGION)}" - JD_PACK_ID="${JD_PACK_ID:-$(_readaccountconf_mutable JD_PACK_ID)}" if [ -z "$JD_ACCESS_KEY_ID" ] || [ -z "$JD_ACCESS_KEY_SECRET" ]; then JD_ACCESS_KEY_ID="" @@ -50,13 +44,6 @@ dns_jd_add() { fi _JD_BASE_URI="$_JD_API_VERSION/regions/$JD_REGION" - if [ -z "$JD_PACK_ID" ]; then - _debug "Using default free pack: $_JD_PACK_FREE" - JD_PACK_ID=$_JD_PACK_FREE - else - _saveaccountconf_mutable JD_PACK_ID "$JD_PACK_ID" - fi - _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" @@ -70,7 +57,7 @@ dns_jd_add() { _debug "Adding records" - _addrr="{\"req\":{\"hostRecord\":\"$_sub_domain\",\"hostValue\":\"$txtvalue\",\"ttl\":120,\"type\":\"TXT\",\"viewValue\":-1},\"regionId\":\"$JD_REGION\",\"domainId\":\"$_domain_id\"}" + _addrr="{\"req\":{\"hostRecord\":\"$_sub_domain\",\"hostValue\":\"$txtvalue\",\"ttl\":300,\"type\":\"TXT\",\"viewValue\":-1},\"regionId\":\"$JD_REGION\",\"domainId\":\"$_domain_id\"}" #_addrr='{"req":{"hostRecord":"xx","hostValue":"\"value4\"","jcloudRes":false,"mxPriority":null,"port":null,"ttl":300,"type":"TXT","weight":null,"viewValue":-1},"regionId":"cn-north-1","domainId":"8824"}' if jd_rest POST "domain/$_domain_id/RRAdd" "" "$_addrr"; then _rid="$(echo "$response" | tr '{},' '\n' | grep '"id":' | cut -d : -f 2)" @@ -97,7 +84,7 @@ dns_jd_rm() { JD_ACCESS_KEY_ID="${JD_ACCESS_KEY_ID:-$(_readaccountconf_mutable JD_ACCESS_KEY_ID)}" JD_ACCESS_KEY_SECRET="${JD_ACCESS_KEY_SECRET:-$(_readaccountconf_mutable JD_ACCESS_KEY_SECRET)}" JD_REGION="${JD_REGION:-$(_readaccountconf_mutable JD_REGION)}" - JD_PACK_ID="${JD_PACK_ID:-$(_readaccountconf_mutable JD_PACK_ID)}" + if [ -z "$JD_REGION" ]; then _debug "Using default region: $_JD_DEFAULT_REGION" JD_REGION="$_JD_DEFAULT_REGION" From 5f944743304976a55c1e974c5835c5b2996c2ce2 Mon Sep 17 00:00:00 2001 From: neil <8305679+Neilpang@users.noreply.github.com> Date: Sat, 13 Jul 2019 20:01:06 +0800 Subject: [PATCH 465/565] support jdcloud.com (#2390) fix https://github.com/Neilpang/acme.sh/pull/2390 --- dnsapi/dns_jd.sh | 286 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 dnsapi/dns_jd.sh diff --git a/dnsapi/dns_jd.sh b/dnsapi/dns_jd.sh new file mode 100644 index 0000000..d0f2a50 --- /dev/null +++ b/dnsapi/dns_jd.sh @@ -0,0 +1,286 @@ +#!/usr/bin/env sh + +# +#JD_ACCESS_KEY_ID="sdfsdfsdfljlbjkljlkjsdfoiwje" +#JD_ACCESS_KEY_SECRET="xxxxxxx" +#JD_REGION="cn-north-1" + +_JD_ACCOUNT="https://uc.jdcloud.com/account/accesskey" + +_JD_PROD="clouddnsservice" +_JD_API="jdcloud-api.com" + +_JD_API_VERSION="v1" +_JD_DEFAULT_REGION="cn-north-1" + +_JD_HOST="$_JD_PROD.$_JD_API" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_jd_add() { + fulldomain=$1 + txtvalue=$2 + + JD_ACCESS_KEY_ID="${JD_ACCESS_KEY_ID:-$(_readaccountconf_mutable JD_ACCESS_KEY_ID)}" + JD_ACCESS_KEY_SECRET="${JD_ACCESS_KEY_SECRET:-$(_readaccountconf_mutable JD_ACCESS_KEY_SECRET)}" + JD_REGION="${JD_REGION:-$(_readaccountconf_mutable JD_REGION)}" + + if [ -z "$JD_ACCESS_KEY_ID" ] || [ -z "$JD_ACCESS_KEY_SECRET" ]; then + JD_ACCESS_KEY_ID="" + JD_ACCESS_KEY_SECRET="" + _err "You haven't specifed the jdcloud api key id or api key secret yet." + _err "Please create your key and try again. see $(__green $_JD_ACCOUNT)" + return 1 + fi + + _saveaccountconf_mutable JD_ACCESS_KEY_ID "$JD_ACCESS_KEY_ID" + _saveaccountconf_mutable JD_ACCESS_KEY_SECRET "$JD_ACCESS_KEY_SECRET" + if [ -z "$JD_REGION" ]; then + _debug "Using default region: $_JD_DEFAULT_REGION" + JD_REGION="$_JD_DEFAULT_REGION" + else + _saveaccountconf_mutable JD_REGION "$JD_REGION" + fi + _JD_BASE_URI="$_JD_API_VERSION/regions/$JD_REGION" + + _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 getViewTree" + + _debug "Adding records" + + _addrr="{\"req\":{\"hostRecord\":\"$_sub_domain\",\"hostValue\":\"$txtvalue\",\"ttl\":300,\"type\":\"TXT\",\"viewValue\":-1},\"regionId\":\"$JD_REGION\",\"domainId\":\"$_domain_id\"}" + #_addrr='{"req":{"hostRecord":"xx","hostValue":"\"value4\"","jcloudRes":false,"mxPriority":null,"port":null,"ttl":300,"type":"TXT","weight":null,"viewValue":-1},"regionId":"cn-north-1","domainId":"8824"}' + if jd_rest POST "domain/$_domain_id/RRAdd" "" "$_addrr"; then + _rid="$(echo "$response" | tr '{},' '\n' | grep '"id":' | cut -d : -f 2)" + if [ -z "$_rid" ]; then + _err "Can not find record id from the result." + return 1 + fi + _info "TXT record added successfully." + _srid="$(_readdomainconf "JD_CLOUD_RIDS")" + if [ "$_srid" ]; then + _rid="$_srid,$_rid" + fi + _savedomainconf "JD_CLOUD_RIDS" "$_rid" + return 0 + fi + + return 1 +} + +dns_jd_rm() { + fulldomain=$1 + txtvalue=$2 + + JD_ACCESS_KEY_ID="${JD_ACCESS_KEY_ID:-$(_readaccountconf_mutable JD_ACCESS_KEY_ID)}" + JD_ACCESS_KEY_SECRET="${JD_ACCESS_KEY_SECRET:-$(_readaccountconf_mutable JD_ACCESS_KEY_SECRET)}" + JD_REGION="${JD_REGION:-$(_readaccountconf_mutable JD_REGION)}" + + if [ -z "$JD_REGION" ]; then + _debug "Using default region: $_JD_DEFAULT_REGION" + JD_REGION="$_JD_DEFAULT_REGION" + fi + + _JD_BASE_URI="$_JD_API_VERSION/regions/$JD_REGION" + + _info "Getting existing records for $fulldomain" + _srid="$(_readdomainconf "JD_CLOUD_RIDS")" + _debug _srid "$_srid" + + if [ -z "$_srid" ]; then + _err "Not rid skip" + return 0 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _cleardomainconf JD_CLOUD_RIDS + + _aws_tmpl_xml="{\"ids\":[$_srid],\"action\":\"del\",\"regionId\":\"$JD_REGION\",\"domainId\":\"$_domain_id\"}" + + if jd_rest POST "domain/$_domain_id/RROperate" "" "$_aws_tmpl_xml" && _contains "$response" "\"code\":\"OK\""; then + _info "TXT record deleted successfully." + return 0 + fi + return 1 + +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + i=1 + p=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug2 "Checking domain: $h" + if ! jd_rest GET "domain"; then + _err "error get domain list" + return 1 + fi + if [ -z "$h" ]; then + #not valid + _err "Invalid domain" + return 1 + fi + + if _contains "$response" "\"domainName\":\"$h\""; then + hostedzone="$(echo "$response" | tr '{}' '\n' | grep "\"domainName\":\"$h\"")" + _debug hostedzone "$hostedzone" + if [ "$hostedzone" ]; then + _domain_id="$(echo "$hostedzone" | tr ',' '\n' | grep "\"id\":" | cut -d : -f 2)" + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + fi + _err "Can't find domain with id: $h" + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +#method uri qstr data +jd_rest() { + mtd="$1" + ep="$2" + qsr="$3" + data="$4" + + _debug mtd "$mtd" + _debug ep "$ep" + _debug qsr "$qsr" + _debug data "$data" + + CanonicalURI="/$_JD_BASE_URI/$ep" + _debug2 CanonicalURI "$CanonicalURI" + + CanonicalQueryString="$qsr" + _debug2 CanonicalQueryString "$CanonicalQueryString" + + RequestDate="$(date -u +"%Y%m%dT%H%M%SZ")" + #RequestDate="20190713T082155Z" ###################################################### + _debug2 RequestDate "$RequestDate" + export _H1="X-Jdcloud-Date: $RequestDate" + + RequestNonce="2bd0852a-8bae-4087-b2d5-$(_time)" + #RequestNonce="894baff5-72d4-4244-883a-7b2eb51e7fbe" ################################# + _debug2 RequestNonce "$RequestNonce" + export _H2="X-Jdcloud-Nonce: $RequestNonce" + + if [ "$data" ]; then + CanonicalHeaders="content-type:application/json\n" + SignedHeaders="content-type;" + else + CanonicalHeaders="" + SignedHeaders="" + fi + CanonicalHeaders="${CanonicalHeaders}host:$_JD_HOST\nx-jdcloud-date:$RequestDate\nx-jdcloud-nonce:$RequestNonce\n" + SignedHeaders="${SignedHeaders}host;x-jdcloud-date;x-jdcloud-nonce" + + _debug2 CanonicalHeaders "$CanonicalHeaders" + _debug2 SignedHeaders "$SignedHeaders" + + Hash="sha256" + + RequestPayload="$data" + _debug2 RequestPayload "$RequestPayload" + + RequestPayloadHash="$(printf "%s" "$RequestPayload" | _digest "$Hash" hex | _lower_case)" + _debug2 RequestPayloadHash "$RequestPayloadHash" + + CanonicalRequest="$mtd\n$CanonicalURI\n$CanonicalQueryString\n$CanonicalHeaders\n$SignedHeaders\n$RequestPayloadHash" + _debug2 CanonicalRequest "$CanonicalRequest" + + HashedCanonicalRequest="$(printf "$CanonicalRequest%s" | _digest "$Hash" hex)" + _debug2 HashedCanonicalRequest "$HashedCanonicalRequest" + + Algorithm="JDCLOUD2-HMAC-SHA256" + _debug2 Algorithm "$Algorithm" + + RequestDateOnly="$(echo "$RequestDate" | cut -c 1-8)" + _debug2 RequestDateOnly "$RequestDateOnly" + + Region="$JD_REGION" + Service="$_JD_PROD" + + CredentialScope="$RequestDateOnly/$Region/$Service/jdcloud2_request" + _debug2 CredentialScope "$CredentialScope" + + StringToSign="$Algorithm\n$RequestDate\n$CredentialScope\n$HashedCanonicalRequest" + + _debug2 StringToSign "$StringToSign" + + kSecret="JDCLOUD2$JD_ACCESS_KEY_SECRET" + + _secure_debug2 kSecret "$kSecret" + + kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")" + _secure_debug2 kSecretH "$kSecretH" + + kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" + _debug2 kDateH "$kDateH" + + kRegionH="$(printf "$Region%s" | _hmac "$Hash" "$kDateH" hex)" + _debug2 kRegionH "$kRegionH" + + kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)" + _debug2 kServiceH "$kServiceH" + + kSigningH="$(printf "%s" "jdcloud2_request" | _hmac "$Hash" "$kServiceH" hex)" + _debug2 kSigningH "$kSigningH" + + signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)" + _debug2 signature "$signature" + + Authorization="$Algorithm Credential=$JD_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" + _debug2 Authorization "$Authorization" + + _H3="Authorization: $Authorization" + _debug _H3 "$_H3" + + url="https://$_JD_HOST$CanonicalURI" + if [ "$qsr" ]; then + url="https://$_JD_HOST$CanonicalURI?$qsr" + fi + + if [ "$mtd" = "GET" ]; then + response="$(_get "$url")" + else + response="$(_post "$data" "$url" "" "$mtd" "application/json")" + fi + + _ret="$?" + _debug2 response "$response" + if [ "$_ret" = "0" ]; then + if _contains "$response" "\"error\""; then + _err "Response error:$response" + return 1 + fi + fi + + return "$_ret" +} From 28a9df669d80e696677ef5ca0248e2801a7bfc0e Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sat, 13 Jul 2019 14:35:09 +0200 Subject: [PATCH 466/565] Escape slashes (#2375) --- dnsapi/dns_namecheap.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index 6553deb..a82e12d 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -164,7 +164,7 @@ _namecheap_set_publicip() { _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)://.*') + addr=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '(http|https):\/\/.*') _debug2 ip "$ip" _debug2 addr "$addr" From 3cdfa4051d98a0bbc1dab64d8028556324b1e0a4 Mon Sep 17 00:00:00 2001 From: Jeff Wang <3102114+wangqiliang@users.noreply.github.com> Date: Sat, 13 Jul 2019 23:05:30 +0800 Subject: [PATCH 467/565] Change 1.1.1.1 to 1.0.0.1 to probe compatibility (#2330) As we can see, 1.1.1.1 is not routed or routed to an Intranet devices due to historical reason. Change 1.1.1.1 to 1.0.0.1 will have a better compatibility. I found this problem on my Tencent Cloud server. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 67fcdcb..d168b56 100755 --- a/acme.sh +++ b/acme.sh @@ -3621,7 +3621,7 @@ _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" + _cf_purl="https://1.0.0.1/api/v1/purge?domain=$_cf_d&type=$_cf_d_type" response="$(_post "" "$_cf_purl")" _debug2 response "$response" } From 28cadc5e06f9d79ba315636e240514c197656bf6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 18 Jul 2019 21:05:59 +0800 Subject: [PATCH 468/565] check empty id --- dnsapi/dns_namesilo.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_namesilo.sh b/dnsapi/dns_namesilo.sh index dc1a4fd..15e4f21 100755 --- a/dnsapi/dns_namesilo.sh +++ b/dnsapi/dns_namesilo.sh @@ -59,9 +59,14 @@ dns_namesilo_rm() { if _namesilo_rest GET "dnsListRecords?version=1&type=xml&key=$Namesilo_Key&domain=$_domain"; then retcode=$(printf "%s\n" "$response" | _egrep_o "300") if [ "$retcode" ]; then - _record_id=$(printf "%s\n" "$response" | _egrep_o "([^<]*)TXT$fulldomain" | _egrep_o "([^<]*)" | sed -r "s/([^<]*)<\/record_id>/\1/" | tail -n 1) + _record_id=$(echo "$response" | _egrep_o "([^<]*)TXT$fulldomain" | _egrep_o "([^<]*)" | sed -r "s/([^<]*)<\/record_id>/\1/" | tail -n 1) _debug record_id "$_record_id" - _info "Successfully retrieved the record id for ACME challenge." + if [ "$record_id" ]; then + _info "Successfully retrieved the record id for ACME challenge." + else + _info "Empty record id, it seems no such record." + return 0 + fi else _err "Unable to retrieve the record id." return 1 From 5c09788ec4cacc85a426f3444436b5b374976cff Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 18 Jul 2019 22:20:51 +0800 Subject: [PATCH 469/565] fix error --- dnsapi/dns_namesilo.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_namesilo.sh b/dnsapi/dns_namesilo.sh index 15e4f21..ed6d0e0 100755 --- a/dnsapi/dns_namesilo.sh +++ b/dnsapi/dns_namesilo.sh @@ -60,8 +60,8 @@ dns_namesilo_rm() { retcode=$(printf "%s\n" "$response" | _egrep_o "300") if [ "$retcode" ]; then _record_id=$(echo "$response" | _egrep_o "([^<]*)TXT$fulldomain" | _egrep_o "([^<]*)" | sed -r "s/([^<]*)<\/record_id>/\1/" | tail -n 1) - _debug record_id "$_record_id" - if [ "$record_id" ]; then + _debug _record_id "$_record_id" + if [ "$_record_id" ]; then _info "Successfully retrieved the record id for ACME challenge." else _info "Empty record id, it seems no such record." From 8d393ff13722bf7acfac84879363b8d50a04c7b7 Mon Sep 17 00:00:00 2001 From: Yuri S Date: Sat, 20 Jul 2019 09:26:23 +0500 Subject: [PATCH 470/565] Add dnsapi for Vultr (#2370) * Add Vultr dns api --- dnsapi/dns_vultr.sh | 163 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 dnsapi/dns_vultr.sh diff --git a/dnsapi/dns_vultr.sh b/dnsapi/dns_vultr.sh new file mode 100644 index 0000000..f15e7c4 --- /dev/null +++ b/dnsapi/dns_vultr.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env sh + +# +#VULTR_API_KEY=000011112222333344445555666677778888 + +VULTR_Api="https://api.vultr.com/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_vultr_add() { + fulldomain=$1 + txtvalue=$2 + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + VULTR_API_KEY="${VULTR_API_KEY:-$(_readaccountconf_mutable VULTR_API_KEY)}" + if test -z "$VULTR_API_KEY"; then + VULTR_API_KEY='' + _err 'VULTR_API_KEY was not exported' + return 1 + fi + + _saveaccountconf_mutable VULTR_API_KEY "$VULTR_API_KEY" + + _debug 'First detect the root zone' + if ! _get_root "$fulldomain"; then + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug 'Getting txt records' + _vultr_rest GET "dns/records?domain=$_domain" + + if printf "%s\n" "$response" | grep "\"type\":\"TXT\",\"name\":\"$fulldomain\"" >/dev/null; then + _err 'Error' + return 1 + fi + + if ! _vultr_rest POST 'dns/create_record' "domain=$_domain&name=$_sub_domain&data=\"$txtvalue\"&type=TXT"; then + _err "$response" + return 1 + fi + + _debug2 _response "$response" + return 0 +} + +#fulldomain txtvalue +dns_vultr_rm() { + fulldomain=$1 + txtvalue=$2 + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + VULTR_API_KEY="${VULTR_API_KEY:-$(_readaccountconf_mutable VULTR_API_KEY)}" + if test -z "$VULTR_API_KEY"; then + VULTR_API_KEY="" + _err 'VULTR_API_KEY was not exported' + return 1 + fi + + _saveaccountconf_mutable VULTR_API_KEY "$VULTR_API_KEY" + + _debug 'First detect the root zone' + if ! _get_root "$fulldomain"; then + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug 'Getting txt records' + _vultr_rest GET "dns/records?domain=$_domain" + + if printf "%s\n" "$response" | grep "\"type\":\"TXT\",\"name\":\"$fulldomain\"" >/dev/null; then + _err 'Error' + return 1 + fi + + _record_id="$(echo "$response" | tr '{}' '\n' | grep '"TXT"' | grep "$txtvalue" | tr ',' '\n' | grep -i 'RECORDID' | cut -d : -f 2)" + _debug _record_id "$_record_id" + if [ "$_record_id" ]; then + _info "Successfully retrieved the record id for ACME challenge." + else + _info "Empty record id, it seems no such record." + return 0 + fi + + if ! _vultr_rest POST 'dns/delete_record' "domain=$_domain&RECORDID=$_record_id"; then + _err "$response" + return 1 + fi + + _debug2 _response "$response" + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + return 1 + fi + + if ! _vultr_rest GET "dns/list"; then + return 1 + fi + + if printf "%s\n" "$response" | grep '^\[.*\]' >/dev/null; then + if _contains "$response" "\"domain\":\"$_domain\""; then + _sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")" + _domain=$_domain + return 0 + else + _err 'Invalid domain' + return 1 + fi + else + _err "$response" + return 1 + fi + i=$(_math "$i" + 1) + done + + return 1 +} + +_vultr_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + api_key_trimmed=$(echo $VULTR_API_KEY | tr -d '"') + + export _H1="Api-Key: $api_key_trimmed" + export _H2='Content-Type: application/x-www-form-urlencoded' + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$VULTR_Api/$ep" "" "$m")" + else + response="$(_get "$VULTR_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "Error $ep" + return 1 + fi + + _debug2 response "$response" + return 0 +} From b8e6287774b64ca42de3b301df7d5b57a3e216af Mon Sep 17 00:00:00 2001 From: tdk1069 Date: Sat, 20 Jul 2019 05:30:56 +0100 Subject: [PATCH 471/565] PushOver notifications (#2325) * PushOver notifications, using AppToken, UserKey, and optional sounds --- notify/pushover.sh | 67 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 notify/pushover.sh diff --git a/notify/pushover.sh b/notify/pushover.sh new file mode 100644 index 0000000..70eba73 --- /dev/null +++ b/notify/pushover.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env sh + +#Support for pushover.net's api. Push notification platform for multiple platforms +#PUSHOVER_TOKEN="" Required, pushover application token +#PUSHOVER_USER="" Required, pushover userkey +#PUSHOVER_DEVICE="" Optional, Specific device or devices by hostnames, joining multiples with a comma (such as device=iphone,nexus5) +#PUSHOVER_PRIORITY="" Optional, Lowest Priority (-2), Low Priority (-1), Normal Priority (0), High Priority (1) + +PUSHOVER_URI="https://api.pushover.net/1/messages.json" + +pushover_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + PUSHOVER_TOKEN="${PUSHOVER_TOKEN:-$(_readaccountconf_mutable PUSHOVER_TOKEN)}" + if [ -z "$PUSHOVER_TOKEN" ]; then + PUSHOVER_TOKEN="" + _err "You didn't specify a PushOver application token yet." + return 1 + fi + _saveaccountconf_mutable PUSHOVER_TOKEN "$PUSHOVER_TOKEN" + + PUSHOVER_USER="${PUSHOVER_USER:-$(_readaccountconf_mutable PUSHOVER_USER)}" + if [ -z "$PUSHOVER_USER" ]; then + PUSHOVER_USER="" + _err "You didn't specify a PushOver UserKey yet." + return 1 + fi + _saveaccountconf_mutable PUSHOVER_USER "$PUSHOVER_USER" + + PUSHOVER_DEVICE="${PUSHOVER_DEVICE:-$(_readaccountconf_mutable PUSHOVER_DEVICE)}" + if [ -z "$PUSHOVER_DEVICE" ]; then + PUSHOVER_DEVICE="" + fi + _saveaccountconf_mutable PUSHOVER_DEVICE "$PUSHOVER_DEVICE" + + PUSHOVER_PRIORITY="${PUSHOVER_PRIORITY:-$(_readaccountconf_mutable PUSHOVER_PRIORITY)}" + if [ -z "$PUSHOVER_PRIORITY" ]; then + PUSHOVER_PRIORITY="0" + fi + _saveaccountconf_mutable PUSHOVER_PRIORITY "$PUSHOVER_PRIORITY" + + + PUSHOVER_SOUND="${PUSHOVER_SOUND:-$(_readaccountconf_mutable PUSHOVER_SOUND)}" + if [ -z "$PUSHOVER_SOUND" ]; then + PUSHOVER_SOUND="" # Play default if not specified. + fi + _saveaccountconf_mutable PUSHOVER_SOUND "$PUSHOVER_SOUND" + + export _H1="Content-Type: application/json" + _content="$(printf "*%s*\n" "$_content" | _json_encode)" + _subject="$(printf "*%s*\n" "$_subject" | _json_encode)" + _data="{\"token\": \"$PUSHOVER_TOKEN\",\"user\": \"$PUSHOVER_USER\",\"title\": \"$_subject\",\"message\": \"$_content\",\"sound\": \"$PUSHOVER_SOUND\", \"device\": \"$PUSHOVER_DEVICE\", \"priority\": \"$PUSHOVER_PRIORITY\"}" + + response="" #just make shellcheck happy + if _post "$_data" "$PUSHOVER_URI"; then + if _contains "$response" "{\"status\":1"; then + _info "PUSHOVER send sccess." + return 0 + fi + fi + _err "PUSHOVER send error." + _err "$response" + return 1 +} From 28c153a0a2dd667f2eb2e810d4f2a3cea4471506 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 20 Jul 2019 12:36:28 +0800 Subject: [PATCH 472/565] fix errors --- notify/pushover.sh | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/notify/pushover.sh b/notify/pushover.sh index 70eba73..309b390 100644 --- a/notify/pushover.sh +++ b/notify/pushover.sh @@ -31,23 +31,20 @@ pushover_send() { _saveaccountconf_mutable PUSHOVER_USER "$PUSHOVER_USER" PUSHOVER_DEVICE="${PUSHOVER_DEVICE:-$(_readaccountconf_mutable PUSHOVER_DEVICE)}" - if [ -z "$PUSHOVER_DEVICE" ]; then - PUSHOVER_DEVICE="" + if [ "$PUSHOVER_DEVICE" ]; then + _saveaccountconf_mutable PUSHOVER_DEVICE "$PUSHOVER_DEVICE" fi - _saveaccountconf_mutable PUSHOVER_DEVICE "$PUSHOVER_DEVICE" PUSHOVER_PRIORITY="${PUSHOVER_PRIORITY:-$(_readaccountconf_mutable PUSHOVER_PRIORITY)}" - if [ -z "$PUSHOVER_PRIORITY" ]; then - PUSHOVER_PRIORITY="0" + if [ "$PUSHOVER_PRIORITY" ]; then + _saveaccountconf_mutable PUSHOVER_PRIORITY "$PUSHOVER_PRIORITY" fi - _saveaccountconf_mutable PUSHOVER_PRIORITY "$PUSHOVER_PRIORITY" - PUSHOVER_SOUND="${PUSHOVER_SOUND:-$(_readaccountconf_mutable PUSHOVER_SOUND)}" - if [ -z "$PUSHOVER_SOUND" ]; then + if [ "$PUSHOVER_SOUND" ]; then PUSHOVER_SOUND="" # Play default if not specified. + _saveaccountconf_mutable PUSHOVER_SOUND "$PUSHOVER_SOUND" fi - _saveaccountconf_mutable PUSHOVER_SOUND "$PUSHOVER_SOUND" export _H1="Content-Type: application/json" _content="$(printf "*%s*\n" "$_content" | _json_encode)" From ccc2142b452a5b86e483fc5d80ff658f91d14146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20Pfeiffer?= Date: Sat, 20 Jul 2019 10:00:38 +0200 Subject: [PATCH 473/565] added dns api support for hexonet (#1776) --- dnsapi/dns_hexonet.sh | 156 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100755 dnsapi/dns_hexonet.sh diff --git a/dnsapi/dns_hexonet.sh b/dnsapi/dns_hexonet.sh new file mode 100755 index 0000000..ccd201e --- /dev/null +++ b/dnsapi/dns_hexonet.sh @@ -0,0 +1,156 @@ +#!/usr/bin/env sh + +# +# Hexonet_Username="username" +# +# Hexonet_Password="password" + +Hexonet_Api="https://coreapi.1api.net/api/call.cgi" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_hexonet_add() { + fulldomain=$1 + txtvalue=$2 + + Hexonet_Username="${Hexonet_Username:-$(_readaccountconf_mutable Hexonet_Username)}" + Hexonet_Password="${Hexonet_Password:-$(_readaccountconf_mutable Hexonet_Password)}" + if [ -z "$Hexonet_Username" ] || [ -z "$Hexonet_Password" ]; then + Hexonet_Username="" + Hexonet_Password="" + _err "You must export variables: Hexonet_Username and Hexonet_Password" + return 1 + fi + + if ! _contains "$Hexonet_Username" "!"; then + _err "It seems that the Hexonet_Username=$Hexonet_Username is not a restrivteed user." + _err "Please check and retry." + return 1 + fi + + #save the username and password to the account conf file. + _saveaccountconf_mutable Hexonet_Username "$Hexonet_Username" + _saveaccountconf_mutable Hexonet_Password "$Hexonet_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" + _hexonet_rest "&command=QueryDNSZoneRRList&dnszone=${h}.&RRTYPE=TXT" + + if ! _contains "$response" "CODE=200"; then + _err "Error" + return 1 + fi + + _info "Adding record" + if _hexonet_rest "command=UpdateDNSZone&dnszone=${_domain}.&addrr0=${_sub_domain}%20IN%20TXT%20${txtvalue}"; then + if _contains "$response" "CODE=200"; 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_hexonet_rm() { + fulldomain=$1 + txtvalue=$2 + + Hexonet_Username="${Hexonet_Username:-$(_readaccountconf_mutable Hexonet_Username)}" + Hexonet_Password="${Hexonet_Password:-$(_readaccountconf_mutable Hexonet_Password)}" + if [ -z "$Hexonet_Username" ] || [ -z "$Hexonet_Password" ]; then + Hexonet_Username="" + Hexonet_Password="" + _err "You must export variables: Hexonet_Username and Hexonet_Password" + 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" + _hexonet_rest "&command=QueryDNSZoneRRList&dnszone=${h}.&RRTYPE=TXT&RR=${txtvalue}" + + if ! _contains "$response" "CODE=200"; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "PROPERTY[TOTAL][0]=" | cut -d = -f 2) + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + if ! _hexonet_rest "&command=UpdateDNSZone&dnszone=${_domain}.&delrr0='${_sub_domain}%20IN%20TXT%20\"${txtvalue}\""; then + _err "Delete record error." + return 1 + fi + _contains "$response" "CODE=200" + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=1 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _hexonet_rest "&command=QueryDNSZoneRRList&dnszone=${h}."; then + return 1 + fi + + if _contains "$response" "CODE=200"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_hexonet_rest() { + query_params="$1" + _debug "$query_params" + + response="$(_get "${Hexonet_Api}?s_login=${Hexonet_Username}&s_pw=${Hexonet_Password}&${query_params}")" + + if [ "$?" != "0" ]; then + _err "error $query_params" + return 1 + fi + _debug2 response "$response" + return 0 +} From 93d29a9733169437cbc5df4a65a8636edbde2c8e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 20 Jul 2019 17:09:36 +0800 Subject: [PATCH 474/565] update --- dnsapi/dns_hexonet.sh | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/dnsapi/dns_hexonet.sh b/dnsapi/dns_hexonet.sh index ccd201e..f150311 100755 --- a/dnsapi/dns_hexonet.sh +++ b/dnsapi/dns_hexonet.sh @@ -1,9 +1,9 @@ #!/usr/bin/env sh # -# Hexonet_Username="username" +# Hexonet_Login="username!roleId" # -# Hexonet_Password="password" +# Hexonet_Password="rolePassword" Hexonet_Api="https://coreapi.1api.net/api/call.cgi" @@ -14,23 +14,23 @@ dns_hexonet_add() { fulldomain=$1 txtvalue=$2 - Hexonet_Username="${Hexonet_Username:-$(_readaccountconf_mutable Hexonet_Username)}" + Hexonet_Login="${Hexonet_Login:-$(_readaccountconf_mutable Hexonet_Login)}" Hexonet_Password="${Hexonet_Password:-$(_readaccountconf_mutable Hexonet_Password)}" - if [ -z "$Hexonet_Username" ] || [ -z "$Hexonet_Password" ]; then - Hexonet_Username="" + if [ -z "$Hexonet_Login" ] || [ -z "$Hexonet_Password" ]; then + Hexonet_Login="" Hexonet_Password="" - _err "You must export variables: Hexonet_Username and Hexonet_Password" + _err "You must export variables: Hexonet_Login and Hexonet_Password" return 1 fi - if ! _contains "$Hexonet_Username" "!"; then - _err "It seems that the Hexonet_Username=$Hexonet_Username is not a restrivteed user." + if ! _contains "$Hexonet_Login" "!"; then + _err "It seems that the Hexonet_Login=$Hexonet_Login is not a restrivteed user." _err "Please check and retry." return 1 fi #save the username and password to the account conf file. - _saveaccountconf_mutable Hexonet_Username "$Hexonet_Username" + _saveaccountconf_mutable Hexonet_Login "$Hexonet_Login" _saveaccountconf_mutable Hexonet_Password "$Hexonet_Password" _debug "First detect the root zone" @@ -69,12 +69,12 @@ dns_hexonet_rm() { fulldomain=$1 txtvalue=$2 - Hexonet_Username="${Hexonet_Username:-$(_readaccountconf_mutable Hexonet_Username)}" + Hexonet_Login="${Hexonet_Login:-$(_readaccountconf_mutable Hexonet_Login)}" Hexonet_Password="${Hexonet_Password:-$(_readaccountconf_mutable Hexonet_Password)}" - if [ -z "$Hexonet_Username" ] || [ -z "$Hexonet_Password" ]; then - Hexonet_Username="" + if [ -z "$Hexonet_Login" ] || [ -z "$Hexonet_Password" ]; then + Hexonet_Login="" Hexonet_Password="" - _err "You must export variables: Hexonet_Username and Hexonet_Password" + _err "You must export variables: Hexonet_Login and Hexonet_Password" return 1 fi @@ -145,7 +145,7 @@ _hexonet_rest() { query_params="$1" _debug "$query_params" - response="$(_get "${Hexonet_Api}?s_login=${Hexonet_Username}&s_pw=${Hexonet_Password}&${query_params}")" + response="$(_get "${Hexonet_Api}?s_login=${Hexonet_Login}&s_pw=${Hexonet_Password}&${query_params}")" if [ "$?" != "0" ]; then _err "error $query_params" From 80af3d6ada23098bb68e3be63e72e0cfd4406ce1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 22 Jul 2019 21:26:47 +0800 Subject: [PATCH 475/565] minor --- notify/pushover.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/notify/pushover.sh b/notify/pushover.sh index 309b390..a07cbd3 100644 --- a/notify/pushover.sh +++ b/notify/pushover.sh @@ -42,7 +42,6 @@ pushover_send() { PUSHOVER_SOUND="${PUSHOVER_SOUND:-$(_readaccountconf_mutable PUSHOVER_SOUND)}" if [ "$PUSHOVER_SOUND" ]; then - PUSHOVER_SOUND="" # Play default if not specified. _saveaccountconf_mutable PUSHOVER_SOUND "$PUSHOVER_SOUND" fi @@ -54,7 +53,7 @@ pushover_send() { response="" #just make shellcheck happy if _post "$_data" "$PUSHOVER_URI"; then if _contains "$response" "{\"status\":1"; then - _info "PUSHOVER send sccess." + _info "PUSHOVER send success." return 0 fi fi From c25947d5447ac03ac0fae56b338e8821d49d61ac Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 22 Jul 2019 22:25:50 +0800 Subject: [PATCH 476/565] support new Cloudflare Token format fix https://github.com/Neilpang/acme.sh/issues/2398 --- dnsapi/dns_cf.sh | 83 +++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index cd93189..d4266d1 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -5,6 +5,9 @@ # #CF_Email="xxxx@sss.com" +#CF_Token="xxxx" +#CF_Account_ID="xxxx" + CF_Api="https://api.cloudflare.com/client/v4" ######## Public functions ##################### @@ -14,26 +17,33 @@ dns_cf_add() { fulldomain=$1 txtvalue=$2 + CF_Token="${CF_Token:-$(_readaccountconf_mutable CF_Token)}" + CF_Account_ID="${CF_Account_ID:-$(_readaccountconf_mutable CF_Account_ID)}" CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" - if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then - CF_Key="" - CF_Email="" - _err "You 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 + + if [ "$CF_Token" ]; then + _saveaccountconf_mutable CF_Token "$CF_Token" + _saveaccountconf_mutable CF_Account_ID "$CF_Account_ID" + else + 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 "You can get yours from here https://dash.cloudflare.com/profile." + return 1 + fi - if ! _contains "$CF_Email" "@"; then - _err "It seems that the CF_Email=$CF_Email is not a valid email address." - _err "Please check and retry." - return 1 + if ! _contains "$CF_Email" "@"; then + _err "It seems that the CF_Email=$CF_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 CF_Key "$CF_Key" + _saveaccountconf_mutable CF_Email "$CF_Email" fi - #save the api key and email to the account conf file. - _saveaccountconf_mutable CF_Key "$CF_Key" - _saveaccountconf_mutable CF_Email "$CF_Email" - _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" @@ -71,19 +81,6 @@ dns_cf_add() { fi _err "Add txt record error." return 1 - # else - # _info "Updating record" - # record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) - # _debug "record_id" "$record_id" - # - # _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" - # if [ "$?" = "0" ]; then - # _info "Updated, OK" - # return 0 - # fi - # _err "Update error" - # return 1 - # fi } @@ -92,15 +89,10 @@ dns_cf_rm() { fulldomain=$1 txtvalue=$2 + CF_Token="${CF_Token:-$(_readaccountconf_mutable CF_Token)}" + CF_Account_ID="${CF_Account_ID:-$(_readaccountconf_mutable CF_Account_ID)}" CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" - if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then - CF_Key="" - CF_Email="" - _err "You 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 _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -157,8 +149,14 @@ _get_root() { return 1 fi - if ! _cf_rest GET "zones?name=$h"; then - return 1 + if [ "$CF_Account_ID" ]; then + if ! _cf_rest GET "zones?name=$h&account.id=$CF_Account_ID"; then + return 1 + fi + else + if ! _cf_rest GET "zones?name=$h"; then + return 1 + fi fi if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_count":1'; then @@ -184,10 +182,15 @@ _cf_rest() { email_trimmed=$(echo $CF_Email | tr -d '"') key_trimmed=$(echo $CF_Key | tr -d '"') + token_trimmed=$(echo $CF_Token | tr -d '"') - export _H1="X-Auth-Email: $email_trimmed" - export _H2="X-Auth-Key: $key_trimmed" - export _H3="Content-Type: application/json" + export _H1="Content-Type: application/json" + if [ "$token_trimmed" ]; then + export _H2="Authorization: Bearer $token_trimmed" + else + export _H2="X-Auth-Email: $email_trimmed" + export _H3="X-Auth-Key: $key_trimmed" + fi if [ "$m" != "GET" ]; then _debug data "$data" From 54e189616c0e96288a42e5fb24ae7fa2846e16d0 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 23 Jul 2019 21:36:42 +0800 Subject: [PATCH 477/565] fix wildcard domain name --- deploy/docker.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deploy/docker.sh b/deploy/docker.sh index 4e55099..44bb044 100755 --- a/deploy/docker.sh +++ b/deploy/docker.sh @@ -223,7 +223,8 @@ _docker_cp() { _debug2 "_frompath" "$_frompath" _toname="$(basename "$_to")" _debug2 "_toname" "$_toname" - if ! tar --transform="s,$_frompath,$_toname," -cz "$_from" 2>/dev/null | _curl_unix_sock "$_DOCKER_SOCK" PUT "/containers/$_dcid/archive?noOverwriteDirNonDir=1&path=$(printf "%s" "$_dir" | _url_encode)" '@-' "Content-Type: application/octet-stream"; then + _debug2 "_from" "$_from" + if ! tar --transform="s,$(printf "%s" "$_frompath" | tr '*' .),$_toname," -cz "$_from" 2>/dev/null | _curl_unix_sock "$_DOCKER_SOCK" PUT "/containers/$_dcid/archive?noOverwriteDirNonDir=1&path=$(printf "%s" "$_dir" | _url_encode)" '@-' "Content-Type: application/octet-stream"; then _err "copy error" return 1 fi From 45e8bb03e438892d974153b5326b06aece628a56 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 23 Jul 2019 21:43:00 +0800 Subject: [PATCH 478/565] add more info --- deploy/docker.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/docker.sh b/deploy/docker.sh index 44bb044..05333b3 100755 --- a/deploy/docker.sh +++ b/deploy/docker.sh @@ -126,6 +126,7 @@ docker_deploy() { fi if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then + _info "Reloading: $DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" if ! _docker_exec "$_cid" "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"; then return 1 fi From 9a733a57e73fbb09f300f8eac5004aafef6e61d6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 24 Jul 2019 21:49:26 +0800 Subject: [PATCH 479/565] fix https://github.com/Neilpang/acme.sh/issues/2377 --- acme.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d168b56..891d2e1 100755 --- a/acme.sh +++ b/acme.sh @@ -3035,11 +3035,13 @@ _clearupdns() { d=$(_getfield "$entry" 1) txtdomain=$(_getfield "$entry" 2) aliasDomain=$(_getfield "$entry" 3) + _currentRoot=$(_getfield "$entry" 4) txt=$(_getfield "$entry" 5) d_api=$(_getfield "$entry" 6) _debug "d" "$d" _debug "txtdomain" "$txtdomain" _debug "aliasDomain" "$aliasDomain" + _debug "_currentRoot" "$_currentRoot" _debug "txt" "$txt" _debug "d_api" "$d_api" if [ "$d_api" = "$txt" ]; then @@ -6787,7 +6789,7 @@ _process() { _debug "Using server: $_server" fi fi - + _debug "Running cmd: ${_CMD}" case "${_CMD}" in install) install "$_nocron" "$_confighome" "$_noprofile" ;; uninstall) uninstall "$_nocron" ;; From 72e7eb6777d14097961422959eaa0e9ecb3becfc Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 27 Jul 2019 10:49:11 +0800 Subject: [PATCH 480/565] 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 d4266d1..f1725bd 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -21,7 +21,7 @@ dns_cf_add() { CF_Account_ID="${CF_Account_ID:-$(_readaccountconf_mutable CF_Account_ID)}" CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" - + if [ "$CF_Token" ]; then _saveaccountconf_mutable CF_Token "$CF_Token" _saveaccountconf_mutable CF_Account_ID "$CF_Account_ID" From 41c951811e38002df1d7efad8b1197368aed4697 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 27 Jul 2019 11:09:13 +0800 Subject: [PATCH 481/565] fix format --- dnsapi/dns_cf.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index f1725bd..62e40ca 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -180,9 +180,9 @@ _cf_rest() { data="$3" _debug "$ep" - email_trimmed=$(echo $CF_Email | tr -d '"') - key_trimmed=$(echo $CF_Key | tr -d '"') - token_trimmed=$(echo $CF_Token | tr -d '"') + email_trimmed=$(echo "$CF_Email" | tr -d '"') + key_trimmed=$(echo "$CF_Key" | tr -d '"') + token_trimmed=$(echo "$CF_Token" | tr -d '"') export _H1="Content-Type: application/json" if [ "$token_trimmed" ]; then From 55dea4ee9d2187912ecf97689e12a6e8183a1091 Mon Sep 17 00:00:00 2001 From: neil <8305679+Neilpang@users.noreply.github.com> Date: Sat, 27 Jul 2019 11:48:29 +0800 Subject: [PATCH 482/565] sync (#2404) * support jdcloud.com * fix format * ttl 3000 * Escape slashes (#2375) * Change 1.1.1.1 to 1.0.0.1 to probe compatibility (#2330) As we can see, 1.1.1.1 is not routed or routed to an Intranet devices due to historical reason. Change 1.1.1.1 to 1.0.0.1 will have a better compatibility. I found this problem on my Tencent Cloud server. * check empty id * fix error * Add dnsapi for Vultr (#2370) * Add Vultr dns api * PushOver notifications (#2325) * PushOver notifications, using AppToken, UserKey, and optional sounds * fix errors * added dns api support for hexonet (#1776) * update * minor * support new Cloudflare Token format fix https://github.com/Neilpang/acme.sh/issues/2398 * fix wildcard domain name * add more info * fix https://github.com/Neilpang/acme.sh/issues/2377 * fix format * fix format --- acme.sh | 6 +- deploy/docker.sh | 4 +- dnsapi/dns_cf.sh | 87 ++++++++++----------- dnsapi/dns_hexonet.sh | 156 ++++++++++++++++++++++++++++++++++++++ dnsapi/dns_namecheap.sh | 2 +- dnsapi/dns_namesilo.sh | 11 ++- dnsapi/dns_vultr.sh | 163 ++++++++++++++++++++++++++++++++++++++++ notify/pushover.sh | 63 ++++++++++++++++ 8 files changed, 443 insertions(+), 49 deletions(-) create mode 100755 dnsapi/dns_hexonet.sh create mode 100644 dnsapi/dns_vultr.sh create mode 100644 notify/pushover.sh diff --git a/acme.sh b/acme.sh index 67fcdcb..891d2e1 100755 --- a/acme.sh +++ b/acme.sh @@ -3035,11 +3035,13 @@ _clearupdns() { d=$(_getfield "$entry" 1) txtdomain=$(_getfield "$entry" 2) aliasDomain=$(_getfield "$entry" 3) + _currentRoot=$(_getfield "$entry" 4) txt=$(_getfield "$entry" 5) d_api=$(_getfield "$entry" 6) _debug "d" "$d" _debug "txtdomain" "$txtdomain" _debug "aliasDomain" "$aliasDomain" + _debug "_currentRoot" "$_currentRoot" _debug "txt" "$txt" _debug "d_api" "$d_api" if [ "$d_api" = "$txt" ]; then @@ -3621,7 +3623,7 @@ _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" + _cf_purl="https://1.0.0.1/api/v1/purge?domain=$_cf_d&type=$_cf_d_type" response="$(_post "" "$_cf_purl")" _debug2 response "$response" } @@ -6787,7 +6789,7 @@ _process() { _debug "Using server: $_server" fi fi - + _debug "Running cmd: ${_CMD}" case "${_CMD}" in install) install "$_nocron" "$_confighome" "$_noprofile" ;; uninstall) uninstall "$_nocron" ;; diff --git a/deploy/docker.sh b/deploy/docker.sh index 4e55099..05333b3 100755 --- a/deploy/docker.sh +++ b/deploy/docker.sh @@ -126,6 +126,7 @@ docker_deploy() { fi if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then + _info "Reloading: $DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" if ! _docker_exec "$_cid" "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"; then return 1 fi @@ -223,7 +224,8 @@ _docker_cp() { _debug2 "_frompath" "$_frompath" _toname="$(basename "$_to")" _debug2 "_toname" "$_toname" - if ! tar --transform="s,$_frompath,$_toname," -cz "$_from" 2>/dev/null | _curl_unix_sock "$_DOCKER_SOCK" PUT "/containers/$_dcid/archive?noOverwriteDirNonDir=1&path=$(printf "%s" "$_dir" | _url_encode)" '@-' "Content-Type: application/octet-stream"; then + _debug2 "_from" "$_from" + if ! tar --transform="s,$(printf "%s" "$_frompath" | tr '*' .),$_toname," -cz "$_from" 2>/dev/null | _curl_unix_sock "$_DOCKER_SOCK" PUT "/containers/$_dcid/archive?noOverwriteDirNonDir=1&path=$(printf "%s" "$_dir" | _url_encode)" '@-' "Content-Type: application/octet-stream"; then _err "copy error" return 1 fi diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index cd93189..62e40ca 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -5,6 +5,9 @@ # #CF_Email="xxxx@sss.com" +#CF_Token="xxxx" +#CF_Account_ID="xxxx" + CF_Api="https://api.cloudflare.com/client/v4" ######## Public functions ##################### @@ -14,25 +17,32 @@ dns_cf_add() { fulldomain=$1 txtvalue=$2 + CF_Token="${CF_Token:-$(_readaccountconf_mutable CF_Token)}" + CF_Account_ID="${CF_Account_ID:-$(_readaccountconf_mutable CF_Account_ID)}" CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" - if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then - CF_Key="" - CF_Email="" - _err "You 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 - if ! _contains "$CF_Email" "@"; then - _err "It seems that the CF_Email=$CF_Email is not a valid email address." - _err "Please check and retry." - return 1 - fi + if [ "$CF_Token" ]; then + _saveaccountconf_mutable CF_Token "$CF_Token" + _saveaccountconf_mutable CF_Account_ID "$CF_Account_ID" + else + 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 "You can get yours from here https://dash.cloudflare.com/profile." + return 1 + fi - #save the api key and email to the account conf file. - _saveaccountconf_mutable CF_Key "$CF_Key" - _saveaccountconf_mutable CF_Email "$CF_Email" + if ! _contains "$CF_Email" "@"; then + _err "It seems that the CF_Email=$CF_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 CF_Key "$CF_Key" + _saveaccountconf_mutable CF_Email "$CF_Email" + fi _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -71,19 +81,6 @@ dns_cf_add() { fi _err "Add txt record error." return 1 - # else - # _info "Updating record" - # record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) - # _debug "record_id" "$record_id" - # - # _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" - # if [ "$?" = "0" ]; then - # _info "Updated, OK" - # return 0 - # fi - # _err "Update error" - # return 1 - # fi } @@ -92,15 +89,10 @@ dns_cf_rm() { fulldomain=$1 txtvalue=$2 + CF_Token="${CF_Token:-$(_readaccountconf_mutable CF_Token)}" + CF_Account_ID="${CF_Account_ID:-$(_readaccountconf_mutable CF_Account_ID)}" CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" - if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then - CF_Key="" - CF_Email="" - _err "You 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 _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -157,8 +149,14 @@ _get_root() { return 1 fi - if ! _cf_rest GET "zones?name=$h"; then - return 1 + if [ "$CF_Account_ID" ]; then + if ! _cf_rest GET "zones?name=$h&account.id=$CF_Account_ID"; then + return 1 + fi + else + if ! _cf_rest GET "zones?name=$h"; then + return 1 + fi fi if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_count":1'; then @@ -182,12 +180,17 @@ _cf_rest() { data="$3" _debug "$ep" - email_trimmed=$(echo $CF_Email | tr -d '"') - key_trimmed=$(echo $CF_Key | tr -d '"') + email_trimmed=$(echo "$CF_Email" | tr -d '"') + key_trimmed=$(echo "$CF_Key" | tr -d '"') + token_trimmed=$(echo "$CF_Token" | tr -d '"') - export _H1="X-Auth-Email: $email_trimmed" - export _H2="X-Auth-Key: $key_trimmed" - export _H3="Content-Type: application/json" + export _H1="Content-Type: application/json" + if [ "$token_trimmed" ]; then + export _H2="Authorization: Bearer $token_trimmed" + else + export _H2="X-Auth-Email: $email_trimmed" + export _H3="X-Auth-Key: $key_trimmed" + fi if [ "$m" != "GET" ]; then _debug data "$data" diff --git a/dnsapi/dns_hexonet.sh b/dnsapi/dns_hexonet.sh new file mode 100755 index 0000000..f150311 --- /dev/null +++ b/dnsapi/dns_hexonet.sh @@ -0,0 +1,156 @@ +#!/usr/bin/env sh + +# +# Hexonet_Login="username!roleId" +# +# Hexonet_Password="rolePassword" + +Hexonet_Api="https://coreapi.1api.net/api/call.cgi" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_hexonet_add() { + fulldomain=$1 + txtvalue=$2 + + Hexonet_Login="${Hexonet_Login:-$(_readaccountconf_mutable Hexonet_Login)}" + Hexonet_Password="${Hexonet_Password:-$(_readaccountconf_mutable Hexonet_Password)}" + if [ -z "$Hexonet_Login" ] || [ -z "$Hexonet_Password" ]; then + Hexonet_Login="" + Hexonet_Password="" + _err "You must export variables: Hexonet_Login and Hexonet_Password" + return 1 + fi + + if ! _contains "$Hexonet_Login" "!"; then + _err "It seems that the Hexonet_Login=$Hexonet_Login is not a restrivteed user." + _err "Please check and retry." + return 1 + fi + + #save the username and password to the account conf file. + _saveaccountconf_mutable Hexonet_Login "$Hexonet_Login" + _saveaccountconf_mutable Hexonet_Password "$Hexonet_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" + _hexonet_rest "&command=QueryDNSZoneRRList&dnszone=${h}.&RRTYPE=TXT" + + if ! _contains "$response" "CODE=200"; then + _err "Error" + return 1 + fi + + _info "Adding record" + if _hexonet_rest "command=UpdateDNSZone&dnszone=${_domain}.&addrr0=${_sub_domain}%20IN%20TXT%20${txtvalue}"; then + if _contains "$response" "CODE=200"; 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_hexonet_rm() { + fulldomain=$1 + txtvalue=$2 + + Hexonet_Login="${Hexonet_Login:-$(_readaccountconf_mutable Hexonet_Login)}" + Hexonet_Password="${Hexonet_Password:-$(_readaccountconf_mutable Hexonet_Password)}" + if [ -z "$Hexonet_Login" ] || [ -z "$Hexonet_Password" ]; then + Hexonet_Login="" + Hexonet_Password="" + _err "You must export variables: Hexonet_Login and Hexonet_Password" + 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" + _hexonet_rest "&command=QueryDNSZoneRRList&dnszone=${h}.&RRTYPE=TXT&RR=${txtvalue}" + + if ! _contains "$response" "CODE=200"; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "PROPERTY[TOTAL][0]=" | cut -d = -f 2) + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + if ! _hexonet_rest "&command=UpdateDNSZone&dnszone=${_domain}.&delrr0='${_sub_domain}%20IN%20TXT%20\"${txtvalue}\""; then + _err "Delete record error." + return 1 + fi + _contains "$response" "CODE=200" + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=1 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _hexonet_rest "&command=QueryDNSZoneRRList&dnszone=${h}."; then + return 1 + fi + + if _contains "$response" "CODE=200"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_hexonet_rest() { + query_params="$1" + _debug "$query_params" + + response="$(_get "${Hexonet_Api}?s_login=${Hexonet_Login}&s_pw=${Hexonet_Password}&${query_params}")" + + if [ "$?" != "0" ]; then + _err "error $query_params" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index 6553deb..a82e12d 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -164,7 +164,7 @@ _namecheap_set_publicip() { _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)://.*') + addr=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '(http|https):\/\/.*') _debug2 ip "$ip" _debug2 addr "$addr" diff --git a/dnsapi/dns_namesilo.sh b/dnsapi/dns_namesilo.sh index dc1a4fd..ed6d0e0 100755 --- a/dnsapi/dns_namesilo.sh +++ b/dnsapi/dns_namesilo.sh @@ -59,9 +59,14 @@ dns_namesilo_rm() { if _namesilo_rest GET "dnsListRecords?version=1&type=xml&key=$Namesilo_Key&domain=$_domain"; then retcode=$(printf "%s\n" "$response" | _egrep_o "300") if [ "$retcode" ]; then - _record_id=$(printf "%s\n" "$response" | _egrep_o "([^<]*)TXT$fulldomain" | _egrep_o "([^<]*)" | sed -r "s/([^<]*)<\/record_id>/\1/" | tail -n 1) - _debug record_id "$_record_id" - _info "Successfully retrieved the record id for ACME challenge." + _record_id=$(echo "$response" | _egrep_o "([^<]*)TXT$fulldomain" | _egrep_o "([^<]*)" | sed -r "s/([^<]*)<\/record_id>/\1/" | tail -n 1) + _debug _record_id "$_record_id" + if [ "$_record_id" ]; then + _info "Successfully retrieved the record id for ACME challenge." + else + _info "Empty record id, it seems no such record." + return 0 + fi else _err "Unable to retrieve the record id." return 1 diff --git a/dnsapi/dns_vultr.sh b/dnsapi/dns_vultr.sh new file mode 100644 index 0000000..f15e7c4 --- /dev/null +++ b/dnsapi/dns_vultr.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env sh + +# +#VULTR_API_KEY=000011112222333344445555666677778888 + +VULTR_Api="https://api.vultr.com/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_vultr_add() { + fulldomain=$1 + txtvalue=$2 + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + VULTR_API_KEY="${VULTR_API_KEY:-$(_readaccountconf_mutable VULTR_API_KEY)}" + if test -z "$VULTR_API_KEY"; then + VULTR_API_KEY='' + _err 'VULTR_API_KEY was not exported' + return 1 + fi + + _saveaccountconf_mutable VULTR_API_KEY "$VULTR_API_KEY" + + _debug 'First detect the root zone' + if ! _get_root "$fulldomain"; then + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug 'Getting txt records' + _vultr_rest GET "dns/records?domain=$_domain" + + if printf "%s\n" "$response" | grep "\"type\":\"TXT\",\"name\":\"$fulldomain\"" >/dev/null; then + _err 'Error' + return 1 + fi + + if ! _vultr_rest POST 'dns/create_record' "domain=$_domain&name=$_sub_domain&data=\"$txtvalue\"&type=TXT"; then + _err "$response" + return 1 + fi + + _debug2 _response "$response" + return 0 +} + +#fulldomain txtvalue +dns_vultr_rm() { + fulldomain=$1 + txtvalue=$2 + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + VULTR_API_KEY="${VULTR_API_KEY:-$(_readaccountconf_mutable VULTR_API_KEY)}" + if test -z "$VULTR_API_KEY"; then + VULTR_API_KEY="" + _err 'VULTR_API_KEY was not exported' + return 1 + fi + + _saveaccountconf_mutable VULTR_API_KEY "$VULTR_API_KEY" + + _debug 'First detect the root zone' + if ! _get_root "$fulldomain"; then + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug 'Getting txt records' + _vultr_rest GET "dns/records?domain=$_domain" + + if printf "%s\n" "$response" | grep "\"type\":\"TXT\",\"name\":\"$fulldomain\"" >/dev/null; then + _err 'Error' + return 1 + fi + + _record_id="$(echo "$response" | tr '{}' '\n' | grep '"TXT"' | grep "$txtvalue" | tr ',' '\n' | grep -i 'RECORDID' | cut -d : -f 2)" + _debug _record_id "$_record_id" + if [ "$_record_id" ]; then + _info "Successfully retrieved the record id for ACME challenge." + else + _info "Empty record id, it seems no such record." + return 0 + fi + + if ! _vultr_rest POST 'dns/delete_record' "domain=$_domain&RECORDID=$_record_id"; then + _err "$response" + return 1 + fi + + _debug2 _response "$response" + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + return 1 + fi + + if ! _vultr_rest GET "dns/list"; then + return 1 + fi + + if printf "%s\n" "$response" | grep '^\[.*\]' >/dev/null; then + if _contains "$response" "\"domain\":\"$_domain\""; then + _sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")" + _domain=$_domain + return 0 + else + _err 'Invalid domain' + return 1 + fi + else + _err "$response" + return 1 + fi + i=$(_math "$i" + 1) + done + + return 1 +} + +_vultr_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + api_key_trimmed=$(echo $VULTR_API_KEY | tr -d '"') + + export _H1="Api-Key: $api_key_trimmed" + export _H2='Content-Type: application/x-www-form-urlencoded' + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$VULTR_Api/$ep" "" "$m")" + else + response="$(_get "$VULTR_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "Error $ep" + return 1 + fi + + _debug2 response "$response" + return 0 +} diff --git a/notify/pushover.sh b/notify/pushover.sh new file mode 100644 index 0000000..a07cbd3 --- /dev/null +++ b/notify/pushover.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env sh + +#Support for pushover.net's api. Push notification platform for multiple platforms +#PUSHOVER_TOKEN="" Required, pushover application token +#PUSHOVER_USER="" Required, pushover userkey +#PUSHOVER_DEVICE="" Optional, Specific device or devices by hostnames, joining multiples with a comma (such as device=iphone,nexus5) +#PUSHOVER_PRIORITY="" Optional, Lowest Priority (-2), Low Priority (-1), Normal Priority (0), High Priority (1) + +PUSHOVER_URI="https://api.pushover.net/1/messages.json" + +pushover_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + PUSHOVER_TOKEN="${PUSHOVER_TOKEN:-$(_readaccountconf_mutable PUSHOVER_TOKEN)}" + if [ -z "$PUSHOVER_TOKEN" ]; then + PUSHOVER_TOKEN="" + _err "You didn't specify a PushOver application token yet." + return 1 + fi + _saveaccountconf_mutable PUSHOVER_TOKEN "$PUSHOVER_TOKEN" + + PUSHOVER_USER="${PUSHOVER_USER:-$(_readaccountconf_mutable PUSHOVER_USER)}" + if [ -z "$PUSHOVER_USER" ]; then + PUSHOVER_USER="" + _err "You didn't specify a PushOver UserKey yet." + return 1 + fi + _saveaccountconf_mutable PUSHOVER_USER "$PUSHOVER_USER" + + PUSHOVER_DEVICE="${PUSHOVER_DEVICE:-$(_readaccountconf_mutable PUSHOVER_DEVICE)}" + if [ "$PUSHOVER_DEVICE" ]; then + _saveaccountconf_mutable PUSHOVER_DEVICE "$PUSHOVER_DEVICE" + fi + + PUSHOVER_PRIORITY="${PUSHOVER_PRIORITY:-$(_readaccountconf_mutable PUSHOVER_PRIORITY)}" + if [ "$PUSHOVER_PRIORITY" ]; then + _saveaccountconf_mutable PUSHOVER_PRIORITY "$PUSHOVER_PRIORITY" + fi + + PUSHOVER_SOUND="${PUSHOVER_SOUND:-$(_readaccountconf_mutable PUSHOVER_SOUND)}" + if [ "$PUSHOVER_SOUND" ]; then + _saveaccountconf_mutable PUSHOVER_SOUND "$PUSHOVER_SOUND" + fi + + export _H1="Content-Type: application/json" + _content="$(printf "*%s*\n" "$_content" | _json_encode)" + _subject="$(printf "*%s*\n" "$_subject" | _json_encode)" + _data="{\"token\": \"$PUSHOVER_TOKEN\",\"user\": \"$PUSHOVER_USER\",\"title\": \"$_subject\",\"message\": \"$_content\",\"sound\": \"$PUSHOVER_SOUND\", \"device\": \"$PUSHOVER_DEVICE\", \"priority\": \"$PUSHOVER_PRIORITY\"}" + + response="" #just make shellcheck happy + if _post "$_data" "$PUSHOVER_URI"; then + if _contains "$response" "{\"status\":1"; then + _info "PUSHOVER send success." + return 0 + fi + fi + _err "PUSHOVER send error." + _err "$response" + return 1 +} From b9b2cd278b098b7e43143e58809878f1e8fbcf2b Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 29 Jul 2019 21:12:19 +0800 Subject: [PATCH 483/565] fix https://github.com/Neilpang/acme.sh/pull/2275 --- acme.sh | 4 ++-- dnsapi/dns_dp.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 891d2e1..66d9b7a 100755 --- a/acme.sh +++ b/acme.sh @@ -3623,7 +3623,7 @@ _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.0.0.1/api/v1/purge?domain=$_cf_d&type=$_cf_d_type" + _cf_purl="https://cloudflare-dns.com/api/v1/purge?domain=$_cf_d&type=$_cf_d_type" response="$(_post "" "$_cf_purl")" _debug2 response "$response" } @@ -3682,11 +3682,11 @@ _check_dns_entries() { 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 + _sleep 10 done if [ "$_left" ]; then _info "Let's wait 10 seconds and check again". diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 6bbf149..480c1f9 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" | tr "{" "\n" | grep "$txtvalue" | grep '^"id"' | cut -d : -f 2 | cut -d '"' -f 2) + 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 75191e71870abdb35365d057ffd746e8cd8d5b4f Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 31 Jul 2019 23:22:07 +0800 Subject: [PATCH 484/565] fix https://github.com/Neilpang/acme.sh/issues/2417 --- acme.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 66d9b7a..8bff2e8 100755 --- a/acme.sh +++ b/acme.sh @@ -5932,8 +5932,11 @@ _send_notify() { _send_err=0 for _n_hook in $(echo "$_nhooks" | tr ',' " "); do _n_hook_file="$(_findHook "" $_SUB_FOLDER_NOTIFY "$_n_hook")" - _info "Found $_n_hook_file" - + _info "Found $_n_hook_file for $_n_hook" + if [ -z "$_n_hook_file" ]; then + _err "Can not find the hook file for $_n_hook" + continue + fi if ! ( if ! . "$_n_hook_file"; then _err "Load file $_n_hook_file error. Please check your api file and try again." From d42cf6daebfd134dca7af41b47aac34866b6a771 Mon Sep 17 00:00:00 2001 From: James Qian Date: Mon, 5 Aug 2019 21:35:03 +0800 Subject: [PATCH 485/565] dnsapi: fix typo in dns_desec.sh (#2427) Signed-off-by: James Qian --- dnsapi/dns_desec.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_desec.sh b/dnsapi/dns_desec.sh index 6488b7f..61d080b 100644 --- a/dnsapi/dns_desec.sh +++ b/dnsapi/dns_desec.sh @@ -25,8 +25,8 @@ dns_desec_add() { if [ -z "$DEDYN_TOKEN" ] || [ -z "$DEDYN_NAME" ]; then DEDYN_TOKEN="" DEDYN_NAME="" - _err "You don't specify DEDYN_TOKEN and DEDYN_NAME yet." - _err "Please create you key and try again." + _err "You did not specify DEDYN_TOKEN and DEDYN_NAME yet." + _err "Please create your key and try again." _err "e.g." _err "export DEDYN_TOKEN=d41d8cd98f00b204e9800998ecf8427e" _err "export DEDYN_NAME=foobar.dedyn.io" @@ -92,8 +92,8 @@ dns_desec_rm() { if [ -z "$DEDYN_TOKEN" ] || [ -z "$DEDYN_NAME" ]; then DEDYN_TOKEN="" DEDYN_NAME="" - _err "You don't specify DEDYN_TOKEN and DEDYN_NAME yet." - _err "Please create you key and try again." + _err "You did not specify DEDYN_TOKEN and DEDYN_NAME yet." + _err "Please create your key and try again." _err "e.g." _err "export DEDYN_TOKEN=d41d8cd98f00b204e9800998ecf8427e" _err "export DEDYN_NAME=foobar.dedyn.io" From d74dfb1f5c333c911d150f7a7485ff99b8c984b4 Mon Sep 17 00:00:00 2001 From: lcdtyph Date: Mon, 5 Aug 2019 21:38:32 +0800 Subject: [PATCH 486/565] IFTTT Webhooks Notification (#2416) * IFTTT webhooks Notification * use sh instead of bash * don't save value that is not set --- notify/ifttt.sh | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 notify/ifttt.sh diff --git a/notify/ifttt.sh b/notify/ifttt.sh new file mode 100644 index 0000000..8a14f5f --- /dev/null +++ b/notify/ifttt.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env sh + +#Support ifttt.com webhooks api + +#IFTTT_API_KEY="xxxx" +#IFTTT_EVENT_NAME="yyyy" + +#IFTTT_SUBJECT_KEY="value1|value2|value3" #optional, use "value1" as default +#IFTTT_CONTENT_KEY="value1|value2|value3" #optional, use "value2" as default + +_IFTTT_AVAIL_MSG_KEYS="value1,value2,value3" + +# subject content statusCode +ifttt_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + IFTTT_API_KEY="${IFTTT_API_KEY:-$(_readaccountconf_mutable IFTTT_API_KEY)}" + if [ -z "$IFTTT_API_KEY" ]; then + IFTTT_API_KEY="" + _err "You didn't specify a ifttt webhooks api key IFTTT_API_KEY yet." + _err "You can get yours from https://ifttt.com" + return 1 + fi + _saveaccountconf_mutable IFTTT_API_KEY "$IFTTT_API_KEY" + + IFTTT_EVENT_NAME="${IFTTT_EVENT_NAME:-$(_readaccountconf_mutable IFTTT_EVENT_NAME)}" + if [ -z "$IFTTT_EVENT_NAME" ]; then + IFTTT_EVENT_NAME="" + _err "You didn't specify a ifttt webhooks event name IFTTT_EVENT_NAME yet." + return 1 + fi + _saveaccountconf_mutable IFTTT_EVENT_NAME "$IFTTT_EVENT_NAME" + + IFTTT_SUBJECT_KEY="${IFTTT_SUBJECT_KEY:-$(_readaccountconf_mutable IFTTT_SUBJECT_KEY)}" + if [ -z "$IFTTT_SUBJECT_KEY" ]; then + IFTTT_SUBJECT_KEY="value1" + _info "The IFTTT_SUBJECT_KEY is not set, so use the default value1 as key." + elif ! _hasfield "$_IFTTT_AVAIL_MSG_KEYS" "$IFTTT_SUBJECT_KEY"; then + _err "The IFTTT_SUBJECT_KEY \"$IFTTT_SUBJECT_KEY\" is not available, should be one of $_IFTTT_AVAIL_MSG_KEYS" + IFTTT_SUBJECT_KEY="" + return 1 + else + _saveaccountconf_mutable IFTTT_SUBJECT_KEY "$IFTTT_SUBJECT_KEY" + fi + + IFTTT_CONTENT_KEY="${IFTTT_CONTENT_KEY:-$(_readaccountconf_mutable IFTTT_CONTENT_KEY)}" + if [ -z "$IFTTT_CONTENT_KEY" ]; then + IFTTT_CONTENT_KEY="value2" + _info "The IFTTT_CONTENT_KEY is not set, so use the default value2 as key." + elif ! _hasfield "$_IFTTT_AVAIL_MSG_KEYS" "$IFTTT_CONTENT_KEY"; then + _err "The IFTTT_CONTENT_KEY \"$IFTTT_CONTENT_KEY\" is not available, should be one of $_IFTTT_AVAIL_MSG_KEYS" + IFTTT_CONTENT_KEY="" + return 1 + else + _saveaccountconf_mutable IFTTT_CONTENT_KEY "$IFTTT_CONTENT_KEY" + fi + + if [ "$IFTTT_SUBJECT_KEY" = "$IFTTT_CONTENT_KEY" ]; then + IFTTT_SUBJECT_KEY="" + IFTTT_CONTENT_KEY="" + _err "The IFTTT_SUBJECT_KEY must not be same as IFTTT_CONTENT_KEY." + return 1 + fi + + IFTTT_API_URL="https://maker.ifttt.com/trigger/$IFTTT_EVENT_NAME/with/key/$IFTTT_API_KEY" + + _content=$(echo "$_content" | _json_encode) + _subject=$(echo "$_subject" | _json_encode) + _data="{\"$IFTTT_SUBJECT_KEY\": \"$_subject\", \"$IFTTT_CONTENT_KEY\": \"$_content\"}" + + response="" #just make shellcheck happy + if _post "$_data" "$IFTTT_API_URL" "" "POST" "application/json"; then + if _contains "$response" "Congratulations"; then + _info "IFTTT webhooks event fired success." + return 0 + fi + fi + _err "IFTTT webhooks event fired error." + _err "$response" + return 1 +} From 143eac092ce8b8fe7c068809449ce7a5b71f3ea2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 5 Aug 2019 22:03:56 +0800 Subject: [PATCH 487/565] fix notify message --- acme.sh | 5 +++-- notify/ifttt.sh | 12 ++++++------ notify/pushover.sh | 12 ++++++------ notify/sendgrid.sh | 12 ++++++------ 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/acme.sh b/acme.sh index 8bff2e8..8452d58 100755 --- a/acme.sh +++ b/acme.sh @@ -5932,7 +5932,8 @@ _send_notify() { _send_err=0 for _n_hook in $(echo "$_nhooks" | tr ',' " "); do _n_hook_file="$(_findHook "" $_SUB_FOLDER_NOTIFY "$_n_hook")" - _info "Found $_n_hook_file for $_n_hook" + _info "Sending via: $_n_hook" + _debug "Found $_n_hook_file for $_n_hook" if [ -z "$_n_hook_file" ]; then _err "Can not find the hook file for $_n_hook" continue @@ -5971,7 +5972,7 @@ _set_notify_hook() { _nhooks="$1" _test_subject="Hello, this is notification from $PROJECT_NAME" - _test_content="If you receive this email, your notification works." + _test_content="If you receive this message, your notification works." _send_notify "$_test_subject" "$_test_content" "$_nhooks" 0 diff --git a/notify/ifttt.sh b/notify/ifttt.sh index 8a14f5f..7b82963 100644 --- a/notify/ifttt.sh +++ b/notify/ifttt.sh @@ -73,13 +73,13 @@ ifttt_send() { _subject=$(echo "$_subject" | _json_encode) _data="{\"$IFTTT_SUBJECT_KEY\": \"$_subject\", \"$IFTTT_CONTENT_KEY\": \"$_content\"}" - response="" #just make shellcheck happy - if _post "$_data" "$IFTTT_API_URL" "" "POST" "application/json"; then - if _contains "$response" "Congratulations"; then - _info "IFTTT webhooks event fired success." - return 0 - fi + response="$(_post "$_data" "$IFTTT_API_URL" "" "POST" "application/json")" + + if [ "$?" = "0" ] && _contains "$response" "Congratulations"; then + _info "IFTTT webhooks event fired success." + return 0 fi + _err "IFTTT webhooks event fired error." _err "$response" return 1 diff --git a/notify/pushover.sh b/notify/pushover.sh index a07cbd3..0f99739 100644 --- a/notify/pushover.sh +++ b/notify/pushover.sh @@ -50,13 +50,13 @@ pushover_send() { _subject="$(printf "*%s*\n" "$_subject" | _json_encode)" _data="{\"token\": \"$PUSHOVER_TOKEN\",\"user\": \"$PUSHOVER_USER\",\"title\": \"$_subject\",\"message\": \"$_content\",\"sound\": \"$PUSHOVER_SOUND\", \"device\": \"$PUSHOVER_DEVICE\", \"priority\": \"$PUSHOVER_PRIORITY\"}" - response="" #just make shellcheck happy - if _post "$_data" "$PUSHOVER_URI"; then - if _contains "$response" "{\"status\":1"; then - _info "PUSHOVER send success." - return 0 - fi + response="$(_post "$_data" "$PUSHOVER_URI")" + + if [ "$?" = "0" ] && _contains "$response" "{\"status\":1"; then + _info "PUSHOVER send success." + return 0 fi + _err "PUSHOVER send error." _err "$response" return 1 diff --git a/notify/sendgrid.sh b/notify/sendgrid.sh index 5c5bfdb..0d5ea3b 100644 --- a/notify/sendgrid.sh +++ b/notify/sendgrid.sh @@ -42,13 +42,13 @@ sendgrid_send() { _content="$(echo "$_content" | _json_encode)" _data="{\"personalizations\": [{\"to\": [{\"email\": \"$SENDGRID_TO\"}]}],\"from\": {\"email\": \"$SENDGRID_FROM\"},\"subject\": \"$_subject\",\"content\": [{\"type\": \"text/plain\", \"value\": \"$_content\"}]}" - response="" #just make shellcheck happy - if _post "$_data" "https://api.sendgrid.com/v3/mail/send"; then - if [ -z "$response" ]; then - _info "sendgrid send sccess." - return 0 - fi + response="$(_post "$_data" "https://api.sendgrid.com/v3/mail/send")" + + if [ "$?" = "0" ] && [ -z "$response" ]; then + _info "sendgrid send sccess." + return 0 fi + _err "sendgrid send error." _err "$response" return 1 From 874bd093cb5076613f74aac84168952af0e27f9f Mon Sep 17 00:00:00 2001 From: neil <8305679+Neilpang@users.noreply.github.com> Date: Mon, 5 Aug 2019 22:35:40 +0800 Subject: [PATCH 488/565] fix https://github.com/Neilpang/acme.sh/issues/2409 (#2430) --- dnsapi/dns_he.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index df00c74..caa4d2c 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -134,9 +134,9 @@ _find_zone() { _zone_ids=$(echo "$_matches" | _egrep_o "hosted_dns_zoneid=[0-9]*&" | cut -d = -f 2 | tr -d '&') _zone_names=$(echo "$_matches" | _egrep_o "name=.*onclick" | cut -d '"' -f 2) _debug2 "These are the zones on this HE account:" - _debug2 "$_zone_names" + _debug2 "_zone_names" "$_zone_names" _debug2 "And these are their respective IDs:" - _debug2 "$_zone_ids" + _debug2 "_zone_ids" "$_zone_ids" if [ -z "$_zone_names" ] || [ -z "$_zone_ids" ]; then _err "Can not get zone names." return 1 @@ -154,10 +154,14 @@ _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\$" | _head_n 1 | cut -d : -f 1)" + _debug2 line_num "$line_num" if [ "$line_num" ]; then _zone_id=$(echo "$_zone_ids" | sed -n "${line_num}p") + if [ -z "$_zone_id" ]; then + _err "Can not find zone id." + return 1 + fi _debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"." return 0 fi From c7849a43e13fd98f2452613165561e547b2606df Mon Sep 17 00:00:00 2001 From: mleo2003 Date: Tue, 6 Aug 2019 06:41:12 -0700 Subject: [PATCH 489/565] Add variable exports for Successful Post Hook and Renew Hook calls (#2431) --- acme.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/acme.sh b/acme.sh index 8452d58..4742e61 100755 --- a/acme.sh +++ b/acme.sh @@ -3265,6 +3265,11 @@ _on_issue_success() { if [ "$_chk_post_hook" ]; then _info "Run post hook:'$_chk_post_hook'" if ! ( + export CERT_PATH + export CERT_KEY_PATH + export CA_CERT_PATH + export CERT_FULLCHAIN_PATH + export Le_Domain="$_main_domain" cd "$DOMAIN_PATH" && eval "$_chk_post_hook" ); then _err "Error when run post hook." @@ -3276,6 +3281,11 @@ _on_issue_success() { if [ "$IS_RENEW" ] && [ "$_chk_renew_hook" ]; then _info "Run renew hook:'$_chk_renew_hook'" if ! ( + export CERT_PATH + export CERT_KEY_PATH + export CA_CERT_PATH + export CERT_FULLCHAIN_PATH + export Le_Domain="$_main_domain" cd "$DOMAIN_PATH" && eval "$_chk_renew_hook" ); then _err "Error when run renew hook." From f82ff90f0670becb8b2c63e9eea591361a380ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=B8=D0=BC=D1=83=D1=80=20=D0=AF=D1=85=D0=B8=D0=BD?= Date: Sun, 11 Aug 2019 06:41:57 +0300 Subject: [PATCH 490/565] fixed json parse regex for support api gcore_cdn (#2381) --- deploy/gcore_cdn.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index e0921bc..bbda58e 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -1,7 +1,6 @@ #!/usr/bin/env sh # Here is the script to deploy the cert to G-Core CDN service (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/). -# Uses command line curl for send requests and jq for parse responses. # Returns 0 when success. # # Written by temoffey @@ -117,7 +116,7 @@ gcore_cdn_deploy() { _debug _request "$_request" _response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT") _debug _response "$_response" - _regex=".*\"sslData\":\([0-9]*\)}.*$" + _regex=".*\"sslData\":\([0-9]*\).*$" _debug _regex "$_regex" _sslDataNew=$(echo "$_response" | sed -n "s/$_regex/\1/p") _debug _sslDataNew "$_sslDataNew" From ee38cccad8f76b807206165324e7bf771aa981dc Mon Sep 17 00:00:00 2001 From: neil <8305679+Neilpang@users.noreply.github.com> Date: Sun, 11 Aug 2019 11:56:59 +0800 Subject: [PATCH 491/565] sync (#2436) * fix https://github.com/Neilpang/acme.sh/issues/2409 (#2430) * Add variable exports for Successful Post Hook and Renew Hook calls (#2431) * fixed json parse regex for support api gcore_cdn (#2381) --- acme.sh | 10 ++++++++++ deploy/gcore_cdn.sh | 3 +-- dnsapi/dns_he.sh | 12 ++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 8452d58..4742e61 100755 --- a/acme.sh +++ b/acme.sh @@ -3265,6 +3265,11 @@ _on_issue_success() { if [ "$_chk_post_hook" ]; then _info "Run post hook:'$_chk_post_hook'" if ! ( + export CERT_PATH + export CERT_KEY_PATH + export CA_CERT_PATH + export CERT_FULLCHAIN_PATH + export Le_Domain="$_main_domain" cd "$DOMAIN_PATH" && eval "$_chk_post_hook" ); then _err "Error when run post hook." @@ -3276,6 +3281,11 @@ _on_issue_success() { if [ "$IS_RENEW" ] && [ "$_chk_renew_hook" ]; then _info "Run renew hook:'$_chk_renew_hook'" if ! ( + export CERT_PATH + export CERT_KEY_PATH + export CA_CERT_PATH + export CERT_FULLCHAIN_PATH + export Le_Domain="$_main_domain" cd "$DOMAIN_PATH" && eval "$_chk_renew_hook" ); then _err "Error when run renew hook." diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index e0921bc..bbda58e 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -1,7 +1,6 @@ #!/usr/bin/env sh # Here is the script to deploy the cert to G-Core CDN service (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/). -# Uses command line curl for send requests and jq for parse responses. # Returns 0 when success. # # Written by temoffey @@ -117,7 +116,7 @@ gcore_cdn_deploy() { _debug _request "$_request" _response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT") _debug _response "$_response" - _regex=".*\"sslData\":\([0-9]*\)}.*$" + _regex=".*\"sslData\":\([0-9]*\).*$" _debug _regex "$_regex" _sslDataNew=$(echo "$_response" | sed -n "s/$_regex/\1/p") _debug _sslDataNew "$_sslDataNew" diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index df00c74..caa4d2c 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -134,9 +134,9 @@ _find_zone() { _zone_ids=$(echo "$_matches" | _egrep_o "hosted_dns_zoneid=[0-9]*&" | cut -d = -f 2 | tr -d '&') _zone_names=$(echo "$_matches" | _egrep_o "name=.*onclick" | cut -d '"' -f 2) _debug2 "These are the zones on this HE account:" - _debug2 "$_zone_names" + _debug2 "_zone_names" "$_zone_names" _debug2 "And these are their respective IDs:" - _debug2 "$_zone_ids" + _debug2 "_zone_ids" "$_zone_ids" if [ -z "$_zone_names" ] || [ -z "$_zone_ids" ]; then _err "Can not get zone names." return 1 @@ -154,10 +154,14 @@ _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\$" | _head_n 1 | cut -d : -f 1)" + _debug2 line_num "$line_num" if [ "$line_num" ]; then _zone_id=$(echo "$_zone_ids" | sed -n "${line_num}p") + if [ -z "$_zone_id" ]; then + _err "Can not find zone id." + return 1 + fi _debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"." return 0 fi From 5bdfdfefbebd7ee4f95f7009947f56a25db07c4a Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 11 Aug 2019 14:07:36 +0800 Subject: [PATCH 492/565] start 2.8.3 Forbidden sudo --- acme.sh | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4742e61..72bf070 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.8.2 +VER=2.8.3 PROJECT_NAME="acme.sh" @@ -135,6 +135,8 @@ _DNS_MANUAL_WIKI="https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode" _NOTIFY_WIKI="https://github.com/Neilpang/acme.sh/wiki/notify" +_SUDO_WIKI="https://github.com/Neilpang/acme.sh/wiki/sudo" + _DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead." _DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR" @@ -6233,6 +6235,23 @@ _processAccountConf() { } +_checkSudo() { + if [ "$SUDO_GID" ] && [ "$SUDO_COMMAND" ] && [ "$SUDO_USER" ] && [ "$SUDO_UID" ]; then + if [ "$SUDO_USER" = "root" ] && [ "$SUDO_UID" = "0" ]; then + #it's root using sudo, no matter it's using sudo or not, just fine + return 0 + fi + if [ "$SUDO_COMMAND" = "/bin/su" ]; then + #it's a normal user doing "sudo su" + #fine + return 0 + fi + #otherwise + return 1 + fi + return 0 +} + _process() { _CMD="" _domain="" @@ -6761,6 +6780,14 @@ _process() { done if [ "${_CMD}" != "install" ]; then + if [ "$__INTERACTIVE" ] && ! _checkSudo; then + if [ -z "$FORCE" ]; then + #Use "echo" here, instead of _info. it's too early + echo "It seems that you are using sudo, please read this link first:" + echo "$_SUDO_WIKI" + return 1 + fi + fi __initHome if [ "$_log" ]; then if [ -z "$_logfile" ]; then From a3361806ab49043fca46f81a0edc2357b7d3947c Mon Sep 17 00:00:00 2001 From: neil <8305679+Neilpang@users.noreply.github.com> Date: Sun, 11 Aug 2019 22:43:07 +0800 Subject: [PATCH 493/565] sync (#2437) * fix https://github.com/Neilpang/acme.sh/issues/2409 (#2430) * Add variable exports for Successful Post Hook and Renew Hook calls (#2431) * fixed json parse regex for support api gcore_cdn (#2381) * start 2.8.3 Forbidden sudo --- acme.sh | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4742e61..72bf070 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.8.2 +VER=2.8.3 PROJECT_NAME="acme.sh" @@ -135,6 +135,8 @@ _DNS_MANUAL_WIKI="https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode" _NOTIFY_WIKI="https://github.com/Neilpang/acme.sh/wiki/notify" +_SUDO_WIKI="https://github.com/Neilpang/acme.sh/wiki/sudo" + _DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead." _DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR" @@ -6233,6 +6235,23 @@ _processAccountConf() { } +_checkSudo() { + if [ "$SUDO_GID" ] && [ "$SUDO_COMMAND" ] && [ "$SUDO_USER" ] && [ "$SUDO_UID" ]; then + if [ "$SUDO_USER" = "root" ] && [ "$SUDO_UID" = "0" ]; then + #it's root using sudo, no matter it's using sudo or not, just fine + return 0 + fi + if [ "$SUDO_COMMAND" = "/bin/su" ]; then + #it's a normal user doing "sudo su" + #fine + return 0 + fi + #otherwise + return 1 + fi + return 0 +} + _process() { _CMD="" _domain="" @@ -6761,6 +6780,14 @@ _process() { done if [ "${_CMD}" != "install" ]; then + if [ "$__INTERACTIVE" ] && ! _checkSudo; then + if [ -z "$FORCE" ]; then + #Use "echo" here, instead of _info. it's too early + echo "It seems that you are using sudo, please read this link first:" + echo "$_SUDO_WIKI" + return 1 + fi + fi __initHome if [ "$_log" ]; then if [ -z "$_logfile" ]; then From 9b173dcd7149dd9fa50d621bf21fe4a874616240 Mon Sep 17 00:00:00 2001 From: Sky Chen Date: Thu, 15 Aug 2019 14:23:12 +0800 Subject: [PATCH 494/565] fixed #2441: dns_namesilo.sh _get_root (#2442) fixed #2441: dns_namesilo.sh _get_root (#2442) --- dnsapi/dns_namesilo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_namesilo.sh b/dnsapi/dns_namesilo.sh index ed6d0e0..0b87b7f 100755 --- a/dnsapi/dns_namesilo.sh +++ b/dnsapi/dns_namesilo.sh @@ -110,7 +110,7 @@ _get_root() { return 1 fi - if _contains "$response" "$host"; then + if _contains "$response" "$host"; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain="$host" return 0 From 0b2b8b960b07232edd92fed0124a35cbfd969a87 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Fri, 16 Aug 2019 22:56:22 -0400 Subject: [PATCH 495/565] Replace grep -o with sed --- dnsapi/dns_freedns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 8a48cf7..ee01366 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -305,7 +305,7 @@ _freedns_domain_id() { domain_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ | grep "$search_domain\|$search_domain(.*)" \ - | grep -o "edit\.php?edit_domain_id=[0-9a-zA-Z]*" \ + | sed -n 's/.*\(edit\.php?edit_domain_id=[0-9a-zA-Z]*\).*/\1/p' \ | cut -d = -f 2)" # The above beauty extracts domain ID from the html page... # strip out all blank space and new lines. Then insert newlines @@ -352,7 +352,7 @@ _freedns_data_id() { data_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ | grep "$record_type" \ | grep "$search_domain" \ - | grep -o "edit\.php?data_id=[0-9a-zA-Z]*" \ + | sed -n 's/.*\(edit\.php?data_id=[0-9a-zA-Z]*\).*/\1/p' \ | cut -d = -f 2)" # The above beauty extracts data ID from the html page... # strip out all blank space and new lines. Then insert newlines From e0deca33d00f6e8dfd9473b1d2bbf83132fb2e72 Mon Sep 17 00:00:00 2001 From: Rolph Haspers Date: Mon, 19 Aug 2019 14:27:23 +0200 Subject: [PATCH 496/565] Added Leaseweb API for dns-01 verification --- dnsapi/dns_leaseweb.sh | 130 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 dnsapi/dns_leaseweb.sh diff --git a/dnsapi/dns_leaseweb.sh b/dnsapi/dns_leaseweb.sh new file mode 100644 index 0000000..3edf55f --- /dev/null +++ b/dnsapi/dns_leaseweb.sh @@ -0,0 +1,130 @@ +#!/usr/bin/env sh + +#Author: Rolph Haspers +#Utilize leaseweb.com API to finish dns-01 verifications. +#Requires a Leaseweb API Key (export LSW_Key="Your Key") +######## Public functions ##################### + +LSW_API="https://api.leaseweb.com/hosting/v2/domains/" + +#Usage: dns_leaseweb_add _acme-challenge.www.domain.com +dns_leaseweb_add() { + fulldomain=$1 + txtvalue=$2 + + LSW_Key="${LSW_Key:-$(_readaccountconf_mutable LSW_Key)}" + if [ -z "$LSW_Key" ]; then + LSW_Key="" + _err "You don't specify Leaseweb api key yet." + _err "Please create your key and try again." + return 1 + fi + + #save the api key to the account conf file. + _saveaccountconf_mutable LSW_Key "$LSW_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _root_domain "$_domain" + _debug _domain "$fulldomain" + + if _lsw_api "POST" "$_domain" "$fulldomain" "$txtvalue"; then + if [ "$_code" = "201" ]; then + _info "Added, OK" + return 0 + else + _err "Add txt record error, invalid code. Code: $_code" + return 1 + fi + fi + _err "Add txt record error." + + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_leaseweb_rm() { + fulldomain=$1 + txtvalue=$2 + + LSW_Key="${LSW_Key:-$(_readaccountconf_mutable LSW_Key)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _root_domain "$_domain" + _debug _domain "$fulldomain" + + if _lsw_api "DELETE" "$_domain" "$fulldomain" "$txtvalue"; then + if [ "$_code" = "204" ]; 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 +# _domain=domain.com +_get_root() { + domain=$1 + i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" + i=$(_math "$i" - 1) + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) + if [ -z "$h" ]; then + return 1 + fi + _domain="$h" + return 0 + done + _debug "$domain not found" + return 1 +} + +_lsw_api() { + cmd=$1 + domain=$2 + fulldomain=$3 + txtvalue=$4 + + # Construct the HTTP Authorization header + export _H2="Content-Type: application/json" + export _H1="X-Lsw-Auth: ${LSW_Key}" + + if [ "$cmd" == "POST" ]; then + data="{\"name\": \"$fulldomain.\",\"type\": \"TXT\",\"content\": [\"$txtvalue\"],\"ttl\": 60}" + response="$(_post "$data" "$LSW_API/$domain/resourceRecordSets" "$data" "POST")" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + _debug "http response code $_code" + _debug response "$response" + return 0 + fi + + if [ "$cmd" == "DELETE" ]; then + response="$(_post "" "$LSW_API/$domain/resourceRecordSets/$fulldomain/TXT" "" "DELETE")" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + _debug "http response code $_code" + _debug response "$response" + return 0 + fi + + return 1 +} \ No newline at end of file From 54b38086e5abc37c48dcb55ffd2f3800098dd126 Mon Sep 17 00:00:00 2001 From: Rolph Haspers Date: Mon, 19 Aug 2019 15:39:19 +0200 Subject: [PATCH 497/565] Fix style issues --- dnsapi/dns_leaseweb.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_leaseweb.sh b/dnsapi/dns_leaseweb.sh index 3edf55f..6160991 100644 --- a/dnsapi/dns_leaseweb.sh +++ b/dnsapi/dns_leaseweb.sh @@ -32,7 +32,7 @@ dns_leaseweb_add() { _debug _root_domain "$_domain" _debug _domain "$fulldomain" - if _lsw_api "POST" "$_domain" "$fulldomain" "$txtvalue"; then + if _lsw_api "POST" "$_domain" "$fulldomain" "$txtvalue"; then if [ "$_code" = "201" ]; then _info "Added, OK" return 0 @@ -63,7 +63,7 @@ dns_leaseweb_rm() { _debug _root_domain "$_domain" _debug _domain "$fulldomain" - if _lsw_api "DELETE" "$_domain" "$fulldomain" "$txtvalue"; then + if _lsw_api "DELETE" "$_domain" "$fulldomain" "$txtvalue"; then if [ "$_code" = "204" ]; then _info "Deleted, OK" return 0 @@ -109,16 +109,16 @@ _lsw_api() { export _H2="Content-Type: application/json" export _H1="X-Lsw-Auth: ${LSW_Key}" - if [ "$cmd" == "POST" ]; then + if [ "$cmd" = "POST" ]; then data="{\"name\": \"$fulldomain.\",\"type\": \"TXT\",\"content\": [\"$txtvalue\"],\"ttl\": 60}" - response="$(_post "$data" "$LSW_API/$domain/resourceRecordSets" "$data" "POST")" + response="$(_post "$data" "$LSW_API/$domain/resourceRecordSets" "$data" "POST")" _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" - _debug "http response code $_code" - _debug response "$response" + _debug "http response code $_code" + _debug response "$response" return 0 fi - if [ "$cmd" == "DELETE" ]; then + if [ "$cmd" = "DELETE" ]; then response="$(_post "" "$LSW_API/$domain/resourceRecordSets/$fulldomain/TXT" "" "DELETE")" _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" _debug "http response code $_code" @@ -127,4 +127,4 @@ _lsw_api() { fi return 1 -} \ No newline at end of file +} From 400c31d03162a596fcbb22330e38df26b960eac0 Mon Sep 17 00:00:00 2001 From: Rolph Haspers Date: Mon, 19 Aug 2019 16:01:51 +0200 Subject: [PATCH 498/565] Fixed another styling issue (trailing spaces) --- dnsapi/dns_leaseweb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_leaseweb.sh b/dnsapi/dns_leaseweb.sh index 6160991..a792290 100644 --- a/dnsapi/dns_leaseweb.sh +++ b/dnsapi/dns_leaseweb.sh @@ -111,7 +111,7 @@ _lsw_api() { if [ "$cmd" = "POST" ]; then data="{\"name\": \"$fulldomain.\",\"type\": \"TXT\",\"content\": [\"$txtvalue\"],\"ttl\": 60}" - response="$(_post "$data" "$LSW_API/$domain/resourceRecordSets" "$data" "POST")" + response="$(_post "$data" "$LSW_API/$domain/resourceRecordSets" "$data" "POST")" _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" _debug "http response code $_code" _debug response "$response" From 0ac37981cbd384ddfa7ccb890ccf4facb6c396ec Mon Sep 17 00:00:00 2001 From: Rolph Haspers Date: Mon, 19 Aug 2019 16:04:16 +0200 Subject: [PATCH 499/565] Styling, newline removed --- dnsapi/dns_leaseweb.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_leaseweb.sh b/dnsapi/dns_leaseweb.sh index a792290..17038f4 100644 --- a/dnsapi/dns_leaseweb.sh +++ b/dnsapi/dns_leaseweb.sh @@ -77,7 +77,6 @@ dns_leaseweb_rm() { return 1 } - #################### Private functions below ################################## # _acme-challenge.www.domain.com # returns From 4a81205e04f22f0de645d117e243794ba6ca403a Mon Sep 17 00:00:00 2001 From: Rolph Haspers Date: Mon, 19 Aug 2019 16:22:48 +0200 Subject: [PATCH 500/565] Styling, trailing space --- dnsapi/dns_leaseweb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_leaseweb.sh b/dnsapi/dns_leaseweb.sh index 17038f4..c9df4dc 100644 --- a/dnsapi/dns_leaseweb.sh +++ b/dnsapi/dns_leaseweb.sh @@ -59,7 +59,7 @@ dns_leaseweb_rm() { _err "invalid domain" return 1 fi - + _debug _root_domain "$_domain" _debug _domain "$fulldomain" From f0d6d46766c8484e32010b2dc624130650900a3c Mon Sep 17 00:00:00 2001 From: Rolph Haspers Date: Mon, 19 Aug 2019 17:27:19 +0200 Subject: [PATCH 501/565] Added link to API docs --- dnsapi/dns_leaseweb.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_leaseweb.sh b/dnsapi/dns_leaseweb.sh index c9df4dc..976ad5a 100644 --- a/dnsapi/dns_leaseweb.sh +++ b/dnsapi/dns_leaseweb.sh @@ -3,6 +3,7 @@ #Author: Rolph Haspers #Utilize leaseweb.com API to finish dns-01 verifications. #Requires a Leaseweb API Key (export LSW_Key="Your Key") +#See http://developer.leaseweb.com for more information. ######## Public functions ##################### LSW_API="https://api.leaseweb.com/hosting/v2/domains/" From 0ca46774ac207517724eb48338c04a4dbde0728a Mon Sep 17 00:00:00 2001 From: neil <8305679+Neilpang@users.noreply.github.com> Date: Mon, 2 Sep 2019 10:36:10 +0800 Subject: [PATCH 502/565] Create FUNDING.yml --- .github/FUNDING.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..24be2c4 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: acmesh +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] From 1081d98bf9fac753a504a78af868eca444c73be1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 5 Sep 2019 22:05:54 +0800 Subject: [PATCH 503/565] support to specify the nginx or site conf for nginx mode. https://github.com/Neilpang/acme.sh/issues/2469 --- acme.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/acme.sh b/acme.sh index 72bf070..3ce377e 100755 --- a/acme.sh +++ b/acme.sh @@ -2799,6 +2799,11 @@ _setNginx() { _debug NGINX_CONF "$NGINX_CONF" NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)" _debug NGINX_CONF "$NGINX_CONF" + if [ -z "$NGINX_CONF" ]; then + _err "Can not find nginx conf." + NGINX_CONF="" + return 1 + fi if [ ! -f "$NGINX_CONF" ]; then _err "'$NGINX_CONF' doesn't exist." NGINX_CONF="" @@ -6503,6 +6508,10 @@ _process() { ;; --nginx) wvalue="$NGINX" + if [ "$2" ] && ! _startswith "$2" "-"; then + wvalue="$NGINX$2" + shift + fi if [ -z "$_webroot" ]; then _webroot="$wvalue" else From 6b817d4563494e64d40d403c90746c869a3db73a Mon Sep 17 00:00:00 2001 From: Phil Porada Date: Thu, 5 Sep 2019 10:15:28 -0400 Subject: [PATCH 504/565] Set TXT record TTL to minimum possible value (#2465) --- dnsapi/dns_linode_v4.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_linode_v4.sh b/dnsapi/dns_linode_v4.sh index c9a83c7..ee7ee89 100755 --- a/dnsapi/dns_linode_v4.sh +++ b/dnsapi/dns_linode_v4.sh @@ -31,7 +31,8 @@ dns_linode_v4_add() { _payload="{ \"type\": \"TXT\", \"name\": \"$_sub_domain\", - \"target\": \"$txtvalue\" + \"target\": \"$txtvalue\", + \"ttl_sec\": 300 }" if _rest POST "/$_domain_id/records" "$_payload" && [ -n "$response" ]; then From 80d63dbb7cef07b14ec05d6d017689c19aec40a2 Mon Sep 17 00:00:00 2001 From: Kent Varmedal Date: Thu, 5 Sep 2019 16:26:28 +0200 Subject: [PATCH 505/565] Add support for Domeneshop DNS API (#2458) * Add support for Domeneshop DNS API * Fix double quotes after build fail * Fixing formating errors --- dnsapi/dns_domeneshop.sh | 155 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 dnsapi/dns_domeneshop.sh diff --git a/dnsapi/dns_domeneshop.sh b/dnsapi/dns_domeneshop.sh new file mode 100644 index 0000000..9a3791f --- /dev/null +++ b/dnsapi/dns_domeneshop.sh @@ -0,0 +1,155 @@ +#!/usr/bin/env sh + +DOMENESHOP_Api_Endpoint="https://api.domeneshop.no/v0" + +##################### Public functions ##################### + +# Usage: dns_domeneshop_add +# Example: dns_domeneshop_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_domeneshop_add() { + fulldomain=$1 + txtvalue=$2 + + # Get token and secret + DOMENESHOP_Token="${DOMENESHOP_Token:-$(_readaccountconf_mutable DOMENESHOP_Token)}" + DOMENESHOP_Secret="${DOMENESHOP_Secret:-$(_readaccountconf_mutable DOMENESHOP_Secret)}" + + if [ -z "$DOMENESHOP_Token" ] || [ -z "$DOMENESHOP_Secret" ]; then + DOMENESHOP_Token="" + DOMENESHOP_Secret="" + _err "You need to spesify a Domeneshop/Domainnameshop API Token and Secret." + return 1 + fi + + # Save the api token and secret. + _saveaccountconf_mutable DOMENESHOP_Token "$DOMENESHOP_Token" + _saveaccountconf_mutable DOMENESHOP_Secret "$DOMENESHOP_Secret" + + # Get the domain name id + if ! _get_domainid "$fulldomain"; then + _err "Did not find domainname" + return 1 + fi + + # Create record + _domeneshop_rest POST "domains/$_domainid/dns" "{\"type\":\"TXT\",\"host\":\"$_sub_domain\",\"data\":\"$txtvalue\",\"ttl\":120}" +} + +# Usage: dns_domeneshop_rm +# Example: dns_domeneshop_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_domeneshop_rm() { + fulldomain=$1 + txtvalue=$2 + + # Get token and secret + DOMENESHOP_Token="${DOMENESHOP_Token:-$(_readaccountconf_mutable DOMENESHOP_Token)}" + DOMENESHOP_Secret="${DOMENESHOP_Secret:-$(_readaccountconf_mutable DOMENESHOP_Secret)}" + + if [ -z "$DOMENESHOP_Token" ] || [ -z "$DOMENESHOP_Secret" ]; then + DOMENESHOP_Token="" + DOMENESHOP_Secret="" + _err "You need to spesify a Domeneshop/Domainnameshop API Token and Secret." + return 1 + fi + + # Get the domain name id + if ! _get_domainid "$fulldomain"; then + _err "Did not find domainname" + return 1 + fi + + # Find record + if ! _get_recordid "$_domainid" "$_sub_domain" "$txtvalue"; then + _err "Did not find dns record" + return 1 + fi + + # Remove record + _domeneshop_rest DELETE "domains/$_domainid/dns/$_recordid" +} + +##################### Private functions ##################### + +_get_domainid() { + domain=$1 + + # Get domains + _domeneshop_rest GET "domains" + + if ! _contains "$response" "\"id\":"; then + _err "failed to get domain names" + 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 + # We have found the domain name. + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + _domainid=$(printf "%s" "$response" | _egrep_o "[^{]*\"domain\":\"$_domain\"[^}]*" | _egrep_o "\"id\":[0-9]+" | cut -d : -f 2) + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_get_recordid() { + domainid=$1 + subdomain=$2 + txtvalue=$3 + + # Get all dns records for the domainname + _domeneshop_rest GET "domains/$domainid/dns" + + if ! _contains "$response" "\"id\":"; then + _debug "No records in dns" + return 1 + fi + + if ! _contains "$response" "\"host\":\"$subdomain\""; then + _debug "Record does not exist" + return 1 + fi + + # Get the id of the record in question + _recordid=$(printf "%s" "$response" | _egrep_o "[^{]*\"host\":\"$subdomain\"[^}]*" | _egrep_o "[^{]*\"data\":\"$txtvalue\"[^}]*" | _egrep_o "\"id\":[0-9]+" | cut -d : -f 2) + if [ -z "$_recordid" ]; then + return 1 + fi + return 0 +} + +_domeneshop_rest() { + method=$1 + endpoint=$2 + data=$3 + + credentials=$(printf "%b" "$DOMENESHOP_Token:$DOMENESHOP_Secret" | _base64) + + export _H1="Authorization: Basic $credentials" + export _H2="Content-Type: application/json" + + if [ "$method" != "GET" ]; then + response="$(_post "$data" "$DOMENESHOP_Api_Endpoint/$endpoint" "" "$method")" + else + response="$(_get "$DOMENESHOP_Api_Endpoint/$endpoint")" + fi + + if [ "$?" != "0" ]; then + _err "error $endpoint" + return 1 + fi + + return 0 +} From b9994e52eb24e2389ca6e29fc79046d92e57e758 Mon Sep 17 00:00:00 2001 From: fgma <30936930+fgma@users.noreply.github.com> Date: Thu, 5 Sep 2019 16:28:47 +0200 Subject: [PATCH 506/565] Notify xmpp (#2407) * notify via xmpp (using sendxmpp) * fix formatting in notify/xmpp.sh * minor cleanup --- notify/xmpp.sh | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 notify/xmpp.sh diff --git a/notify/xmpp.sh b/notify/xmpp.sh new file mode 100644 index 0000000..580f471 --- /dev/null +++ b/notify/xmpp.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env sh + +#Support xmpp via sendxmpp + +#XMPP_BIN="/usr/bin/sendxmpp" +#XMPP_BIN_ARGS="-n -t --tls-ca-path=/etc/ssl/certs" +#XMPP_TO="zzzz@example.com" + +xmpp_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + XMPP_BIN="${XMPP_BIN:-$(_readaccountconf_mutable XMPP_BIN)}" + if [ -n "$XMPP_BIN" ] && ! _exists "$XMPP_BIN"; then + _err "It seems that the command $XMPP_BIN is not in path." + return 1 + fi + _XMPP_BIN=$(_xmpp_bin) + if [ -n "$XMPP_BIN" ]; then + _saveaccountconf_mutable XMPP_BIN "$XMPP_BIN" + else + _clearaccountconf "XMPP_BIN" + fi + + XMPP_BIN_ARGS="${XMPP_BIN_ARGS:-$(_readaccountconf_mutable XMPP_BIN_ARGS)}" + if [ -n "$XMPP_BIN_ARGS" ]; then + _saveaccountconf_mutable XMPP_BIN_ARGS "$XMPP_BIN_ARGS" + else + _clearaccountconf "XMPP_BIN_ARGS" + fi + + XMPP_TO="${XMPP_TO:-$(_readaccountconf_mutable XMPP_TO)}" + if [ -n "$XMPP_TO" ]; then + if ! _xmpp_valid "$XMPP_TO"; then + _err "It seems that the XMPP_TO=$XMPP_TO is not a valid xmpp address." + return 1 + fi + + _saveaccountconf_mutable XMPP_TO "$XMPP_TO" + fi + + result=$({ _xmpp_message | eval "$(_xmpp_cmnd)"; } 2>&1) + + # shellcheck disable=SC2181 + if [ $? -ne 0 ]; then + _debug "xmpp send error." + _err "$result" + return 1 + fi + + _debug "xmpp send success." + return 0 +} + +_xmpp_bin() { + if [ -n "$XMPP_BIN" ]; then + _XMPP_BIN="$XMPP_BIN" + elif _exists "sendxmpp"; then + _XMPP_BIN="sendxmpp" + else + _err "Please install sendxmpp first." + return 1 + fi + + echo "$_XMPP_BIN" +} + +_xmpp_cmnd() { + case $(basename "$_XMPP_BIN") in + sendxmpp) + echo "'$_XMPP_BIN' '$XMPP_TO' $XMPP_BIN_ARGS" + ;; + *) + _err "Command $XMPP_BIN is not supported, use sendxmpp." + return 1 + ;; + esac +} + +_xmpp_message() { + echo "$_subject" +} + +_xmpp_valid() { + _contains "$1" "@" +} From 815a3be48b5d389eae234a5ffefb5eaa56492813 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 14 Sep 2019 11:21:55 +0800 Subject: [PATCH 507/565] fix https://github.com/Neilpang/acme.sh/issues/2478 support `sudo -i` and `sudo -s` --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 3ce377e..980dc02 100755 --- a/acme.sh +++ b/acme.sh @@ -6246,8 +6246,8 @@ _checkSudo() { #it's root using sudo, no matter it's using sudo or not, just fine return 0 fi - if [ "$SUDO_COMMAND" = "/bin/su" ]; then - #it's a normal user doing "sudo su" + if [ "$SUDO_COMMAND" = "/bin/su" ] || [ "$SUDO_COMMAND" = "/bin/bash" ]; then + #it's a normal user doing "sudo su", or `sudo -i` or `sudo -s` #fine return 0 fi From 950d024a117665bcc31a2417360f7b941e16bad6 Mon Sep 17 00:00:00 2001 From: Boot Lee <82433808@qq.com> Date: Sat, 14 Sep 2019 23:06:25 +0800 Subject: [PATCH 508/565] fix grep error when txt value begin with - char (#2471) --- dnsapi/dns_ali.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh index 543a0a5..0c2365d 100755 --- a/dnsapi/dns_ali.sh +++ b/dnsapi/dns_ali.sh @@ -185,7 +185,7 @@ _clean() { return 1 fi - record_id="$(echo "$response" | tr '{' "\n" | grep "$_sub_domain" | grep "$txtvalue" | tr "," "\n" | grep RecordId | cut -d '"' -f 4)" + record_id="$(echo "$response" | tr '{' "\n" | grep "$_sub_domain" | grep -- "$txtvalue" | tr "," "\n" | grep RecordId | cut -d '"' -f 4)" _debug2 record_id "$record_id" if [ -z "$record_id" ]; then From 5723fd112fb9238cd09b6cb2737f328d35746eb7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 24 Sep 2019 20:00:21 +0800 Subject: [PATCH 509/565] fix HEAD request against the new LE CDN. curl is fixed --- README.md | 2 +- acme.sh | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ab3412c..6c6a743 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh) -[![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + [![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - An ACME protocol client written purely in Shell (Unix shell) language. - Full ACME protocol implementation. - Support ACME v1 and ACME v2 diff --git a/acme.sh b/acme.sh index 980dc02..2cb577e 100755 --- a/acme.sh +++ b/acme.sh @@ -1697,6 +1697,9 @@ _post() { if [ "$HTTPS_INSECURE" ]; then _CURL="$_CURL --insecure " fi + if [ "$httpmethod" = "HEAD" ]; then + _CURL="$_CURL -I " + fi _debug "_CURL" "$_CURL" if [ "$needbase64" ]; then if [ "$_postContentType" ]; then From 51b4a9e3509906b86aae4c25a350f8bcdf2d3f8c Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 24 Sep 2019 20:50:24 +0800 Subject: [PATCH 510/565] fix HEAD request against the new LE CDN. wget is fixed --- acme.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/acme.sh b/acme.sh index 2cb577e..cfcd357 100755 --- a/acme.sh +++ b/acme.sh @@ -1727,6 +1727,9 @@ _post() { if [ "$HTTPS_INSECURE" ]; then _WGET="$_WGET --no-check-certificate " fi + if [ "$httpmethod" = "HEAD" ]; then + _WGET="$_WGET --read-timeout=3.0 --tries=2 " + fi _debug "_WGET" "$_WGET" if [ "$needbase64" ]; then if [ "$httpmethod" = "POST" ]; then @@ -1749,6 +1752,12 @@ _post() { else response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" fi + elif [ "$httpmethod" = "HEAD" ]; then + if [ "$_postContentType" ]; then + response="$($_WGET --spider -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + else + response="$($_WGET --spider -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + fi else if [ "$_postContentType" ]; then response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" From 1ba4ab2bd1d200962b7d611e3aeefcf2d32cc48b Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 24 Sep 2019 22:10:36 +0800 Subject: [PATCH 511/565] fix https://github.com/Neilpang/acme.sh/issues/2503 --- acme.sh | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index cfcd357..39c07cb 100755 --- a/acme.sh +++ b/acme.sh @@ -1702,16 +1702,32 @@ _post() { fi _debug "_CURL" "$_CURL" if [ "$needbase64" ]; then - if [ "$_postContentType" ]; then - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" + if [ "$body" ]; then + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" + fi else - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)" + fi fi else - if [ "$_postContentType" ]; then - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" + if [ "$body" ]; then + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" + fi else - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")" + fi fi fi _ret="$?" @@ -1890,7 +1906,7 @@ _send_signed_request() { if [ "$ACME_NEW_NONCE" ]; then _debug2 "Get nonce with HEAD. ACME_NEW_NONCE" "$ACME_NEW_NONCE" nonceurl="$ACME_NEW_NONCE" - if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then + if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type" >/dev/null; then _headers="$(cat "$HTTP_HEADER")" _debug2 _headers "$_headers" _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" From be0df07dfbe5e5fda893450305b9bd1cce3c7ff9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 28 Sep 2019 10:54:31 +0800 Subject: [PATCH 512/565] fix list() performance https://github.com/Neilpang/acme.sh/issues/2296 --- acme.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 39c07cb..0ff24c9 100755 --- a/acme.sh +++ b/acme.sh @@ -4974,18 +4974,14 @@ list() { if [ "$_raw" ]; then printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew" for di in "${CERT_HOME}"/*.*/; do - if ! [ -d "$di" ]; then - _debug "Not directory, skip: $di" - continue - fi d=$(basename "$di") _debug d "$d" ( if _endswith "$d" "$ECC_SUFFIX"; then - _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2) + _isEcc="ecc" d=$(echo "$d" | cut -d "$ECC_SEP" -f 1) fi - _initpath "$d" "$_isEcc" + DOMAIN_CONF="$di/$d.conf" if [ -f "$DOMAIN_CONF" ]; then . "$DOMAIN_CONF" printf "%s\n" "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr" From 10eec7d48c11e91e988be335f5bd4989b628aadb Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 3 Oct 2019 20:37:46 +0800 Subject: [PATCH 513/565] support google dns --- acme.sh | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 0ff24c9..bded4ad 100755 --- a/acme.sh +++ b/acme.sh @@ -90,6 +90,9 @@ DEBUG_LEVEL_3=3 DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1 DEBUG_LEVEL_NONE=0 +DOH_CLOUDFLARE=1 +DOH_GOOGLE=2 + HIDDEN_VALUE="[hidden](please add '--output-insecure' to see this value)" SYSLOG_ERROR="user.error" @@ -3636,7 +3639,7 @@ __trigger_validation() { } #endpoint domain type -_ns_lookup() { +_ns_lookup_impl() { _ns_ep="$1" _ns_domain="$2" _ns_type="$3" @@ -3660,7 +3663,7 @@ _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" + _ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type" } #domain, type @@ -3673,6 +3676,44 @@ _ns_purge_cf() { _debug2 response "$response" } +#checks if cf server is available +_ns_is_available_cf() { + if _get "https://cloudflare-dns.com"; then + return 0 + else + return 1 + fi +} + +#domain, type +_ns_lookup_google() { + _cf_ld="$1" + _cf_ld_type="$2" + _cf_ep="https://dns.google/resolve" + _ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type" +} + +#domain, type +_ns_lookup() { + if [ -z "$DOH_USE" ]; then + _debug "Detect dns server first." + if _ns_is_available_cf; then + _debug "Use cloudflare doh server" + export DOH_USE=$DOH_CLOUDFLARE + else + _debug "Use google doh server" + export DOH_USE=$DOH_GOOGLE + fi + fi + + if [ "$DOH_USE" = "$DOH_CLOUDFLARE" ] || [ -z "$DOH_USE" ]; then + _ns_lookup_cf "$@" + else + _ns_lookup_google "$@" + fi + +} + #txtdomain, alias, txt __check_txt() { _c_txtdomain="$1" @@ -3681,7 +3722,7 @@ __check_txt() { _debug "_c_txtdomain" "$_c_txtdomain" _debug "_c_aliasdomain" "$_c_aliasdomain" _debug "_c_txt" "$_c_txt" - _answers="$(_ns_lookup_cf "$_c_aliasdomain" TXT)" + _answers="$(_ns_lookup "$_c_aliasdomain" TXT)" _contains "$_answers" "$_c_txt" } @@ -3690,7 +3731,13 @@ __check_txt() { __purge_txt() { _p_txtdomain="$1" _debug _p_txtdomain "$_p_txtdomain" - _ns_purge_cf "$_p_txtdomain" "TXT" + if [ "$DOH_USE" = "$DOH_CLOUDFLARE" ] || [ -z "$DOH_USE" ]; then + _ns_purge_cf "$_p_txtdomain" "TXT" + else + _debug "no purge api for google dns api, just sleep 5 secs" + _sleep 5 + fi + } #wait and check each dns entries From b4a62bfa300b0d4c95a3f279b626227e50a8f0a5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 3 Oct 2019 20:51:06 +0800 Subject: [PATCH 514/565] let's start 2.8.4 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index bded4ad..041b5b4 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.8.3 +VER=2.8.4 PROJECT_NAME="acme.sh" From 477a04760c8558d5385736a6537f3313f2f11b96 Mon Sep 17 00:00:00 2001 From: neil <8305679+Neilpang@users.noreply.github.com> Date: Thu, 3 Oct 2019 21:00:30 +0800 Subject: [PATCH 515/565] support google public dns (#2522) * support google dns * let's start 2.8.4 --- acme.sh | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 0ff24c9..041b5b4 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.8.3 +VER=2.8.4 PROJECT_NAME="acme.sh" @@ -90,6 +90,9 @@ DEBUG_LEVEL_3=3 DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1 DEBUG_LEVEL_NONE=0 +DOH_CLOUDFLARE=1 +DOH_GOOGLE=2 + HIDDEN_VALUE="[hidden](please add '--output-insecure' to see this value)" SYSLOG_ERROR="user.error" @@ -3636,7 +3639,7 @@ __trigger_validation() { } #endpoint domain type -_ns_lookup() { +_ns_lookup_impl() { _ns_ep="$1" _ns_domain="$2" _ns_type="$3" @@ -3660,7 +3663,7 @@ _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" + _ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type" } #domain, type @@ -3673,6 +3676,44 @@ _ns_purge_cf() { _debug2 response "$response" } +#checks if cf server is available +_ns_is_available_cf() { + if _get "https://cloudflare-dns.com"; then + return 0 + else + return 1 + fi +} + +#domain, type +_ns_lookup_google() { + _cf_ld="$1" + _cf_ld_type="$2" + _cf_ep="https://dns.google/resolve" + _ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type" +} + +#domain, type +_ns_lookup() { + if [ -z "$DOH_USE" ]; then + _debug "Detect dns server first." + if _ns_is_available_cf; then + _debug "Use cloudflare doh server" + export DOH_USE=$DOH_CLOUDFLARE + else + _debug "Use google doh server" + export DOH_USE=$DOH_GOOGLE + fi + fi + + if [ "$DOH_USE" = "$DOH_CLOUDFLARE" ] || [ -z "$DOH_USE" ]; then + _ns_lookup_cf "$@" + else + _ns_lookup_google "$@" + fi + +} + #txtdomain, alias, txt __check_txt() { _c_txtdomain="$1" @@ -3681,7 +3722,7 @@ __check_txt() { _debug "_c_txtdomain" "$_c_txtdomain" _debug "_c_aliasdomain" "$_c_aliasdomain" _debug "_c_txt" "$_c_txt" - _answers="$(_ns_lookup_cf "$_c_aliasdomain" TXT)" + _answers="$(_ns_lookup "$_c_aliasdomain" TXT)" _contains "$_answers" "$_c_txt" } @@ -3690,7 +3731,13 @@ __check_txt() { __purge_txt() { _p_txtdomain="$1" _debug _p_txtdomain "$_p_txtdomain" - _ns_purge_cf "$_p_txtdomain" "TXT" + if [ "$DOH_USE" = "$DOH_CLOUDFLARE" ] || [ -z "$DOH_USE" ]; then + _ns_purge_cf "$_p_txtdomain" "TXT" + else + _debug "no purge api for google dns api, just sleep 5 secs" + _sleep 5 + fi + } #wait and check each dns entries From 683592fa867ef034afea8036096f96f4f58ea00a Mon Sep 17 00:00:00 2001 From: jess Date: Thu, 3 Oct 2019 06:01:05 -0700 Subject: [PATCH 516/565] Added financial contributors to the README (#2513) --- README.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c6a743..faaf9aa 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh) - [![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + [![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - An ACME protocol client written purely in Shell (Unix shell) language. - Full ACME protocol implementation. - Support ACME v1 and ACME v2 @@ -451,6 +451,36 @@ TODO: 2. ACME protocol: https://github.com/ietf-wg-acme/acme +## Contributors + +### Code Contributors + +This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. + + +### Financial Contributors + +Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/acmesh/contribute)] + +#### Individuals + + + +#### Organizations + +Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/acmesh/contribute)] + + + + + + + + + + + + # 19. License & Others License is GPLv3 From 8ef5daa8070d8c8e2d71b366f14d498c27a74261 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 3 Oct 2019 21:14:11 +0800 Subject: [PATCH 517/565] minor, update link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index faaf9aa..d5012d6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh) - [![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + [![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - An ACME protocol client written purely in Shell (Unix shell) language. - Full ACME protocol implementation. - Support ACME v1 and ACME v2 From 54143ae6d40ba8845de392ab8350c525f47a9417 Mon Sep 17 00:00:00 2001 From: neil <8305679+Neilpang@users.noreply.github.com> Date: Thu, 3 Oct 2019 21:15:32 +0800 Subject: [PATCH 518/565] sync (#2523) sync --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index faaf9aa..d5012d6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh) - [![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + [![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - An ACME protocol client written purely in Shell (Unix shell) language. - Full ACME protocol implementation. - Support ACME v1 and ACME v2 From 72d800ed1098a77f565c14691f164be8ccab969b Mon Sep 17 00:00:00 2001 From: Michael Braunoeder Date: Sat, 5 Oct 2019 05:47:57 +0200 Subject: [PATCH 519/565] [DNSAPI] add dns_rcode0.sh - Support for https://my.rcodezero.at/api-doc (#2489) * first version dns_rcode0.sh * fixed URLs for ACME calls * fixed challenge remove * read & write Token/URL at rm too * make info messages debug * typos fixed * update rrset only if existing challenge is found * polish error messages and make "detect root zone" scaleable * fixed formating issues * code cleanup, remove some unneeded functions * removed empty lines * save rcode0 url only if not default --- dnsapi/dns_rcode0.sh | 224 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100755 dnsapi/dns_rcode0.sh diff --git a/dnsapi/dns_rcode0.sh b/dnsapi/dns_rcode0.sh new file mode 100755 index 0000000..9ed20e6 --- /dev/null +++ b/dnsapi/dns_rcode0.sh @@ -0,0 +1,224 @@ +#!/usr/bin/env sh + +#Rcode0 API Integration +#https://my.rcodezero.at/api-doc +# +# log into https://my.rcodezero.at/enableapi and get your ACME API Token (the ACME API token has limited +# access to the REST calls needed for acme.sh only) +# +#RCODE0_URL="https://my.rcodezero.at" +#RCODE0_API_TOKEN="0123456789ABCDEF" +#RCODE0_TTL=60 + +DEFAULT_RCODE0_URL="https://my.rcodezero.at" +DEFAULT_RCODE0_TTL=60 + +######## Public functions ##################### +#Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000" +#fulldomain +#txtvalue +dns_rcode0_add() { + fulldomain=$1 + txtvalue=$2 + + RCODE0_API_TOKEN="${RCODE0_API_TOKEN:-$(_readaccountconf_mutable RCODE0_API_TOKEN)}" + RCODE0_URL="${RCODE0_URL:-$(_readaccountconf_mutable RCODE0_URL)}" + RCODE0_TTL="${RCODE0_TTL:-$(_readaccountconf_mutable RCODE0_TTL)}" + + if [ -z "$RCODE0_URL" ]; then + RCODE0_URL="$DEFAULT_RCODE0_URL" + fi + + if [ -z "$RCODE0_API_TOKEN" ]; then + RCODE0_API_TOKEN="" + _err "Missing Rcode0 ACME API Token." + _err "Please login and create your token at httsp://my.rcodezero.at/enableapi and try again." + return 1 + fi + + if [ -z "$RCODE0_TTL" ]; then + RCODE0_TTL="$DEFAULT_RCODE0_TTL" + fi + + #save the token to the account conf file. + _saveaccountconf_mutable RCODE0_API_TOKEN "$RCODE0_API_TOKEN" + + if [ "$RCODE0_URL" != "$DEFAULT_RCODE0_URL" ]; then + _saveaccountconf_mutable RCODE0_URL "$RCODE0_URL" + fi + + if [ "$RCODE0_TTL" != "$DEFAULT_RCODE0_TTL" ]; then + _saveaccountconf_mutable RCODE0_TTL "$RCODE0_TTL" + fi + + _debug "Detect root zone" + if ! _get_root "$fulldomain"; then + _err "No 'MASTER' zone for $fulldomain found at RcodeZero Anycast." + return 1 + fi + _debug _domain "$_domain" + + _debug "Adding record" + + _record_string="" + _build_record_string "$txtvalue" + _list_existingchallenges + for oldchallenge in $_existing_challenges; do + _build_record_string "$oldchallenge" + done + + _debug "Challenges: $_existing_challenges" + + if [ -z "$_existing_challenges" ]; then + if ! _rcode0_rest "PATCH" "/api/v1/acme/zones/$_domain/rrsets" "[{\"changetype\": \"add\", \"name\": \"$fulldomain.\", \"type\": \"TXT\", \"ttl\": $RCODE0_TTL, \"records\": [$_record_string]}]"; then + _err "Add txt record error." + return 1 + fi + else + # try update in case a records exists (need for wildcard certs) + if ! _rcode0_rest "PATCH" "/api/v1/acme/zones/$_domain/rrsets" "[{\"changetype\": \"update\", \"name\": \"$fulldomain.\", \"type\": \"TXT\", \"ttl\": $RCODE0_TTL, \"records\": [$_record_string]}]"; then + _err "Set txt record error." + return 1 + fi + fi + + return 0 +} + +#fulldomain txtvalue +dns_rcode0_rm() { + fulldomain=$1 + txtvalue=$2 + + RCODE0_API_TOKEN="${RCODE0_API_TOKEN:-$(_readaccountconf_mutable RCODE0_API_TOKEN)}" + RCODE0_URL="${RCODE0_URL:-$(_readaccountconf_mutable RCODE0_URL)}" + RCODE0_TTL="${RCODE0_TTL:-$(_readaccountconf_mutable RCODE0_TTL)}" + + if [ -z "$RCODE0_URL" ]; then + RCODE0_URL="$DEFAULT_RCODE0_URL" + fi + + if [ -z "$RCODE0_API_TOKEN" ]; then + RCODE0_API_TOKEN="" + _err "Missing Rcode0 API Token." + _err "Please login and create your token at httsp://my.rcodezero.at/enableapi and try again." + return 1 + fi + + #save the api addr and key to the account conf file. + _saveaccountconf_mutable RCODE0_URL "$RCODE0_URL" + _saveaccountconf_mutable RCODE0_API_TOKEN "$RCODE0_API_TOKEN" + + if [ "$RCODE0_TTL" != "$DEFAULT_RCODE0_TTL" ]; then + _saveaccountconf_mutable RCODE0_TTL "$RCODE0_TTL" + fi + + if [ -z "$RCODE0_TTL" ]; then + RCODE0_TTL="$DEFAULT_RCODE0_TTL" + fi + + _debug "Detect root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug "Remove record" + + #Enumerate existing acme challenges + _list_existingchallenges + + if _contains "$_existing_challenges" "$txtvalue"; then + #Delete all challenges (PowerDNS API does not allow to delete content) + if ! _rcode0_rest "PATCH" "/api/v1/acme/zones/$_domain/rrsets" "[{\"changetype\": \"delete\", \"name\": \"$fulldomain.\", \"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 ! _rcode0_rest "PATCH" "/api/v1/acme/zones/$_domain/rrsets" "[{\"changetype\": \"update\", \"name\": \"$fulldomain.\", \"type\": \"TXT\", \"ttl\": $RCODE0_TTL, \"records\": [$_record_string]}]"; then + _err "Set txt record error." + return 1 + fi + fi + else + _info "Record not found, nothing to remove" + fi + + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _domain=domain.com +_get_root() { + domain=$1 + i=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + + _debug "try to find: $h" + if _rcode0_rest "GET" "/api/v1/acme/zones/$h"; then + if [ "$response" = "[\"found\"]" ]; then + _domain="$h" + if [ -z "$h" ]; then + _domain="=2E" + fi + return 0 + elif [ "$response" = "[\"not a master domain\"]" ]; then + return 1 + fi + fi + + if [ -z "$h" ]; then + return 1 + fi + i=$(_math $i + 1) + done + _debug "no matching domain for $domain found" + + return 1 +} + +_rcode0_rest() { + method=$1 + ep=$2 + data=$3 + + export _H1="Authorization: Bearer $RCODE0_API_TOKEN" + + if [ ! "$method" = "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$RCODE0_URL$ep" "" "$method")" + else + response="$(_get "$RCODE0_URL$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + + return 0 +} + +_build_record_string() { + _record_string="${_record_string:+${_record_string}, }{\"content\": \"\\\"${1}\\\"\", \"disabled\": false}" +} + +_list_existingchallenges() { + _rcode0_rest "GET" "/api/v1/acme/zones/$_domain/rrsets" + _existing_challenges=$(echo "$response" | _normalizeJson | _egrep_o "\"name\":\"${fulldomain}[^]]*}" | _egrep_o 'content\":\"\\"[^\\]*' | sed -n 's/^content":"\\"//p') + _debug2 "$_existing_challenges" +} From 1e7534b9d7a4e629f46c6eb9995db20fcf962d80 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 5 Oct 2019 11:59:04 +0800 Subject: [PATCH 520/565] fix https://github.com/Neilpang/acme.sh/issues/2518#issuecomment-538474232 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 041b5b4..cac16d3 100755 --- a/acme.sh +++ b/acme.sh @@ -3678,7 +3678,7 @@ _ns_purge_cf() { #checks if cf server is available _ns_is_available_cf() { - if _get "https://cloudflare-dns.com"; then + if _get "https://cloudflare-dns.com" >/dev/null 2>&1; then return 0 else return 1 From ac9f6e3a4135dbc008c4e22af7f649d139690918 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Sat, 5 Oct 2019 21:06:58 +0800 Subject: [PATCH 521/565] Remove trailing spaces in text files This issue in the shell scripts will also be detected in the stable version of shfmt(we are currently using an ancient pre-release of shfmt) --- .github/ISSUE_TEMPLATE.md | 2 +- .travis.yml | 4 ++-- acme.sh | 4 ++-- deploy/qiniu.sh | 2 +- deploy/routeros.sh | 2 +- deploy/vault_cli.sh | 4 ++-- dnsapi/dns_da.sh | 2 +- dnsapi/dns_doapi.sh | 6 +++--- dnsapi/dns_durabledns.sh | 10 +++++----- dnsapi/dns_euserv.sh | 2 +- dnsapi/dns_freedns.sh | 2 +- dnsapi/dns_me.sh | 2 +- dnsapi/dns_namecheap.sh | 6 +++--- dnsapi/dns_nsupdate.sh | 4 ++-- dnsapi/dns_rcode0.sh | 2 +- 15 files changed, 27 insertions(+), 27 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 189155e..53112c6 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -5,7 +5,7 @@ 如何调试 https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh If it is a bug report: -- make sure you are able to repro it on the latest released version. +- make sure you are able to repro it on the latest released version. You can install the latest version by: `acme.sh --upgrade` - Search the existing issues. diff --git a/.travis.yml b/.travis.yml index 04de193..e77eb32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,5 +34,5 @@ script: matrix: fast_finish: true - - + + diff --git a/acme.sh b/acme.sh index cac16d3..e060e33 100755 --- a/acme.sh +++ b/acme.sh @@ -178,7 +178,7 @@ _printargs() { printf -- "%s" "$1='$2'" fi printf "\n" - # return the saved exit status + # return the saved exit status return "$_exitstatus" } @@ -6215,7 +6215,7 @@ Parameters: --branch, -b Only valid for '--upgrade' command, specifies the branch name to upgrade to. --notify-level 0|1|2|3 Set the notification level: Default value is $NOTIFY_LEVEL_DEFAULT. - 0: disabled, no notification will be sent. + 0: disabled, no notification will be sent. 1: send notifications only when there is an error. 2: send notifications when a cert is successfully renewed, or there is an error. 3: send notifications when a cert is skipped, renewed, or error. diff --git a/deploy/qiniu.sh b/deploy/qiniu.sh index e46e6fb..13b0965 100644 --- a/deploy/qiniu.sh +++ b/deploy/qiniu.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -# Script to create certificate to qiniu.com +# Script to create certificate to qiniu.com # # This deployment required following variables # export QINIU_AK="QINIUACCESSKEY" diff --git a/deploy/routeros.sh b/deploy/routeros.sh index 21c9196..70fe70a 100644 --- a/deploy/routeros.sh +++ b/deploy/routeros.sh @@ -85,7 +85,7 @@ routeros_deploy() { scp "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key" _info "Trying to push cert '$_cfullchain' to router" scp "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer" - DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=ftp,read,write,password,sensitive + DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=ftp,read,write,password,sensitive source=\"## generated by routeros deploy script in acme.sh \n/certificate remove [ find name=$_cdomain.cer_0 ] \n/certificate remove [ find name=$_cdomain.cer_1 ] diff --git a/deploy/vault_cli.sh b/deploy/vault_cli.sh index b93fdd5..5395d87 100644 --- a/deploy/vault_cli.sh +++ b/deploy/vault_cli.sh @@ -2,10 +2,10 @@ # Here is a script to deploy cert to hashicorp vault # (https://www.vaultproject.io/) -# +# # it requires the vault binary to be available in PATH, and the following # environment variables: -# +# # VAULT_PREFIX - this contains the prefix path in vault # VAULT_ADDR - vault requires this to find your vault server # diff --git a/dnsapi/dns_da.sh b/dnsapi/dns_da.sh index 7755c7e..4e9c4ef 100755 --- a/dnsapi/dns_da.sh +++ b/dnsapi/dns_da.sh @@ -9,7 +9,7 @@ # # User must provide login data and URL to DirectAdmin incl. port. # You can create login key, by using the Login Keys function -# ( https://da.example.com:8443/CMD_LOGIN_KEYS ), which only has access to +# ( https://da.example.com:8443/CMD_LOGIN_KEYS ), which only has access to # - CMD_API_DNS_CONTROL # - CMD_API_SHOW_DOMAINS # diff --git a/dnsapi/dns_doapi.sh b/dnsapi/dns_doapi.sh index 135f0b0..a001d52 100755 --- a/dnsapi/dns_doapi.sh +++ b/dnsapi/dns_doapi.sh @@ -1,11 +1,11 @@ #!/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: +# +# Provide the required LetsEncrypt token like this: # DO_LETOKEN="FmD408PdqT1E269gUK57" DO_API="https://www.do.de/api/letsencrypt" diff --git a/dnsapi/dns_durabledns.sh b/dnsapi/dns_durabledns.sh index 9a05eb3..677ae24 100644 --- a/dnsapi/dns_durabledns.sh +++ b/dnsapi/dns_durabledns.sh @@ -147,11 +147,11 @@ _dd_soap() { # build SOAP XML _xml=' - '"$body"' ' diff --git a/dnsapi/dns_euserv.sh b/dnsapi/dns_euserv.sh index 3810156..cfb4b81 100644 --- a/dnsapi/dns_euserv.sh +++ b/dnsapi/dns_euserv.sh @@ -127,7 +127,7 @@ dns_euserv_rm() { else # find XML block where txtvalue is in. The record_id is allways prior this line! _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 is the last Tag with a number before the row _endLine, identified by _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" diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index e76e649..29b1892 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -359,7 +359,7 @@ _freedns_data_id() { # before each table row # search for the record type withing each row (e.g. TXT) # search for the domain within each row (which is within a - # anchor. And finally extract the domain ID. + # anchor. And finally extract the domain ID. if [ -n "$data_id" ]; then printf "%s" "$data_id" return 0 diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 382eeed..98a5841 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -2,7 +2,7 @@ # bug reports to dev@1e.ca -# ME_Key=qmlkdjflmkqdjf +# ME_Key=qmlkdjflmkqdjf # ME_Secret=qmsdlkqmlksdvnnpae ME_Api=https://api.dnsmadeeasy.com/V2.0/dns/managed diff --git a/dnsapi/dns_namecheap.sh b/dnsapi/dns_namecheap.sh index a82e12d..2e38926 100755 --- a/dnsapi/dns_namecheap.sh +++ b/dnsapi/dns_namecheap.sh @@ -3,10 +3,10 @@ # Namecheap API # https://www.namecheap.com/support/api/intro.aspx # -# Requires Namecheap API key set in -#NAMECHEAP_API_KEY, +# Requires Namecheap API key set in +#NAMECHEAP_API_KEY, #NAMECHEAP_USERNAME, -#NAMECHEAP_SOURCEIP +#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 ##################### diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index dfb3672..cd4b714 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -27,7 +27,7 @@ dns_nsupdate_add() { [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D" if [ -z "${NSUPDATE_ZONE}" ]; then nsupdate -k "${NSUPDATE_KEY}" $nsdebug < Date: Sat, 5 Oct 2019 21:13:23 +0800 Subject: [PATCH 522/565] Use shallow clone to speed up git clone on Travis CI Shallow clone is faster than a normal one, there is no need to clone the whole history of a repository when we only needs its latest or certain state of commit. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 04de193..5f0ce0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ script: - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi - cd .. - - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest + - git clone --depth 1 https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./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 From bc396e7a90e05704eddf12d728809e72ce77d5dd Mon Sep 17 00:00:00 2001 From: Vadim Kalinnikov Date: Sun, 6 Oct 2019 14:38:26 +0300 Subject: [PATCH 523/565] Small fix in dns_vultr.sh --- dnsapi/dns_vultr.sh | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_vultr.sh b/dnsapi/dns_vultr.sh index f15e7c4..0dce2ca 100644 --- a/dnsapi/dns_vultr.sh +++ b/dnsapi/dns_vultr.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/bin/bash # #VULTR_API_KEY=000011112222333344445555666677778888 @@ -106,9 +106,9 @@ _get_root() { domain=$1 i=1 while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - _debug h "$h" - if [ -z "$h" ]; then + _domain=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$_domain" + if [ -z "$_domain" ]; then return 1 fi @@ -119,11 +119,9 @@ _get_root() { if printf "%s\n" "$response" | grep '^\[.*\]' >/dev/null; then if _contains "$response" "\"domain\":\"$_domain\""; then _sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")" - _domain=$_domain return 0 else - _err 'Invalid domain' - return 1 + _debug "Go to next level of $_domain" fi else _err "$response" From e484f32b1abe2fea12a4b5fb9d13e7eb23996f9a Mon Sep 17 00:00:00 2001 From: Vadim Kalinnikov Date: Sun, 6 Oct 2019 14:40:57 +0300 Subject: [PATCH 524/565] - Return shell detect via env --- dnsapi/dns_vultr.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_vultr.sh b/dnsapi/dns_vultr.sh index 0dce2ca..c7b52e8 100644 --- a/dnsapi/dns_vultr.sh +++ b/dnsapi/dns_vultr.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env sh # #VULTR_API_KEY=000011112222333344445555666677778888 From 65c950e1a41562b9eca0b23b04a260b18c3335d4 Mon Sep 17 00:00:00 2001 From: MooSE <32853697+moose-kazan@users.noreply.github.com> Date: Sun, 6 Oct 2019 15:02:48 +0300 Subject: [PATCH 525/565] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d5012d6..faaf9aa 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh) - [![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + [![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - An ACME protocol client written purely in Shell (Unix shell) language. - Full ACME protocol implementation. - Support ACME v1 and ACME v2 From f500c7abcba29d19b2d49d8e3b25d9c6d5e2f726 Mon Sep 17 00:00:00 2001 From: Bill Gertz Date: Tue, 8 Oct 2019 15:47:39 +0200 Subject: [PATCH 526/565] dnsapi/dns_miab.sh MIAB DNS-01 Validation Know I'm new to contorting to this project. I i've broke conventions please let me know what I've screwed up and I'll set it right as quickly as possible. Propose this as a new DNS-01 validation script to dynamically add challenge DNS records to MailinaBox (MIAB) DNS. MIAB uses a custom DNS API to manage external DNS records. The script was originally written by Darven Dissek and can be found in his repository: https://framagit.org/DarvenDissek/acme.sh-MIAB-DNS-API/). This has been forked and some slight cleanup applied and change shebang to UNIx shell. The forked repository can be found here: https://github.com/billgertz/MIAB_dns_api. Wrote to Darven but received no reply. Support for this script has been submitted to the OPNsense project via this pull request: https://github.com/opnsense/plugins/pull/1531 --- dnsapi/dns_miab.sh | 273 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 dnsapi/dns_miab.sh diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh new file mode 100644 index 0000000..b0a52d7 --- /dev/null +++ b/dnsapi/dns_miab.sh @@ -0,0 +1,273 @@ +#!/usr/bin/env sh + +#Name: dns_miab.sh +# +#Authors: +# Darven Dissek 2018 +# William Gertz 2019 +# +# Thanks to Neil Pang for the code reused from acme.sh from HTTP-01 validation +# used to communicate with the MailintheBox Custom DNS API +#Report Bugs here: +# https://github.com/billgertz/MIAB_dns_api (for dns_miab.sh) +# https://github.com/Neilpang/acme.sh (for acme.sh) +# +######## Public functions ##################### + +#Usage: dns_miab_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_miab_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using miab" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + MIAB_Username="${MIAB_Username:-$(_readaccountconf_mutable MIAB_Username)}" + MIAB_Password="${MIAB_Password:-$(_readaccountconf_mutable MIAB_Password)}" + MIAB_Server="${MIAB_Server:-$(_readaccountconf_mutable MIAB_Server)}" + + #debug log the environmental variables + _debug MIAB_Username "$MIAB_Username" + _debug MIAB_Password "$MIAB_Password" + _debug MIAB_Server "$MIAB_Server" + + if [ -z "$MIAB_Username" ] || [ -z "$MIAB_Password" ] || [ -z "$MIAB_Server" ]; then + MIAB_Username="" + MIAB_Password="" + MIAB_Server="" + _err "You didn't specify MIAB_Username or MIAB_Password or MIAB_Server." + _err "Please try again." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable MIAB_Username "$MIAB_Username" + _saveaccountconf_mutable MIAB_Password "$MIAB_Password" + _saveaccountconf_mutable MIAB_Server "$MIAB_Server" + + baseurl="https://$MIAB_Server/admin/dns/custom/$fulldomain/txt" + + #Add the challenge record + result="$(_miab_post "$txtvalue" "$baseurl" "" "POST" "" "$MIAB_Username" "$MIAB_Password")" + + _debug result "$result" + + #check if result was good + if _contains "$result" "updated DNS"; then + _info "Successfully created the txt record" + return 0 + else + _err "Error encountered during record addition" + _err "$result" + return 1 + fi + +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_miab_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using miab" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + MIAB_Username="${MIAB_Username:-$(_readaccountconf_mutable MIAB_Username)}" + MIAB_Password="${MIAB_Password:-$(_readaccountconf_mutable MIAB_Password)}" + MIAB_Server="${MIAB_Server:-$(_readaccountconf_mutable MIAB_Server)}" + + #debug log the environmental variables + _debug MIAB_Username "$MIAB_Username" + _debug MIAB_Password "$MIAB_Password" + _debug MIAB_Server "$MIAB_Server" + + if [ -z "$MIAB_Username" ] || [ -z "$MIAB_Password" ] || [ -z "$MIAB_Server" ]; then + MIAB_Username="" + MIAB_Password="" + MIAB_Server="" + _err "You didn't specify MIAB_Username or MIAB_Password or MIAB_Server." + _err "Please try again." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable MIAB_Username "$MIAB_Username" + _saveaccountconf_mutable MIAB_Password "$MIAB_Password" + _saveaccountconf_mutable MIAB_Server "$MIAB_Server" + + baseurl="https://$MIAB_Server/admin/dns/custom/$fulldomain/txt" + + #Remove the challenge record + result="$(_miab_post "$txtvalue" "$baseurl" "" "DELETE" "" "$MIAB_Username" "$MIAB_Password")" + + _debug result $result + + #check if result was good + if _contains "$result" "updated DNS"; then + _info "Successfully created the txt record" + return 0 + else + _err "Error encountered during record addition" + _err "$result" + return 1 + fi +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _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 +} + +# post changes to MIAB dns (taken from acme.sh) +_miab_post() { + body="$1" + _post_url="$2" + needbase64="$3" + httpmethod="$4" + _postContentType="$5" + username="$6" + password="$7" + + if [ -z "$httpmethod" ]; then + httpmethod="POST" + fi + + _debug $httpmethod + _debug "_post_url" "$_post_url" + _debug2 "body" "$body" + _debug2 "_postContentType" "$_postContentType" + + _inithttp + + if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then + _CURL="$_ACME_CURL" + + if [ "$HTTPS_INSECURE" ]; then + _CURL="$_CURL --insecure " + fi + + _debug "_CURL" "$_CURL" + + if [ "$needbase64" ]; then + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod --user "$username:$password" -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod --user "$username:$password" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" + fi + else + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod --user "$username:$password" -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod --user "$username:$password" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" + fi + fi + + _ret="$?" + + if [ "$_ret" != "0" ]; then + _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + _err "Here is the curl dump log:" + _err "$(cat "$_CURL_DUMP")" + fi + fi + + elif [ "$_ACME_WGET" ]; then + _WGET="$_ACME_WGET" + + if [ "$HTTPS_INSECURE" ]; then + _WGET="$_WGET --no-check-certificate " + fi + + _debug "_WGET" "$_WGET" + + if [ "$needbase64" ]; then + + if [ "$httpmethod" = "POST" ]; then + if [ "$_postContentType" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + else + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + fi + else + if [ "$_postContentType" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + else + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + fi + fi + + else + + if [ "$httpmethod" = "POST" ]; then + if [ "$_postContentType" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + else + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + fi + else + if [ "$_postContentType" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + else + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + fi + fi + + fi + + _ret="$?" + + if [ "$_ret" = "8" ]; then + _ret=0 + _debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later." + fi + + if [ "$_ret" != "0" ]; then + _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" + fi + + _sed_i "s/^ *//g" "$HTTP_HEADER" + + else + _ret="$?" + _err "Neither curl nor wget was found, cannot do $httpmethod." + fi + + _debug "_ret" "$_ret" + printf "%s" "$response" + return $_ret +} From 47c33d0344208d0bb47f173d64672e69fc18ac37 Mon Sep 17 00:00:00 2001 From: Bill Gertz Date: Tue, 8 Oct 2019 16:29:23 +0200 Subject: [PATCH 527/565] Cleanup/ removed private function _get_root Function _get_root() copied from acme.sh and is not needed here. Other cleanup as recommended by acme.sh test bot. --- dnsapi/dns_miab.sh | 71 +++++++++++----------------------------------- 1 file changed, 17 insertions(+), 54 deletions(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index b0a52d7..b68f670 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -1,16 +1,16 @@ #!/usr/bin/env sh -#Name: dns_miab.sh +# Name: dns_miab.sh # -#Authors: -# Darven Dissek 2018 -# William Gertz 2019 +# Authors: +# Darven Dissek 2018 +# William Gertz 2019 # -# Thanks to Neil Pang for the code reused from acme.sh from HTTP-01 validation -# used to communicate with the MailintheBox Custom DNS API -#Report Bugs here: -# https://github.com/billgertz/MIAB_dns_api (for dns_miab.sh) -# https://github.com/Neilpang/acme.sh (for acme.sh) +# Thanks to Neil Pang for the code reused from acme.sh from HTTP-01 validation +# used to communicate with the MailintheBox Custom DNS API +# Report Bugs here: +# https://github.com/billgertz/MIAB_dns_api (for dns_miab.sh) +# https://github.com/Neilpang/acme.sh (for acme.sh) # ######## Public functions ##################### @@ -41,9 +41,9 @@ dns_miab_add() { fi #save the credentials to the account conf file. - _saveaccountconf_mutable MIAB_Username "$MIAB_Username" - _saveaccountconf_mutable MIAB_Password "$MIAB_Password" - _saveaccountconf_mutable MIAB_Server "$MIAB_Server" + _saveaccountconf_mutable MIAB_Username "$MIAB_Username" + _saveaccountconf_mutable MIAB_Password "$MIAB_Password" + _saveaccountconf_mutable MIAB_Server "$MIAB_Server" baseurl="https://$MIAB_Server/admin/dns/custom/$fulldomain/txt" @@ -61,7 +61,6 @@ dns_miab_add() { _err "$result" return 1 fi - } #Usage: fulldomain txtvalue @@ -92,16 +91,16 @@ dns_miab_rm() { fi #save the credentials to the account conf file. - _saveaccountconf_mutable MIAB_Username "$MIAB_Username" - _saveaccountconf_mutable MIAB_Password "$MIAB_Password" - _saveaccountconf_mutable MIAB_Server "$MIAB_Server" + _saveaccountconf_mutable MIAB_Username "$MIAB_Username" + _saveaccountconf_mutable MIAB_Password "$MIAB_Password" + _saveaccountconf_mutable MIAB_Server "$MIAB_Server" baseurl="https://$MIAB_Server/admin/dns/custom/$fulldomain/txt" #Remove the challenge record result="$(_miab_post "$txtvalue" "$baseurl" "" "DELETE" "" "$MIAB_Username" "$MIAB_Password")" - _debug result $result + _debug result "$result" #check if result was good if _contains "$result" "updated DNS"; then @@ -115,43 +114,7 @@ dns_miab_rm() { } #################### Private functions below ################################## -#_acme-challenge.www.domain.com -#returns -# _sub_domain=_acme-challenge.www -# _domain=domain.com -# _domain_id=sdjkglgdfewsdfg -_get_root() { - domain=$1 - i=2 - p=1 - - while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - _debug h "$h" - if [ -z "$h" ]; then - #not valid - return 1 - fi - - if _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 -} - +# # post changes to MIAB dns (taken from acme.sh) _miab_post() { body="$1" From a4ec9f8b44a0ae2a22c4af44d423b58e73fa6fdf Mon Sep 17 00:00:00 2001 From: Bill Gertz Date: Tue, 8 Oct 2019 16:34:56 +0200 Subject: [PATCH 528/565] Fixed weird spacing on line 180 Um, fixed. --- dnsapi/dns_miab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index b68f670..c91bf3c 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -180,7 +180,7 @@ _miab_post() { if [ "$needbase64" ]; then - if [ "$httpmethod" = "POST" ]; then + if [ "$httpmethod" = "POST" ]; then if [ "$_postContentType" ]; then response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" else From 835f9aad91e9995e688b1be8e827f0a6443af746 Mon Sep 17 00:00:00 2001 From: Bill Gertz Date: Tue, 8 Oct 2019 16:47:32 +0200 Subject: [PATCH 529/565] Um that's a wee bit of nit pick. 'Errant' space removed on blank line on line 147. --- dnsapi/dns_miab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index c91bf3c..8786634 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -144,7 +144,7 @@ _miab_post() { fi _debug "_CURL" "$_CURL" - + if [ "$needbase64" ]; then if [ "$_postContentType" ]; then response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod --user "$username:$password" -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" From c06ec7c6bae0cc40daede2121d006b764e73cb47 Mon Sep 17 00:00:00 2001 From: Bill Gertz Date: Tue, 8 Oct 2019 18:15:16 +0200 Subject: [PATCH 530/565] Removed parameters and unused code for _miab_post Ok, should have noticed earlier that the calls to the private function _miab_post() never used the _needbase64_ or the __postContentType parameters. Parameters and code to handle them has been factored out. --- dnsapi/dns_miab.sh | 70 +++++++++------------------------------------- 1 file changed, 13 insertions(+), 57 deletions(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index 8786634..df2ca6e 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -48,7 +48,7 @@ dns_miab_add() { baseurl="https://$MIAB_Server/admin/dns/custom/$fulldomain/txt" #Add the challenge record - result="$(_miab_post "$txtvalue" "$baseurl" "" "POST" "" "$MIAB_Username" "$MIAB_Password")" + result="$(_miab_post "$txtvalue" "$baseurl" "POST" "$MIAB_Username" "$MIAB_Password")" _debug result "$result" @@ -91,14 +91,14 @@ dns_miab_rm() { fi #save the credentials to the account conf file. - _saveaccountconf_mutable MIAB_Username "$MIAB_Username" - _saveaccountconf_mutable MIAB_Password "$MIAB_Password" - _saveaccountconf_mutable MIAB_Server "$MIAB_Server" + _saveaccountconf_mutable MIAB_Username "$MIAB_Username" + _saveaccountconf_mutable MIAB_Password "$MIAB_Password" + _saveaccountconf_mutable MIAB_Server "$MIAB_Server" baseurl="https://$MIAB_Server/admin/dns/custom/$fulldomain/txt" #Remove the challenge record - result="$(_miab_post "$txtvalue" "$baseurl" "" "DELETE" "" "$MIAB_Username" "$MIAB_Password")" + result="$(_miab_post "$txtvalue" "$baseurl" "DELETE" "$MIAB_Username" "$MIAB_Password")" _debug result "$result" @@ -119,11 +119,9 @@ dns_miab_rm() { _miab_post() { body="$1" _post_url="$2" - needbase64="$3" - httpmethod="$4" - _postContentType="$5" - username="$6" - password="$7" + httpmethod="$3" + username="$4" + password="$5" if [ -z "$httpmethod" ]; then httpmethod="POST" @@ -144,21 +142,7 @@ _miab_post() { fi _debug "_CURL" "$_CURL" - - if [ "$needbase64" ]; then - if [ "$_postContentType" ]; then - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod --user "$username:$password" -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" - else - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod --user "$username:$password" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" - fi - else - if [ "$_postContentType" ]; then - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod --user "$username:$password" -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" - else - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod --user "$username:$password" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" - fi - fi - + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod --user "$username:$password" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" _ret="$?" if [ "$_ret" != "0" ]; then @@ -178,40 +162,12 @@ _miab_post() { _debug "_WGET" "$_WGET" - if [ "$needbase64" ]; then - - if [ "$httpmethod" = "POST" ]; then - if [ "$_postContentType" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" - else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" - fi - else - if [ "$_postContentType" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" - else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" - fi - fi - + if [ "$httpmethod" = "POST" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" else - - if [ "$httpmethod" = "POST" ]; then - if [ "$_postContentType" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" - else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" - fi - else - if [ "$_postContentType" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" - else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" - fi - fi - + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" fi - + _ret="$?" if [ "$_ret" = "8" ]; then From f323ced4ca0d46c4119a8c4ac3ce67125edce149 Mon Sep 17 00:00:00 2001 From: Bill Gertz Date: Tue, 8 Oct 2019 18:24:14 +0200 Subject: [PATCH 531/565] Style issues and orphan _postContentType debug fix Fixed spacing and removed unneeded debug for _postContenetType --- dnsapi/dns_miab.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index df2ca6e..e2f4d59 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -91,9 +91,9 @@ dns_miab_rm() { fi #save the credentials to the account conf file. - _saveaccountconf_mutable MIAB_Username "$MIAB_Username" - _saveaccountconf_mutable MIAB_Password "$MIAB_Password" - _saveaccountconf_mutable MIAB_Server "$MIAB_Server" + _saveaccountconf_mutable MIAB_Username "$MIAB_Username" + _saveaccountconf_mutable MIAB_Password "$MIAB_Password" + _saveaccountconf_mutable MIAB_Server "$MIAB_Server" baseurl="https://$MIAB_Server/admin/dns/custom/$fulldomain/txt" @@ -130,8 +130,7 @@ _miab_post() { _debug $httpmethod _debug "_post_url" "$_post_url" _debug2 "body" "$body" - _debug2 "_postContentType" "$_postContentType" - + _inithttp if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then @@ -167,7 +166,7 @@ _miab_post() { else response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" fi - + _ret="$?" if [ "$_ret" = "8" ]; then From f64b061a28bf06f7f1586048615cef090b9c09e9 Mon Sep 17 00:00:00 2001 From: Bill Gertz Date: Tue, 8 Oct 2019 18:46:35 +0200 Subject: [PATCH 532/565] Style issue Spaces on blank line on line 133. --- dnsapi/dns_miab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index e2f4d59..d17a1f7 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -130,7 +130,7 @@ _miab_post() { _debug $httpmethod _debug "_post_url" "$_post_url" _debug2 "body" "$body" - + _inithttp if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then From ba7db3edda2c3d4e8265d2c5302b973d6541afd8 Mon Sep 17 00:00:00 2001 From: David Robles Date: Wed, 9 Oct 2019 08:08:05 -0700 Subject: [PATCH 533/565] Use more widely supported options for the "tr" command line utility by removing the use of the character class representation option. Fixes #2536 --- dnsapi/dns_freedns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index e76e649..bb80dc4 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -303,7 +303,7 @@ _freedns_domain_id() { return 1 fi - domain_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ + domain_id="$(echo "$htmlpage" | tr -d "\r\n" | sed 's//@/g' | tr '@' '\n' \ | grep "$search_domain\|$search_domain(.*)" \ | _egrep_o "edit\.php\?edit_domain_id=[0-9a-zA-Z]+" \ | cut -d = -f 2)" @@ -349,7 +349,7 @@ _freedns_data_id() { return 1 fi - data_id="$(echo "$htmlpage" | tr -d "[:space:]" | sed 's//@/g' | tr '@' '\n' \ + data_id="$(echo "$htmlpage" | tr -d "\r\n" | sed 's//@/g' | tr '@' '\n' \ | grep "$record_type" \ | grep "$search_domain" \ | _egrep_o "edit\.php\?data_id=[0-9a-zA-Z]+" \ From 252a21e2ae715885e5c45044fe19538e6b009399 Mon Sep 17 00:00:00 2001 From: temoffey Date: Thu, 10 Oct 2019 00:36:34 +0300 Subject: [PATCH 534/565] fixed json parse regex for support api gcore_cdn --- deploy/gcore_cdn.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/gcore_cdn.sh b/deploy/gcore_cdn.sh index bbda58e..a2a35f7 100644 --- a/deploy/gcore_cdn.sh +++ b/deploy/gcore_cdn.sh @@ -77,15 +77,15 @@ gcore_cdn_deploy() { _debug _regex "$_regex" _resource=$(echo "$_response" | sed 's/},{/},\n{/g' | _egrep_o "$_regex") _debug _resource "$_resource" - _regex=".*\"id\":\([0-9]*\),.*$" + _regex=".*\"id\":\([0-9]*\).*\"rules\".*$" _debug _regex "$_regex" _resourceId=$(echo "$_resource" | sed -n "s/$_regex/\1/p") _debug _resourceId "$_resourceId" - _regex=".*\"sslData\":\([0-9]*\)}.*$" + _regex=".*\"sslData\":\([0-9]*\).*$" _debug _regex "$_regex" _sslDataOld=$(echo "$_resource" | sed -n "s/$_regex/\1/p") _debug _sslDataOld "$_sslDataOld" - _regex=".*\"originGroup\":\([0-9]*\),.*$" + _regex=".*\"originGroup\":\([0-9]*\).*$" _debug _regex "$_regex" _originGroup=$(echo "$_resource" | sed -n "s/$_regex/\1/p") _debug _originGroup "$_originGroup" @@ -101,7 +101,7 @@ gcore_cdn_deploy() { _debug _request "$_request" _response=$(_post "$_request" "https://api.gcdn.co/sslData") _debug _response "$_response" - _regex=".*\"id\":\([0-9]*\),.*$" + _regex=".*\"id\":\([0-9]*\).*$" _debug _regex "$_regex" _sslDataAdd=$(echo "$_response" | sed -n "s/$_regex/\1/p") _debug _sslDataAdd "$_sslDataAdd" From aa6112482d90e17b19127b71d5f12d097e13c485 Mon Sep 17 00:00:00 2001 From: Bill Gertz Date: Sun, 13 Oct 2019 19:56:04 +0200 Subject: [PATCH 535/565] Rewrite to conform to Dev guide Created _get_root() that tests the requested host is a subdomain to the domains hosted on MailinaBox (MIAB) DNS Server. Created common _miab_rest() used with dns_miab_add(), dns_miab_rm() and _get_root(). Also created barbaric _is_json() to test the response given by the MIAB Custom DNS API at least looks like a JSON file. We should add a hint to use _normalizeJson with JSON responses so _startswith, _endswith won't perplexingly fail. --- dnsapi/dns_miab.sh | 257 ++++++++++++++++++++++++--------------------- 1 file changed, 139 insertions(+), 118 deletions(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index d17a1f7..313e4eb 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -6,186 +6,207 @@ # Darven Dissek 2018 # William Gertz 2019 # -# Thanks to Neil Pang for the code reused from acme.sh from HTTP-01 validation -# used to communicate with the MailintheBox Custom DNS API +# Thanks to Neil Pang and other developers here for code reused from acme.sh from DNS-01 +# used to communicate with the MailinaBox Custom DNS API # Report Bugs here: # https://github.com/billgertz/MIAB_dns_api (for dns_miab.sh) # https://github.com/Neilpang/acme.sh (for acme.sh) # ######## Public functions ##################### -#Usage: dns_miab_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +#Usage: dns_miab_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_miab_add() { fulldomain=$1 txtvalue=$2 - _info "Using miab" + _info "Using miab challange add" _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" - MIAB_Username="${MIAB_Username:-$(_readaccountconf_mutable MIAB_Username)}" - MIAB_Password="${MIAB_Password:-$(_readaccountconf_mutable MIAB_Password)}" - MIAB_Server="${MIAB_Server:-$(_readaccountconf_mutable MIAB_Server)}" - - #debug log the environmental variables - _debug MIAB_Username "$MIAB_Username" - _debug MIAB_Password "$MIAB_Password" - _debug MIAB_Server "$MIAB_Server" - - if [ -z "$MIAB_Username" ] || [ -z "$MIAB_Password" ] || [ -z "$MIAB_Server" ]; then - MIAB_Username="" - MIAB_Password="" - MIAB_Server="" - _err "You didn't specify MIAB_Username or MIAB_Password or MIAB_Server." - _err "Please try again." + #retrieve MIAB environemt vars + if ! _retrieve_miab_env; then + return 1 + fi + + #check domain and seperate into doamin and host + if ! _get_root "$fulldomain"; then + _err "Cannot find any part of ${fulldomain} is hosted on ${MIAB_Server}" return 1 fi - #save the credentials to the account conf file. - _saveaccountconf_mutable MIAB_Username "$MIAB_Username" - _saveaccountconf_mutable MIAB_Password "$MIAB_Password" - _saveaccountconf_mutable MIAB_Server "$MIAB_Server" - - baseurl="https://$MIAB_Server/admin/dns/custom/$fulldomain/txt" - - #Add the challenge record - result="$(_miab_post "$txtvalue" "$baseurl" "POST" "$MIAB_Username" "$MIAB_Password")" + _debug2 _sub_domain "$_sub_domain" + _debug2 _domain "$_domain" - _debug result "$result" + #add the challenge record + _api_path="custom/${fulldomain}/txt" + _miab_rest "$txtvalue" "$_api_path" "POST" #check if result was good - if _contains "$result" "updated DNS"; then + if _contains "$response" "updated DNS"; then _info "Successfully created the txt record" return 0 else - _err "Error encountered during record addition" - _err "$result" + _err "Error encountered during record add" + _err "$response" return 1 fi } -#Usage: fulldomain txtvalue -#Remove the txt record after validation. +#Usage: dns_miab_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_miab_rm() { fulldomain=$1 txtvalue=$2 - _info "Using miab" + + _info "Using miab challage delete" _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" - MIAB_Username="${MIAB_Username:-$(_readaccountconf_mutable MIAB_Username)}" - MIAB_Password="${MIAB_Password:-$(_readaccountconf_mutable MIAB_Password)}" - MIAB_Server="${MIAB_Server:-$(_readaccountconf_mutable MIAB_Server)}" - - #debug log the environmental variables - _debug MIAB_Username "$MIAB_Username" - _debug MIAB_Password "$MIAB_Password" - _debug MIAB_Server "$MIAB_Server" + #retrieve MIAB environemt vars + if ! _retrieve_miab_env; then + return 1 + fi - if [ -z "$MIAB_Username" ] || [ -z "$MIAB_Password" ] || [ -z "$MIAB_Server" ]; then - MIAB_Username="" - MIAB_Password="" - MIAB_Server="" - _err "You didn't specify MIAB_Username or MIAB_Password or MIAB_Server." - _err "Please try again." + #check domain and seperate into doamin and host + if ! _get_root "$fulldomain"; then + _err "Cannot find any part of ${fulldomain} is hosted on ${MIAB_Server}" return 1 fi - #save the credentials to the account conf file. - _saveaccountconf_mutable MIAB_Username "$MIAB_Username" - _saveaccountconf_mutable MIAB_Password "$MIAB_Password" - _saveaccountconf_mutable MIAB_Server "$MIAB_Server" - - baseurl="https://$MIAB_Server/admin/dns/custom/$fulldomain/txt" + _debug2 _sub_domain "$_sub_domain" + _debug2 _domain "$_domain" #Remove the challenge record - result="$(_miab_post "$txtvalue" "$baseurl" "DELETE" "$MIAB_Username" "$MIAB_Password")" - - _debug result "$result" + _api_path="custom/${fulldomain}/txt" + _miab_rest "$txtvalue" "$_api_path" "DELETE" #check if result was good - if _contains "$result" "updated DNS"; then - _info "Successfully created the txt record" + if _contains "$response" "updated DNS"; then + _info "Successfully removed the txt record" return 0 else - _err "Error encountered during record addition" - _err "$result" + _err "Error encountered during record remove" + _err "$response" return 1 fi } #################### Private functions below ################################## # -# post changes to MIAB dns (taken from acme.sh) -_miab_post() { - body="$1" - _post_url="$2" - httpmethod="$3" - username="$4" - password="$5" - - if [ -z "$httpmethod" ]; then - httpmethod="POST" +#Usage: _get_root _acme-challenge.www.domain.com +#Returns: +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + _passed_domain=$1 + _debug _passed_domain "$_passed_domain" + _i=2 + _p=1 + + #get the zones hosed on MIAB server, must be a json stream + _miab_rest "" "zones" "GET" + + _info "_startswith test:$(_startswith "test" "t")" + _info "_endstest test:$(_endswith "test" "t")" + + if ! _is_json "$response"; then + _err "ERROR fetching domain list" + _err "$response" + return 1 fi - _debug $httpmethod - _debug "_post_url" "$_post_url" - _debug2 "body" "$body" - - _inithttp - - if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then - _CURL="$_ACME_CURL" + #cycle through the passed domain seperating out a test domain discarding + # the subdomain by marching thorugh the dots + while true; do + _test_domain=$(printf "%s" "$_passed_domain" | cut -d . -f ${_i}-100) + _debug _test_domain "$_test_domain" - if [ "$HTTPS_INSECURE" ]; then - _CURL="$_CURL --insecure " + if [ -z "$_test_domain" ]; then + return 1 fi - _debug "_CURL" "$_CURL" - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod --user "$username:$password" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" - _ret="$?" - - if [ "$_ret" != "0" ]; then - _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - _err "Here is the curl dump log:" - _err "$(cat "$_CURL_DUMP")" - fi + #report found if the test domain is in the json response and + # report the subdomain + if _contains "$response" "\"$_test_domain\""; then + _sub_domain=$(printf "%s" "$_passed_domain" | cut -d . -f 1-${_p}) + _domain=${_test_domain} + return 0 fi - elif [ "$_ACME_WGET" ]; then - _WGET="$_ACME_WGET" + #cycle to the next dot in the passed domain + _p=${_i} + _i=$(_math "$_i" + 1) + done - if [ "$HTTPS_INSECURE" ]; then - _WGET="$_WGET --no-check-certificate " - fi + return 1 +} - _debug "_WGET" "$_WGET" +#Usage: _retrieve_miab_env +#Returns (from store or environment variables): +# MIAB_Username +# MIAB_Password +# MIAB_Server +#retrieve MIAB environment variables, report errors and quit if problems +_retrieve_miab_env() { + MIAB_Username="${MIAB_Username:-$(_readaccountconf_mutable MIAB_Username)}" + MIAB_Password="${MIAB_Password:-$(_readaccountconf_mutable MIAB_Password)}" + MIAB_Server="${MIAB_Server:-$(_readaccountconf_mutable MIAB_Server)}" - if [ "$httpmethod" = "POST" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" - else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" - fi + #debug log the environmental variables + _debug MIAB_Username "$MIAB_Username" + _debug MIAB_Password "$MIAB_Password" + _debug MIAB_Server "$MIAB_Server" - _ret="$?" + #check if MIAB environemt vars set and quit if not + if [ -z "$MIAB_Username" ] || [ -z "$MIAB_Password" ] || [ -z "$MIAB_Server" ]; then + _err "You didn't specify one or more of MIAB_Username, MIAB_Password or MIAB_Server." + _err "Please check these environment variables and try again." + return 1 + fi - if [ "$_ret" = "8" ]; then - _ret=0 - _debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later." - fi + #save the credentials to the account conf file. + _saveaccountconf_mutable MIAB_Username "$MIAB_Username" + _saveaccountconf_mutable MIAB_Password "$MIAB_Password" + _saveaccountconf_mutable MIAB_Server "$MIAB_Server" +} - if [ "$_ret" != "0" ]; then - _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" - fi +#Useage: _miab_rest "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" "custom/_acme-challenge.www.domain.com/txt "POST" +#Returns: "updated DNS: domain.com" +#rest interface MIAB dns +_miab_rest() { + _data="$1" + _api_path="$2" + _httpmethod="$3" + + #encode username and password for url + _username="$(printf "%s" "$MIAB_Username" | _url_encode)" + _password="$(printf "%s" "$MIAB_Password" | _url_encode)" + _url="https://${_username}:${_password}@${MIAB_Server}/admin/dns/${_api_path}" + + _debug2 _data "$_data" + _debug _api_path "$_api_path" + _debug2 _url "$_url" + _debug _httpmethod "$_httpmethod" + + if [ "$_httpmethod" = "GET" ]; then + response="$(_get "$_url")" + else + response="$(_post "$_data" "$_url" "" "$_httpmethod")" + fi - _sed_i "s/^ *//g" "$HTTP_HEADER" + _retcode="$?" - else - _ret="$?" - _err "Neither curl nor wget was found, cannot do $httpmethod." + if [ "$_retcode" != "0" ]; then + _err "MAAB REST authentication failed on $_httpmethod" + return 1 fi - _debug "_ret" "$_ret" - printf "%s" "$response" - return $_ret + _debug response "$response" + return 0 +} + +#Usage: _is_json "\[\n "mydomain.com"\n]" +#Reurns "\[\n "mydomain.com"\n]" +#returns the string if it begins and ends with square braces +_is_json() { + _str="$(echo "$1" | _normalizeJson)" + echo "$_str" | grep '^\[.*\]$' >/dev/null 2>&1 } From 7ec52145e807fc15dfb6c1e501183f14b58f3d80 Mon Sep 17 00:00:00 2001 From: Bill Gertz Date: Sun, 13 Oct 2019 20:02:03 +0200 Subject: [PATCH 536/565] Space style changes. Local copy of shellcheck somehow missed these, odd. --- dnsapi/dns_miab.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index 313e4eb..7630a74 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -23,10 +23,10 @@ dns_miab_add() { _debug txtvalue "$txtvalue" #retrieve MIAB environemt vars - if ! _retrieve_miab_env; then - return 1 - fi - + if ! _retrieve_miab_env; then + return 1 + fi + #check domain and seperate into doamin and host if ! _get_root "$fulldomain"; then _err "Cannot find any part of ${fulldomain} is hosted on ${MIAB_Server}" @@ -61,9 +61,9 @@ dns_miab_rm() { _debug txtvalue "$txtvalue" #retrieve MIAB environemt vars - if ! _retrieve_miab_env; then - return 1 - fi + if ! _retrieve_miab_env; then + return 1 + fi #check domain and seperate into doamin and host if ! _get_root "$fulldomain"; then @@ -76,7 +76,7 @@ dns_miab_rm() { #Remove the challenge record _api_path="custom/${fulldomain}/txt" - _miab_rest "$txtvalue" "$_api_path" "DELETE" + _miab_rest "$txtvalue" "$_api_path" "DELETE" #check if result was good if _contains "$response" "updated DNS"; then From 9af85f5a7eedb7d3fd36a01834492e50e8c65138 Mon Sep 17 00:00:00 2001 From: Bill Gertz Date: Mon, 14 Oct 2019 00:01:25 +0200 Subject: [PATCH 537/565] Updated to use _H1 Authorization: Basic Updated to use suggested export _H1 env var to supply Authorization Basic credentials. This undocumented support for Basic Authorization, ContentType, etc. needs to be documented in DNSAPI Dev Guide. Removed two stray debugging lines. --- dnsapi/dns_miab.sh | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index 7630a74..25a8ffc 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -26,7 +26,7 @@ dns_miab_add() { if ! _retrieve_miab_env; then return 1 fi - + #check domain and seperate into doamin and host if ! _get_root "$fulldomain"; then _err "Cannot find any part of ${fulldomain} is hosted on ${MIAB_Server}" @@ -104,9 +104,6 @@ _get_root() { #get the zones hosed on MIAB server, must be a json stream _miab_rest "" "zones" "GET" - _info "_startswith test:$(_startswith "test" "t")" - _info "_endstest test:$(_endswith "test" "t")" - if ! _is_json "$response"; then _err "ERROR fetching domain list" _err "$response" @@ -176,14 +173,15 @@ _miab_rest() { _api_path="$2" _httpmethod="$3" - #encode username and password for url - _username="$(printf "%s" "$MIAB_Username" | _url_encode)" - _password="$(printf "%s" "$MIAB_Password" | _url_encode)" - _url="https://${_username}:${_password}@${MIAB_Server}/admin/dns/${_api_path}" + #encode username and password for basic authentication + _credentials="$(printf "%s" "$MIAB_Username:$MIAB_Password" | _base64)" + export _H1="Authorization: Basic $_credentials" + _url="https://${MIAB_Server}/admin/dns/${_api_path}" _debug2 _data "$_data" _debug _api_path "$_api_path" _debug2 _url "$_url" + _debug2 _credentails "$_credentials" _debug _httpmethod "$_httpmethod" if [ "$_httpmethod" = "GET" ]; then @@ -195,7 +193,7 @@ _miab_rest() { _retcode="$?" if [ "$_retcode" != "0" ]; then - _err "MAAB REST authentication failed on $_httpmethod" + _err "MIAB REST authentication failed on $_httpmethod" return 1 fi From 933d49b0b09cc886402c59e08de1651e8121d822 Mon Sep 17 00:00:00 2001 From: Bill Gertz Date: Mon, 14 Oct 2019 00:06:08 +0200 Subject: [PATCH 538/565] Style space change Extra space on empty line 27. --- dnsapi/dns_miab.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_miab.sh b/dnsapi/dns_miab.sh index 25a8ffc..23ff6ce 100644 --- a/dnsapi/dns_miab.sh +++ b/dnsapi/dns_miab.sh @@ -26,7 +26,7 @@ dns_miab_add() { if ! _retrieve_miab_env; then return 1 fi - + #check domain and seperate into doamin and host if ! _get_root "$fulldomain"; then _err "Cannot find any part of ${fulldomain} is hosted on ${MIAB_Server}" From dc5c220e8fc0d605a9c4434b421b9d33960b149c Mon Sep 17 00:00:00 2001 From: rserpent <53250916+rserpent@users.noreply.github.com> Date: Wed, 16 Oct 2019 15:12:21 +0500 Subject: [PATCH 539/565] dns_nic init --- dnsapi/dns_nic.sh | 185 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 dnsapi/dns_nic.sh diff --git a/dnsapi/dns_nic.sh b/dnsapi/dns_nic.sh new file mode 100644 index 0000000..277cc2d --- /dev/null +++ b/dnsapi/dns_nic.sh @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +#NIC_Token="sdfsdfsdfljlbjkljlkjsdfoiwjedfglgkdlfgkfgldfkg" +# +#NIC_Username="000000/NIC-D" + +#NIC_Password="xxxxxxx" + +NIC_Api="https://api.nic.ru" + +dns_nic_add() { + fulldomain="${1}" + txtvalue="${2}" + + NIC_Token="${NIC_Token:-$(_readaccountconf_mutable NIC_Token)}" + NIC_Username="${NIC_Username:-$(_readaccountconf_mutable NIC_Username)}" + NIC_Password="${NIC_Password:-$(_readaccountconf_mutable NIC_Password)}" + if [ -z "$NIC_Token" ] || [ -z "$NIC_Username" ] || [ -z "$NIC_Password" ]; then + NIC_Token="" + NIC_Username="" + NIC_Password="" + _err "You must export variables: NIC_Token, NIC_Username and NIC_Password" + return 1 + fi + + _saveaccountconf_mutable NIC_Customer "$NIC_Token" + _saveaccountconf_mutable NIC_Username "$NIC_Username" + _saveaccountconf_mutable NIC_Password "$NIC_Password" + + if ! _nic_get_authtoken "$NIC_Username" "$NIC_Password" "$NIC_Token"; then + _err "get NIC auth token failed" + 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 _service "$_service" + + _info "Adding record" + if ! _nic_rest PUT "services/$_service/zones/$_domain/records" "$_sub_domainTXT$txtvalue"; then + _err "Add TXT record error" + return 1 + fi + + if ! _nic_rest POST "services/$_service/zones/$_domain/commit" ""; then + return 1 + fi + _info "Added, OK" +} + +dns_nic_rm() { + fulldomain="${1}" + txtvalue="${2}" + + NIC_Token="${NIC_Token:-$(_readaccountconf_mutable NIC_Token)}" + NIC_Username="${NIC_Username:-$(_readaccountconf_mutable NIC_Username)}" + NIC_Password="${NIC_Password:-$(_readaccountconf_mutable NIC_Password)}" + if [ -z "$NIC_Token" ] || [ -z "$NIC_Username" ] || [ -z "$NIC_Password" ]; then + NIC_Token="" + NIC_Username="" + NIC_Password="" + _err "You must export variables: NIC_Token, NIC_Username and NIC_Password" + return 1 + fi + + if ! _nic_get_authtoken "$NIC_Username" "$NIC_Password" "$NIC_Token"; then + _err "get NIC auth token failed" + return 1 + fi + + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + _debug _service "$_service" + + if ! _nic_rest GET "services/$_service/zones/$_domain/records"; then + _err "Get records error" + return 1 + fi + + _domain_id=$(printf "%s" "$response" | grep "$_sub_domain" | grep "$txtvalue" | sed -r "s/.*"; then + error=$(printf "%s" "$response" | grep "error code" | sed -r "s/.*(.*)<\/error>/\1/g") + _err "Error: $error" + return 1 + fi + + if ! _contains "$response" "success"; then + return 1 + fi + _debug2 response "$response" + return 0 +} From e00f0b4cf1df691c4baf0293d49d380bf98b5e94 Mon Sep 17 00:00:00 2001 From: rserpent <53250916+rserpent@users.noreply.github.com> Date: Wed, 16 Oct 2019 15:31:50 +0500 Subject: [PATCH 540/565] Update dns_nic.sh --- dnsapi/dns_nic.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_nic.sh b/dnsapi/dns_nic.sh index 277cc2d..b92d2ac 100644 --- a/dnsapi/dns_nic.sh +++ b/dnsapi/dns_nic.sh @@ -113,7 +113,7 @@ _nic_get_authtoken() { export _H1="Authorization: Basic $token" export _H2="Content-Type: application/x-www-form-urlencoded" - res="$(_post "grant_type=password&username=$username&password=$password&scope=%28GET%7CPUT%7CPOST%7CDELETE%29%3A%2Fdns-master%2F.%2B" "$NIC_Api/oauth/token" "" "POST")" + res=$(_post "grant_type=password&username=$username&password=$password&scope=%28GET%7CPUT%7CPOST%7CDELETE%29%3A%2Fdns-master%2F.%2B" "$NIC_Api/oauth/token" "" "POST") if _contains "$res" "access_token"; then _auth_token=$(printf "%s" "$res" | cut -d , -f2 | tr -d "\"" | sed "s/access_token://") _info "Token received" From ffa5472b31b69cedae6e29bc10edf689176d54a0 Mon Sep 17 00:00:00 2001 From: rserpent <53250916+rserpent@users.noreply.github.com> Date: Wed, 16 Oct 2019 16:25:38 +0500 Subject: [PATCH 541/565] fix whitespaces --- dnsapi/dns_nic.sh | 48 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/dnsapi/dns_nic.sh b/dnsapi/dns_nic.sh index b92d2ac..493b05b 100644 --- a/dnsapi/dns_nic.sh +++ b/dnsapi/dns_nic.sh @@ -79,7 +79,7 @@ dns_nic_rm() { _err "Invalid domain" return 1 fi - + _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" _debug _service "$_service" @@ -129,28 +129,28 @@ _get_root() { p=1 if ! _nic_rest GET "zones"; then - return 1 + return 1 fi _all_domains=$(printf "%s" "$response" | grep "idn-name" | sed -r "s/.*idn-name=\"(.*)\" name=.*/\1/g") _debug2 _all_domains "$_all_domains" while true; do - h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) - _debug h "$h" - - if [ -z "$h" ]; then - return 1 - fi - - if _contains "$_all_domains" "^$h$"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _domain=$h - _service=$(printf "%s" "$response" | grep "$_domain" | sed -r "s/.*service=\"(.*)\".*$/\1/") - return 0 - fi - p="$i" - i=$(_math "$i" + 1) + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) + _debug h "$h" + + if [ -z "$h" ]; then + return 1 + fi + + if _contains "$_all_domains" "^$h$"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + _service=$(printf "%s" "$response" | grep "$_domain" | sed -r "s/.*service=\"(.*)\".*$/\1/") + return 0 + fi + p="$i" + i=$(_math "$i" + 1) done return 1 } @@ -165,20 +165,20 @@ _nic_rest() { export _H2="Authorization: Bearer $_auth_token" if [ "$m" != "GET" ]; then - _debug data "$data" - response=$(_post "$data" "$NIC_Api/dns-master/$ep" "" "$m") + _debug data "$data" + response=$(_post "$data" "$NIC_Api/dns-master/$ep" "" "$m") else - response=$(_get "$NIC_Api/dns-master/$ep") + response=$(_get "$NIC_Api/dns-master/$ep") fi if _contains "$response" ""; then - error=$(printf "%s" "$response" | grep "error code" | sed -r "s/.*(.*)<\/error>/\1/g") - _err "Error: $error" - return 1 + error=$(printf "%s" "$response" | grep "error code" | sed -r "s/.*(.*)<\/error>/\1/g") + _err "Error: $error" + return 1 fi if ! _contains "$response" "success"; then - return 1 + return 1 fi _debug2 response "$response" return 0 From 573c8f3b13e002cc948adfee840005cc18982098 Mon Sep 17 00:00:00 2001 From: David Robles Date: Wed, 23 Oct 2019 07:20:01 -0700 Subject: [PATCH 542/565] Use more widely supported options for the "tr" command line utility by removing the use of the character class representation option. [:space:] => "\t\r\n\v\f" --- dnsapi/dns_freedns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 81b1de5..6fac0c2 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -303,7 +303,7 @@ _freedns_domain_id() { return 1 fi - domain_id="$(echo "$htmlpage" | tr -d "\r\n" | sed 's//@/g' | tr '@' '\n' \ + domain_id="$(echo "$htmlpage" | tr -d "\t\r\n\v\f" | sed 's//@/g' | tr '@' '\n' \ | grep "$search_domain\|$search_domain(.*)" \ | sed -n 's/.*\(edit\.php?edit_domain_id=[0-9a-zA-Z]*\).*/\1/p' \ | cut -d = -f 2)" @@ -349,7 +349,7 @@ _freedns_data_id() { return 1 fi - data_id="$(echo "$htmlpage" | tr -d "\r\n" | sed 's//@/g' | tr '@' '\n' \ + data_id="$(echo "$htmlpage" | tr -d "\t\r\n\v\f" | sed 's//@/g' | tr '@' '\n' \ | grep "$record_type" \ | grep "$search_domain" \ | sed -n 's/.*\(edit\.php?data_id=[0-9a-zA-Z]*\).*/\1/p' \ From 18ad01533b3b5d0cf51f9e72464940e7a080d880 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 24 Oct 2019 09:19:18 +0800 Subject: [PATCH 543/565] add space. fix https://github.com/Neilpang/acme.sh/pull/2553 --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 6fac0c2..32d240f 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -303,7 +303,7 @@ _freedns_domain_id() { return 1 fi - domain_id="$(echo "$htmlpage" | tr -d "\t\r\n\v\f" | sed 's//@/g' | tr '@' '\n' \ + domain_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's//@/g' | tr '@' '\n' \ | grep "$search_domain\|$search_domain(.*)" \ | sed -n 's/.*\(edit\.php?edit_domain_id=[0-9a-zA-Z]*\).*/\1/p' \ | cut -d = -f 2)" From 1d1f61613c539eaa0eddf8b10e8a1dea47824b8a Mon Sep 17 00:00:00 2001 From: Rolph Haspers Date: Fri, 25 Oct 2019 09:25:29 +0200 Subject: [PATCH 544/565] Check for root domain via API --- dnsapi/dns_leaseweb.sh | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_leaseweb.sh b/dnsapi/dns_leaseweb.sh index 976ad5a..6a75ef3 100644 --- a/dnsapi/dns_leaseweb.sh +++ b/dnsapi/dns_leaseweb.sh @@ -88,14 +88,24 @@ _get_root() { i=$(_math "$i" - 1) while true; do - h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) + h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then - return 1 + return 1 #not valid domain + fi + + #Check API if domain exists + if _lsw_api "GET" "$h"; then + if [ "$_code" = "200"]; then + _domain="$h" + return 0 + fi + fi + i=$(_math "$i" - 1) + if (( $i < 1)); then + return 1 #not found fi - _domain="$h" - return 0 done - _debug "$domain not found" + return 1 } @@ -109,6 +119,14 @@ _lsw_api() { export _H2="Content-Type: application/json" export _H1="X-Lsw-Auth: ${LSW_Key}" + if [ "$cmd" = "GET" ]; then + response="$(_get "$LSW_API/$domain")" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + _debug "http response code $_code" + _debug response "$response" + return 0 + fi + if [ "$cmd" = "POST" ]; then data="{\"name\": \"$fulldomain.\",\"type\": \"TXT\",\"content\": [\"$txtvalue\"],\"ttl\": 60}" response="$(_post "$data" "$LSW_API/$domain/resourceRecordSets" "$data" "POST")" From e10f447b5b6b56c8742136f1c288dce32c392f41 Mon Sep 17 00:00:00 2001 From: Rolph Haspers Date: Fri, 25 Oct 2019 11:42:15 +0200 Subject: [PATCH 545/565] Fixed some bugs, tested and working --- dnsapi/dns_leaseweb.sh | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_leaseweb.sh b/dnsapi/dns_leaseweb.sh index 6a75ef3..cb49ce7 100644 --- a/dnsapi/dns_leaseweb.sh +++ b/dnsapi/dns_leaseweb.sh @@ -83,19 +83,20 @@ dns_leaseweb_rm() { # returns # _domain=domain.com _get_root() { - domain=$1 - i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" + rdomain=$1 + i="$(echo "$rdomain" | tr '.' ' ' | wc -w)" i=$(_math "$i" - 1) while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(printf "%s" "$rdomain" | cut -d . -f $i-100) + _debug h "$h" if [ -z "$h" ]; then return 1 #not valid domain fi #Check API if domain exists if _lsw_api "GET" "$h"; then - if [ "$_code" = "200"]; then + if [ "$_code" = "200" ]; then _domain="$h" return 0 fi @@ -111,16 +112,16 @@ _get_root() { _lsw_api() { cmd=$1 - domain=$2 - fulldomain=$3 - txtvalue=$4 + data=$2 + fd=$3 + tvalue=$4 # Construct the HTTP Authorization header export _H2="Content-Type: application/json" export _H1="X-Lsw-Auth: ${LSW_Key}" if [ "$cmd" = "GET" ]; then - response="$(_get "$LSW_API/$domain")" + response="$(_get "$LSW_API/$d")" _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" _debug "http response code $_code" _debug response "$response" @@ -128,8 +129,8 @@ _lsw_api() { fi if [ "$cmd" = "POST" ]; then - data="{\"name\": \"$fulldomain.\",\"type\": \"TXT\",\"content\": [\"$txtvalue\"],\"ttl\": 60}" - response="$(_post "$data" "$LSW_API/$domain/resourceRecordSets" "$data" "POST")" + data="{\"name\": \"$fd.\",\"type\": \"TXT\",\"content\": [\"$tvalue\"],\"ttl\": 60}" + response="$(_post "$data" "$LSW_API/$d/resourceRecordSets" "$data" "POST")" _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" _debug "http response code $_code" _debug response "$response" @@ -137,7 +138,7 @@ _lsw_api() { fi if [ "$cmd" = "DELETE" ]; then - response="$(_post "" "$LSW_API/$domain/resourceRecordSets/$fulldomain/TXT" "" "DELETE")" + response="$(_post "" "$LSW_API/$d/resourceRecordSets/$fd/TXT" "" "DELETE")" _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" _debug "http response code $_code" _debug response "$response" From 14f6f9ec94a5d0e68f495fe485610db82b6eefc0 Mon Sep 17 00:00:00 2001 From: Rolph Haspers Date: Fri, 25 Oct 2019 11:56:27 +0200 Subject: [PATCH 546/565] Fixed wrong assignement of var --- dnsapi/dns_leaseweb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_leaseweb.sh b/dnsapi/dns_leaseweb.sh index cb49ce7..31446be 100644 --- a/dnsapi/dns_leaseweb.sh +++ b/dnsapi/dns_leaseweb.sh @@ -112,7 +112,7 @@ _get_root() { _lsw_api() { cmd=$1 - data=$2 + d=$2 fd=$3 tvalue=$4 From 6d62ae226a82c8c42129a1bae560495790e092d4 Mon Sep 17 00:00:00 2001 From: Rolph Haspers Date: Fri, 25 Oct 2019 12:14:53 +0200 Subject: [PATCH 547/565] Small fix --- dnsapi/dns_leaseweb.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_leaseweb.sh b/dnsapi/dns_leaseweb.sh index 31446be..72f53b2 100644 --- a/dnsapi/dns_leaseweb.sh +++ b/dnsapi/dns_leaseweb.sh @@ -102,8 +102,8 @@ _get_root() { fi fi i=$(_math "$i" - 1) - if (( $i < 1)); then - return 1 #not found + if (( i < 2 )); then + return 1 #not found, no need to check _acme-challenge.sub.domain in leaseweb api. fi done From 58642286c95fa42d3e78754a9f0253fa70f529bb Mon Sep 17 00:00:00 2001 From: Rolph Haspers Date: Fri, 25 Oct 2019 13:22:19 +0200 Subject: [PATCH 548/565] Fix for SC2039/SC2086 --- dnsapi/dns_leaseweb.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_leaseweb.sh b/dnsapi/dns_leaseweb.sh index 72f53b2..0fd8dcc 100644 --- a/dnsapi/dns_leaseweb.sh +++ b/dnsapi/dns_leaseweb.sh @@ -88,7 +88,7 @@ _get_root() { i=$(_math "$i" - 1) while true; do - h=$(printf "%s" "$rdomain" | cut -d . -f $i-100) + h=$(printf "%s" "$rdomain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then return 1 #not valid domain @@ -102,7 +102,7 @@ _get_root() { fi fi i=$(_math "$i" - 1) - if (( i < 2 )); then + if $(( i < 2 )); then return 1 #not found, no need to check _acme-challenge.sub.domain in leaseweb api. fi done From e48daffad99af7cd09b0c5860b439de2895541ca Mon Sep 17 00:00:00 2001 From: Rolph Haspers Date: Fri, 25 Oct 2019 13:46:10 +0200 Subject: [PATCH 549/565] Fixed error --- dnsapi/dns_leaseweb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_leaseweb.sh b/dnsapi/dns_leaseweb.sh index 0fd8dcc..a1d9e74 100644 --- a/dnsapi/dns_leaseweb.sh +++ b/dnsapi/dns_leaseweb.sh @@ -102,7 +102,7 @@ _get_root() { fi fi i=$(_math "$i" - 1) - if $(( i < 2 )); then + if [ "$i" -lt 2 ]; then return 1 #not found, no need to check _acme-challenge.sub.domain in leaseweb api. fi done From d04c6dd3ac03ff6031cbb0d8a2d86645fe9adb20 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 25 Oct 2019 22:31:36 +0800 Subject: [PATCH 550/565] fix https://github.com/Neilpang/acme.sh/issues/2557 and https://github.com/Neilpang/acme.sh/issues/2544 --- acme.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e060e33..37ce15a 100755 --- a/acme.sh +++ b/acme.sh @@ -4047,7 +4047,18 @@ $_authorizations_map" fi if [ "$ACME_VERSION" = "2" ]; then - response="$(echo "$_authorizations_map" | grep "^$(_idn "$d")," | sed "s/$d,//")" + _idn_d="$(_idn "$d")" + _candindates="$(echo "$_authorizations_map" | grep "^$_idn_d,")" + _debug2 _candindates "$_candindates" + if [ "$(echo "$_candindates" | wc -l)" -gt 1 ]; then + for _can in $_candindates; do + if _startswith "$(echo "$_can" | tr '.' '|')" "$(echo "$_idn_d" | tr '.' '|'),"; then + _candindates="$_can" + break + fi + done + fi + response="$(echo "$_candindates" | sed "s/$_idn_d,//")" _debug2 "response" "$response" if [ -z "$response" ]; then _err "get to authz error." From 2a2877231268cce11ccc624c007ecf3fc2c8dea6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 25 Oct 2019 22:34:33 +0800 Subject: [PATCH 551/565] fix https://github.com/Neilpang/acme.sh/pull/2553#issuecomment-546173277 --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 32d240f..6a0b58a 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -349,7 +349,7 @@ _freedns_data_id() { return 1 fi - data_id="$(echo "$htmlpage" | tr -d "\t\r\n\v\f" | sed 's//@/g' | tr '@' '\n' \ + data_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's//@/g' | tr '@' '\n' \ | grep "$record_type" \ | grep "$search_domain" \ | sed -n 's/.*\(edit\.php?data_id=[0-9a-zA-Z]*\).*/\1/p' \ From df3575217acc5c50d45145672a3008cdb5895cdc Mon Sep 17 00:00:00 2001 From: scottkof Date: Fri, 25 Oct 2019 12:05:15 -0700 Subject: [PATCH 552/565] Avoid API throttling errors in AWS DNS plugin --- dnsapi/dns_aws.sh | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 246f477..54b1bb3 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -6,6 +6,8 @@ #AWS_SECRET_ACCESS_KEY="xxxxxxx" #This is the Amazon Route53 api wrapper for acme.sh +#All `sleep` commands are included to avoid Route53 throttling, see +#https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests AWS_HOST="route53.amazonaws.com" AWS_URL="https://$AWS_HOST" @@ -43,6 +45,7 @@ dns_aws_add() { _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" + sleep 1 return 1 fi _debug _domain_id "$_domain_id" @@ -51,6 +54,7 @@ dns_aws_add() { _info "Getting existing records for $fulldomain" if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then + sleep 1 return 1 fi @@ -63,6 +67,7 @@ dns_aws_add() { if [ "$_resource_record" ] && _contains "$response" "$txtvalue"; then _info "The TXT record already exists. Skipping." + sleep 1 return 0 fi @@ -72,9 +77,10 @@ dns_aws_add() { if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then _info "TXT record updated successfully." + sleep 1 return 0 fi - + sleep 1 return 1 } @@ -93,6 +99,7 @@ dns_aws_rm() { _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" + sleep 1 return 1 fi _debug _domain_id "$_domain_id" @@ -101,6 +108,7 @@ dns_aws_rm() { _info "Getting existing records for $fulldomain" if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then + sleep 1 return 1 fi @@ -109,6 +117,7 @@ dns_aws_rm() { _debug "_resource_record" "$_resource_record" else _debug "no records exist, skip" + sleep 1 return 0 fi @@ -116,9 +125,10 @@ dns_aws_rm() { if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then _info "TXT record deleted successfully." + sleep 1 return 0 fi - + sleep 1 return 1 } From bba5376a3693dc19186edd6ffc42277d45dfa2fb Mon Sep 17 00:00:00 2001 From: "John L. Villalovos" Date: Tue, 15 Oct 2019 14:37:38 -0700 Subject: [PATCH 553/565] Improve debug capabilities when using bash When calling the _debug3() function will print the filename, function name, and line number when running under bash --- acme.sh | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 041b5b4..46df2ed 100755 --- a/acme.sh +++ b/acme.sh @@ -265,6 +265,37 @@ _usage() { printf "\n" >&2 } +__debug_bash_helper() { + # At this point only do for --debug 3 + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -lt "$DEBUG_LEVEL_3" ]; then + echo "" + return + fi + # Return extra debug info when running with bash, otherwise return empty + # string. + if [ -z "${BASH_VERSION}" ]; then + echo "" + return + fi + # We are a bash shell at this point, return the filename, function name, and + # line number as a string + _dbh_saveIFS=$IFS + IFS=" " + # Must use eval or syntax error happens under dash + # Use 'caller 1' as we want one level up the stack as we should be called + # by one of the _debug* functions + eval "_dbh_called=($(caller 1))" + IFS=$_dbh_saveIFS + _dbh_file=${_dbh_called[2]} + if [ -n "${_script_home}" ]; then + # Trim off the _script_home directory name + _dbh_file=${_dbh_file#$_script_home/} + fi + _dbh_function=${_dbh_called[1]} + _dbh_lineno=${_dbh_called[0]} + printf "%-40s " "$_dbh_file:${_dbh_function}:${_dbh_lineno}" +} + _debug() { if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then _log "$@" @@ -273,7 +304,8 @@ _debug() { _syslog "$SYSLOG_DEBUG" "$@" fi if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then - _printargs "$@" >&2 + _bash_debug=$(__debug_bash_helper) + _printargs "${_bash_debug}$@" >&2 fi } @@ -306,7 +338,8 @@ _debug2() { _syslog "$SYSLOG_DEBUG" "$@" fi if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then - _printargs "$@" >&2 + _bash_debug=$(__debug_bash_helper) + _printargs "${_bash_debug}$@" >&2 fi } @@ -338,7 +371,8 @@ _debug3() { _syslog "$SYSLOG_DEBUG" "$@" fi if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then - _printargs "$@" >&2 + _bash_debug=$(__debug_bash_helper) + _printargs "${_bash_debug}$@" >&2 fi } From 671edc33e173b0318972d7eb4fd50d03fbde85cd Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 27 Oct 2019 11:43:40 +0800 Subject: [PATCH 554/565] fix background color --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 37ce15a..07dc63d 100755 --- a/acme.sh +++ b/acme.sh @@ -153,7 +153,7 @@ fi __green() { if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then - printf '\033[1;31;32m%b\033[0m' "$1" + printf '\33[1;32m%b\33[0m' "$1" return fi printf -- "%b" "$1" @@ -161,7 +161,7 @@ __green() { __red() { if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then - printf '\033[1;31;40m%b\033[0m' "$1" + printf '\33[1;31m%b\33[0m' "$1" return fi printf -- "%b" "$1" From 582c77805c837962129ea5372a664658739a13e1 Mon Sep 17 00:00:00 2001 From: peterkelm Date: Sun, 27 Oct 2019 13:13:22 +0100 Subject: [PATCH 555/565] variomedia dns api initial commit for the variomedia dns api implementation --- dnsapi/dns_variomedia.sh | 166 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 dnsapi/dns_variomedia.sh diff --git a/dnsapi/dns_variomedia.sh b/dnsapi/dns_variomedia.sh new file mode 100644 index 0000000..56f1bf9 --- /dev/null +++ b/dnsapi/dns_variomedia.sh @@ -0,0 +1,166 @@ +#!/usr/bin/env sh + +# +#VARIOMEDIA_API_TOKEN=000011112222333344445555666677778888 + +VARIOMEDIA_API="https://api.variomedia.de" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_variomedia_add() { + fulldomain=$1 + txtvalue=$2 + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + VARIOMEDIA_API_TOKEN="${VARIOMEDIA_API_TOKEN:-$(_readaccountconf_mutable VARIOMEDIA_API_TOKEN)}" + if test -z "$VARIOMEDIA_API_TOKEN"; then + VARIOMEDIA_API_TOKEN="" + _err 'VARIOMEDIA_API_TOKEN was not exported' + return 1 + fi + + _saveaccountconf_mutable VARIOMEDIA_API_TOKEN "$VARIOMEDIA_API_TOKEN" + + _debug 'First detect the root zone' + if ! _get_root "$fulldomain"; then + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + +# _debug 'Getting txt records' +# _variomedia_rest GET "/dns-records?filter[domain]=$_domain" + +# if printf "%s\n" "$response" | grep "\"record_type\": \"A\", \"fqdn\": \"$fulldomain\"" >/dev/null; then +# _err 'Error' +# return 1 +# fi + + if ! _variomedia_rest POST "dns-records" "{\"data\": {\"type\": \"dns-record\", \"attributes\": {\"record_type\": \"TXT\", \"name\": \"$_sub_domain\", \"domain\": \"$_domain\", \"data\": \"$txtvalue\", \"ttl\":300}}}"; then + _err "$response" + return 1 + fi + + _debug2 _response "$response" + return 0 +} + +#fulldomain txtvalue +dns_variomedia_rm() { + fulldomain=$1 + txtvalue=$2 + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + VARIOMEDIA_API_TOKEN="${VARIOMEDIA_API_TOKEN:-$(_readaccountconf_mutable VARIOMEDIA_API_TOKEN)}" + if test -z "$VARIOMEDIA_API_TOKEN"; then + VARIOMEDIA_API_TOKEN="" + _err 'VARIOMEDIA_API_TOKEN was not exported' + return 1 + fi + + _saveaccountconf_mutable VARIOMEDIA_API_TOKEN "$VARIOMEDIA_API_TOKEN" + + _debug 'First detect the root zone' + if ! _get_root "$fulldomain"; then + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug 'Getting txt records' + + if ! _variomedia_rest GET "dns-records?filter[domain]=$_domain"; then + _err 'Error' + return 1 + fi + + _record_id="$(echo $response | cut -d '[' -f2 | cut -d']' -f1 | sed 's/},[ \t]*{/\},§\{/g' | tr § '\n' | grep $_sub_domain | sed 's/^{//;s/}[,]?$//' | tr , '\n' | tr -d '\"' | grep ^id | cut -d : -f2 | tr -d ' ')" + _debug _record_id "$_record_id" + if [ "$_record_id" ]; then + _info "Successfully retrieved the record id for ACME challenge." + else + _info "Empty record id, it seems no such record." + return 0 + fi + + if ! _variomedia_rest DELETE "/dns-records/$_record_id"; then + _err "$response" + return 1 + fi + + _debug2 _response "$response" + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + fulldomain=$1 + i=1 + while true; do + h=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + return 1 + fi + + if ! _variomedia_rest GET "domains/$h"; then + return 1 + fi + + if _startswith "$response" "\{\"data\":"; then + if _contains "$response" "\"id\": \"$h\""; then + _sub_domain="$(echo "$fulldomain" | sed "s/\\.$h\$//")" + _domain=$h + return 0 +# else +# _err 'Invalid domain' +# return 1 + fi +# else +# _err "$response" +# return 1 + fi + i=$(_math "$i" + 1) + done + + _debug "root domain not found" + + return 1 +} + +_variomedia_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + +# api_key_trimmed=$(echo $VARIOMEDIA_API_TOKEN | tr -d '"') + +# export _H1="Api-Key: $api_key_trimmed" + + export _H1="Authorization: token $VARIOMEDIA_API_TOKEN" + export _H2="Content-Type: application/vnd.api+json" + export _H3="Accept: application/vnd.variomedia.v1+json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$VARIOMEDIA_API/$ep" "" "$m")" + else + response="$(_get "$VARIOMEDIA_API/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "Error $ep" + return 1 + fi + + _debug2 response "$response" + return 0 +} From 1271f97b669ee66727293beea3f2a39da2899e04 Mon Sep 17 00:00:00 2001 From: peterkelm Date: Sun, 27 Oct 2019 16:52:51 +0100 Subject: [PATCH 556/565] fixed dns_variomedia_rm for wildcard certs fixed dns_variomedia_rm to respect the txtvalue supplied as function parameter --- dnsapi/dns_variomedia.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_variomedia.sh b/dnsapi/dns_variomedia.sh index 56f1bf9..2e822a0 100644 --- a/dnsapi/dns_variomedia.sh +++ b/dnsapi/dns_variomedia.sh @@ -77,7 +77,7 @@ dns_variomedia_rm() { return 1 fi - _record_id="$(echo $response | cut -d '[' -f2 | cut -d']' -f1 | sed 's/},[ \t]*{/\},§\{/g' | tr § '\n' | grep $_sub_domain | sed 's/^{//;s/}[,]?$//' | tr , '\n' | tr -d '\"' | grep ^id | cut -d : -f2 | tr -d ' ')" + _record_id="$(echo $response | cut -d '[' -f2 | cut -d']' -f1 | sed 's/},[ \t]*{/\},§\{/g' | tr § '\n' | grep $_sub_domain | grep $txtvalue | sed 's/^{//;s/}[,]?$//' | tr , '\n' | tr -d '\"' | grep ^id | cut -d : -f2 | tr -d ' ')" _debug _record_id "$_record_id" if [ "$_record_id" ]; then _info "Successfully retrieved the record id for ACME challenge." From c1b089d1c3adb314daf29a084c3bf13042e72c7f Mon Sep 17 00:00:00 2001 From: peterkelm Date: Sun, 27 Oct 2019 16:58:36 +0100 Subject: [PATCH 557/565] unused code removed --- dnsapi/dns_variomedia.sh | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/dnsapi/dns_variomedia.sh b/dnsapi/dns_variomedia.sh index 2e822a0..8588d7c 100644 --- a/dnsapi/dns_variomedia.sh +++ b/dnsapi/dns_variomedia.sh @@ -30,14 +30,6 @@ dns_variomedia_add() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" -# _debug 'Getting txt records' -# _variomedia_rest GET "/dns-records?filter[domain]=$_domain" - -# if printf "%s\n" "$response" | grep "\"record_type\": \"A\", \"fqdn\": \"$fulldomain\"" >/dev/null; then -# _err 'Error' -# return 1 -# fi - if ! _variomedia_rest POST "dns-records" "{\"data\": {\"type\": \"dns-record\", \"attributes\": {\"record_type\": \"TXT\", \"name\": \"$_sub_domain\", \"domain\": \"$_domain\", \"data\": \"$txtvalue\", \"ttl\":300}}}"; then _err "$response" return 1 @@ -119,13 +111,7 @@ _get_root() { _sub_domain="$(echo "$fulldomain" | sed "s/\\.$h\$//")" _domain=$h return 0 -# else -# _err 'Invalid domain' -# return 1 fi -# else -# _err "$response" -# return 1 fi i=$(_math "$i" + 1) done @@ -141,10 +127,6 @@ _variomedia_rest() { data="$3" _debug "$ep" -# api_key_trimmed=$(echo $VARIOMEDIA_API_TOKEN | tr -d '"') - -# export _H1="Api-Key: $api_key_trimmed" - export _H1="Authorization: token $VARIOMEDIA_API_TOKEN" export _H2="Content-Type: application/vnd.api+json" export _H3="Accept: application/vnd.variomedia.v1+json" From a22d3b239070ddc573a283bf2a709e68a12d2085 Mon Sep 17 00:00:00 2001 From: scottkof Date: Mon, 28 Oct 2019 06:32:08 -0700 Subject: [PATCH 558/565] Switch from `sleep` to `_sleep` --- dnsapi/dns_aws.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 54b1bb3..6db8766 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -6,7 +6,7 @@ #AWS_SECRET_ACCESS_KEY="xxxxxxx" #This is the Amazon Route53 api wrapper for acme.sh -#All `sleep` commands are included to avoid Route53 throttling, see +#All `_sleep` commands are included to avoid Route53 throttling, see #https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests AWS_HOST="route53.amazonaws.com" @@ -45,7 +45,7 @@ dns_aws_add() { _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" - sleep 1 + _sleep 1 return 1 fi _debug _domain_id "$_domain_id" @@ -54,7 +54,7 @@ dns_aws_add() { _info "Getting existing records for $fulldomain" if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then - sleep 1 + _sleep 1 return 1 fi @@ -67,7 +67,7 @@ dns_aws_add() { if [ "$_resource_record" ] && _contains "$response" "$txtvalue"; then _info "The TXT record already exists. Skipping." - sleep 1 + _sleep 1 return 0 fi @@ -77,10 +77,10 @@ dns_aws_add() { if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then _info "TXT record updated successfully." - sleep 1 + _sleep 1 return 0 fi - sleep 1 + _sleep 1 return 1 } @@ -99,7 +99,7 @@ dns_aws_rm() { _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" - sleep 1 + _sleep 1 return 1 fi _debug _domain_id "$_domain_id" @@ -108,7 +108,7 @@ dns_aws_rm() { _info "Getting existing records for $fulldomain" if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then - sleep 1 + _sleep 1 return 1 fi @@ -117,7 +117,7 @@ dns_aws_rm() { _debug "_resource_record" "$_resource_record" else _debug "no records exist, skip" - sleep 1 + _sleep 1 return 0 fi @@ -125,10 +125,10 @@ dns_aws_rm() { if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then _info "TXT record deleted successfully." - sleep 1 + _sleep 1 return 0 fi - sleep 1 + _sleep 1 return 1 } From dca6a4bbd57eed4b87f24cb7f1644fb5a51c2327 Mon Sep 17 00:00:00 2001 From: peterkelm Date: Wed, 30 Oct 2019 20:51:16 +0100 Subject: [PATCH 559/565] minor formatting changes --- dnsapi/dns_variomedia.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_variomedia.sh b/dnsapi/dns_variomedia.sh index 8588d7c..ecc9ea4 100644 --- a/dnsapi/dns_variomedia.sh +++ b/dnsapi/dns_variomedia.sh @@ -5,9 +5,9 @@ VARIOMEDIA_API="https://api.variomedia.de" -######## Public functions ##################### +######## Public functions ##################### -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_variomedia_add() { fulldomain=$1 txtvalue=$2 @@ -69,7 +69,7 @@ dns_variomedia_rm() { return 1 fi - _record_id="$(echo $response | cut -d '[' -f2 | cut -d']' -f1 | sed 's/},[ \t]*{/\},§\{/g' | tr § '\n' | grep $_sub_domain | grep $txtvalue | sed 's/^{//;s/}[,]?$//' | tr , '\n' | tr -d '\"' | grep ^id | cut -d : -f2 | tr -d ' ')" + _record_id="$(echo $response | cut -d '[' -f2 | cut -d']' -f1 | sed 's/},[ \t]*{/\},§\{/g' | tr § '\n' | grep "$_sub_domain" | grep "$txtvalue" | sed 's/^{//;s/}[,]?$//' | tr , '\n' | tr -d '\"' | grep ^id | cut -d : -f2 | tr -d ' ')" _debug _record_id "$_record_id" if [ "$_record_id" ]; then _info "Successfully retrieved the record id for ACME challenge." @@ -87,7 +87,7 @@ dns_variomedia_rm() { return 0 } -#################### Private functions below ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www @@ -117,7 +117,6 @@ _get_root() { done _debug "root domain not found" - return 1 } From bec26ce754fb575a6969c917cd8fd5fa212a800e Mon Sep 17 00:00:00 2001 From: peterkelm Date: Thu, 31 Oct 2019 09:03:35 +0100 Subject: [PATCH 560/565] Shellcheck'd --- dnsapi/dns_variomedia.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_variomedia.sh b/dnsapi/dns_variomedia.sh index ecc9ea4..729cda5 100644 --- a/dnsapi/dns_variomedia.sh +++ b/dnsapi/dns_variomedia.sh @@ -69,7 +69,7 @@ dns_variomedia_rm() { return 1 fi - _record_id="$(echo $response | cut -d '[' -f2 | cut -d']' -f1 | sed 's/},[ \t]*{/\},§\{/g' | tr § '\n' | grep "$_sub_domain" | grep "$txtvalue" | sed 's/^{//;s/}[,]?$//' | tr , '\n' | tr -d '\"' | grep ^id | cut -d : -f2 | tr -d ' ')" + _record_id="$(echo "$response" | cut -d '[' -f2 | cut -d']' -f1 | sed 's/},[ \t]*{/\},§\{/g' | tr § '\n' | grep "$_sub_domain" | grep "$txtvalue" | sed 's/^{//;s/}[,]?$//' | tr , '\n' | tr -d '\"' | grep ^id | cut -d : -f2 | tr -d ' ')" _debug _record_id "$_record_id" if [ "$_record_id" ]; then _info "Successfully retrieved the record id for ACME challenge." From fee9baca895cecf5cb7a6d94791b655f09c73684 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Fri, 1 Nov 2019 17:59:40 +0100 Subject: [PATCH 561/565] Add openssh package * `acme.sh`'s `ssh.sh` is probably one of the hooks that's most versatile * By default, it's not installed on `alpine` docker images and therefore is lacking in the `acme.sh` docker image * This change adds the `openssh` package and therefore the `ssh` and associated commands --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index a6e3799..02dd503 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,7 @@ FROM alpine:3.10 RUN apk update -f \ && apk --no-cache add -f \ openssl \ + openssh \ coreutils \ bind-tools \ curl \ From 5698bec6213d8c1ffa8c3c30b1587c8f982638c8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Nov 2019 09:48:41 +0800 Subject: [PATCH 562/565] fix https://github.com/Neilpang/acme.sh/issues/2566 --- acme.sh | 2 +- notify/dingtalk.sh | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 notify/dingtalk.sh diff --git a/acme.sh b/acme.sh index 07dc63d..7860433 100755 --- a/acme.sh +++ b/acme.sh @@ -6070,7 +6070,7 @@ _send_notify() { _set_notify_hook() { _nhooks="$1" - _test_subject="Hello, this is notification from $PROJECT_NAME" + _test_subject="Hello, this is a notification from $PROJECT_NAME" _test_content="If you receive this message, your notification works." _send_notify "$_test_subject" "$_test_content" "$_nhooks" 0 diff --git a/notify/dingtalk.sh b/notify/dingtalk.sh new file mode 100644 index 0000000..7d354da --- /dev/null +++ b/notify/dingtalk.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env sh + +#Support dingtalk webhooks api + +#DINGTALK_WEBHOOK="xxxx" + +#optional +#DINGTALK_KEYWORD="yyyy" + +#DINGTALK_SIGNING_KEY="SEC08ffdbd403cbc3fc8a65xxxxxxxxxxxxxxxxxxxx" + +# subject content statusCode +dingtalk_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + DINGTALK_WEBHOOK="${DINGTALK_WEBHOOK:-$(_readaccountconf_mutable DINGTALK_WEBHOOK)}" + if [ -z "$DINGTALK_WEBHOOK" ]; then + DINGTALK_WEBHOOK="" + _err "You didn't specify a dingtalk webhooks DINGTALK_WEBHOOK yet." + _err "You can get yours from https://dingtalk.com" + return 1 + fi + _saveaccountconf_mutable DINGTALK_WEBHOOK "$DINGTALK_WEBHOOK" + + DINGTALK_KEYWORD="${DINGTALK_KEYWORD:-$(_readaccountconf_mutable DINGTALK_KEYWORD)}" + if [ "$DINGTALK_KEYWORD" ]; then + _saveaccountconf_mutable DINGTALK_KEYWORD "$DINGTALK_KEYWORD" + fi + +# DINGTALK_SIGNING_KEY="${DINGTALK_SIGNING_KEY:-$(_readaccountconf_mutable DINGTALK_SIGNING_KEY)}" +# if [ -z "$DINGTALK_SIGNING_KEY" ]; then +# DINGTALK_SIGNING_KEY="value1" +# _info "The DINGTALK_SIGNING_KEY is not set, so use the default value1 as key." +# elif ! _hasfield "$_IFTTT_AVAIL_MSG_KEYS" "$DINGTALK_SIGNING_KEY"; then +# _err "The DINGTALK_SIGNING_KEY \"$DINGTALK_SIGNING_KEY\" is not available, should be one of $_IFTTT_AVAIL_MSG_KEYS" +# DINGTALK_SIGNING_KEY="" +# return 1 +# else +# _saveaccountconf_mutable DINGTALK_SIGNING_KEY "$DINGTALK_SIGNING_KEY" +# fi + +# if [ "$DINGTALK_SIGNING_KEY" = "$IFTTT_CONTENT_KEY" ]; then +# DINGTALK_SIGNING_KEY="" +# IFTTT_CONTENT_KEY="" +# _err "The DINGTALK_SIGNING_KEY must not be same as IFTTT_CONTENT_KEY." +# return 1 +# fi + + _content=$(echo "$_content" | _json_encode) + _subject=$(echo "$_subject" | _json_encode) + _data="{\"msgtype\": \"text\", \"text\": {\"content\": \"[$DINGTALK_KEYWORD]\n$_subject\n$_content\"}}" + + response="$(_post "$_data" "$DINGTALK_WEBHOOK" "" "POST" "application/json")" + + if [ "$?" = "0" ] && _contains "$response" "errmsg\":\"ok"; then + _info "dingtalk webhooks event fired success." + return 0 + fi + + _err "dingtalk webhooks event fired error." + _err "$response" + return 1 +} + From 05acf28e0ddb47b5eab3a3c32ed69f7813237736 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sat, 2 Nov 2019 07:10:50 +0100 Subject: [PATCH 563/565] Update Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 02dd503..5112bf0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM alpine:3.10 RUN apk update -f \ && apk --no-cache add -f \ openssl \ - openssh \ + openssh-client \ coreutils \ bind-tools \ curl \ From 35b34c43ed26ec2ad08ff004823f5b408e6a3401 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Nov 2019 19:44:43 +0800 Subject: [PATCH 564/565] fix format --- notify/dingtalk.sh | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/notify/dingtalk.sh b/notify/dingtalk.sh index 7d354da..c547da6 100644 --- a/notify/dingtalk.sh +++ b/notify/dingtalk.sh @@ -32,24 +32,24 @@ dingtalk_send() { _saveaccountconf_mutable DINGTALK_KEYWORD "$DINGTALK_KEYWORD" fi -# DINGTALK_SIGNING_KEY="${DINGTALK_SIGNING_KEY:-$(_readaccountconf_mutable DINGTALK_SIGNING_KEY)}" -# if [ -z "$DINGTALK_SIGNING_KEY" ]; then -# DINGTALK_SIGNING_KEY="value1" -# _info "The DINGTALK_SIGNING_KEY is not set, so use the default value1 as key." -# elif ! _hasfield "$_IFTTT_AVAIL_MSG_KEYS" "$DINGTALK_SIGNING_KEY"; then -# _err "The DINGTALK_SIGNING_KEY \"$DINGTALK_SIGNING_KEY\" is not available, should be one of $_IFTTT_AVAIL_MSG_KEYS" -# DINGTALK_SIGNING_KEY="" -# return 1 -# else -# _saveaccountconf_mutable DINGTALK_SIGNING_KEY "$DINGTALK_SIGNING_KEY" -# fi + # DINGTALK_SIGNING_KEY="${DINGTALK_SIGNING_KEY:-$(_readaccountconf_mutable DINGTALK_SIGNING_KEY)}" + # if [ -z "$DINGTALK_SIGNING_KEY" ]; then + # DINGTALK_SIGNING_KEY="value1" + # _info "The DINGTALK_SIGNING_KEY is not set, so use the default value1 as key." + # elif ! _hasfield "$_IFTTT_AVAIL_MSG_KEYS" "$DINGTALK_SIGNING_KEY"; then + # _err "The DINGTALK_SIGNING_KEY \"$DINGTALK_SIGNING_KEY\" is not available, should be one of $_IFTTT_AVAIL_MSG_KEYS" + # DINGTALK_SIGNING_KEY="" + # return 1 + # else + # _saveaccountconf_mutable DINGTALK_SIGNING_KEY "$DINGTALK_SIGNING_KEY" + # fi -# if [ "$DINGTALK_SIGNING_KEY" = "$IFTTT_CONTENT_KEY" ]; then -# DINGTALK_SIGNING_KEY="" -# IFTTT_CONTENT_KEY="" -# _err "The DINGTALK_SIGNING_KEY must not be same as IFTTT_CONTENT_KEY." -# return 1 -# fi + # if [ "$DINGTALK_SIGNING_KEY" = "$IFTTT_CONTENT_KEY" ]; then + # DINGTALK_SIGNING_KEY="" + # IFTTT_CONTENT_KEY="" + # _err "The DINGTALK_SIGNING_KEY must not be same as IFTTT_CONTENT_KEY." + # return 1 + # fi _content=$(echo "$_content" | _json_encode) _subject=$(echo "$_subject" | _json_encode) @@ -66,4 +66,3 @@ dingtalk_send() { _err "$response" return 1 } - From 6eaf2d67b7588f23f1870c8813d3d6d391820b89 Mon Sep 17 00:00:00 2001 From: Kukushkin Alexander Date: Fri, 16 Nov 2018 08:30:44 +0300 Subject: [PATCH 565/565] Fix Vscale --- dnsapi/dns_vscale.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_vscale.sh b/dnsapi/dns_vscale.sh index e50b7d8..d717d6e 100755 --- a/dnsapi/dns_vscale.sh +++ b/dnsapi/dns_vscale.sh @@ -102,7 +102,7 @@ _get_root() { return 1 fi - hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")" + hostedzone="$(echo "$response" | tr "{" "\n" | _egrep_o "\"name\":\s*\"$h\".*}")" if [ "$hostedzone" ]; then _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) if [ "$_domain_id" ]; then